e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) #include "global.h" #include "gdbm_machine.h" #include "threads.h" /* Todo: make sure only one thread accesses the same gdbmmod */ #include "interpret.h" #include "svalue.h" #include "stralloc.h"
51ef5c2002-10-21Marcus Comstedt #include "module.h"
e206c12014-08-16Per Hedbor #include "array.h"
5d4ff72005-11-16Henrik Grubbström (Grubba) #include "program.h"
440cf92005-11-16Henrik Grubbström (Grubba) #include "module_support.h"
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
6dc2772000-07-28Fredrik Hübinette (Hubbe) #if defined(HAVE_GDBM_H) && defined(HAVE_LIBGDBM)
a80a9c1997-02-11Fredrik Hübinette (Hubbe) #include <gdbm.h>
2505872002-09-25Marcus Comstedt #ifdef _REENTRANT static MUTEX_T gdbm_lock STATIC_MUTEX_INIT; #endif
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
e206c12014-08-16Per Hedbor static struct program *iterator;
a80a9c1997-02-11Fredrik Hübinette (Hubbe) struct gdbm_glue { GDBM_FILE dbf;
e206c12014-08-16Per Hedbor  struct pike_string *iter;
a80a9c1997-02-11Fredrik Hübinette (Hubbe) };
39221e2000-07-07Henrik Grubbström (Grubba) #define THIS ((struct gdbm_glue *)(Pike_fp->current_storage))
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
be478c1997-08-30Henrik Grubbström (Grubba) static void do_free(void)
a80a9c1997-02-11Fredrik Hübinette (Hubbe) { if(THIS->dbf) { GDBM_FILE dbf; dbf=THIS->dbf; THIS->dbf=0; THREADS_ALLOW(); mt_lock(& gdbm_lock); gdbm_close(dbf); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); }
e206c12014-08-16Per Hedbor  if(THIS->iter) { free_string(THIS->iter); THIS->iter=0; }
a80a9c1997-02-11Fredrik Hübinette (Hubbe) }
a080c82006-03-18Henrik Grubbström (Grubba) /* Compat with old gdbm. */ #ifndef GDBM_SYNC #define GDBM_SYNC 0 #endif #ifndef GDBM_NOLOCK #define GDBM_NOLOCK 0 #endif
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static int fixmods(char *mods) {
06d37d2006-03-18Henrik Grubbström (Grubba)  int mode = 0; int flags = GDBM_NOLOCK;
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  while(1) { switch(*(mods++)) { case 0:
06d37d2006-03-18Henrik Grubbström (Grubba)  switch(mode) { default: case 0x0: Pike_error("No mode given for gdbm->open()\n"); case 0x1: /* r */ return GDBM_READER; case 0x3: /* rw */ return GDBM_WRITER | flags; case 0x7: /* rwc */ return GDBM_WRCREAT | flags; case 0xf: /* rwct */ return GDBM_NEWDB | flags;
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  }
06d37d2006-03-18Henrik Grubbström (Grubba)  case 'r': case 'R': mode = 0x1; break; case 'w': case 'W': mode = 0x3; break; case 'c': case 'C': mode = 0x7; break; case 't': case 'T': mode = 0xf; break;
a080c82006-03-18Henrik Grubbström (Grubba)  /* * Flags from this point on. */
06d37d2006-03-18Henrik Grubbström (Grubba)  case 'f': case 'F': flags |= GDBM_FAST; break;
a080c82006-03-18Henrik Grubbström (Grubba)  /* * NOTE: The following are new in Pike 7.7. */ case 's': case 'S': flags |= GDBM_SYNC; break;
06d37d2006-03-18Henrik Grubbström (Grubba)  /* NOTE: This flag is inverted! */ case 'l': case 'L': flags &= ~GDBM_NOLOCK; break;
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  default:
06d37d2006-03-18Henrik Grubbström (Grubba)  Pike_error("Bad mode flag '%c' in gdbm->open.\n", mods[-1]);
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  } } }
e206c12014-08-16Per Hedbor void gdbmmod_fatal(const char *err)
a80a9c1997-02-11Fredrik Hübinette (Hubbe) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM: %s\n",err);
a80a9c1997-02-11Fredrik Hübinette (Hubbe) }
fc293f2001-10-26Martin Nilsson /*! @module Gdbm
e206c12014-08-16Per Hedbor  *! *! This module provides an interface to the GNU ddm databae. *! *! The basic use of GDBM is to store key/data pairs in a data *! file. Each key must be unique and each key is paired with only one *! data item. *! *! The library provides primitives for storing key/data pairs, *! searching and retrieving the data by its key and deleting a key *! along with its data. It also support sequential iteration over all *! key/data pairs in a database. *! *! The @[DB] class also overloads enough operators to make it behave
3f09ab2014-08-16Per Hedbor  *! a lot like a @[mapping(string(8bit):string(8bit))], you can index it,
e206c12014-08-16Per Hedbor  *! assign indices and loop over it using foreach. *!
fc293f2001-10-26Martin Nilsson  */
e206c12014-08-16Per Hedbor /*! @class DB
fc293f2001-10-26Martin Nilsson  */
e206c12014-08-16Per Hedbor /*! @decl protected void create(void|string file, void|string(99..119) mode)
fc293f2001-10-26Martin Nilsson  *! *! Without arguments, this function does nothing. With one argument it *! opens the given file as a gdbm database, if this fails for some *! reason, an error will be generated. If a second argument is present, *! it specifies how to open the database using one or more of the follow *! flags in a string: *! *! @string *! @value r *! Open database for reading *! @value w *! Open database for writing *! @value c *! Create database if it does not exist *! @value t *! Overwrite existing database *! @value f *! Fast mode
06d37d2006-03-18Henrik Grubbström (Grubba)  *! @value s *! Synchronous mode *! @value l *! Locking mode
fc293f2001-10-26Martin Nilsson  *! @endstring *! *! The fast mode prevents the database from syncronizing each change *! in the database immediately. This is dangerous because the database *! can be left in an unusable state if Pike is terminated abnormally. *!
cbe8c92003-04-07Martin Nilsson  *! The default mode is @expr{"rwc"@}.
fc293f2001-10-26Martin Nilsson  *! *! @note *! The gdbm manual states that it is important that the database is *! closed properly. Unfortunately this will not be the case if Pike *! calls exit() or returns from main(). You should therefore make sure *! you call close or destruct your gdbm objects when exiting your
e206c12014-08-16Per Hedbor  *! program. *! *! @[atexit] might be useful. *! *! This is very important if the database is used with the 'l' flag.
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_create(INT32 args) { struct gdbm_glue *this=THIS; do_free();
e206c12014-08-16Per Hedbor  if(!args) Pike_error("Need at least one argument to Gdbm.DB, the filename\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(args) { GDBM_FILE tmp; struct pike_string *tmp2;
06d37d2006-03-18Henrik Grubbström (Grubba)  int rwmode = GDBM_WRCREAT|GDBM_NOLOCK;
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to gdbm->create()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(args>1) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[1-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 2 to gdbm->create()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  rwmode=fixmods(sp[1-args].u.string->str); }
06d37d2006-03-18Henrik Grubbström (Grubba)  if (this->dbf) { do_free(); }
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  tmp2=sp[-args].u.string; THREADS_ALLOW(); mt_lock(& gdbm_lock); tmp=gdbm_open(tmp2->str, 512, rwmode, 00666, gdbmmod_fatal); mt_unlock(& gdbm_lock); THREADS_DISALLOW();
39221e2000-07-07Henrik Grubbström (Grubba)  if(!Pike_fp->current_object->prog)
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  { if(tmp) gdbm_close(tmp);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Object destructed in gdbm->open()n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  }
87a8f92003-05-25Martin Nilsson  this->dbf=tmp;
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args);
87a8f92003-05-25Martin Nilsson  if(!this->dbf)
06d37d2006-03-18Henrik Grubbström (Grubba)  Pike_error("Failed to open GDBM database: %d: %s.\n", gdbm_errno, gdbm_strerror(gdbm_errno));
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  } } #define STRING_TO_DATUM(dat, st) dat.dptr=st->str,dat.dsize=st->len; #define DATUM_TO_STRING(dat) make_shared_binary_string(dat.dptr, dat.dsize)
e206c12014-08-16Per Hedbor /*! @decl string(8bit) fetch(string(8bit) key) *! @decl string(8bit) `[](string(8bit) key)
fc293f2001-10-26Martin Nilsson  *! *! Return the data associated with the key 'key' in the database. *! If there was no such key in the database, zero is returned. */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_fetch(INT32 args) { struct gdbm_glue *this=THIS; datum key,ret; if(!args)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Too few arguments to gdbm->fetch()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to gdbm->fetch()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(!THIS->dbf)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  STRING_TO_DATUM(key, sp[-args].u.string); THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_fetch(this->dbf, key); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); pop_n_elems(args); if(ret.dptr) { push_string(DATUM_TO_STRING(ret)); free(ret.dptr); }else{
e206c12014-08-16Per Hedbor  push_undefined();
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  } }
87a8f92003-05-25Martin Nilsson /*! @decl int(0..1) delete(string key)
fc293f2001-10-26Martin Nilsson  *!
87a8f92003-05-25Martin Nilsson  *! Remove a key from the database. Returns 1 if successful, *! otherwise 0, e.g. when the item is not present or the *! database is read only.
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_delete(INT32 args) { struct gdbm_glue *this=THIS; datum key; int ret; if(!args)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Too few arguments to gdbm->delete()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to gdbm->delete()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(!this->dbf)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  STRING_TO_DATUM(key, sp[-args].u.string); THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_delete(this->dbf, key); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); pop_n_elems(args);
87a8f92003-05-25Martin Nilsson  push_int( ret==0 );
a80a9c1997-02-11Fredrik Hübinette (Hubbe) }
e206c12014-08-16Per Hedbor /*! @decl string(8bit) _m_delete( string(8bit) key ) *! *! Provides overloading of the @[m_delete] function. *! *! Will return the value the key had before it was removed, if any *! *! If the key exists but deletion fails (usually due to a read only *! database) this function will throw an error. */ static void gdbmmod_m_delete(INT32 args) { struct gdbm_glue *this=THIS; datum key, ret; if(TYPEOF(sp[-args]) != T_STRING) { push_undefined(); return; } if(!this->dbf) Pike_error("GDBM database not open.\n"); STRING_TO_DATUM(key, sp[-args].u.string); THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_fetch(this->dbf, key); if( ret.dptr ) if( gdbm_delete(this->dbf, key) ) Pike_error("Failed to delete key from database.\n"); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); if(ret.dptr) { push_string(DATUM_TO_STRING(ret)); free(ret.dptr); }else{ push_undefined(); } }
fc293f2001-10-26Martin Nilsson /*! @decl string firstkey() *! *! Return the first key in the database, this can be any key in the *! database.
e206c12014-08-16Per Hedbor  *! *! Used together with @[nextkey] the databse can be iterated. *! *! @note *! The database also works as an @[Iterator], and can be used as the *! first argument to @[foreach]. *! *! Adding or removing keys will change the iteration order, *! this can cause keys to be skipped while iterating. *! *! *! @example *! @code *! // Write the contents of the database *! for(key=gdbm->firstkey(); k; k=gdbm->nextkey(k)) *! write(k+":"+gdbm->fetch(k)+"\n"); *! @endcode *! *! Or, using foreach *! @code *! // Write the contents of the database *! foreach( db; string key; string value ) *! write(key+":"+value+"\n"); *! @endcode
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_firstkey(INT32 args) { struct gdbm_glue *this=THIS; datum ret; pop_n_elems(args);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if(!this->dbf) Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_firstkey(this->dbf); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); if(ret.dptr) { push_string(DATUM_TO_STRING(ret)); free(ret.dptr); }else{ push_int(0); } }
e206c12014-08-16Per Hedbor /*! @decl string(8bit) nextkey(string(8bit) key)
fc293f2001-10-26Martin Nilsson  *! *! This returns the key in database that follows the key 'key' key. *! This is of course used to iterate over all keys in the database. *!
e206c12014-08-16Per Hedbor  *! @note *! Changing (adding or removing keys) the database while iterating *! can cause keys to be skipped. *! *! The database also works as an @[Iterator], and can be used as the *! first argument to @[foreach]. *!
fc293f2001-10-26Martin Nilsson  *! @example
e206c12014-08-16Per Hedbor  *! @code
fc293f2001-10-26Martin Nilsson  *! // Write the contents of the database *! for(key=gdbm->firstkey(); k; k=gdbm->nextkey(k)) *! write(k+":"+gdbm->fetch(k)+"\n");
e206c12014-08-16Per Hedbor  *! @endcode *! *! Or, using foreach *! @code *! // Write the contents of the database *! foreach( db; string key; string value ) *! write(key+":"+value+"\n"); *! @endcode *!
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_nextkey(INT32 args) { struct gdbm_glue *this=THIS; datum key,ret; if(!args)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Too few arguments to gdbm->nextkey()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to gdbm->nextkey()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(!THIS->dbf)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  STRING_TO_DATUM(key, sp[-args].u.string); THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_nextkey(this->dbf, key); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); pop_n_elems(args); if(ret.dptr) { push_string(DATUM_TO_STRING(ret)); free(ret.dptr); }else{ push_int(0); } }
e206c12014-08-16Per Hedbor /*! @decl string `[]= (string(8bit) key, string(8bit) data)
fc293f2001-10-26Martin Nilsson  *! *! Associate the contents of 'data' with the key 'key'. If the key 'key' *! already exists in the database the data for that key will be replaced. *! If it does not exist it will be added. An error will be generated if *! the database was not open for writing. *! *! @example *! gdbm[key] = data;
1788672007-04-25Henrik Grubbström (Grubba)  *! *! @returns *! Returns @[data] on success. *! *! @seealso *! @[store()] */ /*! @decl int store(string key, string data) *! *! Associate the contents of 'data' with the key 'key'. If the key 'key' *! already exists in the database the data for that key will be replaced. *! If it does not exist it will be added. An error will be generated if *! the database was not open for writing. *! *! @example *! gdbm->store(key, data); *! *! @returns *! Returns @expr{1@} on success. *! *! @note *! Note that the returned value differs from that of @[`[]=()]. *! *! @seealso *! @[`[]=()]
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_store(INT32 args) { struct gdbm_glue *this=THIS; datum key,data;
04878b2001-01-23John W. Pierce  int method = GDBM_REPLACE;
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  int ret; if(args<2)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Too few arguments to gdbm->store()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to gdbm->store()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[1-args]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 2 to gdbm->store()\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
04878b2001-01-23John W. Pierce  if (args > 2) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[2-args]) != T_INT) {
04878b2001-01-23John W. Pierce  Pike_error("Bad argument 3 to gdbm->store()\n"); } if (sp[2-args].u.integer) { method = GDBM_INSERT; } }
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  if(!THIS->dbf)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  STRING_TO_DATUM(key, sp[-args].u.string); STRING_TO_DATUM(data, sp[1-args].u.string); THREADS_ALLOW(); mt_lock(& gdbm_lock);
04878b2001-01-23John W. Pierce  ret=gdbm_store(this->dbf, key, data, method);
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  mt_unlock(& gdbm_lock); THREADS_DISALLOW();
04878b2001-01-23John W. Pierce  if(ret == -1) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("GDBM database not open for writing.\n");
04878b2001-01-23John W. Pierce  } else if (ret == 1) { Pike_error("Duplicate key.\n"); }
1788672007-04-25Henrik Grubbström (Grubba)  ref_push_string(sp[1-args].u.string); stack_pop_n_elems_keep_top(args); } /* Compat */ static void gdbmmod_store_compat(INT32 args) { gdbmmod_store(args); pop_stack(); push_int(1);
a80a9c1997-02-11Fredrik Hübinette (Hubbe) }
fc293f2001-10-26Martin Nilsson /*! @decl int reorganize() *! *! Deletions and insertions into the database can cause fragmentation *! which will make the database bigger. This routine reorganizes the *! contents to get rid of fragmentation. Note however that this function
e206c12014-08-16Per Hedbor  *! can take a LOT of time to run if the database is big.
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_reorganize(INT32 args) { struct gdbm_glue *this=THIS; int ret; pop_n_elems(args);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if(!THIS->dbf) Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  THREADS_ALLOW(); mt_lock(& gdbm_lock); ret=gdbm_reorganize(this->dbf); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); pop_n_elems(args); push_int(ret); }
fc293f2001-10-26Martin Nilsson /*! @decl void sync() *! *! When opening the database with the 'f' flag writings to the database *! can be cached in memory for a long time. Calling sync will write *! all such caches to disk and not return until everything is stored *! on the disk. */
e206c12014-08-16Per Hedbor static void gdbmmod_sync(INT32 UNUSED(args))
a80a9c1997-02-11Fredrik Hübinette (Hubbe) { struct gdbm_glue *this=THIS;
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if(!THIS->dbf) Pike_error("GDBM database not open.\n");
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  THREADS_ALLOW(); mt_lock(& gdbm_lock); gdbm_sync(this->dbf); mt_unlock(& gdbm_lock); THREADS_DISALLOW(); push_int(0); }
e206c12014-08-16Per Hedbor  static void gdbmmod_iter_first(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; gdbmmod_firstkey(0); if( Pike_sp[-1].u.string ) this->iter = Pike_sp[-1].u.string; Pike_sp--; push_int( !!this->iter ); } static void gdbmmod_iter_next(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; if(!this->iter) { push_undefined(); return; } push_string( this->iter ); gdbmmod_nextkey(1); if( TYPEOF(Pike_sp[-1]) != PIKE_T_STRING ) { this->iter = 0; push_undefined(); return; } this->iter = Pike_sp[-1].u.string; push_int(1); return; } static void gdbmmod_iter_index(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; if( this->iter ) ref_push_string( this->iter ); else push_undefined(); } static void gdbmmod_iter_no_value(INT32 UNUSED(args)) { push_int( !THIS->iter ); } static void gdbmmod_iter_value(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; if( this->iter ) { ref_push_string( this->iter ); gdbmmod_fetch(1); } else push_undefined(); } /*! @decl array(string(8bit)) _indices() *! *! Provides overloading of @[indices]. *! *! @note *! Mainly useful when debugging, the returned list might not fit in *! memory for large databases. */ static void gdbmmod_indices(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; struct svalue *start = Pike_sp; gdbmmod_iter_first(0); pop_stack(); while( this->iter ) { ref_push_string( this->iter ); gdbmmod_iter_next(0); pop_stack(); } push_array(aggregate_array( Pike_sp-start )); } /*! @decl array(string(8bit)) _values() *! *! Provides overloading of @[values]. *! *! @note *! Mainly useful when debugging, the returned list might not fit in *! memory for large databases. */ static void gdbmmod_values(INT32 UNUSED(args)) { struct gdbm_glue *this=THIS; struct svalue *start = Pike_sp; gdbmmod_iter_first(0); pop_stack(); while( this->iter ) { ref_push_string( this->iter ); gdbmmod_fetch(1); gdbmmod_iter_next(0); pop_stack(); } push_array(aggregate_array( Pike_sp-start )); } static void gdbmmod_get_iterator(INT32 UNUSED(args)) { push_object( clone_object( iterator, 0 ) ); *((struct gdbm_glue *)Pike_sp[-1].u.object->storage) = *THIS; apply(Pike_sp[-1].u.object, "first", 0); pop_stack(); }
fc293f2001-10-26Martin Nilsson /*! @decl void close() *!
e206c12014-08-16Per Hedbor  *! Closes the database. The object is no longer usable after this function has been called. *! *! This is also done automatically when the object is destructed for *! any reason (running out of references or explicit destruct, as an *! example)
fc293f2001-10-26Martin Nilsson  */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) static void gdbmmod_close(INT32 args) { pop_n_elems(args);
1458b91997-08-31Henrik Grubbström (Grubba)  do_free();
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  push_int(0); }
ab05ad2013-11-03Arne Goedeke static void init_gdbm_glue(struct object *UNUSED(o))
a80a9c1997-02-11Fredrik Hübinette (Hubbe) { THIS->dbf=0;
e206c12014-08-16Per Hedbor  THIS->iter=0; } static void init_gdbm_iterator(struct object *UNUSED(o)) { THIS->dbf=0; THIS->iter=0;
a80a9c1997-02-11Fredrik Hübinette (Hubbe) }
ab05ad2013-11-03Arne Goedeke static void exit_gdbm_glue(struct object *UNUSED(o))
a80a9c1997-02-11Fredrik Hübinette (Hubbe) { do_free(); }
e206c12014-08-16Per Hedbor static void exit_gdbm_iterator(struct object *UNUSED(o)) { if( THIS->iter ) free_string( THIS->iter ); }
fc293f2001-10-26Martin Nilsson /*! @endclass */
e206c12014-08-16Per Hedbor /*! @class Iterator *! @inherit predef::Iterator *! *! Object keeping track of an iteration over a @[DB] *! *! @note *! Can not be usefully constructed manually, instead use the database *! as the first argument to @[foreach] or @[predef::get_iterator] *! */ /*! @endclass */
fc293f2001-10-26Martin Nilsson /*! @endmodule */ #endif /* defined(HAVE_GDBM_H) && defined(HAVE_LIBGDBM) */
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
e206c12014-08-16Per Hedbor PIKE_MODULE_EXIT { }
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_INIT
a80a9c1997-02-11Fredrik Hübinette (Hubbe) {
e206c12014-08-16Per Hedbor  struct program *db;
a80a9c1997-02-11Fredrik Hübinette (Hubbe) #if defined(HAVE_GDBM_H) && defined(HAVE_LIBGDBM) start_new_program();
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(struct gdbm_glue);
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void|string,void|string:void) */
04878b2001-01-23John W. Pierce  ADD_FUNCTION("create", gdbmmod_create,
e206c12014-08-16Per Hedbor  tFunc(tOr(tVoid,tStr) tOr(tVoid,tStr), tVoid), ID_PROTECTED);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:void) */
e64f5a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("close",gdbmmod_close,tFunc(tNone,tVoid),0);
04878b2001-01-23John W. Pierce  /* function(string, string, int(0..1)|void: int) */
1788672007-04-25Henrik Grubbström (Grubba)  ADD_FUNCTION("store", gdbmmod_store_compat,
e206c12014-08-16Per Hedbor  tFunc(tStr8 tStr8 tOr(tInt01, tVoid), tInt), 0);
1788672007-04-25Henrik Grubbström (Grubba)  /* function(string, string, int(0..1)|void: string) */
04878b2001-01-23John W. Pierce  ADD_FUNCTION("`[]=", gdbmmod_store,
e206c12014-08-16Per Hedbor  tFunc(tStr8 tSetvar(0, tStr8) tOr(tInt01, tVoid), tVar(0)), 0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:string) */
e206c12014-08-16Per Hedbor  ADD_FUNCTION("fetch",gdbmmod_fetch,tFunc(tStr,tStr8),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:string) */
e206c12014-08-16Per Hedbor  ADD_FUNCTION("`[]",gdbmmod_fetch,tFunc(tStr,tStr8),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:int) */
87a8f92003-05-25Martin Nilsson  ADD_FUNCTION("delete",gdbmmod_delete,tFunc(tStr,tInt01),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:string) */
e206c12014-08-16Per Hedbor  ADD_FUNCTION("firstkey",gdbmmod_firstkey,tFunc(tNone,tStr8),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:string) */
e206c12014-08-16Per Hedbor  ADD_FUNCTION("nextkey",gdbmmod_nextkey,tFunc(tStr,tStr8),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:int) */
e64f5a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("reorganize",gdbmmod_reorganize,tFunc(tNone,tInt),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:void) */
e64f5a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("sync",gdbmmod_sync,tFunc(tNone,tVoid),0);
a80a9c1997-02-11Fredrik Hübinette (Hubbe) 
e206c12014-08-16Per Hedbor  /* iterator API.*/ ADD_FUNCTION("_get_iterator", gdbmmod_get_iterator,tFunc(tNone,tObj),0); /* some mapping operator overloading */ ADD_FUNCTION("_m_delete",gdbmmod_m_delete,tFunc(tStr,tStr8),0); ADD_FUNCTION("_values",gdbmmod_values,tFunc(tNone,tArr(tStr8)),0); ADD_FUNCTION("_indices",gdbmmod_indices,tFunc(tNone,tArr(tStr8)),0);
a80a9c1997-02-11Fredrik Hübinette (Hubbe)  set_init_callback(init_gdbm_glue); set_exit_callback(exit_gdbm_glue);
e206c12014-08-16Per Hedbor  db = end_program(); start_new_program(); ADD_STORAGE(struct gdbm_glue); ADD_FUNCTION("first", gdbmmod_iter_first,tFunc(tNone,tInt01),0); ADD_FUNCTION("next", gdbmmod_iter_next, tFunc(tNone,tInt01),0); ADD_FUNCTION("index", gdbmmod_iter_index,tFunc(tNone,tStr8),0); ADD_FUNCTION("value", gdbmmod_iter_value,tFunc(tNone,tStr8),0); ADD_FUNCTION("`!", gdbmmod_iter_no_value,tFunc(tNone,tInt01),0); set_init_callback(init_gdbm_iterator); set_exit_callback(exit_gdbm_iterator); iterator = end_program(); add_program_constant( "Iterator", iterator, 0 ); add_program_constant( "DB", db, 0 ); add_program_constant( "gdbm", db, 0 ); /* compat (...-7.8). */ free_program(db);
1fbe3e2005-11-14Martin Nilsson #else if(!TEST_COMPAT(7,6)) HIDE_MODULE();
a80a9c1997-02-11Fredrik Hübinette (Hubbe) #endif }