/* File: varstring.c
** Author(s): kifer
** Contact: xsb-contact@cs.sunysb.edu
**
** Copyright (C) The Research Foundation of SUNY, 1999
**
** XSB is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
**
** XSB 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 Library General Public License for
** more details.
**
** You should have received a copy of the GNU Library General Public License
** along with XSB; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: varstring.c,v 1.13 2001/07/24 15:36:49 dwarren Exp $
**
*/
/*
Usage:
XSB_StrDefine(foo); // Declare foo as a variable length string
XSB_StrDefine(boo); // Declare boo as a variable length string
VarString *goo; // Declare a pointer to a varstring.
foo.op->set(&foo,"abc"); // or XSB_StrSet(&foo, "abc");
foo.op->append(&foo,"123"); // or XSB_StrAppend(&foo, "123");
// shrink foo, set the increment to 5
foo.op->shrink(&foo,5); // or XSB_StrShrink(&foo,5);
foo.op->prepend(&foo,"098"); // or XSB_StrPrepend(&foo,"098");
boo.op->prepend("pasddsf");
goo = &boo;
goo->op->strcmp(goo, "jdshdd"); // or XSB_StrStrCmp(goo,"jdshdd");
if (foo.length > 0)
printf("%s %d\n", foo.string, foo.length);
printf("boo: %s\n", goo->string);
*/
/* To test: define the string below and compile: cc varstring.c; a.out */
#undef DEBUG_VARSTRING
#include "xsb_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "wind2unix.h"
#include "auxlry.h"
#include "cell_xsb.h"
#ifndef DEBUG_VARSTRING
#include "error_xsb.h"
#endif
#include "varstring_xsb.h"
#define DEFAULT_VARSTR_INCREMENT 128
#define NEWLENGTH(vstr,additional_size) \
vstr->length + additional_size +1
static void vs_init(VarString*, int);
static void vs_set(VarString*, char*);
static void vs_setv(VarString*, VarString*);
static void vs_append(VarString*, char*);
static void vs_prepend(VarString*, char*);
static inline void vs_appendv(VarString*, VarString*);
static inline void vs_prependv(VarString*, VarString*);
static inline int vs_compare(VarString*, VarString*);
static inline int vs_strcmp(VarString*, char*);
static inline void vs_destroy(VarString*);
static inline void vs_shrink(VarString*, int);
static inline void vs_ensure_size(VarString*, int);
/* add char to the end of string, don't null-terminate */
static void vs_appendblk(VarString *vstr,char*,int);
static void vs_prependblk(VarString *vstr,char*,int);
static void vs_adjust_size(VarString *vstr, int add_size);
static inline void vs_null_terminate(VarString *vstr);
DllExport struct varstr_ops VarStrOps = {vs_set,vs_setv,
vs_append,vs_prepend,
vs_appendv,vs_prependv,
vs_compare,vs_strcmp,
vs_appendblk,vs_prependblk,
vs_null_terminate,
vs_ensure_size,
vs_shrink,vs_destroy};
DllExport void call_conv varstring_init(VarString *vstr)
{
vstr->size = 0;
vstr->increment = 0;
vstr->length =0;
vstr->string = NULL;
vstr->op = &VarStrOps;
}
DllExport void call_conv varstring_create(VarString **vstr)
{
*vstr = (VarString *) malloc(sizeof(VarString));
varstring_init(*vstr);
}
/* initialize a var string. This is the only function that isn't a member of
the data structure, because somebody must assign functions to the function
pointers inside struct varstr */
static void vs_init(VarString *vstr, int increment)
{
if (vstr->string != NULL)
return;
if (increment < 1)
increment = DEFAULT_VARSTR_INCREMENT;
if (NULL == (vstr->string = (char *)calloc(1, increment))) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Cannot allocate memory for a variable-length string\n");
return;
#else
xsb_abort("Cannot allocate memory for a variable-length string");
#endif
}
vstr->increment = increment;
vstr->size = increment;
vstr->length = 0;
vstr->string[0] = '\0';
}
/* change the increment and also shrink the allocated space to the minimum */
static inline void vs_shrink(VarString *vstr, int increment)
{
if (vstr->string == NULL)
vs_init(vstr,increment);
else { /* already initialized */
vstr->increment = increment;
/* make sure we don't clobber existing stuff */
vs_adjust_size(vstr, vstr->length+1);
}
}
/* ensure that the VarString has room for minsize bytes */
static inline void vs_ensure_size(VarString *vstr, int minsize)
{
vs_init(vstr,0);
vs_adjust_size(vstr, max(vstr->length,minsize)+1);
}
static void vs_set(VarString *vstr, char *str)
{
int newlength;
vs_init(vstr,0); /* conditional init */
if (str == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Assigning a NULL pointer to a variable-length string\n");
return;
#else
xsb_bug("Assigning a NULL pointer to a variable-length string");
#endif
}
newlength = strlen(str);
vs_adjust_size(vstr, newlength+1);
strcpy(vstr->string, str);
vstr->length=newlength;
}
static void vs_setv(VarString *vstr, VarString *vstr1)
{
vs_set(vstr, vstr1->string);
}
static void vs_append(VarString *vstr, char *str)
{
if (str == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Appending a NULL string\n");
return;
#else
xsb_bug("Appending a NULL string");
#endif
}
vs_appendblk(vstr, str, strlen(str));
vs_null_terminate(vstr);
}
static void vs_prepend(VarString *vstr, char *str)
{
if (str == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Appending a NULL string\n");
return;
#else
xsb_bug("Appending a NULL string");
#endif
}
vs_prependblk(vstr, str, strlen(str));
}
static inline void vs_appendv(VarString *vstr, VarString *vstr1)
{
vs_append(vstr, vstr1->string);
}
static inline void vs_prependv(VarString *vstr, VarString *vstr1)
{
vs_prepend(vstr, vstr1->string);
}
static inline int vs_compare(VarString *vstr, VarString *vstr1)
{
/* conditional init */
vs_init(vstr,0);
vs_init(vstr1,0);
return strcmp(vstr->string, vstr1->string);
}
static inline int vs_strcmp(VarString *vstr, char *str)
{
vs_init(vstr,0); /* conditional init */
if (str == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Comparing string with a NULL pointer\n");
return 0;
#else
xsb_bug("Comparing string with a NULL pointer");
#endif
}
return strcmp(vstr->string, str);
}
/* destruction is necessary for automatic VarString's,
or else there will be a memory leak */
static inline void vs_destroy(VarString *vstr)
{
if (vstr->string == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr,
"Attempt to deallocate uninitialized variable-length string\n");
return;
#else
xsb_bug("Attempt to deallocate uninitialized variable-length string");
#endif
}
#ifdef DEBUG_VARSTRING
fprintf(stderr,
"Deallocating a variable-length string\n");
#endif
free(vstr->string);
vstr->string = NULL;
vstr->size = 0;
vstr->length = 0;
vstr->increment = 0;
}
/* append block of chars, don't NULL-terminate */
static void vs_appendblk(VarString *vstr, char *blk, int blk_size)
{
int newlength;
vs_init(vstr,0); /* conditional init */
if (blk == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Appending a NULL string\n");
return;
#else
xsb_bug("Appending a NULL string");
#endif
}
newlength = NEWLENGTH(vstr,blk_size);
if (newlength > vstr->size)
vs_adjust_size(vstr, newlength);
strncpy(vstr->string+vstr->length, blk, blk_size);
vstr->length=vstr->length + blk_size;
}
/* append block of chars */
static void vs_prependblk(VarString *vstr, char *blk, int blk_size)
{
int newlength;
vs_init(vstr,0); /* conditional init */
if (blk == NULL) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "Prepending a NULL string\n");
return;
#else
xsb_bug("Prepending a NULL string");
#endif
}
newlength = NEWLENGTH(vstr,blk_size);
if (newlength > vstr->size)
vs_adjust_size(vstr, newlength);
memmove(vstr->string+blk_size, vstr->string, vstr->length+1);
strncpy(vstr->string, blk, blk_size);
vstr->length=vstr->length + blk_size;
}
static inline void vs_null_terminate(VarString *vstr)
{
int newlength;
vs_init(vstr,0); /* conditional init */
newlength = NEWLENGTH(vstr,0);
if (newlength > vstr->size)
vs_adjust_size(vstr, newlength);
vstr->string[vstr->length] = '\0';
}
/* Adjust size to the next multiple of the increment after minsize;
This can enlarge as well as shrink a VarString.
The caller must make sure that the existing data isn't clobbered by
shrinking. */
static void vs_adjust_size(VarString *vstr, int minsize)
{
int newsize;
vs_init(vstr,0); /* conditional init */
newsize = (minsize/vstr->increment +1) * (vstr->increment);
if (NULL == (vstr->string = (char *)realloc(vstr->string, newsize))) {
#ifdef DEBUG_VARSTRING
fprintf(stderr, "No room to expand a variable-length string\n");
return;
#else
vstr->size = 0;
vstr->length = 0;
xsb_abort("No room to expand a variable-length string");
#endif
}
#ifdef DEBUG_VARSTRING
if (newsize > vstr->size)
fprintf(stderr, "Expanding a VarString from %d to %d\n",
vstr->size, newsize);
else if (newsize < vstr->size)
fprintf(stderr, "Shrinking a VarString from %d to %d\n",
vstr->size, newsize);
#endif
vstr->size = newsize;
}
#ifdef DEBUG_VARSTRING
int main (int argc, char** argv)
{
XSB_StrDefine(foo);
XSB_StrDefine(boo);
XSB_StrDefine(goo);
VarString *loo;
XSB_StrSet(&foo, "abc");
printf("foo1: %s %d/%d\n", foo.string, foo.length, foo.size);
foo.op->append(&foo, "123");
printf("foo2: %s %d/%d\n", foo.string, foo.length, foo.size);
foo.op->prepend(&foo, "098");
printf("foo3: %s %d/%d\n", foo.string, foo.length, foo.size);
boo.op->prepend(&boo, "booooooo");
printf("boo: %s %d/%d\n", boo.string, boo.length, boo.size);
boo.op->shrink(&boo, 3);
boo.op->appendv(&boo, &foo);
loo = &boo;
printf("boo2: %s %d/%d\n", loo->string, boo.length, boo.size);
foo.op->shrink(&foo,60);
if (foo.length > 0)
printf("foo4: %s %d/%d\n", foo.string, foo.length, foo.size);
boo.op->set(&boo,"123");
XSB_StrAppend(loo,"---");
printf("boo3: %s %d/%d\n", loo->string, boo.length, boo.size);
boo.op->append(&boo,"4567");
printf("boo4: %s %d/%d\n", loo->string, boo.length, boo.size);
printf("initialized: boo=%p foo=%p goo=%p\n",
boo.string, foo.string, goo.string);
XSB_StrSetV(loo, &foo);
printf("boo5: %s %d/%d\n", loo->string, boo.length, boo.size);
XSB_StrEnsureSize(loo, 1000);
XSB_StrAppendBlk(loo,NULL,5);
XSB_StrAppend(loo,NULL);
XSB_StrDestroy(&foo);
XSB_StrDestroy(loo);
goo.op->destroy(&goo);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1