ext/gdbm/gdbm.c


DEFINITIONS

This source file includes following functions.
  1. rb_gdbm_fatal
  2. closed_dbm
  3. free_dbm
  4. fgdbm_close
  5. fgdbm_s_new
  6. fgdbm_initialize
  7. fgdbm_s_open
  8. rb_gdbm_fetch
  9. rb_gdbm_fetch2
  10. rb_gdbm_fetch3
  11. rb_gdbm_firstkey
  12. rb_gdbm_nextkey
  13. fgdbm_fetch
  14. fgdbm_aref
  15. fgdbm_fetch_m
  16. fgdbm_index
  17. fgdbm_indexes
  18. fgdbm_select
  19. rb_gdbm_delete
  20. fgdbm_delete
  21. fgdbm_shift
  22. fgdbm_delete_if
  23. fgdbm_clear
  24. fgdbm_invert
  25. each_pair
  26. update_i
  27. fgdbm_update
  28. fgdbm_replace
  29. fgdbm_store
  30. fgdbm_length
  31. fgdbm_empty_p
  32. fgdbm_each_value
  33. fgdbm_each_key
  34. fgdbm_each_pair
  35. fgdbm_keys
  36. fgdbm_values
  37. fgdbm_has_key
  38. fgdbm_has_value
  39. fgdbm_to_a
  40. fgdbm_reorganize
  41. fgdbm_sync
  42. fgdbm_set_cachesize
  43. fgdbm_set_fastmode
  44. fgdbm_set_syncmode
  45. fgdbm_to_hash
  46. fgdbm_reject
  47. Init_gdbm


   1  /************************************************
   2  
   3    gdbm.c -
   4  
   5    $Author: matz $
   6    $Date: 2002/02/27 04:52:19 $
   7    modified at: Mon Jan 24 15:59:52 JST 1994
   8  
   9  ************************************************/
  10  
  11  #include "ruby.h"
  12  
  13  #include <gdbm.h>
  14  #include <fcntl.h>
  15  #include <errno.h>
  16  
  17  static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError;
  18  
  19  #define MY_BLOCK_SIZE (2048)
  20  #define MY_FATAL_FUNC rb_gdbm_fatal
  21  static void
  22  rb_gdbm_fatal(msg)
  23      char *msg;
  24  {
  25      rb_raise(rb_eGDBMFatalError, msg);
  26  }
  27  
  28  struct dbmdata {
  29      int  di_size;
  30      GDBM_FILE di_dbm;
  31  };
  32  
  33  static void
  34  closed_dbm()
  35  {
  36      rb_raise(rb_eRuntimeError, "closed GDBM file");
  37  }
  38  
  39  #define GetDBM(obj, dbmp) {\
  40      Data_Get_Struct(obj, struct dbmdata, dbmp);\
  41      if (dbmp == 0) closed_dbm();\
  42      if (dbmp->di_dbm == 0) closed_dbm();\
  43  }
  44  
  45  static void
  46  free_dbm(dbmp)
  47      struct dbmdata *dbmp;
  48  {
  49      if (dbmp) {
  50          if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
  51          free(dbmp);
  52      }
  53  }
  54  
  55  static VALUE
  56  fgdbm_close(obj)
  57      VALUE obj;
  58  {
  59      struct dbmdata *dbmp;
  60  
  61      GetDBM(obj, dbmp);
  62      gdbm_close(dbmp->di_dbm);
  63      dbmp->di_dbm = 0;
  64  
  65      return Qnil;
  66  }
  67  
  68  static VALUE
  69  fgdbm_s_new(argc, argv, klass)
  70      int argc;
  71      VALUE *argv;
  72      VALUE klass;
  73  {
  74      VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
  75      rb_obj_call_init(obj, argc, argv);
  76      return obj;
  77  }
  78  
  79  static VALUE
  80  fgdbm_initialize(argc, argv, obj)
  81      int argc;
  82      VALUE *argv;
  83      VALUE obj;
  84  {
  85      VALUE file, vmode, vflags;
  86      GDBM_FILE dbm;
  87      struct dbmdata *dbmp;
  88      int mode, flags = 0;
  89  
  90      if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
  91          mode = 0666;            /* default value */
  92      }
  93      else if (NIL_P(vmode)) {
  94          mode = -1;              /* return nil if DB not exist */
  95      }
  96      else {
  97          mode = NUM2INT(vmode);
  98      }
  99  
 100      if (!NIL_P(vflags))
 101          flags = NUM2INT(vflags);
 102  
 103      SafeStringValue(file);
 104  
 105      dbm = 0;
 106      if (mode >= 0)
 107          dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
 108                          GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC);
 109      if (!dbm)
 110          dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
 111                          GDBM_WRITER|flags, 0, MY_FATAL_FUNC);
 112      if (!dbm)
 113          dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
 114                          GDBM_READER|flags, 0, MY_FATAL_FUNC);
 115  
 116      if (!dbm) {
 117          if (mode == -1) return Qnil;
 118  
 119          if (gdbm_errno == GDBM_FILE_OPEN_ERROR ||
 120              gdbm_errno == GDBM_CANT_BE_READER ||
 121              gdbm_errno == GDBM_CANT_BE_WRITER)
 122              rb_sys_fail(RSTRING(file)->ptr);
 123          else
 124              rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 125      }
 126  
 127      dbmp = ALLOC(struct dbmdata);
 128      DATA_PTR(obj) = dbmp;
 129      dbmp->di_dbm = dbm;
 130      dbmp->di_size = -1;
 131  
 132      return obj;
 133  }
 134  
 135  static VALUE
 136  fgdbm_s_open(argc, argv, klass)
 137      int argc;
 138      VALUE *argv;
 139      VALUE klass;
 140  {
 141      VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
 142  
 143      if (NIL_P(fgdbm_initialize(argc, argv, obj))) {
 144          return Qnil;
 145      }
 146  
 147      if (rb_block_given_p()) {
 148          return rb_ensure(rb_yield, obj, fgdbm_close, obj);
 149      }
 150  
 151      return obj;
 152  }
 153  
 154  static VALUE
 155  rb_gdbm_fetch(dbm, key)
 156      GDBM_FILE dbm;
 157      datum key;
 158  {
 159      datum val;
 160      VALUE str;
 161  
 162      val = gdbm_fetch(dbm, key);
 163      if (val.dptr == 0)
 164          return Qnil;
 165  
 166      str = rb_obj_alloc(rb_cString);
 167      RSTRING(str)->len = val.dsize;
 168      RSTRING(str)->aux.capa = val.dsize;
 169      RSTRING(str)->ptr = REALLOC_N(val.dptr,char,val.dsize+1);
 170      RSTRING(str)->ptr[val.dsize] = '\0';
 171  
 172      OBJ_TAINT(str);
 173      return (VALUE)str;
 174  }
 175  
 176  static VALUE
 177  rb_gdbm_fetch2(dbm, keystr)
 178      GDBM_FILE dbm;
 179      VALUE keystr;
 180  {
 181      datum key;
 182  
 183      StringValue(keystr);
 184      key.dptr = RSTRING(keystr)->ptr;
 185      key.dsize = RSTRING(keystr)->len;
 186  
 187      return rb_gdbm_fetch(dbm, key);
 188  }
 189  
 190  static VALUE
 191  rb_gdbm_fetch3(obj, keystr)
 192      VALUE obj, keystr;
 193  {
 194      struct dbmdata *dbmp;
 195      GDBM_FILE dbm;
 196  
 197      GetDBM(obj, dbmp);
 198      dbm = dbmp->di_dbm;
 199      return rb_gdbm_fetch2(dbm, keystr);
 200  }
 201  
 202  static VALUE
 203  rb_gdbm_firstkey(dbm)
 204      GDBM_FILE dbm;
 205  {
 206      datum key;
 207      VALUE str;
 208  
 209      key = gdbm_firstkey(dbm);
 210      if (key.dptr == 0)
 211          return Qnil;
 212  
 213      str = rb_obj_alloc(rb_cString);
 214      RSTRING(str)->len = key.dsize;
 215      RSTRING(str)->aux.capa = key.dsize;
 216      RSTRING(str)->ptr = REALLOC_N(key.dptr,char,key.dsize+1);
 217      RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
 218  
 219      OBJ_TAINT(str);
 220      return str;
 221  }
 222  
 223  static VALUE
 224  rb_gdbm_nextkey(dbm, keystr)
 225      GDBM_FILE dbm;
 226      VALUE keystr;
 227  {
 228      datum key, key2;
 229      VALUE str;
 230  
 231      key.dptr = RSTRING(keystr)->ptr;
 232      key.dsize = RSTRING(keystr)->len;
 233      key2 = gdbm_nextkey(dbm, key);
 234      if (key2.dptr == 0)
 235          return Qnil;
 236  
 237      str = rb_obj_alloc(rb_cString);
 238      RSTRING(str)->len = key2.dsize;
 239      RSTRING(str)->aux.capa = key2.dsize;
 240      RSTRING(str)->ptr = REALLOC_N(key2.dptr,char,key2.dsize+1);
 241      RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
 242  
 243      OBJ_TAINT(str);
 244      return str;
 245  }
 246  
 247  static VALUE
 248  fgdbm_fetch(obj, keystr, ifnone)
 249      VALUE obj, keystr, ifnone;
 250  {
 251      VALUE valstr;
 252  
 253      valstr = rb_gdbm_fetch3(obj, keystr);
 254      if (NIL_P(valstr)) {
 255          if (ifnone == Qnil && rb_block_given_p())
 256              return rb_yield(keystr);
 257          return ifnone;
 258      }
 259      return valstr;
 260  }
 261  
 262  static VALUE
 263  fgdbm_aref(obj, keystr)
 264      VALUE obj, keystr;
 265  {
 266      return rb_gdbm_fetch3(obj, keystr);
 267  }
 268  
 269  static VALUE
 270  fgdbm_fetch_m(argc, argv, obj)
 271      int argc;
 272      VALUE *argv;
 273      VALUE obj;
 274  {
 275      VALUE keystr, valstr, ifnone;
 276  
 277      rb_scan_args(argc, argv, "11", &keystr, &ifnone);
 278      valstr = fgdbm_fetch(obj, keystr, ifnone);
 279      if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
 280          rb_raise(rb_eIndexError, "key not found");
 281  
 282      return valstr;
 283  }
 284  
 285  static VALUE
 286  fgdbm_index(obj, valstr)
 287      VALUE obj, valstr;
 288  {
 289      struct dbmdata *dbmp;
 290      GDBM_FILE dbm;
 291      VALUE keystr, valstr2;
 292  
 293      StringValue(valstr);
 294      GetDBM(obj, dbmp);
 295      dbm = dbmp->di_dbm;
 296      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 297           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 298  
 299          valstr2 = rb_gdbm_fetch2(dbm, keystr);
 300          if (!NIL_P(valstr2) &&
 301              RSTRING(valstr)->len == RSTRING(valstr2)->len &&
 302              memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr,
 303                     RSTRING(valstr)->len) == 0) {
 304              return keystr;
 305          }
 306      }
 307      return Qnil;
 308  }
 309  
 310  static VALUE
 311  fgdbm_indexes(argc, argv, obj)
 312      int argc;
 313      VALUE *argv;
 314      VALUE obj;
 315  {
 316      VALUE new;
 317      int i;
 318  
 319      new = rb_ary_new2(argc);
 320      for (i=0; i<argc; i++) {
 321          rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i]));
 322      }
 323  
 324      return new;
 325  }
 326  
 327  static VALUE
 328  fgdbm_select(argc, argv, obj)
 329      int argc;
 330      VALUE *argv;
 331      VALUE obj;
 332  {
 333      VALUE new = rb_ary_new2(argc);
 334      int i;
 335  
 336      if (rb_block_given_p()) {
 337          GDBM_FILE dbm;
 338          struct dbmdata *dbmp;
 339          VALUE keystr;
 340  
 341          if (argc > 0) {
 342              rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
 343          }
 344          GetDBM(obj, dbmp);
 345          dbm = dbmp->di_dbm;
 346  
 347          for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 348               keystr = rb_gdbm_nextkey(dbm, keystr)) {
 349              VALUE assoc = rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr));
 350  
 351              if (RTEST(rb_yield(assoc)))
 352                  rb_ary_push(new, assoc);
 353          }
 354      }
 355      else {
 356          for (i=0; i<argc; i++) {
 357              rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i]));
 358          }
 359      }
 360  
 361      return new;
 362  }
 363  
 364  static VALUE
 365  rb_gdbm_delete(obj, keystr)
 366      VALUE obj, keystr;
 367  {
 368      datum key;
 369      struct dbmdata *dbmp;
 370      GDBM_FILE dbm;
 371  
 372      rb_secure(4);
 373      StringValue(keystr);
 374      key.dptr = RSTRING(keystr)->ptr;
 375      key.dsize = RSTRING(keystr)->len;
 376  
 377      GetDBM(obj, dbmp);
 378      dbm = dbmp->di_dbm;
 379  
 380      if (!gdbm_exists(dbm, key)) {
 381          return Qnil;
 382      }
 383  
 384      if (gdbm_delete(dbm, key)) {
 385          dbmp->di_size = -1;
 386          rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 387      }
 388      else if (dbmp->di_size >= 0) {
 389          dbmp->di_size--;
 390      }
 391      return obj;
 392  }
 393  
 394  static VALUE
 395  fgdbm_delete(obj, keystr)
 396      VALUE obj, keystr;
 397  {
 398      VALUE valstr;
 399  
 400      valstr = fgdbm_fetch(obj, keystr, Qnil);
 401      rb_gdbm_delete(obj, keystr);
 402      return valstr;
 403  }
 404  
 405  static VALUE
 406  fgdbm_shift(obj)
 407      VALUE obj;
 408  {
 409      struct dbmdata *dbmp;
 410      GDBM_FILE dbm;
 411      VALUE keystr, valstr;
 412  
 413      rb_secure(4);
 414      GetDBM(obj, dbmp);
 415      dbm = dbmp->di_dbm;
 416  
 417      keystr = rb_gdbm_firstkey(dbm);
 418      if (NIL_P(keystr)) return Qnil;
 419      valstr = rb_gdbm_fetch2(dbm, keystr);
 420      rb_gdbm_delete(obj, keystr);
 421  
 422      return rb_assoc_new(keystr, valstr);
 423  }
 424  
 425  static VALUE
 426  fgdbm_delete_if(obj)
 427      VALUE obj;
 428  {
 429      struct dbmdata *dbmp;
 430      GDBM_FILE dbm;
 431      VALUE keystr, valstr;
 432      VALUE ret, ary = rb_ary_new();
 433      int i, status = 0, n;
 434  
 435      rb_secure(4);
 436      GetDBM(obj, dbmp);
 437      dbm = dbmp->di_dbm;
 438      n = dbmp->di_size;
 439      dbmp->di_size = -1;
 440  
 441      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 442           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 443  
 444          valstr = rb_gdbm_fetch2(dbm, keystr);
 445          ret = rb_protect(rb_yield, rb_assoc_new(keystr, valstr), &status);
 446          if (status != 0) break;
 447          if (RTEST(ret)) rb_ary_push(ary, keystr);
 448      }
 449  
 450      for (i = 0; i < RARRAY(ary)->len; i++)
 451          rb_gdbm_delete(obj, RARRAY(ary)->ptr[i]);
 452      if (status) rb_jump_tag(status);
 453      if (n > 0) dbmp->di_size = n - RARRAY(ary)->len;
 454  
 455      return obj;
 456  }
 457  
 458  static VALUE
 459  fgdbm_clear(obj)
 460      VALUE obj;
 461  {
 462      datum key, nextkey;
 463      struct dbmdata *dbmp;
 464      GDBM_FILE dbm;
 465  
 466      rb_secure(4);
 467      GetDBM(obj, dbmp);
 468      dbm = dbmp->di_dbm;
 469      dbmp->di_size = -1;
 470  
 471  #if 0
 472      while (key = gdbm_firstkey(dbm), key.dptr) {
 473          if (gdbm_delete(dbm, key)) {
 474              free(key.dptr);
 475              rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 476          }
 477          free(key.dptr); 
 478      }
 479  #else
 480      while (key = gdbm_firstkey(dbm), key.dptr) {
 481          for (; key.dptr; key = nextkey) {
 482              nextkey = gdbm_nextkey(dbm, key);
 483              if (gdbm_delete(dbm, key)) {
 484                  free(key.dptr);
 485                  if (nextkey.dptr) free(nextkey.dptr);
 486                  rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 487              }
 488              free(key.dptr);
 489          }
 490      }
 491  #endif
 492      dbmp->di_size = 0;
 493  
 494      return obj;
 495  }
 496  
 497  static VALUE
 498  fgdbm_invert(obj)
 499      VALUE obj;
 500  {
 501      struct dbmdata *dbmp;
 502      GDBM_FILE dbm;
 503      VALUE keystr, valstr;
 504      VALUE hash = rb_hash_new();
 505  
 506      GetDBM(obj, dbmp);
 507      dbm = dbmp->di_dbm;
 508      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 509           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 510          valstr = rb_gdbm_fetch2(dbm, keystr);
 511  
 512          rb_hash_aset(hash, valstr, keystr);
 513      }
 514      return hash;
 515  }
 516  
 517  static VALUE
 518  each_pair(obj)
 519      VALUE obj;
 520  {
 521      return rb_funcall(obj, rb_intern("each_pair"), 0, 0);
 522  }
 523  
 524  static VALUE fgdbm_store _((VALUE,VALUE,VALUE));
 525  
 526  static VALUE
 527  update_i(pair, dbm)
 528      VALUE pair, dbm;
 529  {
 530      Check_Type(pair, T_ARRAY);
 531      if (RARRAY(pair)->len < 2) {
 532          rb_raise(rb_eArgError, "pair must be [key, value]");
 533      }
 534      fgdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]);
 535      return Qnil;
 536  }
 537  
 538  static VALUE
 539  fgdbm_update(obj, other)
 540      VALUE obj, other;
 541  {
 542      rb_iterate(each_pair, other, update_i, obj);
 543      return obj;
 544  }
 545  
 546  static VALUE
 547  fgdbm_replace(obj, other)
 548      VALUE obj, other;
 549  {
 550      fgdbm_clear(obj);
 551      rb_iterate(each_pair, other, update_i, obj);
 552      return obj;
 553  }
 554  
 555  static VALUE
 556  fgdbm_store(obj, keystr, valstr)
 557      VALUE obj, keystr, valstr;
 558  {
 559      datum key, val;
 560      struct dbmdata *dbmp;
 561      GDBM_FILE dbm;
 562  
 563      rb_secure(4);
 564      StringValue(keystr);
 565      key.dptr = RSTRING(keystr)->ptr;
 566      key.dsize = RSTRING(keystr)->len;
 567  
 568      StringValue(valstr);
 569      val.dptr = RSTRING(valstr)->ptr;
 570      val.dsize = RSTRING(valstr)->len;
 571  
 572      GetDBM(obj, dbmp);
 573      dbmp->di_size = -1;
 574      dbm = dbmp->di_dbm;
 575      if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
 576          if (errno == EPERM) rb_sys_fail(0);
 577          rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 578      }
 579  
 580      return valstr;
 581  }
 582  
 583  static VALUE
 584  fgdbm_length(obj)
 585      VALUE obj;
 586  {
 587      datum key, nextkey;
 588      struct dbmdata *dbmp;
 589      GDBM_FILE dbm;
 590      int i = 0;
 591  
 592      GetDBM(obj, dbmp);
 593      if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
 594      dbm = dbmp->di_dbm;
 595  
 596      for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
 597          nextkey = gdbm_nextkey(dbm, key);
 598          free(key.dptr);
 599          i++;
 600      }
 601      dbmp->di_size = i;
 602  
 603      return INT2FIX(i);
 604  }
 605  
 606  static VALUE
 607  fgdbm_empty_p(obj)
 608      VALUE obj;
 609  {
 610      datum key;
 611      struct dbmdata *dbmp;
 612      GDBM_FILE dbm;
 613  
 614      GetDBM(obj, dbmp);
 615      if (dbmp->di_size < 0) {
 616          dbm = dbmp->di_dbm;
 617  
 618          key = gdbm_firstkey(dbm);
 619          if (key.dptr) {
 620              free(key.dptr);
 621              return Qfalse;
 622          }
 623          return Qtrue;
 624      }
 625  
 626      if (dbmp->di_size == 0) return Qtrue;
 627      return Qfalse;
 628  }
 629  
 630  static VALUE
 631  fgdbm_each_value(obj)
 632      VALUE obj;
 633  {
 634      struct dbmdata *dbmp;
 635      GDBM_FILE dbm;
 636      VALUE keystr;
 637  
 638      GetDBM(obj, dbmp);
 639      dbm = dbmp->di_dbm;
 640  
 641      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 642           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 643  
 644          rb_yield(rb_gdbm_fetch2(dbm, keystr));
 645      }
 646      return obj;
 647  }
 648  
 649  static VALUE
 650  fgdbm_each_key(obj)
 651      VALUE obj;
 652  {
 653      struct dbmdata *dbmp;
 654      GDBM_FILE dbm;
 655      VALUE keystr;
 656  
 657      GetDBM(obj, dbmp);
 658      dbm = dbmp->di_dbm;
 659  
 660      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 661           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 662  
 663          rb_yield(keystr);
 664      }
 665      return obj;
 666  }
 667  
 668  static VALUE
 669  fgdbm_each_pair(obj)
 670      VALUE obj;
 671  {
 672      GDBM_FILE dbm;
 673      struct dbmdata *dbmp;
 674      VALUE keystr;
 675  
 676      GetDBM(obj, dbmp);
 677      dbm = dbmp->di_dbm;
 678  
 679      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 680           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 681  
 682          rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
 683      }
 684  
 685      return obj;
 686  }
 687  
 688  static VALUE
 689  fgdbm_keys(obj)
 690      VALUE obj;
 691  {
 692      struct dbmdata *dbmp;
 693      GDBM_FILE dbm;
 694      VALUE keystr, ary;
 695  
 696      GetDBM(obj, dbmp);
 697      dbm = dbmp->di_dbm;
 698  
 699      ary = rb_ary_new();
 700      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 701           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 702  
 703          rb_ary_push(ary, keystr);
 704      }
 705  
 706      return ary;
 707  }
 708  
 709  static VALUE
 710  fgdbm_values(obj)
 711      VALUE obj;
 712  {
 713      datum key, nextkey;
 714      struct dbmdata *dbmp;
 715      GDBM_FILE dbm;
 716      VALUE valstr, ary;
 717  
 718      GetDBM(obj, dbmp);
 719      dbm = dbmp->di_dbm;
 720  
 721      ary = rb_ary_new();
 722      for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
 723          nextkey = gdbm_nextkey(dbm, key);
 724          valstr = rb_gdbm_fetch(dbm, key);
 725          free(key.dptr);
 726          rb_ary_push(ary, valstr);
 727      }
 728  
 729      return ary;
 730  }
 731  
 732  static VALUE
 733  fgdbm_has_key(obj, keystr)
 734      VALUE obj, keystr;
 735  {
 736      datum key;
 737      struct dbmdata *dbmp;
 738      GDBM_FILE dbm;
 739  
 740      StringValue(keystr);
 741      key.dptr = RSTRING(keystr)->ptr;
 742      key.dsize = RSTRING(keystr)->len;
 743  
 744      GetDBM(obj, dbmp);
 745      dbm = dbmp->di_dbm;
 746      if (gdbm_exists(dbm, key))
 747          return Qtrue;
 748      return Qfalse;
 749  }
 750  
 751  static VALUE
 752  fgdbm_has_value(obj, valstr)
 753      VALUE obj, valstr;
 754  {
 755      struct dbmdata *dbmp;
 756      GDBM_FILE dbm;
 757      VALUE keystr, valstr2;
 758  
 759      StringValue(valstr);
 760      GetDBM(obj, dbmp);
 761      dbm = dbmp->di_dbm;
 762      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 763           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 764  
 765          valstr2 = rb_gdbm_fetch2(dbm, keystr);
 766  
 767          if (!NIL_P(valstr2) &&
 768              RSTRING(valstr)->len == RSTRING(valstr2)->len &&
 769              memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr,
 770                     RSTRING(valstr)->len) == 0) {
 771              return Qtrue;
 772          }
 773      }
 774      return Qfalse;
 775  }
 776  
 777  static VALUE
 778  fgdbm_to_a(obj)
 779      VALUE obj;
 780  {
 781      struct dbmdata *dbmp;
 782      GDBM_FILE dbm;
 783      VALUE keystr, ary;
 784  
 785      GetDBM(obj, dbmp);
 786      dbm = dbmp->di_dbm;
 787  
 788      ary = rb_ary_new();
 789      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 790           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 791  
 792          rb_ary_push(ary, rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
 793      }
 794  
 795      return ary;
 796  }
 797  
 798  static VALUE
 799  fgdbm_reorganize(obj)
 800      VALUE obj;
 801  {
 802      struct dbmdata *dbmp;
 803      GDBM_FILE dbm;
 804  
 805      rb_secure(4);
 806      GetDBM(obj, dbmp);
 807      dbm = dbmp->di_dbm;
 808      gdbm_reorganize(dbm);
 809      return obj;
 810  }
 811  
 812  static VALUE
 813  fgdbm_sync(obj)
 814      VALUE obj;
 815  {
 816      struct dbmdata *dbmp;
 817      GDBM_FILE dbm;
 818  
 819      rb_secure(4);
 820      GetDBM(obj, dbmp);
 821      dbm = dbmp->di_dbm;
 822      gdbm_sync(dbm);
 823      return obj;
 824  }
 825  
 826  static VALUE
 827  fgdbm_set_cachesize(obj, val)
 828      VALUE obj, val;
 829  {
 830      struct dbmdata *dbmp;
 831      GDBM_FILE dbm;
 832      int optval;
 833  
 834      GetDBM(obj, dbmp);
 835      dbm = dbmp->di_dbm;
 836  
 837      optval = FIX2INT(val);
 838      if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
 839          rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 840      }
 841      return val;
 842  }
 843  
 844  static VALUE
 845  fgdbm_set_fastmode(obj, val)
 846      VALUE obj, val;
 847  {
 848      struct dbmdata *dbmp;
 849      GDBM_FILE dbm;
 850      int optval;
 851  
 852      GetDBM(obj, dbmp);
 853      dbm = dbmp->di_dbm;
 854  
 855      optval = 0;
 856      if (RTEST(val))
 857          optval = 1;
 858  
 859      if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
 860          rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 861      }
 862      return val;
 863  }
 864  
 865  static VALUE
 866  fgdbm_set_syncmode(obj, val)
 867      VALUE obj, val;
 868  {
 869  #if !defined(GDBM_SYNCMODE)
 870      fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue);
 871      return val;
 872  #else
 873      struct dbmdata *dbmp;
 874      GDBM_FILE dbm;
 875      int optval;
 876  
 877      GetDBM(obj, dbmp);
 878      dbm = dbmp->di_dbm;
 879  
 880      optval = 0;
 881      if (RTEST(val))
 882          optval = 1;
 883  
 884      if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
 885          rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
 886      }
 887      return val;
 888  #endif
 889  }
 890  
 891  static VALUE
 892  fgdbm_to_hash(obj)
 893      VALUE obj;
 894  {
 895      struct dbmdata *dbmp;
 896      GDBM_FILE dbm;
 897      VALUE keystr, hash;
 898  
 899      GetDBM(obj, dbmp);
 900      dbm = dbmp->di_dbm;
 901  
 902      hash = rb_hash_new();
 903      for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
 904           keystr = rb_gdbm_nextkey(dbm, keystr)) {
 905  
 906          rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr));
 907      }
 908  
 909      return hash;
 910  }
 911  
 912  static VALUE
 913  fgdbm_reject(obj)
 914      VALUE obj;
 915  {
 916      return rb_hash_delete_if(fgdbm_to_hash(obj));
 917  }
 918  
 919  void
 920  Init_gdbm()
 921  {
 922      rb_cGDBM = rb_define_class("GDBM", rb_cObject);
 923      rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
 924      rb_eGDBMFatalError = rb_define_class("GDBMFatalError", rb_eException);
 925      rb_include_module(rb_cGDBM, rb_mEnumerable);
 926  
 927      rb_define_singleton_method(rb_cGDBM, "new", fgdbm_s_new, -1);
 928      rb_define_singleton_method(rb_cGDBM, "open", fgdbm_s_open, -1);
 929  
 930      rb_define_method(rb_cGDBM, "initialize", fgdbm_initialize, -1);
 931      rb_define_method(rb_cGDBM, "close", fgdbm_close, 0);
 932      rb_define_method(rb_cGDBM, "[]", fgdbm_aref, 1);
 933      rb_define_method(rb_cGDBM, "fetch", fgdbm_fetch_m, -1);
 934      rb_define_method(rb_cGDBM, "[]=", fgdbm_store, 2);
 935      rb_define_method(rb_cGDBM, "store", fgdbm_store, 2);
 936      rb_define_method(rb_cGDBM, "index",  fgdbm_index, 1);
 937      rb_define_method(rb_cGDBM, "indexes",  fgdbm_indexes, -1);
 938      rb_define_method(rb_cGDBM, "indices",  fgdbm_indexes, -1);
 939      rb_define_method(rb_cGDBM, "select",  fgdbm_select, -1);
 940      rb_define_method(rb_cGDBM, "length", fgdbm_length, 0);
 941      rb_define_method(rb_cGDBM, "size", fgdbm_length, 0);
 942      rb_define_method(rb_cGDBM, "empty?", fgdbm_empty_p, 0);
 943      rb_define_method(rb_cGDBM, "each", fgdbm_each_pair, 0);
 944      rb_define_method(rb_cGDBM, "each_value", fgdbm_each_value, 0);
 945      rb_define_method(rb_cGDBM, "each_key", fgdbm_each_key, 0);
 946      rb_define_method(rb_cGDBM, "each_pair", fgdbm_each_pair, 0);
 947      rb_define_method(rb_cGDBM, "keys", fgdbm_keys, 0);
 948      rb_define_method(rb_cGDBM, "values", fgdbm_values, 0);
 949      rb_define_method(rb_cGDBM, "shift", fgdbm_shift, 0);
 950      rb_define_method(rb_cGDBM, "delete", fgdbm_delete, 1);
 951      rb_define_method(rb_cGDBM, "delete_if", fgdbm_delete_if, 0);
 952      rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0);
 953      rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0);
 954      rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0);
 955      rb_define_method(rb_cGDBM,"invert", fgdbm_invert, 0);
 956      rb_define_method(rb_cGDBM,"update", fgdbm_update, 1);
 957      rb_define_method(rb_cGDBM,"replace", fgdbm_replace, 1);
 958      rb_define_method(rb_cGDBM,"reorganize", fgdbm_reorganize, 0);
 959      rb_define_method(rb_cGDBM,"sync", fgdbm_sync, 0);
 960      /* rb_define_method(rb_cGDBM,"setopt", fgdbm_setopt, 2); */
 961      rb_define_method(rb_cGDBM,"cachesize=", fgdbm_set_cachesize, 1);
 962      rb_define_method(rb_cGDBM,"fastmode=", fgdbm_set_fastmode, 1);
 963      rb_define_method(rb_cGDBM,"syncmode=", fgdbm_set_syncmode, 1);
 964  
 965      rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1);
 966      rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1);
 967      rb_define_method(rb_cGDBM, "member?", fgdbm_has_key, 1);
 968      rb_define_method(rb_cGDBM, "has_value?", fgdbm_has_value, 1);
 969      rb_define_method(rb_cGDBM, "key?", fgdbm_has_key, 1);
 970      rb_define_method(rb_cGDBM, "value?", fgdbm_has_value, 1);
 971  
 972      rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0);
 973      rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0);
 974  
 975      /* flags for gdbm_opn() */
 976      /*
 977      rb_define_const(rb_cGDBM, "READER",  INT2FIX(GDBM_READER));
 978      rb_define_const(rb_cGDBM, "WRITER",  INT2FIX(GDBM_WRITER));
 979      rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT));
 980      rb_define_const(rb_cGDBM, "NEWDB",   INT2FIX(GDBM_NEWDB));
 981      */
 982      rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
 983      /* this flag is obsolete in gdbm 1.8.
 984         On gdbm 1.8, fast mode is default behavior. */
 985  
 986      /* gdbm version 1.8 specific */
 987  #if defined(GDBM_SYNC)
 988      rb_define_const(rb_cGDBM, "SYNC",    INT2FIX(GDBM_SYNC));
 989  #endif
 990  #if defined(GDBM_NOLOCK)
 991      rb_define_const(rb_cGDBM, "NOLOCK",  INT2FIX(GDBM_NOLOCK));
 992  #endif
 993      rb_define_const(rb_cGDBM, "VERSION",  rb_str_new2(gdbm_version));
 994  }