sdbm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 61716e1eab009e59d62ba6e6b41a5cf680e8d727
4
+ data.tar.gz: e812e9941b62ae4387e5be14a8719a6798caa166
5
+ SHA512:
6
+ metadata.gz: 6fd74cd6cab2313e01874652def5447ec872df28cdb367ab75bed2ad5196004196cec332f926972bbd8ddf7839be80eb845876f852bfaf7b48d34b49817a3185
7
+ data.tar.gz: a35d46a90ed779440de431a5669f9d570cac13e05aaa4e01171029f57c56c2694aca5cdbac981a49006548cb07f55507cd00526b45e6cd2eb627aada88ad8c73
@@ -0,0 +1,952 @@
1
+ /*
2
+ * sdbm - ndbm work-alike hashed database library
3
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
4
+ * author: oz@nexus.yorku.ca
5
+ * status: public domain.
6
+ *
7
+ * core routines
8
+ */
9
+
10
+ #include "ruby/ruby.h"
11
+
12
+ #ifdef HAVE_UNISTD_H
13
+ #include <unistd.h>
14
+ #endif
15
+
16
+ #include "sdbm.h"
17
+
18
+ /*
19
+ * sdbm - ndbm work-alike hashed database library
20
+ * tuning and portability constructs [not nearly enough]
21
+ * author: oz@nexus.yorku.ca
22
+ */
23
+
24
+ #define BYTESIZ 8
25
+
26
+ #ifdef BSD42
27
+ #define SEEK_SET L_SET
28
+ #define memset(s,c,n) bzero((s), (n)) /* only when c is zero */
29
+ #define memcpy(s1,s2,n) bcopy((s2), (s1), (n))
30
+ #define memcmp(s1,s2,n) bcmp((s1),(s2),(n))
31
+ #endif
32
+
33
+ /*
34
+ * important tuning parms (hah)
35
+ */
36
+
37
+ #ifndef SEEDUPS
38
+ #define SEEDUPS 1 /* always detect duplicates */
39
+ #endif
40
+ #ifndef BADMESS
41
+ #define BADMESS 1 /* generate a message for worst case:
42
+ cannot make room after SPLTMAX splits */
43
+ #endif
44
+
45
+ /*
46
+ * misc
47
+ */
48
+ #ifdef DEBUG
49
+ #define debug(x) printf x
50
+ #else
51
+ #define debug(x)
52
+ #endif
53
+
54
+ #ifdef BIG_E
55
+ #define GET_SHORT(p, i) (((unsigned)((unsigned char *)(p))[(i)*2] << 8) + (((unsigned char *)(p))[(i)*2 + 1]))
56
+ #define PUT_SHORT(p, i, s) (((unsigned char *)(p))[(i)*2] = (unsigned char)((s) >> 8), ((unsigned char *)(p))[(i)*2 + 1] = (unsigned char)(s))
57
+ #else
58
+ #define GET_SHORT(p, i) ((p)[(i)])
59
+ #define PUT_SHORT(p, i, s) ((p)[(i)] = (s))
60
+ #endif
61
+
62
+ /*#include "pair.h"*/
63
+ static int fitpair proto((char *, int));
64
+ static void putpair proto((char *, datum, datum));
65
+ static datum getpair proto((char *, datum));
66
+ static int delpair proto((char *, datum));
67
+ static int chkpage proto((char *));
68
+ static datum getnkey proto((char *, int));
69
+ static void splpage proto((char *, char *, long));
70
+ #if SEEDUPS
71
+ static int duppair proto((char *, datum));
72
+ #endif
73
+
74
+ #include <stdio.h>
75
+ #include <stdlib.h>
76
+ #ifdef DOSISH
77
+ #include <io.h>
78
+ #endif
79
+ #include <sys/types.h>
80
+ #include <sys/stat.h>
81
+ #ifdef BSD42
82
+ #include <sys/file.h>
83
+ #else
84
+ #include <fcntl.h>
85
+ /*#include <memory.h>*/
86
+ #endif
87
+ #ifndef O_BINARY
88
+ #define O_BINARY 0
89
+ #endif
90
+
91
+ #include <errno.h>
92
+ #ifndef EPERM
93
+ #define EPERM EACCES
94
+ #endif
95
+ #include <string.h>
96
+
97
+ #ifdef __STDC__
98
+ #include <stddef.h>
99
+ #endif
100
+
101
+ #ifndef NULL
102
+ #define NULL 0
103
+ #endif
104
+
105
+ /*
106
+ * externals
107
+ */
108
+ #if !defined(__sun) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(errno)
109
+ extern int errno;
110
+ #endif
111
+
112
+ /*
113
+ * forward
114
+ */
115
+ static int getdbit proto((DBM *, long));
116
+ static int setdbit proto((DBM *, long));
117
+ static int getpage proto((DBM *, long));
118
+ static datum getnext proto((DBM *));
119
+ static int makroom proto((DBM *, long, int));
120
+
121
+ /*
122
+ * useful macros
123
+ */
124
+ #define bad(x) ((x).dptr == NULL || (x).dsize < 0)
125
+ #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
126
+ #define ioerr(db) ((db)->flags |= DBM_IOERR)
127
+
128
+ #define OFF_PAG(off) (long) (off) * PBLKSIZ
129
+ #define OFF_DIR(off) (long) (off) * DBLKSIZ
130
+
131
+ static long masks[] = {
132
+ 000000000000L, 000000000001L, 000000000003L,
133
+ 000000000007L, 000000000017L, 000000000037L,
134
+ 000000000077L, 000000000177L, 000000000377L,
135
+ 000000000777L, 000000001777L, 000000003777L,
136
+ 000000007777L, 000000017777L, 000000037777L,
137
+ 000000077777L, 000000177777L, 000000377777L,
138
+ 000000777777L, 000001777777L, 000003777777L,
139
+ 000007777777L, 000017777777L, 000037777777L,
140
+ 000077777777L, 000177777777L, 000377777777L,
141
+ 000777777777L, 001777777777L, 003777777777L,
142
+ 007777777777L, 017777777777L
143
+ };
144
+
145
+ datum nullitem = {NULL, 0};
146
+
147
+ DBM *
148
+ sdbm_open(register char *file, register int flags, register int mode)
149
+ {
150
+ register DBM *db;
151
+ register char *dirname;
152
+ register char *pagname;
153
+ register size_t n;
154
+
155
+ if (file == NULL || !*file)
156
+ return errno = EINVAL, (DBM *) NULL;
157
+ /*
158
+ * need space for two separate filenames
159
+ */
160
+ n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2;
161
+
162
+ if ((dirname = malloc(n)) == NULL)
163
+ return errno = ENOMEM, (DBM *) NULL;
164
+ /*
165
+ * build the file names
166
+ */
167
+ dirname = strcat(strcpy(dirname, file), DIRFEXT);
168
+ pagname = strcpy(dirname + strlen(dirname) + 1, file);
169
+ pagname = strcat(pagname, PAGFEXT);
170
+
171
+ db = sdbm_prep(dirname, pagname, flags, mode);
172
+ free((char *) dirname);
173
+ return db;
174
+ }
175
+
176
+ static int
177
+ fd_set_cloexec(int fd)
178
+ {
179
+ /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
180
+ #ifdef F_GETFD
181
+ int flags, ret;
182
+ flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
183
+ if (flags == -1) {
184
+ return -1;
185
+ }
186
+ if (2 < fd) {
187
+ if (!(flags & FD_CLOEXEC)) {
188
+ flags |= FD_CLOEXEC;
189
+ ret = fcntl(fd, F_SETFD, flags);
190
+ if (ret == -1) {
191
+ return -1;
192
+ }
193
+ }
194
+ }
195
+ #endif
196
+ return 0;
197
+ }
198
+
199
+ DBM *
200
+ sdbm_prep(char *dirname, char *pagname, int flags, int mode)
201
+ {
202
+ register DBM *db;
203
+ struct stat dstat;
204
+
205
+ if ((db = (DBM *) malloc(sizeof(DBM))) == NULL)
206
+ return errno = ENOMEM, (DBM *) NULL;
207
+
208
+ db->pagf = -1;
209
+ db->dirf = -1;
210
+ db->flags = 0;
211
+ db->hmask = 0;
212
+ db->blkptr = 0;
213
+ db->keyptr = 0;
214
+ /*
215
+ * adjust user flags so that WRONLY becomes RDWR,
216
+ * as required by this package. Also set our internal
217
+ * flag for RDONLY.
218
+ */
219
+ if (flags & O_WRONLY)
220
+ flags = (flags & ~O_WRONLY) | O_RDWR;
221
+ if (flags & O_RDONLY)
222
+ db->flags = DBM_RDONLY;
223
+ /*
224
+ * open the files in sequence, and stat the dirfile.
225
+ * If we fail anywhere, undo everything, return NULL.
226
+ */
227
+ flags |= O_BINARY;
228
+ #ifdef O_CLOEXEC
229
+ flags |= O_CLOEXEC;
230
+ #endif
231
+
232
+ if ((db->pagf = open(pagname, flags, mode)) == -1) goto err;
233
+ if (fd_set_cloexec(db->pagf) == -1) goto err;
234
+ if ((db->dirf = open(dirname, flags, mode)) == -1) goto err;
235
+ if (fd_set_cloexec(db->dirf) == -1) goto err;
236
+ /*
237
+ * need the dirfile size to establish max bit number.
238
+ */
239
+ if (fstat(db->dirf, &dstat) == -1) goto err;
240
+ /*
241
+ * zero size: either a fresh database, or one with a single,
242
+ * unsplit data page: dirpage is all zeros.
243
+ */
244
+ db->dirbno = (!dstat.st_size) ? 0 : -1;
245
+ db->pagbno = -1;
246
+ db->maxbno = dstat.st_size * (long) BYTESIZ;
247
+
248
+ (void) memset(db->pagbuf, 0, PBLKSIZ);
249
+ (void) memset(db->dirbuf, 0, DBLKSIZ);
250
+ /*
251
+ * success
252
+ */
253
+ return db;
254
+
255
+ err:
256
+ if (db->pagf != -1)
257
+ (void) close(db->pagf);
258
+ if (db->dirf != -1)
259
+ (void) close(db->dirf);
260
+ free((char *) db);
261
+ return (DBM *) NULL;
262
+ }
263
+
264
+ void
265
+ sdbm_close(register DBM *db)
266
+ {
267
+ if (db == NULL)
268
+ errno = EINVAL;
269
+ else {
270
+ (void) close(db->dirf);
271
+ (void) close(db->pagf);
272
+ free((char *) db);
273
+ }
274
+ }
275
+
276
+ datum
277
+ sdbm_fetch(register DBM *db, datum key)
278
+ {
279
+ if (db == NULL || bad(key))
280
+ return errno = EINVAL, nullitem;
281
+
282
+ if (getpage(db, exhash(key)))
283
+ return getpair(db->pagbuf, key);
284
+
285
+ return ioerr(db), nullitem;
286
+ }
287
+
288
+ int
289
+ sdbm_delete(register DBM *db, datum key)
290
+ {
291
+ if (db == NULL || bad(key))
292
+ return errno = EINVAL, -1;
293
+ if (sdbm_rdonly(db))
294
+ return errno = EPERM, -1;
295
+
296
+ if (getpage(db, exhash(key))) {
297
+ if (!delpair(db->pagbuf, key))
298
+ return -1;
299
+ /*
300
+ * update the page file
301
+ */
302
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
303
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
304
+ return ioerr(db), -1;
305
+
306
+ return 0;
307
+ }
308
+
309
+ return ioerr(db), -1;
310
+ }
311
+
312
+ int
313
+ sdbm_store(register DBM *db, datum key, datum val, int flags)
314
+ {
315
+ int need;
316
+ register long hash;
317
+
318
+ if (db == NULL || bad(key))
319
+ return errno = EINVAL, -1;
320
+ if (sdbm_rdonly(db))
321
+ return errno = EPERM, -1;
322
+
323
+ need = key.dsize + val.dsize;
324
+ /*
325
+ * is the pair too big (or too small) for this database ??
326
+ */
327
+ if (need < 0 || need > PAIRMAX)
328
+ return errno = EINVAL, -1;
329
+
330
+ if (getpage(db, (hash = exhash(key)))) {
331
+ /*
332
+ * if we need to replace, delete the key/data pair
333
+ * first. If it is not there, ignore.
334
+ */
335
+ if (flags == DBM_REPLACE)
336
+ (void) delpair(db->pagbuf, key);
337
+ #if SEEDUPS
338
+ else if (duppair(db->pagbuf, key))
339
+ return 1;
340
+ #endif
341
+ /*
342
+ * if we do not have enough room, we have to split.
343
+ */
344
+ if (!fitpair(db->pagbuf, need))
345
+ if (!makroom(db, hash, need))
346
+ return ioerr(db), -1;
347
+ /*
348
+ * we have enough room or split is successful. insert the key,
349
+ * and update the page file.
350
+ */
351
+ (void) putpair(db->pagbuf, key, val);
352
+
353
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
354
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
355
+ return ioerr(db), -1;
356
+ /*
357
+ * success
358
+ */
359
+ return 0;
360
+ }
361
+
362
+ return ioerr(db), -1;
363
+ }
364
+
365
+ /*
366
+ * makroom - make room by splitting the overfull page
367
+ * this routine will attempt to make room for SPLTMAX times before
368
+ * giving up.
369
+ */
370
+ static int
371
+ makroom(register DBM *db, long int hash, int need)
372
+ {
373
+ long newp;
374
+ char twin[PBLKSIZ];
375
+ #if defined _WIN32
376
+ char zer[PBLKSIZ];
377
+ long oldtail;
378
+ #endif
379
+ char *pag = db->pagbuf;
380
+ char *new = twin;
381
+ register int smax = SPLTMAX;
382
+
383
+ do {
384
+ /*
385
+ * split the current page
386
+ */
387
+ (void) splpage(pag, new, db->hmask + 1);
388
+ /*
389
+ * address of the new page
390
+ */
391
+ newp = (hash & db->hmask) | (db->hmask + 1);
392
+ debug(("newp: %ld\n", newp));
393
+ /*
394
+ * write delay, read avoidance/cache shuffle:
395
+ * select the page for incoming pair: if key is to go to the new page,
396
+ * write out the previous one, and copy the new one over, thus making
397
+ * it the current page. If not, simply write the new page, and we are
398
+ * still looking at the page of interest. current page is not updated
399
+ * here, as sdbm_store will do so, after it inserts the incoming pair.
400
+ */
401
+
402
+ #if defined _WIN32
403
+ /*
404
+ * Fill hole with 0 if made it.
405
+ * (hole is NOT read as 0)
406
+ */
407
+ oldtail = lseek(db->pagf, 0L, SEEK_END);
408
+ memset(zer, 0, PBLKSIZ);
409
+ while (OFF_PAG(newp) > oldtail) {
410
+ if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
411
+ write(db->pagf, zer, PBLKSIZ) < 0) {
412
+
413
+ return 0;
414
+ }
415
+ oldtail += PBLKSIZ;
416
+ }
417
+ #endif
418
+
419
+ if (hash & (db->hmask + 1)) {
420
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
421
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
422
+ return 0;
423
+ db->pagbno = newp;
424
+ (void) memcpy(pag, new, PBLKSIZ);
425
+ }
426
+ else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0
427
+ || write(db->pagf, new, PBLKSIZ) < 0)
428
+ return 0;
429
+
430
+ if (!setdbit(db, db->curbit))
431
+ return 0;
432
+ /*
433
+ * see if we have enough room now
434
+ */
435
+ if (fitpair(pag, need))
436
+ return 1;
437
+ /*
438
+ * try again... update curbit and hmask as getpage would have
439
+ * done. because of our update of the current page, we do not
440
+ * need to read in anything. BUT we have to write the current
441
+ * [deferred] page out, as the window of failure is too great.
442
+ */
443
+ db->curbit = 2 * db->curbit +
444
+ ((hash & (db->hmask + 1)) ? 2 : 1);
445
+ db->hmask |= (db->hmask + 1);
446
+
447
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
448
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
449
+ return 0;
450
+
451
+ } while (--smax);
452
+ /*
453
+ * if we are here, this is real bad news. After SPLTMAX splits,
454
+ * we still cannot fit the key. say goodnight.
455
+ */
456
+ #if BADMESS
457
+ (void) (write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44) < 0);
458
+ #endif
459
+ return 0;
460
+
461
+ }
462
+
463
+ /*
464
+ * the following two routines will break if
465
+ * deletions aren't taken into account. (ndbm bug)
466
+ */
467
+ datum
468
+ sdbm_firstkey(register DBM *db)
469
+ {
470
+ if (db == NULL)
471
+ return errno = EINVAL, nullitem;
472
+ /*
473
+ * start at page 0
474
+ */
475
+ (void) memset(db->pagbuf, 0, PBLKSIZ);
476
+ if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0
477
+ || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
478
+ return ioerr(db), nullitem;
479
+ db->pagbno = 0;
480
+ db->blkptr = 0;
481
+ db->keyptr = 0;
482
+
483
+ return getnext(db);
484
+ }
485
+
486
+ datum
487
+ sdbm_nextkey(register DBM *db)
488
+ {
489
+ if (db == NULL)
490
+ return errno = EINVAL, nullitem;
491
+ return getnext(db);
492
+ }
493
+
494
+ /*
495
+ * all important binary trie traversal
496
+ */
497
+ static int
498
+ getpage(register DBM *db, register long int hash)
499
+ {
500
+ register int hbit;
501
+ register long dbit;
502
+ register long pagb;
503
+
504
+ dbit = 0;
505
+ hbit = 0;
506
+ while (dbit < db->maxbno && getdbit(db, dbit))
507
+ dbit = 2 * dbit + ((hash & ((long) 1 << hbit++)) ? 2 : 1);
508
+
509
+ debug(("dbit: %ld...", dbit));
510
+
511
+ db->curbit = dbit;
512
+ db->hmask = masks[hbit];
513
+
514
+ pagb = hash & db->hmask;
515
+ /*
516
+ * see if the block we need is already in memory.
517
+ * note: this lookaside cache has about 10% hit rate.
518
+ */
519
+ if (pagb != db->pagbno) {
520
+ /*
521
+ * note: here, we assume a "hole" is read as 0s.
522
+ * if not, must zero pagbuf first.
523
+ */
524
+ (void) memset(db->pagbuf, 0, PBLKSIZ);
525
+
526
+ if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0
527
+ || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
528
+ return 0;
529
+ if (!chkpage(db->pagbuf)) {
530
+ return 0;
531
+ }
532
+ db->pagbno = pagb;
533
+
534
+ debug(("pag read: %ld\n", pagb));
535
+ }
536
+ return 1;
537
+ }
538
+
539
+ static int
540
+ getdbit(register DBM *db, register long int dbit)
541
+ {
542
+ register long c;
543
+ register long dirb;
544
+
545
+ c = dbit / BYTESIZ;
546
+ dirb = c / DBLKSIZ;
547
+
548
+ if (dirb != db->dirbno) {
549
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
550
+ || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
551
+ return 0;
552
+ db->dirbno = dirb;
553
+
554
+ debug(("dir read: %ld\n", dirb));
555
+ }
556
+
557
+ return db->dirbuf[c % DBLKSIZ] & (1 << (dbit % BYTESIZ));
558
+ }
559
+
560
+ static int
561
+ setdbit(register DBM *db, register long int dbit)
562
+ {
563
+ register long c;
564
+ register long dirb;
565
+
566
+ c = dbit / BYTESIZ;
567
+ dirb = c / DBLKSIZ;
568
+
569
+ if (dirb != db->dirbno) {
570
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
571
+ || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
572
+ return 0;
573
+ db->dirbno = dirb;
574
+
575
+ debug(("dir read: %ld\n", dirb));
576
+ }
577
+
578
+ db->dirbuf[c % DBLKSIZ] |= (1 << (dbit % BYTESIZ));
579
+
580
+ if (dbit >= db->maxbno)
581
+ db->maxbno += (long) DBLKSIZ * BYTESIZ;
582
+
583
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
584
+ || write(db->dirf, db->dirbuf, DBLKSIZ) < 0)
585
+ return 0;
586
+
587
+ return 1;
588
+ }
589
+
590
+ /*
591
+ * getnext - get the next key in the page, and if done with
592
+ * the page, try the next page in sequence
593
+ */
594
+ static datum
595
+ getnext(register DBM *db)
596
+ {
597
+ datum key;
598
+
599
+ for (;;) {
600
+ db->keyptr++;
601
+ key = getnkey(db->pagbuf, db->keyptr);
602
+ if (key.dptr != NULL)
603
+ return key;
604
+ /*
605
+ * we either run out, or there is nothing on this page..
606
+ * try the next one... If we lost our position on the
607
+ * file, we will have to seek.
608
+ */
609
+ db->keyptr = 0;
610
+ if (db->pagbno != db->blkptr++)
611
+ if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0)
612
+ break;
613
+ db->pagbno = db->blkptr;
614
+ if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0)
615
+ break;
616
+ if (!chkpage(db->pagbuf)) {
617
+ break;
618
+ }
619
+ }
620
+
621
+ return ioerr(db), nullitem;
622
+ }
623
+
624
+ /* pair.c */
625
+ /*
626
+ * sdbm - ndbm work-alike hashed database library
627
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
628
+ * author: oz@nexus.yorku.ca
629
+ * status: public domain.
630
+ *
631
+ * page-level routines
632
+ */
633
+
634
+ #ifndef BSD42
635
+ /*#include <memory.h>*/
636
+ #endif
637
+
638
+ #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
639
+
640
+ /*
641
+ * forward
642
+ */
643
+ static int seepair proto((char *, int, char *, int));
644
+
645
+ /*
646
+ * page format:
647
+ * +------------------------------+
648
+ * ino | n | keyoff | datoff | keyoff |
649
+ * +------------+--------+--------+
650
+ * | datoff | - - - ----> |
651
+ * +--------+---------------------+
652
+ * | F R E E A R E A |
653
+ * +--------------+---------------+
654
+ * | <---- - - - | data |
655
+ * +--------+-----+----+----------+
656
+ * | key | data | key |
657
+ * +--------+----------+----------+
658
+ *
659
+ * calculating the offsets for free area: if the number
660
+ * of entries (ino[0]) is zero, the offset to the END of
661
+ * the free area is the block size. Otherwise, it is the
662
+ * nth (ino[ino[0]]) entry's offset.
663
+ */
664
+
665
+ static int
666
+ fitpair(char *pag, int need)
667
+ {
668
+ register int n;
669
+ register int off;
670
+ register int free;
671
+ register short *ino = (short *) pag;
672
+
673
+ off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
674
+ free = off - (n + 1) * (int)sizeof(short);
675
+ need += 2 * (int)sizeof(short);
676
+
677
+ debug(("free %d need %d\n", free, need));
678
+
679
+ return need <= free;
680
+ }
681
+
682
+ static void
683
+ putpair(char *pag, datum key, datum val)
684
+ {
685
+ register int n;
686
+ register int off;
687
+ register short *ino = (short *) pag;
688
+
689
+ off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
690
+ /*
691
+ * enter the key first
692
+ */
693
+ off -= key.dsize;
694
+ if (key.dsize)
695
+ (void) memcpy(pag + off, key.dptr, key.dsize);
696
+ PUT_SHORT(ino,n + 1,off);
697
+ /*
698
+ * now the data
699
+ */
700
+ off -= val.dsize;
701
+ if (val.dsize)
702
+ (void) memcpy(pag + off, val.dptr, val.dsize);
703
+ PUT_SHORT(ino,n + 2,off);
704
+ /*
705
+ * adjust item count
706
+ */
707
+ PUT_SHORT(ino,0,GET_SHORT(ino,0) + 2);
708
+ }
709
+
710
+ static datum
711
+ getpair(char *pag, datum key)
712
+ {
713
+ register int i;
714
+ register int n;
715
+ datum val;
716
+ register short *ino = (short *) pag;
717
+
718
+ if ((n = GET_SHORT(ino,0)) == 0)
719
+ return nullitem;
720
+
721
+ if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
722
+ return nullitem;
723
+
724
+ val.dptr = pag + GET_SHORT(ino,i + 1);
725
+ val.dsize = GET_SHORT(ino,i) - GET_SHORT(ino,i + 1);
726
+ return val;
727
+ }
728
+
729
+ #if SEEDUPS
730
+ static int
731
+ duppair(char *pag, datum key)
732
+ {
733
+ register short *ino = (short *) pag;
734
+ return GET_SHORT(ino,0) > 0 &&
735
+ seepair(pag, GET_SHORT(ino,0), key.dptr, key.dsize) > 0;
736
+ }
737
+ #endif
738
+
739
+ static datum
740
+ getnkey(char *pag, int num)
741
+ {
742
+ datum key;
743
+ register int off;
744
+ register short *ino = (short *) pag;
745
+
746
+ num = num * 2 - 1;
747
+ if (GET_SHORT(ino,0) == 0 || num > GET_SHORT(ino,0))
748
+ return nullitem;
749
+
750
+ off = (num > 1) ? GET_SHORT(ino,num - 1) : PBLKSIZ;
751
+
752
+ key.dptr = pag + GET_SHORT(ino,num);
753
+ key.dsize = off - GET_SHORT(ino,num);
754
+
755
+ return key;
756
+ }
757
+
758
+ static int
759
+ delpair(char *pag, datum key)
760
+ {
761
+ register int n;
762
+ register int i;
763
+ register short *ino = (short *) pag;
764
+
765
+ if ((n = GET_SHORT(ino,0)) == 0)
766
+ return 0;
767
+
768
+ if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
769
+ return 0;
770
+ /*
771
+ * found the key. if it is the last entry
772
+ * [i.e. i == n - 1] we just adjust the entry count.
773
+ * hard case: move all data down onto the deleted pair,
774
+ * shift offsets onto deleted offsets, and adjust them.
775
+ * [note: 0 < i < n]
776
+ */
777
+ if (i < n - 1) {
778
+ register int m;
779
+ register char *dst = pag + (i == 1 ? PBLKSIZ : GET_SHORT(ino,i - 1));
780
+ register char *src = pag + GET_SHORT(ino,i + 1);
781
+ register ptrdiff_t zoo = dst - src;
782
+
783
+ debug(("free-up %"PRIdPTRDIFF" ", zoo));
784
+ /*
785
+ * shift data/keys down
786
+ */
787
+ m = GET_SHORT(ino,i + 1) - GET_SHORT(ino,n);
788
+ #ifdef DUFF
789
+ #define MOVB *--dst = *--src
790
+
791
+ if (m > 0) {
792
+ register int loop = (m + 8 - 1) >> 3;
793
+
794
+ switch (m & (8 - 1)) {
795
+ case 0: do {
796
+ MOVB; case 7: MOVB;
797
+ case 6: MOVB; case 5: MOVB;
798
+ case 4: MOVB; case 3: MOVB;
799
+ case 2: MOVB; case 1: MOVB;
800
+ } while (--loop);
801
+ }
802
+ }
803
+ #else
804
+ #ifdef MEMMOVE
805
+ memmove(dst-m, src-m, m);
806
+ #else
807
+ while (m--)
808
+ *--dst = *--src;
809
+ #endif
810
+ #endif
811
+ /*
812
+ * adjust offset index up
813
+ */
814
+ while (i < n - 1) {
815
+ PUT_SHORT(ino,i, GET_SHORT(ino,i + 2) + zoo);
816
+ i++;
817
+ }
818
+ }
819
+ PUT_SHORT(ino, 0, GET_SHORT(ino, 0) - 2);
820
+ return 1;
821
+ }
822
+
823
+ /*
824
+ * search for the key in the page.
825
+ * return offset index in the range 0 < i < n.
826
+ * return 0 if not found.
827
+ */
828
+ static int
829
+ seepair(char *pag, register int n, register char *key, register int siz)
830
+ {
831
+ register int i;
832
+ register int off = PBLKSIZ;
833
+ register short *ino = (short *) pag;
834
+
835
+ for (i = 1; i < n; i += 2) {
836
+ if (siz == off - GET_SHORT(ino,i) &&
837
+ memcmp(key, pag + GET_SHORT(ino,i), siz) == 0)
838
+ return i;
839
+ off = GET_SHORT(ino,i + 1);
840
+ }
841
+ return 0;
842
+ }
843
+
844
+ static void
845
+ splpage(char *pag, char *new, long int sbit)
846
+ {
847
+ datum key;
848
+ datum val;
849
+
850
+ register int n;
851
+ register int off = PBLKSIZ;
852
+ char cur[PBLKSIZ];
853
+ register short *ino = (short *) cur;
854
+
855
+ (void) memcpy(cur, pag, PBLKSIZ);
856
+ (void) memset(pag, 0, PBLKSIZ);
857
+ (void) memset(new, 0, PBLKSIZ);
858
+
859
+ n = GET_SHORT(ino,0);
860
+ for (ino++; n > 0; ino += 2) {
861
+ key.dptr = cur + GET_SHORT(ino,0);
862
+ key.dsize = off - GET_SHORT(ino,0);
863
+ val.dptr = cur + GET_SHORT(ino,1);
864
+ val.dsize = GET_SHORT(ino,0) - GET_SHORT(ino,1);
865
+ /*
866
+ * select the page pointer (by looking at sbit) and insert
867
+ */
868
+ (void) putpair((exhash(key) & sbit) ? new : pag, key, val);
869
+
870
+ off = GET_SHORT(ino,1);
871
+ n -= 2;
872
+ }
873
+
874
+ debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
875
+ ((short *) new)[0] / 2,
876
+ ((short *) pag)[0] / 2));
877
+ }
878
+
879
+ /*
880
+ * check page sanity:
881
+ * number of entries should be something
882
+ * reasonable, and all offsets in the index should be in order.
883
+ * this could be made more rigorous.
884
+ */
885
+ static int
886
+ chkpage(char *pag)
887
+ {
888
+ register int n;
889
+ register int off;
890
+ register short *ino = (short *) pag;
891
+
892
+ if ((n = GET_SHORT(ino,0)) < 0 || n > PBLKSIZ / (int)sizeof(short))
893
+ return 0;
894
+
895
+ if (n > 0) {
896
+ off = PBLKSIZ;
897
+ for (ino++; n > 0; ino += 2) {
898
+ if (GET_SHORT(ino,0) > off || GET_SHORT(ino,1) > off ||
899
+ GET_SHORT(ino,1) > GET_SHORT(ino,0))
900
+ return 0;
901
+ off = GET_SHORT(ino,1);
902
+ n -= 2;
903
+ }
904
+ }
905
+ return 1;
906
+ }
907
+
908
+ /* hash.c */
909
+ /*
910
+ * sdbm - ndbm work-alike hashed database library
911
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
912
+ * author: oz@nexus.yorku.ca
913
+ * status: public domain. keep it that way.
914
+ *
915
+ * hashing routine
916
+ */
917
+
918
+ /*
919
+ * polynomial conversion ignoring overflows
920
+ * [this seems to work remarkably well, in fact better
921
+ * then the ndbm hash function. Replace at your own risk]
922
+ * use: 65599 nice.
923
+ * 65587 even better.
924
+ */
925
+ long
926
+ sdbm_hash(register char *str, register int len)
927
+ {
928
+ register unsigned long n = 0;
929
+
930
+ #ifdef DUFF
931
+
932
+ #define HASHC n = *str++ + 65599 * n
933
+
934
+ if (len > 0) {
935
+ register int loop = (len + 8 - 1) >> 3;
936
+
937
+ switch(len & (8 - 1)) {
938
+ case 0: do {
939
+ HASHC; case 7: HASHC;
940
+ case 6: HASHC; case 5: HASHC;
941
+ case 4: HASHC; case 3: HASHC;
942
+ case 2: HASHC; case 1: HASHC;
943
+ } while (--loop);
944
+ }
945
+
946
+ }
947
+ #else
948
+ while (len--)
949
+ n = ((*str++) & 255) + 65587L * n;
950
+ #endif
951
+ return n;
952
+ }