]>
git.ipfire.org Git - location/libloc.git/blob - src/stringpool.c
2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
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.
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.
25 #include <loc/libloc.h>
26 #include <loc/format.h>
27 #include <loc/private.h>
28 #include <loc/stringpool.h>
30 enum loc_stringpool_mode
{
35 struct loc_stringpool
{
39 enum loc_stringpool_mode mode
;
47 static off_t
loc_stringpool_get_offset(struct loc_stringpool
* pool
, const char* pos
) {
51 if (pos
> (pool
->data
+ pool
->length
))
54 return pos
- pool
->data
;
57 static char* __loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
58 if (offset
< 0 || offset
>= pool
->length
)
61 return pool
->data
+ offset
;
64 static int loc_stringpool_grow(struct loc_stringpool
* pool
, size_t length
) {
65 DEBUG(pool
->ctx
, "Growing string pool to %zu bytes\n", length
);
68 off_t pos
= loc_stringpool_get_offset(pool
, pool
->pos
);
70 // Reallocate data section
71 pool
->data
= realloc(pool
->data
, length
);
75 pool
->length
= length
;
78 pool
->pos
= __loc_stringpool_get(pool
, pos
);
83 static off_t
loc_stringpool_append(struct loc_stringpool
* pool
, const char* string
) {
84 if (!string
|| !*string
)
87 DEBUG(pool
->ctx
, "Appending '%s' to string pool at %p\n", string
, pool
);
89 // Make sure we have enough space
90 int r
= loc_stringpool_grow(pool
, pool
->length
+ strlen(string
) + 1);
96 off_t offset
= loc_stringpool_get_offset(pool
, pool
->pos
);
98 // Copy string byte by byte
100 *pool
->pos
++ = *string
++;
102 // Terminate the string
108 static int __loc_stringpool_new(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
, enum loc_stringpool_mode mode
) {
109 struct loc_stringpool
* p
= calloc(1, sizeof(*p
));
113 p
->ctx
= loc_ref(ctx
);
124 LOC_EXPORT
int loc_stringpool_new(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
) {
125 int r
= __loc_stringpool_new(ctx
, pool
, STRINGPOOL_DEFAULT
);
129 // Add an empty string to new string pools
130 loc_stringpool_append(*pool
, "");
135 static int loc_stringpool_mmap(struct loc_stringpool
* pool
, FILE* f
, size_t length
, off_t offset
) {
136 if (pool
->mode
!= STRINGPOOL_MMAP
)
139 DEBUG(pool
->ctx
, "Reading string pool starting from %jd (%zu bytes)\n", (intmax_t)offset
, length
);
141 // Map file content into memory
142 pool
->data
= pool
->pos
= mmap(NULL
, length
, PROT_READ
,
143 MAP_PRIVATE
, fileno(f
), offset
);
145 // Store size of section
146 pool
->length
= length
;
148 if (pool
->data
== MAP_FAILED
)
154 LOC_EXPORT
int loc_stringpool_open(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
,
155 FILE* f
, size_t length
, off_t offset
) {
156 int r
= __loc_stringpool_new(ctx
, pool
, STRINGPOOL_MMAP
);
160 // Map data into memory
162 r
= loc_stringpool_mmap(*pool
, f
, length
, offset
);
170 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_ref(struct loc_stringpool
* pool
) {
176 static void loc_stringpool_free(struct loc_stringpool
* pool
) {
177 DEBUG(pool
->ctx
, "Releasing string pool %p\n", pool
);
180 switch (pool
->mode
) {
181 case STRINGPOOL_DEFAULT
:
186 case STRINGPOOL_MMAP
:
188 r
= munmap(pool
->data
, pool
->length
);
190 ERROR(pool
->ctx
, "Could not unmap data at %p: %s\n",
191 pool
->data
, strerror(errno
));
196 loc_unref(pool
->ctx
);
200 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_unref(struct loc_stringpool
* pool
) {
201 if (--pool
->refcount
> 0)
204 loc_stringpool_free(pool
);
209 static off_t
loc_stringpool_get_next_offset(struct loc_stringpool
* pool
, off_t offset
) {
210 const char* string
= loc_stringpool_get(pool
, offset
);
212 return offset
+ strlen(string
) + 1;
215 LOC_EXPORT
const char* loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
216 return __loc_stringpool_get(pool
, offset
);
219 LOC_EXPORT
size_t loc_stringpool_get_size(struct loc_stringpool
* pool
) {
220 return loc_stringpool_get_offset(pool
, pool
->pos
);
223 static off_t
loc_stringpool_find(struct loc_stringpool
* pool
, const char* s
) {
228 while (offset
< pool
->length
) {
229 const char* string
= loc_stringpool_get(pool
, offset
);
233 int r
= strcmp(s
, string
);
237 offset
= loc_stringpool_get_next_offset(pool
, offset
);
243 LOC_EXPORT off_t
loc_stringpool_add(struct loc_stringpool
* pool
, const char* string
) {
244 off_t offset
= loc_stringpool_find(pool
, string
);
246 DEBUG(pool
->ctx
, "Found '%s' at position %jd\n", string
, (intmax_t)offset
);
250 return loc_stringpool_append(pool
, string
);
253 LOC_EXPORT
void loc_stringpool_dump(struct loc_stringpool
* pool
) {
256 while (offset
< pool
->length
) {
257 const char* string
= loc_stringpool_get(pool
, offset
);
261 printf("%jd (%zu): %s\n", (intmax_t)offset
, strlen(string
), string
);
263 offset
= loc_stringpool_get_next_offset(pool
, offset
);
267 LOC_EXPORT
size_t loc_stringpool_write(struct loc_stringpool
* pool
, FILE* f
) {
268 size_t size
= loc_stringpool_get_size(pool
);
270 return fwrite(pool
->data
, sizeof(*pool
->data
), size
, f
);