pax_global_header00006660000000000000000000000064144072525000014511gustar00rootroot0000000000000052 comment=b7d3bea0effb6663a6d69897bc1c4ea3cc08b682 sfsexp-1.4.1/000077500000000000000000000000001440725250000130245ustar00rootroot00000000000000sfsexp-1.4.1/.gitignore000066400000000000000000000002131440725250000150100ustar00rootroot00000000000000*~ *.o *.lo Makefile Makefile.in *.log *.status *.a .deps install-sh missing configure config.h aclocal.m4 depcomp stamp-h1 autom4te.cache sfsexp-1.4.1/COPYING000066400000000000000000000027051440725250000140630ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ sfsexp-1.4.1/Doxyfile000066400000000000000000000160151440725250000145350ustar00rootroot00000000000000# Doxyfile 1.2.13-20020210 #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- PROJECT_NAME = "Small, Fast S-Expression Library" PROJECT_NUMBER = OUTPUT_DIRECTORY = ./doxygen/ OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = INTERNAL_DOCS = NO STRIP_CODE_COMMENTS = YES CASE_SENSE_NAMES = YES SHORT_NAMES = NO HIDE_SCOPE_NAMES = YES VERBATIM_HEADERS = YES SHOW_INCLUDE_FILES = YES JAVADOC_AUTOBRIEF = NO INHERIT_DOCS = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO ALIASES = ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 OPTIMIZE_OUTPUT_FOR_C = YES SHOW_USED_FILES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ./src/sexp.h \ ./src/sexp_errors.h \ ./src/sexp_ops.h \ ./src/faststack.h \ ./src/sexp_memory.h \ ./src/sexp_vis.h \ ./src/cstring.h FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex COMPACT_LATEX = NO PAPER_TYPE = letter EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = YES MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES TEMPLATE_RELATIONS = YES HIDE_UNDOC_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = gif DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO CGI_NAME = search.cgi CGI_URL = DOC_URL = DOC_ABSPATH = BIN_ABSPATH = /usr/local/bin/ EXT_DOC_PATHS = sfsexp-1.4.1/INSTALL000066400000000000000000000011711440725250000140550ustar00rootroot00000000000000To build, you'll need: autoconf automake libtool m4. To try things out, just type: % ./configure % make Try out the example in the examples directory, or torture test things with the testers in the tests directory. To build the doxygen latex/html/manpages, type this: % make doc Look in doxygen/ for the files. If you are working off a version of the code directly from git, you will likely need to run automake before the ./configure line above: % autoreconf --install % ./configure % make To enable debug symbols and turn off optimization, configure with the --enable-debug option set. % configure --enable-debug % make sfsexp-1.4.1/LICENSE.makefile000066400000000000000000000027671440725250000156210ustar00rootroot00000000000000# # SFSEXP: Small, Fast S-Expression Library # Written by Matthew Sottile (mjsottile@gmail.com) # # 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 # sfsexp-1.4.1/LICENSE_LGPL000066400000000000000000000635101440725250000146540ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. 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 not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the 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 specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! sfsexp-1.4.1/Makefile.am000066400000000000000000000002711440725250000150600ustar00rootroot00000000000000SUBDIRS = src examples tests EXTRA_DIST = Doxyfile LICENSE_LGPL README.md README_cmake.txt win32 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = sfsexp.pc ACLOCAL_AMFLAGS = -I m4 sfsexp-1.4.1/README.md000066400000000000000000000203551440725250000143100ustar00rootroot00000000000000sfsexp ====== This library is intended for developers who wish to manipulate (read, parse, modify, and create) symbolic expressions from C or C++ programs. A symbolic expression, or s-expression, is essentially a LISP-like expression such as `(a (b c))`. S-expressions are able to represent complex, structured data without requiring additional meta-data describing the structure. They are recursively defined: an s-expression is a list of either atoms or s-expressions. In the example above, the expression contains an atom "a" and an s-expression, which in turn contains two atoms, "b" and "c". They are simple, useful, and well understood. This library is designed to provide a minimal set of functions and data structures for the four functions listed above: reading s-expressions (I/O), parsing strings containing them into an AST equivalent, modifying the AST representation, and converting the AST back into a well formatted string. The primary goals are efficiency and simplicity. Beyond basic s-expression handling, the library supports a mode to inline binary data within an expression. The continuation-based parser is designed to efficiently handle parsing multiple streams. The library is also designed with a limited memory mode for use in embedded systems. This library forms the basis of the data representation and transmission protocol for the [Supermon](https://dl.acm.org/doi/10.5555/792762.793324) high-speed cluster monitoring system from the LANL Advanced Computing Laboratory. The usefulness and lack of choice in available, open source s-expression libraries around 2003 motivated the independent (from supermon) release of this library. ## Building (Attention Windows Users: If you are using cygwin, this section applies as cygwin looks pretty much like unix for compilation. Visual Studio users see the note at the end and look inside the win32 directory.) Configure the sources via autoconf. ``` % ./configure ``` Currently, the major features that can be enabled via autoconf are: - "--enable-debug" to enable any debugging code in the library, - "--enable-thread-unsafe-memory-management" to enable caching of s-expressions in a thread-unsafe way. Other features are toggled by setting appropriate options in the CFLAGS, such as the memory-limiting mode. ``` % CFLAGS=-D_SEXP_LIMIT_MEMORY_ ./configure ``` Note that you should use the vanilla configuration unless you know that you want to use debug mode or other options, and understand precisely what they mean. After building, just invoke make: ``` % make ``` What comes out is a library called "libsexp.a". If you wish to copy the headers and libraries to an installation location, you should then say: ``` % make install ``` At the current time, this is not recommended if the installation prefix is /usr or /usr/local, since the headers do not go into an isolated subdirectory. In the future, we will hopefully have a single consolidated header that encapsulates all of the headers currently included in the library. If you do not want to aim your project that uses the library into the library source and build directories directly, creating a separate installation prefix and installing there is recommended. For example, from the root of the sfsexp tree: ``` % mkdir installTree % ./configure --prefix=`pwd`/installTree % make % make install ``` If you want the docs, make sure you have doxygen installed and that the DOXYGEN variable in the Makefile.in in this directory points at the right place. Re-run autoconf to regenerate the makefiles, and then type: ``` % make doc ``` ## Usage notes In any code that wants to use this, just include "sexp.h". That contains the one data structure, enumeration, and five functions for manipulating and parsing strings and s-expressions. Compilation typically will look like: ``` % cc -I/path/to/sexp/include -L/path/to/sexp/library \ -o foo foo.o -lsexp ``` The critical parts are to ensure that the include path aims at the path containing the library headers, the library path aims at the path containing the compiled binary libraries, and the library is linked in with the executable. The API is well-documented in the header files, esp. [sexp.h](src/sexp.h) and [sexp_ops.h](src/sexp_ops.h). The latter contains some convenience operators that may make your life slightly easier; for example, it defines `hd_sexp`, `tl_sexp`, and `next_sexp`, which make it a little easier to navigate sexps. (see below for a schematic representation of sexp structure). The library includes a basic (optional) string library as well; see [cstring.h](src/cstring.h). This string library is useful to avoid working with fixed sized buffers and will grow strings as necessary automatically. If you are parsing a set of smallish sexps, as you might have in a lispy source file, you probably want to use `init_iowrap` and `read_one_sexp`. The [examples](examples) and [tests](tests) directories contain multiple examples showing how to do this. The drawback with `read_one_sexp` is that it uses a read buffer of size `BUFSIZ`, which may relatively small (1024 on MacOS Big Sur). If you try to read a sexp that is larger than `BUFSIZ` using this method you will get error `SEXP_ERR_INCOMPLETE`, meaning "parsing is incomplete and needs more data to complete it." ([sexp_errors.h](src/sexp_errors.h)). This can easily happen if you are reading data encoded as sexps. For example, it's not uncommon for a big hunk o' data to be encoded as a single sexp in a file. One way to handle this situation is to get the file size, dynamically allocate a buffer big enough to hold it, and then use `parse_sexp`. Here's a minimal example (error checking omitted): ```c int fd; FILE *fp = fopen(fname, "r"); fseek(fp, 0, SEEK_END); size_t fsize = (size_t) ftell(fp); fseek(fp, 0, SEEK_SET); /* reset file pos to beginning of file, for reading */ char *work_buf = (char*) malloc(fsize + 1); char *check_buf = (char*) malloc(fsize + 1); /* for debugging */ size_t read_len = fread(work_buf, 1, fsize, fp); work_buf[read_len] = '\0'; /* make sure it's properly terminated */ sexp_t the_sexp = parse_sexp(work_buf, read_len); /* assumption: file contains one sexp */ /* check the parse result by serializing it to check_buf */ size_t write_len = print_sexp(check_buf, fsize, the_sexp); printf("sexp: '%s'", check_buf); /* process the_sexp ... */ destroy_sexp(the_sexp); free(work_buf); free(check_buf); close(fd); ``` The internal representation of sexps is lispy. For example, `(a (b c) d)` looks something like this: ``` sexp_t | list | \_/ sexp_t -- next --> sexp_t -- next --> sexp_t | | | val list val | | | \_/ | \_/ a | d | \_/ sexp_t --> next --> sexp_t | | val val | | \_/ \_/ b c ``` ## Windows users Please look in the win32/ subdirectory. Note that as of 9/2013, this has not been looked at nor tested in a number of years. If you try to use it and find it broken, fixes and updates to bring it up to speed with modern Windows development environments would be appreciated! ## Credits The library is by Matt Sottile. Steve James of Linux Labs has contributed bug fixes and features while developing for the related Supermon project. Sung-Eun Choi and Paul Ruth have contributed many bug reports as the library has grown. Erik Hendriks contributed the malloc debugging tools now used when building with the -D_DEBUG_MALLOCS_ option. Brad Green contributed code (in win32/) and testing for the Windows Visual Studio build target. Others who have contributed can be found in the Github repository contributor list. ### Funding acknowledgement This work was funded by the Department of Energy, Office of Science. The original development was performed at the Los Alamos National Laboratory between 2002 and 2007. It is currently maintained independently of any funding source as a service to the community (plus, it's fun to work on). sfsexp-1.4.1/README_cmake.txt000066400000000000000000000010211440725250000156540ustar00rootroot00000000000000Using sfsexp library from cmake-based projects: ---------------------------------------------- Presently, the library does not come with a proper FindSfsexp.cmake module file. In the meantime, you can add the following lines to a CMakeLists.txt file. Assuming the source tree for the sfsexp library exists in /Users/matt/Research/sfsexp/src : INCLUDE_DIRECTORIES( /Users/matt/Research/sfsexp/src/src ) LINK_DIRECTORIES( /Users/matt/Research/sfsexp/src/src ) And then just add "sexp" to the TARGET_LINK_LIBRARIES list. sfsexp-1.4.1/_config.yml000066400000000000000000000000331440725250000151470ustar00rootroot00000000000000theme: jekyll-theme-minimalsfsexp-1.4.1/configure.ac000066400000000000000000000027411440725250000153160ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT(sfsexp, 1.4.1, mjsottile@me.com) AM_INIT_AUTOMAKE(foreign) AC_OUTPUT([Makefile src/Makefile examples/Makefile tests/Makefile]) AC_CONFIG_SRCDIR([examples/binmode.c]) AC_CONFIG_FILES([sfsexp.pc]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIRS([m4]) # use libtool LT_INIT ## FROM: http://lists.gnu.org/archive/html/automake/2008-09/msg00075.html SX_CPPFLAGS="$CPPFLAGS -DNODEBUG" SX_CFLAGS="$CFLAGS -O3 -Wall" AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],[turn on debug options and code (disabled by default)])], [SX_CPPFLAGS="" SX_CFLAGS="$CFLAGS -g -O0 -Wall"], []) AC_ARG_ENABLE(thread-unsafe-memory-management, [AS_HELP_STRING([--enable-thread-unsafe-memory-management],[turn on thread-unsafe memory management (disabled by default)])], [], [SX_CFLAGS="$SX_CFLAGS -D_NO_MEMORY_MANAGEMENT_"]) # Export flags AC_SUBST([SFSEXP_CPPFLAGS], $SX_CPPFLAGS) AC_SUBST([SFSEXP_CFLAGS], $SX_CFLAGS) # Checks for programs. AC_PROG_CXX AC_PROG_CC # Checks for libraries. # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h sys/time.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AC_HEADER_TIME # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC AC_FUNC_STRTOD AC_CHECK_FUNCS([gettimeofday pow sqrt]) AC_OUTPUT sfsexp-1.4.1/examples/000077500000000000000000000000001440725250000146425ustar00rootroot00000000000000sfsexp-1.4.1/examples/.gitignore000066400000000000000000000001211440725250000166240ustar00rootroot00000000000000binmode callbacks continuations packunpack paultest rcfile sexpvis simple_interp sfsexp-1.4.1/examples/Makefile.am000066400000000000000000000013131440725250000166740ustar00rootroot00000000000000CFLAGS = $(SFSEXP_CFLAGS) CPPFLAGS = -I../src $(SFSEXP_CPPFLAGS) LDFLAGS = EXTRA_DIST = testrc vis.in sexps.in edgelist.dat conttest noinst_PROGRAMS = binmode callbacks continuations packunpack paultest rcfile sexpvis simple_interp noinst_HEADERS = ../src/sexp.h LDADD = ../src/libsexp.la binmode_SOURCES = binmode.c ../src/sexp.h callbacks_SOURCES = callbacks.c ../src/sexp.h continuations_SOURCES = continuations.c ../src/sexp.h packunpack_SOURCES = packunpack.c ../src/sexp.h paultest_SOURCES = paultest.c ../src/sexp.h rcfile_SOURCES = rcfile.c ../src/sexp.h ../src/sexp_ops.h sexpvis_SOURCES = sexpvis.c ../src/sexp.h ../src/sexp_vis.h simple_interp_SOURCES = simple_interp.c ../src/sexp.h ../src/sexp_ops.h sfsexp-1.4.1/examples/binmode.c000066400000000000000000000100631440725250000164230ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include #include "sexp.h" #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include /** * read a binary file from fd. Length is filled in, bss is buffer * start size and bgs is buffer growth size for realloc()ing. returns * pointer to byte-buffer. if NULL, then there was some sort of error. */ char *readfile(int fd, size_t *length, size_t bss, size_t bgs) { char *buf, *tmp; size_t bused, ballocd; int amt; /* check for either errors on the caller side */ assert(fd > 0); bused = 0; ballocd = bss; buf = (char *)malloc(sizeof(char)*bss); assert(buf != NULL); while ((amt = read(fd,buf+bused,ballocd-bused)) > 0) { bused += amt; if (bused == ballocd) { tmp = (char *)realloc(buf,ballocd+bgs); assert(tmp != NULL); buf = tmp; ballocd += bgs; } } if (bused == 0) return NULL; *length = bused; return buf; } int main(int argc, char **argv) { sexp_t *sx_in, *sx_binatom, *sx_out; int fd, status; char *b; size_t l = 0; CSTRING *s = NULL; pcont_t *pc; /* read data */ fd = open("testdata",O_RDONLY); if (fd <= 0) { printf("Error opening test data file ``testdata''\n"); exit(EXIT_FAILURE); } b = readfile(fd,&l,1024,256); close(fd); /* report */ printf("Read %lu bytes of data.\n",(unsigned long)l); sx_binatom = new_sexp_binary_atom(b, l); assert(sx_binatom != NULL); /* IMPORTANT: since sx_binatom is now being subsumed by the list sx_in that contains it, we will not need to explicitly free sx_binatom since it will be freed during the traversal when sx_in is destroyed. */ sx_in = new_sexp_list(sx_binatom); printf("Created expression.\n"); print_sexp_cstr(&s,sx_in,l+1024); destroy_sexp(sx_in); b = NULL; sx_in = NULL; printf("Destroyed AST and buffer.\n"); pc = init_continuation(NULL); pc->mode = PARSER_INLINE_BINARY; pc = cparse_sexp(s->base,s->len,pc); sx_out = pc->last_sexp; printf("Parsed unparsed version back to AST.\n"); assert(sx_out != NULL); b = sx_out->list->bindata; l = sx_out->list->binlength; fd = open("testdata_out",O_RDWR|O_CREAT,0644); if (fd <= 0) { printf("Error opening ``testdata_out'': Create empty file to write to.\n"); exit(EXIT_FAILURE); } status = write(fd,b,l); if (status < 0) { printf("Write failed.\n"); exit(EXIT_FAILURE); } close(fd); sdestroy(s); destroy_continuation(pc); destroy_sexp(sx_out); sexp_cleanup(); printf("Extracted and wrote bindata from AST.\n"); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/callbacks.c000066400000000000000000000071441440725250000167330ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include #include #include #include "sexp.h" #include #include #include #include typedef enum { WAITING, NEXT_EDGE, GET_X1, GET_X2, GET_Y1, GET_Y2 } state_t; static double x1,x2,y1,y2; static state_t current_state = WAITING; static int depth = 0; void add_edge(double ax, double ay, double bx, double by) { printf("EDGE DEFINED FROM (%f,%f) to (%f,%f)\n",ax,ay,bx,by); } void enter_sexpr() { depth++; switch (current_state) { case WAITING: current_state = NEXT_EDGE; break; case NEXT_EDGE: case GET_X1: current_state = GET_X1; break; case GET_X2: current_state = GET_X2; break; default: printf("This is unexpected.\n"); break; } } void exit_sexpr() { depth--; switch (current_state) { case GET_Y1: current_state = GET_X2; break; case GET_Y2: add_edge(x1,y1,x2,y2); case NEXT_EDGE: current_state = NEXT_EDGE; break; default: printf("This is also unexpected.\n"); break; } if (depth == 0) { printf("All edges for room found.\n"); current_state = WAITING; } } void characters(const char *buf, size_t len, atom_t aty) { switch (current_state) { case NEXT_EDGE: printf("%s\n",buf); break; case GET_X1: x1 = strtod(buf,NULL); current_state = GET_Y1; break; case GET_X2: x2 = strtod(buf,NULL); current_state = GET_Y2; break; case GET_Y1: y1 = strtod(buf,NULL); break; case GET_Y2: y2 = strtod(buf,NULL); break; default: printf("Also not expected.\n"); break; } } int main(int argc, char **argv) { parser_event_handlers_t peh_t; int fd; sexp_iowrap_t *iow = NULL; sexp_t *sx = NULL; current_state = WAITING; peh_t.start_sexpr = enter_sexpr; peh_t.end_sexpr = exit_sexpr; peh_t.characters = characters; fd = open("edgelist.dat", O_RDONLY); iow = init_iowrap(fd); iow->cc = init_continuation(NULL); iow->cc->event_handlers = &peh_t; do { if (sx != NULL) destroy_sexp(sx); sx = read_one_sexp(iow); } while (sx != NULL); destroy_iowrap(iow); sexp_cleanup(); close(fd); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/check_leaks.sh000077500000000000000000000011671440725250000174420ustar00rootroot00000000000000#!/usr/bin/env bash # if valgrind isn't present we can't proceed - otherwise # we get a cascade of command not found failures if ! command -v valgrind &> /dev/null then echo "cannot continue: valgrind could not be found" exit fi function test { libtool --mode=execute valgrind --leak-check=full --show-reachable=yes -q "$@" > /dev/null status=$? if [ $status -ne 0 ]; then echo "error with $1" else echo "no error with $1" fi return $status } test ./binmode test ./callbacks test ./continuations test ./packunpack test ./paultest test ./rcfile test ./sexpvis test ./simple_interp sfsexp-1.4.1/examples/config.h.in000066400000000000000000000001161440725250000166630ustar00rootroot00000000000000/* config.h.in. Generated automatically from configure.in by autoheader. */ sfsexp-1.4.1/examples/continuations.c000066400000000000000000000045441440725250000177120ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsotile@gmail.com) 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 **/ #include #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include "sexp.h" int main(int argc, char **argv) { char foo[255]; char buf[4096]; sexp_t *sx = NULL; pcont_t *cc = NULL; int fd,len; cc = NULL; fd = open("conttest",O_RDONLY); len = -1; while (len != 0) { len = read(fd,foo,16); foo[len] = '\0'; printf("[%s]\n",foo); if (cc == NULL) { cc = init_continuation(foo); } if (len > 0) sx = (sexp_t *)iparse_sexp(foo,len,cc); while (sx != NULL) { print_sexp(buf,4096,sx); printf("\n\n%s\n",buf); destroy_sexp(sx); sx = (sexp_t *)iparse_sexp(foo,len,cc); } } destroy_continuation(cc); sexp_cleanup(); close(fd); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/conttest000066400000000000000000000000721440725250000164270ustar00rootroot00000000000000 (\(unusedparam (this is "\"unused and will be ignored")) sfsexp-1.4.1/examples/conttest_old000066400000000000000000000000701440725250000172630ustar00rootroot00000000000000 (unusedparam (this is "\"unused and will be ignored")) sfsexp-1.4.1/examples/edgelist.dat000066400000000000000000000005501440725250000171340ustar00rootroot00000000000000(edges ( (1389.886593 1341.567282) (1383.122623 1339.369530) ) ( (1383.122623 1339.369530) (1387.706464 1325.261939) ) ( (1387.706464 1325.261939) (1394.470360 1327.459664) ) ( (1394.470360 1327.459664) (1389.886593 1341.567282) ) ); edges end (edges ( ( 1.1 2.2 ) (2.2 3.3) ) ( ( 2.2 3.3 ) (3.3 3.3) ) ( ( 3.3 3.3 ) (1.1 2.2) ) ) ; end edges of triangle room sfsexp-1.4.1/examples/packunpack.c000066400000000000000000000102561440725250000171320ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include #include #include #include #include /** * Given an s-expression of the form: * * (tag (val_list)) * * Where each value in the val_list is a float, extract the data and * populate the array passed in (the length of the array is in `size'). * Assume the array was allocated properly, size is correct, and the * expression contains the right number of values. This eliminates lots * of error checking code and makes the process a bit clearer. */ void extract(sexp_t *sx, float *data, size_t size) { sexp_t *s; unsigned int i; assert(sx != NULL && data != NULL); /* duh */ /* assumption : s-expression is formatted as (tag (val1 val2 val3)) */ printf("Data tag: [%s]\n",sx->list->val); /* s = (vallist) */ s = sx->list->next; i = 0; s = s->list; while (s != NULL && i < size) { sscanf(s->val,"%f",&data[i]); s = s->next; i++; } } /** * example of packing three values into an expression of the form: * * (tag (v1 v2 v3)) * * COMMENTS SHOW THE STATE OF SX AS IT IS CONSTRUCTED */ sexp_t *pack(char *tag, float v1, float v2, float v3) { sexp_t *sx = new_sexp_list(new_sexp_atom(tag,strlen(tag),SEXP_BASIC)); /* sx = (tag) */ char sbuf[32]; sexp_t *vlist,*vptr; vlist = new_sexp_list(NULL); /* vlist = () */ sx->list->next = vlist; /* sx = (tag ()) */ sprintf(sbuf,"%f",v1); vlist->list = new_sexp_atom(sbuf,strlen(sbuf),SEXP_BASIC); /* vlist = (v1) */ vptr = vlist->list; /* sx = (tag (v1)) */ sprintf(sbuf,"%f",v2); vptr->next = new_sexp_atom(sbuf,strlen(sbuf),SEXP_BASIC); /* vlist = (v1 v2) */ vptr = vptr->next; /* sx = (tag (v1 v2)) */ sprintf(sbuf,"%f",v3); vptr->next = new_sexp_atom(sbuf,strlen(sbuf),SEXP_BASIC); /* vlist = (v1 v2 v3) */ /* sx = (tag (v1 v2 v3)) ---- done, return. */ return sx; } /**** * main ****/ int main(int argc, char **argv) { char buf[256]; /* string to sprintf to */ float vals[3]; /* place to put data */ sexp_t *sx = NULL; /*** method #1: create expression as string on one side, extract data on the other. ***/ printf("===>> PART 1 <<===\n"); sprintf(buf,"(thetag (1.0 2.0 3.0))"); sx = parse_sexp(buf,strlen(buf)); extract(sx,vals,3); printf("Extracted V1=%f V2=%f V3=%f\n",vals[0],vals[1],vals[2]); destroy_sexp(sx); /*** method #2: packing function creates expression, same extract function extracts data. print in between to show expression. ***/ printf("\n===>> PART 2 <<===\n"); sx = pack("part2tag",4.0,5.0,6.0); print_sexp(buf,256,sx); printf("SX=%s\n",buf); extract(sx,vals,3); printf("Extracted V1=%f V2=%f V3=%f\n",vals[0],vals[1],vals[2]); destroy_sexp(sx); sexp_cleanup(); return 0; } sfsexp-1.4.1/examples/paultest.c000066400000000000000000000036701440725250000166550ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include #include #include #include "sexp.h" int main(int argc, char **argv) { char foo[8192]; char buf[4096]; sexp_t *sx = NULL; int fd,len; fd = open("conttest",O_RDONLY); len = -1; while (len != 0) { len = read(fd,foo,8192); foo[len] = '\0'; sx = parse_sexp(foo,8192); print_sexp(buf,4096,sx); printf("\n\n%s\n",buf); destroy_sexp(sx); } sexp_cleanup(); close(fd); return 0; } sfsexp-1.4.1/examples/rcfile.c000066400000000000000000000043451440725250000162600ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include "sexp.h" #include "sexp_ops.h" int main(int argc, char **argv) { int fd; char pstr[1024]; sexp_t *sx, *param; sexp_iowrap_t *iow; fd = open("testrc",O_RDONLY); iow = init_iowrap(fd); sx = read_one_sexp(iow); param = find_sexp("parameter1",sx); print_sexp(pstr,1024,param->next); printf("parameter1 = %s\n",pstr); param = find_sexp("parameter2",sx); print_sexp(pstr,1024,param->next); printf("parameter2 = %s\n",pstr); param = find_sexp("parameter3",sx); if (param == NULL) { printf("parameter3 not defined.\n"); } destroy_sexp(sx); destroy_iowrap(iow); sexp_cleanup(); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/runall.sh000066400000000000000000000010061440725250000164700ustar00rootroot00000000000000#!/bin/sh echo "====================================================================" echo "rcfile" ./rcfile echo "====================================================================" echo "packunpack" ./packunpack echo "====================================================================" echo "simple_interp" ./simple_interp echo "====================================================================" echo "continuations" ./continuations echo "====================================================================" sfsexp-1.4.1/examples/sexps.in000066400000000000000000000002421440725250000163320ustar00rootroot00000000000000(setq a (point 1 2)) (setq b (point 5 7)) (setq k1 (circle a b)) (setq k2 (circle b a)) (setq tmp (section k1 k2)) (draw a b (segment (point1 tmp) (point2 tmp))) sfsexp-1.4.1/examples/sexpvis.c000066400000000000000000000051231440725250000165100ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include #include #include #include #include "sexp.h" #include "sexp_vis.h" /** * default behavior: read file "vis.in", write DOT representation of s-expression structure * as "sexpexample.dot". * * if one argument provided, read filename specified in first argument, write DOT * representation to "sexpexample.dot" * * if two arguments provided, read filename specified in first argument, write DOT * representation to filename specified in second argument. */ int main(int argc, char **argv) { sexp_t *a; int fd; sexp_iowrap_t *iow; if (argc == 1) { fd = open("vis.in",O_RDONLY); } else { fd = open(argv[1],O_RDONLY); } iow = init_iowrap(fd); a = read_one_sexp(iow); while (a != NULL) { if (argc != 3) { sexp_to_dotfile(a,"sexpexample.dot"); } else { sexp_to_dotfile(a,argv[2]); } destroy_sexp(a); a = read_one_sexp(iow); } destroy_iowrap(iow); sexp_cleanup(); close(fd); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/simple_interp.c000066400000000000000000000141251440725250000176630ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ /* * Simple interpreter of s-expressions */ #include #include #include #include typedef struct dict { char varname[255]; sexp_t *valexp; struct dict *next; } dict_t; /** * lookup a variable. if we find it, return it. Otherwise * return null. */ sexp_t *lookup(char *varname, dict_t *d) { sexp_t *ret = NULL; dict_t *_d = d; printf("Lookup : %s\n",varname); while (_d != NULL) { if (strcmp(varname,_d->varname) == 0) { ret = _d->valexp; break; } _d = _d->next; } return ret; } /** * insert a variable into the dictionary */ dict_t *insert(char *varname, sexp_t *val, dict_t *d) { dict_t *_d = d; char dbgbuf[BUFSIZ]; printf("Inserting %s into dictionary.\n",varname); print_sexp(dbgbuf,BUFSIZ,val); printf("%s value is : %s\n",varname,dbgbuf); if (_d == NULL) { /* empty dictionary -- create one entry and return */ _d = (dict_t *)malloc(sizeof(dict_t)); _d->valexp = val; strcpy(_d->varname,varname); _d->next = NULL; } else { /* not empty, so first see if the name is already used. If so, purge the expression that was there and replace it. */ while (1) { if (strcmp(_d->varname,varname) == 0) { destroy_sexp(_d->valexp); _d->valexp = val; return d; } /* if we're at the end with nothing left, break out of the loop */ if (_d->next == NULL) break; _d = _d->next; } /* we're at the end, so tack on one entry for the value we want to add. */ _d->next = (dict_t *)malloc(sizeof(dict_t)); _d->next->valexp = val; strcpy(_d->next->varname,varname); _d->next->next = NULL; return d; } return _d; } /** * look up an entry and purge it -- not done yet */ dict_t *purge(char *varname, dict_t *d) { /* find an entry and purge it */ return d; } /** * purge all entries in the dictionary and free the dictionary itself. */ void purge_all(dict_t *d) { dict_t *_d = d; dict_t *td; while (_d != NULL) { td = _d->next; printf("PURGING: %s\n",_d->varname); destroy_sexp(_d->valexp); free(_d); _d = td; } } /****************** eval function *******************/ dict_t *eval(sexp_t *exp, dict_t *env) { char *v; dict_t *d = env; sexp_t *tmpsx, *tmpsx2; /** * values understood here: * setq * circle * point * section * draw * segment */ if (exp->ty == SEXP_LIST) { if (exp->list->ty == SEXP_VALUE) v = exp->list->val; else return env; } else return env; if (strcmp(v,"setq") == 0) { d = insert(exp->list->next->val,exp->list->next->next,env); exp->list->next->next = NULL; } else if (strcmp(v,"circle") == 0) { printf("CIRCLE: \n"); tmpsx = lookup(exp->list->next->val,d); d = eval(tmpsx,d); tmpsx = lookup(exp->list->next->next->val,d); d = eval(tmpsx,d); } else if (strcmp(v,"point") == 0) { printf("POINT AT: %s,%s\n",exp->list->next->val, exp->list->next->next->val); } else if (strcmp(v,"section") == 0) { printf("SECTION: \n"); tmpsx = lookup(exp->list->next->val,d); d = eval(tmpsx,d); tmpsx = lookup(exp->list->next->next->val,d); d = eval(tmpsx,d); } else if (strcmp(v,"draw") == 0) { tmpsx = exp->list->next; while (tmpsx != NULL) { printf("DRAWING: "); if (tmpsx->ty == SEXP_VALUE) { tmpsx2 = lookup(tmpsx->val,d); d = eval(tmpsx2,d); } else { d = eval(tmpsx,d); } tmpsx = tmpsx->next; } } else if (strcmp(v,"segment") == 0) { printf("SEGMENT:\n"); d = eval(exp->list->next,d); d = eval(exp->list->next->next,d); } else if (strcmp(v,"point1") == 0) { printf("POINT1 OF :\n"); tmpsx = lookup(exp->list->next->val,d); d = eval(tmpsx,d); } else if (strcmp(v,"point2") == 0) { printf("POINT2 OF :\n"); tmpsx = lookup(exp->list->next->val,d); d = eval(tmpsx,d); } else { printf("EVAL: Unknown = %s\n",v); } return d; } /**** * main ****/ int main(int argc, char **argv) { char linebuf[BUFSIZ]; FILE *fp; char *status; sexp_t *sx; dict_t *env = NULL; fp = fopen("sexps.in","r+"); while (1) { status = fgets(linebuf,BUFSIZ,fp); if (feof(fp) != 0) break; /* if not EOF and status was NULL, something bad happened. */ if (status != linebuf) { printf("Error encountered on fgets.\n"); exit(EXIT_FAILURE); } sx = parse_sexp(linebuf,BUFSIZ); print_sexp(linebuf,BUFSIZ,sx); env = eval(sx,env); destroy_sexp(sx); fflush(stderr); } purge_all(env); sexp_cleanup(); fclose(fp); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/slisp/000077500000000000000000000000001440725250000157745ustar00rootroot00000000000000sfsexp-1.4.1/examples/slisp/OLD/000077500000000000000000000000001440725250000164125ustar00rootroot00000000000000sfsexp-1.4.1/examples/slisp/OLD/driver.c000066400000000000000000000020011440725250000200420ustar00rootroot00000000000000/* * Filename: driver.c * Author : matt@lanl.gov * Created : 19 Mar 2003 */ #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include #include "sexp.h" #include "slisp.h" int main(int argc, char **argv) { char buf[BUFSIZ], outbuf[BUFSIZ]; sexp_t *in, *out; sexp_iowrap_t *iow; int fd; fd = open("test_expressions",O_RDONLY); iow = init_iowrap(fd); in = read_one_sexp(iow); while (in != NULL) { printf("\n---------------------------------------------\n"); print_sexp(buf,BUFSIZ,in); printf("Evaluating : %s\n",buf); out = slisp_eval(in); if (out != NULL) { print_sexp(outbuf,BUFSIZ,out); printf("%s ==> %s\n",buf,outbuf); } else { printf("%s ==> ERROR\n",buf); } #ifdef _DEBUG_ printf("\n"); #endif /* _DEBUG_ */ destroy_sexp(in); destroy_sexp(out); in = read_one_sexp(iow); } destroy_iowrap(iow); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/slisp/OLD/slisp.h000066400000000000000000000001441440725250000177140ustar00rootroot00000000000000#ifndef __SLISP_H__ #define __SLISP_H__ #include "sexp.h" sexp_t *slisp_eval(sexp_t *sx); #endif sfsexp-1.4.1/examples/slisp/OLD/slisp_eval.c000066400000000000000000000360041440725250000207220ustar00rootroot00000000000000/* * Filename: slisp_eval.c * Author : matt@lanl.gov * Created : 19 Mar 2003 */ #include #include #include #include #include "slisp.h" #include "slisp_store.h" #include "sexp.h" /** * tokens for operations */ typedef enum { /* binary logical operations */ SL_EQ, SL_GT, SL_LT, SL_NE, SL_GEQ, SL_LEQ, /* unary logical operations */ SL_NOT, /* mathematical operations, binary */ SL_PLUS, SL_MINUS, SL_MULT, SL_DIVIDE, SL_EXP, /* mathematical operations, unary */ SL_SQRT, /* list construction/separation */ SL_CONS, SL_CDR, SL_CAR, /* function application over lists */ SL_FOLD, SL_MAP, /* list sorting */ SL_SORT, /* conditional */ SL_IF, /* lambda */ SL_LAMBDA, /* UNKNOWN : ERROR */ SL_UNKNOWN } slisp_op_t; /* * types for expression elements */ typedef enum { SL_INT, SL_FLOAT, SL_STRING, SL_SEXP, SL_INVALID } slisp_val_t; /* * return type from the internal eval */ typedef enum { SL_PRIMITIVE, SL_CLOSURE } sl_wrap_t; /* * wrapper around primitive values and closures */ typedef struct sexp_wrapper { sl_wrap_t ty; sexp_t *sx; slisp_store_t *store; } sexp_wrap_t; void dump_sexp_t(sexp_t *s) { fprintf(stderr,"\n"); fprintf(stderr,"s=0x%x\n",(unsigned int)s); fprintf(stderr,"s->ty=%d (",s->ty); if (s->ty == SEXP_VALUE) fprintf(stderr,"SEXP_VALUE)\n"); else fprintf(stderr,"SEXP_LIST)\n"); fprintf(stderr,"s->aty=%d\n",s->aty); fprintf(stderr,"s->val=0x%x (",(unsigned int)s->val); if (s->val != NULL) fprintf(stderr,"%s",s->val); fprintf(stderr,")\n"); fprintf(stderr,"s->next=0x%x\n",(unsigned int)s->next); fprintf(stderr,"s->list=0x%x\n",(unsigned int)s->list); } /** * Given a sexp_t element, return the token that it represents. */ slisp_op_t tokenize(sexp_t *sx) { if (sx->ty != SEXP_VALUE) { return SL_UNKNOWN; } if (strcmp("+",sx->val) == 0) return SL_PLUS; else if (strcmp("-",sx->val) == 0) return SL_MINUS; else if (strcmp("*",sx->val) == 0) return SL_MULT; else if (strcmp("/",sx->val) == 0) return SL_DIVIDE; else if (strcmp("^",sx->val) == 0) return SL_EXP; else if (strcmp("=",sx->val) == 0) return SL_EQ; else if (strcmp(">",sx->val) == 0) return SL_GT; else if (strcmp("<",sx->val) == 0) return SL_LT; else if (strcmp("<=",sx->val) == 0) return SL_LEQ; else if (strcmp(">=",sx->val) == 0) return SL_GEQ; else if (strcmp("<>",sx->val) == 0) return SL_NE; else if (strcmp("if",sx->val) == 0) return SL_IF; else if (strcmp("not",sx->val) == 0) return SL_NOT; else if (strcmp("cdr",sx->val) == 0) return SL_CDR; else if (strcmp("car",sx->val) == 0) return SL_CAR; else if (strcmp("map",sx->val) == 0) return SL_MAP; else if (strcmp("cons",sx->val) == 0) return SL_CONS; else if (strcmp("fold",sx->val) == 0) return SL_FOLD; else if (strcmp("sort",sx->val) == 0) return SL_SORT; else if (strcmp("sqrt",sx->val) == 0) return SL_SQRT; else if (strcmp("lambda",sx->val) == 0) return SL_LAMBDA; return SL_UNKNOWN; } /** * Given an expression element, try to derive the type. */ slisp_val_t derive_type(sexp_t *sx) { slisp_val_t ty = SL_INT; char *p; if (sx->ty == SEXP_LIST) return SL_SEXP; p = sx->val; if (p == NULL) return SL_INVALID; /* only one minus, first character, is allowed while still remaining a numeric type. */ if (p[0] == '-') p++; while (p[0] != '\0' && ty != SL_STRING) { if (p[0] == '.') { if (ty == SL_INT) ty = SL_FLOAT; else ty = SL_STRING; } else if (p[0] > '9'|| p[0] < '0') ty = SL_STRING; p++; } return ty; } #define NUMBUFSIZE 30 /**************************************/ /** macros to keep eval code cleaner **/ /**************************************/ #define CHECK_ARGS(arity,num,_op) if((arity)+1 != (num)) { fprintf(stderr,"OPERATOR %d REQUIRING %d ARGUMENTS RECEIVED %d\n",(_op),(arity),(num)-1); return NULL; } #define CHECK_NUMERIC_TYPE(ty_arg) if ((ty_arg) == SL_INVALID || (ty_arg) == SL_STRING) { fprintf(stderr,"CANNOT PERFORM OPERATION ON NON-NUMERIC TYPES (%s:%d)\n",__FILE__,__LINE__); return NULL; } #define SQUOTE_EVAL(sx,tmp) if ((sx)->ty == SEXP_VALUE && (sx)->aty == SEXP_SQUOTE) { (tmp)=parse_sexp((sx)->val,strlen((sx)->val)); destroy_sexp((sx)); (sx)=(tmp); (tmp)=NULL;} #define CHECK_NONZERO(sx) if (strtod((sx)->val,NULL) == 0.0) { fprintf(stderr,"VALUE MUST BE NON-ZERO\n"); return NULL; } #define CHECK_NONNEGATIVE(sx) if (strtod((sx)->val,NULL) < 0.0) { fprintf(stderr,"VALUE MUST BE NON-NEGATIVE\n"); return NULL; } /**************************************/ /**************************************/ /**************************************/ /** * Allocate a new sexp_t element representing a list. */ sexp_t *new_sexp_list(sexp_t *l) { sexp_t *sx = sexp_t_allocate(); 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(char *buf, int bs) { sexp_t *sx = sexp_t_allocate(); sx->ty = SEXP_VALUE; sx->val = (char *)malloc(sizeof(char)*(bs+1)); assert(sx->val != NULL); sx->val_used = sx->val_allocated = bs+1; strcpy(sx->val,buf); sx->list = sx->next = NULL; #ifdef _DEBUG_ dump_sexp_t(sx); #endif /* _DEBUG_ */ return sx; } sexp_t *_slisp_eval(sexp_t *sx, slisp_store_t *store) { slisp_op_t op; int mult = 1; char numbuf[NUMBUFSIZE]; sexp_t *sx_a, *sx_b, *tmp_sx; slisp_val_t ty_a, ty_b; int len, d; #ifdef _DEBUG_ char debugbuf[BUFSIZ]; #endif /* _DEBUG_ */ /* NULL returns NULL */ if (sx == NULL) { #ifdef _DEBUG_ fprintf(stderr,"_slisp_eval passed null sx\n"); #endif /* _DEBUG_ */ return NULL; } #ifdef _DEBUG_ printf("_slisp_eval: sx=0x%x\n",sx); dump_sexp_t(sx); print_sexp(debugbuf,BUFSIZ,sx); printf("=======>%s\n",debugbuf); #endif /* _DEBUG_ */ /* values evaluate to themselves or whatever variable they're bound to */ if (sx->ty == SEXP_VALUE) { if (store->vmap == NULL) return copy_sexp(sx); // d=store->scope_depth; sx_a = get_variable(sx->val,store,store->scope_depth); if (sx_a == NULL) return copy_sexp(sx); else { d = store->scope_depth - 1; sx_b = get_variable(sx_a->val,store,d); if (sx_b != NULL) { destroy_sexp(sx_a); sx_a = sx_b; d--; } #ifdef _DEBUG_ print_sexp(debugbuf,BUFSIZ,sx_a); fprintf(stderr,"GOT: %s\n",debugbuf); #endif /* _DEBUG_ */ return sx_a; } } #ifdef _DEBUG_ printf("_slisp_eval: pointing at list...\n"); dump_sexp_t(sx->list); #endif /* _DEBUG_ */ if (sx->list->ty == SEXP_LIST) return _slisp_eval(sx->list,store); len = sexp_list_length(sx); op = tokenize(sx->list); #ifdef _DEBUG_ fprintf(stderr,"----> OPERATION %d (%s)\n",op,sx->list->val); #endif /* _DEBUG_ */ switch (op) { /* LOGICAL OPERATIONS */ /** unary **/ case SL_NOT: CHECK_ARGS(1,len,op); sx_a = _slisp_eval(sx->list->next,store); if (sx_a->ty == SEXP_VALUE && strcmp(sx_a->val,"t") == 0) sprintf(numbuf,"f"); else sprintf(numbuf,"t"); destroy_sexp(sx_a); return new_sexp(numbuf,strlen(numbuf)); break; /** binary **/ case SL_EQ: case SL_LEQ: case SL_GEQ: case SL_NE: case SL_GT: case SL_LT: CHECK_ARGS(2,len,op); sx_a = _slisp_eval(sx->list->next,store); sx_b = _slisp_eval(sx->list->next->next,store); ty_a = derive_type(sx_a); ty_b = derive_type(sx_b); if (ty_a == SL_SEXP || ty_b == SL_SEXP) { fprintf(stderr,"BOOLEAN TESTS REQUIRE NON-LIST OPERANDS.\n"); return NULL; } if (ty_a != ty_b) sprintf(numbuf,"f"); else { switch(op) { case SL_EQ: if (strcmp(sx_a->val,sx_b->val) == 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); break; case SL_NE: if (strcmp(sx_a->val,sx_b->val) != 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); break; case SL_GEQ: if (ty_a == SL_STRING) { if (strcmp(sx_a->val,sx_b->val) >= 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } else { if (strtod(sx_a->val,NULL) >= strtod(sx_b->val,NULL)) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } break; case SL_LEQ: if (ty_a == SL_STRING) { if (strcmp(sx_a->val,sx_b->val) <= 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } else { if (strtod(sx_a->val,NULL) <= strtod(sx_b->val,NULL)) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } break; case SL_GT: if (ty_a == SL_STRING) { if (strcmp(sx_a->val,sx_b->val) > 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } else { if (strtod(sx_a->val,NULL) > strtod(sx_b->val,NULL)) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } break; case SL_LT: if (ty_a == SL_STRING) { if (strcmp(sx_a->val,sx_b->val) < 0) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } else { if (strtod(sx_a->val,NULL) < strtod(sx_b->val,NULL)) sprintf(numbuf,"t"); else sprintf(numbuf,"f"); } break; default: fprintf(stderr,"THIS SHOULD NEVER HAPPEN!\n"); return NULL; } } destroy_sexp(sx_a); destroy_sexp(sx_b); return new_sexp(numbuf,strlen(numbuf)); break; /* MINUS and PLUS */ case SL_MINUS: mult = -1; case SL_PLUS: CHECK_ARGS(2,len,op); sx_a = _slisp_eval(sx->list->next,store); sx_b = _slisp_eval(sx->list->next->next,store); ty_a = derive_type(sx_a); ty_b = derive_type(sx_b); CHECK_NUMERIC_TYPE(ty_a); CHECK_NUMERIC_TYPE(ty_b); /* float */ if (ty_a == SL_FLOAT || ty_b == SL_FLOAT) sprintf(numbuf,"%f",(strtod(sx_a->val,NULL) + ((double)mult * strtod(sx_b->val,NULL)))); /* int */ else sprintf(numbuf,"%d",(atoi(sx_a->val) + (mult *atoi(sx_b->val)))); destroy_sexp(sx_a); destroy_sexp(sx_b); return new_sexp(numbuf,strlen(numbuf)); break; /* DIVIDE and MULT */ case SL_DIVIDE: case SL_MULT: CHECK_ARGS(2,len,op); sx_a = _slisp_eval(sx->list->next,store); sx_b = _slisp_eval(sx->list->next->next,store); if (sx_a == NULL || sx_b == NULL) dump_store(store); assert(sx_a != NULL); assert(sx_b != NULL); ty_a = derive_type(sx_a); ty_b = derive_type(sx_b); CHECK_NUMERIC_TYPE(ty_a); CHECK_NUMERIC_TYPE(ty_b); if (op == SL_DIVIDE) CHECK_NONZERO(sx_b); /* division */ if (op == SL_DIVIDE) { sprintf(numbuf,"%f",(strtod(sx_a->val,NULL) / strtod(sx_b->val,NULL))); /* multiplication */ } else { if (ty_a == SL_INT && ty_b == SL_INT) sprintf(numbuf,"%d",(atoi(sx_a->val) * atoi(sx_b->val))); else sprintf(numbuf,"%f",(strtod(sx_a->val,NULL) * strtod(sx_b->val,NULL))); } destroy_sexp(sx_a); destroy_sexp(sx_b); return new_sexp(numbuf,strlen(numbuf)); break; case SL_EXP: CHECK_ARGS(2,len,op); sx_a = _slisp_eval(sx->list->next,store); sx_b = _slisp_eval(sx->list->next->next,store); ty_a = derive_type(sx_a); ty_b = derive_type(sx_b); CHECK_NUMERIC_TYPE(ty_a); CHECK_NUMERIC_TYPE(ty_b); if (strtod(sx_b->val,NULL) < 0.0) { sprintf(numbuf,"%f",(pow(strtod(sx_a->val,NULL), strtod(sx_b->val,NULL)))); } else { if (ty_a == SL_INT && ty_b == SL_INT) sprintf(numbuf,"%d",(int)(pow(strtod(sx_a->val,NULL), strtod(sx_b->val,NULL)))); else sprintf(numbuf,"%f",(pow(strtod(sx_a->val,NULL), strtod(sx_b->val,NULL)))); } destroy_sexp(sx_a); destroy_sexp(sx_b); return new_sexp(numbuf,strlen(numbuf)); break; case SL_SQRT: CHECK_ARGS(1,len,op); sx_a = _slisp_eval(sx->list->next,store); ty_a = derive_type(sx_a); CHECK_NUMERIC_TYPE(ty_a); CHECK_NONNEGATIVE(sx_a); sprintf(numbuf,"%f",(sqrt(strtod(sx_a->val,NULL)))); destroy_sexp(sx_a); return new_sexp(numbuf,strlen(numbuf)); break; case SL_CDR: case SL_CAR: CHECK_ARGS(1,len,op); sx_a = _slisp_eval(sx->list->next,store); SQUOTE_EVAL(sx_a,tmp_sx); if (sx_a->ty != SEXP_LIST) { fprintf(stderr,"CANNOT PERFORM CAR ON NON-LIST EXPRESSION.\n"); return NULL; } if (op == SL_CAR) { sx_b = copy_sexp(sx_a->list); destroy_sexp(sx_a); sx_a = sx_b; sx_a->next = NULL; } else { sx_b = new_sexp_list(copy_sexp(sx_a->list->next)); sx_b->next = NULL; destroy_sexp(sx_a); sx_a = sx_b; } return sx_a; break; case SL_CONS: CHECK_ARGS(2,len,op); sx_a = _slisp_eval(sx->list->next,store); sx_b = _slisp_eval(sx->list->next->next,store); SQUOTE_EVAL(sx_a,tmp_sx); SQUOTE_EVAL(sx_b,tmp_sx); tmp_sx = new_sexp_list(sx_a); if (sx_b->ty != SEXP_LIST) tmp_sx->list->next = sx_b; else tmp_sx->list->next = sx_b->list; return tmp_sx; break; case SL_IF: CHECK_ARGS(3,len,op); sx_a = _slisp_eval(sx->list->next,store); if (sx_a->ty != SEXP_VALUE) { fprintf(stderr,"IF REQUIRES BOOLEAN TEST\n"); return NULL; } if (strcmp(sx_a->val, "t") == 0) { destroy_sexp(sx_a); return _slisp_eval(sx->list->next->next,store); } else { destroy_sexp(sx_a); return _slisp_eval(sx->list->next->next->next,store); } break; case SL_LAMBDA: if (len < 2) { fprintf(stderr,"LAMBDA REQUIRES AT LEAST ONE ARGUMENT.\n"); return NULL; } /* no arguments */ if (len == 2) { fprintf(stderr,"LAMBDA W/ NO ARGS\n"); } /* walk to the last expression in the sequence */ sx_a = sx->list->next; /* arg1 name */ sx_b = sx->next; /* arg1 expression */ while (sx_a->next != NULL) { #ifdef _DEBUG_ fprintf(stderr,"VAR:%s.\n",sx_a->val); #endif /* _DEBUG_ */ if (sx_b == NULL) { fprintf(stderr,"LAMBDA EXPRESSION REQUIRES MORE ARGUMENTS.\n"); return NULL; } tmp_sx = sx_b->next; sx_b->next = NULL; set_variable(sx_a->val,sx_b,store); sx_b->next = tmp_sx; sx_a = sx_a->next; sx_b = sx_b->next; } while (sx_a->next != NULL) sx_a = sx_a->next; tmp_sx = _slisp_eval(sx_a,store); sx->next = NULL; destroy_sexp(sx); return tmp_sx; break; case SL_SORT: case SL_FOLD: case SL_MAP: default: fprintf(stderr,"UNKNOWN OPERATION %d (%s)\n",op,sx->list->val); return NULL; }; return NULL; } sexp_t *slisp_eval(sexp_t *sx) { slisp_store_t *store = NULL; sexp_t *ret = NULL; store = init_store(); ret = _slisp_eval(copy_sexp(sx),store); destroy_store(store); return ret; } sfsexp-1.4.1/examples/slisp/OLD/slisp_store.c000066400000000000000000000100341440725250000211220ustar00rootroot00000000000000/** * implementation of a primitive store for slisp */ #include #include #include #include "slisp_store.h" /** * set_variable(name,sx,store) * * Bind the name to the given s-expression in the store. */ void set_variable(char *name, sexp_t *sx, slisp_store_t *store) { varmap_t *prev, *v, *tmpv; /* paranoia */ assert(store != NULL); assert(sx != NULL); assert(name != NULL); #ifdef _DEBUG_ fprintf(stderr,"[STORE]: SET %s.\n",name); #endif /* _DEBUG_ */ prev = NULL; v = store->vmap; while (v != NULL) { if (strcmp(name,v->vname) == 0) { destroy_sexp(v->value); v->value = sx; } else { /* move on, remember the last varmap we visited */ prev = v; v = v->next; } } /* at this point we know the name we're storing wasn't previously bound */ /* allocate a varmap element */ tmpv = (varmap_t *)malloc(sizeof(varmap_t)); assert(tmpv != NULL); /* no next */ tmpv->next = NULL; /* save the s-expression */ tmpv->value = sx; /* save the name */ strcpy(tmpv->vname,name); /* if prev == NULL, then the store had no variables bound, so this is the first. otherwise, attach this vmap to the previous one looked at. */ if (prev == NULL) store->vmap = tmpv; else prev->next = tmpv; } /** * get_variable(name,store) * * find the named variable in the store and return it. if it isn't bound, * return NULL. */ sexp_t *get_variable(char *name, slisp_store_t *store, int max_depth) { varmap_t *v,*tv; sexp_t *sx = NULL; assert(store != NULL); assert(name != NULL); #ifdef _DEBUG_ fprintf(stderr,"[STORE]: GET %s.\n",name); #endif /* _DEBUG_ */ v = store->vmap; while (v != NULL) if (strcmp(name,v->vname) == 0) { tv = v; while (tv->entered_depth > max_depth && tv->shadowed != NULL) tv = tv->shadowed; sx = copy_sexp(tv->value); break; } else v = v->next; return sx; } /** * dump_store(s) * * for debugging : dump the current contents of the store. */ void dump_store(slisp_store_t *s) { varmap_t *v1; char sxbuf[BUFSIZ]; fprintf(stderr,"====> DUMPING STORE <====\n"); if (s == NULL) { fprintf(stderr,"Store is null.\n"); return; } v1 = s->vmap; while (v1 != NULL) { print_sexp(sxbuf,BUFSIZ,v1->value); fprintf(stderr,"[%s]%d :: 0x%x = \"%s\"\n", v1->vname,v1->entered_depth, (unsigned int)v1->value,sxbuf); v2 = v1->shadowed; indent = 1; while (v2 != NULL) { for(i=0;ivalue); fprintf(stderr,"[%s]%d :: 0x%x = \"%s\"\n", v2->vname,v2->entered_depth, (unsigned int)v2->value,sxbuf); v2 = v2->shadowed; indent++; } v1 = v1->next; } } /** * init_store() * * create a new empty store and return it. */ slisp_store_t *init_store() { slisp_store_t *s = (slisp_store_t*)malloc(sizeof(slisp_store_t)); assert(s != NULL); s->vmap = NULL; return s; } slisp_store_t *copy_store(slisp_store_t *store) { slisp_store_t *new_store; varmap_t *vm,*nvm,*prev; if (store == NULL) return NULL; new_store = (slisp_store_t *)malloc(sizeof(slisp_store_t)); assert(new_store != NULL); vm = store->vmap; prev = NULL; while (vm != NULL) { nvm = (varmap_t *)malloc(sizeof(varmap_t)); assert(nvm != NULL); strcpy(nvm->vname,vm->vname); nvm->value = copy_sexp(vm->value); nvm->next = NULL; if (prev != NULL) prev->next = nvm; else new_store->vmap = nvm; prev = nvm; vm = vm->next; } return new_store; } /** * destroy_varmap(v) * * free a varmap and recursively destroy those that it points at. */ void destroy_varmap(varmap_t *v) { if (v == NULL) return; destroy_varmap(v->next); v->next = NULL; destroy_sexp(v->value); free(v); } /** * destroy_store(s) * * free the memory used by the store. */ void destroy_store(slisp_store_t *s) { assert(s != NULL); destroy_varmap(s->vmap); s->vmap = NULL; free(s); } sfsexp-1.4.1/examples/slisp/OLD/slisp_store.h000066400000000000000000000011571440725250000211350ustar00rootroot00000000000000#ifndef __SLISP_STORE_H__ #define __SLISP_STORE_H__ #include "sexp.h" typedef struct slisp_varmap { char vname[255]; sexp_t *value; struct slisp_varmap *next; } varmap_t; typedef struct slisp_store { varmap_t *vmap; } slisp_store_t; void dump_store(slisp_store_t *s); void set_variable(char *name, sexp_t *sx, slisp_store_t *store); sexp_t *get_variable(char *name, slisp_store_t *store, int max_depth); slisp_store_t *init_store(); void destroy_varmap(varmap_t *v); void destroy_store(slisp_store_t *s); void enter_scope(slisp_store_t *s); void exit_scope(slisp_store_t *s); #endif /* __SLISP_STORE_H__ */ sfsexp-1.4.1/examples/slisp/slisp.h000066400000000000000000000033151440725250000173010ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * main header to the slisp interpreter - this exposes eval. */ #ifndef __SLISP_H__ #define __SLISP_H__ #include "sexp.h" #ifdef __cplusplus extern "C" { #endif sexp_t *slisp_eval(sexp_t *sx); #ifdef __cplusplus } #endif #endif /* __SLISP_H__ */ sfsexp-1.4.1/examples/slisp/slisp_driver.c000066400000000000000000000051461440725250000206530ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * testing harness driver for slisp - not intended for use outside * development of slisp itself (and possibly as an educational aid for * users who wish to embed SLISP in their own code.) * * -mjs 8.2003 */ #include "slisp.h" #include "sexp.h" #include "slisp_memman.h" #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include int main(int argc, char **argv) { char buf[BUFSIZ], outbuf[BUFSIZ]; sexp_t *in, *out; sexp_iowrap_t *iow; int fd; reset_memory_counters(); fd = open("test_expressions",O_RDONLY); iow = init_iowrap(fd); in = read_one_sexp(iow); while (in != NULL) { print_sexp(buf,BUFSIZ,in); out = slisp_eval(in); if (out != NULL) { print_sexp(outbuf,BUFSIZ,out); printf("%s ==> %s\n",buf,outbuf); } else { printf("%s ==> ERROR\n",buf); } destroy_sexp(in); if (out != NULL) { destroy_sexp(out); FREE_CHECKPOINT(out); } report_memory_counters(); reset_memory_counters(); in = read_one_sexp(iow); } destroy_iowrap(iow); exit(EXIT_SUCCESS); } sfsexp-1.4.1/examples/slisp/slisp_env.c000066400000000000000000000070771440725250000201550ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /* implementation of slisp environment */ #include "slisp_env.h" #include #include #include slisp_env_t *enter_scope(slisp_env_t *cur, int numvars) { slisp_env_t *n; n = (slisp_env_t *)malloc(sizeof(slisp_env_t)); assert(n != NULL); if (cur == NULL) { n->depth = 0; n->parent = NULL; } else { n->parent = cur; n->depth = cur->depth + 1; } assert(numvars >= 0); n->numvars = n->numfree = numvars; if (numvars > 0) { n->varnames = (char **)calloc(numvars,sizeof(char *)); assert(n->varnames != NULL); n->bindings = (sexp_t **)calloc(numvars,sizeof(sexp_t *)); assert(n->bindings != NULL); } n->body = NULL; return n; } slisp_env_t *exit_scope(slisp_env_t *cur) { slisp_env_t *p; assert(cur != NULL); p = cur->parent; /** put code to free contents of struct here */ free(cur); return p; } slisp_env_t *add_varname(char *name, slisp_env_t *cur) { int idx, slen; assert(cur != NULL); assert(name != NULL); /* index that this value goes */ idx = cur->numvars - (cur->numvars - cur->numfree); slen = strlen(name); cur->varnames[idx] = (char *)malloc(sizeof(char)*(slen + 1)); strcpy(cur->varnames[idx],name); cur->varnames[slen] = '\0'; return cur; } slisp_env_t *bind_variable(sexp_t *sx, slisp_env_t *cur) { int idx; assert(sx != NULL); assert(cur != NULL); if (cur->numfree == 0) { fprintf(stderr,"ERROR: attempting to bind a variable in an env with no free variables!\n"); return cur; } idx = cur->numvars - (cur->numvars - cur->numfree); cur->bindings[idx] = sx; cur->numfree--; return cur; } slisp_env_t *set_body(sexp_t *b, slisp_env_t *cur) { assert(b != NULL); assert(cur != NULL); cur->body = b; return cur; } sexp_t *lookup_binding(char *name, slisp_env_t *cur) { int i; assert(name != NULL); assert(cur != NULL); for (i = 0; i < cur->numvars; i++) if (strcmp(name,cur->varnames[i]) == 0) return cur->bindings[i]; /* here means not found. try parent. */ if (cur->parent != NULL) return lookup_binding(name,cur->parent); return NULL; } sfsexp-1.4.1/examples/slisp/slisp_env.h000066400000000000000000000051611440725250000201520ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * implementation of environments for SLISP interpreter. necessary for * handling lambda. * * -mjs 8/2003 */ #ifndef __SLISP_ENV_H__ #define __SLISP_ENV_H__ #include "sexp.h" typedef struct slisp_env_struct { /* depth this environment is nested */ int depth; /* number of free variables */ int numfree; /* number of total variables */ int numvars; /* names of variables, in reverse order. positions numvars-numfree -> * numvars-1 are bound variables. */ char **varnames; /* bindings for bound variables. each binding matches the name in * position. */ sexp_t **bindings; /* body of the expression */ sexp_t *body; /* environment containing this one */ struct slisp_env_struct *parent; } slisp_env_t; #ifdef __cplusplus extern "C" { #endif slisp_env_t *enter_scope(slisp_env_t *cur, int numvars); slisp_env_t *exit_scope(slisp_env_t *cur); slisp_env_t *add_varname(char *name, slisp_env_t *cur); slisp_env_t *bind_variable(sexp_t *sx, slisp_env_t *cur); slisp_env_t *set_body(sexp_t *b, slisp_env_t *cur); sexp_t *lookup_binding(char *name, slisp_env_t *cur); #ifdef __cplusplus } #endif #endif /* __SLISP_ENV_H__ */ sfsexp-1.4.1/examples/slisp/slisp_eval.c000066400000000000000000000316511440725250000203070ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ #include "slisp.h" #include "slisp_util.h" #include "slisp_env.h" #include "slisp_memman.h" #include #include #include #include sexp_t *_slisp_eval(sexp_t *s, slisp_env_t *e); sexp_t *slisp_eval(sexp_t *sx) { /* return _slisp_eval(deep_copy_sexp(sx),NULL); */ return _slisp_eval(sx,NULL); } sexp_t *new_sexp_bool(int i) { sexp_t *sx; sx = (sexp_t *)malloc(sizeof(sexp_t)); assert(sx != NULL); MEM_CHECKPOINT(sx); sx->ty = SEXP_VALUE; sx->aty = SEXP_BASIC; sx->val_allocated = 2; sx->val_used = 2; sx->val = (char *)malloc(sizeof(char)*2); assert(sx->val != NULL); if (i == 1) sx->val[0] = 't'; else sx->val[0] = 'f'; sx->val[1] = '\0'; return sx; } #define SX_TRUE new_sexp_bool(1) #define SX_FALSE new_sexp_bool(0) #define SX_NIL new_sexp_atom("nil",4,SEXP_BASIC) #ifdef _ENABLE_WARNINGS_ #define WARNING(str) fprintf(stderr,"WARNING::%s\n",(str)); #else #define WARNING(str) { } #endif #define DEBUG(str) fprintf(stderr,"[%s:%d]::%s\n",__FILE__,__LINE__,(str)); /******** ** ** don't look at the macros below. they may cause illness, or an urge ** to wring my neck. neither are recommended outcomes. ** **/ /** typeless comparison operator. prevent duplication of code for SL_??? operators for each supported type. **/ #define COMPARE_OPERATOR(a,b,op) { switch((op)) { case SL_EQ: if ((a) == (b)) return SX_TRUE; else return SX_FALSE; break; case SL_NE: if ((a) != (b)) return SX_TRUE; else return SX_FALSE; case SL_GT: if ((a) > (b)) return SX_TRUE; else return SX_FALSE; case SL_LT: if ((a) < (b)) return SX_TRUE; else return SX_FALSE; case SL_GEQ: if ((a) >= (b)) return SX_TRUE; else return SX_FALSE; case SL_LEQ: if ((a) <= (b)) return SX_TRUE; else return SX_FALSE; default: break;} } /** typeless arithmetic operator **/ #define ARITH_OPERATOR(a,b,c,op) { switch((op)) { case SL_PLUS: (c)=(a)+(b); break; case SL_MINUS: (c)=(a)-(b); break; case SL_MULT: (c)=(a)*(b); break; case SL_DIVIDE: (c)=(a)/(b); break; case SL_EXP: (c)=pow((double)(a),(double)(b)); break; default: break; } } /** ** Ok - you can look again. ** ********/ /** evaluate if operations **/ sexp_t *eval_conditional(sexp_t *sx, slisp_env_t *env) { sexp_t *tresult, *test, *tclause, *eclause; test = sx->list->next; if (test == NULL) { DEBUG("bad if arguments."); return NULL; } tclause = test->next; if (tclause == NULL) { DEBUG("bad then clause in if"); return NULL; } eclause = tclause->next; /* this is optional. if it is null, return NULL. */ tresult = _slisp_eval(test,env); if (tresult == NULL) { DEBUG("conditional test evaluation error."); return NULL; } if (tresult->aty != SEXP_VALUE) { DEBUG("conditional test evaluated to non-primitive type."); return NULL; } if (tresult->val_allocated > 1 && tresult->val[1] == '\0') { if (tresult->val[0] == 't') { destroy_sexp(tresult); FREE_CHECKPOINT(tresult); return _slisp_eval(tclause,env); } else if (tresult->val[0] == 'f') { destroy_sexp(tresult); FREE_CHECKPOINT(tresult); if (eclause == NULL) return SX_NIL; else return _slisp_eval(eclause,env); } else { DEBUG("conditional test evaluated to non-boolean value."); return NULL; } } DEBUG("unknown error in conditional evaluation."); return NULL; } /** evaluate binary operators **/ sexp_t *eval_binop(sexp_t *sx, slisp_op_t op, slisp_env_t *env) { sexp_t *operator, *a1, *a2; slisp_val_t t1, t2; int i1, i2; double f1, f2; int reeval = 0x00; operator = sx->list; a1 = operator->next; if (a1 == NULL) { DEBUG("first argument of binary operator undefined.\n"); return NULL; } a2 = a1->next; if (a2 == NULL) { DEBUG("second argument of binary operator undefined.\n"); return NULL; } t1 = derive_type(a1); t2 = derive_type(a2); if (t1 == SL_SEXP) { a1 = _slisp_eval(a1,env); reeval |= 0x01; t1 = derive_type(a1); } if (t2 == SL_SEXP) { a2 = _slisp_eval(a2,env); reeval |= 0x02; t2 = derive_type(a2); } if (t1 != t2) { WARNING("comparison between incompatible types always false."); return SX_FALSE; } else { switch (t1) { case SL_INT: i1 = atoi(a1->val); i2 = atoi(a2->val); if (reeval != 0) { if ((reeval & 0x01) == 0x01) { destroy_sexp(a1); FREE_CHECKPOINT(a1); } if ((reeval & 0x02) == 0x02) { destroy_sexp(a2); FREE_CHECKPOINT(a2); } } COMPARE_OPERATOR(i1,i2,op); break; case SL_FLOAT: f1 = strtod(a1->val,NULL); f2 = strtod(a2->val,NULL); if (reeval != 0) { if ((reeval & 0x01) == 0x01) { destroy_sexp(a1); FREE_CHECKPOINT(a1); } if ((reeval & 0x02) == 0x02) { destroy_sexp(a2); FREE_CHECKPOINT(a2); } } COMPARE_OPERATOR(f1,f2,op); break; case SL_STRING: i1 = strcmp(a1->val,a2->val); i2 = 0; if (reeval != 0) { if ((reeval & 0x01) == 0x01) { destroy_sexp(a1); FREE_CHECKPOINT(a1); } if ((reeval & 0x02) == 0x02) { destroy_sexp(a2); FREE_CHECKPOINT(a2); } } COMPARE_OPERATOR(i1,i2,op); break; case SL_SEXP: WARNING("comparison between sexp elements always false."); return SX_FALSE; break; default: DEBUG("never should be here!!!"); } } return SX_FALSE; } /** evaluate binary arithmetic **/ sexp_t *eval_binarith(sexp_t *sx, slisp_op_t op, slisp_env_t *env) { sexp_t *operator, *a1, *a2, *retval; slisp_val_t t1, t2; int i1, i2, ires; double f1, f2, fres; char cbuf[30]; int reeval = 0; operator = sx->list; a1 = operator->next; if (a1 == NULL) { DEBUG("first argument of binary operator undefined.\n"); return NULL; } a2 = a1->next; if (a2 == NULL) { DEBUG("second argument of binary operator undefined.\n"); return NULL; } t1 = derive_type(a1); t2 = derive_type(a2); if (t1 == SL_SEXP) { a1 = _slisp_eval(a1,env); t1 = derive_type(a1); reeval |= 0x01; } if (t2 == SL_SEXP) { a2 = _slisp_eval(a2,env); t2 = derive_type(a2); reeval |= 0x02; } if (t1 == SL_STRING || t2 == SL_STRING) { DEBUG("cannot perform arithmetic on strings."); /* idiot */ return NULL; } if (t1 == SL_SEXP || t1 == SL_INVALID || t2 == SL_SEXP || t2 == SL_INVALID) { DEBUG("invalid arguments for arithmetic operator."); return NULL; } if (t1 == t2 && t1 == SL_INT) { i1 = atoi(a1->val); i2 = atoi(a2->val); if (reeval != 0) { if ((reeval & 0x01) == 0x01) { destroy_sexp(a1); FREE_CHECKPOINT(a1); } if ((reeval & 0x02) == 0x02) { destroy_sexp(a2); FREE_CHECKPOINT(a2); } } ARITH_OPERATOR(i1,i2,ires,op); sprintf(cbuf,"%d",ires); retval = new_sexp_atom(cbuf,strlen(cbuf),SEXP_BASIC); MEM_CHECKPOINT(retval); return retval; } else { f1 = strtod(a1->val,NULL); f2 = strtod(a2->val,NULL); if (reeval != 0) { if ((reeval & 0x01) == 0x01) { destroy_sexp(a1); FREE_CHECKPOINT(a1); } if ((reeval & 0x02) == 0x02) { destroy_sexp(a2); FREE_CHECKPOINT(a2); } } ARITH_OPERATOR(f1,f2,fres,op); sprintf(cbuf,"%f",fres); retval = new_sexp_atom(cbuf,strlen(cbuf), SEXP_BASIC); MEM_CHECKPOINT(retval); return retval; } DEBUG("unknown error evaluating arithmetic operator."); return NULL; } sexp_t *eval_listop(sexp_t *sx, slisp_op_t op, slisp_env_t *env) { sexp_t *retval, *l1, *l2; if (op == SL_CAR || op == SL_CDR) { l1 = sx->list->next; if (l1 == NULL) { DEBUG("invalid argument for car/cdr"); return NULL; } l1 = _slisp_eval(l1,env); if (l1->ty == SEXP_LIST || (l1->ty == SEXP_VALUE && l1->aty == SEXP_SQUOTE)) { if (l1->ty == SEXP_VALUE && l1->aty == SEXP_SQUOTE) { l1 = parse_sexp(l1->val,l1->val_used); if (l1->ty != SEXP_LIST) { DEBUG("car/cdr squote eval'd to non-list."); return NULL; } } if (op == SL_CAR) { l2 = l1->list->next; l1->list->next = NULL; retval = deep_copy_sexp(l1->list); l1->list->next = l2; MEM_CHECKPOINT(retval); return retval; } else { assert(l1->list != NULL); retval = deep_copy_sexp(l1->list->next); MEM_CHECKPOINT(retval); return retval; } } else { DEBUG("car/cdr argument must evaluate to a list."); return NULL; } } else { } DEBUG("unknown error in eval_listop"); return NULL; } sexp_t *_slisp_eval(sexp_t *sx, slisp_env_t *env) { sexp_t *retval = NULL; slisp_op_t op; sexp_t *tmpsx; double d; /* ??? */ char cbuf[30]; int reeval = 0; assert(sx != NULL); /* check type of element. if it is an atom, return it. otherwise, treat lists as (function arg0 arg1 ... argn) */ if (sx->ty == SEXP_VALUE) { retval = deep_copy_sexp(sx); MEM_CHECKPOINT(retval); return retval; } /* tokenize head of list */ op = tokenize(sx->list); switch (op) { case SL_EQ: case SL_GT: case SL_LT: case SL_NE: case SL_GEQ: case SL_LEQ: /** binary operator **/ return eval_binop(sx,op,env); break; case SL_NOT: /** unary operator **/ tmpsx = sx->list->next; if (tmpsx == NULL) { DEBUG("argument error for unary not operator."); return NULL; } if (tmpsx->ty == SEXP_LIST) { reeval = 1; tmpsx = _slisp_eval(tmpsx,env); if (tmpsx->ty == SEXP_LIST) { DEBUG("cannot evaluate not operator on list argument."); return NULL; } } if (tmpsx->val_allocated > 1 && tmpsx->val[1] == '\0') { if (tmpsx->val[0] == 't') { if (reeval == 1) { destroy_sexp(tmpsx); FREE_CHECKPOINT(tmpsx); } return SX_FALSE; } else { if (tmpsx->val[0] == 'f') { if (reeval == 1) { destroy_sexp(tmpsx); FREE_CHECKPOINT(tmpsx); } return SX_TRUE; } else { DEBUG("invalid argument for not operator."); if (reeval == 1) { destroy_sexp(tmpsx); FREE_CHECKPOINT(tmpsx); } return NULL; } } } DEBUG("error evaluating not operator."); return NULL; break; case SL_PLUS: case SL_MINUS: case SL_MULT: case SL_DIVIDE: case SL_EXP: /** binary arithmetic **/ return eval_binarith(sx,op,env); break; case SL_SQRT: /** unary arithmetic **/ tmpsx = sx->list->next; if (tmpsx == NULL) { DEBUG("missing argument for sqrt."); return NULL; } switch (derive_type(tmpsx)) { case SL_INT: case SL_FLOAT: d = sqrt(strtod(tmpsx->val,NULL)); sprintf(cbuf,"%f",d); tmpsx = new_sexp_atom(cbuf,30, SEXP_BASIC); return tmpsx; default: DEBUG("bad type in sqrt"); return NULL; } DEBUG("unknown error in eval for sqrt."); return NULL; break; case SL_CONS: case SL_CDR: case SL_CAR: /** list stuff **/ return eval_listop(sx,op,env); break; case SL_FOLD: case SL_MAP: /** function application over lists **/ break; case SL_SORT: break; case SL_IF: return eval_conditional(sx,env); break; case SL_LAMBDA: break; default: fprintf(stderr,"EVAL: unknown token\n"); } return retval; } sfsexp-1.4.1/examples/slisp/slisp_memman.c000066400000000000000000000116351440725250000206320ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ #include "slisp_memman.h" #include #include #include #include #ifndef __DISABLE_MEMMAN__ /* reference counting - used for debugging, disabled for production build */ static unsigned int malloc_count, free_count; static struct allocated_memory *mem_allocated; #endif #ifdef __DISABLE_MEMMAN__ #define reset_memory_counters() {/*'da void*/} #else void reset_memory_counters() { struct allocated_memory *tmp; malloc_count = free_count = 0; if (mem_allocated != NULL) { for (tmp = mem_allocated; tmp != NULL; tmp = tmp->next) { free(tmp->filename); free(tmp); } mem_allocated = NULL; } } #endif #ifdef __DISABLE_MEMMAN__ #define report_memory_counters() { /* nada */ } #else void report_memory_counters() { struct allocated_memory *tmp; int i; if (malloc_count == free_count && mem_allocated == NULL) { return; } for (i=0;i<72;i++) fprintf(stderr,"="); fprintf(stderr,"\n"); fprintf(stderr,"MALLOCS/FREES = [%d / %d]\n",malloc_count,free_count); tmp = mem_allocated; if (tmp != NULL) { for (; tmp != NULL; tmp = tmp->next) { fprintf(stderr,"ADDRESS=0x%x :: ALLOCATED %s:%d\n",tmp->address, tmp->filename,tmp->line); } } for (i=0;i<72;i++) fprintf(stderr,"="); fprintf(stderr,"\n"); fprintf(stderr,"\n"); } #endif #ifdef __DISABLE_MEMMAN__ #define add_mem_checkpoint(a,b,c) { /* nuttin' */ } #else void add_mem_checkpoint(unsigned int addr, unsigned int line, char *fname) { struct allocated_memory *tmp = mem_allocated; if (tmp == NULL) { mem_allocated = (struct allocated_memory *)malloc(sizeof(struct allocated_memory)); mem_allocated->next = mem_allocated->prev = NULL; mem_allocated->line = line; mem_allocated->address = addr; mem_allocated->filename = (char *)malloc(sizeof(char)*(strlen(fname) + 1)); assert(mem_allocated->filename != NULL); strcpy(mem_allocated->filename,fname); } else { for ( ; tmp->next != NULL; tmp = tmp->next) { } tmp->next = (struct allocated_memory *)malloc(sizeof(struct allocated_memory)); assert(tmp->next != NULL); tmp->next->prev = tmp; tmp = tmp->next; tmp->next = NULL; tmp->address = addr; tmp->line = line; tmp->filename = (char *)malloc(sizeof(char)*(strlen(fname) + 1)); assert(tmp->filename != NULL); strcpy(tmp->filename,fname); } malloc_count++; } #endif #ifdef __DISABLE_MEMMAN__ #define free_mem_checkpoint(a,b,c) { /* zilch */ } #else void free_mem_checkpoint(void *ptr, int line, char *filename) { unsigned int addr = (unsigned int)ptr; struct allocated_memory *tmp = mem_allocated; if (tmp == NULL) { fprintf(stderr,"WARNING! Attempting to deallocate memory not recorded as allocated.\n"); fprintf(stderr," Address = 0x%x\n",addr); fprintf(stderr," Checkpoint = %s:%d\n",filename,line); } for ( ; tmp != NULL; tmp = tmp->next) { if (tmp->address == addr) break; } if (tmp == NULL) { fprintf(stderr,"WARNING! Attempting to deallocate memory not recorded as allocated.\n"); fprintf(stderr," Address = 0x%x\n",addr); fprintf(stderr," Checkpoint = %s:%d\n",filename,line); } else { if (tmp->prev != NULL) tmp->prev->next = tmp->next; if (tmp->next != NULL) tmp->next->prev = tmp->prev; free(tmp->filename); if (tmp == mem_allocated && tmp->next == NULL) mem_allocated = NULL; free(tmp); free_count++; } } #endif sfsexp-1.4.1/examples/slisp/slisp_memman.h000066400000000000000000000045371440725250000206420ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * memory management related stuff for slisp * based on Erik Hendriks' malloc debugging stuff that matt can't find now */ #ifndef __SLISP_MEMMAN_H__ #define __SLISP_MEMMAN_H__ /* structures for tracking leaks */ struct allocated_memory { unsigned int address; unsigned int line; char *filename; struct allocated_memory *prev; struct allocated_memory *next; }; #ifdef __cplusplus extern "C" { #endif void reset_memory_counters(); void report_memory_counters(); void add_mem_checkpoint(unsigned int addr, unsigned int line, char *fname); void free_mem_checkpoint(void *ptr, int line, char *fname); #ifdef __cplusplus } #endif /* macro to hide uglier call with line and file stuff */ #define MEM_CHECKPOINT(ptr) add_mem_checkpoint((unsigned int)(ptr),__LINE__,__FILE__); #define FREE_CHECKPOINT(ptr) free_mem_checkpoint((ptr),__LINE__,__FILE__); #endif /* __SLISP_MEMMAN_H__ */ sfsexp-1.4.1/examples/slisp/slisp_util.c000066400000000000000000000122561440725250000203350ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * utility routines of some use to the slisp implementation, removed from * the eval source file to unclutter things. also, these routines may * prove useful enough in a general sense that they may be migrated into * the main s-expression library code base in the future. * * -mjs 8.2003 */ #include "slisp_util.h" #include #include #include /** * */ sexp_t *deep_copy_sexp(sexp_t *sx) { sexp_t *c_sx; if (sx == NULL) return NULL; c_sx = (sexp_t *)malloc(sizeof(sexp_t)); assert(c_sx != NULL); c_sx->ty = sx->ty; c_sx->aty = sx->aty; if (sx->ty == SEXP_VALUE) { switch(sx->aty) { case SEXP_BASIC: case SEXP_SQUOTE: case SEXP_DQUOTE: c_sx->val_used = sx->val_used; c_sx->val_allocated = sx->val_allocated; c_sx->val = (char *)malloc(sizeof(char)*c_sx->val_allocated); assert(c_sx->val != NULL); memcpy(c_sx->val,sx->val,c_sx->val_used); c_sx->bindata = NULL; c_sx->binlength = 0; break; case SEXP_BINARY: c_sx->val_used = c_sx->val_allocated = 0; c_sx->val = NULL; c_sx->binlength = sx->binlength; c_sx->bindata = (char *)malloc(sizeof(char)*c_sx->binlength); assert(c_sx->bindata != NULL); memcpy(c_sx->bindata,sx->bindata,sx->binlength); break; default: fprintf(stderr,"ERROR: Unknown atom type in SEXP_VALUE element.\n"); break; } } else { /* this is a list - so null out all atom data pointers, set counts to zero, and deal with the list/next fields. if someone was trying to be clever and was hiding stuff in these fields, they're screwed. :) */ c_sx->val = NULL; c_sx->val_allocated = c_sx->val_used = 0; c_sx->binlength = 0; c_sx->bindata = NULL; c_sx->list = deep_copy_sexp(sx->list); c_sx->next = deep_copy_sexp(sx->next); } return c_sx; } /** * Given a sexp_t element, return the token that it represents. */ slisp_op_t tokenize(sexp_t *sx) { if (sx->ty != SEXP_VALUE) { return SL_UNKNOWN; } if (strcmp("+",sx->val) == 0) return SL_PLUS; else if (strcmp("-",sx->val) == 0) return SL_MINUS; else if (strcmp("*",sx->val) == 0) return SL_MULT; else if (strcmp("/",sx->val) == 0) return SL_DIVIDE; else if (strcmp("^",sx->val) == 0) return SL_EXP; else if (strcmp("=",sx->val) == 0) return SL_EQ; else if (strcmp(">",sx->val) == 0) return SL_GT; else if (strcmp("<",sx->val) == 0) return SL_LT; else if (strcmp("<=",sx->val) == 0) return SL_LEQ; else if (strcmp(">=",sx->val) == 0) return SL_GEQ; else if (strcmp("<>",sx->val) == 0) return SL_NE; else if (strcmp("if",sx->val) == 0) return SL_IF; else if (strcmp("not",sx->val) == 0) return SL_NOT; else if (strcmp("cdr",sx->val) == 0) return SL_CDR; else if (strcmp("car",sx->val) == 0) return SL_CAR; else if (strcmp("map",sx->val) == 0) return SL_MAP; else if (strcmp("cons",sx->val) == 0) return SL_CONS; else if (strcmp("fold",sx->val) == 0) return SL_FOLD; else if (strcmp("sort",sx->val) == 0) return SL_SORT; else if (strcmp("sqrt",sx->val) == 0) return SL_SQRT; else if (strcmp("lambda",sx->val) == 0) return SL_LAMBDA; return SL_UNKNOWN; } /** * Given an expression element, try to derive the type. */ slisp_val_t derive_type(sexp_t *sx) { slisp_val_t ty = SL_INT; char *p; if (sx->ty == SEXP_LIST) return SL_SEXP; p = sx->val; if (p == NULL) return SL_INVALID; /* only one minus, first character, is allowed while still remaining a numeric type. */ if (p[0] == '-') p++; while (p[0] != '\0' && ty != SL_STRING) { if (p[0] == '.') { if (ty == SL_INT) ty = SL_FLOAT; else ty = SL_STRING; } else if (p[0] > '9'|| p[0] < '0') ty = SL_STRING; p++; } return ty; } sfsexp-1.4.1/examples/slisp/slisp_util.h000066400000000000000000000050741440725250000203420ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ /** * utility functions and other relevant stuff for making slisp work */ #ifndef __SLISP_UTIL_H__ #define __SLISP_UTIL_H__ #include "sexp.h" /** * tokens for operations */ typedef enum { /* binary logical operations */ SL_EQ, SL_GT, SL_LT, SL_NE, SL_GEQ, SL_LEQ, /* unary logical operations */ SL_NOT, /* mathematical operations, binary */ SL_PLUS, SL_MINUS, SL_MULT, SL_DIVIDE, SL_EXP, /* mathematical operations, unary */ SL_SQRT, /* list construction/separation */ SL_CONS, SL_CDR, SL_CAR, /* function application over lists */ SL_FOLD, SL_MAP, /* list sorting */ SL_SORT, /* conditional */ SL_IF, /* lambda */ SL_LAMBDA, /* UNKNOWN : ERROR */ SL_UNKNOWN } slisp_op_t; /* * types for expression elements */ typedef enum { SL_INT, SL_FLOAT, SL_STRING, SL_SEXP, SL_INVALID } slisp_val_t; #ifdef __cplusplus extern "C" { #endif sexp_t *deep_copy_sexp(sexp_t *sx); slisp_op_t tokenize(sexp_t *sx); slisp_val_t derive_type(sexp_t *sx); #ifdef __cplusplus } #endif #endif /* __SLISP_UTIL_H__ */ sfsexp-1.4.1/examples/slisp/test_expressions000066400000000000000000000007131440725250000213410ustar00rootroot00000000000000(= 4 4) (= 5 4) (> 4.0 54.0) (= 4 s) (= aaa bbb) (= aaa aaa) (< aaa bbb) (= (= 4 4) (> 5 4)) (= (> matt zzzzz) (= foo foo)) (not (= 3 3)) (not (= (> matt zzzzz) (= foo foo))) (not 4) (if (= 4 4) 42 666) (if (= pig cow) 42 666) (if (= pig cow) 42) (if (= pig pig) '(42)) (if (= 4.0 4.0) (42)) (+ 4 4) (+ 5.0 6.5) (- 4 5) (^ 2 3) (^ 3 2) (^ 3 (+ 2 1)) (= (^ 2 3) (^ 3 2)) (sqrt 4) (sqrt 9) (sqrt 10) (sqrt 11.4) (sqrt dog) (car '(a b)) (cdr '(a b)) (car (a b)) sfsexp-1.4.1/examples/testrc000066400000000000000000000001731440725250000160720ustar00rootroot00000000000000( (parameter1 (some data here)) (unusedparam (this is unused and will be ignored)) (parameter2 ("some \"other" data)) ) sfsexp-1.4.1/examples/vis.in000066400000000000000000000001771440725250000160000ustar00rootroot00000000000000; ; example input for sexpvis sample code ; ( (this (is a nested) list) (and this "has a dquote" in it) '(squote here) ) sfsexp-1.4.1/python/000077500000000000000000000000001440725250000143455ustar00rootroot00000000000000sfsexp-1.4.1/python/COPYING000066400000000000000000000431271440725250000154070ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. sfsexp-1.4.1/python/README.txt000066400000000000000000000014721440725250000160470ustar00rootroot00000000000000pysexp : python bindings for libsexp ------------------------------------ Original version contributed by Steve James (pyro@linuxlabs.com), Nov. 2004 1.0 BUILDING ============ The python bindings for the library, like ruby, are not built by default when the main library is built. To build the library, first make sure that the main library has been built and libsexp is in ../src. Next, type % python setup.py build to build the shared-object used by Python for the pysexp extension module. Distutils (setup.py) makes building extensions portable, removing the need to worry about things like build flags, assembling shared libraries on arbitrary platforms, etc... Currently, there is no install or config target for setup.py, but expect this to be added in the future. 2.0 BASIC USAGE =============== Write me. sfsexp-1.4.1/python/TAGS000066400000000000000000000007401440725250000150270ustar00rootroot00000000000000 pysexp.c,453 #define DPRINTF(DPRINTF8,88 #define DPRINTF(DPRINTF10,137 struct sexp_parser_state_t *state;13,172 struct sexp_t *out;14,207 static PyObject *iter_val(19,302 #define Py_OneRef(Py_OneRef32,646 static PyObject *iter_real_list(34,682 static PyObject *iter_list(76,1359 static PyObject *iter(127,2175 static char parse__doc__[141,2347 static PyObject *pysexp_parse(144,2466 static PyMethodDef PySexpMethods[170,2910 void initpysexp(175,3024 test.py,0 sfsexp-1.4.1/python/pysexp.c000066400000000000000000000113341440725250000160430ustar00rootroot00000000000000/***************************************************************************** * * pysexp - A simple python binding to libsexp to translate an S expression * into a complex python data structure * * Copyright 2004, Steven James and * Linux Labs International http://www.linuxlabs.com * * Thanks to Matt Sottile for the small, fast s-expression library * but don't blame him for bugs in the Python binding :-) * * This work is released under the terms of the General Public License version * 2 or later. * ****************************************************************************/ #include #include //#define DEBUG #ifdef DEBUG #include #define DPRINTF( X... ) fprintf(stderr, X) #else #define DPRINTF( X... ) {} #endif struct sexp_parser_state_t *state; struct sexp_t *out; static PyObject *iter(sexp_t *s); static PyObject *iter_list(sexp_t *s); static PyObject *iter_val(sexp_t *s) { PyObject *ret; return PyString_FromString( s->val); } /**************************************************************************** * * Translation functions: These iterate through a parsed S-expression and * translate it into a complex hierarchy of python objects. * * Due to the richer variety of Python objects, a few conventions are adopted. * * Lists containing only one value are stripped: * ( foo ) -> foo * * lists containing 2 items become a dict: * ( foo bar ) -> { foo: bar } * ( foo bar baz ) -> { foo: [bar baz] } * * Lists containing only dicts are merged into a single dict: * ( ( foo 1 ) ( bar 2 ) ( baz 5 6 7 8) ) * -> { foo:1, bar:2, baz:[ 5 6 7 8] } * * ((( foo bar ))) -> { foo:bar } * *****************************************************************************/ // Special list handling // If S has length 1, 'promote' it to a value // If S starts with a value, 'promote' it to a dict. //#define Py_OneRef( x) { fprintf(stderr, "obj: %p, refcnt = %u\n", x, x->ob_refcnt); if(x->ob_refcnt) x->ob_refcnt=2; } #define Py_OneRef( x) Py_DECREF(x) static PyObject *iter_real_list(sexp_t *s) { PyObject *list; PyObject *ret; sexp_t *r = s; char alldict=1; if(!s->next) { if( s->ty == SEXP_LIST) return( iter_list(s->list)); return iter_val(s); } list = PyList_New(0); while(r) { ret = iter(r); if(! PyDict_Check(ret)) alldict = 0; PyList_Append( list, ret); Py_OneRef(ret); r = r->next; } if(alldict) { PyObject *dict, *subdict; int i, count; dict = PyDict_New(); count = PyList_GET_SIZE(list); for(i=0; inext) { if( s->ty == SEXP_LIST) return( iter_list(s->list)); return iter_val(s); } if(s->ty == SEXP_VALUE) { list= PyDict_New(); ret = iter_real_list( s->next); PyDict_SetItemString( list, s->val, ret); Py_OneRef(ret); return list; } list = PyList_New(0); while(r) { ret = iter(r); PyList_Append( list, ret); Py_OneRef(ret); r = r->next; } if(alldict) { PyObject *dict, *subdict; int i, count; dict = PyDict_New(); count = PyList_GET_SIZE(list); for(i=0; ity == SEXP_LIST) ret = iter_list( s->list ); else ret = iter_val( s); return ret; } static char parse__doc__[] = "parse() - Accepts an S-expression in a string, returns a complex Python structure.\n"; static PyObject *pysexp_parse( PyObject *self, PyObject *args) { PyObject *list, *list2; char *in; sexp_t *out; int ret; if(!PyArg_ParseTuple( args, "s", &in)) return; out = parse_sexp( in, strlen(in)); if(!out) { Py_INCREF(Py_None); return Py_None; } DPRINTF("parsing: %s\n", in); list = iter(out); DPRINTF("list = %p\n", list); destroy_sexp(out); return list; } /* functions supporting continuations */ typedef struct ContFind { int handle; sexp_t *sx; struct ContFind *prev; struct ContFind *next; } ContFind_t; typedef struct ContSexpr { int handle; pcont_t *pc; sexp_t *sx; ContFind_t *finds; struct ContSexpr *prev; struct ContSexpr *next; } ContSexpr_t; static PyMethodDef PySexpMethods[] = { {"parse", pysexp_parse, METH_VARARGS, parse__doc__}, {NULL,NULL}, }; void initpysexp(void) { PyObject *m, *d, *i; m = Py_InitModule("pysexp", PySexpMethods); d = PyModule_GetDict(m); } sfsexp-1.4.1/python/pysexp.spec000066400000000000000000000014331440725250000165520ustar00rootroot00000000000000Summary: Python binding for libsexp in cmtools Name: pysexp Version: 1.0 Release: 1 Vendor: Linux Labs http://www.linuxlabs.com License: GPL Group: Development/Libraries/Python Source: %{name}.tar.gz Packager: Steven James BuildRoot: /var/tmp/%{name} Requires: sexpr >= 0.3.2 %description libsexp is a fast efficient parser for S-expressions in C. pysexp is the Python binding. %prep %setup -q -n %{name} %build make %install make DESTDIR=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT %post %preun %files %defattr(-,root,root) /usr/lib/python2.2/site-packages/pysexp.so %changelog * Sat Mar 13 2004 Steven James - Fixed memory leak, made test program much tougher * Thu Mar 11 2004 Steven James - Initial release sfsexp-1.4.1/python/setup.py000066400000000000000000000012721440725250000160610ustar00rootroot00000000000000from distutils.core import setup, Extension module1 = Extension('pysexp', define_macros = [('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], include_dirs = ['../src'], libraries = ['sexp'], library_dirs = ['../src'], sources = ['pysexp.c']) setup (name = 'pysexp', version = '1.0', description = 'Python libsexp interface', author = 'Steve James', author_email = 'pyro@linuxlabs.com', url = 'http://sexpr.sf.net/', long_description = ''' Python interface for s-expression library ''', ext_modules = [module1]) sfsexp-1.4.1/python/test.py000077500000000000000000000046731440725250000157130ustar00rootroot00000000000000#!/usr/bin/env python import os import socket import pysexp sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(( 'localhost', 2709)) sock.send("S\r\n") reader = sock.makefile('rb', 65532) #test = "(n0 (cpuinfo (user 1) (system 1))(avenrun (1)))" test="" line = reader.readline() print "read: %s"%(line) while not line == "\n": test = test + line line = reader.readline() print "read: %s"%(line) print "got: %s"%(test) #test="((n-1 ((cpuinfo (mask 0x1) (node 0x104000a) (user 818850 890795 1408606 342835) (nice 1037 1285 1818 498) (system 645674 170505 306031 73840))(avenrun (mask 0x2) (node 0x104000a) (avenrun 0 82 29 1))(paging (mask 0x4) (node 0x104000a) (pgpgin 10957834) (pgpgout 87122990) (pswpin 63225) (pswpout 92396))(switch (mask 0x8) (node 0x104000a) (switch 500974983))(time (mask 0x10) (node 0x104000a) (timestamp 0x4aef9de7) (jiffies 51869081))(netinfo (mask 0x20) (node 0x104000a) (name lo eth0 eth1 myri0) (rxbytes 1451959993 406853376 1580448122 0) (rxpackets 3250956 2069344 149849254 0) (rxerrs 0 0 0 0) (rxdrop 0 0 0 0) (rxfifo 0 0 0 0) (rxframe 0 0 0 0) (rxcompressed 0 0 0 0) (rxmulticast 0 0 0 0) (txbytes 1451959993 784732193 1533941160 0) (txpackets 3250956 2378754 149890084 0) (txerrs 0 0 0 0) (txdrop 0 0 0 0) (txfifo 0 0 0 0) (txcolls 0 0 0 0) (txcarrier 0 0 0 0) (txcompressed 0 0 0 0))(meminfo (mask 0x40) (node 0x104000a) (total 258150) (free 12378) (buffer 2560) (shared 0) (totalhigh 32624) (freehigh 8018))(swapinfo (mask 0x80) (node 0x104000a) (total 246997) (used 9213) (pagecache 21721))(fsinfo (mask 0x100) (node 0x104000a) (devname rootfs /dev/root /proc usbdevfs none none /dev/hda1 /dev/hda6 /dev/hda5 none) (mountpoint / / proc usb pts shm scratch usr var bpfs) (fstype rootfs ext3 proc usbdevfs devpts tmpfs ext3 ext3 ext3 bpfs) (size 0 482217 0 0 0 129075 101107 16913589 1925167 0) (available 0 190290 0 0 0 129075 86689 312087 1575932 0)))))" #t1 = pysexp.parse( "%s))"%(test) ) t1 = pysexp.parse( test ) print "===========================================================" print t1 print "===========================================================" for node in t1.keys(): print "node: " + node print t1[node] print "-----------------------------------------------" print "=============================================" #print t1['cpuinfo'] print "=============================================" t2 = {} t2['mask'] = 0x20 t2['cpuinfo'] = [ 1, 2, 3, 4] print t2 while(1): t1 = pysexp.parse( test ) sfsexp-1.4.1/ruby/000077500000000000000000000000001440725250000140055ustar00rootroot00000000000000sfsexp-1.4.1/ruby/README.txt000066400000000000000000000003741440725250000155070ustar00rootroot00000000000000Ruby bindings for the s-expression library. An attempt is made to preserve efficiency while providing a natural interface for Ruby programmers. To build: % ruby extconf.rb --with-sexp-lib=../src --with-sexp-include=../src % make -matt (5/26/2003) sfsexp-1.4.1/ruby/Sexp.c000066400000000000000000000267321440725250000151020ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ #include "ruby.h" #include "sexp.h" /** ** below are rudimentary Ruby bindings for the sexp library ** ** Matt Sottile (matt@lanl.gov) / 5.26.2003 **/ VALUE cSexp; /* * enumeration and inferrence routine used to guess what the strings * represent in detail regarding string vs int vs float. */ typedef enum { SVAL_STRING, SVAL_INTEGER, SVAL_REAL, SVAL_NONE } sval_type; /* inferrence routine - about the umpteenth version of this code. never * can remember where it was written the LAST time I wrote it... */ static sval_type infer_sval_type(sexp_t *sx) { char *c; int ishex = 0; int sawdecimal = 0; int isnegative = 0; /* null sx, sx->val, or sx being a list means no type */ if (sx == NULL || sx->val == NULL || sx->ty != SEXP_VALUE) return SVAL_NONE; /* beginning of val string */ c = sx->val; /* start with -? Might be a negative number. */ if (c[0] == '-') { isnegative = 1; c++; } /* start with 0? Might be hex. */ if (c[0] == '0') { c++; /* follow 0 with x or X? Better chance that it is hex */ if (c[0] == 'x' || c[0] == 'X') { /* hex numbers don't start with a minus sign! */ if (isnegative == 1) { return SVAL_STRING; } c++; if ((c[0] >= '0' && c[0] <= '9') || ((c[0] >= 'a' && c[0] <= 'f') || (c[0] >= 'A' && c[0] <= 'F'))) /* starts with 0x and a hex digit. so far, it looks like a hex number */ ishex = 2; else /* string starting with 0x and a non-hex caracter -- must be * a string. */ return SVAL_STRING; } else ishex = 0; } /* loop over each character. so far, we know if sx->val starts like a * hex number or not, and if not, whether or not it might be a negative * number. */ while (c[0] != '\0') { if (ishex == 1) { if (!((c[0] >= '0' && c[0] <= '9') || ((c[0] >= 'a' && c[0] <= 'f') || (c[0] >= 'A' && c[0] <= 'F')))) return SVAL_STRING; } else { /* not hex */ if (c[0] == '.') { if (sawdecimal == 0) sawdecimal = 1; else return SVAL_STRING; /* 2 '.'s mean non-numeric */ } else { if (!(c[0] >= '0' && c[0] <= '9')) { return SVAL_STRING; /* not a decimal digit, and not hex, so... */ } } } c++; } if (ishex == 1) return SVAL_INTEGER; if (sawdecimal == 1) return SVAL_REAL; return SVAL_INTEGER; } /* destructor called by ruby when cleaning up to deal with the sexp_t * stashed away in the object */ static void sexp_rubyfree(void *s) { sexp_t *sx = (sexp_t *)s; destroy_sexp(sx); } /* given a sexp_t, recursively turn it into a ruby array of strings. * This is not sufficient to deal with DQUOTE and SQUOTE atoms. * This needs to be fixed eventually. Likely by storing either: * 1. A second array corresponding to the first of sexp_t types * 2. Replacing string elements in the array(s) with a record type * containing the string and the type. */ static VALUE sexp_to_array(sexp_t *sx, int aggressive_typing) { VALUE a = rb_ary_new(); /* create array */ sexp_t *s = sx; sval_type svt; int i; double d; while (s != NULL) { if (s->ty == SEXP_LIST) { rb_ary_push(a, sexp_to_array(s->list, aggressive_typing)); } else { if (aggressive_typing == 1) { svt = infer_sval_type(s); switch (svt) { case SVAL_INTEGER: i = atoi(s->val); rb_ary_push(a, INT2FIX(i)); break; case SVAL_REAL: d = strtod(s->val,NULL); rb_ary_push(a, rb_float_new(d)); break; case SVAL_NONE: rb_fatal("ERROR: infer_sval_type => SVAL_NONE for array elt.\n"); break; default: rb_ary_push(a, rb_str_new2(s->val)); } } else { /* no aggressive typing - everything is a string */ rb_ary_push(a, rb_str_new2(s->val)); } } s = s->next; } return a; } /* given a string, parse it and create the corresponding ruby object * for the sexp_t that results. */ VALUE sexp_new(VALUE class, VALUE str) { sexp_t *sx; char *ptr; int len; VALUE argv[2]; VALUE td; /* make sure it is a string */ Check_Type(str, T_STRING); /* grab the length and base pointer to the string */ ptr = rb_str2cstr(str, (long *)&len); /* parse the string */ if (len == 0) { sx = NULL; } else { sx = parse_sexp(ptr,len); } /* stash the sexp_t away in the ruby object */ td = Data_Wrap_Struct(class, 0, sexp_rubyfree, sx); /* set arguments to init up - argv[0] is the original string, argv[1] is the array representing it in ruby space. */ argv[0] = str; /* turn the sexp_t into an array */ if (sx == NULL) { argv[1] = rb_ary_new(); /* empty */ } else { if (sx->ty == SEXP_LIST) argv[1] = sexp_to_array(sx->list,1); else argv[1] = sexp_to_array(sx,1); } /* call the ruby initialize method */ rb_obj_call_init(td, 2, argv); /* return the instance of the ruby object */ return td; } /* initialize expects the original string and the array created from * the parsed sexp_t structure. */ static VALUE sexp_init(VALUE self, VALUE str, VALUE ary) { rb_iv_set(self, "@str", str); rb_iv_set(self, "@ary", ary); return self; } /* given an array representing a s-expression, recursively walk it and * string together an equivalent sexp_t representation. This routine * suffers from the same issues mentioned above related to atom * type details. */ static sexp_t *sexp_unparse_array(VALUE val) { sexp_t *sx, *s; VALUE v; char *b; int bs; char buf[32]; /* initialize s to be safe */ s = NULL; /* makes no sense to pass an atom in here... */ Check_Type(val, T_ARRAY); /* create a new list with nothing in it. We know that this is an * array being passed in, so we must start with a list. */ sx = new_sexp_list(NULL); /* pop elements off from the front of the array one at a time */ v = rb_ary_shift(val); while (!NIL_P(v)) { switch (TYPE(v)) { /* array? make recursive call */ case T_ARRAY: if (sx->list == NULL) { s = sexp_unparse_array(v); sx->list = s; } else { s->next = sexp_unparse_array(v); s = s->next; } break; /* int */ case T_FIXNUM: sprintf(buf,"%ld",FIX2LONG(v)); b = buf; bs = strlen(buf); if (sx->list == NULL) { s = new_sexp_atom(b,bs); sx->list = s; } else { s->next = new_sexp_atom(b,bs); s = s->next; } break; /* int */ case T_BIGNUM: sprintf(buf,"%ld",NUM2LONG(v)); b = buf; bs = strlen(buf); if (sx->list == NULL) { s = new_sexp_atom(b,bs); sx->list = s; } else { s->next = new_sexp_atom(b,bs); s = s->next; } break; /* floating point */ case T_FLOAT: /* ick - there is a better way to get b and bs */ sprintf(buf,"%f",NUM2DBL(v)); b = buf; bs = strlen(buf); if (sx->list == NULL) { s = new_sexp_atom(b,bs); sx->list = s; } else { s->next = new_sexp_atom(b,bs); s = s->next; } break; /* string */ case T_STRING: b = rb_str2cstr(v,(long *)&bs); if (sx->list == NULL) { s = new_sexp_atom(b,bs); sx->list = s; } else { s->next = new_sexp_atom(b,bs); s = s->next; } break; default: /* error? */ /* who cares - for now, fatal error - GCC doesn't like it if this bit of the switch is empty... */ rb_fatal("Very bad contents of array!\n"); } /* pop the next */ v = rb_ary_shift(val); } /* return sx */ return sx; } /* unparse the ary representation of the s-expression into a sexp_t and * then into a char *. In the process, replace @str with the new string * and the sx pointer in the ruby object with the new one. Must make * sure the hack to store the new sx pointer follows the rules for * playing nicely with the garbage collector */ static VALUE sexp_unparse(VALUE self) { /* get the ary */ VALUE ary = rb_iv_get(self,"@ary"); /* turn ary into a sexp_t */ sexp_t *sx = sexp_unparse_array(ary); /* the CSTRING we unparse sx into, the ruby string it represents, and * the old sx pointer to replace */ CSTRING *s = NULL; VALUE str; sexp_t *sx_old; /* unparse sx */ print_sexp_cstr(&s, sx, 256,128); /* make sure the CSTRING char * is null terminated */ s->base[s->curlen] = '\0'; /* create the ruby string */ str = rb_str_new2(s->base); /* set the str field to the new string. Make sure this is the correct * way to do it while still making sure the original we are replacing * gets garbage collected */ rb_iv_set(self, "@str", str); /* assuming the string was copied in the rb_str_new2() call, dispose of * the CSTRING. */ sdestroy(s); /* look up the old sx pointer in the ruby object */ Data_Get_Struct(self, sexp_t, sx_old); /* ...and destroy it */ destroy_sexp(sx_old); /* stash the new sx pointer in the object */ DATA_PTR(self) = (void *)sx; /* return self */ return self; } /* setter for ary field */ static VALUE sexp_setAry(VALUE self, VALUE ary) { rb_iv_set(self, "@ary", ary); return self; } /* accessor for ary field */ static VALUE sexp_getAry(VALUE self) { return rb_iv_get(self, "@ary"); } /* accessor for str field */ static VALUE sexp_getStr(VALUE self) { return rb_iv_get(self, "@str"); } /* call made by ruby when loading the dynamlic library of this code. * defines the Sexp class and the methods on it. They are implemented * above. */ void Init_Sexp() { cSexp = rb_define_class("Sexp", rb_cObject); rb_define_singleton_method(cSexp, "new", sexp_new, 1); rb_define_method(cSexp, "initialize", sexp_init, 2); rb_define_method(cSexp, "getAry", sexp_getAry, 0); rb_define_method(cSexp, "getStr", sexp_getStr, 0); rb_define_method(cSexp, "setAry", sexp_setAry, 1); rb_define_method(cSexp, "unparse", sexp_unparse, 0); } sfsexp-1.4.1/ruby/driver.rb000066400000000000000000000034771440725250000156400ustar00rootroot00000000000000# # SFSEXP: Small, Fast S-Expression Library version 1.0 # Written by Matthew Sottile (matt@lanl.gov) # # 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 # require "Sexp" s = Sexp.new("(test (sexp this might work) or not)") sa = s.getAry puts s.getStr sa[0] = "newatom" s.setAry(sa) s.unparse puts s.getStr s2 = Sexp.new("") a = [] b = [] a = a << "i" << "am" << "a" b = b << "new" << "sexp" << "awkwardly" a = a << b << "constructed" s.setAry(a) s.unparse() puts s.getStr sfsexp-1.4.1/ruby/extconf.rb000066400000000000000000000001361440725250000160000ustar00rootroot00000000000000require 'mkmf' dir_config('sexp') have_library('sexp', 'parse_sexp') create_makefile("Sexp"); sfsexp-1.4.1/ruby/supermon_example.rb000066400000000000000000000037601440725250000177230ustar00rootroot00000000000000# # SFSEXP: Small, Fast S-Expression Library version 1.0 # Written by Matthew Sottile (matt@lanl.gov) # # 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 # # # sample client for supermon written in ruby! # require "Sexp" require "socket" s = TCPsocket.open("localhost",2709) 100.times { s.write("0x40S\n") str = s.recv(65535) sx = Sexp.new(str) a = sx.getAry() avg = [0.0,0.0,0.0] nn = a.length a.each do |samp| avg[0] = avg[0] + ((samp[4][1]+0.0) / nn) avg[1] = avg[1] + ((samp[4][2]+0.0) / nn) avg[2] = avg[2] + ((samp[4][3]+0.0) / nn) end; puts sprintf("%f %f %f",avg[0],avg[1],avg[2]) sleep 10 } sfsexp-1.4.1/sexp.dot000066400000000000000000000027641440725250000145240ustar00rootroot00000000000000digraph G { state1 state2 state3 state4 state5 state6 state7 state8 state9 state10 state11 state12 state13 state14 state15 state1 -> state1 [label="\\n"] state1 -> state1 [label="\' \'"] state1 -> state1 [label="\\t"] state1 -> state1 [label="\\r"] state1 -> state11 [label=";"] state1 -> state2 [label="("] state1 -> state3 [label=")"] state1 -> state5 [label="\""] state1 -> state7 [label="\'"] state1 -> state12 [label="# and INLINE_BINARY"] state1 -> state4 [label="otherwise and NORMAL"] state2 -> state1 state3 -> state1 state4 -> state1 [label="\\n"] state4 -> state1 [label="\' \'"] state4 -> state1 [label="\\t"] state4 -> state1 [label="\\r"] state4 -> state3 [label=")"] state4 -> state1 state4 -> state4 [label="valid atom chars"] state5 -> state6 [label="\""] state5 -> state5 state6 -> state1 state7 -> state5 [label="\""] state7 -> state8 [label="("] state7 -> state4 state8 -> state9 [label=")"] state8 -> state8 [label="("] state8 -> state10 [label="\""] state9 -> state1 [label="qdepth==0"] state9 -> state8 [label="qdepth>0"] state10 -> state8 [label="\" and esc==0"] state10 -> state10 [label="otherwise"] state11 -> state1 [label="\\n"] state11 -> state11 [label="otherwise"] state12 -> state13 [label="b"] state12 -> state4 [label="otherwise"] state13 -> state14 [label="#"] state13 -> state4 [label="otherwise"] state14 -> state15 [label="#"] state14 -> state14 [label="otherwise"] state15 -> state15 [label="binread < binlength"] state15 -> state1 [label="binread == binlength"] } sfsexp-1.4.1/sfsexp.pc.in000066400000000000000000000004041440725250000152630ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: sfsexp Description: small and fast s-expressions library URL: https://github.com/mjsottile/sfsexp Version: @VERSION@ Libs: -L@libdir@ -lsexp Cflags: -I@includedir@/sfsexp sfsexp-1.4.1/src/000077500000000000000000000000001440725250000136135ustar00rootroot00000000000000sfsexp-1.4.1/src/Makefile.am000066400000000000000000000006431440725250000156520ustar00rootroot00000000000000CFLAGS = $(SFSEXP_CFLAGS) CPPFLAGS = $(SFSEXP_CPPFLAGS) lib_LTLIBRARIES = libsexp.la pkginclude_HEADERS = sexp.h sexp_vis.h sexp_ops.h sexp_memory.h sexp_errors.h cstring.h faststack.h libsexp_la_SOURCES = cstring.c cstring.h event_temp.c faststack.c faststack.h io.c parser.c sexp.c sexp.h sexp_memory.c sexp_memory.h sexp_errors.h sexp_ops.c sexp_ops.h sexp_vis.c sexp_vis.h libsexp_la_LDFLAGS = -version-info 1:0:0 sfsexp-1.4.1/src/cstring.c000066400000000000000000000124631440725250000154360ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 */ #include "cstring.h" #include #include #include #include "sexp_memory.h" #include "sexp.h" /** * 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) { size_t 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)); } sfsexp-1.4.1/src/cstring.h000066400000000000000000000114711440725250000154410ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 */ #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__ */ sfsexp-1.4.1/src/event_temp.c000066400000000000000000000645071440725250000161410ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #include "sexp.h" 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 = (size_t) 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; } sfsexp-1.4.1/src/faststack.c000066400000000000000000000124171440725250000157470ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 */ #include #include #include "faststack.h" #include "sexp.h" /** * 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, *tmp; if (cur_stack == NULL) { sexp_errno = SEXP_ERR_BAD_STACK; return NULL; } top = cur_stack->top; /* 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; } sfsexp-1.4.1/src/faststack.h000066400000000000000000000120721440725250000157510ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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. */ #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(); /** * 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__ */ sfsexp-1.4.1/src/io.c000066400000000000000000000070651440725250000143760ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include #include #include "sexp.h" /** * initialize an io-wrapper */ sexp_iowrap_t *init_iowrap(int fd) { sexp_iowrap_t *iow; #ifdef __cplusplus iow = (sexp_iowrap_t *)sexp_calloc(1,sizeof(sexp_iowrap_t)); #else iow = sexp_calloc(1,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 = (size_t) 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 = (size_t) 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; } sfsexp-1.4.1/src/parser.c000066400000000000000000001325221440725250000152600ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #include #include #include "sexp.h" #include "faststack.h" /* * 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. */ #ifndef _NO_MEMORY_MANAGEMENT_ faststack_t *pd_cache; #endif /** * 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. */ #ifndef _NO_MEMORY_MANAGEMENT_ faststack_t *sexp_t_cache; #endif /** * 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_ERR_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 */ #ifdef _NO_MEMORY_MANAGEMENT_ parse_data_t * pd_allocate(void) { parse_data_t *p = NULL; p = sexp_malloc(sizeof(parse_data_t)); return p; } #else 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; } #endif /* _NO_MEMORY_MANAGEMENT_ */ /** * de-allocation */ #ifdef _NO_MEMORY_MANAGEMENT_ void pd_deallocate(parse_data_t *p) { sexp_free(p, sizeof(parse_data_t)); } #else 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); } #endif /* _NO_MEMORY_MANAGEMENT_ */ /** * print the current parsing state based on the contents of the parser * continuation. Useful for error reporting if an error is detected * while the current expression being parsed is incomplete. */ void print_pcont(pcont_t * pc, char * buf, size_t buflen) { char *cur = buf; int loc = 0; int n; stack_lvl_t *lvl; parse_data_t *pdata; sexp_t *sx; /* return if either the buffer or continuation are null */ if (buf == NULL) return; if (pc == NULL) return; /* if continuation has no stack, return */ if (pc->stack == NULL) return; /* start at the bottom of the stack */ lvl = pc->stack->bottom; /* go until we either run out of buffer space or we hit the top of the stack */ while (loc < buflen-1 && lvl != NULL) { /* get the data at the current stack level */ pdata = (parse_data_t *)lvl->data; /* if this is null, we're at a level with nothing added yet */ if (pdata == NULL) break; /* get first fully parsed sexpr for this level. this could be any sub-expression, like an atom or a full s-expression */ sx = pdata->fst; /* spin through all of the s-expressions at this level */ while (sx != NULL) { /* if we have a list that has no contents, just add the open paren. this means we haven't finished this expression and the stack contains it's partial contents. Just print the open paren and break out so we can pop up the stack. */ if (sx->ty == SEXP_LIST && sx->list == NULL) { cur[0] = '('; cur++; loc++; break; } else { /* print the fully parsed sub-expression */ n = print_sexp(cur,buflen-loc,sx); /* add a space between this and the next expression. note that this may induce spaces that were not part of the original expression. */ cur[n] = ' '; /* increment n to compensate for the space we added */ n++; /* push the pointer into the output buffer forward by n */ cur += n; /* increment counter for location in buffer by n */ loc += n; } /* go to next s-expr */ sx = sx->next; } /* go up to next level in stack */ lvl = lvl->above; } /* at this point, all that may remain is a partially parsed string that hasn't been turned into a sexpr yet. attach it to the output string. */ if (pc->val_used < (buflen-loc)-1) { strncpy(cur, pc->val, pc->val_used); cur += pc->val_used; } else { /* don't bother if we're so close to the end of the buffer that we can't attach our null terminator. */ if (buflen-loc > 2) { strncpy(cur, pc->val, (buflen-loc)-2); cur += (buflen-loc)-2; } } /* add null terminator */ cur[0] = '\0'; } /** * 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) { char dummy[2] = "\n\0"; 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 */ /* did someone hand us a bare atom with no trailing whitespace? */ if (sexp_errno == SEXP_ERR_INCOMPLETE && pc->lastPos == NULL) { /* simulate trailing whitespace to see if that terminates an atom. */ pc = cparse_sexp (dummy, 2, pc); if (pc == NULL) return NULL; /* assume that cparse_sexp set sexp_errno */ } sx = pc->last_sexp; 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) { 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 ***/ /** NOTE1: sbuffer is set manually as appropriate. **/ /** NOTE2: this also sets sexp_errno to the same value as the error field in the continuation. This used to be done in iparse_sexp and parse_sexp, but that meant that direct callers of cparse_sexp would see inconsistent errors. sexp_errno could say one thing, but cc would say the other. This has been fixed. **/ #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; \ sexp_errno = (err); \ } /*** 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 = (size_t) atoi(val); 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_INCOMPLETE, NULL); if (t[0] == '\0' || t == bufEnd) cc->lastPos = NULL; else cc->lastPos = t; } return cc; } sfsexp-1.4.1/src/sexp.c000066400000000000000000000324601440725250000147430ustar00rootroot00000000000000/** @Cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #include #include #include "sexp.h" #include "faststack.h" /* * 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 if there * is space. If there is not, the buffer will be partially filled * up to but not exceeding the buffer size. */ int print_sexp (char *buf, size_t size, const sexp_t * sx) { int retval; size_t 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 no space left, then cleanup, set the error flag, null terminate b, and return -1. */ #define out_of_space() { \ sexp_errno = SEXP_ERR_BUFFER_FULL; \ b--; \ b[0] = 0; \ retval = -1; \ destroy_stack(stack); \ sexp_t_deallocate(fakehead); \ return retval; \ } /* macro for adding one char to b. */ #define add_char_break_full(c) { \ b[0] = c; \ b++; \ left--; \ if (left == 0) \ { \ out_of_space(); \ } \ } if (sx == NULL) { buf[0] = '\0'; return 0; } if (size < 1) { return -1; } 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) { depth--; add_char_break_full(')'); } if (stack->top == NULL) break; top = stack->top; top->data = ((sexp_t *) top->data)->next; if (top->data != NULL) { add_char_break_full(' '); } } else if (tdata->ty == SEXP_VALUE) { if (tdata->aty == SEXP_DQUOTE) { add_char_break_full('\"'); } else if (tdata->aty == SEXP_SQUOTE) { add_char_break_full('\''); } 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) { add_char_break_full('\\'); } add_char_break_full(tc[0]); tc++; } } else { if (left > 3) { add_char_break_full('#'); add_char_break_full('b'); add_char_break_full('#'); #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 out_of_space(); } if (sz < 0) { out_of_space(); } b += sz; left -= sz; if (left < tdata->binlength) { out_of_space(); } if (tdata->binlength > 0) { memcpy(b,tdata->bindata,tdata->binlength); left -= tdata->binlength; b+=tdata->binlength; } add_char_break_full(' '); } else { out_of_space(); } } if (tdata->aty == SEXP_DQUOTE && left > 0) { add_char_break_full('\"'); } if (left == 0) { out_of_space(); } top->data = ((sexp_t *) top->data)->next; if (top->data != NULL) { add_char_break_full(' '); } } else if (tdata->ty == SEXP_LIST) { depth++; add_char_break_full('('); push (stack, tdata->list); } else { sexp_errno = SEXP_ERR_BADCONTENT; destroy_stack (stack); sexp_t_deallocate(fakehead); return -1; } } while (depth != 0) { add_char_break_full(')'); depth--; } if (left != 0) { b[0] = 0; retval = (int) (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 = (int) _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 raw binary value */ sexp_t *new_sexp_binary_atom(char *data, size_t binlength) { sexp_t *sx = sexp_t_allocate(); if (sx == NULL) { sexp_errno = SEXP_ERR_MEMORY; return NULL; } sx->ty = SEXP_VALUE; sx->next = sx->list = NULL; sx->aty = SEXP_BINARY; sx->bindata = data; sx->binlength = binlength; 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 = NULL; if (aty == SEXP_BINARY) { sexp_errno = SEXP_ERR_BAD_CONSTRUCTOR; return NULL; } 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; } sfsexp-1.4.1/src/sexp.h000066400000000000000000000717211440725250000147530ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #ifndef __SEXP_H__ #define __SEXP_H__ #include #include /* for BUFSIZ only */ #include "faststack.h" #include "cstring.h" #include "sexp_memory.h" #include "sexp_errors.h" /* 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 \n * Written by Matthew Sottile (mjsottile@gmail.com) * * \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)(); /** * The end_sexpr function pointer is called when an close parenthesis * is encountered ending an expression. */ void (* end_sexpr)(); /** * 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. */ size_t 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 raw binary atom. * This element will contain a pointer to the raw binary data * provided, as well as the binary data length. The character * atom fields will be NULL and the corresponding val * length and allocation size will be set to zero since this * element is carrying a binary pointer only. */ sexp_t *new_sexp_binary_atom(char *data, size_t binlength); /** * 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(); /** * print the contents of the parser continuation stack to a buffer. * this is useful if an expression is partially parsed and the caller * realizes that something is wrong with it. with this routine, * the caller can reconstruct the expression parsed so far and use it * for error reporting. this works with fixed size buffers allocated * by the caller. there is not a CSTRING-based version currently. */ void print_pcont(pcont_t * pc, char * buf, size_t buflen); /* this is for C++ users */ #ifdef __cplusplus } #endif #include "sexp_ops.h" #endif /* __SEXP_H__ */ sfsexp-1.4.1/src/sexp_errors.h000066400000000000000000000114431440725250000163420ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #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, /** * parsing is incomplete and need more data to complete it. */ SEXP_ERR_INCOMPLETE, /** * this error code indicates that an atom was created with * the incorrect constructor. For example, attempting to * create a binary mode atom with the new_sexp_atom * constructor intended for text atoms will cause this to * be set. */ SEXP_ERR_BAD_CONSTRUCTOR } sexp_errcode_t; #endif /* __SEXP_ERRORS_H__ */ sfsexp-1.4.1/src/sexp_memory.c000066400000000000000000000064761440725250000163430ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #include #include "sexp.h" #include "sexp_errors.h" #include "sexp_memory.h" #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_ */ sfsexp-1.4.1/src/sexp_memory.h000066400000000000000000000124311440725250000163340ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #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__ */ sfsexp-1.4.1/src/sexp_ops.c000066400000000000000000000127521440725250000156260ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include #include #include #include "sexp_ops.h" /** * 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 *s_new; if (s == NULL) return NULL; s_new = sexp_t_allocate(); if (s_new == NULL) { sexp_errno = SEXP_ERR_MEMORY; return NULL; } /* initialize fields to null and zero, and fill in only those necessary. */ s_new->val_allocated = s_new->val_used = 0; s_new->val = NULL; s_new->list = s_new->next = NULL; s_new->bindata = NULL; s_new->binlength = 0; /* now start copying in data and setting appropriate fields. */ s_new->ty = s->ty; /* values */ if (s_new->ty == SEXP_VALUE) { s_new->aty = s->aty; /* binary */ if (s_new->aty == SEXP_BINARY) { if (s->bindata == NULL && s->binlength > 0) { sexp_errno = SEXP_ERR_BADCONTENT; sexp_t_deallocate(s_new); return NULL; } s_new->binlength = s->binlength; if (s->bindata == NULL) { s_new->bindata = NULL; } else { /** allocate space **/ #ifdef __cplusplus s_new->bindata = (char *)sexp_malloc(sizeof(char)*s->binlength); #else s_new->bindata = sexp_malloc(sizeof(char)*s->binlength); #endif } if (s_new->bindata == NULL) { sexp_errno = SEXP_ERR_MEMORY; sexp_t_deallocate(s_new); return NULL; } memcpy(s_new->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(s_new); return NULL; } s_new->val_used = s->val_used; s_new->val_allocated = s->val_allocated; if (s->val == NULL) { s_new->val = NULL; } else { /** allocate space **/ #ifdef __cplusplus s_new->val = (char *)sexp_calloc(1,sizeof(char)*s->val_allocated); #else s_new->val = sexp_calloc(1,sizeof(char)*s->val_allocated); #endif if (s_new->val == NULL) { sexp_errno = SEXP_ERR_MEMORY; sexp_t_deallocate(s_new); return NULL; } memcpy(s_new->val, s->val, sizeof(char)*s->val_used); } } } else { s_new->list = copy_sexp(s->list); } s_new->next = copy_sexp(s->next); return s_new; } sfsexp-1.4.1/src/sexp_ops.h000066400000000000000000000111531440725250000156250ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #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 "sexp.h" #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__ */ sfsexp-1.4.1/src/sexp_vis.c000066400000000000000000000074051440725250000156250ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 **/ #include "faststack.h" #include "sexp.h" static 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; } sfsexp-1.4.1/src/sexp_vis.h000066400000000000000000000051051440725250000156250ustar00rootroot00000000000000/** @cond IGNORE ====================================================== SFSEXP: Small, Fast S-Expression Library Written by Matthew Sottile (mjsottile@gmail.com) ====================================================== 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 */ /** * \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__ */ sfsexp-1.4.1/state_machine.txt000066400000000000000000000025331440725250000163740ustar00rootroot00000000000000state_machine.txt Basic description of the state machine used by the parser. This parser is based on a very simple DFA, much like yacc/lex generated parsers. Shorthand notes: WS stands for whitespace characters ' ', \t, \r and \n. --------- Start state = 1 1. STARTING STATE t[0] = WS : t++; state=1 = ';' : t++; state = 11 = '(' : t++; state = 2 = ')' : state = 3 = '\"' : vcur = val; t++; state = 5 = '\'' : t++; state = 7 = else : process character as atom head (Note 1); t++; state = 4 2. BEGIN NESTED EXPRESSION allocate new sexp_t element, type LIST if (stack empty) create new stack level, new sexp_t added to level (lst=fst=sx), pushed else get top of stack, attach sx to end of chain allocate new stack level, null out contents push empty level state = 1 3. CLOSE NESTED EXPRESSION pop the stack (old top = lvl) save head of chain on lvl free stack level if (stack top nonnull) attach head saved from popped level to 'list' pointer from current top chain end. else error state = 1 4. PARSE ATOM 5. if escape on, save char, move pointer (unset escape) 6. unquoted, enter state 1 7. 8. 9. 10. 11. ------ Note 1: Duplicated code from state 4 into state 1 to prevent 2 iterations of main loop on first character of each atom. sfsexp-1.4.1/test_builds.sh000077500000000000000000000012051440725250000157020ustar00rootroot00000000000000#!/usr/bin/env bash if [ ! -f ./configure ]; then echo "Generate configure first. See INSTALL." exit 1 fi if [ -f ./Makefile ]; then make distclean fi ./configure --enable-thread-unsafe-memory-management make cd tests ./check_leaks.sh cd ../examples ./check_leaks.sh cd .. make distclean ./configure --enable-debug --enable-thread-unsafe-memory-management make cd tests ./check_leaks.sh cd ../examples ./check_leaks.sh cd .. make distclean ./configure make cd tests ./check_leaks.sh cd ../examples ./check_leaks.sh cd .. make distclean ./configure --enable-debug make cd tests ./check_leaks.sh cd ../examples ./check_leaks.sh cd .. sfsexp-1.4.1/tests/000077500000000000000000000000001440725250000141665ustar00rootroot00000000000000sfsexp-1.4.1/tests/.gitignore000066400000000000000000000001151440725250000161530ustar00rootroot00000000000000ctest ctorture error_codes partial read_and_dump readtests vis_test out*.dot sfsexp-1.4.1/tests/Makefile.am000066400000000000000000000010511440725250000162170ustar00rootroot00000000000000CFLAGS = $(SFSEXP_CFLAGS) CPPFLAGS = -I../src $(SFSEXP_CPPFLAGS) LDFLAGS = EXTRA_DIST = test_expressions dotests.sh randsexp.pl noinst_PROGRAMS = bug ctest ctorture error_codes partial read_and_dump readtests vis_test LDADD = ../src/libsexp.la bug_SOURCES = bug.c ../src/sexp.h ctest_SOURCES = ctest.c ../src/sexp.h ctorture_SOURCES = ctorture.c ../src/sexp.h error_codes_SOURCES = error_codes.c ../src/sexp.h partial_SOURCES = partial.c ../src/sexp.h read_and_dump_SOURCES = read_and_dump.c ../src/sexp.h readtests_SOURCES = readtests.c ../src/sexp.h sfsexp-1.4.1/tests/README000066400000000000000000000076001440725250000150510ustar00rootroot00000000000000README matt sottile / 7.25.02 updated / 6.17.03 updated again / 5.23.05 Tests: These test programs are intended to take an s-expression, preferably one that is VERY large, and parse it then turn it back into a string, and finally free the memory used for the parsed expression tree. This process is repeated some large number of times. Note that output from the program is not useful until the end, though the iteration number is printed within the loop of parse/print/free. This is useful only to make sure that the program is actually proceeding on VERY large expressions where parsing may take a while. Included is a program to test the parser performance (ctorture), generate large random s-expressions, and test the correctness of the parser against a set of interesting expressions (readtests). read_and_dump is a similar test to readtests, but instead of doing a parse->unparse->parse->unparse loop and comparing output, it simply does a parse->unparse and print of each expression so one can compare the originals on disk and the version that is printed to see if they match. Try it on your ~/.emacs file -- suprisingly enough, my .emacs revealed a couple of bugs that were otherwise not showing up! Finally, ctest is a tester that takes a fixed s-expression string and parses it with different size chunks passed into the continuation-based parser. This allows us to test that the continuation save/restore process that the parser uses works as the boundary between calls moves through the string and has to deal with various states. The example expression forces the continuations to properly store single and double quote state and partially parsed atoms. To generate a random s-expression: ---------------------------------- The perl script in this directory, randsexp.pl, will do this. The arguments are: % perl ./randsexp.pl [minimum atom count] [maximum string length] The minimum atom count is the minimum number of atoms in the s-expression we wish to generate. So the number of atoms will be >= min_count. The maximum string length is the maximum length in characters of the s-expression that is generated. This is useful to bound the length so we don't blow up any buffers in the ctorture program that will eventually process these random expressions. To use ctorture.c : ------------------- Create a file called TESTEXP containing an s-expression. Run ctorture like this: % ./ctorture < TESTEXP Or, if you have some program that generates a valid s-expression, try this: % myprogram | ./ctorture Or, you can specify the file as an argument. % ctorture -f TESTEXP See the usage for ctorture to get more info on various options. % ctorture -h To use readtest.c : ------------------- This is a new addition to the test suite (as of August 2002). It provides a simple test harness to read in a file called 'test_expressions', parse each expression in the file, and attempt to reach a fixed point for ensuring that: original->parse->unparse == original->parse->unparse->parse->unparse This program tests two things. First, it tests if the parser works or breaks on a given string. Second, it tests that things like escaped characters, quoting, and other possible things are interpreted by the parser correctly. Users are strongly encouraged to submit expressions that break the parser so that the bugs can be fixed and the rogue strings can be added to the test_expressions file to ensure that they don't break the parser in the future. To use vis_test.c : ------------------- Add any desired s-expressions to the file 'test_expressions'. Run vis_test; if all s-expressions are sucessfully transformed to DOT, it will exit 0. DOT output can be examined in out${n}.dot where is the index (from 0) of the s-expression in 'test_expressions'. The optional first argument defines a number of seconds to allow the program to run before interrupting. Pass "0" to disable the watchdog timer (i.e. do not interrupt). sfsexp-1.4.1/tests/bug.c000066400000000000000000000041411440725250000151070ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ #include #include "sexp.h" #include #include #include #include #define RAWSTRING "(i am the test '(expression) \"with\" 'weird atoms)\0" int main(int argc, char **argv) { sexp_t *sx; unsigned int len; pcont_t *pc = NULL; char outbuf[6]; char inbuf[256]; strcpy(inbuf,RAWSTRING); len = strlen(inbuf); pc = cparse_sexp(inbuf,len,pc); assert(pc != NULL); sx = pc->last_sexp; outbuf[5] = '\0'; print_sexp(outbuf,5,sx); destroy_sexp(sx); destroy_continuation(pc); printf("%s\n",outbuf); printf("sexp_errno: %d\n", sexp_errno); sexp_cleanup(); exit(EXIT_SUCCESS); } sfsexp-1.4.1/tests/check_leaks.sh000077500000000000000000000014421440725250000167620ustar00rootroot00000000000000#!/usr/bin/env bash # if valgrind isn't present we can't proceed - otherwise # we get a cascade of command not found failures if ! command -v valgrind &> /dev/null then echo "cannot continue: valgrind could not be found" exit fi function test { libtool --mode=execute valgrind --leak-check=full --show-reachable=yes -q "$@" > /dev/null status=$? if [ $status -ne 0 ]; then echo "error with $1" else echo "no error with $1" fi return $status } test ./ctest ## note: need to keep iteration count for ctorture low here ## due to performance overhead of valgrind. perl ./randsexp.pl 200 40000 0.4 > /tmp/SEXP.SKINNY test ./ctorture -i 10 -f /tmp/SEXP.SKINNY rm -f /tmp/SEXP.SKINNY test ./error_codes test ./partial test ./read_and_dump test ./readtests sfsexp-1.4.1/tests/config.h.in000066400000000000000000000001161440725250000162070ustar00rootroot00000000000000/* config.h.in. Generated automatically from configure.in by autoheader. */ sfsexp-1.4.1/tests/ctest.c000066400000000000000000000044501440725250000154570ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (matt@lanl.gov) 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 **/ #include #include "sexp.h" #include #include #include #include #define RAWSTRING "(i am the test '(expression) \"with\" 'weird atoms)\0" int main(int argc, char **argv) { sexp_t *sx; int i, offset; unsigned int len; pcont_t *pc; CSTRING *s = NULL; char inbuf[256]; strcpy(inbuf,RAWSTRING); len = strlen(inbuf); for (i=len;i>0;i--) { pc = NULL; pc = cparse_sexp(inbuf,i,pc); assert(pc != NULL); offset = i; while (pc->last_sexp == NULL) { printf("."); pc = cparse_sexp(inbuf+offset,i,pc); offset+=i; } printf("\n"); sx = pc->last_sexp; print_sexp_cstr(&s,sx,8); destroy_sexp(sx); destroy_continuation(pc); printf("%d :: %s\n",i,s->base); sdestroy(s); s = NULL; } sexp_cleanup(); exit(EXIT_SUCCESS); } sfsexp-1.4.1/tests/ctorture.c000066400000000000000000000125731440725250000162110ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include "config.h" #ifdef HAVE_GETOPT_H #include #endif #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include "sexp.h" #include #include /** ** defaults **/ #define MAXSIZE 8000000 #define DEFITERS 100000 /** ** for fixed size buffer tests, here are the buffers. **/ char buf[MAXSIZE], pstr[MAXSIZE]; /* flag defining which type of print_sexp to use */ enum { FIXBUF, CSTR }; /** ** usage() **/ void usage(char *av0) { printf("\nusage: %s [-t] [-c] [-i iters] [-f fname] [-h]\n\n",av0); printf(" -i iters : specify number of iterations (default: %d)\n", DEFITERS); printf(" -f fname : read expression from file fname (default: STDIN)\n"); printf(" -c : toggle CSTRING-based print_sexp (default: fixed buffer ~8MB)\n"); printf(" -t : execute original test from torture.c (see * below)\n"); printf(" -h : usage\n\n"); printf("* please note that ctorture.c subsumes and replaces torture.c from now on.\n\n"); exit(EXIT_FAILURE); } /** ** main() **/ int main(int argc, char **argv) { sexp_t *sx; int i, maxiters, fd; struct timeval t_start, t_end; float elapsed; pcont_t *cc = NULL; sexp_iowrap_t *iow; int ch; int print_type = FIXBUF; CSTRING *cs1, *cs2; int do_old_torture = 0; maxiters = DEFITERS; /* default */ fd = STDIN_FILENO; /* default */ while ((ch = getopt(argc,argv,"i:f:cht")) != -1) { switch ((char)ch) { case 'i': maxiters = atoi(optarg); if (maxiters < 1) { maxiters = DEFITERS; /* default if argument was less than 1 */ fprintf(stderr,"WARNING: specified iteration count invalid (%s)\n", optarg); } break; case 'f': fd = open(optarg,O_RDONLY); if (fd == -1) { fprintf(stderr,"ERROR: could not open file %s for input.\n", optarg); exit(EXIT_FAILURE); } break; case 'h': usage(argv[0]); break; case 't': do_old_torture = 1; break; case 'c': print_type = CSTR; break; default: break; } } /* init cstrings to null */ cs1 = cs2 = NULL; iow = init_iowrap(fd); sx = read_one_sexp(iow); /* this is the code that replaces the old torture.c code */ if (do_old_torture == 1) { print_sexp(buf,MAXSIZE,sx); destroy_sexp(sx); gettimeofday(&t_start,0); for (i=0;ibase,cs1->curlen,cc); else cc = cparse_sexp(buf,MAXSIZE,cc); sx = cc->last_sexp; cc->lastPos = NULL; if (print_type == CSTR) print_sexp_cstr(&cs2,sx,(cs1->curlen)+1); else print_sexp(pstr,MAXSIZE,sx); destroy_sexp(sx); if (print_type == CSTR) { sempty(cs2); } } destroy_iowrap(iow); if (fd != STDIN_FILENO) close(fd); sexp_cleanup(); destroy_continuation(cc); if (print_type == CSTR) { sdestroy(cs2); sdestroy(cs1); } gettimeofday(&t_end,0); elapsed = ((double)t_end.tv_sec + (double)((double)t_end.tv_usec)/1000000)- ((double)t_start.tv_sec + (double)((double)t_start.tv_usec)/1000000); printf("%f\n",elapsed); exit(EXIT_SUCCESS); } sfsexp-1.4.1/tests/dotests.sh000066400000000000000000000020461440725250000162110ustar00rootroot00000000000000#!/bin/sh echo "==================================================================" echo "Generating trees" perl ./randsexp.pl 200 40000 0.1 > /tmp/SEXP.FAT perl ./randsexp.pl 200 40000 0.25 > /tmp/SEXP.REGULAR perl ./randsexp.pl 200 40000 0.4 > /tmp/SEXP.SKINNY echo "==================================================================" echo "Running ctorture tests..." ./ctorture -i 10000 < /tmp/SEXP.FAT ./ctorture -i 10000 < /tmp/SEXP.REGULAR ./ctorture -i 10000 < /tmp/SEXP.SKINNY echo "==================================================================" echo "Running torture tests..." ./ctorture -t -i 10000 < /tmp/SEXP.FAT ./ctorture -t -i 10000 < /tmp/SEXP.REGULAR ./ctorture -t -i 10000 < /tmp/SEXP.SKINNY echo "==================================================================" echo "Running readtests..." ./readtests echo "==================================================================" echo "Cleaning up..." rm -f /tmp/SEXP.FAT /tmp/SEXP.REGULAR /tmp/SEXP.SKINNY echo "==================================================================" sfsexp-1.4.1/tests/error_codes.c000066400000000000000000000065111440725250000166430ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include "config.h" #ifdef HAVE_GETOPT_H #include #endif #include #include "sexp.h" #include #include #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include int main(int argc, char **argv) { pcont_t *pc = NULL; char buf[128]; CSTRING *s = NULL; int len; char tinybuf[5]; sprintf(buf,"(I am a (test))"); pc = init_continuation(buf); if (pc == NULL) { printf("init_continuation returned NULL.\n"); exit(EXIT_FAILURE); } pc = cparse_sexp(NULL,42,pc); if (pc->error != SEXP_ERR_OK) { printf("cparse reacted properly to null string.\nerr=%d\n", pc->error); } destroy_continuation(pc); pc = NULL; pc = cparse_sexp(buf,strlen(buf),pc); if (pc->error != SEXP_ERR_OK) { printf("cparse returned unexpected error.\n"); exit(EXIT_FAILURE); } len = print_sexp(tinybuf, 5, pc->last_sexp); if (len == -1) { printf("print_sexp reacted correctly to buffer with insufficient space.\nerr=%d\n", sexp_errno); sexp_errno = SEXP_ERR_OK; } else { printf("print_sexp did not fail correctly with insufficient buffer.\n"); exit(EXIT_FAILURE); } len = print_sexp_cstr(&s,NULL,42); if (len == -1) { printf("print_sexp_cstr reacted correctly to NULL sexp_t.\nerr=%d\n", sexp_errno); } else { printf("print_sexp_cstr did not bail out properly given a NULL sexp_t.\n"); exit(EXIT_FAILURE); } if (s != NULL) { sdestroy(s); s = NULL; } len = print_sexp_cstr(&s,pc->last_sexp,128); if (len == -1) { printf("print_sexp_cstr reacted incorrectly to valid sexp_t.\nerr=%d\n", sexp_errno); exit(EXIT_FAILURE); } printf("%s\n",s->base); sdestroy(s); destroy_sexp(pc->last_sexp); destroy_continuation(pc); sexp_cleanup(); exit(EXIT_SUCCESS); } sfsexp-1.4.1/tests/partial.c000066400000000000000000000013071440725250000157670ustar00rootroot00000000000000#include #include "sexp.h" #include #include #include #include #define RAWSTRING "(this expression (is incomplete) and (has more\0" int main(int argc, char **argv) { unsigned int len; pcont_t *pc; char inbuf[256]; char outbuf[1024]; strcpy(inbuf,RAWSTRING); len = strlen(inbuf); pc = NULL; pc = cparse_sexp(inbuf,len,pc); if (sexp_errno == SEXP_ERR_INCOMPLETE) { printf("Incomplete expression detected.\n"); } else { printf("Unexpected error: %d\n", sexp_errno); exit(EXIT_FAILURE); } print_pcont(pc,outbuf,1024); printf("%s\n",outbuf); destroy_continuation(pc); sexp_cleanup(); exit(EXIT_SUCCESS); } sfsexp-1.4.1/tests/randsexp.pl000066400000000000000000000046561440725250000163620ustar00rootroot00000000000000# # SFSEXP: Small, Fast S-Expression Library version 1.0 # Written by Matthew Sottile (mjsottile@gmail.com) # # 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 # # # generate random s-expressions # if ($#ARGV != 2) { print "randsexp.pl [minatoms] [maxlen] [prob]\n"; exit; } # minimum number of atoms $mincount = $ARGV[0]; # maximum length of sexpr string in chars $maxlength = $ARGV[1]; # probability cut off $prob = $ARGV[2]; # initialize atom count and string $count = 0; $s = ""; while ($count < $mincount && length($s) < $maxlength) { $depth = 1; $count = 0; $s = "("; $tabs = ""; while ($depth > 0) { $r = rand(); if ($r < $prob) { $depth++; $tabs = ""; for ($i = 1; $i < $depth; $i++) { $tabs .= " "; } $s .= "\n".$tabs."(foo$count"; } else { if (1-$r < $prob) { $depth--; $tabs = ""; for ($i = 1; $i < $depth; $i++) { $tabs .= " "; } $s .= " foo$count".")\n".$tabs; } else { $s .= " foo$count"; } } $count++; if ($count > ($mincount * 2)) { $depth = 0; $count = -1; } } } print $s."\n"; #print STDERR "Elements: $count\n"; sfsexp-1.4.1/tests/read_and_dump.c000066400000000000000000000052631440725250000171220ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include "config.h" #ifdef HAVE_GETOPT_H #include #endif #include #include #include "sexp.h" #include #include #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #define TESTFILE "test_expressions" int main(int argc, char **argv) { int fd; sexp_t *sx; sexp_iowrap_t *iow; int ch; char fname[BUFSIZ]; CSTRING *s1 = NULL; int binmode = 0; strcpy(fname,TESTFILE); while ((ch = getopt(argc,argv,"f:b")) != -1) { switch ((char)ch) { case 'f': strcpy(fname,optarg); break; case 'b': binmode = 1; break; default: break; } } fd = open(fname,O_RDONLY); iow = init_iowrap(fd); if (binmode == 1) { iow->cc = init_continuation(NULL); iow->cc->mode = PARSER_INLINE_BINARY; } sx = read_one_sexp(iow); while (sx != NULL) { assert(sx != NULL); print_sexp_cstr(&s1,sx,8); destroy_sexp(sx); sexp_cleanup(); printf("READ: %s\n", s1->base); /** clean up strings **/ sdestroy(s1); s1 = NULL; sx = read_one_sexp(iow); } destroy_iowrap(iow); close(fd); exit(0); } sfsexp-1.4.1/tests/readtests.c000066400000000000000000000124151440725250000163330ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.0 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #include "config.h" #ifdef HAVE_GETOPT_H #include #endif #include #include "sexp.h" #include #include #include #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #define TESTFILE "test_expressions" int main(int argc, char **argv) { int fd; sexp_t *sx; sexp_iowrap_t *iow; int diff; unsigned int i; int ch; char fname[BUFSIZ]; CSTRING *s1,*s2; int passes, failures; char outbuf1[8192], outbuf2[8192]; s1 = s2 = NULL; passes = failures = 0; strcpy(fname,TESTFILE); while ((ch = getopt(argc,argv,"f:")) != -1) { switch ((char)ch) { case 'f': strcpy(fname,optarg); break; default: break; } } fd = open(fname,O_RDONLY); iow = init_iowrap(fd); printf("TESTING CSTRING BASED UNPARSE:\n"); sx = read_one_sexp(iow); while (sx != NULL) { print_sexp_cstr(&s1,sx,8); destroy_sexp(sx); sx = parse_sexp(s1->base,s1->curlen); if (sx == NULL) { fprintf(stderr,"ERROR: parser error state of %d\n", sexp_errno); exit(1); } print_sexp_cstr(&s2,sx,8); destroy_sexp(sx); sexp_cleanup(); diff = 0; for (i=0;icurlen;i++) { diff += abs((s1->base[i] - s2->base[i])); if (s1->base[i] == '\0') break; } /** * diff is the lexical difference between the first unparsing * of the original buffer and the unparsed version of the parsed * version of the first unparsed string. In other words, does: * * orig->parse->unparse == orig->parse->unparse->parse->unparse * * This catches issues with print and parse to make sure the meaning * of the original is kept (or at least, "bugs" in the parser have * matching "bugs" in the printer.) */ if (diff != 0) { printf("FIXED POINT MISSED (diff=%d): \nS1: %s\nS2: %s\n",diff, s1->base,s2->base); failures++; } else { passes++; } /** clean up strings **/ sdestroy(s1); sdestroy(s2); s1 = s2 = NULL; sx = read_one_sexp(iow); } destroy_iowrap(iow); close(fd); printf("TOTAL TESTS: %d PASS=%d FAIL=%d\n\n", passes+failures,passes,failures); passes = failures = 0; /*** *** now do normal fixed length buffer unparse testing ***/ fd = open(fname,O_RDONLY); iow = init_iowrap(fd); printf("TESTING FIXED SIZE BUFFER BASED UNPARSE:\n"); sx = read_one_sexp(iow); while (sx != NULL) { print_sexp(outbuf1,8192,sx); destroy_sexp(sx); sx = parse_sexp(outbuf1,8192); if (sx == NULL) { fprintf(stderr,"ERROR: parser error state of %d\n", sexp_errno); exit(1); } print_sexp(outbuf2,8192,sx); destroy_sexp(sx); sexp_cleanup(); diff = 0; for (i=0;i<8192;i++) { diff += abs((outbuf1[i] - outbuf2[i])); if (outbuf1[i] == '\0' || outbuf2[i] == '\0') break; } /** * diff is the lexical difference between the first unparsing * of the original buffer and the unparsed version of the parsed * version of the first unparsed string. In other words, does: * * orig->parse->unparse == orig->parse->unparse->parse->unparse * * This catches issues with print and parse to make sure the meaning * of the original is kept (or at least, "bugs" in the parser have * matching "bugs" in the printer.) */ if (diff != 0) { printf("FIXED POINT MISSED (diff=%d): \nS1: %s\nS2: %s\n",diff, outbuf1,outbuf2); failures++; } else { passes++; } sx = read_one_sexp(iow); } destroy_iowrap(iow); close(fd); printf("TOTAL TESTS: %d PASS=%d FAIL=%d\n", passes+failures,passes,failures); exit(0); } sfsexp-1.4.1/tests/test_expressions000066400000000000000000000026351440725250000175400ustar00rootroot00000000000000(we should be able to have () arbitrary empty expressions () right?) (this file contains a set of test s-expressions to try and break the library) (add your own if you want!) (")" this should not break read_sexp) ("\" ) " this should also not break read_sexp.) (this one"is supposed to behave like common lisp" would) (lets make sure single character a t o m s work fine...) (single quote '(tells the parser to ignore what appears in here ")")) (thisissupposedtobeareallylongatomtotestthegrowingoftheparservaluebuffersoihopetoputabunchofgibberishherenowoksfhaskdjhflkewrhtlkwehtlksdfjhglskdfjhglsdkfjghlskdfjhgksdjfghlskdjfghlsdfhglsdkfjghgksdfjhglskdfjghlsdkfjghlsdkfjghsldkfjghslkdfjghlskjrhtlkwerjthlwkerjthwlkerjthwlerktjhwelrkjthwelkrjthwelkrtjhwlekrjthwelkrjthwlekrjthwlekjrthwlerkjthlwkerjthwlekrjthwlekrjthlwkerjthwlekrjthwlekrjthwlekrjthwlekrjthwlkerjthwlekrthwiuertyowieruytoweiurtyowierutywoeirutywoeirutywoeirutyoweirutyowiuertyoiweruylgjkhdlsdkjfghsdfng,mdfgnbs,fnmdbgbsbngfsngfnsd,fmngbsbfngbnmsfdbgs,bfmnfngnb,dfg hopefully that worked) (lets see if this ; this comment should be ignored ; and so should this one, and their parens shouldn't mess things up is ok) "another valid atom" '(yet another valid atom "to parse") "'\"''\'''\'" ;; this one has lots of funky quotes - make sure all is ok (#blah) (Single 'quoted 'atom 'test) ('"hmm") () () ;; below this line are all expressions that are known to break the parser sfsexp-1.4.1/tests/utf8_test_expressions000066400000000000000000000276621440725250000205150ustar00rootroot00000000000000;; based on ;; https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt ;; Markus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25 CC BY ((∮E⋅da=Q n→∞ ∑f(i)=∏g(i)) ( (∀x∈ℝ: ⌈x⌉ = −⌊−x⌋) α ∧ ¬β = ¬'(¬α ∨ β)) (ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ) (⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫)) (2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm) (ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn) (Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]) ( ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ )) (( ╔══════════════════════════════════════════╗ ) ( ║ • ‘single’ and “double” quotes ║ ) ( ║ • Curly apostrophes: “We’ve been here” ║ ) ( ║ ║ ) ( ║ • Latin-1 apostrophe and accents: '´` ║ ) ( ║ ║ ) ( ║ • ‚deutsche‘ „Anführungszeichen“ ║ ) ( ║ ║ ) ( ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ ) ( ║ ║ ) ( ║ • "ASCII safety test": 1lI|, 0OD, 8B ║ ) ( ║ ╭─────────╮ ║ ) ( ║ • the euro symbol: │ 14.95 € │ ║ ) ( ║ ╰─────────╯ ║ ) ( ╚══════════════════════════════════════════╝ )) ( STARGΛ̊TE "SG-1", 'a = v̇ = r̈, a⃑ ⊥ b⃑ ) (( Σὲ γνωρίζω ἀπὸ τὴν κόψη ) ( τοῦ σπαθιοῦ τὴν τρομερή,) ( σὲ γνωρίζω ἀπὸ τὴν ὄψη) ( ποὺ μὲ βία μετράει τὴ γῆ.) ( ᾿Απ᾿ τὰ κόκκαλα βγαλμένη) ( τῶν ῾Ελλήνων τὰ ἱερά) ( καὶ σὰν πρῶτα ἀνδρειωμένη) ( χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!)) (( Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,) ( ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς) ( λόγους οὓς ἀκούω· '(τοὺς μὲν γὰρ λόγους) περὶ τοῦ) ( τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿) ( εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ) ( πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν) ( οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,) ( οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν) ( ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς "ἔχειν ἀσφαλῶς καὶ" Φίλιππον) ( τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι) ( γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν) ( προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους) ( σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ) ( τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ) ( τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς) ( τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.) ( Δημοσθένους, Γ´ ᾿Ολυνθιακὸς)) (( გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო) ( კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,) ( ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს) ( ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,) ( ინტერნაციონალიზაცია "და ლოკალიზაცია, Unicode-ის" გამოყენება) ( ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,) ( ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.) ( Зарегистрируйтесь сейчас на Десятую Международную Конференцию по) ( Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.) ( Конференция соберет широкий круг экспертов по вопросам глобального) ( Интернета и Unicode, локализации и интернационализации, воплощению и) ( применению Unicode в различных операционных системах и программных) ( приложениях, шрифтах, верстке и многоязычных компьютерных системах.)) ('( ๏ "แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่") ( สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา) ( ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา) ( โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ) ( เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ) ( ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ) ( พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้) ( ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ)) (( ሰማይ አይታረስ ንጉሥ አይከሰስ።) ( ብላ ካለኝ "እንደአባቴ በቆመጠኝ።") ( ጌጥ ያለቤቱ ቁምጥና ነው።) ( ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።) ( የአፍ ወለምታ በቅቤ አይታሽም።) ( አይጥ በበላ ዳዋ ተመታ።) ( ሲተረጉሙ ይደረግሙ።) ( ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።) ( ድር ቢያብር አንበሳ ያስር።) ( ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።) ( እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።) ( የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።) ( ሥራ ከመፍታት ልጄን ላፋታት።) ( ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።) ( የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።) ( ተንጋሎ ቢተፉ ተመልሶ ባፉ።) ( ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።) ( እግርህን በፍራሽህ ልክ ዘርጋ።)) (( ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ)) (( ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌) ( ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞) ( ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎) ( ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂) ( ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙) ( ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑) ( ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲) ( ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲) ( ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹) ( ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞) ( ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕) ( ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹) ( ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎) ( ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎) ( ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳) ( ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞) ( ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲)) (( ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789) ( abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ) ( –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд) ( ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა)) ( Hello world, Καλημέρα κόσμε, コンニチハ) (( ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳) ( ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳) ( ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳) ( "╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤" ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳) ( ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎) ( ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏) ('(╚══╩══╝) └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█) ( ▝▀▘▙▄▟)) sfsexp-1.4.1/tests/vis_test.c000066400000000000000000000046321440725250000161770ustar00rootroot00000000000000/** SFSEXP: Small, Fast S-Expression Library version 1.3 Written by Matthew Sottile (mjsottile@gmail.com) 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 **/ #ifndef WIN32 # include #else # define ssize_t int # include # include #endif #include #include #include #include #include #include #include "sexp.h" #include "sexp_vis.h" /** * read file "test_expressions", write DOT representation of the n'th s-expression * as "out.dot". */ int main(int argc, char **argv) { sexp_t *a; int fd; sexp_iowrap_t *iow; int count = 0; unsigned int timeout = 1; if (argc>1) timeout = atoi (argv[1]); /* Watchdog timer, to catch infinite loops */ alarm(timeout); fd = open("test_expressions",O_RDONLY); iow = init_iowrap(fd); a = read_one_sexp(iow); while (a != NULL) { char fname[4096]; sprintf (fname, "out%02d.dot", count++); sexp_to_dotfile(a,fname); destroy_sexp(a); a = read_one_sexp(iow); } destroy_iowrap(iow); sexp_cleanup(); close(fd); exit(EXIT_SUCCESS); } sfsexp-1.4.1/win32/000077500000000000000000000000001440725250000137665ustar00rootroot00000000000000sfsexp-1.4.1/win32/README.txt000066400000000000000000000013371440725250000154700ustar00rootroot00000000000000This directory contains files kindly contributed by Brad Green to get the library working under Visual Studio .NET 2003 for Windows. Windows users who will use the library from cygwin should use it as described for Unix systems like Linux and OSX. Two subdirectories are under here: libsexpr/ sexpr_test/ The libsexpr directory contains the project file for building the library itself. The sexpr_test directory contains a sample C++ test project that uses the library. This hasn't been tested with any other Visual Studio version other than the .NET 2003 version. It should serve as a starting point though to get you started with other versions that may be incompatible with the project files included here. (3.15.2005) sfsexp-1.4.1/win32/libsexpr/000077500000000000000000000000001440725250000156165ustar00rootroot00000000000000sfsexp-1.4.1/win32/libsexpr/README.txt000066400000000000000000000006011440725250000173110ustar00rootroot00000000000000Unpack the sexpr_1.0.0 distribution in this directory. The project file expects ./sexpr_1.0.0/ to be here with the source distribution inside there. If there are problems, ensure that the directories inside the project file match the one for the distribution. For example, if the version of the distribution increases, it is possible that this project file will need to be updated. sfsexp-1.4.1/win32/libsexpr/libsexpr.vcproj000066400000000000000000000102761440725250000207010ustar00rootroot00000000000000 sfsexp-1.4.1/win32/sexpr_test.sln000066400000000000000000000026261440725250000167120ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sexpr_test", "sexpr_test\sexpr_test.vcproj", "{6BED4E20-49EF-4984-826F-510584F523A5}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsexpr", "libsexpr\libsexpr.vcproj", "{D204D811-D51A-4E70-B202-0FD72538F963}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {6BED4E20-49EF-4984-826F-510584F523A5}.Debug.ActiveCfg = Debug|Win32 {6BED4E20-49EF-4984-826F-510584F523A5}.Debug.Build.0 = Debug|Win32 {6BED4E20-49EF-4984-826F-510584F523A5}.Release.ActiveCfg = Release|Win32 {6BED4E20-49EF-4984-826F-510584F523A5}.Release.Build.0 = Release|Win32 {D204D811-D51A-4E70-B202-0FD72538F963}.Debug.ActiveCfg = Debug|Win32 {D204D811-D51A-4E70-B202-0FD72538F963}.Debug.Build.0 = Debug|Win32 {D204D811-D51A-4E70-B202-0FD72538F963}.Release.ActiveCfg = Release|Win32 {D204D811-D51A-4E70-B202-0FD72538F963}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal sfsexp-1.4.1/win32/sexpr_test.suo000066400000000000000000000250001440725250000167130ustar00rootroot00000000000000ࡱ>   Root Entry v~*ProjInfoExTaskListUserTasks$IVSMDPropertyBrowser* M P8 !=#%&'()*X,-./012346E9:;<R>?@ABCDFGHIJKLNOQSTUVWYMNzq3C Device ControlsCrystal ReportsData XML Schema Dialog EditorMobile Web Forms Web Forms Components Windows FormsHTMLClipboard RingGeneral0C:\projects\sexpr_test\ IToolboxService DebuggerWatches DebuggerBreakpoints(BDebuggerExceptions& bC:\projects\sexpr_test\sexpr_test\sexpr_testc:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\mfc\c:\Program FiDebuggerFindSource& DebuggerFindSymbol&DebuggerMemoryWindows,TExternalFilesProjectContents:les\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\atl\c:\Program Files\Microsoft Visuadz 'LKLB{A2Fͫ4ᆳPwͫ4ᆳDocumentWindowPositions0 DocumentWindowUserData. <SolutionConfiguration,^ObjMgrContents"uMultiStartupProj=;4{6BED4E20-49EF-4984-826F-510584F523A5}.dwStartupOpt=;StartupProject=&{6BED4E20-49EF-4984-826F-510584F523A5};?{6BED4E20-49EF-4984-826F-510584F523A5}.Release|Win32.fBatchBld=;={6BED4E20-49EF-4984-826F-510584F523A5}.Debug|Win32.fBatchBld=;4{D204D811-D51A-4E70-B202-0FD72538F963NSܾ M%%ү##G}'bm4l #O¤Elibsexprsexpr_testQ `C:\projects\sexpr_test\libsexpr\libsexpr.vcproj`C:\projects\sexpr_test\libsexpr\libsexpr.vcprojSource FilesHeader ClassViewContents$ProjExplorerState$$UnloadedProjects"sexpr_test+lFileshC:\projects\sexpr_test\sexpr_test\sexpr_test.vcprojhC:\projects\sexpr_test\sexpr_teDebug|Win32DebugSettings... ....... .,GeneralConfigSettingsVCBscMakeTool(EndConfigPropertiesRelease|Win32DebugSettings... ....... .,GeneralConfigSettingsVCBscMakeTool(EndConfigProperties,GeneralCDebug|Win32DebugSettings... ...X TaskListShortcuts$7libsexpr5lIVsServerExplorer$E74E1-B743-11D0-AE1A-00A0C90FFFC3}|<MiscFiles>|c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\crt0.c||{8B382828-6202-11D1-8870-0000F87579D2}1234}.dwStartupOpt=;?{D204D811-D51A-4E70-B202-0FD72538F963}.Release|Win32.fBatchBld=;={D204D811-D51A-4E70-B202-0FD72538F963}.Debug|Win32.fBatchBld=;4{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}.dwStartupOpt=; ActiveCfg=Debug;11D0-AE1A-00A0C90.... .,GeneralConfigSettingsVCBscMakeTool(EndConfigPropertiesRelease|Win32DebugSettings... ....... .,GeneralConfigSettingsVCBscMakeTool(EndConfigProperties...cppVV':lB$Jol(EndConfigPropertiesRell Studio .NET 2003\Vc7\crt\src\crt0.c<open> .... (LKL:{6BED4E20-49EF-4984-826F-510584F523A5}|sexpr_test\sexpr_test.vcproj|c:\projects\sexpr_test\sexpr_test\sexpr_test.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}1234_test\sexpst\sexpr_test.vcprojSource Filesn> l Studio .NET 2003\Vc7\crt\src\crt0.c<open> <7 B{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|<MiscFiles>|c:\Program Files\Microsoft Visual Studisfsexp-1.4.1/win32/sexpr_test/000077500000000000000000000000001440725250000161665ustar00rootroot00000000000000sfsexp-1.4.1/win32/sexpr_test/sexpr_test.cpp000066400000000000000000000057511440725250000211020ustar00rootroot00000000000000// This is the main project file for VC++ application project // generated using an Application Wizard. #include "stdafx.h" #include #include "sexp.h" #include #include #using using namespace System; /** * Given an s-expression of the form: * * (tag (val_list)) * * Where each value in the val_list is a float, extract the data and * populate the array passed in (the length of the array is in `size'). * Assume the array was allocated properly, size is correct, and the * expression contains the right number of values. This eliminates lots * of error checking code and makes the process a bit clearer. */ void extract(sexp_t *sx, float *data, int size) { sexp_t *s; int i; assert(sx != NULL && data != NULL && size > 0); /* duh */ /* assumption : s-expression is formatted as (tag (val1 val2 val3)) */ printf("Data tag: [%s]\n",sx->list->val); /* s = (vallist) */ s = sx->list->next; i = 0; s = s->list; while (s != NULL && i < size) { sscanf(s->val,"%f",&data[i]); s = s->next; i++; } } /** * example of packing three values into an expression of the form: * * (tag (v1 v2 v3)) * * COMMENTS SHOW THE STATE OF SX AS IT IS CONSTRUCTED */ sexp_t *pack(char *tag, float v1, float v2, float v3) { sexp_t *sx = new_sexp_list(new_sexp_atom(tag,strlen(tag))); /* sx = (tag) */ char sbuf[32]; sexp_t *vlist,*vptr; vlist = new_sexp_list(NULL); /* vlist = () */ sx->list->next = vlist; /* sx = (tag ()) */ sprintf(sbuf,"%f",v1); vlist->list = new_sexp_atom(sbuf,strlen(sbuf)); /* vlist = (v1) */ vptr = vlist->list; /* sx = (tag (v1)) */ sprintf(sbuf,"%f",v2); vptr->next = new_sexp_atom(sbuf,strlen(sbuf)); /* vlist = (v1 v2) */ vptr = vptr->next; /* sx = (tag (v1 v2)) */ sprintf(sbuf,"%f",v3); vptr->next = new_sexp_atom(sbuf,strlen(sbuf)); /* vlist = (v1 v2 v3) */ /* sx = (tag (v1 v2 v3)) ---- done, return. */ return sx; } int _tmain() { // TODO: Please replace the sample code below with your own. Console::WriteLine(S"Hello World"); char buf[256]; /* string to sprintf to */ float vals[3]; /* place to put data */ sexp_t *sx; /*** method #1: create expression as string on one side, extract data on the other. ***/ printf("===>> PART 1 <<===\n"); sprintf(buf,"(thetag (1.0 2.0 3.0))"); sx = parse_sexp(buf,strlen(buf)); extract(sx,vals,3); printf("Extracted V1=%f V2=%f V3=%f\n",vals[0],vals[1],vals[2]); destroy_sexp(sx); /*** method #2: packing function creates expression, same extract function extracts data. print in between to show expression. ***/ printf("\n===>> PART 2 <<===\n"); sx = pack("part2tag",4.0,5.0,6.0); print_sexp(buf,256,sx); printf("SX=%s\n",buf); extract(sx,vals,3); printf("Extracted V1=%f V2=%f V3=%f\n",vals[0],vals[1],vals[2]); destroy_sexp(sx); return 0; }sfsexp-1.4.1/win32/sexpr_test/sexpr_test.vcproj000066400000000000000000000072471440725250000216250ustar00rootroot00000000000000 sfsexp-1.4.1/win32/sexpr_test/stdafx.cpp000066400000000000000000000003221440725250000201600ustar00rootroot00000000000000// stdafx.cpp : source file that includes just the standard includes // sexpr_test.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" sfsexp-1.4.1/win32/sexpr_test/stdafx.h000066400000000000000000000004231440725250000176270ustar00rootroot00000000000000// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #include #include // TODO: reference additional headers your program requires here