ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Geo-LatLon2Place/cdb-embedded.c
Revision: 1.1
Committed: Mon Mar 14 22:48:05 2022 UTC (2 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 /* embeddable/static cdb version by schmorp */
2
3 /* cdb.h: public cdb include file
4 *
5 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
6 * Public domain.
7 */
8
9 #ifndef TINYCDB_VERSION
10 #define TINYCDB_VERSION 0.78
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 typedef unsigned int cdbi_t; /* compatibility */
17
18 /* common routines */
19 static unsigned cdb_hash(const void *buf, unsigned len);
20 static unsigned cdb_unpack(const unsigned char buf[4]);
21 static void cdb_pack(unsigned num, unsigned char buf[4]);
22
23 struct cdb {
24 int cdb_fd; /* file descriptor */
25 /* private members */
26 unsigned cdb_fsize; /* datafile size */
27 unsigned cdb_dend; /* end of data ptr */
28 const unsigned char *cdb_mem; /* mmap'ed file memory */
29 unsigned cdb_vpos, cdb_vlen; /* found data */
30 unsigned cdb_kpos, cdb_klen; /* found key */
31 };
32
33 #define CDB_STATIC_INIT {0,0,0,0,0,0,0,0}
34
35 #define cdb_datapos(c) ((c)->cdb_vpos)
36 #define cdb_datalen(c) ((c)->cdb_vlen)
37 #define cdb_keypos(c) ((c)->cdb_kpos)
38 #define cdb_keylen(c) ((c)->cdb_klen)
39 #define cdb_fileno(c) ((c)->cdb_fd)
40
41 static int cdb_init(struct cdb *cdbp, int fd);
42 static void cdb_free(struct cdb *cdbp);
43
44 static int cdb_read(const struct cdb *cdbp,
45 void *buf, unsigned len, unsigned pos);
46 #define cdb_readdata(cdbp, buf) \
47 cdb_read((cdbp), (buf), cdb_datalen(cdbp), cdb_datapos(cdbp))
48 #define cdb_readkey(cdbp, buf) \
49 cdb_read((cdbp), (buf), cdb_keylen(cdbp), cdb_keypos(cdbp))
50
51 static const void *cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos);
52 #define cdb_getdata(cdbp) \
53 cdb_get((cdbp), cdb_datalen(cdbp), cdb_datapos(cdbp))
54 #define cdb_getkey(cdbp) \
55 cdb_get((cdbp), cdb_keylen(cdbp), cdb_keypos(cdbp))
56
57 static int cdb_find(struct cdb *cdbp, const void *key, unsigned klen);
58
59 struct cdb_find {
60 struct cdb *cdb_cdbp;
61 unsigned cdb_hval;
62 const unsigned char *cdb_htp, *cdb_htab, *cdb_htend;
63 unsigned cdb_httodo;
64 const void *cdb_key;
65 unsigned cdb_klen;
66 };
67
68 static int cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
69 const void *key, unsigned klen);
70 static int cdb_findnext(struct cdb_find *cdbfp);
71
72 #define cdb_seqinit(cptr, cdbp) ((*(cptr))=2048)
73 static int cdb_seqnext(unsigned *cptr, struct cdb *cdbp);
74
75 /* old simple interface */
76 /* open file using standard routine, then: */
77 static int cdb_seek(int fd, const void *key, unsigned klen, unsigned *dlenp);
78 static int cdb_bread(int fd, void *buf, int len);
79
80 /* cdb_make */
81
82 struct cdb_make {
83 int cdb_fd; /* file descriptor */
84 /* private */
85 unsigned cdb_dpos; /* data position so far */
86 unsigned cdb_rcnt; /* record count so far */
87 unsigned char cdb_buf[4096]; /* write buffer */
88 unsigned char *cdb_bpos; /* current buf position */
89 struct cdb_rl *cdb_rec[256]; /* list of arrays of record infos */
90 };
91
92 enum cdb_put_mode {
93 CDB_PUT_ADD = 0, /* add unconditionnaly, like cdb_make_add() */
94 #define CDB_PUT_ADD CDB_PUT_ADD
95 CDB_FIND = CDB_PUT_ADD,
96 CDB_PUT_REPLACE, /* replace: do not place to index OLD record */
97 #define CDB_PUT_REPLACE CDB_PUT_REPLACE
98 CDB_FIND_REMOVE = CDB_PUT_REPLACE,
99 CDB_PUT_INSERT, /* add only if not already exists */
100 #define CDB_PUT_INSERT CDB_PUT_INSERT
101 CDB_PUT_WARN, /* add unconditionally but ret. 1 if exists */
102 #define CDB_PUT_WARN CDB_PUT_WARN
103 CDB_PUT_REPLACE0, /* if a record exists, fill old one with zeros */
104 #define CDB_PUT_REPLACE0 CDB_PUT_REPLACE0
105 CDB_FIND_FILL0 = CDB_PUT_REPLACE0
106 };
107
108 static int cdb_make_start(struct cdb_make *cdbmp, int fd);
109 static int cdb_make_add(struct cdb_make *cdbmp,
110 const void *key, unsigned klen,
111 const void *val, unsigned vlen);
112 static int cdb_make_exists(struct cdb_make *cdbmp,
113 const void *key, unsigned klen);
114 static int cdb_make_find(struct cdb_make *cdbmp,
115 const void *key, unsigned klen,
116 enum cdb_put_mode mode);
117 static int cdb_make_put(struct cdb_make *cdbmp,
118 const void *key, unsigned klen,
119 const void *val, unsigned vlen,
120 enum cdb_put_mode mode);
121 static int cdb_make_finish(struct cdb_make *cdbmp);
122
123 #ifdef __cplusplus
124 } /* extern "C" */
125 #endif
126
127 #endif /* include guard */
128
129 /* cdb_int.h: internal cdb library declarations
130 *
131 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
132 * Public domain.
133 */
134
135 #include <errno.h>
136 #include <string.h>
137
138 #ifndef EPROTO
139 # define EPROTO EINVAL
140 #endif
141
142 #define internal_function static
143
144 struct cdb_rec {
145 unsigned hval;
146 unsigned rpos;
147 };
148
149 struct cdb_rl {
150 struct cdb_rl *next;
151 unsigned cnt;
152 struct cdb_rec rec[254];
153 };
154
155 static int _cdb_make_write(struct cdb_make *cdbmp,
156 const unsigned char *ptr, unsigned len);
157 static int _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len);
158 static int _cdb_make_flush(struct cdb_make *cdbmp);
159 static int _cdb_make_add(struct cdb_make *cdbmp, unsigned hval,
160 const void *key, unsigned klen,
161 const void *val, unsigned vlen);
162 /* cdb_find.c: cdb_find routine
163 *
164 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
165 * Public domain.
166 */
167
168 static int
169 cdb_find(struct cdb *cdbp, const void *key, unsigned klen)
170 {
171 const unsigned char *htp; /* hash table pointer */
172 const unsigned char *htab; /* hash table */
173 const unsigned char *htend; /* end of hash table */
174 unsigned httodo; /* ht bytes left to look */
175 unsigned pos, n;
176
177 unsigned hval;
178
179 if (klen >= cdbp->cdb_dend) /* if key size is too large */
180 return 0;
181
182 hval = cdb_hash(key, klen);
183
184 /* find (pos,n) hash table to use */
185 /* first 2048 bytes (toc) are always available */
186 /* (hval % 256) * 8 */
187 htp = cdbp->cdb_mem + ((hval << 3) & 2047); /* index in toc (256x8) */
188 n = cdb_unpack(htp + 4); /* table size */
189 if (!n) /* empty table */
190 return 0; /* not found */
191 httodo = n << 3; /* bytes of htab to lookup */
192 pos = cdb_unpack(htp); /* htab position */
193 if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
194 || pos < cdbp->cdb_dend /* is htab inside data section ? */
195 || pos > cdbp->cdb_fsize /* htab start within file ? */
196 || httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
197 return errno = EPROTO, -1;
198
199 htab = cdbp->cdb_mem + pos; /* htab pointer */
200 htend = htab + httodo; /* after end of htab */
201 /* htab starting position: rest of hval modulo htsize, 8bytes per elt */
202 htp = htab + (((hval >> 8) % n) << 3);
203
204 for(;;) {
205 pos = cdb_unpack(htp + 4); /* record position */
206 if (!pos)
207 return 0;
208 if (cdb_unpack(htp) == hval) {
209 if (pos > cdbp->cdb_dend - 8) /* key+val lengths */
210 return errno = EPROTO, -1;
211 if (cdb_unpack(cdbp->cdb_mem + pos) == klen) {
212 if (cdbp->cdb_dend - klen < pos + 8)
213 return errno = EPROTO, -1;
214 if (memcmp(key, cdbp->cdb_mem + pos + 8, klen) == 0) {
215 n = cdb_unpack(cdbp->cdb_mem + pos + 4);
216 pos += 8;
217 if (cdbp->cdb_dend < n || cdbp->cdb_dend - n < pos + klen)
218 return errno = EPROTO, -1;
219 cdbp->cdb_kpos = pos;
220 cdbp->cdb_klen = klen;
221 cdbp->cdb_vpos = pos + klen;
222 cdbp->cdb_vlen = n;
223 return 1;
224 }
225 }
226 }
227 httodo -= 8;
228 if (!httodo)
229 return 0;
230 if ((htp += 8) >= htend)
231 htp = htab;
232 }
233
234 }
235
236 /* cdb_hash.c: cdb hashing routine
237 *
238 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
239 * Public domain.
240 */
241
242 static unsigned
243 cdb_hash(const void *buf, unsigned len)
244 {
245 register const unsigned char *p = (const unsigned char *)buf;
246 register const unsigned char *end = p + len;
247 register unsigned hash = 5381; /* start value */
248 while (p < end)
249 hash = (hash + (hash << 5)) ^ *p++;
250 return hash;
251 }
252
253 /* cdb_init.c: cdb_init, cdb_free and cdb_read routines
254 *
255 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
256 * Public domain.
257 */
258
259 #include <sys/types.h>
260 #ifdef _WIN32
261 # include <windows.h>
262 #else
263 # include <sys/mman.h>
264 # ifndef MAP_FAILED
265 # define MAP_FAILED ((void*)-1)
266 # endif
267 #endif
268 #include <sys/stat.h>
269
270 static int
271 cdb_init(struct cdb *cdbp, int fd)
272 {
273 struct stat st;
274 unsigned char *mem;
275 unsigned fsize, dend;
276 #ifdef _WIN32
277 HANDLE hFile, hMapping;
278 #endif
279
280 /* get file size */
281 if (fstat(fd, &st) < 0)
282 return -1;
283 /* trivial sanity check: at least toc should be here */
284 if (st.st_size < 2048)
285 return errno = EPROTO, -1;
286 fsize = st.st_size < 0xffffffffu ? st.st_size : 0xffffffffu;
287 /* memory-map file */
288 #ifdef _WIN32
289 hFile = (HANDLE) _get_osfhandle(fd);
290 if (hFile == (HANDLE) -1)
291 return -1;
292 hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
293 if (!hMapping)
294 return -1;
295 mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
296 CloseHandle(hMapping);
297 if (!mem)
298 return -1;
299 #else
300 mem = (unsigned char*)mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
301 if (mem == MAP_FAILED)
302 return -1;
303 #endif /* _WIN32 */
304
305 cdbp->cdb_fd = fd;
306 cdbp->cdb_fsize = fsize;
307 cdbp->cdb_mem = mem;
308
309 #if 0
310 /* XXX don't know well about madvise syscall -- is it legal
311 to set different options for parts of one mmap() region?
312 There is also posix_madvise() exist, with POSIX_MADV_RANDOM etc...
313 */
314 #ifdef MADV_RANDOM
315 /* set madvise() parameters. Ignore errors for now if system
316 doesn't support it */
317 madvise(mem, 2048, MADV_WILLNEED);
318 madvise(mem + 2048, cdbp->cdb_fsize - 2048, MADV_RANDOM);
319 #endif
320 #endif
321
322 cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
323 cdbp->cdb_kpos = cdbp->cdb_klen = 0;
324 dend = cdb_unpack(mem);
325 if (dend < 2048) dend = 2048;
326 else if (dend >= fsize) dend = fsize;
327 cdbp->cdb_dend = dend;
328
329 return 0;
330 }
331
332 static void
333 cdb_free(struct cdb *cdbp)
334 {
335 if (cdbp->cdb_mem) {
336 #ifdef _WIN32
337 UnmapViewOfFile((void*) cdbp->cdb_mem);
338 #else
339 munmap((void*)cdbp->cdb_mem, cdbp->cdb_fsize);
340 #endif /* _WIN32 */
341 cdbp->cdb_mem = NULL;
342 }
343 cdbp->cdb_fsize = 0;
344 }
345
346 static const void *
347 cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos)
348 {
349 if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) {
350 errno = EPROTO;
351 return NULL;
352 }
353 return cdbp->cdb_mem + pos;
354 }
355
356 static int
357 cdb_read(const struct cdb *cdbp, void *buf, unsigned len, unsigned pos)
358 {
359 const void *data = cdb_get(cdbp, len, pos);
360 if (!data) return -1;
361 memcpy(buf, data, len);
362 return 0;
363 }
364
365 /* cdb_make_add.c: basic cdb_make_add routine
366 *
367 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
368 * Public domain.
369 */
370
371 #include <stdlib.h> /* for malloc */
372
373 int internal_function
374 _cdb_make_add(struct cdb_make *cdbmp, unsigned hval,
375 const void *key, unsigned klen,
376 const void *val, unsigned vlen)
377 {
378 unsigned char rlen[8];
379 struct cdb_rl *rl;
380 unsigned i;
381 if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) ||
382 vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8))
383 return errno = ENOMEM, -1;
384 i = hval & 255;
385 rl = cdbmp->cdb_rec[i];
386 if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) {
387 rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl));
388 if (!rl)
389 return errno = ENOMEM, -1;
390 rl->cnt = 0;
391 rl->next = cdbmp->cdb_rec[i];
392 cdbmp->cdb_rec[i] = rl;
393 }
394 i = rl->cnt++;
395 rl->rec[i].hval = hval;
396 rl->rec[i].rpos = cdbmp->cdb_dpos;
397 ++cdbmp->cdb_rcnt;
398 cdb_pack(klen, rlen);
399 cdb_pack(vlen, rlen + 4);
400 if (_cdb_make_write(cdbmp, rlen, 8) < 0 ||
401 _cdb_make_write(cdbmp, key, klen) < 0 ||
402 _cdb_make_write(cdbmp, val, vlen) < 0)
403 return -1;
404 return 0;
405 }
406
407 static int
408 cdb_make_add(struct cdb_make *cdbmp,
409 const void *key, unsigned klen,
410 const void *val, unsigned vlen) {
411 return _cdb_make_add(cdbmp, cdb_hash(key, klen), key, klen, val, vlen);
412 }
413
414 /* cdb_unpack.c: unpack 32bit integer
415 *
416 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
417 * Public domain.
418 */
419
420 static inline unsigned
421 cdb_unpack(const unsigned char buf[4])
422 {
423 unsigned n = buf[3];
424 n <<= 8; n |= buf[2];
425 n <<= 8; n |= buf[1];
426 n <<= 8; n |= buf[0];
427 return n;
428 }
429
430 /* cdb_make.c: basic cdb creation routines
431 *
432 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
433 * Public domain.
434 */
435
436 #include <unistd.h>
437 #include <stdlib.h>
438 #include <string.h>
439
440 static inline void
441 cdb_pack(unsigned num, unsigned char buf[4])
442 {
443 buf[0] = num & 255; num >>= 8;
444 buf[1] = num & 255; num >>= 8;
445 buf[2] = num & 255;
446 buf[3] = num >> 8;
447 }
448
449 static int
450 cdb_make_start(struct cdb_make *cdbmp, int fd)
451 {
452 memset(cdbmp, 0, sizeof(*cdbmp));
453 cdbmp->cdb_fd = fd;
454 cdbmp->cdb_dpos = 2048;
455 cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048;
456 return 0;
457 }
458
459 int internal_function
460 _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len)
461 {
462 while(len) {
463 int l = write(fd, buf, len);
464 if (l > 0) {
465 len -= l;
466 buf += l;
467 }
468 else if (l < 0 && errno != EINTR)
469 return -1;
470 }
471 return 0;
472 }
473
474 int internal_function
475 _cdb_make_flush(struct cdb_make *cdbmp) {
476 unsigned len = cdbmp->cdb_bpos - cdbmp->cdb_buf;
477 if (len) {
478 if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, len) < 0)
479 return -1;
480 cdbmp->cdb_bpos = cdbmp->cdb_buf;
481 }
482 return 0;
483 }
484
485 int internal_function
486 _cdb_make_write(struct cdb_make *cdbmp, const unsigned char *ptr, unsigned len)
487 {
488 unsigned l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf);
489 cdbmp->cdb_dpos += len;
490 if (len > l) {
491 memcpy(cdbmp->cdb_bpos, ptr, l);
492 cdbmp->cdb_bpos += l;
493 if (_cdb_make_flush(cdbmp) < 0)
494 return -1;
495 ptr += l; len -= l;
496 l = len / sizeof(cdbmp->cdb_buf);
497 if (l) {
498 l *= sizeof(cdbmp->cdb_buf);
499 if (_cdb_make_fullwrite(cdbmp->cdb_fd, ptr, l) < 0)
500 return -1;
501 ptr += l; len -= l;
502 }
503 }
504 if (len) {
505 memcpy(cdbmp->cdb_bpos, ptr, len);
506 cdbmp->cdb_bpos += len;
507 }
508 return 0;
509 }
510
511 static int
512 cdb_make_finish_internal(struct cdb_make *cdbmp)
513 {
514 unsigned hcnt[256]; /* hash table counts */
515 unsigned hpos[256]; /* hash table positions */
516 struct cdb_rec *htab;
517 unsigned char *p;
518 struct cdb_rl *rl;
519 unsigned hsize;
520 unsigned t, i;
521
522 if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt)
523 return errno = ENOMEM, -1;
524
525 /* count htab sizes and reorder reclists */
526 hsize = 0;
527 for (t = 0; t < 256; ++t) {
528 struct cdb_rl *rlt = NULL;
529 i = 0;
530 rl = cdbmp->cdb_rec[t];
531 while(rl) {
532 struct cdb_rl *rln = rl->next;
533 rl->next = rlt;
534 rlt = rl;
535 i += rl->cnt;
536 rl = rln;
537 }
538 cdbmp->cdb_rec[t] = rlt;
539 if (hsize < (hcnt[t] = i << 1))
540 hsize = hcnt[t];
541 }
542
543 /* allocate memory to hold max htable */
544 htab = (struct cdb_rec*)malloc((hsize + 2) * sizeof(struct cdb_rec));
545 if (!htab)
546 return errno = ENOENT, -1;
547 p = (unsigned char *)htab;
548 htab += 2;
549
550 /* build hash tables */
551 for (t = 0; t < 256; ++t) {
552 unsigned len, hi;
553 hpos[t] = cdbmp->cdb_dpos;
554 if ((len = hcnt[t]) == 0)
555 continue;
556 for (i = 0; i < len; ++i)
557 htab[i].hval = htab[i].rpos = 0;
558 for (rl = cdbmp->cdb_rec[t]; rl; rl = rl->next)
559 for (i = 0; i < rl->cnt; ++i) {
560 hi = (rl->rec[i].hval >> 8) % len;
561 while(htab[hi].rpos)
562 if (++hi == len)
563 hi = 0;
564 htab[hi] = rl->rec[i];
565 }
566 for (i = 0; i < len; ++i) {
567 cdb_pack(htab[i].hval, p + (i << 3));
568 cdb_pack(htab[i].rpos, p + (i << 3) + 4);
569 }
570 if (_cdb_make_write(cdbmp, p, len << 3) < 0) {
571 free(p);
572 return -1;
573 }
574 }
575 free(p);
576 if (_cdb_make_flush(cdbmp) < 0)
577 return -1;
578 p = cdbmp->cdb_buf;
579 for (t = 0; t < 256; ++t) {
580 cdb_pack(hpos[t], p + (t << 3));
581 cdb_pack(hcnt[t], p + (t << 3) + 4);
582 }
583 if (lseek(cdbmp->cdb_fd, 0, 0) != 0 ||
584 _cdb_make_fullwrite(cdbmp->cdb_fd, p, 2048) != 0)
585 return -1;
586
587 return 0;
588 }
589
590 static void
591 cdb_make_free(struct cdb_make *cdbmp)
592 {
593 unsigned t;
594 for(t = 0; t < 256; ++t) {
595 struct cdb_rl *rl = cdbmp->cdb_rec[t];
596 while(rl) {
597 struct cdb_rl *tm = rl;
598 rl = rl->next;
599 free(tm);
600 }
601 }
602 }
603
604 static int
605 cdb_make_finish(struct cdb_make *cdbmp)
606 {
607 int r = cdb_make_finish_internal(cdbmp);
608 cdb_make_free(cdbmp);
609 return r;
610 }
611