From: Markus R. <rol...@us...> - 2005-12-19 19:13:38
|
Update of /cvsroot/simspark/simspark/spark/utility/sfsexp In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24814/sfsexp Added Files: .cvsignore Makefile.am cstring.c cstring.h faststack.c faststack.h io.c malloc_util.c malloc_util.h parser.c sexp.c sexp.h sexp_ops.c sexp_ops.h Log Message: - added spark utility library --- NEW FILE: faststack.h --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ /** * \file faststack.h * * \brief Implementation of a fast stack with smart memory management. * * Author: Matt Sottile (ma...@la...) * See LICENSE for info on licensing. */ #ifndef __FASTSTACK_H__ #define __FASTSTACK_H__ #ifdef _DEBUG_MALLOCS_ #include "malloc_util.h" #endif /** * 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. */ 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. */ 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. */ 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__ */ --- NEW FILE: .cvsignore --- .cvsignore .deps Makefile Makefile.in --- NEW FILE: io.c --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ /*** * Matt's smaller s-expression parsing library * * Written by Matt Sottile (ma...@la...), January 2002. ***/ #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "sexp.h" #include <assert.h> /** * initialize an io-wrapper */ sexp_iowrap_t *init_iowrap(int fd) { sexp_iowrap_t *iow; iow = (sexp_iowrap_t *)malloc(sizeof(sexp_iowrap_t)); assert(iow != NULL); iow->cc = NULL; iow->fd = fd; iow->cnt = 0; return iow; } /** * */ void destroy_iowrap(sexp_iowrap_t *iow) { if (iow == NULL) return; /* idiot */ destroy_continuation(iow->cc); free(iow); } /** * */ sexp_t *read_one_sexp(sexp_iowrap_t *iow) { sexp_t *sx = NULL; if (iow->cnt == 0) { iow->cnt = read(iow->fd,iow->buf,BUFSIZ); if (iow->cnt == 0) return NULL; } iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc); while (iow->cc->last_sexp == NULL) { if (iow->cc->error != 0) { fprintf(stderr,"ERROR\n"); return NULL; } iow->cnt = read(iow->fd,iow->buf,BUFSIZ); if (iow->cnt == 0) return NULL; iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc); } sx = iow->cc->last_sexp; iow->cc->last_sexp = NULL; return sx; } --- NEW FILE: parser.c --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility for the use of this SOFTWARE. If SOFTWARE is modified to produce derivative works, such modified [...1214 lines suppressed...] 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->error = 0; } return cc; } --- NEW FILE: sexp_ops.h --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ #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. Note that cons, * car, and cdr do <B>not</B> currently have any guarantee to behave in a * identical manner as their LISP or Scheme equivalents. This would be * fairly easy to fix, but not high on the priority list currently. */ #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. */ sexp_t *find_sexp(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). */ sexp_t *bfs_find_sexp(char *str, sexp_t *sx); /** * 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. */ int sexp_list_length(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. */ sexp_t *copy_sexp(sexp_t *s); /** * Cons: Concatenate two s-expressions together, without references to the * originals. */ sexp_t *cons_sexp(sexp_t *r, sexp_t *l); /** * car: Like hd(), but returning a copy of the head, not a reference to it. */ sexp_t *car_sexp(sexp_t *s); /** * cdr: Like tl(), but returning a copy of the tail, not a reference to it. */ sexp_t *cdr_sexp(sexp_t *s); #ifdef __cplusplus } #endif #endif /* __SEXP_OPS_H__ */ --- NEW FILE: sexp.c --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ /*** * Matt's smaller s-expression parsing library * * Written by Matt Sottile (ma...@la...), January 2002. ***/ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "sexp.h" #include "faststack.h" /** * 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); if (s->ty == SEXP_VALUE && s->val != NULL) free(s->val); s->val = 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, int size, sexp_t * sx) { int retval; int sz; char *b = buf, *tc; int left = size; int depth = 0; faststack_t *stack; stack_lvl_t *top; sexp_t *tdata; sexp_t *fakehead; if (sx == NULL) { fprintf(stderr,"print_sexp: s-expression is null.\n"); return -1; } fakehead = sexp_t_allocate(); assert(fakehead!=NULL); /* duplicate the head to prevent going down a sx->next path that we don't really want to see. */ fakehead->list = sx->list; fakehead->ty = sx->ty; fakehead->next = NULL; /* this is the important part of fakehead */ fakehead->aty = sx->aty; if (fakehead->ty == SEXP_VALUE) { assert(sx->val != NULL); /* duplicate the head value into the fake head */ fakehead->val = (char *)malloc(sizeof(char)*sx->val_used); assert(fakehead->val != NULL); fakehead->val_used = fakehead->val_allocated = sx->val_used; strcpy(fakehead->val,sx->val); } if (size < 1) { fprintf (stderr, "Warning: print_sexp not provided sufficient space.\n"); return -1; } stack = make_stack (); 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) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); 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) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); 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) { assert(tdata->val != NULL); 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; if ((sz = snprintf(b,left,"%d#",tdata->binlength)) >= left) { left = 0; break; } b += sz; left -= sz; if (left < tdata->binlength) { left = 0; break; } memcpy(b,tdata->bindata,tdata->binlength); left -= tdata->binlength; b+=tdata->binlength; b[0] = ' '; left--; } else { left = 0; break; } } if (tdata->aty == SEXP_DQUOTE && left > 0) { b[0] = '\"'; b++; left--; } if (left < 0) left = 0; if (left == 0) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); break; } top->data = ((sexp_t *) top->data)->next; if (top->data != NULL) { b[0] = ' '; b++; left--; if (left == 0) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); break; } } } else if (tdata->ty == SEXP_LIST) { depth++; b[0] = '('; b++; left--; if (left == 0) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); break; } push (stack, tdata->list); } else { fprintf (stderr, "ERROR: Unknown type in sexp_t.\n"); fflush (stderr); return -1; } } while (depth != 0) { b[0] = ')'; b++; left--; depth--; if (left == 0) { fprintf (stderr, "Warning: print_sexp out of buffer space.\n"); break; } } if (left != 0) { b[0] = 0; retval = (size-left); } else { b--; b[0] = 0; retval = -1; } destroy_stack (stack); sexp_t_deallocate(fakehead); return retval; } /** * Iterative method to walk sx and turn it back into the string * representation of the s-expression. Fills the buffer. */ int print_sexp_cstr (CSTRING **s, sexp_t *sx, int ss, int gs) { int retval; char *tc; int depth = 0; faststack_t *stack; stack_lvl_t *top; sexp_t *tdata; sexp_t *fakehead; CSTRING *_s; char sbuf[32]; int i; if (sx == NULL) { fprintf(stderr,"print_sexp_cstr warning: s-expression is null.\n"); return -1; } _s = snew(ss); sgrowsize(gs); fakehead = sexp_t_allocate(); assert(fakehead!=NULL); /* duplicate the head to prevent going down a sx->next path that we don't really want to see. */ fakehead->list = sx->list; fakehead->ty = sx->ty; fakehead->next = NULL; /* this is the important part of fakehead */ fakehead->aty = sx->aty; if (fakehead->ty == SEXP_VALUE) { assert(sx->val != NULL); /* duplicate the value of the head into the fake head */ fakehead->val = (char *)malloc(sizeof(char)*sx->val_used); assert(fakehead->val != NULL); fakehead->val_used = fakehead->val_allocated = sx->val_used; strcpy(fakehead->val,sx->val); } stack = make_stack (); 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) { assert(tdata->bindata != NULL); assert(tdata->binlength > 0); sprintf(sbuf,"#b#%d#",tdata->binlength); _s = sadd(_s,sbuf); for (i=0;i<tdata->binlength;i++) _s = saddch(_s,tdata->bindata[i]); _s = saddch(_s,' '); } else { assert(tdata->val != NULL); 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 { fprintf (stderr, "ERROR: Unknown type in sexp_t.\n"); fflush (stderr); return -1; } } while (depth != 0) { _s = saddch(_s,')'); depth--; } *s = _s; retval = _s->curlen; destroy_stack (stack); sexp_t_deallocate(fakehead); return retval; } /** * Allocate a new sexp_t element representing a list. */ sexp_t *new_sexp_list(sexp_t *l) { sexp_t *sx = sexp_t_allocate(); sx->ty = SEXP_LIST; sx->list = l; sx->next = NULL; sx->val = NULL; sx->val_used = sx->val_allocated = 0; return sx; } /** * allocate a new sexp_t element representing a value */ sexp_t *new_sexp_atom(char *buf, int bs) { sexp_t *sx = sexp_t_allocate(); sx->ty = SEXP_VALUE; sx->val = (char *)malloc(sizeof(char)*(bs+1)); assert(sx->val != NULL); sx->val_used = sx->val_allocated = bs+1; strcpy(sx->val,buf); sx->list = sx->next = NULL; return sx; } --- NEW FILE: malloc_util.h --- /** * malloc_util.h : malloc debugging routines * * written by erik a. hendriks (hen...@la...). * * Copyright 2002 Erik Arjan Hendriks. * This software may be used and distributed according to the terms of the * GNU Public License, incorporated herein by reference. */ #ifndef _MALLOC_UTIL_H_ #define _MALLOC_UTIL_H_ #include <sys/types.h> /*-- Memory debugging stuff --*/ void x_init_alloc(void); void x_check_point_count(void); void x_inc_check_point(void); void *x_malloc(char *, int, size_t); void x_free (char *, int, void *); char *x_strdup(char *, int, char *); #ifdef _DEBUG_MALLOCS_ #define malloc(x) x_malloc(__FILE__, __LINE__, (x)) #define safe_malloc(x) x_malloc(__FILE__, __LINE__, (x)) #define free(x) x_free (__FILE__, __LINE__, (x)) #define strdup(x) x_strdup(__FILE__, __LINE__, (x)) #endif #endif --- NEW FILE: faststack.c --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ /** * faststack.c : implementation of fast stack. * * matt sottile / ma...@la... */ #include <stdlib.h> #include <stdio.h> #include "faststack.h" #include "sexp.h" /** * create an empty stack. */ faststack_t * make_stack () { faststack_t *s; s = (faststack_t *) malloc (sizeof (faststack_t)); s->top = NULL; s->bottom = NULL; s->height = 0; return s; } /** * free all levels of a stack */ void destroy_stack (faststack_t * s) { stack_lvl_t *sl; /* start at the bottom */ sl = s->bottom; /* if bottom is null, no levels to free. */ if (sl == NULL) 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; free (sl->above); } /* free the bottom level */ free (sl); /* free the stack wrapper itself. */ free (s); } /** * 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 = cur_stack->top; stack_lvl_t *tmp; /* if top isn't null, try to push above it. */ if (top != NULL) { /* if above isn't null, set the stack top to it and set the data */ if (top->above != NULL) { top = cur_stack->top = cur_stack->top->above; top->data = data; } else { /* otherwise, allocate a new level. */ tmp = top->above = (stack_lvl_t *) malloc (sizeof (stack_lvl_t)); 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 { tmp = cur_stack->top = (stack_lvl_t *) malloc (sizeof (stack_lvl_t)); 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; 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 { fprintf(stderr,"STACK: non-null top, but height < 0!\n"); } return top; } --- NEW FILE: sexp.h --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ #ifndef __SEXP_H__ #define __SEXP_H__ #include <stdio.h> /* for BUFSIZ only */ #include "faststack.h" #include "cstring.h" /** ** though unlikely to affect performance based on some simple tests ** run recently, this is available for people who wish to disable ** assertion paranoia. beware: if your code has assert() used in it ** and you don't want THOSE assertions disabled, #include <assert.h> ** after the last place sexp.h is included. I put this here to ** avoid the annoyance of "#ifdef .." messes around each assert() **/ #ifdef _NOASSERTS_ #undef assert #define assert(x) { } #endif /** * \mainpage A small and quick S-expression parsing library. * * \section intro Intro * * 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 (although every parseable expression is valid LISP), * 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 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 performance Performance Results * * The standard benchmark to compare versions of this parser has been the * "torture.c" file included in the tests/ subdirectory. This file takes * a large s-expression via STDIN, and parses, unparses, and destroys it * 1,000 times. The following numbers reflect tests done on a * representative expression from Supermon, the tool that this code was * created for. * * - <B>v0.1.1</B> : 1.61s * - <B>v0.1.2</B> : 1.12s * - <B>v0.2.0</B> : 1.07s * - <B>v0.2.1</B> : 1.09s * - <B>v0.2.2</B> : 1.09s * - <B>v0.2.3</B> : 1.11s * - <B>v0.3.0</B> : 0.42s * - <B>v0.3.1</B> : ?.??s * - <B>v0.3.2</B> : ?.??s * * \section license License Information * * This software and ancillary information (herein called "SOFTWARE") * called Supermon is made available under the terms described * here. The SOFTWARE has been approved for release with associated * LA-CC Number LA-CC 99-51. * * Unless otherwise indicated, this SOFTWARE has been authored by an * employee or employees of the University of California, operator of the * Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with * the U.S. Department of Energy. The U.S. Government has rights to use, * reproduce, and distribute this SOFTWARE, and to allow others to do so. * The public may copy, distribute, prepare derivative works and publicly * display this SOFTWARE without charge, provided that this Notice and * any statement of authorship are reproduced on all copies. Neither the * Government nor the University makes any warranty, express or implied, * or assumes any liability or responsibility 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. * * This software is licensed under the GNU Public License, which * is included as LICENSE_GPL in this source distribution. * * This library is part of the Supermon project, hence the name * "Supermon" above. See http://www.acl.lanl.gov/supermon/ for details on * that project. */ /** * \file sexp.h * * \brief API for a small, fast and portable s-expression parser library. * * Written by Matt Sottile (ma...@la...), January 2002. See LICENSE * file for licensing details. */ /*==============*/ /* 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. */ 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 the val field * is meaningful 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> this field will contain * the actual data represented by this element. */ char *val; /** * Number of bytes allocated for val. */ int val_allocated; /** * Number of bytes used in val (<= val_allocated). */ int 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.). */ 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. */ char *bindata; /** * The length of the data pointed at by bindata in bytes. */ unsigned int 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 } parsermode_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. */ int val_allocated; /** * Current number of used bytes in val. */ int 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. If this value is 0, no error occurred. Otherwise, it will be 1. */ unsigned int 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. */ unsigned int binexpected; /** * Number of bytes of the binary blob that have already been read in. */ unsigned int binread; /** * Pointer to the memory containing the binary data being read in. */ char *bindata; } pcont_t; /** * This structure is a wrapper around a standard I/O file descriptor and * the parsing infrastructure (continuation and a buffer) required to * parse off of it. This is used so that routines can hide the loops and * details required to accumulate up data read off of the file descriptor * and parse expressions individually out of it. */ typedef struct sexp_iowrap { /** * Continuation used to parse off of the file descriptor. */ pcont_t *cc; /** * The file descriptor. Currently CANNOT be a socket since implementation * uses read(), not recv(). */ int fd; /** * Buffer to read data into before parsing. */ char buf[BUFSIZ]; /** * Byte count for last read. If it is -1, there was an error. Otherwise, * it will be a value from 0 to BUFSIZ. */ int cnt; } sexp_iowrap_t; /*===========*/ /* FUNCTIONS */ /*===========*/ /* this is for C++ users */ #ifdef __cplusplus extern "C" { #endif /** * 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. */ void set_parser_buffer_params(int ss, int 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(); /** * 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. */ void sexp_cleanup(); /** * 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. */ int print_sexp(char *loc, int size, 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 arguments * to tune for performance reasons are <tt>ss</tt> and <tt>gs</tt> - the * buffer start size and growth size. */ int print_sexp_cstr(CSTRING **s, sexp_t *e, int ss, int gs); /** * Allocate a new sexp_t element representing a list. */ sexp_t *new_sexp_list(sexp_t *l); /** * allocate a new sexp_t element representing a value */ sexp_t *new_sexp_atom(char *buf, int bs); /** * 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); /** * create an IO wrapper structure around a file descriptor. */ sexp_iowrap_t *init_iowrap(int fd); /** * destroy an IO wrapper structure */ void destroy_iowrap(sexp_iowrap_t *iow); /** * 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. * returning null implies no s-expression was able to be read. */ sexp_t *read_one_sexp(sexp_iowrap_t *iow); /** * wrapper around parser for compatibility. */ sexp_t *parse_sexp(char *s, int len); /** * wrapper around parser for friendlier continuation use * pre-condition : continuation (cc) is NON-NULL! */ sexp_t *iparse_sexp(char *s, int len, pcont_t *cc); /** * given a LISP style s-expression string, parse it into a set of * connected sexp_t structures. */ pcont_t *cparse_sexp(char *s, int 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. */ void destroy_sexp(sexp_t *s); /* this is for C++ users */ #ifdef __cplusplus } #endif #include "sexp_ops.h" #endif /* __SEXP_H__ */ --- NEW FILE: cstring.c --- /* ACL:license */ /* This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. */ /* ACL:license */ /** * Implementation of stuff in cstring.h to make ron happy */ #include "cstring.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /** * growth size for cstrings -- default is 8k. use sgrowsize() to adjust. */ static size_t cstring_growsize = 8192; void sgrowsize(size_t s) { assert(s > 0); cstring_growsize = s; } CSTRING *snew(size_t s) { CSTRING *cs; cs = (CSTRING *)malloc(sizeof(CSTRING)); assert(cs != NULL); cs->len = s; cs->curlen = 0; cs->base = (char *)calloc(sizeof(char),s); assert(cs->base != NULL); return cs; } CSTRING *sadd(CSTRING *s, char *a) { int alen; char *newbase; /* no string, so bail */ if (s == NULL) { return NULL; } /* nothing to add, return s */ if (a == NULL) { return s; } alen = strlen(a); if (s->curlen + alen >= s->len) { newbase = (char *)realloc(s->base,s->len+cstring_growsize+alen); if (! newbase) { perror("realloc string"); s->len = s->curlen = 0; s->base = 0; return 0; } 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) { newbase = (char *)realloc(s->base,s->len+cstring_growsize+1); if (! newbase) { perror("realloc string"); s->len = s->curlen = 0; s->base = 0; return 0; } 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; } newbase = (char *)realloc(s->base,s->curlen+1); if (!newbase) { perror("realloc string in trim"); s->len = s->curlen = 0; s->base = 0; return NULL; } s->len = s->curlen+1; s->base = newbase; return s; } char *toCharPtr(CSTRING *s) { return s->base; } void sempty(CSTRING *s) { s->curlen = 0; } void sdestroy(CSTRING *s) { free(s->base); free(s); } --- NEW FILE: sexp_ops.c --- /** This software and ancillary information (herein called "SOFTWARE") called Supermon is made available under the terms described here. The SOFTWARE has been approved for release with associated LA-CC Number LA-CC 99-51. Unless otherwise indicated, this SOFTWARE has been authored by an employee or employees of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE, and to allow others to do so. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility 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. **/ /** NOTICE: This software is licensed under the GNU Public License, which is included as LICENSE_GPL in this source distribution. **/ /** NOTE: This library is part of the supermon project, hence the name supermon above. **/ #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "sexp_ops.h" /** * Given an s-expression, find the atom inside of it with the * value matchine name, and return a reference to it. If the atom * doesn't occur inside start, return NULL. */ sexp_t * find_sexp (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 { assert(start->val != NULL); if (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(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) { assert(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(sexp_t *sx) { int len = 0; 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(sexp_t *s) { sexp_t *snew; if (s == NULL) return NULL; snew = sexp_t_allocate(); assert(snew != NULL); snew->ty = s->ty; if (snew->ty == SEXP_VALUE) { snew->aty = s->aty; assert(s->val != NULL); /** allocate space **/ snew->val = (char *)malloc(sizeof(char)*s->val_used); assert(snew->val != NULL); snew->val_used = snew->val_allocated = s->val_used; strcpy(snew->val,s->val); snew->list = NULL; } else { snew->list = copy_sexp(s->list); } snew->next = copy_sexp(s->next); return snew; } /** * Cons: Concatenate two s-expressions together, without references to the * originals. */ sexp_t *cons_sexp(sexp_t *r, sexp_t *l) { sexp_t *cr, *cl, *t; cr = copy_sexp(r); if (cr->ty == SEXP_VALUE) { fprintf(stderr,"Cannot cons non-lists.\n"); destroy_sexp(cr); return NULL; } else { t = cr->list; while (t != NULL && t->next != NULL) t = t->next; } cl = copy_sexp(l); if (cl->ty == SEXP_LIST) { if (t != NULL && cl != NULL) { t->next = cl->list; /* free(cl); */ /* memory leak fix: SMJ, 4/24/2002 */ sexp_t_deallocate(cl); } } else { fprintf(stderr,"Cannot cons non-lists.\n"); destroy_sexp(cr); destroy_sexp(cl); return NULL; } return cr; } /** * car: similar to head, except this is a copy and not just a reference. */ sexp_t *car_sexp(sexp_t *s) { sexp_t *cr, *ocr; /* really dumb - calling on null */ if (s == NULL) { fprintf(stderr,"car called on null sexpr.\n"); return NULL; } /* less dumb - calling on an atom */ if (s->ty == SEXP_VALUE) { fprintf(stderr,"car called on an atom.\n"); return NULL; } /* ocr = (sexp_t *)malloc(sizeof(sexp_t));*/ ocr = sexp_t_allocate(); assert(ocr != NULL); ocr->ty = SEXP_LIST; ocr->next = NULL; /* allocate the new sexp_t */ /* cr = (sexp_t *)malloc(sizeof(sexp_t)); */ cr = sexp_t_allocate(); assert(cr != NULL); ocr->list = cr; /* copy the head of the sexpr */ if (s->list->ty == ... [truncated message content] |