[core] Added tdata, sexpr libraries to the project;
This commit is contained in:
		
							parent
							
								
									1cfb0aed3c
								
							
						
					
					
						commit
						3ef4cece81
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -58,7 +58,7 @@ tests/lv2ftpd | ||||
| tests/lv2ftpc | ||||
| tests/*.cfg | ||||
| debian/libsntl.substvars | ||||
| lib/libsxmp.pc | ||||
| *.pc | ||||
| compile | ||||
| test-driver | ||||
| *.pem | ||||
|  | ||||
| @ -6,7 +6,7 @@ else | ||||
| EXAMPLES =  | ||||
| endif | ||||
| 
 | ||||
| SUBDIRS = include lib man $(EXAMPLES) | ||||
| SUBDIRS = include tdata sexpr sxmp man $(EXAMPLES) | ||||
| 
 | ||||
| libsxmpdocdir = ${prefix}/doc/libsxmp | ||||
| libsxmpdoc_DATA = \
 | ||||
|  | ||||
							
								
								
									
										43
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								configure.ac
									
									
									
									
									
								
							| @ -1,6 +1,8 @@ | ||||
| dnl Process this file with autoconf to produce a configure script. | ||||
| 
 | ||||
| AC_INIT(libsxmp, m4_esyscmd([tr -d '\n' < VERSION.sxmp])) | ||||
| AC_SUBST([LIBTDATA_VERSION], m4_esyscmd([tr -d '\n' < tdata/VERSION])) | ||||
| AC_SUBST([LIBSEXPR_VERSION], m4_esyscmd([tr -d '\n' < sexpr/VERSION])) | ||||
| 
 | ||||
| AC_CONFIG_HEADERS([config.h]) | ||||
| 
 | ||||
| @ -12,6 +14,36 @@ AC_PROG_CC | ||||
| 
 | ||||
| LT_INIT | ||||
| 
 | ||||
| # Checks for pointer size. | ||||
| # TODO: Later this is irrelevant, and we should just bail on 32-bit platforms always | ||||
| AC_CHECK_SIZEOF([uintptr_t]) | ||||
| if test "x$ac_cv_sizeof_uintptr_t" == "x"; then | ||||
|   AC_ERROR([Cannot determine size of uintptr_t]) | ||||
| fi | ||||
| AC_SUBST(ac_cv_sizeof_uintptr_t) | ||||
| 
 | ||||
| if test "${ac_cv_sizeof_uintptr_t}" = "4"; then | ||||
|    AC_DEFINE([BUILD_HOST_32BIT], 1, [Define to 1 if host is 32bit]) | ||||
| fi | ||||
| 
 | ||||
| dnl  ************************************** | ||||
| dnl ***** tests for compiler built-ins ***** | ||||
| dnl  ************************************** | ||||
| 
 | ||||
| AC_CACHE_CHECK([for __sync_bool_compare_and_swap_8], | ||||
| [ctrie_cv_func___sync_bool_compare_and_swap_8], | ||||
| [AC_LINK_IFELSE([ | ||||
| typedef unsigned int uint64  __attribute__ ((mode (DI))); | ||||
| uint64 i; | ||||
| int main() { return __sync_bool_compare_and_swap (&i, 0, 1); } | ||||
| ], | ||||
| [ctrie_cv_func___sync_bool_compare_and_swap_8=yes], | ||||
| [ctrie_cv_func___sync_bool_compare_and_swap_8=no])]) | ||||
| if test "$ctrie_cv_func___sync_bool_compare_and_swap_8" = "yes"; then | ||||
|   AC_DEFINE([HAVE__SYNC_BOOL_COMPARE_AND_SWAP_8], 1, | ||||
|     [Define to 1 if the compiler provides the __sync_bool_compare_and_swap function for uint64]) | ||||
| fi | ||||
| 
 | ||||
| dnl  ***************** | ||||
| dnl ***** options ***** | ||||
| dnl  ***************** | ||||
| @ -41,9 +73,6 @@ dnl checking fpr dependencies | ||||
| 
 | ||||
| PKG_CHECK_MODULES(OPENSSL, [openssl]) | ||||
| 
 | ||||
| PKG_CHECK_MODULES(LIBTDATA, [libtdata >= 0.2.2]) | ||||
| PKG_CHECK_MODULES(LIBSEXPR, [libsexpr >= 1.3.1]) | ||||
| 
 | ||||
| case $host_os in  | ||||
| 	linux*) 	WIN32=no | ||||
| 				LINUX=yes | ||||
| @ -72,8 +101,12 @@ dnl AM_CONDITIONAL(BUILD_WIN32, test "x$enable_win32_build" = "xyes") | ||||
| 
 | ||||
| AC_OUTPUT([ | ||||
| Makefile | ||||
| lib/libsxmp.pc | ||||
| lib/Makefile | ||||
| sxmp/libsxmp.pc | ||||
| sxmp/Makefile | ||||
| sexpr/Makefile | ||||
| sexpr/libsexpr.pc | ||||
| tdata/Makefile | ||||
| tdata/libtdata.pc | ||||
| include/Makefile | ||||
| man/Makefile | ||||
| examples/Makefile]) | ||||
|  | ||||
| @ -10,8 +10,8 @@ AM_CPPFLAGS = \ | ||||
| 
 | ||||
| AM_CFLAGS = -Wall -g | ||||
| 
 | ||||
| # where to find libsxmp
 | ||||
| libsxmp = ../lib/.libs/libsxmp.la | ||||
| # where to find libsxmp libraries
 | ||||
| libsxmp = ../sexpr/.libs/libsexpr.la ../tdata/.libs/libtdata.la ../sxmp/.libs/libsxmp.la | ||||
| 
 | ||||
| if BUILD_SMPF_EXAMPLE | ||||
| smpf_programs = smpfd smpfc | ||||
|  | ||||
| @ -1,2 +1,6 @@ | ||||
| nobase_include_HEADERS = sxmp/sxmp.h sxmp/errno.h sxmp/limits.h sxmp/version.h \
 | ||||
| 	sxmp/base64.h | ||||
| 	sxmp/base64.h \
 | ||||
| 	sexpr/cstring.h sexpr/faststack.h sexpr/sexp_errors.h sexpr/sexp.h \
 | ||||
| 	sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h \
 | ||||
| 	tdata/bitwise.h tdata/idx_allocator.h tdata/macro.h tdata/tree.h \
 | ||||
| 	tdata/usrtc.h tdata/list.h tdata/ctrie.h | ||||
|  | ||||
							
								
								
									
										142
									
								
								include/sexpr/cstring.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								include/sexpr/cstring.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,142 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stdlib.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * 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__ */ | ||||
							
								
								
									
										152
									
								
								include/sexpr/faststack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								include/sexpr/faststack.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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. | ||||
|    * <B>Important note</B> : This function <I>does not</I> 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__ */ | ||||
							
								
								
									
										806
									
								
								include/sexpr/sexp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										806
									
								
								include/sexpr/sexp.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,806 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stddef.h> | ||||
| #include <stdio.h> /* 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 1.2, October 2007 \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 <i>value</i> | ||||
|  * represents an atom with an associated text value.  A <i>list</i> | ||||
|  * 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 <i>basic</i> value is a simple string with | ||||
|  * no whitespace (and therefore no quotes required).  A <i>double quote</i> | ||||
|  * value, or <i>dquote</i>, is one that contains characters (such as | ||||
|  * whitespace) that requires quotation marks to contain the string.  A | ||||
|  * <i>single quote</i> value, or <i>squote</i>, 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, <i>binary</I> 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 <I>atom</I> or <I>list</I>.  An | ||||
|  * atom corresponds to a string, while a list corresponds to an | ||||
|  * s-expression.  The following grammar represents our definition of | ||||
|  * an s-expression:<P> | ||||
|  * | ||||
|  * <pre> | ||||
|  * sexpr  ::= ( sx ) | ||||
|  * sx     ::= atom sxtail | sexpr sxtail | 'sexpr sxtail | 'atom sxtail | NULL | ||||
|  * sxtail ::= sx | NULL | ||||
|  * atom   ::= quoted | value | ||||
|  * quoted ::= "ws_string" | ||||
|  * value  ::= nws_string | ||||
|  * </pre> | ||||
|  * <P> | ||||
|  * | ||||
|  * 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 <i>value</i> and data stored in the <i>val</i> | ||||
|  * field.  An element of type <i>list</i> represents an s-expression | ||||
|  * corresponding to <i>sexpr</i> 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 <B>SEXP_VALUE</B>, 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 | ||||
|    * <B>SEXP_LIST</B>, 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 <B>SEXP_VALUE</B> and the aty field | ||||
|    * is not <B>SEXP_BINARY</B>, 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 <B>SEXP_LIST</B>, this field will contain | ||||
|    * a pointer to the head element of the list. | ||||
|    */ | ||||
|   struct elt *list; | ||||
| 
 | ||||
|   /**
 | ||||
|    * The <I>next</I> 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 <I>NULL</I>. | ||||
|    */ | ||||
|   struct elt *next; | ||||
| 
 | ||||
|   /**
 | ||||
|    * For elements that represent <I>values</I>, 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 <i>binary</I> 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. | ||||
|    * <B>IMPORTANT NOTE</B>: 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 <i>last_sexpr</i> 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.<P> | ||||
|  * | ||||
|  * 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 <b>not | ||||
|  * recommended</b> 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 | ||||
|  * <i>parse_sexp</i> function that simply returns an s-expression without | ||||
|  * exposing the continuations, or the <i>iparse_sexp</i> 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.  <I>Note: | ||||
|    * Mallocing your own expressions is fine - you can even use  | ||||
|    * sexp_t_deallocate to deallocate them and put them in the pool.</I> | ||||
|    * 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 <tt>ss</tt> - 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 <B>not</B> 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 | ||||
| 
 | ||||
| /* sexp helpers */ | ||||
| #define SEXP_IS_LIST(sx) \ | ||||
|         ((sx)->ty == SEXP_LIST) ? 1 : 0 | ||||
| 
 | ||||
| #define SEXP_IS_TYPE(sx,type) \ | ||||
|         ((sx)->ty == SEXP_VALUE && (sx)->aty == (type)) ? 1 : 0 | ||||
| 
 | ||||
| #define SEXP_ITERATE_LIST(lst, iter, ind) \ | ||||
|         for((ind) = 0, (iter) = (lst)->list; (ind) < sexp_list_length(lst); \ | ||||
|             (ind)++, (iter) = (iter)->next) | ||||
| 
 | ||||
| /* additional functions to work with sexp */ | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| int sexp_list_cdr(sexp_t *expr, sexp_t **sx); | ||||
| int sexp_list_car(sexp_t *expr, sexp_t **sx); | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #include "sexp_ops.h" | ||||
| 
 | ||||
| #endif /* __SEXP_H__ */ | ||||
| 
 | ||||
							
								
								
									
										148
									
								
								include/sexpr/sexp_errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								include/sexpr/sexp_errors.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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__ */ | ||||
							
								
								
									
										160
									
								
								include/sexpr/sexp_memory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								include/sexpr/sexp_memory.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,160 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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__ */ | ||||
							
								
								
									
										133
									
								
								include/sexpr/sexp_ops.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								include/sexpr/sexp_ops.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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__ */ | ||||
							
								
								
									
										65
									
								
								include/sexpr/sexp_vis.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								include/sexpr/sexp_vis.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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__ */ | ||||
							
								
								
									
										429
									
								
								include/tdata/bitwise.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								include/tdata/bitwise.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,429 @@ | ||||
| /*
 | ||||
|  * This program 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 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. | ||||
|  * | ||||
|  * (c) Copyright 2006,2007,2008 Jari OS Core Team <http://jarios.org>
 | ||||
|  * (c) Copyright 2008 Dmitry Gromada <gromada82@gmail.com> | ||||
|  * (c) Copyright 2010 Alexander Vdolainen <vdo@askele.com> | ||||
|  * | ||||
|  * (c) Copyright 2012 - 2013 Askele Oy <http://askele.com>
 | ||||
|  * | ||||
|  * Implements bitwise operations with multiword bitmaps | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __BITWISE_H__ | ||||
| #define __BITWISE_H__ | ||||
| 
 | ||||
| /* TODO: add arch deps */ | ||||
| //#include <arch/bitwise.h>
 | ||||
| 
 | ||||
| /* TODO: add linux headers tests */ | ||||
| #include <asm-generic/bitsperlong.h> | ||||
| 
 | ||||
| #ifdef __BITS_PER_LONG | ||||
| #define BITS_PER_LONG  __BITS_PER_LONG | ||||
| #endif | ||||
| 
 | ||||
| #if BITS_PER_LONG == 64 | ||||
| #define TYPE_LONG_SHIFT  6 | ||||
| #endif | ||||
| 
 | ||||
| #if BITS_PER_LONG == 32 | ||||
| #define TYPE_LONG_SHIFT  5 | ||||
| #endif | ||||
| 
 | ||||
| typedef struct __bitmap { | ||||
|   int nwords; | ||||
|   unsigned long *map; | ||||
| } bitmap_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void bit_set(void *bitmap, int bit) | ||||
|  * Set bit number @a bit in the bitmap @a bitmap | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param[out] bitmap - A pointer to the bitmap | ||||
|  * @param bit - Number of bit to set | ||||
|  */ | ||||
| #ifndef ARCH_BIT_SET | ||||
| static inline void bit_set(void *bitmap, int bit) | ||||
| { | ||||
|   *(unsigned long *)bitmap |= (1 << bit); | ||||
| } | ||||
| #else | ||||
| #define bit_set(bitmap, bit) arch_bit_set(bitmap, bit) | ||||
| #endif /* ARCH_BIT_SET */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void bit_clear(void *bitmap, int bit) | ||||
|  * Clear bit number @a bit in the bitmap @a bitmap | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param[out] bitmap - A pointer to the bitmap | ||||
|  * @param bit - Number of bit to clear | ||||
|  */ | ||||
| #ifndef ARCH_BIT_CLEAR | ||||
| static inline void bit_clear(void *bitmap, int bit) | ||||
| { | ||||
|   *(unsigned long *)bitmap &= ~(1 << bit); | ||||
| } | ||||
| #else | ||||
| #define bit_clear(bitmap, bit) arch_bit_clear(bitmap, bit) | ||||
| #endif /* ARCH_BIT_CLEAR */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void bit_toggle(void *bitmap, int bit) | ||||
|  * Toggle bit @a bit in the bitmap @a bitmap. | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param[out] bitmap - A pointer to the bitmap. | ||||
|  * @param bit - Number of bit to toggle | ||||
|  */ | ||||
| #ifndef ARCH_BIT_TOGGLE | ||||
| static inline void bit_toggle(void *bitmap, int bit) | ||||
| { | ||||
|   *(unsigned long *)bitmap ^= (1 << bit); | ||||
| } | ||||
| #else | ||||
| #define bit_toggle(bitmap, bit) arch_bit_toggle(bitmap, bit) | ||||
| #endif /* ARCH_BIT_TOGGLE */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline int bit_test(void *bitmap, int bitno) | ||||
|  * Test if bit with number @a bitno is set in the bitmap @a bitmap. | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap. | ||||
|  * @param bitno - Number of bit to test | ||||
|  * @return 1 if bit is set and 0 otherwise | ||||
|  */ | ||||
| #ifndef ARCH_BIT_TEST | ||||
| static inline int bit_test(void *bitmap, int bitno) | ||||
| { | ||||
|   return ((*(unsigned long *)bitmap & (1 << bitno)) >> bitno); | ||||
| } | ||||
| #else | ||||
| #define bit_test(bitmap, bitno) arch_bit_test(bitmap, bitno) | ||||
| #endif /* ARCH_BIT_TEST */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline int bit_test_and_set(void *bitmap, int bitno) | ||||
|  * @brief Get old value of bit with number @a bitno and set @a bitno bit in the bitmap | ||||
|  * | ||||
|  * This function is similar to bit_set() except it copies old bit value before | ||||
|  * setting it to 1 and return that value after needed bit was setted. | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bitno  - The number of bit to test and set | ||||
|  * @return Old value of bit with number @a bitno | ||||
|  */ | ||||
| #ifndef ARCH_BIT_TEST_AND_SET | ||||
| static inline int bit_test_and_set(void *bitmap, int bitno) | ||||
| { | ||||
|   int val = (*(unsigned long *)bitmap & (1 << bitno)); | ||||
|   *(unsigned long *)bitmap |= (1 << bitno); | ||||
| 
 | ||||
|   return val; | ||||
| } | ||||
| #else | ||||
| #define bit_test_and_set(bitmap, bitno) arch_bit_test_and_set(bitmap, bitno) | ||||
| #endif /* ARCH_BIT_TEST_AND_SET */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline int bit_test_and_reset(void *bitmap, int bitno) | ||||
|  * @brief Get old value of bit with number @a bitno and clear @a bitno bit in the bitmap | ||||
|  * | ||||
|  * This function is similar to bit_clear() except it copies old bit value before | ||||
|  * setting it to 1 and return that value after needed bit was setted. | ||||
|  * @note The limit of @a bitmap = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bitno  - The number of bit to test and set | ||||
|  * @return Old value of bit with number @a bitno | ||||
|  */ | ||||
| #ifndef ARCH_BIT_TEST_AND_RESET | ||||
| static inline int bit_test_and_reset(void *bitmap, int bitno) | ||||
| { | ||||
|   int val = (*(unsigned long *)bitmap & (1 << bitno)); | ||||
|   *(unsigned long *)bitmap &= ~(1 << bitno); | ||||
| 
 | ||||
|   return val; | ||||
| } | ||||
| #else | ||||
| #define bit_test_and_reset(bitmap, bitno) arch_bit_test_and_reset(bitmap, bitno) | ||||
| #endif /* ARCH_BIT_TEST_AND_RESET */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline long bit_find_lsf(unsigned long word) | ||||
|  * Find first set least significant bit. | ||||
|  * | ||||
|  * @param word - Where to search | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| #ifndef ARCH_BIT_FIND_LSF | ||||
| static inline long bit_find_lsf(unsigned long word) | ||||
| { | ||||
|   long c = -1; | ||||
| 
 | ||||
|   for (; word; c++, word >>= 1) { | ||||
|     if ((word & 0x01)) { | ||||
|       c++; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return c; | ||||
| } | ||||
| #else | ||||
| #define bit_find_lsf(word) arch_bit_find_lsf(word) | ||||
| #endif /* ARCH_BIT_FIND_LSF */ | ||||
| 
 | ||||
| #ifndef ARCH_ZERO_BIT_FIND_LSF | ||||
| #define zero_bit_find_lsf(word) bit_find_lsf(~(word)) | ||||
| #else | ||||
| #define zero_bit_find_lsf(word) arch_zero_bit_find_lsf(word) | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline long bit_find_msf(unsigned long word) | ||||
|  * Find most significant set bit in the @a word. | ||||
|  * | ||||
|  * @param word - Where to search. | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| #ifndef ARCH_BIT_FIND_MSF | ||||
| static inline long bit_find_msf(unsigned long word) | ||||
| { | ||||
|   long c = -1; | ||||
| 
 | ||||
|   while (word) { | ||||
|     c++; | ||||
|     word >>= 1; | ||||
|   } | ||||
| 
 | ||||
|   return c; | ||||
| } | ||||
| #else | ||||
| #define bit_find_msf(word) arch_bit_find_msf(word) | ||||
| #endif /* ARCH_BIT_FIND_MSF */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline long bit_find_lsfz(unsigned long word) | ||||
|  * Find first zero least significant bit. | ||||
|  * | ||||
|  * @param word - Where to search | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| #ifndef ARCH_BIT_FIND_LSFZ | ||||
| static inline long bit_find_lsfz(unsigned long word) | ||||
| { | ||||
|   long c = -1; | ||||
| 
 | ||||
|   word = ~word; | ||||
|    | ||||
|   for (; word; c++, word >>= 1) { | ||||
|     if ((word & 0x01)) { | ||||
|       c++; | ||||
|       break; | ||||
|     }       | ||||
|   } | ||||
|    | ||||
|   return c; | ||||
| } | ||||
| #else | ||||
| #define bit_find_lsfz(word) arch_bit_find_lsfz(word) | ||||
| #endif /* ARCH_BIT_FIND_LSFZ */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline long bit_find_msfz(unsigned long word) | ||||
|  * Find most significant zero bit in the @a word. | ||||
|  * | ||||
|  * @param word - Where to search. | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| #ifndef ARCH_BIT_FIND_MSFZ | ||||
| static inline long bit_find_msfz(unsigned long word) | ||||
| { | ||||
|   long c = -1; | ||||
| 
 | ||||
|   word = ~word; | ||||
| 
 | ||||
|   while (word) { | ||||
|     c++; | ||||
|     word >>= 1; | ||||
|   } | ||||
| 
 | ||||
|   return c; | ||||
| } | ||||
| #else | ||||
| #define bit_find_msfz(word) arch_bit_find_msfz(word) | ||||
| #endif /* ARCH_BIT_FIND_MSFZ */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void bits_or(void *word, unsigned long flags) | ||||
|  * Executes logical OR with @a word and @a flags and writes result to @a word | ||||
|  * @note The limit of @a word = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param[out] word - A pointer to memory results will be written to | ||||
|  * @param flsgs - Flags that will be OR'ed with @a word | ||||
|  */ | ||||
| #ifndef ARCH_BITS_OR | ||||
| static inline void bits_or(void *word, unsigned long flags) | ||||
| { | ||||
|   *(unsigned long *)word |= flags; | ||||
| } | ||||
| #define bits_or(word, flags) panic("bits_or uniplemented") | ||||
| #else | ||||
| #define bits_or(word, flags) arch_bits_or(word, flags) | ||||
| #endif /* ARCH_BITS_OR */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void bits_and(void *word, unsigned long mask) | ||||
|  * Executes logical AND with @a word and @a mask and writes result to @a word. | ||||
|  * @note The limit of @a word = sizeof(unsigned long) | ||||
|  * | ||||
|  * @param[out] word - A pointer to memory results will be written to | ||||
|  * @param mask - A mask that will be AND'ed with @a word | ||||
|  */ | ||||
| #ifndef ARCH_BITS_AND | ||||
| static inline void bits_and(void *word, unsigned long mask) | ||||
| { | ||||
|   *(unsigned long *)word &= mask; | ||||
| } | ||||
| #else | ||||
| #define bits_and(word, mask) arch_bits_and(word, mask) | ||||
| #endif /* ARCH_BITS_AND */ | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Initialize multiword bitmap | ||||
|  * | ||||
|  * @param map - pointer to the multiword bitmap | ||||
|  * @param bitno - memory size in bits to allocate | ||||
|  * | ||||
|  * @return 0 on success, -1 if can't allocate memory | ||||
|  */ | ||||
| int init_bitmap(bitmap_t *bitmap, int nbits); | ||||
| 
 | ||||
| /*
 | ||||
|  * Free memory taken by multiword bitmap | ||||
|  * | ||||
|  * @param bitmap - bitmap to free | ||||
|  */ | ||||
| void free_bitmap(bitmap_t *map); | ||||
| 
 | ||||
| /**
 | ||||
|  * Set bit number @a bit in the bitmap @a bitmap | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bit - Number of bit to set | ||||
|  */ | ||||
| void bit_set_multi(bitmap_t *bitmap, int bitno); | ||||
| 
 | ||||
| /**
 | ||||
|  * test bit of a multiword bitmap | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bitno  - The number of bit to test | ||||
|  * | ||||
|  * @return value of the specified bit | ||||
|  */ | ||||
| int bit_test_multi(bitmap_t *bitmap, int bitno); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Get old value of bit with number @a bitno and set @a bitno bit in the bitmap | ||||
|  * | ||||
|  * This function is similar to bit_set() except it copies old bit value before | ||||
|  * setting it to 1 and return that value after needed bit was setted. | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bitno  - The number of bit to test and set | ||||
|  * | ||||
|  * @return Old value of bit with number @a bitno or -1 if bitno is illegal | ||||
|  */ | ||||
| int bit_test_and_set_multi(bitmap_t *bitmap, int bitno); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Get old value of bit with number @a bitno and clear @a bitno bit in the bitmap | ||||
|  * | ||||
|  * This function is similar to bit_set() except it copies old bit value before | ||||
|  * setting it to 1 and return that value after needed bit was setted. | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bitno  - The number of bit to test and set | ||||
|  * | ||||
|  * @return Old value of bit with number @a bitno or -1 if bitno is illegal | ||||
|  */ | ||||
| int bit_test_and_reset_multi(bitmap_t *bitmap, int bitno); | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Clear bit number @a bit in the bitmap @a bitmap | ||||
|  * | ||||
|  * @param bitmap - A pointer to the bitmap | ||||
|  * @param bit - Number of bit to clear | ||||
|  */ | ||||
| void bit_clear_multi(bitmap_t *bitmap, int bitno); | ||||
| 
 | ||||
| /*
 | ||||
|  * Set multiple bits in the multiword bitmap | ||||
|  * | ||||
|  * @param bitmap - pointer to the multimap bitmap | ||||
|  * @param start_bit - bit to set from | ||||
|  * int end_bit - bit to set upto | ||||
|  */ | ||||
| void bitrange_set_multi(bitmap_t *bitmap, int start_bit, int end_bit); | ||||
| 
 | ||||
| /*
 | ||||
|  * Clear multiple bits in the multiword bitmap | ||||
|  * | ||||
|  * @param bitmap - pointer to the multimap bitmap | ||||
|  * @param start_bit - bit to clear from | ||||
|  * int end_bit - bit to clear upto | ||||
|  */ | ||||
| void bitrange_clear_multi(bitmap_t *bitmap, int start_bit, int end_bit); | ||||
| 
 | ||||
| /**
 | ||||
|  * Find most significant set bit in multimap word which from the 0 bit | ||||
|  * upto @end_bit | ||||
|  * | ||||
|  * @param word - Where to search. | ||||
|  * @param end_bit - most bit to search upto | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| int bit_find_msf_multi(bitmap_t *bitmap, int mbit); | ||||
| 
 | ||||
| /**
 | ||||
|  * Find first set least significant bit. | ||||
|  * | ||||
|  * @param word - Where to search | ||||
|  * @param sbit - least bit to search from | ||||
|  * @return Found bit number on success, negative value on failure. | ||||
|  */ | ||||
| int bit_find_lsf_multi(bitmap_t *bitmap, int lbit); | ||||
| 
 | ||||
| #ifndef ARCH_BIT_TEST_AND_CLEAR | ||||
| static inline int bit_test_and_clear(void *bitmap, int bitno) | ||||
| { | ||||
|   int val = bit_test(bitmap, bitno); | ||||
|   bit_clear(bitmap, bitno); | ||||
|   return val; | ||||
| } | ||||
| #else | ||||
| #define bit_test_and_clear(bitmap, bitno) arch_bit_test_and_clear(bitmap, bitno) | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __BITWISE_H__ */ | ||||
							
								
								
									
										42
									
								
								include/tdata/ctrie.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								include/tdata/ctrie.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * cas.c | ||||
|  * Copyright (C) 2015 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TDATA_CTRIE_H__ | ||||
| #define __TDATA_CTRIE_H__ | ||||
| 
 | ||||
| #include "../config.h" | ||||
| 
 | ||||
| /* flags */ | ||||
| #define CTRIE_FLAG_RO  (1 << 1) | ||||
| 
 | ||||
| /* structure Ctrie (flags is also underlying node type) */ | ||||
| typedef struct __ctrie_type { | ||||
|   int flags; | ||||
|   void **root; | ||||
| }__attribute__((packed)) ctrie_t; | ||||
| 
 | ||||
| /* structure SNode (key-value node) */ | ||||
| typedef struct __ctrie_snode { | ||||
| 	ct_key_t key; | ||||
| 	void *value; | ||||
| }__attribute__((packed)) ct_snode_t; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif /* __TDATA_CTRIE_H__ */ | ||||
							
								
								
									
										130
									
								
								include/tdata/idx_allocator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								include/tdata/idx_allocator.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
| /*
 | ||||
|  * 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. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  * (c) Copyright 2006,2007,2008 MString Core Team <http://mstring.jarios.org>
 | ||||
|  * (c) Copyright 2009 Dan Kruchinin <dan.kruchinin@gmail.com> | ||||
|  * (c) Copyright 2009 Alfeiks Kaanoken <madtirra@jarios.org> (libc adaptation) | ||||
|  * (c) Copyright 2009 Dmitry Gromada <gromada@jarios.org> (locking added) | ||||
|  * (c) Copyright 2013 Alexander Vdolainen <vdo@askele.com> (verios changes to make it run on linux) | ||||
|  * | ||||
|  * (c) Copyright 2012 - 2013 Askele Oy <http://askele.com>
 | ||||
|  * | ||||
|  * Index allocator | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @file include/libdata/idx_allocator.h | ||||
|  * @brief Index allocator API and definitions | ||||
|  * | ||||
|  * Index allocator is a quite simple bitmaps based data | ||||
|  * structure allowing to allocate non-negative integers | ||||
|  * from an ordered continuous numbers set. | ||||
|  * It may be useful for dynamic allocation of pids, uids and | ||||
|  * other identifiers that must be unique. | ||||
|  * Any identifier from a given set may be allocated, deallocated and reserved | ||||
|  * (which prevents its allocation). | ||||
|  * Note, there is no any sence to use index allocator for relatively | ||||
|  * small(for example for sets containing less than 1024 items) identifier sets. | ||||
|  * Allocator uses *at least* BYTES_PER_ITEM + sizeof(ulong_t) bytes for its internal bitmaps. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __IDX_ALLOCATOR_H__ | ||||
| #define __IDX_ALLOCATOR_H__ | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <pthread.h> | ||||
| 
 | ||||
| typedef unsigned long ulong_t; | ||||
| 
 | ||||
| #define BYTES_PER_ITEM 64 /**< Number of bytes per one entry of a second-level bitmap */ | ||||
| #define WORDS_PER_ITEM (BYTES_PER_ITEM / sizeof(ulong_t)) /**< Number of machine words(ulong_t) per second-level bitmap item */ | ||||
| #define IDX_INVAL    ~0UL /**< Invalid index value */ | ||||
| 
 | ||||
| #define ida_lock_init(lock)     pthread_mutex_init(lock, NULL) | ||||
| #define ida_lock_destroy(lock)  pthread_mutex_destroy(lock); | ||||
| #define ida_lock(a)             pthread_mutex_lock(&a->lock) | ||||
| #define ida_unlock(a)           pthread_mutex_unlock(&a->lock) | ||||
| #define ida_lockable(a)         (a->lck) | ||||
| 
 | ||||
| typedef pthread_mutex_t ida_lock_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * @struct idx_allocator_t | ||||
|  * @brief Index allocator structure | ||||
|  */ | ||||
| typedef struct __idx_allocator { | ||||
|   int size;            /**< Total number of words used for second-level bitmap */ | ||||
|   ulong_t max_id;      /**< Maximum index value(exclusive) */ | ||||
|   ulong_t *main_bmap;  /**< First-level(main) bitmap that splits second-level bitmap on several parts */ | ||||
|   ulong_t *ids_bmap;   /**< Second-level bitmap whose each bit corresponds to particular unique identifier */ | ||||
|   ida_lock_t lock; | ||||
|   int lck; | ||||
| } idx_allocator_t; | ||||
| 
 | ||||
| #define idx_allocator_initialized(ida)  (((idx_allocator_t*)(ida))->max_id) | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Initialize an index allocator. | ||||
|  * @param ida     - A pointer to particular index allocator | ||||
|  * @param idx_max - Maximum index value. | ||||
|  * @lockable - flag to indicate the allocator must support locking itself | ||||
|  */ | ||||
| int idx_allocator_init(idx_allocator_t *ida, ulong_t idx_max, int lockable); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Destroy index allocator. | ||||
|  * | ||||
|  * This function frees space used by allocator's internal | ||||
|  * bitmaps. After it is called, allocator can not be used. | ||||
|  * | ||||
|  * @param ida - A pointer to praticular index allocator. | ||||
|  */ | ||||
| void idx_allocator_destroy(idx_allocator_t *ida); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Allocate new index from an allocator's set. | ||||
|  * @param ida - A pointer to target index allocator. | ||||
|  * @return Valid index value on success, IDX_INVAL on error. | ||||
|  * @see IDX_INVAL | ||||
|  * @see idx_reserve | ||||
|  * @see idx_free | ||||
|  */ | ||||
| ulong_t idx_allocate(idx_allocator_t *ida); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reserves particular index number. | ||||
|  * | ||||
|  * This action prevents named index number from | ||||
|  * allocation. Index allocator skips reserved indices until | ||||
|  * they are fried with idx_free | ||||
|  * | ||||
|  * @param ida - A pointer to particular index allocator. | ||||
|  * @param idx - Number of index to reserve. | ||||
|  * @see idx_free | ||||
|  * @see idx_allocate | ||||
|  */ | ||||
| void idx_reserve(idx_allocator_t *ida, ulong_t idx); | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Free back index @a idx to named allocator @a ida. | ||||
|  * @param ida - Allocator index will be freed back to. | ||||
|  * @param idx - An index to free. | ||||
|  * @see idx_allocate | ||||
|  * @see idx_reserve | ||||
|  */ | ||||
| void idx_free(idx_allocator_t *ida, ulong_t idx); | ||||
| 
 | ||||
| #endif /* __IDX_ALLOCATOR_H__ */ | ||||
							
								
								
									
										428
									
								
								include/tdata/list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								include/tdata/list.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,428 @@ | ||||
| /*
 | ||||
|  * Typical data structures used. | ||||
|  * 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. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  * (c) 2013-2014, 2015 Copyright Askele, inc. <http://askele.com>
 | ||||
|  * (c) 2013-2014, 2015 Copyright Askele Ingria, inc. <http://askele-ingria.com>
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TDATA_LIST_H__ | ||||
| #define __TDATA_LIST_H__ | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define __MILESTONE ((unsigned long)0x123) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def MILESTONES_SEQ(num) ((void *)__MILESTONE##num) | ||||
|  * @brief Easy way to define next item in milestones sequence | ||||
|  * @pararm num - number of milestone in sequence | ||||
|  */ | ||||
| #define MILESTONES_SEQ(num) ((void *)(__MILESTONE + (num))) | ||||
| 
 | ||||
| /* milestones for list's next and prev pointers respectively */ | ||||
| #define MLST_LIST_NEXT MILESTONES_SEQ(1) | ||||
| #define MLST_LIST_PREV MILESTONES_SEQ(2) | ||||
| 
 | ||||
| #ifndef offsetof | ||||
| #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef container_of | ||||
| #define container_of(PTR, TYPE, MEMBER) \ | ||||
|   ((TYPE *)((char *)(PTR) - offsetof(TYPE, MEMBER))) | ||||
| #endif | ||||
| 
 | ||||
| /* init root node of non containerized double linked non cyclic list */ | ||||
| #define nclist_init_root(root)                  \ | ||||
| do {                                            \ | ||||
|   root->next = NULL;                            \ | ||||
|   root->prev = root;                            \ | ||||
| } while (0) | ||||
| 
 | ||||
| /* add to tail of non containerized double linked non cyclic list */ | ||||
| #define nclist_add2tail(root,node)              \ | ||||
| do {                                            \ | ||||
|   typeof(root) __tail = (root)->prev;           \ | ||||
|                                                 \ | ||||
|   __tail->next = node;                          \ | ||||
|   node->prev = __tail;                          \ | ||||
|   node->next = NULL;                            \ | ||||
|   (root)->prev = node;                          \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define nclist_for_each(root, node)             \ | ||||
|   for (node = root; node != NULL; node = node->next) | ||||
| 
 | ||||
| /**
 | ||||
|  * @typedef struct __list_node list_node_t | ||||
|  * @struct __list_node | ||||
|  * @brief List node | ||||
|  */ | ||||
| typedef struct __list_node { | ||||
|   struct __list_node *next; | ||||
|   struct __list_node *prev; | ||||
| } list_node_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * @typedef struct __list_head list_head_t | ||||
|  * @struct __list_head | ||||
|  * @brief List head | ||||
|  * Actually list_head_t is the same as list_node_t, but | ||||
|  * they have different types though. That was done to prevent | ||||
|  * potentional errors(notice that list head is a stub, it's never | ||||
|  * tied with any real data and it's used only to determine where list | ||||
|  * starts and where it ends) | ||||
|  */ | ||||
| typedef struct __list_head { | ||||
|   list_node_t head; /**< Head element of the list */ | ||||
| } list_head_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * @def LIST_DEFINE(name) | ||||
|  * @brief Define and initialize list head with name @a name | ||||
|  * @param name - name of variable | ||||
|  */ | ||||
| #define LIST_DEFINE(name)                                       \ | ||||
|   list_head_t name = { .head = { &(name).head, &(name).head } } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_init_head(list_head_t *lst) | ||||
|  * @brief Initialize list head | ||||
|  * @param lst - a pointer to list head. | ||||
|  */ | ||||
| static inline void list_init_head(list_head_t *lst) | ||||
| { | ||||
|   lst->head.next = lst->head.prev = &lst->head; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_init_node(list_node_t *node) | ||||
|  * @brief Initialize list node | ||||
|  * @param node - a pointer to free(unattached from list) node. | ||||
|  */ | ||||
| static inline void list_init_node(list_node_t *node) | ||||
| { | ||||
|   node->next = MLST_LIST_NEXT; | ||||
|   node->prev = MLST_LIST_PREV; | ||||
| } | ||||
| 
 | ||||
| static inline bool list_node_next_isbound(list_node_t *node) | ||||
| { | ||||
|   return (node->next == MLST_LIST_NEXT); | ||||
| } | ||||
| 
 | ||||
| static inline bool list_node_prev_isbound(list_node_t *node) | ||||
| { | ||||
|   return (node->prev == MLST_LIST_PREV); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_entry(lst, nptr) | ||||
|  * @brief Get item that holds @a nptr node | ||||
|  * @param list - A pointer to the list | ||||
|  * @param nptr - A pointer to the node | ||||
|  * @return A pointer to the object given node contains | ||||
|  */ | ||||
| #define list_entry(node, type, member)                 \ | ||||
|   container_of(node, type, member) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_head(lst) | ||||
|  * @brief Get head of the list | ||||
|  * @param lst - a pointer to list_head_t | ||||
|  * @return A pointer to header list_node_t | ||||
|  */ | ||||
| #define list_head(lst)                          \ | ||||
|   (&(lst)->head) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_node_first(lst) | ||||
|  * @brief Get list's first node | ||||
|  * @param list - A pointer to the list_head_t | ||||
|  * @return A pointer to the list first node | ||||
|  */ | ||||
| #define list_node_first(lst)                    \ | ||||
|   ((lst)->head.next) | ||||
| 
 | ||||
| /**
 | ||||
|  * list_first_entry - get the first element from a list | ||||
|  * @lst: the list head to take the element from. | ||||
|  * @type:	the type of the struct this is embedded in. | ||||
|  * @member:	the name of the list_struct within the struct. | ||||
|  * | ||||
|  * Note, that list is expected to be not empty. | ||||
|  */ | ||||
| #define list_first_entry(lst, type, member) \ | ||||
| 	list_entry((lst)->head.next, type, member) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_node_last(lst) | ||||
|  * @brief Get list's last node | ||||
|  * @param list - A pointer to the list_head_t | ||||
|  * @return A pointer to the list last node | ||||
|  */ | ||||
| #define list_node_last(lst)                     \ | ||||
|   ((lst)->head.prev) | ||||
| 
 | ||||
| /**
 | ||||
|  * list_last_entry - get the last element from a list | ||||
|  * @lst: the list head to take the element from. | ||||
|  * @type:	the type of the struct this is embedded in. | ||||
|  * @member:	the name of the list_struct within the struct. | ||||
|  * | ||||
|  * Note, that list is expected to be not empty. | ||||
|  */ | ||||
| #define list_last_entry(lst, type, member)      \ | ||||
| 	list_entry((lst)->head.prev, type, member) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_add2head(lst, new) | ||||
|  * @brief Add a node @a new to the head of the list | ||||
|  * @param lst - A pointer to the list | ||||
|  * @param new - A pointer to the list node | ||||
|  */ | ||||
| #define list_add2head(lst, new)                 \ | ||||
|   list_add(list_node_first(lst), new) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_add2tail(lst, new) | ||||
|  * @brief Add a node @a new to the tail of the list | ||||
|  * @param lst - A pointer to the list | ||||
|  * @param new - A pointer to node to add | ||||
|  */ | ||||
| #define list_add2tail(lst, new)                         \ | ||||
|   list_add(list_head(lst), new) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_delfromhead(lst) | ||||
|  * @brief Remove first element of the list | ||||
|  * @param lst - A pointer to the list | ||||
|  */ | ||||
| #define list_delfromhead(lst)					\ | ||||
|   list_del(list_node_first(lst)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_delfromtail(lst) | ||||
|  * @brief Remove the last element of the list | ||||
|  * @param list - A pointer to the list | ||||
|  */ | ||||
| #define list_delfromtail(lst)					\ | ||||
|   list_del(list_node_last(lst)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_del(del) | ||||
|  * @brief Remove node @a del from the list | ||||
|  * @param del - A node to remove | ||||
|  */ | ||||
| #define list_del(del)                           \ | ||||
|   (list_del_range(del, del)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_add(before, new, after) | ||||
|  * @param after  - will be the next node after @a new | ||||
|  * @param new    - node to insert | ||||
|  */ | ||||
| #define list_add(after, new)                        \ | ||||
|   (list_add_range(new, new, (after)->prev, after)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_move2head(to, from) | ||||
|  * @brief Move all nodes from list @a from to the head of list @a to | ||||
|  * @param to   - destination list | ||||
|  * @param from - source list | ||||
|  */ | ||||
| #define list_move2head(to, from)                \ | ||||
|   (list_move(list_head(to), list_node_first(to), from)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_move2tail(to, from) | ||||
|  * @brief Move all nodes from list @a from to the tail of list @a to | ||||
|  * @param to   - destination list | ||||
|  * @param from - source list | ||||
|  */ | ||||
| #define list_move2tail(to, from)                \ | ||||
|   (list_move(list_node_last(to), list_head(to), from)) | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_for_each(lst, liter) | ||||
|  * @brief Iterate through each element of the list | ||||
|  * @param lst   - A pointer to list head | ||||
|  * @param liter - A pointer to list which will be used for iteration | ||||
|  */ | ||||
| #define list_for_each(lst, liter)                                       \ | ||||
|   for (liter = list_node_first(lst);                                    \ | ||||
|        (liter) != list_head(lst); (liter) = (liter)->next) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_for_each_safe(lst, liter, save) | ||||
|  * @brief Safe iteration through the list @a lst | ||||
|  * | ||||
|  * This iteration wouldn't be broken even if @a liter will be removed | ||||
|  * from the list | ||||
|  * | ||||
|  * @param lst   - A pointer to the list head | ||||
|  * @param liter - A pointer to list node which will be used for iteration | ||||
|  * @param save  - The same | ||||
|  */ | ||||
| #define list_for_each_safe(lst, liter, save)                            \ | ||||
|   for (liter = list_node_first(lst), save = (liter)->next;              \ | ||||
|        (liter) != list_head(lst); (liter) = (save),                     \ | ||||
|          (save) = (liter)->next) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_for_each_entry(lst, iter, member) | ||||
|  * @brief Iterate through each list node member | ||||
|  * @param lst    - a pointer list head | ||||
|  * @param iter   - a pointer to list entry using as iterator | ||||
|  * @param member - name of list node member in the parent structure | ||||
|  */ | ||||
| #define list_for_each_entry(lst, iter, member)                         \ | ||||
|   for (iter = list_entry(list_node_first(lst), typeof(*iter), member); \ | ||||
|        &iter->member != list_head(lst);                                \ | ||||
|        iter = list_entry(iter->member.next, typeof(*iter), member)) | ||||
| 
 | ||||
| /**
 | ||||
|  * @def list_for_each_entry(lst, iter, member) | ||||
|  * @brief Iterate through each list node member and calls specified function with argument | ||||
|  *        pointing to a list entry | ||||
|  * | ||||
|  * @param lst    - a pointer list head | ||||
|  * @param iter   - a pointer to list entry using as iterator | ||||
|  * @param member - name of list node member in the parent structure | ||||
|  * @param fn     - function doing some actins against each entry of the list | ||||
|  */ | ||||
| #define list_do_for_each_entry(lst, type, member, fn)                   \ | ||||
| {                                                                       \ | ||||
|   type *t;                                                              \ | ||||
|   list_node_t *node, *save;                                             \ | ||||
|                                                                         \ | ||||
|   list_for_each_safe(lst, node, save) {                                 \ | ||||
|     t = container_of(node, type, member);                               \ | ||||
|     fn(t);                                                              \ | ||||
|   }                                                                     \ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline int list_is_empty(list_t *list) | ||||
|  * @brief Determines if list @a list is empty | ||||
|  * @param list - A pointer to list to test | ||||
|  * @return True if list is empty, false otherwise | ||||
|  */ | ||||
| static inline int list_is_empty(list_head_t *list) | ||||
| { | ||||
|   return (list_node_first(list) == list_head(list)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_add_range(list_node_t *first, list_node_t *last, | ||||
|  *                                list_node_t *prev, list_node_t *next) | ||||
|  * @brief Insert a range of nodes from @a frist to @a last after @a prev and before @a last | ||||
|  * @param first - first node of range | ||||
|  * @param last  - last node of range | ||||
|  * @param prev  - after this node a range will be inserted | ||||
|  * @param next  - before this node a range will be inserted | ||||
|  */ | ||||
| static inline void list_add_range(list_node_t *first, list_node_t *last, | ||||
|                                   list_node_t *prev, list_node_t *next) | ||||
| { | ||||
|   next->prev = last; | ||||
|   last->next = next; | ||||
|   prev->next = first; | ||||
|   first->prev = prev; | ||||
| } | ||||
| 
 | ||||
| /* for internal usage */ | ||||
| static inline void __list_del_range(list_node_t *first, list_node_t *last) | ||||
| { | ||||
|   first->prev->next = last->next; | ||||
|   last->next->prev = first->prev; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline list_del_range(list_node_t *first, list_node_t *last) | ||||
|  * @brief Delete nodes from @a first to @a last from list. | ||||
|  * @param fist - first node to delete | ||||
|  * @param last - last node to delete | ||||
|  */ | ||||
| static inline void list_del_range(list_node_t *first, list_node_t *last) | ||||
| { | ||||
|   __list_del_range(first, last); | ||||
|   first->prev = MLST_LIST_PREV; | ||||
|   last->next = MLST_LIST_NEXT; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_cut_sublist(list_node_t *first, list_node_t *last) | ||||
|  * @brief Cut a "sublist" started from @a first and ended with @a last | ||||
|  * | ||||
|  * A @e "sublist" is similar to ordinary list except it hasn't a head. | ||||
|  * In other words it's a cyclic list in which all nodes are equitable. | ||||
|  * | ||||
|  * @param first - From this node sublist will be cutted | ||||
|  * @param last  - The last node in the cutted sequence | ||||
|  */ | ||||
| static inline void list_cut_sublist(list_node_t *first, list_node_t *last) | ||||
| { | ||||
|   __list_del_range(first, last); | ||||
|   first->prev = last; | ||||
|   last->next = first; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_cut_head(list_head_t *head) | ||||
|  * @brief Cut a head from the list and make a "sublist" | ||||
|  * @param head - List's head that will be cutted. | ||||
|  * @see list_cut_sublist | ||||
|  * @see list_set_head | ||||
|  */ | ||||
| static inline void list_cut_head(list_head_t *head) | ||||
| { | ||||
|   list_cut_sublist(list_node_first(head), list_node_last(head)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_cut_head(list_head_t *head) | ||||
|  * @brief Attach a head to the sublist @a cyclist | ||||
|  * @param new_head - A head that will be attached | ||||
|  * @param cyclist  - "sublist" | ||||
|  * @see list_cut_sublist | ||||
|  * @see list_set_head | ||||
|  */ | ||||
| static inline void list_set_head(list_head_t *new_head, list_node_t *cyclist) | ||||
| { | ||||
|   list_add_range(cyclist, cyclist->prev, | ||||
|                  list_node_first(new_head), list_node_last(new_head)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @fn static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from) | ||||
|  * @brief Insert nodes of list @a from after @a prev and before @a next | ||||
|  * @param prev - a node after which nodes of @a from will be inserted | ||||
|  * @param next - a node before which nodes of @a from will be inserted | ||||
|  */ | ||||
| static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from) | ||||
| { | ||||
|   list_add_range(list_node_first(from), list_node_last(from), | ||||
|                  prev, next); | ||||
|   list_init_head(from); | ||||
| } | ||||
| 
 | ||||
| #endif /* __TDATA_LIST_H__ */ | ||||
| 
 | ||||
							
								
								
									
										45
									
								
								include/tdata/macro.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/tdata/macro.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * macro.h | ||||
|  * Copyright (C) 2006-2013 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __MACRO_H__ | ||||
| #define __MACRO_H__ | ||||
| 
 | ||||
| /*this macros just for better source code look and feel*/ | ||||
| 
 | ||||
| #define left usrtc_left | ||||
| #define right usrtc_right | ||||
| #define parent usrtc_parent | ||||
| #define next usrtc_right | ||||
| #define prev usrtc_left | ||||
| #define data usrtc_data | ||||
| #define key usrtc_node_key | ||||
| #define rb_color usrtc_rb_color | ||||
| #define impl_specific usrtc_impldata | ||||
| 
 | ||||
| #define futable usrtc_futable | ||||
| #define nodecount usrtc_nodecount | ||||
| #define maxcount usrtc_maxcount | ||||
| #define dupes_allowed usrtc_dupes_allowed | ||||
| #define sentinel usrtc_sentinel | ||||
| #define compare usrtc_compare | ||||
| #define node_alloc usrtc_node_alloc | ||||
| #define node_free usrtc_node_free | ||||
| #define context usrtc_context | ||||
| 
 | ||||
| #endif /*__MACRO_H__*/ | ||||
							
								
								
									
										47
									
								
								include/tdata/tree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								include/tdata/tree.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * tree.h | ||||
|  * Copyright (C) 2006-2013 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TREE_H__ | ||||
| #define __TREE_H__ | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| 
 | ||||
| #define tree_root_priv(T) ((T)->sentinel.left) | ||||
| #define tree_null_priv(L) (&(L)->sentinel) | ||||
| #define TREE_DEPTH_MAX 64 | ||||
| 
 | ||||
| /*tree functions*/ | ||||
| void usrtc_tree_init(usrtc_t *us); | ||||
| void usrtc_tree_insert(usrtc_t *us, usrtc_node_t *node, const void *key); | ||||
| void usrtc_tree_delete(usrtc_t *us, usrtc_node_t *node, usrtc_node_t **pswap, | ||||
| 											 usrtc_node_t **pchild); | ||||
| usrtc_node_t *usrtc_tree_lookup(usrtc_t *us, const void *key); | ||||
| usrtc_node_t *usrtc_tree_lower_bound(usrtc_t *us, const void *key); | ||||
| usrtc_node_t *usrtc_tree_upper_bound(usrtc_t *us, const void *key); | ||||
| usrtc_node_t *usrtc_tree_first(usrtc_t *us); | ||||
| usrtc_node_t *usrtc_tree_last(usrtc_t *us); | ||||
| usrtc_node_t *usrtc_tree_next(usrtc_t *us, usrtc_node_t *curr); | ||||
| usrtc_node_t *usrtc_tree_prev(usrtc_t *us, usrtc_node_t *curr); | ||||
| void usrtc_tree_convert_to_list(usrtc_t *us); | ||||
| void usrtc_tree_convert_from_list(usrtc_t *us); | ||||
| void usrtc_tree_rotate_left(usrtc_node_t *child, usrtc_node_t *parent); | ||||
| void usrtc_tree_rotate_right(usrtc_node_t *child, usrtc_node_t *parent); | ||||
| 
 | ||||
| 
 | ||||
| #endif /*__TREE_H__*/ | ||||
							
								
								
									
										136
									
								
								include/tdata/usrtc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								include/tdata/usrtc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * usrtc.h | ||||
|  * Copyright (C) 2006-2013 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __USRTC_H__ | ||||
| #define __USRTC_H__ | ||||
| 
 | ||||
| #define USRTC_COUNT_T_MAX  ((1 << (sizeof(unsigned long)*(sizeof(char) << 1)))-1) | ||||
| 
 | ||||
| /*count and some misc typedefs*/ | ||||
| typedef unsigned long usrtc_count_t; | ||||
| typedef unsigned int usrtc_impl_id_t; | ||||
| 
 | ||||
| /* implementations ids,
 | ||||
|  * if you want to add some | ||||
|  * add the id here, don't forget to do it. | ||||
|  */ | ||||
| #define USRTC_LIST      0 | ||||
| #define USRTC_BST       1 | ||||
| #define USRTC_REDBLACK  2 | ||||
| #define USRTC_SPLAY     3 | ||||
| #define USRTC_AVL       4 | ||||
| 
 | ||||
| typedef enum { | ||||
|   usrtc_lst, | ||||
|   usrtc_bst, | ||||
|   usrtc_other | ||||
| } usrtc_impltype_t; | ||||
| 
 | ||||
| typedef enum { | ||||
|   usrtc_red, | ||||
|   usrtc_black | ||||
| } usrtc_rb_color_t; | ||||
| typedef enum { | ||||
|   usrtc_balanced, | ||||
|   usrtc_leftheavy, | ||||
|   usrtc_rightheavy | ||||
| } usrtc_avl_balance_t; | ||||
| 
 | ||||
| /*used for the specific implementation features*/ | ||||
| typedef union { | ||||
|   int usrtc_dummy; | ||||
|   usrtc_rb_color_t usrtc_rb_color; | ||||
|   usrtc_avl_balance_t usrtc_avl_balance; | ||||
| } usrtc_impldata_t; | ||||
| 
 | ||||
| /*universal node*/ | ||||
| typedef struct __usrtc_node_t { | ||||
|   struct __usrtc_node_t *usrtc_left; | ||||
|   struct __usrtc_node_t *usrtc_right; | ||||
|   struct __usrtc_node_t *usrtc_parent; | ||||
|   void *usrtc_data; | ||||
|   const void *usrtc_node_key; | ||||
|   usrtc_impldata_t usrtc_impldata; | ||||
| } usrtc_node_t; | ||||
| 
 | ||||
| typedef long (*usrtc_compare_t)(const void*, const void*); | ||||
| typedef usrtc_node_t *(*usrtc_node_alloc_t)(void *); | ||||
| typedef void (*usrtc_node_free_t)(void *, usrtc_node_t *); | ||||
| 
 | ||||
| typedef struct __usrtc_t { | ||||
|     struct __usrtc_functions_t *usrtc_futable; | ||||
|     usrtc_count_t usrtc_nodecount; | ||||
|     usrtc_count_t usrtc_maxcount; | ||||
|     int usrtc_dupes_allowed; | ||||
|     usrtc_node_t usrtc_sentinel; | ||||
|     usrtc_compare_t usrtc_compare; | ||||
|     usrtc_node_alloc_t usrtc_node_alloc; | ||||
|     usrtc_node_free_t usrtc_node_free; | ||||
|     void *usrtc_context; | ||||
| } usrtc_t; | ||||
| 
 | ||||
| typedef struct __usrtc_functions_t { | ||||
|     void (*usrtc_init)(usrtc_t *); | ||||
|     void (*usrtc_insert)(usrtc_t *, usrtc_node_t *, const void *); | ||||
|     void (*usrtc_delete)(usrtc_t *, usrtc_node_t *); | ||||
|     usrtc_node_t *(*usrtc_lookup)(usrtc_t *, const void *); | ||||
|     usrtc_node_t *(*usrtc_lower_bound)(usrtc_t *, const void *); | ||||
|     usrtc_node_t *(*usrtc_upper_bound)(usrtc_t *, const void *); | ||||
|     usrtc_node_t *(*usrtc_first)(usrtc_t *); | ||||
|     usrtc_node_t *(*usrtc_last)(usrtc_t *); | ||||
|     usrtc_node_t *(*usrtc_next)(usrtc_t *, usrtc_node_t *); | ||||
|     usrtc_node_t *(*usrtc_prev)(usrtc_t *, usrtc_node_t *); | ||||
|     void (*usrtc_convert_to_list)(usrtc_t *); | ||||
|     void (*usrtc_convert_from_list)(usrtc_t *); | ||||
|     usrtc_impltype_t usrtc_type; | ||||
| } usrtc_functions_t; | ||||
| 
 | ||||
| /*basic rtc functions*/ | ||||
| void usrtc_init(usrtc_t *us,int impl,usrtc_count_t maxcount,usrtc_compare_t compare); | ||||
| usrtc_t *usrtc_create(int impl,usrtc_count_t maxcount,usrtc_compare_t compare); | ||||
| void usrtc_destroy(usrtc_t *us); | ||||
| void usrtc_convert_to(usrtc_t *us,int impl); | ||||
| usrtc_count_t usrtc_count(usrtc_t *us); | ||||
| int usrtc_isempty(usrtc_t *us); | ||||
| int usrtc_isfull(usrtc_t *us); | ||||
| int usrtc_alloc_insert(usrtc_t *us,const void *key,void *data); | ||||
| void usrtc_delete_free(usrtc_t *us,usrtc_node_t *node); | ||||
| void usrtc_set_allocator(usrtc_t *us,usrtc_node_alloc_t alloc,usrtc_node_free_t n_free,void *context); | ||||
| void usrtc_allow_dupes(usrtc_t *ud); | ||||
| 
 | ||||
| /*basic node functions*/ | ||||
| void usrtc_node_init(usrtc_node_t *node,void *data); | ||||
| usrtc_node_t *usrtc_node_create(void *data); | ||||
| void usrtc_node_destroy(usrtc_node_t *node); | ||||
| void *usrtc_node_getdata(usrtc_node_t *node); | ||||
| void usrtc_node_setdata(usrtc_node_t *node,void *data); | ||||
| const void *usrtc_node_getkey(usrtc_node_t *node); | ||||
| 
 | ||||
| /*rtc wrappers for the specific data structure functions*/ | ||||
| void usrtc_insert(usrtc_t *us,usrtc_node_t *node,const void *key); | ||||
| void usrtc_delete(usrtc_t *us,usrtc_node_t *node); | ||||
| usrtc_node_t *usrtc_lookup(usrtc_t *us,const void *key); | ||||
| usrtc_node_t *usrtc_lower_bound(usrtc_t *us,const void *key); | ||||
| usrtc_node_t *usrtc_upper_bound(usrtc_t *us,const void *key); | ||||
| usrtc_node_t *usrtc_first(usrtc_t *us); | ||||
| usrtc_node_t *usrtc_last(usrtc_t *us); | ||||
| usrtc_node_t *usrtc_next(usrtc_t *us,usrtc_node_t *node); | ||||
| usrtc_node_t *usrtc_prev(usrtc_t *us,usrtc_node_t *node); | ||||
| 
 | ||||
| #endif /*__USRTC_H__*/ | ||||
							
								
								
									
										38
									
								
								sexpr/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								sexpr/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| ## Process this file with automake to produce Makefile.in
 | ||||
| 
 | ||||
| AM_CPPFLAGS = \
 | ||||
| 	-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
 | ||||
| 	-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
 | ||||
| 	-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
 | ||||
| 	-I../include | ||||
| 
 | ||||
| #if WIN32
 | ||||
| #AM_CPPFLAGS + = -I../../include
 | ||||
| #endif
 | ||||
| 
 | ||||
| AM_CFLAGS =\
 | ||||
| 	 -Wall\
 | ||||
| 	 -g | ||||
| 
 | ||||
| lib_LTLIBRARIES = libsexpr.la | ||||
| 
 | ||||
| 
 | ||||
| libsexpr_la_SOURCES = \
 | ||||
| 	cstring.c event_temp.c faststack.c io.c \
 | ||||
| 	parser.c sexp.c sexp_memory.c sexp_ops.c sexp_vis.c | ||||
| 
 | ||||
| libsexpr_la_LDFLAGS =  | ||||
| 
 | ||||
| libsexpr_la_LIBADD =  | ||||
| 
 | ||||
| ##include_HEADERS = \
 | ||||
| ##	../include/sexpr/cstring.h ../include/sexpr/faststack.h ../include/sexpr/sexp_errors.h \
 | ||||
| ##	../include/sexpr/sexp.h ../include/sexpr/sexp_memory.h ../include/sexpr/sexp_ops.h \
 | ||||
| ##	../include/sexpr/sexp_vis.h
 | ||||
| 
 | ||||
| pkgconfigdir = $(libdir)/pkgconfig | ||||
| pkgconfig_DATA = libsexpr.pc | ||||
| 
 | ||||
| EXTRA_DIST = \
 | ||||
| 	libsexpr.pc.in | ||||
| 
 | ||||
							
								
								
									
										3
									
								
								sexpr/VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								sexpr/VERSION
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| 1.3.1 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										220
									
								
								sexpr/cstring.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								sexpr/cstring.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <sexpr/cstring.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sexpr/sexp_memory.h> | ||||
| #include <sexpr/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)); | ||||
| } | ||||
							
								
								
									
										891
									
								
								sexpr/event_temp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										891
									
								
								sexpr/event_temp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,891 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <assert.h> | ||||
| #include <sexpr/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; | ||||
| } | ||||
							
								
								
									
										221
									
								
								sexpr/faststack.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								sexpr/faststack.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,221 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <sexpr/faststack.h> | ||||
| #include <sexpr/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; | ||||
| } | ||||
							
								
								
									
										139
									
								
								sexpr/io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								sexpr/io.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <fcntl.h> | ||||
| #ifndef WIN32 | ||||
| # include <unistd.h> | ||||
| #else | ||||
| # define ssize_t int | ||||
| # include <io.h> | ||||
| # include <sys/types.h> | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sexpr/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; | ||||
| } | ||||
							
								
								
									
										13
									
								
								sexpr/libsexpr.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								sexpr/libsexpr.pc.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=@exec_prefix@ | ||||
| libdir=@libdir@ | ||||
| datarootdir=@datarootdir@ | ||||
| datadir=@datadir@ | ||||
| includedir=@includedir@ | ||||
| 
 | ||||
| Name: libsexpr | ||||
| Description: Small, fast s-expression handling library (so called sexpr). | ||||
| Version: @LIBSEXPR_VERSION@ | ||||
| Requires:  | ||||
| Libs: -L${libdir} -lsexpr | ||||
| Cflags: -I${includedir} | ||||
							
								
								
									
										1719
									
								
								sexpr/parser.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1719
									
								
								sexpr/parser.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										589
									
								
								sexpr/sexp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										589
									
								
								sexpr/sexp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,589 @@ | ||||
| /**
 | ||||
| @Cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sexpr/sexp.h> | ||||
| #include <sexpr/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. | ||||
|  */ | ||||
| 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 (sx == NULL) { | ||||
| 	buf[0] = '\0'; | ||||
| 	return 0; | ||||
|   } | ||||
| 
 | ||||
|   tmp = *sx; | ||||
|   tmp.next = tmp.list = NULL; | ||||
| 
 | ||||
|   fakehead = copy_sexp(&tmp); | ||||
| 
 | ||||
|   if (fakehead == NULL) { | ||||
|     sexp_errno = SEXP_ERR_MEMORY; | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   fakehead->list = sx->list; | ||||
|   fakehead->next = NULL; /* this is the important part of fakehead */ | ||||
| 
 | ||||
|   stack = make_stack (); | ||||
|   if (stack == NULL) { | ||||
|     sexp_errno = SEXP_ERR_MEMORY; | ||||
|     sexp_t_deallocate(fakehead); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   push (stack, fakehead); | ||||
| 
 | ||||
|   while (stack->top != NULL) | ||||
|     { | ||||
|       top = stack->top; | ||||
|       tdata = (sexp_t *) top->data; | ||||
| 
 | ||||
|       if (tdata == NULL) | ||||
| 	{ | ||||
| 	  pop (stack); | ||||
| 
 | ||||
| 	  if (depth > 0) | ||||
| 	    { | ||||
| 	      b[0] = ')'; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	      depth--; | ||||
| 	      if (left == 0) | ||||
| 		{ | ||||
| 		  sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (stack->top == NULL) | ||||
| 	    break; | ||||
| 
 | ||||
| 	  top = stack->top; | ||||
| 	  top->data = ((sexp_t *) top->data)->next; | ||||
| 	  if (top->data != NULL) | ||||
| 	    { | ||||
| 	      b[0] = ' '; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	      if (left == 0) | ||||
| 		{ | ||||
| 		  sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
|       else if (tdata->ty == SEXP_VALUE) | ||||
| 	{ | ||||
| 	  if (tdata->aty == SEXP_DQUOTE) | ||||
| 	    { | ||||
| 	      b[0] = '\"'; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	    } | ||||
| 	  else if (tdata->aty == SEXP_SQUOTE) | ||||
| 	    { | ||||
| 	      b[0] = '\''; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	    } | ||||
| 
 | ||||
|           if (tdata->aty != SEXP_BINARY && tdata->val_used > 0) { | ||||
| 	    tc = tdata->val; | ||||
|             /* copy value into string */ | ||||
|             while (tc[0] != 0 && left > 0) | ||||
|               { | ||||
|                 /* escape characters that need escaping. */ | ||||
|                 if ((tc[0] == '\"' || tc[0] == '\\') && | ||||
|                     tdata->aty == SEXP_DQUOTE) | ||||
|                   { | ||||
|                     b[0] = '\\'; | ||||
|                     b++; | ||||
|                     left--; | ||||
|                     if (left == 0) break; | ||||
|                   } | ||||
|                  | ||||
|                 b[0] = tc[0]; | ||||
|                 b++; | ||||
|                 tc++; | ||||
|                 left--; | ||||
|                 if (left == 0) | ||||
|                   break; | ||||
|               } | ||||
|           } else { | ||||
|             if (left > 3) { | ||||
|               b[0] = '#'; b[1] = 'b'; b[2] = '#'; | ||||
|               b+=3; | ||||
|               left-=3; | ||||
| 
 | ||||
| #ifndef WIN32 | ||||
|               if ((size_t)(sz = snprintf(b,left,"%lu#",(unsigned long)tdata->binlength)) >= left) { | ||||
| #else | ||||
|               if ((sz = _snprintf(b,left,"%lu#",tdata->binlength)) >= left) { | ||||
| #endif | ||||
|                 left = 0; | ||||
|                 break; | ||||
|               } | ||||
|               b += sz; | ||||
|               left -= sz; | ||||
|                | ||||
|               if (left < tdata->binlength) { | ||||
|                 left = 0; | ||||
|                 break; | ||||
|               } | ||||
| 
 | ||||
| 	      if (tdata->binlength > 0) { | ||||
| 		memcpy(b,tdata->bindata,tdata->binlength); | ||||
| 		left -= tdata->binlength; | ||||
| 		b+=tdata->binlength; | ||||
| 	      } | ||||
| 
 | ||||
|               b[0] = ' '; | ||||
|               left--; | ||||
| 
 | ||||
|             } else { | ||||
|               left = 0;  | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
| 	  if (tdata->aty == SEXP_DQUOTE && left > 0) | ||||
| 	    { | ||||
| 	      b[0] = '\"'; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (left == 0) | ||||
| 	    { | ||||
| 	      sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 	      break; | ||||
| 	    } | ||||
| 
 | ||||
| 	  top->data = ((sexp_t *) top->data)->next; | ||||
| 
 | ||||
| 	  if (top->data != NULL) | ||||
| 	    { | ||||
| 	      b[0] = ' '; | ||||
| 	      b++; | ||||
| 	      left--; | ||||
| 	      if (left == 0) | ||||
| 		{ | ||||
| 		  sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
|       else if (tdata->ty == SEXP_LIST) | ||||
| 	{ | ||||
| 	  depth++; | ||||
| 	  b[0] = '('; | ||||
| 	  b++; | ||||
| 	  left--; | ||||
| 	  if (left == 0) | ||||
| 	    { | ||||
| 	      sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 	      break; | ||||
| 	    } | ||||
| 
 | ||||
| 	  push (stack, tdata->list); | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  sexp_errno = SEXP_ERR_BADCONTENT; | ||||
| 	  destroy_stack (stack); | ||||
| 	  sexp_t_deallocate(fakehead); | ||||
| 	  return -1; | ||||
| 	} | ||||
| 
 | ||||
|     } | ||||
|   while (depth != 0) | ||||
|     { | ||||
|       b[0] = ')'; | ||||
|       b++; | ||||
|       left--; | ||||
|       depth--; | ||||
|       if (left == 0) | ||||
| 	{ | ||||
| 	  sexp_errno = SEXP_ERR_BUFFER_FULL; | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   if (left != 0) { | ||||
|     b[0] = 0; | ||||
|     retval = (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;i<tdata->binlength;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; | ||||
| } | ||||
| 
 | ||||
| /* sexp helpers */ | ||||
| int sexp_list_car(sexp_t *expr, sexp_t **sx) | ||||
| { | ||||
|   if (!SEXP_IS_LIST(expr) || expr->list->ty != SEXP_VALUE)    return 1; | ||||
| 
 | ||||
|   *sx = expr->list; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int sexp_list_cdr(sexp_t *expr, sexp_t **sx) | ||||
| { | ||||
|   /* Dummy function. Can we do cdr properly? */ | ||||
|   if (!SEXP_IS_LIST(expr) || expr->list->ty != SEXP_VALUE)    return 1; | ||||
| 
 | ||||
|   if (!expr->list->next)    *sx = NULL; | ||||
|   else    *sx = expr->list->next; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										125
									
								
								sexpr/sexp_memory.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								sexpr/sexp_memory.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <sexpr/sexp.h> | ||||
| #include <sexpr/sexp_errors.h> | ||||
| #include <sexpr/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_ */ | ||||
							
								
								
									
										224
									
								
								sexpr/sexp_ops.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								sexpr/sexp_ops.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,224 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <sexpr/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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										124
									
								
								sexpr/sexp_vis.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								sexpr/sexp_vis.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | ||||
| /**
 | ||||
| @cond IGNORE | ||||
| 
 | ||||
| ====================================================== | ||||
|  SFSEXP: Small, Fast S-Expression Library version 1.2 | ||||
|  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 <sexpr/faststack.h> | ||||
| #include <sexpr/sexp.h> | ||||
| 
 | ||||
| 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,"{ <type> 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,"<type> SEXP_LIST"); | ||||
| 
 | ||||
|     if (tmp->ty == SEXP_LIST) { | ||||
|       fprintf(fp,"| <list> list | <next> 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> next\"];\n", | ||||
| 		(unsigned long)tmp->binlength); | ||||
|       else  | ||||
| 	fprintf(fp,"| { va=%lu | vu=%lu } | val=%s | <next> 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; | ||||
| } | ||||
| @ -29,7 +29,7 @@ libsxmp_la_LIBADD += -lmman -luuid /mingw64/lib/libsexpr.a /mingw64/lib/libtdata | ||||
| 
 | ||||
| else | ||||
| 
 | ||||
| libsxmp_la_LIBADD += $(LIBTDATA_LIBS) $(LIBSEXPR_LIBS) $(LIBUUID_LIBS) | ||||
| libsxmp_la_LIBADD += $(LIBUUID_LIBS) ../tdata/.libs/libtdata.la ../sexpr/.libs/libsexpr.la | ||||
| 
 | ||||
| endif !COND_WIN32 | ||||
| 
 | ||||
							
								
								
									
										34
									
								
								tdata/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tdata/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| ## Process this file with automake to produce Makefile.in
 | ||||
| 
 | ||||
| AM_CPPFLAGS = \
 | ||||
| 	-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
 | ||||
| 	-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
 | ||||
| 	-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
 | ||||
| 	$(LIBTDATA_CFLAGS) -I../include | ||||
| 
 | ||||
| AM_CFLAGS =\
 | ||||
| 	 -Wall\
 | ||||
| 	 -g | ||||
| 
 | ||||
| lib_LTLIBRARIES = libtdata.la | ||||
| 
 | ||||
| 
 | ||||
| libtdata_la_SOURCES = \
 | ||||
| 	avl.c lslist.c redblack.c splay.c \
 | ||||
| 	tree.c usrtc.c bitwise.c idx_allocator.c \
 | ||||
| 	cas.c | ||||
| 
 | ||||
| libtdata_la_LDFLAGS =  | ||||
| 
 | ||||
| libtdata_la_LIBADD =  | ||||
| 
 | ||||
| ##include_HEADERS = \
 | ||||
| ##	../include/tdata/macro.h ../include/tdata/tree.h ../include/tdata/usrtc.h \
 | ||||
| ##	../include/tdata/bitwise.h ../include/tdata/idx_allocator.h
 | ||||
| 
 | ||||
| pkgconfigdir = $(libdir)/pkgconfig | ||||
| pkgconfig_DATA = libtdata.pc | ||||
| 
 | ||||
| EXTRA_DIST = \
 | ||||
| 	libtdata.pc.in | ||||
| 
 | ||||
							
								
								
									
										3
									
								
								tdata/VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tdata/VERSION
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| 0.2.3 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										328
									
								
								tdata/avl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								tdata/avl.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,328 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * avl.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| #include <tdata/macro.h> | ||||
| #include <tdata/tree.h> | ||||
| 
 | ||||
| #define balance     usrtc_impldata.usrtc_avl_balance | ||||
| #define BALANCED    usrtc_balanced | ||||
| #define LEFTHEAVY   usrtc_leftheavy | ||||
| #define RIGHTHEAVY  usrtc_rightheavy | ||||
| 
 | ||||
| /*local functions prototypes*/ | ||||
| static void avl_init(usrtc_t *); | ||||
| static void avl_insert(usrtc_t *,usrtc_node_t *,const void *); | ||||
| static void avl_delete(usrtc_t *,usrtc_node_t *); | ||||
| static void avl_convert_from_list(usrtc_t *); | ||||
| 
 | ||||
| usrtc_functions_t usrtc_avl_fu = { | ||||
|   avl_init, | ||||
|   avl_insert, | ||||
|   avl_delete, | ||||
|   usrtc_tree_lookup, | ||||
|   usrtc_tree_lower_bound, | ||||
|   usrtc_tree_upper_bound, | ||||
|   usrtc_tree_first, | ||||
|   usrtc_tree_last, | ||||
|   usrtc_tree_next, | ||||
|   usrtc_tree_prev, | ||||
|   usrtc_tree_convert_to_list, | ||||
|   avl_convert_from_list, | ||||
|   usrtc_bst | ||||
| }; | ||||
| 
 | ||||
| /*internal use*/ | ||||
| static void rotate_left(usrtc_node_t **); | ||||
| static void rotate_right(usrtc_node_t **); | ||||
| static void fix_balance(usrtc_node_t **,usrtc_avl_balance_t ); | ||||
| static int insert(usrtc_t *,usrtc_node_t *,usrtc_node_t **,usrtc_node_t *); | ||||
| static usrtc_node_t *make_tree(usrtc_node_t **,usrtc_count_t ,int *,usrtc_node_t *); | ||||
| 
 | ||||
| /*implementation*/ | ||||
| static void avl_init(usrtc_t *us) | ||||
| { | ||||
|   usrtc_tree_init(us); | ||||
|   us->sentinel.balance=BALANCED; | ||||
| } | ||||
| 
 | ||||
| static void avl_insert(usrtc_t *us,usrtc_node_t *node,const void *key) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|    | ||||
|   node->key=key; | ||||
|   node->left=nil; | ||||
|   node->right=nil; | ||||
|   node->balance=BALANCED; | ||||
|    | ||||
|   if(insert(us,node,&nil->left,nil)) { | ||||
|     nil->balance=LEFTHEAVY; | ||||
|   } | ||||
|    | ||||
|   us->nodecount++; | ||||
| } | ||||
| 
 | ||||
| static void avl_delete(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *swap; | ||||
|   usrtc_node_t *child; | ||||
|   usrtc_node_t *parent; | ||||
| 
 | ||||
|   /*basic deletion*/ | ||||
|   usrtc_tree_delete(us,node,&swap,&child); | ||||
| 
 | ||||
|   /*implementation specific*/ | ||||
|   swap->balance=node->balance; | ||||
|   parent=child->parent; | ||||
| 
 | ||||
|   if(parent==nil) { | ||||
|     if(child==nil) { | ||||
|       parent->balance=BALANCED; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   while(parent!=nil) { | ||||
|     if((parent->left==nil) && (parent->right==nil)) { | ||||
|       if(child!=nil) | ||||
| 	return; | ||||
|       if(parent==BALANCED) | ||||
| 	return; | ||||
|       parent->balance=BALANCED; | ||||
|     } | ||||
|     else { | ||||
|       usrtc_node_t **pparent; | ||||
|       if(parent==parent->parent->left) | ||||
| 	pparent=&parent->parent->left; | ||||
|       else | ||||
| 	pparent=&parent->parent->right; | ||||
| 
 | ||||
|       if(child==parent->left) | ||||
| 	fix_balance(pparent,RIGHTHEAVY); | ||||
|       else { | ||||
| 	if(child!=parent->right) | ||||
| 	  return; | ||||
| 
 | ||||
| 	fix_balance(pparent,LEFTHEAVY); | ||||
|       } | ||||
| 
 | ||||
|       parent=*pparent; | ||||
|     } | ||||
| 
 | ||||
|     if(parent->balance==BALANCED) { | ||||
|       child=parent; | ||||
|       parent=child->parent; | ||||
|     } | ||||
|     else | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void avl_convert_from_list(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *root; | ||||
|   int height; | ||||
|    | ||||
|   if(us->nodecount==0) { | ||||
|     nil->balance=BALANCED; | ||||
|     return; | ||||
|   } | ||||
|    | ||||
|   root=make_tree(&nil->next,us->nodecount,&height,nil); | ||||
| 
 | ||||
|   if(nil->next!=nil) | ||||
|     return; | ||||
|    | ||||
|   nil->left=root; | ||||
|   root->parent=nil; | ||||
|   nil->balance=LEFTHEAVY; | ||||
| } | ||||
| 
 | ||||
| /*---*/ | ||||
| static void rotate_left(usrtc_node_t **top) | ||||
| { | ||||
|   usrtc_node_t *parent=*top; | ||||
|   usrtc_node_t *child=parent->right; | ||||
|    | ||||
|   child->parent=parent->parent; | ||||
|   parent->right=child->left; | ||||
|   parent->right->parent=parent; | ||||
|   child->left=parent; | ||||
|   parent->parent=child; | ||||
|   *top=child; | ||||
| } | ||||
| 
 | ||||
| static void rotate_right(usrtc_node_t **top) | ||||
| { | ||||
|   usrtc_node_t *parent=*top; | ||||
|   usrtc_node_t *child=parent->left; | ||||
|    | ||||
|   child->parent=parent->parent; | ||||
|   parent->left=child->right; | ||||
|   parent->left->parent=parent; | ||||
|   child->right=parent; | ||||
|   parent->parent=child; | ||||
|   *top=child; | ||||
| } | ||||
| 
 | ||||
| static void fix_balance(usrtc_node_t **pnode,usrtc_avl_balance_t bal) | ||||
| { | ||||
|   usrtc_node_t *node=*pnode; | ||||
|   usrtc_node_t *child; | ||||
|   usrtc_node_t *grandchild; | ||||
| 
 | ||||
|   if(node->balance==BALANCED) | ||||
|     node->balance=bal; | ||||
|   else if(node->balance!=bal) | ||||
|     node->balance=BALANCED; | ||||
|   else { | ||||
|     if(node->balance!=bal) | ||||
|       return; | ||||
| 
 | ||||
|     if(bal==LEFTHEAVY) { | ||||
|       child=node->left; | ||||
|       if(child->balance==LEFTHEAVY) { | ||||
| 	node->balance=BALANCED; | ||||
| 	child->balance=BALANCED; | ||||
| 	rotate_right(pnode); | ||||
|       } | ||||
|       else if(child->balance==BALANCED) { | ||||
| 	node->balance=LEFTHEAVY; | ||||
| 	child->balance=RIGHTHEAVY; | ||||
| 	rotate_right(pnode); | ||||
|       } | ||||
|       else { | ||||
| 	grandchild=child->right; | ||||
| 	if(grandchild->balance==LEFTHEAVY) { | ||||
| 	  node->balance=RIGHTHEAVY; | ||||
| 	  child->balance=BALANCED; | ||||
| 	} | ||||
| 	else if(grandchild->balance==RIGHTHEAVY) { | ||||
| 	  node->balance=BALANCED; | ||||
| 	  child->balance=LEFTHEAVY; | ||||
| 	} | ||||
| 	else { | ||||
| 	  node->balance=BALANCED; | ||||
| 	  child->balance=BALANCED; | ||||
| 	} | ||||
| 	grandchild->balance=BALANCED; | ||||
| 	rotate_left(&node->left); | ||||
| 	rotate_right(pnode); | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       child=node->right; | ||||
|       if(child->balance==RIGHTHEAVY) { | ||||
| 	node->balance=BALANCED; | ||||
| 	child->balance=BALANCED; | ||||
| 	rotate_left(pnode); | ||||
|       } | ||||
|       else if(child->balance==BALANCED) { | ||||
| 	node->balance=RIGHTHEAVY; | ||||
| 	child->balance=LEFTHEAVY; | ||||
| 	rotate_left(pnode); | ||||
|       } | ||||
|       else { | ||||
| 	grandchild=child->left; | ||||
| 	if(grandchild->balance==RIGHTHEAVY) { | ||||
| 	  node->balance=LEFTHEAVY; | ||||
| 	  child->balance=BALANCED; | ||||
| 	} | ||||
| 	else if(grandchild->balance==LEFTHEAVY) { | ||||
| 	  node->balance=BALANCED; | ||||
| 	  child->balance=RIGHTHEAVY; | ||||
| 	} | ||||
| 	else { | ||||
| 	  node->balance=BALANCED; | ||||
| 	  child->balance=BALANCED; | ||||
| 	} | ||||
| 	grandchild->balance=BALANCED; | ||||
| 	rotate_right(&node->right); | ||||
| 	rotate_left(pnode); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static int insert(usrtc_t *us,usrtc_node_t *what,usrtc_node_t **where,usrtc_node_t *parent) | ||||
| { | ||||
|   usrtc_node_t *here=*where; | ||||
|   int result; | ||||
| 
 | ||||
|   if(here==tree_null_priv(us)) { | ||||
|     *where=what; | ||||
|     what->parent=parent; | ||||
|     return 1; | ||||
|   } | ||||
|   else { | ||||
|     result=us->compare(what->key,here->key);	 | ||||
| 
 | ||||
|     if(result < 0) { | ||||
|       if(insert(us,what,&here->left,here)) { | ||||
| 	fix_balance(where,LEFTHEAVY); | ||||
| 	return ((*where)->balance!=BALANCED); | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       if(insert(us,what,&here->right,here)) { | ||||
| 	fix_balance(where,RIGHTHEAVY); | ||||
| 	return ((*where)->balance!=BALANCED); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *make_tree(usrtc_node_t **pnode,usrtc_count_t count, | ||||
| 			       int *pheight,usrtc_node_t *nil) | ||||
| { | ||||
|   usrtc_count_t leftcount; | ||||
|   int leftheight, rightheight; | ||||
|   usrtc_node_t *root; | ||||
|   usrtc_node_t *leftroot; | ||||
| 
 | ||||
|   if(count==0) { | ||||
|     *pheight=0; | ||||
|     return nil; | ||||
|   } | ||||
| 
 | ||||
|   leftcount=(count-1)/2; | ||||
|   leftroot=make_tree(pnode,leftcount,&leftheight,nil); | ||||
|   count-=leftcount; | ||||
| 
 | ||||
|   root=*pnode; | ||||
|   *pnode=root->next; | ||||
|   --count; | ||||
| 
 | ||||
|   root->left=leftroot; | ||||
|   leftroot->parent=root; | ||||
|   root->right=make_tree(pnode,count,&rightheight,nil); | ||||
|   root->right->parent=root; | ||||
| 
 | ||||
|   if(leftheight>rightheight) | ||||
|     return (void *)0; | ||||
| 
 | ||||
|   *pheight=rightheight+1; | ||||
|   root->balance=(leftheight==rightheight) ? BALANCED : RIGHTHEAVY; | ||||
| 
 | ||||
|   return root; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										201
									
								
								tdata/bitwise.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								tdata/bitwise.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
| /*
 | ||||
|  * This program 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 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. | ||||
|  * | ||||
|  * (c) Copyright 2006,2007,2008 Jari OS Core Team <http://jarios.org>
 | ||||
|  * (c) Copyright 2008 Dmitry Gromada <gromada82@gmail.com> | ||||
|  * (c) Copyright 2010 Alexander Vdolainen <vdo@askele.com> | ||||
|  * | ||||
|  * (c) Copyright 2012 - 2013, 2014 Askele Oy <http://askele.com>
 | ||||
|  * | ||||
|  * Implements bitwise operations with multiword bitmaps | ||||
|  */ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <sys/types.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <tdata/bitwise.h> | ||||
| 
 | ||||
| /* operation equivalent to division modulo number of power 2 */ | ||||
| #define MOD_POW2(var, pow) ((var) & ((pow) - 1)) | ||||
| 
 | ||||
| int init_bitmap(bitmap_t *bitmap, int nbits) | ||||
| { | ||||
|   int ret = 0; | ||||
|   int size = nbits >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   if (nbits < 0) | ||||
|     return -1; | ||||
| 
 | ||||
|   if (size << TYPE_LONG_SHIFT != nbits) | ||||
|      size++; | ||||
| 
 | ||||
|   bitmap->map = (unsigned long*)malloc(size * sizeof(unsigned long)); | ||||
|   if (bitmap->map == NULL) | ||||
|     ret = -1; | ||||
|   else | ||||
|      bitmap->nwords = size; | ||||
| 
 | ||||
|   memset(bitmap->map, 0, size * sizeof(unsigned long)); | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void free_bitmap(bitmap_t *bitmap) | ||||
| { | ||||
|   if (bitmap->map) { | ||||
|     free(bitmap->map); | ||||
|     bitmap->map = NULL; | ||||
|   } | ||||
|   bitmap->nwords = 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bit_set_multi(bitmap_t *bitmap, int bitno) | ||||
| { | ||||
|   int i = bitno >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   return bit_set( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) ); | ||||
| } | ||||
| 
 | ||||
| int bit_test_and_set_multi(bitmap_t *bitmap, int bitno) | ||||
| { | ||||
|   int i = bitno >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   return bit_test_and_set( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) ); | ||||
| } | ||||
| 
 | ||||
| int bit_test_and_reset_multi(bitmap_t *bitmap, int bitno) | ||||
| { | ||||
|   int i = bitno >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   return bit_test_and_reset( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) ); | ||||
| } | ||||
| 
 | ||||
| void bit_clear_multi(bitmap_t *bitmap, int bitno) | ||||
| { | ||||
|   int i = bitno >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   return bit_clear( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) ); | ||||
| } | ||||
| 
 | ||||
| int bit_find_msf_multi(bitmap_t *bitmap, int mbit) | ||||
| { | ||||
|   int i, r; | ||||
|   unsigned long word; | ||||
| 
 | ||||
|   if (mbit < 0) | ||||
|     return -1; | ||||
|   else if (mbit >= bitmap->nwords * BITS_PER_LONG) | ||||
|     mbit = bitmap->nwords * BITS_PER_LONG - 1; | ||||
| 
 | ||||
|   i = mbit >> TYPE_LONG_SHIFT; | ||||
|   word = bitmap->map[i] & (~0UL >> ( BITS_PER_LONG - 1 - MOD_POW2(mbit, BITS_PER_LONG) )); | ||||
|   r = bit_find_msf(word); | ||||
| 
 | ||||
|   while ((r == -1) && (--i >= 0)) { | ||||
|     if (bitmap->map[i]) | ||||
|       r = bit_find_msf(bitmap->map[i]); | ||||
|   } | ||||
| 
 | ||||
|   r = (r == -1) ? r : (i * BITS_PER_LONG + r); | ||||
| 
 | ||||
|   return r; | ||||
| } | ||||
| 
 | ||||
| int bit_find_lsf_multi(bitmap_t *bitmap, int lbit) | ||||
| { | ||||
|   int i, r; | ||||
|   unsigned long word; | ||||
| 
 | ||||
|   if (lbit >= bitmap->nwords * BITS_PER_LONG) | ||||
|     return -1; | ||||
|   else if (lbit < 0) | ||||
|     lbit = 0; | ||||
| 
 | ||||
|   i = lbit >> TYPE_LONG_SHIFT; | ||||
|   word = bitmap->map[i] & (~0UL << MOD_POW2(lbit, BITS_PER_LONG)); | ||||
|   r = bit_find_lsf(word); | ||||
| 
 | ||||
|   while ((r == -1) && (++i < bitmap->nwords)) { | ||||
|     if (bitmap->map[i]) | ||||
|       r = bit_find_lsf(bitmap->map[i]); | ||||
|   } | ||||
| 
 | ||||
|   r = (r == -1) ? r : (i * BITS_PER_LONG + r); | ||||
| 
 | ||||
|   return r; | ||||
| } | ||||
| 
 | ||||
| int bit_test_multi(bitmap_t *bitmap, int bitno) | ||||
| { | ||||
|   int i = bitno >> TYPE_LONG_SHIFT; | ||||
| 
 | ||||
|   return bit_test( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) ); | ||||
| } | ||||
| 
 | ||||
| void bitrange_set_multi(bitmap_t *bitmap, int start_bit, int end_bit) | ||||
| { | ||||
|   int i1, i2; | ||||
|   unsigned long mask1, mask2, *p = bitmap->map; | ||||
| 
 | ||||
|   if (start_bit > end_bit) | ||||
|     return; | ||||
| 
 | ||||
|   i1 = start_bit >> TYPE_LONG_SHIFT; | ||||
|   mask1 = ~0UL << MOD_POW2(start_bit, BITS_PER_LONG); | ||||
| 
 | ||||
|   i2 = end_bit >> TYPE_LONG_SHIFT; | ||||
|   mask2 = ~0UL >> (BITS_PER_LONG - 1 - MOD_POW2(end_bit, BITS_PER_LONG)); | ||||
| 
 | ||||
|   if (i1 == i2) | ||||
|     p[i1] |= mask1 & mask2; | ||||
|   else { | ||||
|     p[i1++] |= mask1; | ||||
| 
 | ||||
|     if (i2 - i1 > 0) | ||||
|       memset( p + i1, 0xFF, (i2 - i1) * sizeof(unsigned long) ); | ||||
| 
 | ||||
|     p[i2] |= mask2; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void bitrange_clear_multi(bitmap_t *bitmap, int start_bit, int end_bit) | ||||
| { | ||||
|   int          i1, i2; | ||||
|   unsigned long mask1, mask2, *p = bitmap->map; | ||||
| 
 | ||||
|   if (start_bit > end_bit) | ||||
|     return; | ||||
| 
 | ||||
|   i1 = start_bit >> TYPE_LONG_SHIFT; | ||||
|   mask1 = ( 1UL << (start_bit & MOD_POW2(start_bit, BITS_PER_LONG)) ) - 1; | ||||
| 
 | ||||
|   i2 = end_bit >> TYPE_LONG_SHIFT; | ||||
|   mask2 = ~0UL << (MOD_POW2(end_bit, BITS_PER_LONG) + 1); | ||||
| 
 | ||||
|   if (i1 == i2) | ||||
|     p[i1] &= mask1 | mask2; | ||||
|   else { | ||||
|     p[i1++] &= mask1; | ||||
| 
 | ||||
|     if (i2 - i1 > 0) | ||||
|       memset(p + i1, 0, (i2 - i1) * sizeof(unsigned long)); | ||||
| 
 | ||||
|     p[i2] &= mask2; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										51
									
								
								tdata/cas.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								tdata/cas.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * cas.c | ||||
|  * Copyright (C) 2015 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "../config.h" | ||||
| 
 | ||||
| #if !defined (HAVE__SYNC_BOOL_COMPARE_AND_SWAP_8) | ||||
| #include <pthread.h> | ||||
| static pthread_mutex_t __sync_lock = PTHREAD_MUTEX_INITIALIZER; | ||||
| #endif | ||||
| 
 | ||||
| #ifndef HAVE__SYNC_BOOL_COMPARE_AND_SWAP_8 | ||||
| _Bool __sync_bool_compare_and_swap_8 (uint64_t*, uint64_t, uint64_t) | ||||
| __attribute__ ((visibility ("hidden"))); | ||||
| 
 | ||||
| _Bool __sync_bool_compare_and_swap_8 (uint64_t* ptr, uint64_t old, uint64_t new) | ||||
| { | ||||
|   int i; | ||||
|   _Bool ret; | ||||
| 
 | ||||
|   i = pthread_mutex_lock(&__sync_lock); | ||||
| 
 | ||||
|   if(*ptr != old)    ret = 0; | ||||
|   else { | ||||
|     *ptr = new; | ||||
|     ret = 1; | ||||
|   } | ||||
| 
 | ||||
|   i = pthread_mutex_unlock(&__sync_lock); | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										254
									
								
								tdata/idx_allocator.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								tdata/idx_allocator.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,254 @@ | ||||
| /*
 | ||||
|  * 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. | ||||
|  * | ||||
|  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  * (c) Copyright 2006,2007,2008 MString Core Team <http://mstring.jarios.org>
 | ||||
|  * (c) Copyright 2009 Dan Kruchinin <dan.kruchinin@gmail.com> | ||||
|  * (c) Copyright 2009 Alexander Vdolainen <madtirra@jarios.org> (libc adaptation) | ||||
|  * (c) Copyright 2009 Dmitry Gromada <gromada@jarios.org> (locking added) | ||||
|  * (c) Copyright 2013 Alexander Vdolainen <vdo@askele.com> (verios changes to make it run on linux) | ||||
|  * | ||||
|  * (c) Copyright 2012 - 2013, 2014 Askele Oy <http://askele.com>
 | ||||
|  * | ||||
|  * Index allocator | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <assert.h> | ||||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <tdata/bitwise.h> | ||||
| #include <tdata/idx_allocator.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Main idea of index allocator is quite simple: | ||||
|  * There is a group of tasks that requires dynamic allocation | ||||
|  * of unique non-negative integer identifiers. Where a set of such | ||||
|  * integers is relatively big (thousands of numbers), index allocator | ||||
|  * becomes a nifty solution. | ||||
|  * The core of allocator is two bitmaps. One of them called "indices bitmap" | ||||
|  * or "second level bitmap". Each bit of that bitmap corresponds to particular unique | ||||
|  * index. Since second-level bitmap is a large portion of continuous memory, searching | ||||
|  * of set/zero bit in it becomes relatively slow. For speeding-up search process we invented | ||||
|  * a first-level bitmap. Second-level array is splitted on groups each of them contains BYTES_PER_ITEM bytes. | ||||
|  * First-level(or main) bitmap establishes corresponding between particular group and its | ||||
|  * state(group may have free indices or not). | ||||
|  * So index allocation assumes at first searching of group index in a the first-level bitmap and only | ||||
|  * then searching an index in the second level bitmap starting from a group index. | ||||
|  */ | ||||
| 
 | ||||
| #define MIN_IDA_SIZE (WORDS_PER_ITEM * sizeof(ulong_t)) | ||||
| #define MAX_UNLOCKED_ATTEMPTS 3 | ||||
| 
 | ||||
| /* there macros defined only on new glibc (from 12-jul-2013), let's use our own */ | ||||
| #ifndef is_powerof2 | ||||
| #define is_powerof2(num) (((num) & ~((num) - 1)) == (num)) | ||||
| #endif | ||||
| #ifndef round_up_pow2 | ||||
| #define round_up_pow2(x) (!is_powerof2(x) ? (1 << (bit_find_msf(x) + 1)) : (x) ) | ||||
| #endif | ||||
| 
 | ||||
| static inline size_t __get_main_bmap_size(idx_allocator_t *ida) | ||||
| { | ||||
|   if (ida->ids_bmap != NULL) | ||||
|     return (round_up_pow2((ida->size * sizeof(ulong_t)) / BYTES_PER_ITEM)); | ||||
| 
 | ||||
|   return ida->size; | ||||
| } | ||||
| 
 | ||||
| ulong_t idx_allocate(idx_allocator_t *ida) | ||||
| { | ||||
|   ulong_t id = IDX_INVAL; | ||||
|   long fnfi = 0; | ||||
|   size_t i, main_offs = 0, main_sz; | ||||
|   int natm = 0;   /* attempt number */ | ||||
| 
 | ||||
|   main_sz = __get_main_bmap_size(ida) / sizeof(ulong_t); | ||||
|   i = 0; | ||||
| 
 | ||||
|   if (ida->ids_bmap != NULL) { | ||||
|     for (;;) { | ||||
|       while (i < main_sz) { | ||||
|         fnfi = zero_bit_find_lsf(ida->main_bmap[i]); | ||||
|         if (fnfi >= 0) { | ||||
|           fnfi = (fnfi * WORDS_PER_ITEM) + i * WORDS_PER_ITEM * BITS_PER_LONG; | ||||
|           main_offs = i; | ||||
|           break; | ||||
|         } | ||||
| 
 | ||||
|         i++; | ||||
|       } | ||||
|       if ((fnfi >= 0) && (fnfi < ida->size)) { | ||||
|         int res_id, j, total_sz; | ||||
| 
 | ||||
|         total_sz = fnfi + WORDS_PER_ITEM; | ||||
|         j = fnfi; | ||||
|         while (j < total_sz) { | ||||
|           res_id = zero_bit_find_lsf(ida->ids_bmap[j]); | ||||
|           if (res_id < 0) { | ||||
|             j++; | ||||
|             continue; | ||||
|           } | ||||
| 
 | ||||
|           if (ida_lockable(ida) /*&& atomic_test_and_set_bit(ida->ids_bmap + j, res_id)*/) { | ||||
|             natm++; | ||||
|             if (natm == MAX_UNLOCKED_ATTEMPTS) | ||||
|               ida_lock(ida); | ||||
|           } else { | ||||
|             bit_set(ida->ids_bmap + j, res_id); | ||||
|           } | ||||
| 
 | ||||
|           id = res_id + j * BITS_PER_LONG; | ||||
|           if (id >= ida->max_id) { | ||||
|             bit_clear(ida->ids_bmap + j, res_id); | ||||
|             id = IDX_INVAL; | ||||
|           } | ||||
| 
 | ||||
|           goto out; | ||||
|         } | ||||
| 
 | ||||
|         bit_set(ida->main_bmap + main_offs, | ||||
|                 (fnfi - (main_offs * WORDS_PER_ITEM * BITS_PER_LONG)) / WORDS_PER_ITEM); | ||||
|         if ((ida->main_bmap[i] & ~0UL) == ~0UL) | ||||
|           i++; | ||||
|       } | ||||
|       else | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     while (i < main_sz)  { | ||||
|       fnfi = zero_bit_find_lsf(ida->main_bmap[i]); | ||||
|       if (fnfi >= 0) { | ||||
|         bit_set(ida->main_bmap + i, fnfi); | ||||
|         id = fnfi + i * BITS_PER_LONG; | ||||
|         if (id >= ida->max_id) { | ||||
|           bit_clear(ida->main_bmap + i, fnfi); | ||||
|           id = IDX_INVAL; | ||||
|         } | ||||
| 
 | ||||
|         break; | ||||
|       } | ||||
| 
 | ||||
|       i++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   out: | ||||
|   if (natm == MAX_UNLOCKED_ATTEMPTS) | ||||
|     ida_unlock(ida); | ||||
| 
 | ||||
|   return id; | ||||
| } | ||||
| 
 | ||||
| void idx_reserve(idx_allocator_t *ida, ulong_t idx) | ||||
| { | ||||
|   int start_id, bitno; | ||||
|   ulong_t *ptr; | ||||
| 
 | ||||
|   start_id = idx / BITS_PER_LONG; | ||||
|   bitno = idx - start_id * BITS_PER_LONG; | ||||
|   if (ida->ids_bmap != NULL) | ||||
|     ptr = ida->ids_bmap + start_id; | ||||
|   else | ||||
|     ptr = ida->main_bmap + start_id; | ||||
| 
 | ||||
|   if (bit_test_and_set(ptr, bitno)) { | ||||
|     printf("[libc warning] Detected an attempt to reserve already busy index %ld " | ||||
|            "[function: %s]!\n", idx, __FUNCTION__); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void idx_free(idx_allocator_t *ida, ulong_t idx) | ||||
| { | ||||
|   int start_id, bitno, main_id, main_bitno; | ||||
|   ulong_t *ptr; | ||||
| 
 | ||||
|   start_id = idx / BITS_PER_LONG; | ||||
|   bitno = idx - start_id * BITS_PER_LONG; | ||||
|   if (ida->ids_bmap != NULL) { | ||||
|     ptr = ida->ids_bmap + start_id; | ||||
|     main_id = start_id / WORDS_PER_ITEM; | ||||
|     main_bitno = start_id - main_id * WORDS_PER_ITEM; | ||||
|     bit_clear(ida->main_bmap + main_id, main_bitno); | ||||
|   } | ||||
|   else | ||||
|     ptr = ida->main_bmap + start_id; | ||||
| 
 | ||||
|   if (!bit_test_and_clear(ptr, bitno)) { | ||||
|     printf("[libc warning] Detected an attempt to free already fried index %ld " | ||||
|            "[function: %s]!\n", idx, __FUNCTION__); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int idx_allocator_init(idx_allocator_t *ida, ulong_t idx_max, int lockable) | ||||
| { | ||||
|   size_t bmap_sz; | ||||
|   int err = -ENOMEM; | ||||
| 
 | ||||
|   bmap_sz = (round_up_pow2(idx_max) >> 3); | ||||
|   memset(ida, 0, sizeof(*ida)); | ||||
|   ida->size = bmap_sz / sizeof(ulong_t); | ||||
|   if (ida->size >= MIN_IDA_SIZE) { | ||||
|     ida->ids_bmap = malloc(bmap_sz); | ||||
|     if (!ida->ids_bmap) { | ||||
|       goto error; | ||||
|     } | ||||
| 
 | ||||
|     memset(ida->ids_bmap, 0, bmap_sz); | ||||
|   } | ||||
|   else | ||||
|     ida->size = (ida->size > 0) ? (ida->size * sizeof(ulong_t)) : sizeof(ulong_t); | ||||
| 
 | ||||
|   ida->main_bmap = malloc(__get_main_bmap_size(ida)); | ||||
|   if (!ida->main_bmap) { | ||||
|     goto error; | ||||
|   } | ||||
| 
 | ||||
| #if 0 | ||||
|   if (lockable && ida_lock_init(&ida->lock)) | ||||
|     goto error; | ||||
| #endif | ||||
|   ida->lck = 0; /* cutty, we don't use the lockable due to the very arch specifics */ | ||||
| 
 | ||||
|   memset(ida->main_bmap, 0, __get_main_bmap_size(ida)); | ||||
|   ida->max_id = idx_max; | ||||
|   return 0; | ||||
| 
 | ||||
|   error: | ||||
|   if (ida->ids_bmap) { | ||||
|     free(ida->ids_bmap); | ||||
|   } | ||||
|   if (ida->main_bmap) { | ||||
|     free(ida->main_bmap); | ||||
|   } | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| void idx_allocator_destroy(idx_allocator_t *ida) | ||||
| { | ||||
|   if (ida->ids_bmap != NULL) | ||||
|     free(ida->ids_bmap); | ||||
| 
 | ||||
|   free(ida->main_bmap); | ||||
| 
 | ||||
|   if (ida_lockable(ida)) | ||||
|     ida_lock_destroy(&ida->lock); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										13
									
								
								tdata/libtdata.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tdata/libtdata.pc.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=@exec_prefix@ | ||||
| libdir=@libdir@ | ||||
| datarootdir=@datarootdir@ | ||||
| datadir=@datadir@ | ||||
| includedir=@includedir@ | ||||
| 
 | ||||
| Name: libtdata | ||||
| Description: Data structures C implementation. | ||||
| Version: @LIBTDATA_VERSION@ | ||||
| Requires:  | ||||
| Libs: -L${libdir} -ltdata | ||||
| Cflags: -I${includedir} | ||||
							
								
								
									
										174
									
								
								tdata/lslist.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								tdata/lslist.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * lslist.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <tdata/macro.h> | ||||
| #include <tdata/usrtc.h> | ||||
| 
 | ||||
| #define list_first_priv(L) ((L)->sentinel.next) | ||||
| #define list_last_priv(L) ((L)->sentinel.prev) | ||||
| #define list_null_priv(L) (&(L)->sentinel) | ||||
| 
 | ||||
| /*function prototypes*/ | ||||
| static void list_init(usrtc_t *); | ||||
| static void list_insert(usrtc_t *,usrtc_node_t *,const void *); | ||||
| static void list_delete(usrtc_t *,usrtc_node_t *); | ||||
| static usrtc_node_t *list_lookup(usrtc_t *,const void *); | ||||
| static usrtc_node_t *list_lower_bound(usrtc_t *,const void *); | ||||
| static usrtc_node_t *list_upper_bound(usrtc_t *,const void *); | ||||
| static usrtc_node_t *list_first(usrtc_t *); | ||||
| static usrtc_node_t *list_last(usrtc_t *); | ||||
| static usrtc_node_t *list_next(usrtc_t *, usrtc_node_t *); | ||||
| static usrtc_node_t *list_prev(usrtc_t *, usrtc_node_t *); | ||||
| static void list_convert_to_list(usrtc_t *); | ||||
| static void list_convert_from_list(usrtc_t *); | ||||
| 
 | ||||
| usrtc_functions_t usrtc_list_fu = { | ||||
|     list_init, | ||||
|     list_insert, | ||||
|     list_delete, | ||||
|     list_lookup, | ||||
|     list_lower_bound, | ||||
|     list_upper_bound, | ||||
|     list_first, | ||||
|     list_last, | ||||
|     list_next, | ||||
|     list_prev, | ||||
|     list_convert_to_list, | ||||
|     list_convert_from_list, | ||||
|     usrtc_lst | ||||
| }; | ||||
| 
 | ||||
| static void insert_before(usrtc_t *,usrtc_node_t *,usrtc_node_t *); | ||||
| 
 | ||||
| /*implementation*/ | ||||
| static void list_init(usrtc_t *us) | ||||
| { | ||||
|   us->sentinel.next=&us->sentinel; | ||||
|   us->sentinel.prev=&us->sentinel; | ||||
| } | ||||
| 
 | ||||
| static void list_insert(usrtc_t *us,usrtc_node_t *newnode,const void *key) | ||||
| { | ||||
|   usrtc_node_t *succ; | ||||
|    | ||||
|   newnode->key=key; | ||||
|    | ||||
|   for(succ=list_first_priv(us);succ!=list_null_priv(us);succ=succ->next) { | ||||
|     if(us->compare(succ->key,key)>0) | ||||
|       break; | ||||
|   } | ||||
|    | ||||
|   insert_before(us,newnode,succ); | ||||
| } | ||||
| 
 | ||||
| static void list_delete(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *pred=node->prev; | ||||
|   usrtc_node_t *succ=node->next; | ||||
|    | ||||
|   pred->next=succ; | ||||
|   succ->prev=pred; | ||||
|   /*check node count*/ | ||||
|   us->nodecount--; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_lookup(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *node; | ||||
|    | ||||
|   for(node=list_first_priv(us);node!=list_null_priv(us);node=node->next) { | ||||
|     if(us->compare(node->key,key)==0) | ||||
|       return node; | ||||
|   } | ||||
|    | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_lower_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *node; | ||||
|    | ||||
|   for(node=list_first_priv(us);node!=list_null_priv(us);node=node->next) { | ||||
|     if(us->compare(node->key,key) >= 0) | ||||
|       return node; | ||||
|   } | ||||
|    | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_upper_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *node; | ||||
|    | ||||
|   for(node=list_first_priv(us);node!=list_null_priv(us);node=node->prev) { | ||||
|     if(us->compare(node->key,key) >= 0) | ||||
|       return node; | ||||
|   } | ||||
|    | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_first(usrtc_t *us) | ||||
| { | ||||
|   return (list_first_priv(us) == list_null_priv(us)) ? 0 : list_first_priv(us); | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_last(usrtc_t *us) | ||||
| { | ||||
|   return (list_last_priv(us) == list_null_priv(us)) ? 0 : list_last_priv(us); | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_next(usrtc_t *us, usrtc_node_t *node) | ||||
| { | ||||
|   return (node->next == list_null_priv(us)) ? 0 : node->next; | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *list_prev(usrtc_t *us, usrtc_node_t *node) | ||||
| { | ||||
|   return (node->prev == list_null_priv(us)) ? 0 : node->prev; | ||||
| } | ||||
| 
 | ||||
| static void list_convert_to_list(usrtc_t *us) | ||||
| { | ||||
|   /*dummy*/ | ||||
| } | ||||
| 
 | ||||
| static void list_convert_from_list(usrtc_t *us) | ||||
| { | ||||
|   /*dummy*/ | ||||
| } | ||||
| 
 | ||||
| /*internal function*/ | ||||
| static void insert_before(usrtc_t *us,usrtc_node_t *newnode,usrtc_node_t *succ) | ||||
| { | ||||
|   usrtc_node_t *pred=succ->prev; | ||||
|    | ||||
|   newnode->prev=pred; | ||||
|   newnode->next=succ; | ||||
|    | ||||
|   pred->next=newnode; | ||||
|   succ->prev=newnode; | ||||
|    | ||||
|   /*TODO: check for maxcount*/ | ||||
|   us->nodecount++; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										310
									
								
								tdata/redblack.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								tdata/redblack.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,310 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * redblack.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| #include <tdata/macro.h> | ||||
| #include <tdata/tree.h> | ||||
| 
 | ||||
| #define color usrtc_impldata.usrtc_rb_color | ||||
| 
 | ||||
| /*function prototypes*/ | ||||
| static void redblack_init(usrtc_t *); | ||||
| static void redblack_insert(usrtc_t *, usrtc_node_t *, const void *); | ||||
| static void redblack_delete(usrtc_t *, usrtc_node_t *); | ||||
| static void redblack_convert_from_list(usrtc_t *); | ||||
| 
 | ||||
| usrtc_functions_t usrtc_redblack_fu = { | ||||
|     redblack_init, | ||||
|     redblack_insert, | ||||
|     redblack_delete, | ||||
|     usrtc_tree_lookup, | ||||
|     usrtc_tree_lower_bound, | ||||
|     usrtc_tree_upper_bound, | ||||
|     usrtc_tree_first, | ||||
|     usrtc_tree_last, | ||||
|     usrtc_tree_next, | ||||
|     usrtc_tree_prev, | ||||
|     usrtc_tree_convert_to_list, | ||||
|     redblack_convert_from_list, | ||||
|     usrtc_bst | ||||
| }; | ||||
| 
 | ||||
| /*implementation*/ | ||||
| static void redblack_init(usrtc_t *us) | ||||
| { | ||||
|   usrtc_tree_init(us); | ||||
|   us->sentinel.color = usrtc_black; | ||||
| } | ||||
| 
 | ||||
| static void redblack_insert(usrtc_t *us, usrtc_node_t *node, const void *key) | ||||
| { | ||||
|   usrtc_node_t *parent; | ||||
| 
 | ||||
|   /* simple bt insert */ | ||||
|   usrtc_tree_insert(us,node,key); | ||||
| 
 | ||||
|   /* implementation specific insert */ | ||||
|   node->color = usrtc_red; | ||||
|   parent=node->parent; | ||||
|    | ||||
|   while(parent->color==usrtc_red) { | ||||
|     usrtc_node_t *grandpa=parent->parent; | ||||
|      | ||||
|     if(parent==grandpa->left) { | ||||
|       usrtc_node_t *uncle=grandpa->right; | ||||
|       if(uncle->color==usrtc_red) { /*red parent->red uncle*/ | ||||
| 	parent->color=usrtc_black; | ||||
| 	uncle->color=usrtc_black; | ||||
| 	grandpa->color=usrtc_red; | ||||
| 	node=grandpa; | ||||
| 	parent=grandpa->parent; | ||||
|       } else { /*red parent->black uncle */ | ||||
| 	if(node==parent->right) { | ||||
| 	  usrtc_tree_rotate_left(node,parent); | ||||
| 	  parent=node; | ||||
| 	  if(grandpa!=parent->parent) | ||||
| 	    return; | ||||
| 	} | ||||
| 	parent->color=usrtc_black; | ||||
| 	grandpa->color=usrtc_red; | ||||
| 	usrtc_tree_rotate_right(parent,grandpa); | ||||
| 	break; | ||||
|       } | ||||
|     } else { /*ooh,parent == parent->parent->right*/ | ||||
|       usrtc_node_t *uncle=grandpa->left; | ||||
|       if(uncle->color==usrtc_red) { | ||||
| 	parent->color=usrtc_black; | ||||
| 	uncle->color=usrtc_black; | ||||
| 	grandpa->color=usrtc_red; | ||||
| 	node=grandpa; | ||||
| 	parent=grandpa->parent; | ||||
|       } else { | ||||
| 	if(node==parent->left) { | ||||
| 	  usrtc_tree_rotate_right(node,parent); | ||||
| 	  parent=node; | ||||
| 
 | ||||
| 	  if(grandpa!=parent->parent) | ||||
| 	    return; | ||||
| 	} | ||||
| 	parent->color=usrtc_black; | ||||
| 	grandpa->color=usrtc_red; | ||||
| 	usrtc_tree_rotate_left(parent,grandpa); | ||||
| 	break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   tree_root_priv(us)->color=usrtc_black; | ||||
| } | ||||
| 
 | ||||
| static void redblack_delete(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *swap; | ||||
|   usrtc_node_t *child; | ||||
|   usrtc_rb_color_t savecolor; | ||||
| 
 | ||||
|   /*basic bt delete*/ | ||||
|   usrtc_tree_delete(us,node,&swap,&child); | ||||
|      | ||||
|   /*implementation specific deletion*/ | ||||
|   savecolor=node->color; | ||||
|   node->color=swap->color; | ||||
|   swap->color=savecolor; | ||||
| 
 | ||||
|   if(node->color==usrtc_black) { /*black*/ | ||||
|     usrtc_node_t *parent; | ||||
|     usrtc_node_t *sister; | ||||
| 
 | ||||
|     tree_root_priv(us)->color=usrtc_red; | ||||
| 
 | ||||
|     while(child->color==usrtc_black) { | ||||
|       parent=child->parent; | ||||
|       if(child==parent->left) { | ||||
| 	sister=parent->right; | ||||
| 	if(sister==tree_null_priv(us)) | ||||
| 	  return; | ||||
| 
 | ||||
| 	if(sister->color==usrtc_red) { | ||||
| 	  sister->color=usrtc_black; | ||||
| 	  parent->color=usrtc_red; | ||||
| 	  usrtc_tree_rotate_left(sister,parent); | ||||
| 	  sister=parent->right; | ||||
| 
 | ||||
| 	  if(sister==tree_null_priv(us)) | ||||
| 	    return; | ||||
| 	} | ||||
| 	if(sister->left->color==usrtc_black && sister->right->color==usrtc_black) { | ||||
| 	  sister->color=usrtc_red; | ||||
| 	  child=parent; | ||||
| 	} else { | ||||
| 	  if(sister->right->color==usrtc_black) { | ||||
| 	    if(sister->left->color!=usrtc_red) | ||||
| 	      return; | ||||
| 
 | ||||
| 	    sister->left->color=usrtc_black; | ||||
| 	    sister->color=usrtc_red; | ||||
| 	    usrtc_tree_rotate_right(sister->left,sister); | ||||
| 	    sister=parent->right; | ||||
| 
 | ||||
| 	    if(sister==tree_null_priv(us)) | ||||
| 	      return; | ||||
| 	  } | ||||
| 	  sister->color=parent->color; | ||||
| 	  sister->right->color=usrtc_black; | ||||
| 	  parent->color=usrtc_black; | ||||
| 	  usrtc_tree_rotate_left(sister,parent); | ||||
| 	  break; | ||||
| 	} | ||||
|       } else {	/*!child == child->parent->right*/ | ||||
| 	if(child!=parent->right) | ||||
| 	  return; | ||||
| 
 | ||||
| 	sister=parent->left; | ||||
| 
 | ||||
| 	if(sister==tree_null_priv(us)) | ||||
| 	  return; | ||||
| 
 | ||||
| 	if(sister->color==usrtc_red) { | ||||
| 	  sister->color=usrtc_black; | ||||
| 	  parent->color=usrtc_red; | ||||
| 	  usrtc_tree_rotate_right(sister,parent); | ||||
| 	  sister = parent->left; | ||||
| 
 | ||||
| 	  if(sister==tree_null_priv(us)) | ||||
| 	    return; | ||||
| 	} | ||||
| 	if(sister->right->color==usrtc_black && sister->left->color==usrtc_black) { | ||||
| 	  sister->color=usrtc_red; | ||||
| 	  child=parent; | ||||
| 	} else { | ||||
| 	  if(sister->left->color == usrtc_black) { | ||||
| 	    if(sister->right->color!=usrtc_red) | ||||
| 	      return; | ||||
| 
 | ||||
| 	    sister->right->color=usrtc_black; | ||||
| 	    sister->color=usrtc_red; | ||||
| 	    usrtc_tree_rotate_left(sister->right, sister); | ||||
| 	    sister=parent->left; | ||||
| 
 | ||||
| 	    if(sister==tree_null_priv(us)) | ||||
| 	      return; | ||||
| 	  } | ||||
| 	  sister->color=parent->color; | ||||
| 	  sister->left->color=usrtc_black; | ||||
| 	  parent->color=usrtc_black; | ||||
| 	  usrtc_tree_rotate_right(sister,parent); | ||||
| 	  break; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     child->color=usrtc_black; | ||||
|     tree_root_priv(us)->color=usrtc_black; | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void redblack_convert_from_list(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *tree[TREE_DEPTH_MAX] = { NULL }; | ||||
|   usrtc_node_t *curr; | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *next; | ||||
|   usrtc_node_t *complete=NULL; | ||||
|   usrtc_count_t fullcount=(usrtc_count_t)USRTC_COUNT_T_MAX; | ||||
|   usrtc_count_t nodecount=us->nodecount; | ||||
|   usrtc_count_t botrowcount; | ||||
|   unsigned int baselevel=0; | ||||
|   unsigned int level=0; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   if(usrtc_red!=0 && usrtc_black!=1) | ||||
|     return; | ||||
| 
 | ||||
|   while(fullcount>=nodecount && fullcount) /*calc*/ | ||||
|     fullcount >>= 1; | ||||
| 
 | ||||
|   botrowcount=nodecount-fullcount; | ||||
| 
 | ||||
|   for(curr=nil->next;curr!=nil;curr=next) { | ||||
|     next=curr->next; | ||||
| 
 | ||||
|     if(complete==NULL && botrowcount--==0) { | ||||
|       baselevel=level=1; | ||||
|       complete=tree[0]; | ||||
| 
 | ||||
|       if(complete!=NULL) { | ||||
| 	tree[0]=NULL; | ||||
| 	complete->right=nil; | ||||
| 	while(tree[level]!=0) { | ||||
| 	  tree[level]->right=complete; | ||||
| 	  complete->parent=tree[level]; | ||||
| 	  complete=tree[level]; | ||||
| 	  tree[level++]=NULL; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if(complete==NULL) { | ||||
|       curr->left=nil; | ||||
|       curr->right=nil; | ||||
|       curr->color=level%2; | ||||
|       complete=curr; | ||||
| 
 | ||||
|       if(level!=baselevel) | ||||
| 	return; | ||||
| 
 | ||||
|       while(tree[level]!=NULL) { | ||||
| 	tree[level]->right=complete; | ||||
| 	complete->parent=tree[level]; | ||||
| 	complete=tree[level]; | ||||
| 	tree[level++]=NULL; | ||||
|       } | ||||
|     } else { | ||||
|       curr->left=complete; | ||||
|       curr->color=(level+1)%2; | ||||
|       complete->parent=curr; | ||||
|       tree[level]=curr; | ||||
|       complete=NULL; | ||||
|       level=baselevel; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if(complete==NULL) | ||||
|     complete=nil; | ||||
| 
 | ||||
|   for (i=0;i<TREE_DEPTH_MAX;i++) { | ||||
|     if (tree[i]!=NULL) { | ||||
|       tree[i]->right=complete; | ||||
|       complete->parent=tree[i]; | ||||
|       complete=tree[i]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   nil->right=nil; | ||||
|   nil->left=complete; | ||||
|   nil->color=usrtc_black; | ||||
|   complete->parent=nil; | ||||
|   complete->color=usrtc_black; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										143
									
								
								tdata/splay.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								tdata/splay.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * splay.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| #include <tdata/macro.h> | ||||
| #include <tdata/tree.h> | ||||
| 
 | ||||
| /*prototypes*/ | ||||
| static void splay_insert(usrtc_t *,usrtc_node_t *,const void *); | ||||
| static void splay_delete(usrtc_t *,usrtc_node_t *); | ||||
| static usrtc_node_t *splay_lookup(usrtc_t *,const void *); | ||||
| 
 | ||||
| usrtc_functions_t usrtc_splay_fu = { | ||||
|     usrtc_tree_init, | ||||
|     splay_insert, | ||||
|     splay_delete, | ||||
|     splay_lookup, | ||||
|     usrtc_tree_lower_bound, | ||||
|     usrtc_tree_upper_bound, | ||||
|     usrtc_tree_first, | ||||
|     usrtc_tree_last, | ||||
|     usrtc_tree_next, | ||||
|     usrtc_tree_prev, | ||||
|     usrtc_tree_convert_to_list, | ||||
|     usrtc_tree_convert_from_list, | ||||
|     usrtc_bst | ||||
| }; | ||||
| 
 | ||||
| static void right_zig_zig(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *); | ||||
| static void left_zig_zig(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *); | ||||
| static void right_zig_zag(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *); | ||||
| static void left_zig_zag(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *); | ||||
| static void splay_node(usrtc_t *,usrtc_node_t *); | ||||
| 
 | ||||
| /*implementation*/ | ||||
| 
 | ||||
| static void splay_insert(usrtc_t *us,usrtc_node_t *node,const void *key) | ||||
| { | ||||
|   usrtc_tree_insert(us,node,key); | ||||
|    | ||||
|   while(node!=tree_root_priv(us)) | ||||
|     splay_node(us,node); | ||||
| } | ||||
| 
 | ||||
| static void splay_delete(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *dummy; | ||||
|   usrtc_tree_delete(us,node,&dummy,&dummy); | ||||
| } | ||||
| 
 | ||||
| static usrtc_node_t *splay_lookup(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *node=usrtc_tree_lookup(us,key); | ||||
|    | ||||
|   if(node) | ||||
|     while(node!=tree_root_priv(us)) | ||||
|       splay_node(us,node); | ||||
|    | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| static void right_zig_zig(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa) | ||||
| { | ||||
|   usrtc_tree_rotate_right(parent,grandpa); | ||||
|   usrtc_tree_rotate_right(child,parent); | ||||
| } | ||||
| 
 | ||||
| static void left_zig_zig(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa) | ||||
| { | ||||
|   usrtc_tree_rotate_left(parent,grandpa); | ||||
|   usrtc_tree_rotate_left(child,parent); | ||||
| } | ||||
| 
 | ||||
| static void right_zig_zag(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa) | ||||
| { | ||||
|   usrtc_tree_rotate_right(child,parent); | ||||
|   usrtc_tree_rotate_left(child,grandpa); | ||||
| } | ||||
| 
 | ||||
| static void left_zig_zag(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa) | ||||
| { | ||||
|   usrtc_tree_rotate_left(child,parent); | ||||
|   usrtc_tree_rotate_right(child,grandpa); | ||||
| } | ||||
| 
 | ||||
| static void splay_node(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *parent=node->parent; | ||||
|    | ||||
|   if(parent->left==node) { | ||||
|     if(parent==root) { | ||||
|       usrtc_tree_rotate_right(node,parent); | ||||
|     } else { | ||||
|       usrtc_node_t *grandpa=parent->parent; | ||||
|        | ||||
|       if(grandpa->left==parent) | ||||
| 	right_zig_zig(node,parent,grandpa); | ||||
|       else { | ||||
| 	if(grandpa->right!=parent) | ||||
| 	  return; | ||||
| 
 | ||||
| 	right_zig_zag(node,parent,grandpa); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     if(parent->right!=node) | ||||
|       return; | ||||
|      | ||||
|     if(parent==root) { | ||||
|       usrtc_tree_rotate_left(node,parent); | ||||
|     } else { | ||||
|       usrtc_node_t *grandpa=parent->parent; | ||||
|        | ||||
|       if(grandpa->right==parent) { | ||||
| 	left_zig_zig(node,parent,grandpa); | ||||
|       } else { | ||||
| 	if(grandpa->left!=parent) | ||||
| 	  return; | ||||
| 
 | ||||
| 	left_zig_zag(node,parent,grandpa); | ||||
|       } | ||||
|     } | ||||
|      | ||||
|   } | ||||
| } | ||||
							
								
								
									
										492
									
								
								tdata/tree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										492
									
								
								tdata/tree.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,492 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * tree.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| #include <tdata/macro.h> | ||||
| #include <tdata/tree.h> | ||||
| 
 | ||||
| /*local functions prototypes*/ | ||||
| static void tree_delete(usrtc_t *, usrtc_node_t *); | ||||
| 
 | ||||
| usrtc_functions_t usrtc_tree_fu = { | ||||
|     usrtc_tree_init, | ||||
|     usrtc_tree_insert, | ||||
|     tree_delete, | ||||
|     usrtc_tree_lookup, | ||||
|     usrtc_tree_lower_bound, | ||||
|     usrtc_tree_upper_bound, | ||||
|     usrtc_tree_first, | ||||
|     usrtc_tree_last, | ||||
|     usrtc_tree_next, | ||||
|     usrtc_tree_prev, | ||||
|     usrtc_tree_convert_to_list, | ||||
|     usrtc_tree_convert_from_list, | ||||
|     usrtc_bst | ||||
| }; | ||||
| 
 | ||||
| /*implementation*/ | ||||
| 
 | ||||
| void usrtc_tree_init(usrtc_t *us) | ||||
| { | ||||
|   us->sentinel.left=&us->sentinel; | ||||
|   us->sentinel.right=&us->sentinel; | ||||
|   us->sentinel.parent=&us->sentinel; | ||||
| 
 | ||||
|   us->sentinel.impl_specific.usrtc_dummy=0; | ||||
|   us->sentinel.data=0; | ||||
|   us->sentinel.key=0; | ||||
| } | ||||
| 
 | ||||
| void usrtc_tree_insert(usrtc_t *us,usrtc_node_t *node,const void *key) | ||||
| { | ||||
|   usrtc_node_t *where=tree_root_priv(us); | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *parent=nil; | ||||
|   long res=-1; | ||||
| 
 | ||||
|   node->key=key; | ||||
| 
 | ||||
|   while(where!=nil) { | ||||
|     parent=where; | ||||
|     res=us->compare(key,where->key); | ||||
| 
 | ||||
|     if(us->dupes_allowed && !res) /*trying to put duplicate to the disabled dupe tree*/ | ||||
|       return; | ||||
| 
 | ||||
|     if(res<0) | ||||
|       where=where->left; | ||||
|     else | ||||
|       where=where->right; | ||||
|   } | ||||
| 
 | ||||
|   /*assert(where==nil);*/ | ||||
| 
 | ||||
|   if(res<0) | ||||
|     parent->left=node; | ||||
|   else | ||||
|     parent->right=node; | ||||
| 
 | ||||
|   node->parent=parent; | ||||
|   node->left=nil; | ||||
|   node->right=nil; | ||||
| 
 | ||||
|   us->nodecount++; | ||||
| } | ||||
| 
 | ||||
| void usrtc_tree_delete(usrtc_t *us,usrtc_node_t *node,usrtc_node_t **pswap,usrtc_node_t **pchild) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us);  | ||||
|   usrtc_node_t *child; | ||||
|   usrtc_node_t *delparent=node->parent; | ||||
|   usrtc_node_t *next=node; | ||||
|   usrtc_node_t *nextparent; | ||||
| 
 | ||||
|   if(node->left!=nil && node->right!=nil) { | ||||
|     next=usrtc_tree_next(us,node); | ||||
|     nextparent=next->parent; | ||||
| 
 | ||||
|     /*if(next!=nil && next->parent!=nil && next->parent==nil)
 | ||||
|       return;*/ | ||||
| 
 | ||||
|     child=next->right; | ||||
|     child->parent=nextparent; | ||||
| 
 | ||||
|     if(nextparent->left==next) | ||||
|       nextparent->left=child; | ||||
|     else { | ||||
|       //if(nextparent->right!=next)
 | ||||
|       //return;
 | ||||
|       nextparent->right=child; | ||||
|     } | ||||
| 
 | ||||
|     next->parent=delparent; | ||||
|     next->left=node->left; | ||||
|     next->right=node->right; | ||||
|     next->left->parent=next; | ||||
|     next->right->parent=next; | ||||
| 
 | ||||
|     if(delparent->left==node) { | ||||
|       delparent->left=next; | ||||
|     } else { | ||||
|       //if(delparent->right!=node)
 | ||||
|       //	return;
 | ||||
|       delparent->right = next; | ||||
|     } | ||||
| 
 | ||||
|   } else { | ||||
|     /*if(node==nil)
 | ||||
|       return; | ||||
|     if(node->left!=nil && node->right!=nil) | ||||
|     return;*/ | ||||
| 
 | ||||
|     child=(node->left!=nil) ? node->left : node->right; | ||||
| 
 | ||||
|     child->parent=delparent=node->parent; | ||||
| 
 | ||||
|     if(node==delparent->left) { | ||||
|       delparent->left=child; | ||||
|     } else { | ||||
|       /*if(node!=delparent->right)
 | ||||
| 	return;*/ | ||||
|       delparent->right=child; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   node->parent=0; | ||||
|   node->right=0; | ||||
|   node->left=0; | ||||
| 
 | ||||
|   us->nodecount--; | ||||
| 
 | ||||
|   *pswap = next; | ||||
|   *pchild = child; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_lookup(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *saved; | ||||
|   long res; | ||||
| 
 | ||||
|   while (root!=nil) { | ||||
|     res=us->compare(key,root->key); | ||||
|     if(res<0) | ||||
|       root=root->left; | ||||
|     else if(res>0) | ||||
|       root=root->right; | ||||
|     else { | ||||
|       if(!us->dupes_allowed) | ||||
| 				return root; /*no duplicates*/ | ||||
|       else { /*duplicate, then find left occurence*/ | ||||
| 				do { | ||||
| 					saved=root; | ||||
| 					root=root->left; | ||||
| 					while(root!=nil && us->compare(key,root->key)) | ||||
| 						root=root->right; | ||||
| 				} while(root!=nil); | ||||
| 				return saved; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_lower_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *tentative=NULL; | ||||
|   long res; | ||||
| 
 | ||||
|   while(root!=nil) { | ||||
|     res=us->compare(key,root->key); | ||||
| 
 | ||||
|     if(res>0) { | ||||
|       root=root->right; | ||||
|     } else if(res<0) { | ||||
|       tentative=root; | ||||
|       root=root->left; | ||||
|     } else { | ||||
|       if (!us->dupes_allowed) | ||||
| 				return root; | ||||
|       else { | ||||
| 				tentative=root; | ||||
| 				root=root->left; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return tentative; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_upper_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *tentative=NULL; | ||||
|   long res; | ||||
| 
 | ||||
|   while(root!=nil) { | ||||
|     res=us->compare(key,root->key); | ||||
| 
 | ||||
|     if(res>0) { | ||||
|       root=root->left; | ||||
|     } else if(res<0) { | ||||
|       tentative=root; | ||||
|       root=root->right; | ||||
|     } else { | ||||
|       if (!us->dupes_allowed) | ||||
| 				return root; | ||||
|       else { | ||||
| 				tentative=root; | ||||
| 				root=root->right; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return tentative; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_first(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *left; | ||||
| 
 | ||||
|   if(root!=nil) | ||||
|     while((left=root->left)!=nil) | ||||
|       root=left; | ||||
| 
 | ||||
|   return (root==nil) ? NULL : root; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_last(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *root=tree_root_priv(us); | ||||
|   usrtc_node_t *right; | ||||
| 
 | ||||
|   if(root!=nil) | ||||
|     while((right=root->right)!=nil) | ||||
|       root=right; | ||||
| 
 | ||||
|   return (root==nil) ? NULL : root; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_next(usrtc_t *us, usrtc_node_t *curr) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *parent; | ||||
|   usrtc_node_t *left; | ||||
| 
 | ||||
|   if(curr->right!=nil) { | ||||
|     curr=curr->right; | ||||
|     while((left=curr->left)!=nil) | ||||
|       curr=left; | ||||
|     return curr; | ||||
|   } | ||||
| 
 | ||||
|   parent=curr->parent; | ||||
| 
 | ||||
|   while(parent!=nil && curr==parent->right) { | ||||
|     curr=parent; | ||||
|     parent=curr->parent; | ||||
|   } | ||||
| 
 | ||||
|   return (parent==nil) ? NULL : parent; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_tree_prev(usrtc_t *us, usrtc_node_t *curr) | ||||
| { | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *parent; | ||||
|   usrtc_node_t *right; | ||||
| 
 | ||||
|   if(curr->left!=nil) { | ||||
|     curr=curr->left; | ||||
|     while((right=curr->right)!=nil) | ||||
|       curr=right; | ||||
|     return curr; | ||||
|   } | ||||
| 
 | ||||
|   parent=curr->parent; | ||||
| 
 | ||||
|   while(parent!=nil && curr==parent->left) { | ||||
|     curr=parent; | ||||
|     parent=curr->parent; | ||||
|   } | ||||
| 
 | ||||
|   return (parent==nil) ? NULL : parent; | ||||
| } | ||||
| 
 | ||||
| /*uff, convertation between trees and lists*/ | ||||
| void usrtc_tree_convert_to_list(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *node; | ||||
|   usrtc_node_t tempsentinel; | ||||
|   usrtc_node_t *nil=&tempsentinel; | ||||
|   usrtc_node_t *tail,*next; | ||||
|   usrtc_node_t *treenil=tree_null_priv(us); | ||||
| 
 | ||||
|   if(us->nodecount==0) /* no nodes */ | ||||
|     return; | ||||
| 
 | ||||
|   tempsentinel.next=nil; | ||||
|   tempsentinel.prev=nil; | ||||
| 
 | ||||
|   /* two passes */ | ||||
|   for(tail=nil,node=usrtc_tree_first(us);node!=0;tail=node,node=next) { | ||||
|     next=usrtc_tree_next(us,node); | ||||
|     node->prev=tail; | ||||
|   } | ||||
| 
 | ||||
|   nil->prev=tail; | ||||
| 
 | ||||
|   for(tail=nil,node=nil->prev;node!=nil;tail=node,node=node->prev) | ||||
|     node->next=tail; | ||||
| 
 | ||||
|   nil->next=tail; | ||||
| 
 | ||||
|   us->sentinel.next=tempsentinel.next; | ||||
|   us->sentinel.prev=tempsentinel.prev; | ||||
|   us->sentinel.next->prev=treenil; | ||||
|   us->sentinel.prev->next=treenil; | ||||
| } | ||||
| 
 | ||||
| void usrtc_tree_convert_from_list(usrtc_t *us) | ||||
| { | ||||
|   usrtc_node_t *tree[TREE_DEPTH_MAX]={ 0 }; | ||||
|   usrtc_node_t *curr; | ||||
|   usrtc_node_t *nil=tree_null_priv(us); | ||||
|   usrtc_node_t *next; | ||||
|   usrtc_node_t *complete=NULL; | ||||
|   usrtc_count_t fullcount=(usrtc_count_t)USRTC_COUNT_T_MAX; | ||||
|   usrtc_count_t nodecount=us->nodecount; | ||||
|   usrtc_count_t botrowcount; | ||||
|   int baselevel=0; | ||||
|   int level=0; | ||||
|   int i=0; | ||||
| 
 | ||||
|   while (fullcount>=nodecount && fullcount) /* calc */ | ||||
|     fullcount>>=1; | ||||
| 
 | ||||
|   botrowcount=nodecount-fullcount; | ||||
| 
 | ||||
|   for(curr=nil->next;curr!=nil;curr=next) { | ||||
|     next=curr->next; | ||||
| 
 | ||||
|     if(complete==NULL && botrowcount-- ==0) { | ||||
|       baselevel=level=1; | ||||
|       complete=tree[0]; | ||||
| 
 | ||||
|       if(complete!=NULL) { | ||||
| 				tree[0]=0; | ||||
| 				complete->right=nil; | ||||
| 				while(tree[level]!=NULL) { | ||||
| 					tree[level]->right=complete; | ||||
| 					complete->parent=tree[level]; | ||||
| 					complete=tree[level]; | ||||
| 					tree[level++]=0; | ||||
| 				} | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if(complete==NULL) { | ||||
|       curr->left=nil; | ||||
|       curr->right=nil; | ||||
|       complete=curr; | ||||
| 
 | ||||
|       if(level!=baselevel) | ||||
| 				return; | ||||
|       while(tree[level]!=NULL) { | ||||
| 				tree[level]->right=complete; | ||||
| 				complete->parent=tree[level]; | ||||
| 				complete=tree[level]; | ||||
| 				tree[level++]=0; | ||||
|       } | ||||
|     } else { | ||||
|       curr->left=complete; | ||||
|       complete->parent=curr; | ||||
|       tree[level]=curr; | ||||
|       complete=NULL; | ||||
|       level=baselevel; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if(complete==NULL) | ||||
|     complete=nil; | ||||
| 
 | ||||
|   for(i=0;i<TREE_DEPTH_MAX;i++) { | ||||
|     if(tree[i]!=NULL) { | ||||
|       tree[i]->right=complete; | ||||
|       complete->parent=tree[i]; | ||||
|       complete=tree[i]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   nil->right=nil; | ||||
|   nil->left=complete; | ||||
|   complete->parent=nil; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void usrtc_tree_rotate_left(usrtc_node_t *child,usrtc_node_t *parent) | ||||
| { | ||||
|   usrtc_node_t *leftgrandchild; | ||||
|   usrtc_node_t *grandpa; | ||||
| 
 | ||||
|   if(parent->right!=child) | ||||
|     return; | ||||
| 
 | ||||
|   child=parent->right; | ||||
|   parent->right=leftgrandchild=child->left; | ||||
|   leftgrandchild->parent=parent; | ||||
| 
 | ||||
|   child->parent=grandpa=parent->parent; | ||||
| 
 | ||||
|   if(parent==grandpa->left) { | ||||
|     grandpa->left=child; | ||||
|   } else { | ||||
|     if(parent!=grandpa->right) | ||||
|       return; | ||||
|     grandpa->right=child; | ||||
|   } | ||||
| 
 | ||||
|   child->left=parent; | ||||
|   parent->parent=child; | ||||
| } | ||||
| 
 | ||||
| void usrtc_tree_rotate_right(usrtc_node_t *child,usrtc_node_t *parent) | ||||
| { | ||||
|   usrtc_node_t *rightgrandchild; | ||||
|   usrtc_node_t *grandpa; | ||||
| 
 | ||||
|   if(parent->left!=child) | ||||
|     return; | ||||
| 
 | ||||
|   parent->left=rightgrandchild=child->right; | ||||
|   rightgrandchild->parent=parent; | ||||
| 
 | ||||
|   child->parent=grandpa=parent->parent; | ||||
| 
 | ||||
|   if(parent==grandpa->right) { | ||||
|     grandpa->right=child; | ||||
|   } else { | ||||
|     if(parent!=grandpa->left) | ||||
|       return; | ||||
|     grandpa->left=child; | ||||
|   } | ||||
| 
 | ||||
|   child->right=parent; | ||||
|   parent->parent=child; | ||||
| } | ||||
| 
 | ||||
| /* local functions */ | ||||
| static void tree_delete(usrtc_t *us, usrtc_node_t *node) | ||||
| { | ||||
|   usrtc_node_t *dummy; | ||||
| 
 | ||||
|   usrtc_tree_delete(us, node, &dummy, &dummy); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										244
									
								
								tdata/usrtc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								tdata/usrtc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,244 @@ | ||||
| /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ | ||||
| /*
 | ||||
|  * usrtc.c | ||||
|  * Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com> | ||||
|  * Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
 | ||||
|  * | ||||
|  * libtdata 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 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * libtdata 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include <tdata/usrtc.h> | ||||
| #include <tdata/macro.h> | ||||
| 
 | ||||
| /* so, if you want to add your implementation of the data
 | ||||
|  * structure please add this here, like the following. | ||||
|  */ | ||||
| 
 | ||||
| #define MAX_IMPL  4 | ||||
| 
 | ||||
| extern usrtc_functions_t usrtc_list_fu; | ||||
| extern usrtc_functions_t usrtc_tree_fu; | ||||
| extern usrtc_functions_t usrtc_redblack_fu; | ||||
| extern usrtc_functions_t usrtc_splay_fu; | ||||
| extern usrtc_functions_t usrtc_avl_fu; | ||||
| 
 | ||||
| static usrtc_functions_t *impl_table[] = { | ||||
|   &usrtc_list_fu,&usrtc_tree_fu, | ||||
|   &usrtc_redblack_fu,&usrtc_splay_fu, | ||||
|   &usrtc_avl_fu }; | ||||
| 
 | ||||
| static usrtc_node_t *default_node_alloc(void *context) | ||||
| { | ||||
|   return malloc(sizeof *default_node_alloc(context)); | ||||
| } | ||||
| 
 | ||||
| static void default_node_free(void *context,usrtc_node_t *node) | ||||
| { | ||||
|   free(node); | ||||
| } | ||||
| 
 | ||||
| void usrtc_init(usrtc_t *us,int impl,usrtc_count_t maxcount,usrtc_compare_t compare) | ||||
| { | ||||
|   if(!us) | ||||
|     return; | ||||
|   if(impl>MAX_IMPL) | ||||
|     return; | ||||
| 
 | ||||
|   us->nodecount=0; | ||||
|   us->maxcount=maxcount; | ||||
|   us->dupes_allowed=0; | ||||
|   us->compare=compare; | ||||
|   us->node_alloc=default_node_alloc; | ||||
|   us->node_free=default_node_free; | ||||
|   us->context=0; | ||||
|   us->futable=impl_table[impl]; | ||||
|   us->futable->usrtc_init(us); | ||||
| } | ||||
| 
 | ||||
| usrtc_t *usrtc_create(int impl,usrtc_count_t maxcount,usrtc_compare_t compare) | ||||
| { | ||||
|   usrtc_t *newrtc=(usrtc_t*)malloc(sizeof *newrtc); | ||||
|    | ||||
|   if(newrtc) | ||||
|     usrtc_init(newrtc,impl,maxcount,compare); | ||||
|    | ||||
|   return newrtc; | ||||
| } | ||||
| 
 | ||||
| void usrtc_destroy(usrtc_t *us) | ||||
| { | ||||
|   /*assert(usrtc_isempty(us));*/ | ||||
|   if(!us) | ||||
|     return; | ||||
| 
 | ||||
|   free(us); | ||||
| } | ||||
| 
 | ||||
| void usrtc_convert_to(usrtc_t *us,int impl) | ||||
| { | ||||
|   if(impl_table[impl]==us->futable) | ||||
|     return; | ||||
| 
 | ||||
|   if(us->futable->usrtc_type==usrtc_bst && (impl==USRTC_BST || impl==USRTC_SPLAY)) { | ||||
|     us->futable=impl_table[impl]; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   us->futable->usrtc_convert_to_list(us); | ||||
|   us->futable=impl_table[impl]; | ||||
| 
 | ||||
|   if(impl_table[impl]->usrtc_type==usrtc_lst) | ||||
|     return; | ||||
| 
 | ||||
|   us->futable->usrtc_convert_from_list(us); | ||||
| } | ||||
| 
 | ||||
| usrtc_count_t usrtc_count(usrtc_t *us) | ||||
| { | ||||
|   return us->nodecount; | ||||
| } | ||||
| 
 | ||||
| int usrtc_isempty(usrtc_t *us) | ||||
| { | ||||
|   return us->nodecount == 0; | ||||
| } | ||||
| 
 | ||||
| int usrtc_isfull(usrtc_t *us) | ||||
| { | ||||
|   return us->nodecount == us->maxcount; | ||||
| } | ||||
| 
 | ||||
| int usrtc_alloc_insert(usrtc_t *us,const void *key,void *data) | ||||
| { | ||||
|   usrtc_node_t *newnode=us->node_alloc(us->context); | ||||
|    | ||||
|   if(newnode!=NULL) { | ||||
|     newnode->data=data; | ||||
|     us->futable->usrtc_insert(us,newnode,key); | ||||
|   } | ||||
|    | ||||
|   return newnode!=NULL; | ||||
| } | ||||
| 
 | ||||
| void usrtc_delete_free(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   us->futable->usrtc_delete(us,node); | ||||
|   us->node_free(us->context,node); | ||||
| } | ||||
| 
 | ||||
| void usrtc_set_allocator(usrtc_t *us,usrtc_node_alloc_t alloc,usrtc_node_free_t n_free,void *context) | ||||
| { | ||||
|   us->node_alloc=alloc; | ||||
|   us->node_free=n_free; | ||||
|   us->context=context; | ||||
| } | ||||
| 
 | ||||
| void usrtc_allow_dupes(usrtc_t *us) | ||||
| { | ||||
|   /*assert(us->nodecount == 0);*/ | ||||
|   if(!us->nodecount) | ||||
|     return; | ||||
| 
 | ||||
|   us->dupes_allowed=1; | ||||
| } | ||||
| 
 | ||||
| void usrtc_node_init(usrtc_node_t *node,void *data) | ||||
| { | ||||
|   node->data=data; | ||||
|   node->impl_specific.usrtc_dummy=0; | ||||
|   node->left=NULL; | ||||
|   node->right=NULL; | ||||
|   node->parent=NULL; | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_node_create(void *data) | ||||
| { | ||||
|   usrtc_node_t *newnode=(usrtc_node_t*)malloc(sizeof *newnode); | ||||
|    | ||||
|   if(newnode!=NULL) | ||||
|     newnode->data=data; | ||||
|    | ||||
|   return newnode; | ||||
| } | ||||
| 
 | ||||
| void usrtc_node_destroy(usrtc_node_t *node) | ||||
| { | ||||
|   free(node); | ||||
| } | ||||
| 
 | ||||
| void *usrtc_node_getdata(usrtc_node_t *node) | ||||
| { | ||||
|   return node->data; | ||||
| } | ||||
| 
 | ||||
| void usrtc_node_setdata(usrtc_node_t *node,void *data) | ||||
| { | ||||
|   node->data=data; | ||||
| } | ||||
| 
 | ||||
| const void *usrtc_node_getkey(usrtc_node_t *node) | ||||
| { | ||||
|   return node->key; | ||||
| } | ||||
| 
 | ||||
| void usrtc_insert(usrtc_t *us,usrtc_node_t *node,const void *key) | ||||
| { | ||||
|   us->futable->usrtc_insert(us,node,key); | ||||
| } | ||||
| 
 | ||||
| void usrtc_delete(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   us->futable->usrtc_delete(us,node); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_lookup(usrtc_t *us,const void *key) | ||||
| { | ||||
|   return us->futable->usrtc_lookup(us,key); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_lower_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   return us->futable->usrtc_lower_bound(us,key); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_upper_bound(usrtc_t *us,const void *key) | ||||
| { | ||||
|   return us->futable->usrtc_upper_bound(us,key); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_first(usrtc_t *us) | ||||
| { | ||||
|   return us->futable->usrtc_first(us); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_last(usrtc_t *us) | ||||
| { | ||||
|   return us->futable->usrtc_last(us); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_next(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   return us->futable->usrtc_next(us,node); | ||||
| } | ||||
| 
 | ||||
| usrtc_node_t *usrtc_prev(usrtc_t *us,usrtc_node_t *node) | ||||
| { | ||||
|   return us->futable->usrtc_prev(us,node); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user