aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/preproc/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/preproc/util.c')
-rw-r--r--src/interfaces/ecpg/preproc/util.c119
1 files changed, 97 insertions, 22 deletions
diff --git a/src/interfaces/ecpg/preproc/util.c b/src/interfaces/ecpg/preproc/util.c
index cb1eca7f3cb..f177df32488 100644
--- a/src/interfaces/ecpg/preproc/util.c
+++ b/src/interfaces/ecpg/preproc/util.c
@@ -104,33 +104,117 @@ mm_strdup(const char *string)
return new;
}
+
/*
- * String concatenation
+ * "Local" memory management support
+ *
+ * These functions manage memory that is only needed for a short time
+ * (processing of one input statement) within the ecpg grammar.
+ * Data allocated with these is not meant to be freed separately;
+ * rather it's freed by calling reclaim_local_storage() at the end
+ * of each statement cycle.
*/
+typedef struct loc_chunk
+{
+ struct loc_chunk *next; /* list link */
+ unsigned int chunk_used; /* index of first unused byte in data[] */
+ unsigned int chunk_avail; /* # bytes still available in data[] */
+ char data[FLEXIBLE_ARRAY_MEMBER]; /* actual storage */
+} loc_chunk;
+
+#define LOC_CHUNK_OVERHEAD MAXALIGN(offsetof(loc_chunk, data))
+#define LOC_CHUNK_MIN_SIZE 8192
+
+/* Head of list of loc_chunks */
+static loc_chunk *loc_chunks = NULL;
+
/*
- * Concatenate 2 strings, inserting a space between them unless either is empty
+ * Allocate local space of the requested size.
*
- * The input strings are freed.
+ * Exits on OOM.
+ */
+void *
+loc_alloc(size_t size)
+{
+ void *result;
+ loc_chunk *cur_chunk = loc_chunks;
+
+ /* Ensure all allocations are adequately aligned */
+ size = MAXALIGN(size);
+
+ /* Need a new chunk? */
+ if (cur_chunk == NULL || size > cur_chunk->chunk_avail)
+ {
+ size_t chunk_size = Max(size, LOC_CHUNK_MIN_SIZE);
+
+ cur_chunk = mm_alloc(chunk_size + LOC_CHUNK_OVERHEAD);
+ /* Depending on alignment rules, we could waste a bit here */
+ cur_chunk->chunk_used = LOC_CHUNK_OVERHEAD - offsetof(loc_chunk, data);
+ cur_chunk->chunk_avail = chunk_size;
+ /* New chunk becomes the head of the list */
+ cur_chunk->next = loc_chunks;
+ loc_chunks = cur_chunk;
+ }
+
+ result = cur_chunk->data + cur_chunk->chunk_used;
+ cur_chunk->chunk_used += size;
+ cur_chunk->chunk_avail -= size;
+ return result;
+}
+
+/*
+ * Copy given string into local storage
+ */
+char *
+loc_strdup(const char *string)
+{
+ char *result = loc_alloc(strlen(string) + 1);
+
+ strcpy(result, string);
+ return result;
+}
+
+/*
+ * Reclaim local storage when appropriate
+ */
+void
+reclaim_local_storage(void)
+{
+ loc_chunk *cur_chunk,
+ *next_chunk;
+
+ for (cur_chunk = loc_chunks; cur_chunk; cur_chunk = next_chunk)
+ {
+ next_chunk = cur_chunk->next;
+ free(cur_chunk);
+ }
+ loc_chunks = NULL;
+}
+
+
+/*
+ * String concatenation support routines. These return "local" (transient)
+ * storage.
+ */
+
+/*
+ * Concatenate 2 strings, inserting a space between them unless either is empty
*/
char *
-cat2_str(char *str1, char *str2)
+cat2_str(const char *str1, const char *str2)
{
- char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 2);
+ char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 2);
strcpy(res_str, str1);
if (strlen(str1) != 0 && strlen(str2) != 0)
strcat(res_str, " ");
strcat(res_str, str2);
- free(str1);
- free(str2);
return res_str;
}
/*
* Concatenate N strings, inserting spaces between them unless they are empty
- *
- * The input strings are freed.
*/
char *
cat_str(int count,...)
@@ -154,36 +238,27 @@ cat_str(int count,...)
/*
* Concatenate 2 strings, with no space between
- *
- * The input strings are freed.
*/
char *
-make2_str(char *str1, char *str2)
+make2_str(const char *str1, const char *str2)
{
- char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 1);
+ char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 1);
strcpy(res_str, str1);
strcat(res_str, str2);
- free(str1);
- free(str2);
return res_str;
}
/*
* Concatenate 3 strings, with no space between
- *
- * The input strings are freed.
*/
char *
-make3_str(char *str1, char *str2, char *str3)
+make3_str(const char *str1, const char *str2, const char *str3)
{
- char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
+ char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
strcpy(res_str, str1);
strcat(res_str, str2);
strcat(res_str, str3);
- free(str1);
- free(str2);
- free(str3);
return res_str;
}