[core] Added tdata, sexpr libraries to the project;

v0.5.xx
Alexander Vdolainen 9 years ago
parent 1cfb0aed3c
commit 3ef4cece81

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 = \

@ -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

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__ */

@ -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__*/

@ -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__*/

@ -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__*/

@ -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

@ -0,0 +1,3 @@
1.3.1

@ -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));
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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}

File diff suppressed because it is too large Load Diff

@ -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;
}

@ -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_ */

@ -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;
}

@ -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

@ -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

@ -0,0 +1,3 @@
0.2.3

@ -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;
}

@ -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;
}
}

@ -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

@ -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);
}

@ -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}

@ -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++;
}

@ -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;
}

@ -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);
}
}
}
}

@ -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);
}

@ -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…
Cancel
Save