Addons updated to new doc format
[io.git] / addons / QDBM / source / IoQDBM.c
blob013379a351340bbe556e81780ceb3f34dad91093
2 //metadoc QDBM copyright Steve Dekorte 2002
3 //metadoc QDBM license BSD revised
4 /*metadoc QDBM description
5 A key/value database.
6 */
7 //metadoc QDBM category Databases
9 #include "IoQDBM.h"
11 #include <depot.h>
12 #include <cabin.h>
13 #include <villa.h>
14 #include <stdlib.h>
16 #include "IoObject.h"
17 #include "IoState.h"
18 #include "IoSeq.h"
19 #include "IoState.h"
20 #include "IoNumber.h"
22 #define QDBM(self) ((VILLA *)(IoObject_dataPointer(self)))
24 int pathCompare(const char *p1, const char *p2, char sepChar)
26 int i;
27 int len1 = strlen(p1);
28 int len2 = strlen(p2);
29 int len = len1 < len2 ? len1 : len2;
31 for (i = 0; i < len; i ++)
33 char c1 = p1[i];
34 char c2 = p2[i];
36 if (c1 == sepChar && c2 != sepChar)
38 return -1;
42 if (c2 == sepChar && c1 != sepChar)
44 return 1;
47 if (c1 > c2) return 1;
48 if (c1 < c2) return -1;
51 if (len1 > len2) return 1;
52 if (len1 < len2) return -1;
54 return 0;
58 int comparePathComponent(const char *p1, const char *p2, char sepChar, int *size)
60 char *b1 = strchr(p1 + i, sepChar);
61 char *b2 = strchr(p2 + i, sepChar);
62 int len1 = b1 ? b1 - p1 : strlen(p1);
63 int len2 = b2 ? b2 - p2 : strlen(p2);
65 if (len1 && isdigit(p1[0]))
67 return strtod(p1, p1 + len1) -
70 if (len1 > len2) return 1;
71 if (len1 < len2) return -1;
72 if (len1 == 0) return 0;
74 return strcmpn(p1, p2, len1);
77 int pathCompare(const char *p1, const char *p2, char sepChar)
79 int i;
80 int len1 = strlen(p1);
81 int len2 = strlen(p2);
82 //int len = len1 < len2 ? len1 : len2;
85 char *b1 = strchr(p1 + i, '/');
86 char *b2 = strchr(p2 + i, '/');
88 int blen1 = p1 - b1;
91 if (len1 > len2) return 1;
92 if (len1 < len2) return -1;
94 return 0;
98 int pathCompareFunc(const char *aptr, int asiz, const char *bptr, int bsiz)
100 return pathCompare(aptr, bptr, '/');
104 int compareFunc(const char *aptr, int asiz, const char *bptr, int bsiz)
106 return strcmp(aptr, bptr);
108 //int r = strncmp(aptr, bptr, max);
109 if (r > 0) return -1;
110 if (r < 0) return 1;
111 return 0;
116 int compareStrNumFunc(const char *a, int asize, const char *b, int bsize)
118 long an = atol(a);
119 long bn = atol(b);
120 if (an > bn) return 1;
121 if (an < bn) return -1;
124 int smaller = (asize < bsize) ? asize : bsize;
125 return memcmp(a + smaller + 1, b + smaller + 1, smaller);
130 int compareStrNumFunc(const char *a, int asize, const char *b, int bsize)
132 char *as = strchr((char *)a, '/');
133 char *bs = strchr((char *)b, '/');
134 long an;
135 long bn;
136 int r;
138 if (as != NULL) *as = 0;
139 if (bs != NULL) *bs = 0;
141 an = atol(a);
142 bn = atol(b);
144 //printf("%i cmp %i ", an, bn);
146 if (as != NULL) *as = '/';
147 if (bs != NULL) *bs = '/';
150 if (an > bn) { r = 1; }
151 else
152 if (an < bn) { r = -1; }
153 else
155 // an and bn are the same, so just do a lex compare of the whole
156 r = strcmp(a, b);
159 //printf("%s %s %s\n", a, (r == 0) ? "==" : ((r == 1) ? ">" : "<"), b);
161 return r;
164 IoTag *IoQDBM_newTag(void *state)
166 IoTag *tag = IoTag_newWithName_("QDBM");
167 IoTag_state_(tag, state);
168 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoQDBM_free);
169 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoQDBM_rawClone);
170 //IoTag_markFunc_(tag, (IoTagMarkFunc *)IoQDBM_mark);
171 return tag;
174 IoQDBM *IoQDBM_proto(void *state)
176 IoMethodTable methodTable[] = {
177 {"open", IoQDBM_open},
178 {"close", IoQDBM_close},
180 {"atPut", IoQDBM_atPut},
181 {"at", IoQDBM_at},
182 {"sizeAt", IoQDBM_sizeAt},
183 {"removeAt", IoQDBM_removeAt},
184 //{"sync", IoQDBM_sync},
186 {"size", IoQDBM_size},
187 {"optimize", IoQDBM_optimize},
188 {"name", IoQDBM_name},
190 {"begin", IoQDBM_begin},
191 {"commit", IoQDBM_commit},
192 {"abort", IoQDBM_abort},
194 {"cursorFirst", IoQDBM_cursorFirst},
195 {"cursorLast", IoQDBM_cursorLast},
196 {"cursorPrevious", IoQDBM_cursorPrevious},
197 {"cursorNext", IoQDBM_cursorNext},
198 {"cursorJumpForward", IoQDBM_cursorJumpForward},
199 {"cursorJumpBackward", IoQDBM_cursorJumpBackward},
200 {"cursorKey", IoQDBM_cursorKey},
201 {"cursorValue", IoQDBM_cursorValue},
202 {"cursorPut", IoQDBM_cursorPut},
203 {"cursorRemove", IoQDBM_cursorRemove},
205 {NULL, NULL},
208 IoObject *self = IoObject_new(state);
209 IoObject_tag_(self, IoQDBM_newTag(state));
211 IoObject_setDataPointer_(self, NULL);
212 IoState_registerProtoWithFunc_((IoState *)state, self, IoQDBM_proto);
214 IoObject_addMethodTable_(self, methodTable);
215 return self;
218 IoQDBM *IoQDBM_rawClone(IoQDBM *proto)
220 IoObject *self = IoObject_rawClonePrimitive(proto);
221 IoObject_tag_(self, IoObject_tag(proto));
222 IoObject_setDataPointer_(self, NULL);
223 return self;
226 IoQDBM *IoQDBM_new(void *state)
228 IoObject *proto = IoState_protoWithInitFunction_((IoState *)state, IoQDBM_proto);
229 return IOCLONE(proto);
232 void IoQDBM_free(IoQDBM *self)
234 if(QDBM(self))
236 vlclose(QDBM(self));
237 IoObject_setDataPointer_(self, NULL);
242 void IoQDBM_mark(IoQDBM *self)
247 // --------------------------------------------------------
249 IoObject *IoQDBM_open(IoObject *self, IoObject *locals, IoMessage *m)
251 /*doc QDBM open(path)
252 Opens the database.
255 VILLA *villa;
256 IoSeq *path = IoMessage_locals_seqArgAt_(m, locals, 0);
257 VLCFUNC cf = VL_CMPLEX;
259 if(IoMessage_argCount(m) > 1)
261 IoSeq *compareType = IoMessage_locals_seqArgAt_(m, locals, 1);
262 //printf("using compareType:%s\n", CSTRING(compareType));
264 if(strcmp(CSTRING(compareType), "VL_CMPDEC") == 0) cf = VL_CMPDEC;
265 else
266 if(strcmp(CSTRING(compareType), "VL_CMPINT") == 0) cf = VL_CMPINT;
267 else
268 if(strcmp(CSTRING(compareType), "VL_CMPNUM") == 0) cf = VL_CMPNUM;
269 else
270 if(strcmp(CSTRING(compareType), "VL_CMPLEX") == 0) cf = VL_CMPLEX;
271 else
272 if(strcmp(CSTRING(compareType), "VL_CMPSNM") == 0)
274 cf = compareStrNumFunc;
275 //printf("using compareStrNumFunc\n");
277 else
278 if(strcmp(CSTRING(compareType), "VL_CMPPTH") == 0)
280 cf = pathCompareFunc;
281 //printf("using pathCompareFunc\n");
283 else
285 fprintf(stderr, "ivalid compare function name\n");
286 return IONIL(self);
290 if(!(villa = vlopen(CSTRING(path), VL_OWRITER | VL_OCREAT, cf)))
292 fprintf(stderr, "dpopen failed\n");
293 return IONIL(self);
296 IoObject_setDataPointer_(self, villa);
298 return self;
301 IoObject *IoQDBM_close(IoObject *self, IoObject *locals, IoMessage *m)
303 /*doc QDBM close
304 Closes the database.
307 if(QDBM(self))
309 vlclose(QDBM(self));
310 IoObject_setDataPointer_(self, NULL);
313 return self;
316 IoObject *IoQDBM_sync(IoObject *self, IoObject *locals, IoMessage *m)
318 /*doc QDBM sync
319 Syncs the database. Returns self
322 int result;
323 IOASSERT(QDBM(self), "invalid QDBM");
324 result = vlsync(QDBM(self));
325 IOASSERT(result, dperrmsg(dpecode));
326 return self;
329 IoObject *IoQDBM_size(IoObject *self, IoObject *locals, IoMessage *m)
331 /*doc QDBM size
332 Returns number of records in database. Returns self
335 int result;
336 IOASSERT(QDBM(self), "invalid QDBM");
337 result = vlrnum(QDBM(self));
338 return IONUMBER(result);
341 IoObject *IoQDBM_optimize(IoObject *self, IoObject *locals, IoMessage *m)
343 /*doc QDBM optimize
344 Optimizes the database. Returns self
347 IOASSERT(QDBM(self), "invalid QDBM");
348 IOASSERT(vloptimize(QDBM(self)), dperrmsg(dpecode));
349 return self;
352 IoObject *IoQDBM_name(IoObject *self, IoObject *locals, IoMessage *m)
354 /*doc QDBM name
355 Returns the name of the database.
358 IOASSERT(QDBM(self), "invalid QDBM");
359 return IOSYMBOL(vlname(QDBM(self)));
362 IoObject *IoQDBM_begin(IoObject *self, IoObject *locals, IoMessage *m)
364 /*doc QDBM begin
365 Begin transaction. Returns self
368 IOASSERT(QDBM(self), "invalid QDBM");
369 IOASSERT(vltranbegin(QDBM(self)), dperrmsg(dpecode));
370 return self;
373 IoObject *IoQDBM_commit(IoObject *self, IoObject *locals, IoMessage *m)
375 /*doc QDBM commit
376 Commit transaction. Returns self
379 IOASSERT(QDBM(self), "invalid QDBM");
380 IOASSERT(vltrancommit(QDBM(self)), dperrmsg(dpecode));
381 return self;
384 IoObject *IoQDBM_abort(IoObject *self, IoObject *locals, IoMessage *m)
386 /*doc QDBM abort
387 Abort transaction. Returns self
390 int result;
391 IOASSERT(QDBM(self), "invalid QDBM");
392 result = vltranabort(QDBM(self));
393 IOASSERT(result, dperrmsg(dpecode));
394 return self;
397 // ---------------------------------------------------------------------------------
399 IoObject *IoQDBM_atPut(IoObject *self, IoObject *locals, IoMessage *m)
401 /*doc QDBM atPut(keySymbol, valueSequence)
402 Sets the value of valueSequence with the key keySymbol. Returns self.
405 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
406 IoSeq *value = IoMessage_locals_seqArgAt_(m, locals, 1);
407 int result;
409 IOASSERT(QDBM(self), "invalid QDBM");
411 result = vlput(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), (const char *)IoSeq_rawBytes(value), IoSeq_rawSizeInBytes(value), VL_DOVER);
413 IOASSERT(result, dperrmsg(dpecode));
415 return self;
418 IoObject *IoQDBM_at(IoObject *self, IoObject *locals, IoMessage *m)
420 /*doc QDBM at(keySymbol)
421 Returns a Sequence for the value at the given key or nil if there is no such key.
424 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
425 char *value;
426 int size;
428 IOASSERT(QDBM(self), "invalid QDBM");
430 value = vlget(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), &size);
432 if (value)
434 IoSeq *v = IoSeq_newWithData_length_(IOSTATE, (unsigned char *)value, size);
435 free(value);
436 return v;
439 return IONIL(self);
442 IoObject *IoQDBM_sizeAt(IoObject *self, IoObject *locals, IoMessage *m)
444 /*doc QDBM sizeAt(keySymbol)
445 Returns the size of the value at the given key or nil if there is no such key.
448 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
449 int size;
451 IOASSERT(QDBM(self), "invalid QDBM");
453 size = vlvsiz(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key));
455 if (size == -1)
457 return IONIL(self);
460 return IONUMBER(size);
463 IoObject *IoQDBM_removeAt(IoObject *self, IoObject *locals, IoMessage *m)
465 /*doc QDBM atRemove(keySymbol)
466 Removes the specified key. Returns self
469 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
470 int result;
471 IOASSERT(QDBM(self), "invalid QDBM");
472 result = vloutlist(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key));
473 //IOASSERT(result, dperrmsg(dpecode)); // commented to avoid 'no item found' exception
474 return self;
477 IoObject *IoQDBM_cursorFirst(IoObject *self, IoObject *locals, IoMessage *m)
479 /*doc QDBM cursorFirst
480 Move cursor to first record. Returns self
483 IOASSERT(QDBM(self), "invalid QDBM");
484 return IOBOOL(self, vlcurfirst(QDBM(self)));
487 IoObject *IoQDBM_cursorLast(IoObject *self, IoObject *locals, IoMessage *m)
489 /*doc QDBM cursorLast
490 Move cursor to last record. Returns self
493 IOASSERT(QDBM(self), "invalid QDBM");
494 return IOBOOL(self, vlcurlast(QDBM(self)));
497 IoObject *IoQDBM_cursorPrevious(IoObject *self, IoObject *locals, IoMessage *m)
499 /*doc QDBM cursorPrevious
500 Move cursor to previous record. Returns true if there is another key,
501 or false if there is no previous record.
504 IOASSERT(QDBM(self), "invalid QDBM");
505 return IOBOOL(self, vlcurprev(QDBM(self)));
508 IoObject *IoQDBM_cursorNext(IoObject *self, IoObject *locals, IoMessage *m)
510 /*doc QDBM cursorNext
511 Move cursor to next record. Returns true if there is another key,
512 or false if there is no next record.
515 IOASSERT(QDBM(self), "invalid QDBM");
516 return IOBOOL(self, vlcurnext(QDBM(self)));
519 IoObject *IoQDBM_cursorJumpForward(IoObject *self, IoObject *locals, IoMessage *m)
521 /*doc QDBM cursorJumpForward(key)
522 Move cursor to next record around key. Returns self
525 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
527 IOASSERT(QDBM(self), "invalid QDBM");
528 //IOASSERT(vlcurjump(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), VL_JFORWARD), dperrmsg(dpecode));
529 return IOBOOL(self, vlcurjump(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), VL_JFORWARD));
532 IoObject *IoQDBM_cursorJumpBackward(IoObject *self, IoObject *locals, IoMessage *m)
534 /*doc QDBM cursorJumpBackward(key)
535 Move cursor to previous record around key. Returns self
538 IoSeq *key = IoMessage_locals_seqArgAt_(m, locals, 0);
540 IOASSERT(QDBM(self), "invalid QDBM");
541 //IOASSERT(vlcurjump(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), VL_JBACKWARD), dperrmsg(dpecode));
542 return IOBOOL(self, vlcurjump(QDBM(self), (const char *)IoSeq_rawBytes(key), IoSeq_rawSizeInBytes(key), VL_JBACKWARD));
545 IoObject *IoQDBM_cursorKey(IoObject *self, IoObject *locals, IoMessage *m)
547 /*doc QDBM cursorKey
548 Returns current cursor key or nil.
551 int size;
552 char *value;
554 IOASSERT(QDBM(self), "invalid QDBM");
555 value = vlcurkey(QDBM(self), &size);
557 if (value)
559 IoSeq *s = IoSeq_newWithData_length_(IOSTATE, (unsigned char *)value, size);
560 free(value);
561 return s;
564 return IONIL(self);
567 IoObject *IoQDBM_cursorValue(IoObject *self, IoObject *locals, IoMessage *m)
569 /*doc QDBM cursorValue
570 Returns current cursor value or nil.
573 int size;
574 char *value;
576 IOASSERT(QDBM(self), "invalid QDBM");
577 value = vlcurval(QDBM(self), &size);
579 if (value)
581 IoSeq *s = IoSeq_newWithData_length_(IOSTATE, (unsigned char *)value, size);
582 free(value);
583 return s;
586 return IONIL(self);
589 IoObject *IoQDBM_cursorPut(IoObject *self, IoObject *locals, IoMessage *m)
591 /*doc QDBM cursorPut(value)
592 Sets the value at the current cursor postion. Returns self.
595 IoSeq *value = IoMessage_locals_seqArgAt_(m, locals, 0);
597 IOASSERT(QDBM(self), "invalid QDBM");
599 IOASSERT(vlcurput(QDBM(self), (const char *)IoSeq_rawBytes(value), IoSeq_rawSizeInBytes(value), VL_CPCURRENT), dperrmsg(dpecode));
601 return self;
604 IoObject *IoQDBM_cursorRemove(IoObject *self, IoObject *locals, IoMessage *m)
606 /*doc QDBM cursorRemove
607 Removes the current cursor postion. Returns self.
610 IOASSERT(QDBM(self), "invalid QDBM");
612 IOASSERT(vlcurout(QDBM(self)), dperrmsg(dpecode));
614 return self;