]> git.ipfire.org Git - people/ms/libloc.git/blobdiff - src/stringpool.c
network: Add function to return a reverse pointer for networks
[people/ms/libloc.git] / src / stringpool.c
index cbb1fb7af5117f9c22cde038eb6fa14902fee8dd..9986a619485f83f10961cde304c21b4a6e6e3412 100644 (file)
 #include <sys/mman.h>
 #include <unistd.h>
 
-#include <loc/libloc.h>
-#include <loc/format.h>
-#include "libloc-private.h"
-#include "stringpool.h"
-
-enum loc_stringpool_mode {
-       STRINGPOOL_DEFAULT,
-       STRINGPOOL_MMAP,
-};
+#include <libloc/libloc.h>
+#include <libloc/format.h>
+#include <libloc/private.h>
+#include <libloc/stringpool.h>
+
+#define LOC_STRINGPOOL_BLOCK_SIZE      (512 * 1024)
 
 struct loc_stringpool {
        struct loc_ctx* ctx;
        int refcount;
 
-       enum loc_stringpool_mode mode;
-
-       char* data;
+       // Reference to any mapped data
+       const char* data;
        ssize_t length;
 
-       char* pos;
+       // Reference to own storage
+       char* blocks;
+       size_t size;
 };
 
-static int __loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool, enum loc_stringpool_mode mode) {
-       struct loc_stringpool* p = calloc(1, sizeof(*p));
-       if (!p)
-               return -ENOMEM;
+static int loc_stringpool_grow(struct loc_stringpool* pool, const size_t size) {
+       DEBUG(pool->ctx, "Growing string pool by %zu byte(s)\n", size);
 
-       p->ctx = loc_ref(ctx);
-       p->refcount = 1;
+       // Increment size
+       pool->size += size;
 
-       // Save mode
-       p->mode = mode;
+       // Reallocate blocks
+       pool->blocks = realloc(pool->blocks, pool->size);
+       if (!pool->blocks) {
+               ERROR(pool->ctx, "Could not grow string pool: %m\n");
+               return 1;
+       }
 
-       *pool = p;
+       // Update data pointer
+       pool->data = pool->blocks;
 
        return 0;
 }
 
-LOC_EXPORT int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
-       return __loc_stringpool_new(ctx, pool, STRINGPOOL_DEFAULT);
+static off_t loc_stringpool_append(struct loc_stringpool* pool, const char* string) {
+       if (!string) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       DEBUG(pool->ctx, "Appending '%s' to string pool at %p\n", string, pool);
+
+       // How much space to we need?
+       const size_t length = strlen(string) + 1;
+
+       // Make sure we have enough space
+       if (pool->length + length > pool->size) {
+               int r = loc_stringpool_grow(pool, LOC_STRINGPOOL_BLOCK_SIZE);
+               if (r)
+                       return r;
+       }
+
+       off_t offset = pool->length;
+
+       // Copy the string
+       memcpy(pool->blocks + offset, string, length);
+
+       // Update the length of the pool
+       pool->length += length;
+
+       return offset;
 }
 
-static int loc_stringpool_mmap(struct loc_stringpool* pool, FILE* f, size_t length, off_t offset) {
-       if (pool->mode != STRINGPOOL_MMAP)
-               return -EINVAL;
+static void loc_stringpool_free(struct loc_stringpool* pool) {
+       DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
 
-       DEBUG(pool->ctx, "Reading string pool starting from %zu (%zu bytes)\n", offset, length);
+       // Free any data
+       if (pool->blocks)
+               free(pool->blocks);
 
-       // Map file content into memory
-       pool->data = pool->pos = mmap(NULL, length, PROT_READ,
-               MAP_PRIVATE, fileno(f), offset);
+       loc_unref(pool->ctx);
+       free(pool);
+}
 
-       // Store size of section
-       pool->length = length;
+int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
+       struct loc_stringpool* p = calloc(1, sizeof(*p));
+       if (!p)
+               return 1;
 
-       if (pool->data == MAP_FAILED)
-               return -errno;
+       p->ctx = loc_ref(ctx);
+       p->refcount = 1;
+
+       *pool = p;
 
        return 0;
 }
 
-LOC_EXPORT int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
-               FILE* f, size_t length, off_t offset) {
-       int r = __loc_stringpool_new(ctx, pool, STRINGPOOL_MMAP);
-       if (r)
-               return r;
+int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
+               const char* data, const size_t length) {
+       struct loc_stringpool* p = NULL;
 
-       // Map data into memory
-       r = loc_stringpool_mmap(*pool, f, length, offset);
+       // Allocate a new stringpool
+       int r = loc_stringpool_new(ctx, &p);
        if (r)
-               return r;
+               goto ERROR;
+
+       // Store data and length
+       p->data   = data;
+       p->length = length;
+
+       DEBUG(p->ctx, "Opened string pool at %p (%zu bytes)\n", p->data, p->length);
 
+       *pool = p;
        return 0;
-}
 
-LOC_EXPORT struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool) {
-       pool->refcount++;
+ERROR:
+       if (p)
+               loc_stringpool_free(p);
 
-       return pool;
+       return r;
 }
 
-static void loc_stringpool_free(struct loc_stringpool* pool) {
-       DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
-       int r;
-
-       switch (pool->mode) {
-               case STRINGPOOL_DEFAULT:
-                       if (pool->data)
-                               free(pool->data);
-                       break;
-
-               case STRINGPOOL_MMAP:
-                       if (pool->data) {
-                               r = munmap(pool->data, pool->length);
-                               if (r)
-                                       ERROR(pool->ctx, "Could not unmap data at %p: %s\n",
-                                               pool->data, strerror(errno));
-                       }
-                       break;
-       }
+struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool) {
+       pool->refcount++;
 
-       loc_unref(pool->ctx);
-       free(pool);
+       return pool;
 }
 
-LOC_EXPORT struct loc_stringpool* loc_stringpool_unref(struct loc_stringpool* pool) {
+struct loc_stringpool* loc_stringpool_unref(struct loc_stringpool* pool) {
        if (--pool->refcount > 0)
                return NULL;
 
@@ -136,126 +154,74 @@ LOC_EXPORT struct loc_stringpool* loc_stringpool_unref(struct loc_stringpool* po
        return NULL;
 }
 
-static off_t loc_stringpool_get_offset(struct loc_stringpool* pool, const char* pos) {
-       if (pos < pool->data)
-               return -EFAULT;
-
-       if (pos > (pool->data + pool->length))
-               return -EFAULT;
-
-       return pos - pool->data;
-}
-
-static off_t loc_stringpool_get_next_offset(struct loc_stringpool* pool, off_t offset) {
-       const char* string = loc_stringpool_get(pool, offset);
-
-       return offset + strlen(string) + 1;
-}
-
-static char* __loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
-       if (offset < 0 || offset >= pool->length)
+const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
+       // Check boundaries
+       if (offset < 0 || offset >= pool->length) {
+               errno = ERANGE;
                return NULL;
+       }
 
+       // Return any data that we have in memory
        return pool->data + offset;
 }
 
-LOC_EXPORT const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
-       return __loc_stringpool_get(pool, offset);
-}
-
-LOC_EXPORT size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
-       return loc_stringpool_get_offset(pool, pool->pos);
+size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
+       return pool->length;
 }
 
 static off_t loc_stringpool_find(struct loc_stringpool* pool, const char* s) {
-       if (!s || !*s)
-               return -EINVAL;
+       if (!s || !*s) {
+               errno = EINVAL;
+               return -1;
+       }
 
        off_t offset = 0;
        while (offset < pool->length) {
                const char* string = loc_stringpool_get(pool, offset);
+
+               // Error!
                if (!string)
-                       break;
+                       return 1;
 
-               int r = strcmp(s, string);
-               if (r == 0)
+               // Is this a match?
+               if (strcmp(s, string) == 0)
                        return offset;
 
-               offset = loc_stringpool_get_next_offset(pool, offset);
+               // Shift offset
+               offset += strlen(string) + 1;
        }
 
-       return -ENOENT;
-}
-
-static int loc_stringpool_grow(struct loc_stringpool* pool, size_t length) {
-       DEBUG(pool->ctx, "Growing string pool to %zu bytes\n", length);
-
-       // Save pos pointer
-       off_t pos = loc_stringpool_get_offset(pool, pool->pos);
-
-       // Reallocate data section
-       pool->data = realloc(pool->data, length);
-       if (!pool->data)
-               return -ENOMEM;
-
-       pool->length = length;
-
-       // Restore pos
-       pool->pos = __loc_stringpool_get(pool, pos);
-
-       return 0;
-}
-
-static off_t loc_stringpool_append(struct loc_stringpool* pool, const char* string) {
-       if (!string || !*string)
-               return -EINVAL;
-
-       DEBUG(pool->ctx, "Appending '%s' to string pool at %p\n", string, pool);
-
-       // Make sure we have enough space
-       int r = loc_stringpool_grow(pool, pool->length + strlen(string) + 1);
-       if (r) {
-               errno = r;
-               return -1;
-       }
-
-       off_t offset = loc_stringpool_get_offset(pool, pool->pos);
-
-       // Copy string byte by byte
-       while (*string)
-               *pool->pos++ = *string++;
-
-       // Terminate the string
-       *pool->pos++ = '\0';
-
-       return offset;
+       // Nothing found
+       errno = ENOENT;
+       return -1;
 }
 
-LOC_EXPORT off_t loc_stringpool_add(struct loc_stringpool* pool, const char* string) {
+off_t loc_stringpool_add(struct loc_stringpool* pool, const char* string) {
        off_t offset = loc_stringpool_find(pool, string);
        if (offset >= 0) {
-               DEBUG(pool->ctx, "Found '%s' at position %jd\n", string, offset);
+               DEBUG(pool->ctx, "Found '%s' at position %jd\n", string, (intmax_t)offset);
                return offset;
        }
 
        return loc_stringpool_append(pool, string);
 }
 
-LOC_EXPORT void loc_stringpool_dump(struct loc_stringpool* pool) {
+void loc_stringpool_dump(struct loc_stringpool* pool) {
        off_t offset = 0;
 
        while (offset < pool->length) {
                const char* string = loc_stringpool_get(pool, offset);
                if (!string)
-                       break;
+                       return;
 
-               printf("%jd (%zu): %s\n", offset, strlen(string), string);
+               printf("%jd (%zu): %s\n", (intmax_t)offset, strlen(string), string);
 
-               offset = loc_stringpool_get_next_offset(pool, offset);
+               // Shift offset
+               offset += strlen(string) + 1;
        }
 }
 
-LOC_EXPORT size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
+size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
        size_t size = loc_stringpool_get_size(pool);
 
        return fwrite(pool->data, sizeof(*pool->data), size, f);