PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/dbm/dbm.c

https://github.com/thepelkus/ruby
C | 1133 lines | 676 code | 128 blank | 329 comment | 94 complexity | c9c3ce036091f7f9ff099ef365a35d2c MD5 | raw file
Possible License(s): 0BSD, Unlicense, GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. /************************************************
  2. dbm.c -
  3. $Author$
  4. created at: Mon Jan 24 15:59:52 JST 1994
  5. Copyright (C) 1995-2001 Yukihiro Matsumoto
  6. ************************************************/
  7. #include "ruby.h"
  8. #ifdef HAVE_CDEFS_H
  9. # include <cdefs.h>
  10. #endif
  11. #ifdef HAVE_SYS_CDEFS_H
  12. # include <sys/cdefs.h>
  13. #endif
  14. #include DBM_HDR
  15. #include <fcntl.h>
  16. #include <errno.h>
  17. #define DSIZE_TYPE TYPEOF_DATUM_DSIZE
  18. #if SIZEOF_DATUM_DSIZE > SIZEOF_INT
  19. # define RSTRING_DSIZE(s) RSTRING_LEN(s)
  20. # define TOO_LONG(n) 0
  21. #else
  22. # define RSTRING_DSIZE(s) RSTRING_LENINT(s)
  23. # define TOO_LONG(n) ((long)(+(DSIZE_TYPE)(n)) != (n))
  24. #endif
  25. static VALUE rb_cDBM, rb_eDBMError;
  26. #define RUBY_DBM_RW_BIT 0x20000000
  27. struct dbmdata {
  28. long di_size;
  29. DBM *di_dbm;
  30. };
  31. static void
  32. closed_dbm(void)
  33. {
  34. rb_raise(rb_eDBMError, "closed DBM file");
  35. }
  36. #define GetDBM(obj, dbmp) {\
  37. Data_Get_Struct((obj), struct dbmdata, (dbmp));\
  38. if ((dbmp) == 0) closed_dbm();\
  39. if ((dbmp)->di_dbm == 0) closed_dbm();\
  40. }
  41. #define GetDBM2(obj, data, dbm) {\
  42. GetDBM((obj), (data));\
  43. (dbm) = dbmp->di_dbm;\
  44. }
  45. static void
  46. free_dbm(struct dbmdata *dbmp)
  47. {
  48. if (dbmp) {
  49. if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
  50. xfree(dbmp);
  51. }
  52. }
  53. /*
  54. * call-seq:
  55. * dbm.close
  56. *
  57. * Closes the database.
  58. */
  59. static VALUE
  60. fdbm_close(VALUE obj)
  61. {
  62. struct dbmdata *dbmp;
  63. GetDBM(obj, dbmp);
  64. dbm_close(dbmp->di_dbm);
  65. dbmp->di_dbm = 0;
  66. return Qnil;
  67. }
  68. /*
  69. * call-seq:
  70. * dbm.closed? -> true or false
  71. *
  72. * Returns true if the database is closed, false otherwise.
  73. */
  74. static VALUE
  75. fdbm_closed(VALUE obj)
  76. {
  77. struct dbmdata *dbmp;
  78. Data_Get_Struct(obj, struct dbmdata, dbmp);
  79. if (dbmp == 0)
  80. return Qtrue;
  81. if (dbmp->di_dbm == 0)
  82. return Qtrue;
  83. return Qfalse;
  84. }
  85. static VALUE
  86. fdbm_alloc(VALUE klass)
  87. {
  88. return Data_Wrap_Struct(klass, 0, free_dbm, 0);
  89. }
  90. /*
  91. * call-seq:
  92. * DBM.new(filename[, mode[, flags]]) -> dbm
  93. *
  94. * Open a dbm database with the specified name, which can include a directory
  95. * path. Any file extensions needed will be supplied automatically by the dbm
  96. * library. For example, Berkeley DB appends '.db', and GNU gdbm uses two
  97. * physical files with extensions '.dir' and '.pag'.
  98. *
  99. * The mode should be an integer, as for Unix chmod.
  100. *
  101. * Flags should be one of READER, WRITER, WRCREAT or NEWDB.
  102. */
  103. static VALUE
  104. fdbm_initialize(int argc, VALUE *argv, VALUE obj)
  105. {
  106. volatile VALUE file;
  107. VALUE vmode, vflags;
  108. DBM *dbm;
  109. struct dbmdata *dbmp;
  110. int mode, flags = 0;
  111. if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
  112. mode = 0666; /* default value */
  113. }
  114. else if (NIL_P(vmode)) {
  115. mode = -1; /* return nil if DB not exist */
  116. }
  117. else {
  118. mode = NUM2INT(vmode);
  119. }
  120. if (!NIL_P(vflags))
  121. flags = NUM2INT(vflags);
  122. FilePathValue(file);
  123. /*
  124. * Note:
  125. * gdbm 1.10 works with O_CLOEXEC. gdbm 1.9.1 silently ignore it.
  126. */
  127. #ifndef O_CLOEXEC
  128. # define O_CLOEXEC 0
  129. #endif
  130. if (flags & RUBY_DBM_RW_BIT) {
  131. flags &= ~RUBY_DBM_RW_BIT;
  132. dbm = dbm_open(RSTRING_PTR(file), flags|O_CLOEXEC, mode);
  133. }
  134. else {
  135. dbm = 0;
  136. if (mode >= 0) {
  137. dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT|O_CLOEXEC, mode);
  138. }
  139. if (!dbm) {
  140. dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CLOEXEC, 0);
  141. }
  142. if (!dbm) {
  143. dbm = dbm_open(RSTRING_PTR(file), O_RDONLY|O_CLOEXEC, 0);
  144. }
  145. }
  146. if (dbm) {
  147. /*
  148. * History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
  149. * (dbm_pagfno() and dbm_dirfno() is not standardized.)
  150. *
  151. * 1986: 4.3BSD provides ndbm.
  152. * It provides dbm_pagfno() and dbm_dirfno() as macros.
  153. * 1991: gdbm-1.5 provides them as functions.
  154. * They returns a same descriptor.
  155. * (Earlier releases may have the functions too.)
  156. * 1991: Net/2 provides Berkeley DB.
  157. * It doesn't provide dbm_pagfno() and dbm_dirfno().
  158. * 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
  159. * dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
  160. * 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
  161. * It defines dbm_pagfno() and dbm_dirfno() as macros.
  162. * 2011: gdbm-1.9 creates a separate dir file.
  163. * dbm_pagfno() and dbm_dirfno() returns different descriptors.
  164. */
  165. #if defined(HAVE_DBM_PAGFNO)
  166. rb_fd_fix_cloexec(dbm_pagfno(dbm));
  167. #endif
  168. #if defined(HAVE_DBM_DIRFNO)
  169. rb_fd_fix_cloexec(dbm_dirfno(dbm));
  170. #endif
  171. #if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC)
  172. /* Disable Berkeley DB error messages such as:
  173. * DB->put: attempt to modify a read-only database */
  174. ((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL);
  175. #endif
  176. }
  177. if (!dbm) {
  178. if (mode == -1) return Qnil;
  179. rb_sys_fail_str(file);
  180. }
  181. dbmp = ALLOC(struct dbmdata);
  182. DATA_PTR(obj) = dbmp;
  183. dbmp->di_dbm = dbm;
  184. dbmp->di_size = -1;
  185. return obj;
  186. }
  187. /*
  188. * call-seq:
  189. * DBM.open(filename[, mode[, flags]]) -> dbm
  190. * DBM.open(filename[, mode[, flags]]) {|dbm| block}
  191. *
  192. * Open a dbm database and yields it if a block is given. See also
  193. * <code>DBM.new</code>.
  194. */
  195. static VALUE
  196. fdbm_s_open(int argc, VALUE *argv, VALUE klass)
  197. {
  198. VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
  199. if (NIL_P(fdbm_initialize(argc, argv, obj))) {
  200. return Qnil;
  201. }
  202. if (rb_block_given_p()) {
  203. return rb_ensure(rb_yield, obj, fdbm_close, obj);
  204. }
  205. return obj;
  206. }
  207. static VALUE
  208. fdbm_fetch(VALUE obj, VALUE keystr, VALUE ifnone)
  209. {
  210. datum key, value;
  211. struct dbmdata *dbmp;
  212. DBM *dbm;
  213. long len;
  214. ExportStringValue(keystr);
  215. len = RSTRING_LEN(keystr);
  216. if (TOO_LONG(len)) goto not_found;
  217. key.dptr = RSTRING_PTR(keystr);
  218. key.dsize = (DSIZE_TYPE)len;
  219. GetDBM2(obj, dbmp, dbm);
  220. value = dbm_fetch(dbm, key);
  221. if (value.dptr == 0) {
  222. not_found:
  223. if (ifnone == Qnil && rb_block_given_p())
  224. return rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
  225. return ifnone;
  226. }
  227. return rb_tainted_str_new(value.dptr, value.dsize);
  228. }
  229. /*
  230. * call-seq:
  231. * dbm[key] -> string value or nil
  232. *
  233. * Return a value from the database by locating the key string
  234. * provided. If the key is not found, returns nil.
  235. */
  236. static VALUE
  237. fdbm_aref(VALUE obj, VALUE keystr)
  238. {
  239. return fdbm_fetch(obj, keystr, Qnil);
  240. }
  241. /*
  242. * call-seq:
  243. * dbm.fetch(key[, ifnone]) -> value
  244. *
  245. * Return a value from the database by locating the key string
  246. * provided. If the key is not found, returns +ifnone+. If +ifnone+
  247. * is not given, raises IndexError.
  248. */
  249. static VALUE
  250. fdbm_fetch_m(int argc, VALUE *argv, VALUE obj)
  251. {
  252. VALUE keystr, valstr, ifnone;
  253. rb_scan_args(argc, argv, "11", &keystr, &ifnone);
  254. valstr = fdbm_fetch(obj, keystr, ifnone);
  255. if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
  256. rb_raise(rb_eIndexError, "key not found");
  257. return valstr;
  258. }
  259. /*
  260. * call-seq:
  261. * dbm.key(value) -> string
  262. *
  263. * Returns the key for the specified value.
  264. */
  265. static VALUE
  266. fdbm_key(VALUE obj, VALUE valstr)
  267. {
  268. datum key, val;
  269. struct dbmdata *dbmp;
  270. DBM *dbm;
  271. long len;
  272. ExportStringValue(valstr);
  273. len = RSTRING_LEN(valstr);
  274. if (TOO_LONG(len)) return Qnil;
  275. val.dptr = RSTRING_PTR(valstr);
  276. val.dsize = (DSIZE_TYPE)len;
  277. GetDBM2(obj, dbmp, dbm);
  278. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  279. val = dbm_fetch(dbm, key);
  280. if ((long)val.dsize == RSTRING_LEN(valstr) &&
  281. memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0) {
  282. return rb_tainted_str_new(key.dptr, key.dsize);
  283. }
  284. }
  285. return Qnil;
  286. }
  287. /* :nodoc: */
  288. static VALUE
  289. fdbm_index(VALUE hash, VALUE value)
  290. {
  291. rb_warn("DBM#index is deprecated; use DBM#key");
  292. return fdbm_key(hash, value);
  293. }
  294. /*
  295. * call-seq:
  296. * dbm.select {|key, value| block} -> array
  297. *
  298. * Returns a new array consisting of the [key, value] pairs for which the code
  299. * block returns true.
  300. */
  301. static VALUE
  302. fdbm_select(VALUE obj)
  303. {
  304. VALUE new = rb_ary_new();
  305. datum key, val;
  306. DBM *dbm;
  307. struct dbmdata *dbmp;
  308. GetDBM2(obj, dbmp, dbm);
  309. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  310. VALUE assoc, v;
  311. val = dbm_fetch(dbm, key);
  312. assoc = rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
  313. rb_tainted_str_new(val.dptr, val.dsize));
  314. v = rb_yield(assoc);
  315. if (RTEST(v)) {
  316. rb_ary_push(new, assoc);
  317. }
  318. GetDBM2(obj, dbmp, dbm);
  319. }
  320. return new;
  321. }
  322. /*
  323. * call-seq:
  324. * dbm.values_at(key, ...) -> Array
  325. *
  326. * Returns an array containing the values associated with the given keys.
  327. */
  328. static VALUE
  329. fdbm_values_at(int argc, VALUE *argv, VALUE obj)
  330. {
  331. VALUE new = rb_ary_new2(argc);
  332. int i;
  333. for (i=0; i<argc; i++) {
  334. rb_ary_push(new, fdbm_fetch(obj, argv[i], Qnil));
  335. }
  336. return new;
  337. }
  338. static void
  339. fdbm_modify(VALUE obj)
  340. {
  341. rb_secure(4);
  342. if (OBJ_FROZEN(obj)) rb_error_frozen("DBM");
  343. }
  344. /*
  345. * call-seq:
  346. * dbm.delete(key)
  347. *
  348. * Deletes an entry from the database.
  349. */
  350. static VALUE
  351. fdbm_delete(VALUE obj, VALUE keystr)
  352. {
  353. datum key, value;
  354. struct dbmdata *dbmp;
  355. DBM *dbm;
  356. VALUE valstr;
  357. long len;
  358. fdbm_modify(obj);
  359. ExportStringValue(keystr);
  360. len = RSTRING_LEN(keystr);
  361. if (TOO_LONG(len)) goto not_found;
  362. key.dptr = RSTRING_PTR(keystr);
  363. key.dsize = (DSIZE_TYPE)len;
  364. GetDBM2(obj, dbmp, dbm);
  365. value = dbm_fetch(dbm, key);
  366. if (value.dptr == 0) {
  367. not_found:
  368. if (rb_block_given_p()) return rb_yield(keystr);
  369. return Qnil;
  370. }
  371. /* need to save value before dbm_delete() */
  372. valstr = rb_tainted_str_new(value.dptr, value.dsize);
  373. if (dbm_delete(dbm, key)) {
  374. dbmp->di_size = -1;
  375. rb_raise(rb_eDBMError, "dbm_delete failed");
  376. }
  377. else if (dbmp->di_size >= 0) {
  378. dbmp->di_size--;
  379. }
  380. return valstr;
  381. }
  382. /*
  383. * call-seq:
  384. * dbm.shift() -> [key, value]
  385. *
  386. * Removes a [key, value] pair from the database, and returns it.
  387. * If the database is empty, returns nil.
  388. * The order in which values are removed/returned is not guaranteed.
  389. */
  390. static VALUE
  391. fdbm_shift(VALUE obj)
  392. {
  393. datum key, val;
  394. struct dbmdata *dbmp;
  395. DBM *dbm;
  396. VALUE keystr, valstr;
  397. fdbm_modify(obj);
  398. GetDBM2(obj, dbmp, dbm);
  399. dbmp->di_size = -1;
  400. key = dbm_firstkey(dbm);
  401. if (!key.dptr) return Qnil;
  402. val = dbm_fetch(dbm, key);
  403. keystr = rb_tainted_str_new(key.dptr, key.dsize);
  404. valstr = rb_tainted_str_new(val.dptr, val.dsize);
  405. dbm_delete(dbm, key);
  406. return rb_assoc_new(keystr, valstr);
  407. }
  408. /*
  409. * call-seq:
  410. * dbm.reject! {|key, value| block} -> self
  411. * dbm.delete_if {|key, value| block} -> self
  412. *
  413. * Deletes all entries for which the code block returns true.
  414. * Returns self.
  415. */
  416. static VALUE
  417. fdbm_delete_if(VALUE obj)
  418. {
  419. datum key, val;
  420. struct dbmdata *dbmp;
  421. DBM *dbm;
  422. VALUE keystr, valstr;
  423. VALUE ret, ary = rb_ary_tmp_new(0);
  424. int i, status = 0;
  425. long n;
  426. fdbm_modify(obj);
  427. GetDBM2(obj, dbmp, dbm);
  428. n = dbmp->di_size;
  429. dbmp->di_size = -1;
  430. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  431. val = dbm_fetch(dbm, key);
  432. keystr = rb_tainted_str_new(key.dptr, key.dsize);
  433. OBJ_FREEZE(keystr);
  434. valstr = rb_tainted_str_new(val.dptr, val.dsize);
  435. ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
  436. if (status != 0) break;
  437. if (RTEST(ret)) rb_ary_push(ary, keystr);
  438. GetDBM2(obj, dbmp, dbm);
  439. }
  440. for (i = 0; i < RARRAY_LEN(ary); i++) {
  441. keystr = RARRAY_PTR(ary)[i];
  442. key.dptr = RSTRING_PTR(keystr);
  443. key.dsize = (DSIZE_TYPE)RSTRING_LEN(keystr);
  444. if (dbm_delete(dbm, key)) {
  445. rb_raise(rb_eDBMError, "dbm_delete failed");
  446. }
  447. }
  448. if (status) rb_jump_tag(status);
  449. if (n > 0) dbmp->di_size = n - RARRAY_LEN(ary);
  450. rb_ary_clear(ary);
  451. return obj;
  452. }
  453. /*
  454. * call-seq:
  455. * dbm.clear
  456. *
  457. * Deletes all data from the database.
  458. */
  459. static VALUE
  460. fdbm_clear(VALUE obj)
  461. {
  462. datum key;
  463. struct dbmdata *dbmp;
  464. DBM *dbm;
  465. fdbm_modify(obj);
  466. GetDBM2(obj, dbmp, dbm);
  467. dbmp->di_size = -1;
  468. while (key = dbm_firstkey(dbm), key.dptr) {
  469. if (dbm_delete(dbm, key)) {
  470. rb_raise(rb_eDBMError, "dbm_delete failed");
  471. }
  472. }
  473. dbmp->di_size = 0;
  474. return obj;
  475. }
  476. /*
  477. * call-seq:
  478. * dbm.invert -> hash
  479. *
  480. * Returns a Hash (not a DBM database) created by using each value in the
  481. * database as a key, with the corresponding key as its value.
  482. */
  483. static VALUE
  484. fdbm_invert(VALUE obj)
  485. {
  486. datum key, val;
  487. struct dbmdata *dbmp;
  488. DBM *dbm;
  489. VALUE keystr, valstr;
  490. VALUE hash = rb_hash_new();
  491. GetDBM2(obj, dbmp, dbm);
  492. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  493. val = dbm_fetch(dbm, key);
  494. keystr = rb_tainted_str_new(key.dptr, key.dsize);
  495. valstr = rb_tainted_str_new(val.dptr, val.dsize);
  496. rb_hash_aset(hash, valstr, keystr);
  497. }
  498. return hash;
  499. }
  500. static VALUE fdbm_store(VALUE,VALUE,VALUE);
  501. static VALUE
  502. update_i(VALUE pair, VALUE dbm)
  503. {
  504. Check_Type(pair, T_ARRAY);
  505. if (RARRAY_LEN(pair) < 2) {
  506. rb_raise(rb_eArgError, "pair must be [key, value]");
  507. }
  508. fdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
  509. return Qnil;
  510. }
  511. /*
  512. * call-seq:
  513. * dbm.update(obj)
  514. *
  515. * Updates the database with multiple values from the specified object.
  516. * Takes any object which implements the each_pair method, including
  517. * Hash and DBM objects.
  518. */
  519. static VALUE
  520. fdbm_update(VALUE obj, VALUE other)
  521. {
  522. rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
  523. return obj;
  524. }
  525. /*
  526. * call-seq:
  527. * dbm.replace(obj)
  528. *
  529. * Replaces the contents of the database with the contents of the specified
  530. * object. Takes any object which implements the each_pair method, including
  531. * Hash and DBM objects.
  532. */
  533. static VALUE
  534. fdbm_replace(VALUE obj, VALUE other)
  535. {
  536. fdbm_clear(obj);
  537. rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj);
  538. return obj;
  539. }
  540. /*
  541. * call-seq:
  542. * dbm.store(key, value) -> value
  543. * dbm[key] = value
  544. *
  545. * Stores the specified string value in the database, indexed via the
  546. * string key provided.
  547. */
  548. static VALUE
  549. fdbm_store(VALUE obj, VALUE keystr, VALUE valstr)
  550. {
  551. datum key, val;
  552. struct dbmdata *dbmp;
  553. DBM *dbm;
  554. fdbm_modify(obj);
  555. keystr = rb_obj_as_string(keystr);
  556. valstr = rb_obj_as_string(valstr);
  557. key.dptr = RSTRING_PTR(keystr);
  558. key.dsize = RSTRING_DSIZE(keystr);
  559. val.dptr = RSTRING_PTR(valstr);
  560. val.dsize = RSTRING_DSIZE(valstr);
  561. GetDBM2(obj, dbmp, dbm);
  562. dbmp->di_size = -1;
  563. if (dbm_store(dbm, key, val, DBM_REPLACE)) {
  564. dbm_clearerr(dbm);
  565. if (errno == EPERM) rb_sys_fail(0);
  566. rb_raise(rb_eDBMError, "dbm_store failed");
  567. }
  568. return valstr;
  569. }
  570. /*
  571. * call-seq:
  572. * dbm.length -> integer
  573. *
  574. * Returns the number of entries in the database.
  575. */
  576. static VALUE
  577. fdbm_length(VALUE obj)
  578. {
  579. datum key;
  580. struct dbmdata *dbmp;
  581. DBM *dbm;
  582. int i = 0;
  583. GetDBM2(obj, dbmp, dbm);
  584. if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
  585. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  586. i++;
  587. }
  588. dbmp->di_size = i;
  589. return INT2FIX(i);
  590. }
  591. /*
  592. * call-seq:
  593. * dbm.empty?
  594. *
  595. * Returns true if the database is empty, false otherwise.
  596. */
  597. static VALUE
  598. fdbm_empty_p(VALUE obj)
  599. {
  600. datum key;
  601. struct dbmdata *dbmp;
  602. DBM *dbm;
  603. GetDBM2(obj, dbmp, dbm);
  604. if (dbmp->di_size < 0) {
  605. dbm = dbmp->di_dbm;
  606. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  607. return Qfalse;
  608. }
  609. }
  610. else {
  611. if (dbmp->di_size)
  612. return Qfalse;
  613. }
  614. return Qtrue;
  615. }
  616. /*
  617. * call-seq:
  618. * dbm.each_value {|value| block} -> self
  619. *
  620. * Calls the block once for each value string in the database. Returns self.
  621. */
  622. static VALUE
  623. fdbm_each_value(VALUE obj)
  624. {
  625. datum key, val;
  626. struct dbmdata *dbmp;
  627. DBM *dbm;
  628. RETURN_ENUMERATOR(obj, 0, 0);
  629. GetDBM2(obj, dbmp, dbm);
  630. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  631. val = dbm_fetch(dbm, key);
  632. rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
  633. GetDBM2(obj, dbmp, dbm);
  634. }
  635. return obj;
  636. }
  637. /*
  638. * call-seq:
  639. * dbm.each_key {|key| block} -> self
  640. *
  641. * Calls the block once for each key string in the database. Returns self.
  642. */
  643. static VALUE
  644. fdbm_each_key(VALUE obj)
  645. {
  646. datum key;
  647. struct dbmdata *dbmp;
  648. DBM *dbm;
  649. RETURN_ENUMERATOR(obj, 0, 0);
  650. GetDBM2(obj, dbmp, dbm);
  651. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  652. rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
  653. GetDBM2(obj, dbmp, dbm);
  654. }
  655. return obj;
  656. }
  657. /*
  658. * call-seq:
  659. * dbm.each_pair {|key,value| block} -> self
  660. *
  661. * Calls the block once for each [key, value] pair in the database.
  662. * Returns self.
  663. */
  664. static VALUE
  665. fdbm_each_pair(VALUE obj)
  666. {
  667. datum key, val;
  668. DBM *dbm;
  669. struct dbmdata *dbmp;
  670. VALUE keystr, valstr;
  671. RETURN_ENUMERATOR(obj, 0, 0);
  672. GetDBM2(obj, dbmp, dbm);
  673. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  674. val = dbm_fetch(dbm, key);
  675. keystr = rb_tainted_str_new(key.dptr, key.dsize);
  676. valstr = rb_tainted_str_new(val.dptr, val.dsize);
  677. rb_yield(rb_assoc_new(keystr, valstr));
  678. GetDBM2(obj, dbmp, dbm);
  679. }
  680. return obj;
  681. }
  682. /*
  683. * call-seq:
  684. * dbm.keys -> array
  685. *
  686. * Returns an array of all the string keys in the database.
  687. */
  688. static VALUE
  689. fdbm_keys(VALUE obj)
  690. {
  691. datum key;
  692. struct dbmdata *dbmp;
  693. DBM *dbm;
  694. VALUE ary;
  695. GetDBM2(obj, dbmp, dbm);
  696. ary = rb_ary_new();
  697. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  698. rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize));
  699. }
  700. return ary;
  701. }
  702. /*
  703. * call-seq:
  704. * dbm.values -> array
  705. *
  706. * Returns an array of all the string values in the database.
  707. */
  708. static VALUE
  709. fdbm_values(VALUE obj)
  710. {
  711. datum key, val;
  712. struct dbmdata *dbmp;
  713. DBM *dbm;
  714. VALUE ary;
  715. GetDBM2(obj, dbmp, dbm);
  716. ary = rb_ary_new();
  717. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  718. val = dbm_fetch(dbm, key);
  719. rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
  720. }
  721. return ary;
  722. }
  723. /*
  724. * call-seq:
  725. * dbm.has_key?(key) -> boolean
  726. *
  727. * Returns true if the database contains the specified key, false otherwise.
  728. */
  729. static VALUE
  730. fdbm_has_key(VALUE obj, VALUE keystr)
  731. {
  732. datum key, val;
  733. struct dbmdata *dbmp;
  734. DBM *dbm;
  735. long len;
  736. ExportStringValue(keystr);
  737. len = RSTRING_LEN(keystr);
  738. if (TOO_LONG(len)) return Qfalse;
  739. key.dptr = RSTRING_PTR(keystr);
  740. key.dsize = (DSIZE_TYPE)len;
  741. GetDBM2(obj, dbmp, dbm);
  742. val = dbm_fetch(dbm, key);
  743. if (val.dptr) return Qtrue;
  744. return Qfalse;
  745. }
  746. /*
  747. * call-seq:
  748. * dbm.has_value?(value) -> boolean
  749. *
  750. * Returns true if the database contains the specified string value, false
  751. * otherwise.
  752. */
  753. static VALUE
  754. fdbm_has_value(VALUE obj, VALUE valstr)
  755. {
  756. datum key, val;
  757. struct dbmdata *dbmp;
  758. DBM *dbm;
  759. long len;
  760. ExportStringValue(valstr);
  761. len = RSTRING_LEN(valstr);
  762. if (TOO_LONG(len)) return Qfalse;
  763. val.dptr = RSTRING_PTR(valstr);
  764. val.dsize = (DSIZE_TYPE)len;
  765. GetDBM2(obj, dbmp, dbm);
  766. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  767. val = dbm_fetch(dbm, key);
  768. if ((DSIZE_TYPE)val.dsize == (DSIZE_TYPE)RSTRING_LEN(valstr) &&
  769. memcmp(val.dptr, RSTRING_PTR(valstr), val.dsize) == 0)
  770. return Qtrue;
  771. }
  772. return Qfalse;
  773. }
  774. /*
  775. * call-seq:
  776. * dbm.to_a -> array
  777. *
  778. * Converts the contents of the database to an array of [key, value] arrays,
  779. * and returns it.
  780. */
  781. static VALUE
  782. fdbm_to_a(VALUE obj)
  783. {
  784. datum key, val;
  785. struct dbmdata *dbmp;
  786. DBM *dbm;
  787. VALUE ary;
  788. GetDBM2(obj, dbmp, dbm);
  789. ary = rb_ary_new();
  790. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  791. val = dbm_fetch(dbm, key);
  792. rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
  793. rb_tainted_str_new(val.dptr, val.dsize)));
  794. }
  795. return ary;
  796. }
  797. /*
  798. * call-seq:
  799. * dbm.to_hash -> hash
  800. *
  801. * Converts the contents of the database to an in-memory Hash object, and
  802. * returns it.
  803. */
  804. static VALUE
  805. fdbm_to_hash(VALUE obj)
  806. {
  807. datum key, val;
  808. struct dbmdata *dbmp;
  809. DBM *dbm;
  810. VALUE hash;
  811. GetDBM2(obj, dbmp, dbm);
  812. hash = rb_hash_new();
  813. for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
  814. val = dbm_fetch(dbm, key);
  815. rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize),
  816. rb_tainted_str_new(val.dptr, val.dsize));
  817. }
  818. return hash;
  819. }
  820. /*
  821. * call-seq:
  822. * dbm.reject {|key,value| block} -> Hash
  823. *
  824. * Converts the contents of the database to an in-memory Hash, then calls
  825. * Hash#reject with the specified code block, returning a new Hash.
  826. */
  827. static VALUE
  828. fdbm_reject(VALUE obj)
  829. {
  830. return rb_hash_delete_if(fdbm_to_hash(obj));
  831. }
  832. /*
  833. * Documented by mathew meta@pobox.com.
  834. * = Introduction
  835. *
  836. * The DBM class provides a wrapper to a Unix-style
  837. * {dbm}[http://en.wikipedia.org/wiki/Dbm] or Database Manager library.
  838. *
  839. * Dbm databases do not have tables or columns; they are simple key-value
  840. * data stores, like a Ruby Hash except not resident in RAM. Keys and values
  841. * must be strings.
  842. *
  843. * The exact library used depends on how Ruby was compiled. It could be any
  844. * of the following:
  845. *
  846. * - The original ndbm library is released in 4.3BSD.
  847. * It is based on dbm library in Unix Version 7 but has different API to
  848. * support multiple databases in a process.
  849. * - {Berkeley DB}[http://en.wikipedia.org/wiki/Berkeley_DB] versions
  850. * 1 thru 5, also known as BDB and Sleepycat DB, now owned by Oracle
  851. * Corporation.
  852. * - Berkeley DB 1.x, still found in 4.4BSD derivatives (FreeBSD, OpenBSD, etc).
  853. * - {gdbm}[http://www.gnu.org/software/gdbm/], the GNU implementation of dbm.
  854. * - {qdbm}[http://fallabs.com/qdbm/index.html], another open source
  855. * reimplementation of dbm.
  856. *
  857. * All of these dbm implementations have their own Ruby interfaces
  858. * available, which provide richer (but varying) APIs.
  859. *
  860. * = Cautions
  861. *
  862. * Before you decide to use DBM, there are some issues you should consider:
  863. *
  864. * - Each implementation of dbm has its own file format. Generally, dbm
  865. * libraries will not read each other's files. This makes dbm files
  866. * a bad choice for data exchange.
  867. *
  868. * - Even running the same OS and the same dbm implementation, the database
  869. * file format may depend on the CPU architecture. For example, files may
  870. * not be portable between PowerPC and 386, or between 32 and 64 bit Linux.
  871. *
  872. * - Different versions of Berkeley DB use different file formats. A change to
  873. * the OS may therefore break DBM access to existing files.
  874. *
  875. * - Data size limits vary between implementations. Original Berkeley DB was
  876. * limited to 2GB of data. Dbm libraries also sometimes limit the total
  877. * size of a key/value pair, and the total size of all the keys that hash
  878. * to the same value. These limits can be as little as 512 bytes. That said,
  879. * gdbm and recent versions of Berkeley DB do away with these limits.
  880. *
  881. * Given the above cautions, DBM is not a good choice for long term storage of
  882. * important data. It is probably best used as a fast and easy alternative
  883. * to a Hash for processing large amounts of data.
  884. *
  885. * = Example
  886. *
  887. * require 'dbm'
  888. * db = DBM.open('rfcs', 666, DBM::CREATRW)
  889. * db['822'] = 'Standard for the Format of ARPA Internet Text Messages'
  890. * db['1123'] = 'Requirements for Internet Hosts - Application and Support'
  891. * db['3068'] = 'An Anycast Prefix for 6to4 Relay Routers'
  892. * puts db['822']
  893. */
  894. void
  895. Init_dbm(void)
  896. {
  897. rb_cDBM = rb_define_class("DBM", rb_cObject);
  898. /* Document-class: DBMError
  899. * Exception class used to return errors from the dbm library.
  900. */
  901. rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
  902. rb_include_module(rb_cDBM, rb_mEnumerable);
  903. rb_define_alloc_func(rb_cDBM, fdbm_alloc);
  904. rb_define_singleton_method(rb_cDBM, "open", fdbm_s_open, -1);
  905. rb_define_method(rb_cDBM, "initialize", fdbm_initialize, -1);
  906. rb_define_method(rb_cDBM, "close", fdbm_close, 0);
  907. rb_define_method(rb_cDBM, "closed?", fdbm_closed, 0);
  908. rb_define_method(rb_cDBM, "[]", fdbm_aref, 1);
  909. rb_define_method(rb_cDBM, "fetch", fdbm_fetch_m, -1);
  910. rb_define_method(rb_cDBM, "[]=", fdbm_store, 2);
  911. rb_define_method(rb_cDBM, "store", fdbm_store, 2);
  912. rb_define_method(rb_cDBM, "index", fdbm_index, 1);
  913. rb_define_method(rb_cDBM, "key", fdbm_key, 1);
  914. rb_define_method(rb_cDBM, "select", fdbm_select, 0);
  915. rb_define_method(rb_cDBM, "values_at", fdbm_values_at, -1);
  916. rb_define_method(rb_cDBM, "length", fdbm_length, 0);
  917. rb_define_method(rb_cDBM, "size", fdbm_length, 0);
  918. rb_define_method(rb_cDBM, "empty?", fdbm_empty_p, 0);
  919. rb_define_method(rb_cDBM, "each", fdbm_each_pair, 0);
  920. rb_define_method(rb_cDBM, "each_value", fdbm_each_value, 0);
  921. rb_define_method(rb_cDBM, "each_key", fdbm_each_key, 0);
  922. rb_define_method(rb_cDBM, "each_pair", fdbm_each_pair, 0);
  923. rb_define_method(rb_cDBM, "keys", fdbm_keys, 0);
  924. rb_define_method(rb_cDBM, "values", fdbm_values, 0);
  925. rb_define_method(rb_cDBM, "shift", fdbm_shift, 0);
  926. rb_define_method(rb_cDBM, "delete", fdbm_delete, 1);
  927. rb_define_method(rb_cDBM, "delete_if", fdbm_delete_if, 0);
  928. rb_define_method(rb_cDBM, "reject!", fdbm_delete_if, 0);
  929. rb_define_method(rb_cDBM, "reject", fdbm_reject, 0);
  930. rb_define_method(rb_cDBM, "clear", fdbm_clear, 0);
  931. rb_define_method(rb_cDBM, "invert", fdbm_invert, 0);
  932. rb_define_method(rb_cDBM, "update", fdbm_update, 1);
  933. rb_define_method(rb_cDBM, "replace", fdbm_replace, 1);
  934. rb_define_method(rb_cDBM, "include?", fdbm_has_key, 1);
  935. rb_define_method(rb_cDBM, "has_key?", fdbm_has_key, 1);
  936. rb_define_method(rb_cDBM, "member?", fdbm_has_key, 1);
  937. rb_define_method(rb_cDBM, "has_value?", fdbm_has_value, 1);
  938. rb_define_method(rb_cDBM, "key?", fdbm_has_key, 1);
  939. rb_define_method(rb_cDBM, "value?", fdbm_has_value, 1);
  940. rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0);
  941. rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0);
  942. /* Indicates that dbm_open() should open the database in read-only mode */
  943. rb_define_const(rb_cDBM, "READER", INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT));
  944. /* Indicates that dbm_open() should open the database in read/write mode */
  945. rb_define_const(rb_cDBM, "WRITER", INT2FIX(O_RDWR|RUBY_DBM_RW_BIT));
  946. /* Indicates that dbm_open() should open the database in read/write mode,
  947. * and create it if it does not already exist
  948. */
  949. rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT));
  950. /* Indicates that dbm_open() should open the database in read/write mode,
  951. * create it if it does not already exist, and delete all contents if it
  952. * does already exist.
  953. */
  954. rb_define_const(rb_cDBM, "NEWDB", INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT));
  955. {
  956. VALUE version;
  957. #if defined(_DBM_IOERR)
  958. version = rb_str_new2("ndbm (4.3BSD)");
  959. #elif defined(RUBYDBM_GDBM_HEADER)
  960. # if defined(HAVE_DECLARED_LIBVAR_GDBM_VERSION)
  961. /* since gdbm 1.9 */
  962. version = rb_str_new2(gdbm_version);
  963. # elif defined(HAVE_UNDECLARED_LIBVAR_GDBM_VERSION)
  964. /* ndbm.h doesn't declare gdbm_version until gdbm 1.8.3.
  965. * See extconf.rb for more information. */
  966. RUBY_EXTERN char *gdbm_version;
  967. version = rb_str_new2(gdbm_version);
  968. # else
  969. version = rb_str_new2("GDBM (unknown)");
  970. # endif
  971. #elif defined(RUBYDBM_DB_HEADER)
  972. # if defined(HAVE_DB_VERSION)
  973. /* The version of the dbm library, if using Berkeley DB */
  974. version = rb_str_new2(db_version(NULL, NULL, NULL));
  975. # else
  976. version = rb_str_new2("Berkeley DB (unknown)");
  977. # endif
  978. #elif defined(_RELIC_H)
  979. # if defined(HAVE_DPVERSION)
  980. version = rb_sprintf("QDBM %s", dpversion);
  981. # else
  982. version = rb_str_new2("QDBM (unknown)");
  983. # endif
  984. #else
  985. version = rb_str_new2("ndbm (unknown)");
  986. #endif
  987. /*
  988. * Identifies ndbm library version.
  989. *
  990. * Examples:
  991. *
  992. * - "ndbm (4.3BSD)"
  993. * - "Berkeley DB 4.8.30: (April 9, 2010)"
  994. * - "Berkeley DB (unknown)" (4.4BSD, maybe)
  995. * - "GDBM version 1.8.3. 10/15/2002 (built Jul 1 2011 12:32:45)"
  996. * - "QDBM 1.8.78"
  997. *
  998. */
  999. rb_define_const(rb_cDBM, "VERSION", version);
  1000. }
  1001. }