summaryrefslogtreecommitdiffstats
path: root/libtecla-1.6.3/stringrp.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@oarcorp.com>2015-05-27 13:48:33 -0700
committerJoel Sherrill <joel.sherrill@oarcorp.com>2015-05-27 13:48:33 -0700
commite96199c670ce672049d7f009bd03258649352fc5 (patch)
treee5f30408253b02c04b349c262d8d9fddfed76d25 /libtecla-1.6.3/stringrp.c
parentAdd libtecla 1.6.3 (diff)
downloadrtems-addon-packages-e96199c670ce672049d7f009bd03258649352fc5.tar.bz2
Rename libtecla to a versioned directory (1.6.3)
Diffstat (limited to 'libtecla-1.6.3/stringrp.c')
-rw-r--r--libtecla-1.6.3/stringrp.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/libtecla-1.6.3/stringrp.c b/libtecla-1.6.3/stringrp.c
new file mode 100644
index 0000000..de7369a
--- /dev/null
+++ b/libtecla-1.6.3/stringrp.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2012 by Martin C. Shepherd.
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "freelist.h"
+#include "stringrp.h"
+
+/*
+ * StringSegment objects store lots of small strings in larger
+ * character arrays. Since the total length of all of the strings can't
+ * be known in advance, an extensible list of large character arrays,
+ * called string-segments are used.
+ */
+typedef struct StringSegment StringSegment;
+struct StringSegment {
+ StringSegment *next; /* A pointer to the next segment in the list */
+ char *block; /* An array of characters to be shared between strings */
+ int unused; /* The amount of unused space at the end of block[] */
+};
+
+/*
+ * StringGroup is typedef'd in stringrp.h.
+ */
+struct StringGroup {
+ FreeList *node_mem; /* The StringSegment free-list */
+ int block_size; /* The dimension of each character array block */
+ StringSegment *head; /* The list of character arrays */
+};
+
+/*
+ * Specify how many StringSegment's to allocate at a time.
+ */
+#define STR_SEG_BLK 20
+
+/*.......................................................................
+ * Create a new StringGroup object.
+ *
+ * Input:
+ * segment_size int The length of each of the large character
+ * arrays in which multiple strings will be
+ * stored. This sets the length of longest
+ * string that can be stored, and for efficiency
+ * should be at least 10 times as large as
+ * the average string that will be stored.
+ * Output:
+ * return StringGroup * The new object, or NULL on error.
+ */
+StringGroup *_new_StringGroup(int segment_size)
+{
+ StringGroup *sg; /* The object to be returned */
+/*
+ * Check the arguments.
+ */
+ if(segment_size < 1) {
+ errno = EINVAL;
+ return NULL;
+ };
+/*
+ * Allocate the container.
+ */
+ sg = (StringGroup *) malloc(sizeof(StringGroup));
+ if(!sg) {
+ errno = ENOMEM;
+ return NULL;
+ };
+/*
+ * Before attempting any operation that might fail, initialize the
+ * container at least up to the point at which it can safely be passed
+ * to _del_StringGroup().
+ */
+ sg->node_mem = NULL;
+ sg->head = NULL;
+ sg->block_size = segment_size;
+/*
+ * Allocate the free list that is used to allocate list nodes.
+ */
+ sg->node_mem = _new_FreeList(sizeof(StringSegment), STR_SEG_BLK);
+ if(!sg->node_mem)
+ return _del_StringGroup(sg);
+ return sg;
+}
+
+/*.......................................................................
+ * Delete a StringGroup object.
+ *
+ * Input:
+ * sg StringGroup * The object to be deleted.
+ * Output:
+ * return StringGroup * The deleted object (always NULL).
+ */
+StringGroup *_del_StringGroup(StringGroup *sg)
+{
+ if(sg) {
+ StringSegment *node;
+/*
+ * Delete the character arrays.
+ */
+ for(node=sg->head; node; node=node->next) {
+ if(node->block)
+ free(node->block);
+ node->block = NULL;
+ };
+/*
+ * Delete the list nodes that contained the string segments.
+ */
+ sg->node_mem = _del_FreeList(sg->node_mem, 1);
+ sg->head = NULL; /* Already deleted by deleting sg->node_mem */
+/*
+ * Delete the container.
+ */
+ free(sg);
+ };
+ return NULL;
+}
+
+/*.......................................................................
+ * Make a copy of a string in the specified string group, and return
+ * a pointer to the copy.
+ *
+ * Input:
+ * sg StringGroup * The group to store the string in.
+ * string const char * The string to be recorded.
+ * remove_escapes int If true, omit backslashes which escape
+ * other characters when making the copy.
+ * Output:
+ * return char * The pointer to the copy of the string,
+ * or NULL if there was insufficient memory.
+ */
+char *_sg_store_string(StringGroup *sg, const char *string, int remove_escapes)
+{
+ char *copy; /* The recorded copy of string[] */
+/*
+ * Check the arguments.
+ */
+ if(!sg || !string)
+ return NULL;
+/*
+ * Get memory for the string.
+ */
+ copy = _sg_alloc_string(sg, strlen(string));
+ if(copy) {
+/*
+ * If needed, remove backslash escapes while copying the input string
+ * into the cache string.
+ */
+ if(remove_escapes) {
+ int escaped = 0; /* True if the next character should be */
+ /* escaped. */
+ const char *src = string; /* A pointer into the input string */
+ char *dst = copy; /* A pointer into the cached copy of the */
+ /* string. */
+ while(*src) {
+ if(!escaped && *src == '\\') {
+ escaped = 1;
+ src++;
+ } else {
+ escaped = 0;
+ *dst++ = *src++;
+ };
+ };
+ *dst = '\0';
+/*
+ * If escapes have already been removed, copy the input string directly
+ * into the cache.
+ */
+ } else {
+ strcpy(copy, string);
+ };
+ };
+/*
+ * Return a pointer to the copy of the string (or NULL if the allocation
+ * failed).
+ */
+ return copy;
+}
+
+/*.......................................................................
+ * Allocate memory for a string of a given length.
+ *
+ * Input:
+ * sg StringGroup * The group to store the string in.
+ * length int The required length of the string.
+ * Output:
+ * return char * The pointer to the copy of the string,
+ * or NULL if there was insufficient memory.
+ */
+char *_sg_alloc_string(StringGroup *sg, int length)
+{
+ StringSegment *node; /* A node of the list of string segments */
+ char *copy; /* The allocated string */
+/*
+ * If the string is longer than block_size, then we can't record it.
+ */
+ if(length > sg->block_size || length < 0)
+ return NULL;
+/*
+ * See if there is room to record the string in one of the existing
+ * string segments. Do this by advancing the node pointer until we find
+ * a node with length+1 bytes unused, or we get to the end of the list.
+ */
+ for(node=sg->head; node && node->unused <= length; node=node->next)
+ ;
+/*
+ * If there wasn't room, allocate a new string segment.
+ */
+ if(!node) {
+ node = (StringSegment *) _new_FreeListNode(sg->node_mem);
+ if(!node)
+ return NULL;
+/*
+ * Initialize the segment.
+ */
+ node->next = NULL;
+ node->block = NULL;
+ node->unused = sg->block_size;
+/*
+ * Attempt to allocate the string segment character array.
+ */
+ node->block = (char *) malloc(sg->block_size);
+ if(!node->block)
+ return NULL;
+/*
+ * Prepend the node to the list.
+ */
+ node->next = sg->head;
+ sg->head = node;
+ };
+/*
+ * Get memory for the string.
+ */
+ copy = node->block + sg->block_size - node->unused;
+ node->unused -= length + 1;
+/*
+ * Return a pointer to the string memory.
+ */
+ return copy;
+}
+
+/*.......................................................................
+ * Delete all of the strings that are currently stored by a specified
+ * StringGroup object.
+ *
+ * Input:
+ * sg StringGroup * The group of strings to clear.
+ */
+void _clr_StringGroup(StringGroup *sg)
+{
+ StringSegment *node; /* A node in the list of string segments */
+/*
+ * Mark all of the string segments as unoccupied.
+ */
+ for(node=sg->head; node; node=node->next)
+ node->unused = sg->block_size;
+ return;
+}