]> git.ipfire.org Git - people/ms/libloc.git/blame - src/stringpool.c
importer: Drop EDROP as it has been merged into DROP
[people/ms/libloc.git] / src / stringpool.c
CommitLineData
62b83e6d
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stddef.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
6809d5ac
MT
22#include <sys/mman.h>
23#include <unistd.h>
62b83e6d 24
c12a1385
MT
25#include <libloc/libloc.h>
26#include <libloc/format.h>
27#include <libloc/private.h>
28#include <libloc/stringpool.h>
62b83e6d 29
975f280f
MT
30#define LOC_STRINGPOOL_BLOCK_SIZE (512 * 1024)
31
62b83e6d
MT
32struct loc_stringpool {
33 struct loc_ctx* ctx;
62b83e6d 34 int refcount;
0e974d4b 35
975f280f
MT
36 // Reference to any mapped data
37 const char* data;
0e974d4b 38 ssize_t length;
62b83e6d 39
975f280f
MT
40 // Reference to own storage
41 char* blocks;
42 size_t size;
62b83e6d
MT
43};
44
975f280f
MT
45static int loc_stringpool_grow(struct loc_stringpool* pool, const size_t size) {
46 DEBUG(pool->ctx, "Growing string pool by %zu byte(s)\n", size);
010fe9b6 47
975f280f
MT
48 // Increment size
49 pool->size += size;
e4b6ca42 50
975f280f
MT
51 // Reallocate blocks
52 pool->blocks = realloc(pool->blocks, pool->size);
53 if (!pool->blocks) {
54 ERROR(pool->ctx, "Could not grow string pool: %m\n");
198e382c 55 return 1;
975f280f 56 }
010fe9b6 57
975f280f
MT
58 // Update data pointer
59 pool->data = pool->blocks;
010fe9b6
MT
60
61 return 0;
62}
63
64static off_t loc_stringpool_append(struct loc_stringpool* pool, const char* string) {
198e382c
MT
65 if (!string) {
66 errno = EINVAL;
67 return -1;
68 }
010fe9b6
MT
69
70 DEBUG(pool->ctx, "Appending '%s' to string pool at %p\n", string, pool);
71
975f280f
MT
72 // How much space to we need?
73 const size_t length = strlen(string) + 1;
74
010fe9b6 75 // Make sure we have enough space
975f280f
MT
76 if (pool->length + length > pool->size) {
77 int r = loc_stringpool_grow(pool, LOC_STRINGPOOL_BLOCK_SIZE);
78 if (r)
79 return r;
80 }
010fe9b6 81
975f280f 82 off_t offset = pool->length;
010fe9b6 83
975f280f
MT
84 // Copy the string
85 memcpy(pool->blocks + offset, string, length);
010fe9b6 86
975f280f
MT
87 // Update the length of the pool
88 pool->length += length;
010fe9b6
MT
89
90 return offset;
91}
92
acf44a73
MT
93static void loc_stringpool_free(struct loc_stringpool* pool) {
94 DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
acf44a73 95
e4b6ca42 96 // Free any data
975f280f
MT
97 if (pool->blocks)
98 free(pool->blocks);
e4b6ca42 99
acf44a73
MT
100 loc_unref(pool->ctx);
101 free(pool);
102}
103
22d8abdc 104int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
0e974d4b
MT
105 struct loc_stringpool* p = calloc(1, sizeof(*p));
106 if (!p)
8d10d064 107 return 1;
0e974d4b
MT
108
109 p->ctx = loc_ref(ctx);
110 p->refcount = 1;
6809d5ac 111
0e974d4b 112 *pool = p;
6809d5ac
MT
113
114 return 0;
115}
116
22d8abdc 117int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
975f280f 118 const char* data, const size_t length) {
acf44a73
MT
119 struct loc_stringpool* p = NULL;
120
121 // Allocate a new stringpool
122 int r = loc_stringpool_new(ctx, &p);
0e974d4b 123 if (r)
e4b6ca42
MT
124 goto ERROR;
125
975f280f
MT
126 // Store data and length
127 p->data = data;
e4b6ca42
MT
128 p->length = length;
129
975f280f 130 DEBUG(p->ctx, "Opened string pool at %p (%zu bytes)\n", p->data, p->length);
62b83e6d 131
acf44a73 132 *pool = p;
62b83e6d 133 return 0;
e4b6ca42
MT
134
135ERROR:
136 if (p)
137 loc_stringpool_free(p);
138
139 return r;
62b83e6d
MT
140}
141
22d8abdc 142struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool) {
62b83e6d
MT
143 pool->refcount++;
144
145 return pool;
146}
147
22d8abdc 148struct loc_stringpool* loc_stringpool_unref(struct loc_stringpool* pool) {
62b83e6d
MT
149 if (--pool->refcount > 0)
150 return NULL;
151
152 loc_stringpool_free(pool);
153
154 return NULL;
155}
156
22d8abdc 157const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
975f280f
MT
158 // Check boundaries
159 if (offset < 0 || offset >= pool->length) {
160 errno = ERANGE;
161 return NULL;
162 }
163
164 // Return any data that we have in memory
165 return pool->data + offset;
62b83e6d
MT
166}
167
22d8abdc 168size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
975f280f 169 return pool->length;
2601e83e
MT
170}
171
62b83e6d 172static off_t loc_stringpool_find(struct loc_stringpool* pool, const char* s) {
198e382c
MT
173 if (!s || !*s) {
174 errno = EINVAL;
175 return -1;
176 }
62b83e6d
MT
177
178 off_t offset = 0;
0e974d4b 179 while (offset < pool->length) {
62b83e6d 180 const char* string = loc_stringpool_get(pool, offset);
21dfa79e
MT
181
182 // Error!
62b83e6d 183 if (!string)
21dfa79e 184 return 1;
62b83e6d 185
21dfa79e
MT
186 // Is this a match?
187 if (strcmp(s, string) == 0)
62b83e6d
MT
188 return offset;
189
21dfa79e
MT
190 // Shift offset
191 offset += strlen(string) + 1;
62b83e6d
MT
192 }
193
198e382c
MT
194 // Nothing found
195 errno = ENOENT;
196 return -1;
62b83e6d
MT
197}
198
22d8abdc 199off_t loc_stringpool_add(struct loc_stringpool* pool, const char* string) {
62b83e6d
MT
200 off_t offset = loc_stringpool_find(pool, string);
201 if (offset >= 0) {
5c57de03 202 DEBUG(pool->ctx, "Found '%s' at position %jd\n", string, (intmax_t)offset);
62b83e6d
MT
203 return offset;
204 }
205
206 return loc_stringpool_append(pool, string);
207}
208
22d8abdc 209void loc_stringpool_dump(struct loc_stringpool* pool) {
62b83e6d
MT
210 off_t offset = 0;
211
0e974d4b 212 while (offset < pool->length) {
62b83e6d
MT
213 const char* string = loc_stringpool_get(pool, offset);
214 if (!string)
21dfa79e 215 return;
62b83e6d 216
5c57de03 217 printf("%jd (%zu): %s\n", (intmax_t)offset, strlen(string), string);
62b83e6d 218
21dfa79e
MT
219 // Shift offset
220 offset += strlen(string) + 1;
62b83e6d
MT
221 }
222}
2601e83e 223
22d8abdc 224size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
2601e83e
MT
225 size_t size = loc_stringpool_get_size(pool);
226
8f5b676a 227 return fwrite(pool->data, sizeof(*pool->data), size, f);
2601e83e 228}