]>
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 "libloc-private.h"
27 #include "stringpool.h"
29 struct loc_stringpool
{
39 static int loc_stringpool_deallocate(struct loc_stringpool
* pool
) {
41 int r
= munmap(pool
->data
, pool
->max_length
);
43 ERROR(pool
->ctx
, "Could not unmap data at %p: %s\n",
44 pool
->data
, strerror(errno
));
53 static int loc_stringpool_allocate(struct loc_stringpool
* pool
, size_t length
) {
55 int r
= loc_stringpool_deallocate(pool
);
59 pool
->max_length
= length
;
62 while (pool
->max_length
% sysconf(_SC_PAGE_SIZE
) > 0)
65 DEBUG(pool
->ctx
, "Allocating pool of %zu bytes\n", pool
->max_length
);
67 // Allocate some memory
68 pool
->data
= pool
->pos
= mmap(NULL
, pool
->max_length
,
69 PROT_READ
|PROT_WRITE
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
71 if (pool
->data
== MAP_FAILED
) {
72 DEBUG(pool
->ctx
, "%s\n", strerror(errno
));
76 DEBUG(pool
->ctx
, "Allocated pool at %p\n", pool
->data
);
81 LOC_EXPORT
int loc_stringpool_new(struct loc_ctx
* ctx
, struct loc_stringpool
** pool
, size_t max_length
) {
82 struct loc_stringpool
* p
= calloc(1, sizeof(*p
));
86 p
->ctx
= loc_ref(ctx
);
89 // Allocate the data section
91 int r
= loc_stringpool_allocate(p
, max_length
);
93 loc_stringpool_unref(p
);
98 DEBUG(p
->ctx
, "String pool allocated at %p\n", p
);
99 DEBUG(p
->ctx
, " Maximum size: %zu bytes\n", p
->max_length
);
105 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_ref(struct loc_stringpool
* pool
) {
111 static void loc_stringpool_free(struct loc_stringpool
* pool
) {
112 DEBUG(pool
->ctx
, "Releasing string pool %p\n", pool
);
114 loc_stringpool_deallocate(pool
);
115 loc_unref(pool
->ctx
);
119 LOC_EXPORT
struct loc_stringpool
* loc_stringpool_unref(struct loc_stringpool
* pool
) {
120 if (--pool
->refcount
> 0)
123 loc_stringpool_free(pool
);
128 static off_t
loc_stringpool_get_offset(struct loc_stringpool
* pool
, const char* pos
) {
129 if (pos
< pool
->data
)
132 if (pos
> (pool
->data
+ pool
->max_length
))
135 return pos
- pool
->data
;
138 static off_t
loc_stringpool_get_next_offset(struct loc_stringpool
* pool
, off_t offset
) {
139 const char* string
= loc_stringpool_get(pool
, offset
);
141 return offset
+ strlen(string
) + 1;
144 static size_t loc_stringpool_space_left(struct loc_stringpool
* pool
) {
145 return pool
->max_length
- loc_stringpool_get_size(pool
);
148 LOC_EXPORT
const char* loc_stringpool_get(struct loc_stringpool
* pool
, off_t offset
) {
149 if (offset
>= (ssize_t
)pool
->max_length
)
152 const char* string
= pool
->data
+ offset
;
154 // If the string is empty, we have reached the end
161 LOC_EXPORT
size_t loc_stringpool_get_size(struct loc_stringpool
* pool
) {
162 return loc_stringpool_get_offset(pool
, pool
->pos
);
165 static off_t
loc_stringpool_find(struct loc_stringpool
* pool
, const char* s
) {
170 while (offset
< pool
->max_length
) {
171 const char* string
= loc_stringpool_get(pool
, offset
);
175 int r
= strcmp(s
, string
);
179 offset
= loc_stringpool_get_next_offset(pool
, offset
);
185 static off_t
loc_stringpool_append(struct loc_stringpool
* pool
, const char* string
) {
186 if (!string
|| !*string
)
189 DEBUG(pool
->ctx
, "Appending '%s' to string pool at %p\n", string
, pool
);
191 // Check if we have enough space left
192 size_t l
= strlen(string
) + 1;
193 if (l
> loc_stringpool_space_left(pool
)) {
194 DEBUG(pool
->ctx
, "Not enough space to append '%s'\n", string
);
195 DEBUG(pool
->ctx
, " Need %zu bytes but only have %zu\n", l
, loc_stringpool_space_left(pool
));
199 off_t offset
= loc_stringpool_get_offset(pool
, pool
->pos
);
201 // Copy string byte by byte
202 while (*string
&& loc_stringpool_space_left(pool
) > 1) {
203 *pool
->pos
++ = *string
++;
206 // Terminate the string
212 LOC_EXPORT off_t
loc_stringpool_add(struct loc_stringpool
* pool
, const char* string
) {
213 off_t offset
= loc_stringpool_find(pool
, string
);
215 DEBUG(pool
->ctx
, "Found '%s' at position %jd\n", string
, offset
);
219 return loc_stringpool_append(pool
, string
);
222 LOC_EXPORT
void loc_stringpool_dump(struct loc_stringpool
* pool
) {
225 while (offset
< pool
->max_length
) {
226 const char* string
= loc_stringpool_get(pool
, offset
);
230 printf("%jd (%zu): %s\n", offset
, strlen(string
), string
);
232 offset
= loc_stringpool_get_next_offset(pool
, offset
);
238 LOC_EXPORT
int loc_stringpool_read(struct loc_stringpool
* pool
, FILE* f
, off_t offset
, size_t length
) {
239 DEBUG(pool
->ctx
, "Reading string pool from %zu (%zu bytes)\n", offset
, length
);
241 pool
->data
= pool
->pos
= mmap(NULL
, length
, PROT_READ
,
242 MAP_PRIVATE
, fileno(f
), offset
);
243 pool
->max_length
= length
;
245 if (pool
->data
== MAP_FAILED
)
251 LOC_EXPORT
size_t loc_stringpool_write(struct loc_stringpool
* pool
, FILE* f
) {
252 size_t size
= loc_stringpool_get_size(pool
);
254 return fwrite(pool
->data
, sizeof(*pool
->data
), size
, f
);