diff options
Diffstat (limited to 'src/libs/resource')
-rw-r--r-- | src/libs/resource/Makeinfo | 3 | ||||
-rw-r--r-- | src/libs/resource/direct.c | 101 | ||||
-rw-r--r-- | src/libs/resource/filecntl.c | 146 | ||||
-rw-r--r-- | src/libs/resource/getres.c | 257 | ||||
-rw-r--r-- | src/libs/resource/index.h | 54 | ||||
-rw-r--r-- | src/libs/resource/loadres.c | 54 | ||||
-rw-r--r-- | src/libs/resource/propfile.c | 129 | ||||
-rw-r--r-- | src/libs/resource/propfile.h | 30 | ||||
-rw-r--r-- | src/libs/resource/resinit.c | 651 | ||||
-rw-r--r-- | src/libs/resource/resintrn.h | 34 | ||||
-rw-r--r-- | src/libs/resource/stringbank.c | 181 | ||||
-rw-r--r-- | src/libs/resource/stringbank.h | 57 |
12 files changed, 1697 insertions, 0 deletions
diff --git a/src/libs/resource/Makeinfo b/src/libs/resource/Makeinfo new file mode 100644 index 0000000..ddac8e2 --- /dev/null +++ b/src/libs/resource/Makeinfo @@ -0,0 +1,3 @@ +uqm_CFILES="direct.c filecntl.c getres.c loadres.c stringbank.c + propfile.c resinit.c" +uqm_HFILES="index.h propfile.h resintrn.h stringbank.h" diff --git a/src/libs/resource/direct.c b/src/libs/resource/direct.c new file mode 100644 index 0000000..b3d3541 --- /dev/null +++ b/src/libs/resource/direct.c @@ -0,0 +1,101 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "libs/strings/strintrn.h" +#include "libs/memlib.h" +#include "port.h" +#include "libs/uio.h" +#include <sys/stat.h> + +DIRENTRY_REF +LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path, + const char *pattern, match_MatchType matchType) +{ + uio_DirList *dirList; + COUNT num_entries; + COUNT i; + uio_DirHandle *dir; + STRING_TABLE StringTable; + STRING_TABLE_DESC *lpST; + STRING lpLastString; + + dir = uio_openDirRelative (dirHandle, path, 0); + assert(dir != NULL); + dirList = uio_getDirList (dir, "", pattern, matchType); + assert(dirList != NULL); + num_entries = 0; + + // First, count the amount of space needed + for (i = 0; i < dirList->numNames; i++) + { + struct stat sb; + + if (dirList->names[i][0] == '.') + { + dirList->names[i] = NULL; + continue; + } + if (uio_stat (dir, dirList->names[i], &sb) == -1) + { + dirList->names[i] = NULL; + continue; + } + if (!S_ISREG (sb.st_mode)) + { + dirList->names[i] = NULL; + continue; + } + num_entries++; + } + uio_closeDir (dir); + + if (num_entries == 0) { + uio_DirList_free(dirList); + return ((DIRENTRY_REF) 0); + } + + StringTable = AllocStringTable (num_entries, 0); + lpST = StringTable; + if (lpST == 0) + { + FreeStringTable (StringTable); + uio_DirList_free(dirList); + return ((DIRENTRY_REF) 0); + } + lpST->size = num_entries; + lpLastString = lpST->strings; + + for (i = 0; i < dirList->numNames; i++) + { + int size; + STRINGPTR target; + if (dirList->names[i] == NULL) + continue; + size = strlen (dirList->names[i]) + 1; + target = HMalloc (size); + memcpy (target, dirList->names[i], size); + lpLastString->data = target; + lpLastString->length = size; + lpLastString++; + } + + uio_DirList_free(dirList); + return StringTable; +} + + diff --git a/src/libs/resource/filecntl.c b/src/libs/resource/filecntl.c new file mode 100644 index 0000000..e2a81d9 --- /dev/null +++ b/src/libs/resource/filecntl.c @@ -0,0 +1,146 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef WIN32 +#include <io.h> +#endif +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "port.h" +#include "resintrn.h" +#include "libs/uio.h" + +uio_Stream * +res_OpenResFile (uio_DirHandle *dir, const char *filename, const char *mode) +{ + uio_Stream *fp; + struct stat sb; + + if (uio_stat (dir, filename, &sb) == 0 && S_ISDIR(sb.st_mode)) + return ((uio_Stream *) ~0); + + fp = uio_fopen (dir, filename, mode); + + return (fp); +} + +BOOLEAN +res_CloseResFile (uio_Stream *fp) +{ + if (fp) + { + if (fp != (uio_Stream *)~0) + uio_fclose (fp); + return (TRUE); + } + + return (FALSE); +} + +BOOLEAN +DeleteResFile (uio_DirHandle *dir, const char *filename) +{ + return (uio_unlink (dir, filename) == 0); +} + +size_t +ReadResFile (void *lpBuf, size_t size, size_t count, uio_Stream *fp) +{ + int retval; + + retval = uio_fread (lpBuf, size, count, fp); + + return (retval); +} + +size_t +WriteResFile (const void *lpBuf, size_t size, size_t count, uio_Stream *fp) +{ + int retval; + + retval = uio_fwrite (lpBuf, size, count, fp); + + return (retval); +} + +int +GetResFileChar (uio_Stream *fp) +{ + int retval; + + retval = uio_getc (fp); + + return (retval); +} + +int +PutResFileChar (char ch, uio_Stream *fp) +{ + int retval; + + retval = uio_putc (ch, fp); + return (retval); +} + +int +PutResFileNewline (uio_Stream *fp) +{ + int retval; + +#ifdef WIN32 + PutResFileChar ('\r', fp); +#endif + retval = PutResFileChar ('\n', fp); + return (retval); +} + +long +SeekResFile (uio_Stream *fp, long offset, int whence) +{ + long retval; + + retval = uio_fseek (fp, offset, whence); + + return (retval); +} + +long +TellResFile (uio_Stream *fp) +{ + long retval; + + retval = uio_ftell (fp); + + return (retval); +} + +size_t +LengthResFile (uio_Stream *fp) +{ + struct stat sb; + + if (fp == (uio_Stream *)~0) + return (1); + if (uio_fstat(uio_streamHandle(fp), &sb) == -1) + return 1; + return sb.st_size; +} + + diff --git a/src/libs/resource/getres.c b/src/libs/resource/getres.c new file mode 100644 index 0000000..39e24a9 --- /dev/null +++ b/src/libs/resource/getres.c @@ -0,0 +1,257 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "options.h" +#include "port.h" +#include "resintrn.h" +#include "libs/memlib.h" +#include "libs/log.h" +#include "libs/uio/charhashtable.h" + +const char *_cur_resfile_name; +// When a file is being loaded, _cur_resfile_name is set to its name. +// At other times, it is NULL. + +ResourceDesc * +lookupResourceDesc (RESOURCE_INDEX idx, RESOURCE res) +{ + return (ResourceDesc *) CharHashTable_find (idx->map, res); +} + +void +loadResourceDesc (ResourceDesc *desc) +{ + desc->vtable->loadFun (desc->fname, &desc->resdata); +} + +void * +LoadResourceFromPath (const char *path, ResourceLoadFileFun *loadFun) +{ + uio_Stream *stream; + unsigned long dataLen; + void *resdata; + + stream = res_OpenResFile (contentDir, path, "rb"); + if (stream == NULL) + { + log_add (log_Warning, "Warning: Can't open '%s'", path); + return NULL; + } + + dataLen = LengthResFile (stream); + log_add (log_Info, "\t'%s' -- %lu bytes", path, dataLen); + + if (dataLen == 0) + { + log_add (log_Warning, "Warning: Trying to load empty file '%s'.", path); + goto err; + } + + _cur_resfile_name = path; + resdata = (*loadFun) (stream, dataLen); + _cur_resfile_name = NULL; + res_CloseResFile (stream); + + return resdata; + +err: + res_CloseResFile (stream); + return NULL; +} + +const char * +res_GetResourceType (RESOURCE res) +{ + RESOURCE_INDEX resourceIndex; + ResourceDesc *desc; + + if (res == NULL_RESOURCE) + { + log_add (log_Warning, "Trying to get type of null resource"); + return NULL; + } + + resourceIndex = _get_current_index_header (); + desc = lookupResourceDesc (resourceIndex, res); + if (desc == NULL) + { + log_add (log_Warning, "Trying to get type of undefined resource '%s'", + res); + return NULL; + } + + return desc->vtable->resType; +} + + +// Get a resource by its resource ID. +void * +res_GetResource (RESOURCE res) +{ + RESOURCE_INDEX resourceIndex; + ResourceDesc *desc; + + if (res == NULL_RESOURCE) + { + log_add (log_Warning, "Trying to get null resource"); + return NULL; + } + + resourceIndex = _get_current_index_header (); + + desc = lookupResourceDesc (resourceIndex, res); + if (desc == NULL) + { + log_add (log_Warning, "Trying to get undefined resource '%s'", + res); + return NULL; + } + + if (desc->resdata.ptr == NULL) + loadResourceDesc (desc); + if (desc->resdata.ptr != NULL) + ++desc->refcount; + + return desc->resdata.ptr; + // May still be NULL, if the load failed. +} + +DWORD +res_GetIntResource (RESOURCE res) +{ + RESOURCE_INDEX resourceIndex; + ResourceDesc *desc; + + if (res == NULL_RESOURCE) + { + log_add (log_Warning, "Trying to get null resource"); + return 0; + } + + resourceIndex = _get_current_index_header (); + + desc = lookupResourceDesc (resourceIndex, res); + if (desc == NULL) + { + log_add (log_Warning, "Trying to get undefined resource '%s'", + res); + return 0; + } + + return desc->resdata.num; +} + +BOOLEAN +res_GetBooleanResource (RESOURCE res) +{ + return (res_GetIntResource (res) != 0); +} + +// NB: this function appears to be never called! +void +res_FreeResource (RESOURCE res) +{ + ResourceDesc *desc; + ResourceFreeFun *freeFun; + + desc = lookupResourceDesc (_get_current_index_header(), res); + if (desc == NULL) + { + log_add (log_Debug, "Warning: trying to free an unrecognised " + "resource."); + return; + } + + if (desc->refcount > 0) + --desc->refcount; + else + log_add (log_Debug, "Warning: freeing an unreferenced resource."); + if (desc->refcount > 0) + return; // Still references left + + freeFun = desc->vtable->freeFun; + if (freeFun == NULL) + { + log_add (log_Debug, "Warning: trying to free a non-heap resource."); + return; + } + + if (desc->resdata.ptr == NULL) + { + log_add (log_Debug, "Warning: trying to free not loaded " + "resource."); + return; + } + + (*freeFun) (desc->resdata.ptr); + desc->resdata.ptr = NULL; +} + +// By calling this function the caller will be responsible of unloading +// the resource. If res_GetResource() get called again for this +// resource, a NEW copy will be loaded, regardless of whether a detached +// copy still exists. +void * +res_DetachResource (RESOURCE res) +{ + ResourceDesc *desc; + ResourceFreeFun *freeFun; + void *result; + + desc = lookupResourceDesc (_get_current_index_header(), res); + if (desc == NULL) + { + log_add (log_Debug, "Warning: trying to detach from an unrecognised " + "resource."); + return NULL; + } + + freeFun = desc->vtable->freeFun; + if (freeFun == NULL) + { + log_add (log_Debug, "Warning: trying to detach from a non-heap resource."); + return NULL; + } + + if (desc->resdata.ptr == NULL) + { + log_add (log_Debug, "Warning: trying to detach from a not loaded " + "resource."); + return NULL; + } + + if (desc->refcount > 1) + { + log_add (log_Debug, "Warning: trying to detach a resource referenced " + "%u times", desc->refcount); + return NULL; + } + + result = desc->resdata.ptr; + desc->resdata.ptr = NULL; + desc->refcount = 0; + + return result; +} + +BOOLEAN +FreeResourceData (void *data) +{ + HFree (data); + return TRUE; +} diff --git a/src/libs/resource/index.h b/src/libs/resource/index.h new file mode 100644 index 0000000..bdbb162 --- /dev/null +++ b/src/libs/resource/index.h @@ -0,0 +1,54 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef LIBS_RESOURCE_INDEX_H_ +#define LIBS_RESOURCE_INDEX_H_ + +typedef struct resource_handlers ResourceHandlers; +typedef struct resource_desc ResourceDesc; + +#include <stdio.h> +#include "libs/reslib.h" +#include "libs/uio/charhashtable.h" + +struct resource_handlers +{ + const char *resType; + ResourceLoadFun *loadFun; + ResourceFreeFun *freeFun; + ResourceStringFun *toString; +}; + +struct resource_desc +{ + RESOURCE res_id; + char *fname; + ResourceHandlers *vtable; + RESOURCE_DATA resdata; + // refcount is rudimentary as nothing really frees the descriptors + unsigned refcount; +}; + +struct resource_index_desc +{ + CharHashTable_HashTable *map; + size_t numRes; +}; + +#endif /* LIBS_RESOURCE_INDEX_H_ */ + diff --git a/src/libs/resource/loadres.c b/src/libs/resource/loadres.c new file mode 100644 index 0000000..a9849e4 --- /dev/null +++ b/src/libs/resource/loadres.c @@ -0,0 +1,54 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "resintrn.h" +#include "libs/memlib.h" +#include "libs/log.h" + + +void * +GetResourceData (uio_Stream *fp, DWORD length) +{ + void *result; + DWORD compLen; + + // Resource data used to be prefixed by its length in package files. + // A valid length prefix indicated compressed data, and + // a length prefix ~0 meant uncompressed. + // Currently, .ct and .xlt files still carry a ~0 length prefix. + if (ReadResFile (&compLen, sizeof (compLen), 1, fp) != 1) + return NULL; + if (compLen != ~(DWORD)0) + { + log_add (log_Warning, "LZ-compressed binary data not supported"); + return NULL; + } + length -= sizeof (DWORD); + + result = AllocResourceData (length); + if (!result) + return NULL; + + if (ReadResFile (result, 1, length, fp) != length) + { + FreeResourceData (result); + result = NULL; + } + + return result; +} diff --git a/src/libs/resource/propfile.c b/src/libs/resource/propfile.c new file mode 100644 index 0000000..1784600 --- /dev/null +++ b/src/libs/resource/propfile.c @@ -0,0 +1,129 @@ +/* propfile.c, Copyright (c) 2008 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se 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. + */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "libs/log.h" +#include "propfile.h" +#include "libs/reslib.h" + +void +PropFile_from_string (char *d, PROPERTY_HANDLER handler, const char *prefix) +{ + int len, i; + + len = strlen(d); + i = 0; + while (i < len) { + int key_start, key_end, value_start, value_end; + /* Starting a line: search for non-whitespace */ + while ((i < len) && isspace (d[i])) i++; + if (i >= len) break; /* Done parsing! */ + /* If it was a comment, skip to end of comment/file */ + if (d[i] == '#') { + while ((i < len) && (d[i] != '\n')) i++; + if (i >= len) break; + continue; /* Back to keyword search */ + } + key_start = i; + /* Find the = on this line */ + while ((i < len) && (d[i] != '=') && + (d[i] != '\n') && (d[i] != '#')) i++; + if (i >= len) { /* Bare key at EOF */ + log_add (log_Warning, "Warning: Bare keyword at EOF"); + break; + } + /* Comments here mean incomplete line too */ + if (d[i] != '=') { + log_add (log_Warning, "Warning: Key without value"); + while ((i < len) && (d[i] != '\n')) i++; + if (i >= len) break; + continue; /* Back to keyword search */ + } + /* Key ends at first whitespace before = , or at key_start*/ + key_end = i; + while ((key_end > key_start) && isspace (d[key_end-1])) + key_end--; + + /* Consume the = */ + i++; + /* Value starts at first non-whitespace after = on line... */ + while ((i < len) && (d[i] != '#') && (d[i] != '\n') && + isspace (d[i])) + i++; + value_start = i; + /* Until first non-whitespace before terminator */ + while ((i < len) && (d[i] != '#') && (d[i] != '\n')) + i++; + value_end = i; + while ((value_end > value_start) && isspace (d[value_end-1])) + value_end--; + /* Skip past EOL or EOF */ + while ((i < len) && (d[i] != '\n')) + i++; + i++; + + /* We now have start and end values for key and value. + We terminate the strings for both by writing \0s, then + make a new map entry. */ + d[key_end] = '\0'; + d[value_end] = '\0'; + if (prefix) { + char buf[256]; + snprintf(buf, 255, "%s%s", prefix, d+key_start); + buf[255]=0; + handler(buf, d+value_start); + } else { + handler (d+key_start, d+value_start); + } + } +} + +void +PropFile_from_file (uio_Stream *f, PROPERTY_HANDLER handler, const char *prefix) +{ + size_t flen; + char *data; + + flen = LengthResFile (f); + + data = malloc (flen + 1); + if (!data) { + return; + } + + // We may end up with less bytes than we asked for due to the + // DOS->Unix newline conversion + flen = ReadResFile (data, 1, flen, f); + data[flen] = '\0'; + + PropFile_from_string (data, handler, prefix); + free (data); +} + +void +PropFile_from_filename (uio_DirHandle *path, const char *fname, PROPERTY_HANDLER handler, const char *prefix) +{ + uio_Stream *f = res_OpenResFile (path, fname, "rt"); + if (!f) { + return; + } + PropFile_from_file (f, handler, prefix); + res_CloseResFile(f); +} diff --git a/src/libs/resource/propfile.h b/src/libs/resource/propfile.h new file mode 100644 index 0000000..edc8c36 --- /dev/null +++ b/src/libs/resource/propfile.h @@ -0,0 +1,30 @@ +/* propfile.h, Copyright (c) 2008 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se 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. + */ + +#ifndef PROPFILE_H_ +#define PROPFILE_H_ + +#include "libs/uio.h" + +typedef void (*PROPERTY_HANDLER) (const char *, const char *); + +void PropFile_from_string (char *d, PROPERTY_HANDLER handler, const char *prefix); +void PropFile_from_file (uio_Stream *f, PROPERTY_HANDLER handler, const char *prefix); +void PropFile_from_filename (uio_DirHandle *path, const char *fname, PROPERTY_HANDLER handler, const char *prefix); + +#endif diff --git a/src/libs/resource/resinit.c b/src/libs/resource/resinit.c new file mode 100644 index 0000000..dacbee4 --- /dev/null +++ b/src/libs/resource/resinit.c @@ -0,0 +1,651 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "resintrn.h" +#include "libs/memlib.h" +#include "options.h" +#include "types.h" +#include "libs/log.h" +#include "libs/gfxlib.h" +#include "libs/reslib.h" +#include "libs/sndlib.h" +#include "libs/vidlib.h" +#include "propfile.h" +#include <ctype.h> +#include <stdlib.h> +// XXX: we should not include anything from uqm/ inside libs/ +#include "uqm/coderes.h" + +static RESOURCE_INDEX +allocResourceIndex (void) { + RESOURCE_INDEX ndx = HMalloc (sizeof (RESOURCE_INDEX_DESC)); + ndx->map = CharHashTable_newHashTable (NULL, NULL, NULL, NULL, NULL, + 0, 0.85, 0.9); + return ndx; +} + +static void +freeResourceIndex (RESOURCE_INDEX h) { + if (h != NULL) + { + /* TODO: This leaks the contents of h->map */ + CharHashTable_deleteHashTable (h->map); + HFree (h); + } +} + +#define TYPESIZ 32 + +static ResourceDesc * +newResourceDesc (const char *res_id, const char *resval) +{ + const char *path; + int pathlen; + ResourceHandlers *vtable; + ResourceDesc *result, *handlerdesc; + RESOURCE_INDEX idx = _get_current_index_header (); + char typestr[TYPESIZ]; + + path = strchr (resval, ':'); + if (path == NULL) + { + log_add (log_Warning, "Could not find type information for resource '%s'", res_id); + strncpy(typestr, "sys.UNKNOWNRES", TYPESIZ); + path = resval; + } + else + { + int n = path - resval; + + if (n >= TYPESIZ - 4) + { + n = TYPESIZ - 5; + } + strncpy (typestr, "sys.", TYPESIZ); + strncat (typestr+1, resval, n); + typestr[n+4] = '\0'; + path++; + } + pathlen = strlen (path); + + handlerdesc = lookupResourceDesc(idx, typestr); + if (handlerdesc == NULL) { + path = resval; + log_add (log_Warning, "Illegal type '%s' for resource '%s'; treating as UNKNOWNRES", typestr, res_id); + handlerdesc = lookupResourceDesc(idx, "sys.UNKNOWNRES"); + } + + vtable = (ResourceHandlers *)handlerdesc->resdata.ptr; + + if (vtable->loadFun == NULL) + { + log_add (log_Warning, "Warning: Unable to load '%s'; no handler " + "for type %s defined.", res_id, typestr); + return NULL; + } + + result = HMalloc (sizeof (ResourceDesc)); + if (result == NULL) + return NULL; + + result->fname = HMalloc (pathlen + 1); + strncpy (result->fname, path, pathlen); + result->fname[pathlen] = '\0'; + result->vtable = vtable; + result->refcount = 0; + + if (vtable->freeFun == NULL) + { + /* Non-heap resources are raw values. Work those out at load time. */ + vtable->loadFun (result->fname, &result->resdata); + } + else + { + result->resdata.ptr = NULL; + } + return result; +} + +static void +process_resource_desc (const char *key, const char *value) +{ + CharHashTable_HashTable *map = _get_current_index_header ()->map; + ResourceDesc *newDesc = newResourceDesc (key, value); + if (newDesc != NULL) + { + if (!CharHashTable_add (map, key, newDesc)) + { + res_Remove (key); + CharHashTable_add (map, key, newDesc); + } + } +} + +static void +UseDescriptorAsRes (const char *descriptor, RESOURCE_DATA *resdata) +{ + resdata->str = descriptor; +} + +static void +DescriptorToInt (const char *descriptor, RESOURCE_DATA *resdata) +{ + resdata->num = atoi (descriptor); +} + +static void +DescriptorToBoolean (const char *descriptor, RESOURCE_DATA *resdata) +{ + if (!strcasecmp (descriptor, "true")) + { + resdata->num = TRUE; + } + else + { + resdata->num = FALSE; + } +} + +static inline size_t +skipWhiteSpace (const char *start) +{ + const char *ptr = start; + while (isspace (*ptr)) + ptr++; + return (ptr - start); +} + +// On success, resdata->num will be filled with a 32-bits RGBA value. +static void +DescriptorToColor (const char *descriptor, RESOURCE_DATA *resdata) +{ + int bytesParsed; + int componentBits; + int maxComponentValue; + size_t componentCount; + size_t compI; + int comps[4]; + // One element for each of r, g, b, a. + + descriptor += skipWhiteSpace (descriptor); + +#if 0 + // Can't use this; '#' starts a comment. + if (*descriptor == '#') + { + // "#rrggbb" + int i; + DWORD value = 0; + + descriptor++; + for (i = 0; i < 6; i++) + { + BYTE nibbleValue; + if (*descriptor >= '0' && *descriptor <= '9') + nibbleValue = *descriptor - '0'; + else if (*descriptor >= 'a' && *descriptor <= 'f') + nibbleValue = 0xa + *descriptor - 'a'; + else if (*descriptor >= 'A' && *descriptor <= 'F') + nibbleValue = 0xa + *descriptor - 'A'; + else + goto fail; + + value = (value * 16) + nibbleValue; + descriptor++; + } + + descriptor += skipWhiteSpace (descriptor); + + if (*descriptor != '\0') + log_add (log_Warning, "Junk after color resource string."); + + resdata->num = (value << 8) | 0xff; + return; + } +#endif + + // Color is of the form "rgb(r, g, b)", "rgba(r, g, b, a)", + // or "rgb15(r, g, b)". + + if (sscanf (descriptor, "rgb ( %i , %i , %i ) %n", + &comps[0], &comps[1], &comps[2], &bytesParsed) >= 3) + { + componentBits = 8; + componentCount = 3; + comps[3] = 0xff; + } + else if (sscanf (descriptor, "rgba ( %i , %i , %i , %i ) %n", + &comps[0], &comps[1], &comps[2], &comps[3], &bytesParsed) >= 4) + { + componentBits = 8; + componentCount = 4; + } + else if (sscanf (descriptor, "rgb15 ( %i , %i , %i ) %n", + &comps[0], &comps[1], &comps[2], &bytesParsed) >= 3) + { + componentBits = 5; + componentCount = 3; + comps[3] = 0xff; + } + else + goto fail; + + if (descriptor[bytesParsed] != '\0') + log_add (log_Warning, "Junk after color resource string."); + + maxComponentValue = (1 << componentBits) - 1; + + // Check the range of the components. + for (compI = 0; compI < componentCount; compI++) + { + if (comps[compI] < 0) + { + comps[compI] = 0; + log_add (log_Warning, "Color component value too small; " + "value clipped."); + } + + if (comps[compI] > (long) maxComponentValue) + { + comps[compI] = maxComponentValue; + log_add (log_Warning, "Color component value too large; " + "value clipped."); + } + } + + if (componentBits == 5) + resdata->num = ((CC5TO8 (comps[0]) << 24) | + (CC5TO8 (comps[1]) << 16) | (CC5TO8 (comps[2]) << 8) | + comps[3]); + else + resdata->num = ((comps[0] << 24) | (comps[1] << 16) | + (comps[2] << 8) | comps[3]); + + return; + +fail: + log_add (log_Error, "Invalid color description string for resource.\n"); + resdata->num = 0x00000000; +} + +static void +RawDescriptor (RESOURCE_DATA *resdata, char *buf, unsigned int size) +{ + snprintf (buf, size, "%s", resdata->str); +} + +static void +IntToString (RESOURCE_DATA *resdata, char *buf, unsigned int size) +{ + snprintf (buf, size, "%d", resdata->num); +} + + +static void +BooleanToString (RESOURCE_DATA *resdata, char *buf, unsigned int size) +{ + snprintf (buf, size, "%s", resdata->num ? "true" : "false"); +} + +static void +ColorToString (RESOURCE_DATA *resdata, char *buf, unsigned int size) +{ + if ((resdata->num & 0xff) == 0xff) + { + // Opaque color, save as "rgb". + snprintf (buf, size, "rgb(0x%02x, 0x%02x, 0x%02x)", + (resdata->num >> 24), (resdata->num >> 16) & 0xff, + (resdata->num >> 8) & 0xff); + } + else + { + // (Partially) transparent color, save as "rgba". + snprintf (buf, size, "rgba(0x%02x, 0x%02x, 0x%02x, 0x%02x)", + (resdata->num >> 24), (resdata->num >> 16) & 0xff, + (resdata->num >> 8) & 0xff, resdata->num & 0xff); + } +} + +static RESOURCE_INDEX curResourceIndex; + +void +_set_current_index_header (RESOURCE_INDEX newResourceIndex) +{ + curResourceIndex = newResourceIndex; +} + +RESOURCE_INDEX +InitResourceSystem (void) +{ + RESOURCE_INDEX ndx; + if (curResourceIndex) { + return curResourceIndex; + } + ndx = allocResourceIndex (); + + _set_current_index_header (ndx); + + InstallResTypeVectors ("UNKNOWNRES", UseDescriptorAsRes, NULL, NULL); + InstallResTypeVectors ("STRING", UseDescriptorAsRes, NULL, RawDescriptor); + InstallResTypeVectors ("INT32", DescriptorToInt, NULL, IntToString); + InstallResTypeVectors ("BOOLEAN", DescriptorToBoolean, NULL, + BooleanToString); + InstallResTypeVectors ("COLOR", DescriptorToColor, NULL, ColorToString); + InstallGraphicResTypes (); + InstallStringTableResType (); + InstallAudioResTypes (); + InstallVideoResType (); + InstallCodeResType (); + + return ndx; +} + +RESOURCE_INDEX +_get_current_index_header (void) +{ + if (!curResourceIndex) { + InitResourceSystem (); + } + return curResourceIndex; +} + +void +LoadResourceIndex (uio_DirHandle *dir, const char *rmpfile, const char *prefix) +{ + PropFile_from_filename (dir, rmpfile, process_resource_desc, prefix); +} + +void +SaveResourceIndex (uio_DirHandle *dir, const char *rmpfile, const char *root, BOOLEAN strip_root) +{ + uio_Stream *f; + CharHashTable_Iterator *it; + unsigned int prefix_len; + + f = res_OpenResFile (dir, rmpfile, "wb"); + if (!f) { + /* TODO: Warning message */ + return; + } + prefix_len = root ? strlen (root) : 0; + for (it = CharHashTable_getIterator (_get_current_index_header ()->map); + !CharHashTable_iteratorDone (it); + it = CharHashTable_iteratorNext (it)) { + char *key = CharHashTable_iteratorKey (it); + if (!root || !strncmp (root, key, prefix_len)) { + ResourceDesc *value = CharHashTable_iteratorValue (it); + if (!value) { + log_add(log_Warning, "Resource %s had no value", key); + } else if (!value->vtable) { + log_add(log_Warning, "Resource %s had no type", key); + } else if (value->vtable->toString) { + char buf[256]; + value->vtable->toString (&value->resdata, buf, 256); + buf[255]=0; + if (root && strip_root) { + WriteResFile (key+prefix_len, 1, strlen (key) - prefix_len, f); + } else { + WriteResFile (key, 1, strlen (key), f); + } + PutResFileChar(' ', f); + PutResFileChar('=', f); + PutResFileChar(' ', f); + WriteResFile (value->vtable->resType, 1, strlen (value->vtable->resType), f); + PutResFileChar(':', f); + WriteResFile (buf, 1, strlen (buf), f); + PutResFileNewline(f); + } + } + } + res_CloseResFile (f); + CharHashTable_freeIterator (it); +} + +void +UninitResourceSystem (void) +{ + freeResourceIndex (_get_current_index_header ()); + _set_current_index_header (NULL); +} + +BOOLEAN +InstallResTypeVectors (const char *resType, ResourceLoadFun *loadFun, + ResourceFreeFun *freeFun, ResourceStringFun *stringFun) +{ + ResourceHandlers *handlers; + ResourceDesc *result; + char key[TYPESIZ]; + int typelen; + CharHashTable_HashTable *map; + + snprintf(key, TYPESIZ, "sys.%s", resType); + key[TYPESIZ-1] = '\0'; + typelen = strlen(resType); + + handlers = HMalloc (sizeof (ResourceHandlers)); + if (handlers == NULL) + { + return FALSE; + } + handlers->loadFun = loadFun; + handlers->freeFun = freeFun; + handlers->toString = stringFun; + handlers->resType = resType; + + result = HMalloc (sizeof (ResourceDesc)); + if (result == NULL) + return FALSE; + + result->fname = HMalloc (strlen(resType) + 1); + strncpy (result->fname, resType, typelen); + result->fname[typelen] = '\0'; + result->vtable = NULL; + result->resdata.ptr = handlers; + + map = _get_current_index_header ()->map; + return CharHashTable_add (map, key, result) != 0; +} + +/* These replace the mapres.c calls and probably should be split out at some point. */ +BOOLEAN +res_IsString (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + return desc && !strcmp(desc->vtable->resType, "STRING"); +} + +const char * +res_GetString (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || !desc->resdata.str || strcmp(desc->vtable->resType, "STRING")) + return ""; + /* TODO: Work out exact STRING semantics, specifically, the lifetime of + * the returned value. If caller is allowed to reference the returned + * value forever, STRING has to be ref-counted. */ + return desc->resdata.str; +} + +void +res_PutString (const char *key, const char *value) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + int srclen, dstlen; + if (!desc || !desc->resdata.str || strcmp(desc->vtable->resType, "STRING")) + { + /* TODO: This is kind of roundabout. We can do better by refactoring newResourceDesc */ + process_resource_desc(key, "STRING:undefined"); + desc = lookupResourceDesc (idx, key); + } + srclen = strlen (value); + dstlen = strlen (desc->fname); + if (srclen > dstlen) { + char *newValue = HMalloc(srclen + 1); + char *oldValue = desc->fname; + log_add(log_Warning, "Reallocating string space for '%s'", key); + strncpy (newValue, value, srclen + 1); + desc->resdata.str = newValue; + desc->fname = newValue; + HFree (oldValue); + } else { + strncpy (desc->fname, value, dstlen + 1); + } +} + +BOOLEAN +res_IsInteger (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + return desc && !strcmp(desc->vtable->resType, "INT32"); +} + +int +res_GetInteger (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || strcmp(desc->vtable->resType, "INT32")) + { + // TODO: Better error handling + return 0; + } + return desc->resdata.num; +} + +void +res_PutInteger (const char *key, int value) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || strcmp(desc->vtable->resType, "INT32")) + { + /* TODO: This is kind of roundabout. We can do better by refactoring newResourceDesc */ + process_resource_desc(key, "INT32:0"); + desc = lookupResourceDesc (idx, key); + } + desc->resdata.num = value; +} + +BOOLEAN +res_IsBoolean (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + return desc && !strcmp(desc->vtable->resType, "BOOLEAN"); +} + +BOOLEAN +res_GetBoolean (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || strcmp(desc->vtable->resType, "BOOLEAN")) + { + // TODO: Better error handling + return FALSE; + } + return desc->resdata.num ? TRUE : FALSE; +} + +void +res_PutBoolean (const char *key, BOOLEAN value) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || strcmp(desc->vtable->resType, "BOOLEAN")) + { + /* TODO: This is kind of roundabout. We can do better by refactoring newResourceDesc */ + process_resource_desc(key, "BOOLEAN:false"); + desc = lookupResourceDesc (idx, key); + } + desc->resdata.num = value; +} + +BOOLEAN +res_IsColor (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + return desc && !strcmp(desc->vtable->resType, "COLOR"); +} + +Color +res_GetColor (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + DWORD num; + if (!desc || strcmp(desc->vtable->resType, "COLOR")) + { + // TODO: Better error handling + return buildColorRgba (0, 0, 0, 0); + } + + num = desc->resdata.num; + return buildColorRgba (num >> 24, (num >> 16) & 0xff, + (desc->resdata.num >> 8) & 0xff, num & 0xff); +} + +void +res_PutColor (const char *key, Color value) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + ResourceDesc *desc = lookupResourceDesc (idx, key); + if (!desc || strcmp(desc->vtable->resType, "COLOR")) + { + /* TODO: This is kind of roundabout. We can do better by refactoring + * newResourceDesc */ + process_resource_desc(key, "COLOR:rgb(0, 0, 0)"); + desc = lookupResourceDesc (idx, key); + } + desc->resdata.num = + (value.r << 24) | (value.g << 16) | (value.b << 8) | value.a; +} + +BOOLEAN +res_HasKey (const char *key) +{ + RESOURCE_INDEX idx = _get_current_index_header (); + return (lookupResourceDesc(idx, key) != NULL); +} + +BOOLEAN +res_Remove (const char *key) +{ + CharHashTable_HashTable *map = _get_current_index_header ()->map; + ResourceDesc *oldDesc = (ResourceDesc *)CharHashTable_find (map, key); + if (oldDesc != NULL) + { + if (oldDesc->resdata.ptr != NULL) + { + if (oldDesc->refcount > 0) + log_add (log_Warning, "WARNING: Replacing '%s' while it is live", key); + if (oldDesc->vtable && oldDesc->vtable->freeFun) + { + oldDesc->vtable->freeFun(oldDesc->resdata.ptr); + } + } + HFree (oldDesc->fname); + HFree (oldDesc); + } + return CharHashTable_remove (map, key); +} diff --git a/src/libs/resource/resintrn.h b/src/libs/resource/resintrn.h new file mode 100644 index 0000000..e2255ea --- /dev/null +++ b/src/libs/resource/resintrn.h @@ -0,0 +1,34 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef LIBS_RESOURCE_RESINTRN_H_ +#define LIBS_RESOURCE_RESINTRN_H_ + +#include <string.h> +#include "libs/reslib.h" +#include "index.h" + +ResourceDesc *lookupResourceDesc (RESOURCE_INDEX idx, RESOURCE res); +void loadResourceDesc (ResourceDesc *desc); + +void _set_current_index_header (RESOURCE_INDEX newResourceIndex); +RESOURCE_INDEX _get_current_index_header (void); + + +#endif /* LIBS_RESOURCE_RESINTRN_H_ */ + diff --git a/src/libs/resource/stringbank.c b/src/libs/resource/stringbank.c new file mode 100644 index 0000000..a1b9576 --- /dev/null +++ b/src/libs/resource/stringbank.c @@ -0,0 +1,181 @@ +/* stringbank.c, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "stringbank.h" + +typedef stringbank chunk; + +static stringbank * +add_chunk (stringbank *bank) +{ + stringbank *n = malloc (sizeof (stringbank)); + n->len = 0; + n->next = NULL; + if (bank) + { + while (bank->next) + bank = bank->next; + bank->next = n; + } + return n; +} + +stringbank * +StringBank_Create (void) +{ + return add_chunk (NULL); +} + +void +StringBank_Free (stringbank *bank) +{ + if (bank) + { + StringBank_Free (bank->next); + free (bank); + } +} + +const char * +StringBank_AddString (stringbank *bank, const char *str) +{ + unsigned int len = strlen (str) + 1; + stringbank *x = bank; + if (len > STRBANK_CHUNK_SIZE) + return NULL; + while (x) { + unsigned int remaining = STRBANK_CHUNK_SIZE - x->len; + if (len < remaining) { + char *result = x->data + x->len; + strcpy (result, str); + x->len += len; + return result; + } + x = x->next; + } + /* No room in any currently existing chunk */ + x = add_chunk (bank); + strcpy (x->data, str); + x->len += len; + return x->data; +} + +const char * +StringBank_AddOrFindString (stringbank *bank, const char *str) +{ + unsigned int len = strlen (str) + 1; + stringbank *x = bank; + if (len > STRBANK_CHUNK_SIZE) + return NULL; + while (x) { + int i = 0; + while (i < x->len) { + if (!strcmp (x->data + i, str)) + return x->data + i; + while (x->data[i]) i++; + i++; + } + x = x->next; + } + /* We didn't find it, so add it */ + return StringBank_AddString (bank, str); +} + +static char buffer[STRBANK_CHUNK_SIZE]; + +const char * +StringBank_AddSubstring (stringbank *bank, const char *str, unsigned int n) +{ + unsigned int len = strlen (str); + if (n > len) + { + return StringBank_AddString (bank, str); + } + if (n >= STRBANK_CHUNK_SIZE) + { + return NULL; + } + strncpy (buffer, str, n); + buffer[n] = '\0'; + return StringBank_AddString(bank, buffer); +} + +const char * +StringBank_AddOrFindSubstring (stringbank *bank, const char *str, unsigned int n) +{ + unsigned int len = strlen (str); + if (n > len) + { + return StringBank_AddOrFindString (bank, str); + } + if (n >= STRBANK_CHUNK_SIZE) + { + return NULL; + } + strncpy (buffer, str, n); + buffer[n] = '\0'; + return StringBank_AddOrFindString(bank, buffer); +} + +int +SplitString (const char *s, char splitchar, int n, const char **result, stringbank *bank) +{ + int i; + const char *index = s; + + for (i = 0; i < n-1; i++) + { + const char *next; + int len; + + next = strchr (index, splitchar); + if (!next) + { + break; + } + + len = next - index; + result[i] = StringBank_AddOrFindSubstring (bank, index, len); + index = next+1; + } + result[i] = StringBank_AddOrFindString (bank, index); + return i+1; +} + +#ifdef SB_DEBUG + +void +StringBank_Dump (stringbank *bank, FILE *s) +{ + stringbank *x = bank; + while (x) { + int i = 0; + while (i < x->len) { + fprintf (s, "\"%s\"\n", x->data + i); + while (x->data[i]) i++; + i++; + } + x = x->next; + } +} + +#endif diff --git a/src/libs/resource/stringbank.h b/src/libs/resource/stringbank.h new file mode 100644 index 0000000..e77105b --- /dev/null +++ b/src/libs/resource/stringbank.h @@ -0,0 +1,57 @@ +/* stringbank.h, Copyright (c) 2005 Michael C. Martin */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope thta it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Se 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. + */ + +#ifndef LIBS_RESOURCE_STRINGBANK_H_ +#define LIBS_RESOURCE_STRINGBANK_H_ + +#ifdef SB_DEBUG +#include <stdio.h> +#endif + +#define STRBANK_CHUNK_SIZE (1024 - sizeof (void *) - sizeof (int)) + +typedef struct _stringbank_chunk { + char data[STRBANK_CHUNK_SIZE]; + int len; + struct _stringbank_chunk *next; +} stringbank; + +/* Constructors and destructors */ +stringbank *StringBank_Create (void); +void StringBank_Free (stringbank *bank); + +/* Put str or n chars after str into the string bank. */ +const char *StringBank_AddString (stringbank *bank, const char *str); +const char *StringBank_AddSubstring (stringbank *bank, const char *str, unsigned int n); + +/* Put str or n chars after str into the string bank if it's not already + there. Much slower. */ +const char *StringBank_AddOrFindString (stringbank *bank, const char *str); +const char *StringBank_AddOrFindSubstring (stringbank *bank, const char *str, unsigned int n); + +/* Split a string s into at most n substrings, separated by splitchar. + Pointers to these substrings will be stored in result; the + substrings themselves will be filed in the specified stringbank. */ +int SplitString (const char *s, char splitchar, int n, const char **result, stringbank *bank); + +#ifdef SB_DEBUG +/* Print out a list of the contents of the string bank to the named stream. */ +void StringBank_Dump (stringbank *bank, FILE *s); +#endif /* SB_DEBUG */ + +#endif /* LIBS_RESOURCE_STRINGBANK_H_ */ |