]>
git.ipfire.org Git - people/ms/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 "libloc-private.h"
28 #include "stringpool.h"
30 struct loc_stringpool
{
40 static int loc_stringpool_deallocate(struct loc_stringpool
* pool
) {
42 int r
= munmap(pool
->data
, pool
->max_length
);
44 ERROR(pool
->ctx
, "Could not unmap data at %p: %s\n",
45 pool
->data
, strerror(errno
));
54 static int loc_stringpool_allocate(struct loc_stringpool
* pool
, size_t length
) {
56 int r
= loc_stringpool_deallocate(pool
);
60 pool
->max_length
= length
;
63 while (pool
->max_length
% sysconf(_SC_PAGE_SIZE
) > 0)
66 DEBUG(pool
->ctx
, "Allocating pool of %zu bytes\n", pool
->max_length
);
68 // Allocate some memory
69 pool
->data
= pool
->pos
= mmap(NULL
, pool
->max_length
,
70 PROT_READ
|PROT_WRITE
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
72 if (pool
->data
== MAP_FAILED
) {
73 DEBUG(pool
->ctx
, "%s\n", strerror(errno
));
77 DEBUG(pool
->ctx
, "Allocated pool at %p\n", pool
->data
);
82 LOC_EXPORT
int loc_stringpool_new(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
, size_t max_length
) {
83 struct loc_stringpool
* p
= calloc(1, sizeof(*p
));
87 p
->ctx
= loc_ref(ctx
);
90 // Allocate the data section
92 int r
= loc_stringpool_allocate(p
, max_length
);
94 loc_stringpool_unref(p
);
99 DEBUG(p
->ctx
, "String pool allocated at %p\n", p
);
100 DEBUG(p
->ctx
, " Maximum size: %zu bytes\n", p
->max_length
);
106 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_ref(struct loc_stringpool
* pool
) {
112 static void loc_stringpool_free(struct loc_stringpool
* pool
) {
113 DEBUG(pool
->ctx
, "Releasing string pool %p\n", pool
);
115 loc_stringpool_deallocate(pool
);
116 loc_unref(pool
->ctx
);
120 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_unref(struct loc_stringpool
* pool
) {
121 if (--pool
->refcount
> 0)
124 loc_stringpool_free(pool
);
129 static off_t
loc_stringpool_get_offset(struct loc_stringpool
* pool
, const char* pos
) {
130 if (pos
< pool
->data
)
133 if (pos
> (pool
->data
+ pool
->max_length
))
136 return pos
- pool
->data
;
139 static off_t
loc_stringpool_get_next_offset(struct loc_stringpool
* pool
, off_t offset
) {
140 const char* string
= loc_stringpool_get(pool
, offset
);
142 return offset
+ strlen(string
) + 1;
145 static size_t loc_stringpool_space_left(struct loc_stringpool
* pool
) {
146 return pool
->max_length
- loc_stringpool_get_size(pool
);
149 LOC_EXPORT
const char* loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
150 if (offset
>= (ssize_t
)pool
->max_length
)
153 const char* string
= pool
->data
+ offset
;
155 // If the string is empty, we have reached the end
162 LOC_EXPORT
size_t loc_stringpool_get_size(struct loc_stringpool
* pool
) {
163 return loc_stringpool_get_offset(pool
, pool
->pos
);
166 static off_t
loc_stringpool_find(struct loc_stringpool
* pool
, const char* s
) {
171 while (offset
< pool
->max_length
) {
172 const char* string
= loc_stringpool_get(pool
, offset
);
176 int r
= strcmp(s
, string
);
180 offset
= loc_stringpool_get_next_offset(pool
, offset
);
186 static off_t
loc_stringpool_append(struct loc_stringpool
* pool
, const char* string
) {
187 if (!string
|| !*string
)
190 DEBUG(pool
->ctx
, "Appending '%s' to string pool at %p\n", string
, pool
);
192 // Check if we have enough space left
193 size_t l
= strlen(string
) + 1;
194 if (l
> loc_stringpool_space_left(pool
)) {
195 DEBUG(pool
->ctx
, "Not enough space to append '%s'\n", string
);
196 DEBUG(pool
->ctx
, " Need %zu bytes but only have %zu\n", l
, loc_stringpool_space_left(pool
));
200 off_t offset
= loc_stringpool_get_offset(pool
, pool
->pos
);
202 // Copy string byte by byte
203 while (*string
&& loc_stringpool_space_left(pool
) > 1) {
204 *pool
->pos
++ = *string
++;
207 // Terminate the string
213 LOC_EXPORT off_t
loc_stringpool_add(struct loc_stringpool
* pool
, const char* string
) {
214 off_t offset
= loc_stringpool_find(pool
, string
);
216 DEBUG(pool
->ctx
, "Found '%s' at position %jd\n", string
, offset
);
220 return loc_stringpool_append(pool
, string
);
223 LOC_EXPORT
void loc_stringpool_dump(struct loc_stringpool
* pool
) {
226 while (offset
< pool
->max_length
) {
227 const char* string
= loc_stringpool_get(pool
, offset
);
231 printf("%jd (%zu): %s\n", offset
, strlen(string
), string
);
233 offset
= loc_stringpool_get_next_offset(pool
, offset
);
237 LOC_EXPORT
int loc_stringpool_read(struct loc_stringpool
* pool
, FILE* f
, off_t offset
, size_t length
) {
238 DEBUG(pool
->ctx
, "Reading string pool from %zu (%zu bytes)\n", offset
, length
);
240 pool
->data
= pool
->pos
= mmap(NULL
, length
, PROT_READ
,
241 MAP_PRIVATE
, fileno(f
), offset
);
242 pool
->max_length
= length
;
244 if (pool
->data
== MAP_FAILED
)
250 LOC_EXPORT
size_t loc_stringpool_write(struct loc_stringpool
* pool
, FILE* f
) {
251 size_t size
= loc_stringpool_get_size(pool
);
253 return fwrite(pool
->data
, sizeof(*pool
->data
), size
, f
);