2 //metadoc QDBM copyright Steve Dekorte 2002
3 //metadoc QDBM license BSD revised
4 /*metadoc QDBM description
7 //metadoc QDBM category Databases
22 #define QDBM(self) ((VILLA *)(IoObject_dataPointer(self)))
24 int pathCompare(const char *p1
, const char *p2
, char sepChar
)
27 int len1
= strlen(p1
);
28 int len2
= strlen(p2
);
29 int len
= len1
< len2
? len1
: len2
;
31 for (i
= 0; i
< len
; i
++)
36 if (c1
== sepChar
&& c2
!= sepChar
)
42 if (c2
== sepChar
&& c1
!= sepChar
)
47 if (c1
> c2
) return 1;
48 if (c1
< c2
) return -1;
51 if (len1
> len2
) return 1;
52 if (len1
< len2
) return -1;
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)
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, '/');
91 if (len1 > len2) return 1;
92 if (len1 < len2) return -1;
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;
116 int compareStrNumFunc(const char *a, int asize, const char *b, int bsize)
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
, '/');
138 if (as
!= NULL
) *as
= 0;
139 if (bs
!= NULL
) *bs
= 0;
144 //printf("%i cmp %i ", an, bn);
146 if (as
!= NULL
) *as
= '/';
147 if (bs
!= NULL
) *bs
= '/';
150 if (an
> bn
) { r
= 1; }
152 if (an
< bn
) { r
= -1; }
155 // an and bn are the same, so just do a lex compare of the whole
159 //printf("%s %s %s\n", a, (r == 0) ? "==" : ((r == 1) ? ">" : "<"), b);
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);
174 IoQDBM
*IoQDBM_proto(void *state
)
176 IoMethodTable methodTable
[] = {
177 {"open", IoQDBM_open
},
178 {"close", IoQDBM_close
},
180 {"atPut", IoQDBM_atPut
},
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
},
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
);
218 IoQDBM
*IoQDBM_rawClone(IoQDBM
*proto
)
220 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
221 IoObject_tag_(self
, IoObject_tag(proto
));
222 IoObject_setDataPointer_(self
, NULL
);
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
)
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)
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
;
266 if(strcmp(CSTRING(compareType
), "VL_CMPINT") == 0) cf
= VL_CMPINT
;
268 if(strcmp(CSTRING(compareType
), "VL_CMPNUM") == 0) cf
= VL_CMPNUM
;
270 if(strcmp(CSTRING(compareType
), "VL_CMPLEX") == 0) cf
= VL_CMPLEX
;
272 if(strcmp(CSTRING(compareType
), "VL_CMPSNM") == 0)
274 cf
= compareStrNumFunc
;
275 //printf("using compareStrNumFunc\n");
278 if(strcmp(CSTRING(compareType
), "VL_CMPPTH") == 0)
280 cf
= pathCompareFunc
;
281 //printf("using pathCompareFunc\n");
285 fprintf(stderr
, "ivalid compare function name\n");
290 if(!(villa
= vlopen(CSTRING(path
), VL_OWRITER
| VL_OCREAT
, cf
)))
292 fprintf(stderr
, "dpopen failed\n");
296 IoObject_setDataPointer_(self
, villa
);
301 IoObject
*IoQDBM_close(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
310 IoObject_setDataPointer_(self
, NULL
);
316 IoObject
*IoQDBM_sync(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
319 Syncs the database. Returns self
323 IOASSERT(QDBM(self
), "invalid QDBM");
324 result
= vlsync(QDBM(self
));
325 IOASSERT(result
, dperrmsg(dpecode
));
329 IoObject
*IoQDBM_size(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
332 Returns number of records in database. Returns self
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
)
344 Optimizes the database. Returns self
347 IOASSERT(QDBM(self
), "invalid QDBM");
348 IOASSERT(vloptimize(QDBM(self
)), dperrmsg(dpecode
));
352 IoObject
*IoQDBM_name(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
365 Begin transaction. Returns self
368 IOASSERT(QDBM(self
), "invalid QDBM");
369 IOASSERT(vltranbegin(QDBM(self
)), dperrmsg(dpecode
));
373 IoObject
*IoQDBM_commit(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
376 Commit transaction. Returns self
379 IOASSERT(QDBM(self
), "invalid QDBM");
380 IOASSERT(vltrancommit(QDBM(self
)), dperrmsg(dpecode
));
384 IoObject
*IoQDBM_abort(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
387 Abort transaction. Returns self
391 IOASSERT(QDBM(self
), "invalid QDBM");
392 result
= vltranabort(QDBM(self
));
393 IOASSERT(result
, dperrmsg(dpecode
));
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);
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
));
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);
428 IOASSERT(QDBM(self
), "invalid QDBM");
430 value
= vlget(QDBM(self
), (const char *)IoSeq_rawBytes(key
), IoSeq_rawSizeInBytes(key
), &size
);
434 IoSeq
*v
= IoSeq_newWithData_length_(IOSTATE
, (unsigned char *)value
, size
);
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);
451 IOASSERT(QDBM(self
), "invalid QDBM");
453 size
= vlvsiz(QDBM(self
), (const char *)IoSeq_rawBytes(key
), IoSeq_rawSizeInBytes(key
));
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);
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
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
)
548 Returns current cursor key or nil.
554 IOASSERT(QDBM(self
), "invalid QDBM");
555 value
= vlcurkey(QDBM(self
), &size
);
559 IoSeq
*s
= IoSeq_newWithData_length_(IOSTATE
, (unsigned char *)value
, size
);
567 IoObject
*IoQDBM_cursorValue(IoObject
*self
, IoObject
*locals
, IoMessage
*m
)
569 /*doc QDBM cursorValue
570 Returns current cursor value or nil.
576 IOASSERT(QDBM(self
), "invalid QDBM");
577 value
= vlcurval(QDBM(self
), &size
);
581 IoSeq
*s
= IoSeq_newWithData_length_(IOSTATE
, (unsigned char *)value
, size
);
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
));
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
));