tcl_compat.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:23k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_compat.c,v 11.22 2001/01/11 18:19:55 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <tcl.h>
  17. #endif
  18. #define DB_DBM_HSEARCH 1
  19. #include "db_int.h"
  20. #include "tcl_db.h"
  21. /*
  22.  * Prototypes for procedures defined later in this file:
  23.  */
  24. static int mutex_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  25. /*
  26.  * bdb_HCommand --
  27.  * Implements h* functions.
  28.  *
  29.  * PUBLIC: int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  30.  */
  31. int
  32. bdb_HCommand(interp, objc, objv)
  33. Tcl_Interp *interp; /* Interpreter */
  34. int objc; /* How many arguments? */
  35. Tcl_Obj *CONST objv[]; /* The argument objects */
  36. {
  37. static char *hcmds[] = {
  38. "hcreate",
  39. "hdestroy",
  40. "hsearch",
  41. NULL
  42. };
  43. enum hcmds {
  44. HHCREATE,
  45. HHDESTROY,
  46. HHSEARCH
  47. };
  48. static char *srchacts[] = {
  49. "enter",
  50. "find",
  51. NULL
  52. };
  53. enum srchacts {
  54. ACT_ENTER,
  55. ACT_FIND
  56. };
  57. ENTRY item, *hres;
  58. ACTION action;
  59. int actindex, cmdindex, nelem, result, ret;
  60. Tcl_Obj *res;
  61. result = TCL_OK;
  62. /*
  63.  * Get the command name index from the object based on the cmds
  64.  * defined above.  This SHOULD NOT fail because we already checked
  65.  * in the 'berkdb' command.
  66.  */
  67. if (Tcl_GetIndexFromObj(interp,
  68.     objv[1], hcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  69. return (IS_HELP(objv[1]));
  70. res = NULL;
  71. switch ((enum hcmds)cmdindex) {
  72. case HHCREATE:
  73. /*
  74.  * Must be 1 arg, nelem.  Error if not.
  75.  */
  76. if (objc != 3) {
  77. Tcl_WrongNumArgs(interp, 2, objv, "nelem");
  78. return (TCL_ERROR);
  79. }
  80. result = Tcl_GetIntFromObj(interp, objv[2], &nelem);
  81. if (result == TCL_OK) {
  82. _debug_check();
  83. ret = hcreate(nelem) == 0 ? 1: 0;
  84. _ReturnSetup(interp, ret, "hcreate");
  85. }
  86. break;
  87. case HHSEARCH:
  88. /*
  89.  * 3 args for this.  Error if different.
  90.  */
  91. if (objc != 5) {
  92. Tcl_WrongNumArgs(interp, 2, objv, "key data action");
  93. return (TCL_ERROR);
  94. }
  95. item.key = Tcl_GetStringFromObj(objv[2], NULL);
  96. item.data = Tcl_GetStringFromObj(objv[3], NULL);
  97. action = 0;
  98. if (Tcl_GetIndexFromObj(interp, objv[4], srchacts,
  99.     "action", TCL_EXACT, &actindex) != TCL_OK)
  100. return (IS_HELP(objv[4]));
  101. switch ((enum srchacts)actindex) {
  102. case ACT_FIND:
  103. action = FIND;
  104. break;
  105. case ACT_ENTER:
  106. action = ENTER;
  107. break;
  108. }
  109. _debug_check();
  110. hres = hsearch(item, action);
  111. if (hres == NULL)
  112. Tcl_SetResult(interp, "-1", TCL_STATIC);
  113. else if (action == FIND)
  114. Tcl_SetResult(interp, (char *)hres->data, TCL_STATIC);
  115. else
  116. /* action is ENTER */
  117. Tcl_SetResult(interp, "0", TCL_STATIC);
  118. break;
  119. case HHDESTROY:
  120. /*
  121.  * No args for this.  Error if there are some.
  122.  */
  123. if (objc != 2) {
  124. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  125. return (TCL_ERROR);
  126. }
  127. _debug_check();
  128. (void)hdestroy();
  129. res = Tcl_NewIntObj(0);
  130. break;
  131. }
  132. /*
  133.  * Only set result if we have a res.  Otherwise, lower
  134.  * functions have already done so.
  135.  */
  136. if (result == TCL_OK && res)
  137. Tcl_SetObjResult(interp, res);
  138. return (result);
  139. }
  140. /*
  141.  *
  142.  * bdb_NdbmOpen --
  143.  * Opens an ndbm database.
  144.  *
  145.  * PUBLIC: #if DB_DBM_HSEARCH != 0
  146.  * PUBLIC: int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **));
  147.  * PUBLIC: #endif
  148.  */
  149. int
  150. bdb_NdbmOpen(interp, objc, objv, dbpp)
  151. Tcl_Interp *interp; /* Interpreter */
  152. int objc; /* How many arguments? */
  153. Tcl_Obj *CONST objv[]; /* The argument objects */
  154. DBM **dbpp; /* Dbm pointer */
  155. {
  156. static char *ndbopen[] = {
  157. "-create",
  158. "-mode",
  159. "-rdonly",
  160. "-truncate",
  161. "--",
  162. NULL
  163. };
  164. enum ndbopen {
  165. NDB_CREATE,
  166. NDB_MODE,
  167. NDB_RDONLY,
  168. NDB_TRUNC,
  169. NDB_ENDARG
  170. };
  171. u_int32_t open_flags;
  172. int endarg, i, mode, optindex, read_only, result;
  173. char *arg, *db;
  174. result = TCL_OK;
  175. open_flags = 0;
  176. endarg = mode = 0;
  177. read_only = 0;
  178. if (objc < 2) {
  179. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  180. return (TCL_ERROR);
  181. }
  182. /*
  183.  * Get the option name index from the object based on the args
  184.  * defined above.
  185.  */
  186. i = 2;
  187. while (i < objc) {
  188. if (Tcl_GetIndexFromObj(interp, objv[i], ndbopen, "option",
  189.     TCL_EXACT, &optindex) != TCL_OK) {
  190. arg = Tcl_GetStringFromObj(objv[i], NULL);
  191. if (arg[0] == '-') {
  192. result = IS_HELP(objv[i]);
  193. goto error;
  194. } else
  195. Tcl_ResetResult(interp);
  196. break;
  197. }
  198. i++;
  199. switch ((enum ndbopen)optindex) {
  200. case NDB_CREATE:
  201. open_flags |= O_CREAT;
  202. break;
  203. case NDB_RDONLY:
  204. read_only = 1;
  205. break;
  206. case NDB_TRUNC:
  207. open_flags |= O_TRUNC;
  208. break;
  209. case NDB_MODE:
  210. if (i >= objc) {
  211. Tcl_WrongNumArgs(interp, 2, objv,
  212.     "?-mode mode?");
  213. result = TCL_ERROR;
  214. break;
  215. }
  216. /*
  217.  * Don't need to check result here because
  218.  * if TCL_ERROR, the error message is already
  219.  * set up, and we'll bail out below.  If ok,
  220.  * the mode is set and we go on.
  221.  */
  222. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  223. break;
  224. case NDB_ENDARG:
  225. endarg = 1;
  226. break;
  227. } /* switch */
  228. /*
  229.  * If, at any time, parsing the args we get an error,
  230.  * bail out and return.
  231.  */
  232. if (result != TCL_OK)
  233. goto error;
  234. if (endarg)
  235. break;
  236. }
  237. if (result != TCL_OK)
  238. goto error;
  239. /*
  240.  * Any args we have left, (better be 0, or 1 left) is a
  241.  * file name.  If we have 0, then an in-memory db.  If
  242.  * there is 1, a db name.
  243.  */
  244. db = NULL;
  245. if (i != objc && i != objc - 1) {
  246. Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?");
  247. result = TCL_ERROR;
  248. goto error;
  249. }
  250. if (i != objc)
  251. db = Tcl_GetStringFromObj(objv[objc - 1], NULL);
  252. /*
  253.  * When we get here, we have already parsed all of our args
  254.  * and made all our calls to set up the database.  Everything
  255.  * is okay so far, no errors, if we get here.
  256.  *
  257.  * Now open the database.
  258.  */
  259. if (read_only)
  260. open_flags |= O_RDONLY;
  261. else
  262. open_flags |= O_RDWR;
  263. _debug_check();
  264. if ((*dbpp = dbm_open(db, open_flags, mode)) == NULL) {
  265. result = _ReturnSetup(interp, Tcl_GetErrno(), "db open");
  266. goto error;
  267. }
  268. return (TCL_OK);
  269. error:
  270. *dbpp = NULL;
  271. return (result);
  272. }
  273. /*
  274.  * bdb_DbmCommand --
  275.  * Implements "dbm" commands.
  276.  *
  277.  * PUBLIC: #if DB_DBM_HSEARCH != 0
  278.  * PUBLIC: int bdb_DbmCommand
  279.  * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *));
  280.  * PUBLIC: #endif
  281.  */
  282. int
  283. bdb_DbmCommand(interp, objc, objv, flag, dbm)
  284. Tcl_Interp *interp; /* Interpreter */
  285. int objc; /* How many arguments? */
  286. Tcl_Obj *CONST objv[]; /* The argument objects */
  287. int flag; /* Which db interface */
  288. DBM *dbm; /* DBM pointer */
  289. {
  290. static char *dbmcmds[] = {
  291. "dbmclose",
  292. "dbminit",
  293. "delete",
  294. "fetch",
  295. "firstkey",
  296. "nextkey",
  297. "store",
  298. NULL
  299. };
  300. enum dbmcmds {
  301. DBMCLOSE,
  302. DBMINIT,
  303. DBMDELETE,
  304. DBMFETCH,
  305. DBMFIRST,
  306. DBMNEXT,
  307. DBMSTORE
  308. };
  309. static char *stflag[] = {
  310. "insert", "replace",
  311. NULL
  312. };
  313. enum stflag {
  314. STINSERT, STREPLACE
  315. };
  316. datum key, data;
  317. int cmdindex, stindex, result, ret;
  318. char *name, *t;
  319. result = TCL_OK;
  320. /*
  321.  * Get the command name index from the object based on the cmds
  322.  * defined above.  This SHOULD NOT fail because we already checked
  323.  * in the 'berkdb' command.
  324.  */
  325. if (Tcl_GetIndexFromObj(interp,
  326.     objv[1], dbmcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  327. return (IS_HELP(objv[1]));
  328. switch ((enum dbmcmds)cmdindex) {
  329. case DBMCLOSE:
  330. /*
  331.  * No arg for this.  Error if different.
  332.  */
  333. if (objc != 2) {
  334. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  335. return (TCL_ERROR);
  336. }
  337. _debug_check();
  338. if (flag == DBTCL_DBM)
  339. ret = dbmclose();
  340. else {
  341. Tcl_SetResult(interp,
  342.     "Bad interface flag for command", TCL_STATIC);
  343. return (TCL_ERROR);
  344. }
  345. _ReturnSetup(interp, ret, "dbmclose");
  346. break;
  347. case DBMINIT:
  348. /*
  349.  * Must be 1 arg - file.
  350.  */
  351. if (objc != 3) {
  352. Tcl_WrongNumArgs(interp, 2, objv, "file");
  353. return (TCL_ERROR);
  354. }
  355. name = Tcl_GetStringFromObj(objv[2], NULL);
  356. if (flag == DBTCL_DBM)
  357. ret = dbminit(name);
  358. else {
  359. Tcl_SetResult(interp, "Bad interface flag for command",
  360.     TCL_STATIC);
  361. return (TCL_ERROR);
  362. }
  363. _ReturnSetup(interp, ret, "dbminit");
  364. break;
  365. case DBMFETCH:
  366. /*
  367.  * 1 arg for this.  Error if different.
  368.  */
  369. if (objc != 3) {
  370. Tcl_WrongNumArgs(interp, 2, objv, "key");
  371. return (TCL_ERROR);
  372. }
  373. key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize);
  374. _debug_check();
  375. if (flag == DBTCL_DBM)
  376. data = fetch(key);
  377. else if (flag == DBTCL_NDBM)
  378. data = dbm_fetch(dbm, key);
  379. else {
  380. Tcl_SetResult(interp,
  381.     "Bad interface flag for command", TCL_STATIC);
  382. return (TCL_ERROR);
  383. }
  384. if (data.dptr == NULL ||
  385.     (ret = __os_malloc(NULL, data.dsize + 1, NULL, &t)) != 0)
  386. Tcl_SetResult(interp, "-1", TCL_STATIC);
  387. else {
  388. memcpy(t, data.dptr, data.dsize);
  389. t[data.dsize] = '';
  390. Tcl_SetResult(interp, t, TCL_VOLATILE);
  391. __os_free(t, data.dsize + 1);
  392. }
  393. break;
  394. case DBMSTORE:
  395. /*
  396.  * 2 args for this.  Error if different.
  397.  */
  398. if (objc != 4 && flag == DBTCL_DBM) {
  399. Tcl_WrongNumArgs(interp, 2, objv, "key data");
  400. return (TCL_ERROR);
  401. }
  402. if (objc != 5 && flag == DBTCL_NDBM) {
  403. Tcl_WrongNumArgs(interp, 2, objv, "key data action");
  404. return (TCL_ERROR);
  405. }
  406. key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize);
  407. data.dptr =
  408.     (char *)Tcl_GetByteArrayFromObj(objv[3], &data.dsize);
  409. _debug_check();
  410. if (flag == DBTCL_DBM)
  411. ret = store(key, data);
  412. else if (flag == DBTCL_NDBM) {
  413. if (Tcl_GetIndexFromObj(interp, objv[4], stflag,
  414.     "flag", TCL_EXACT, &stindex) != TCL_OK)
  415. return (IS_HELP(objv[4]));
  416. switch ((enum stflag)stindex) {
  417. case STINSERT:
  418. flag = DBM_INSERT;
  419. break;
  420. case STREPLACE:
  421. flag = DBM_REPLACE;
  422. break;
  423. }
  424. ret = dbm_store(dbm, key, data, flag);
  425. } else {
  426. Tcl_SetResult(interp,
  427.     "Bad interface flag for command", TCL_STATIC);
  428. return (TCL_ERROR);
  429. }
  430. _ReturnSetup(interp, ret, "store");
  431. break;
  432. case DBMDELETE:
  433. /*
  434.  * 1 arg for this.  Error if different.
  435.  */
  436. if (objc != 3) {
  437. Tcl_WrongNumArgs(interp, 2, objv, "key");
  438. return (TCL_ERROR);
  439. }
  440. key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize);
  441. _debug_check();
  442. if (flag == DBTCL_DBM)
  443. ret = delete(key);
  444. else if (flag == DBTCL_NDBM)
  445. ret = dbm_delete(dbm, key);
  446. else {
  447. Tcl_SetResult(interp,
  448.     "Bad interface flag for command", TCL_STATIC);
  449. return (TCL_ERROR);
  450. }
  451. _ReturnSetup(interp, ret, "delete");
  452. break;
  453. case DBMFIRST:
  454. /*
  455.  * No arg for this.  Error if different.
  456.  */
  457. if (objc != 2) {
  458. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  459. return (TCL_ERROR);
  460. }
  461. _debug_check();
  462. if (flag == DBTCL_DBM)
  463. key = firstkey();
  464. else if (flag == DBTCL_NDBM)
  465. key = dbm_firstkey(dbm);
  466. else {
  467. Tcl_SetResult(interp,
  468.     "Bad interface flag for command", TCL_STATIC);
  469. return (TCL_ERROR);
  470. }
  471. if (key.dptr == NULL ||
  472.     (ret = __os_malloc(NULL, key.dsize + 1, NULL, &t)) != 0)
  473. Tcl_SetResult(interp, "-1", TCL_STATIC);
  474. else {
  475. memcpy(t, key.dptr, key.dsize);
  476. t[key.dsize] = '';
  477. Tcl_SetResult(interp, t, TCL_VOLATILE);
  478. __os_free(t, key.dsize + 1);
  479. }
  480. break;
  481. case DBMNEXT:
  482. /*
  483.  * 0 or 1 arg for this.  Error if different.
  484.  */
  485. _debug_check();
  486. if (flag == DBTCL_DBM) {
  487. if (objc != 3) {
  488. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  489. return (TCL_ERROR);
  490. }
  491. key.dptr = (char *)
  492.     Tcl_GetByteArrayFromObj(objv[2], &key.dsize);
  493. data = nextkey(key);
  494. } else if (flag == DBTCL_NDBM) {
  495. if (objc != 2) {
  496. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  497. return (TCL_ERROR);
  498. }
  499. data = dbm_nextkey(dbm);
  500. } else {
  501. Tcl_SetResult(interp,
  502.     "Bad interface flag for command", TCL_STATIC);
  503. return (TCL_ERROR);
  504. }
  505. if (data.dptr == NULL ||
  506.     (ret = __os_malloc(NULL, data.dsize + 1, NULL, &t)) != 0)
  507. Tcl_SetResult(interp, "-1", TCL_STATIC);
  508. else {
  509. memcpy(t, data.dptr, data.dsize);
  510. t[data.dsize] = '';
  511. Tcl_SetResult(interp, t, TCL_VOLATILE);
  512. __os_free(t, data.dsize + 1);
  513. }
  514. break;
  515. }
  516. return (result);
  517. }
  518. /*
  519.  * ndbm_Cmd --
  520.  * Implements the "ndbm" widget.
  521.  *
  522.  * PUBLIC: int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  523.  */
  524. int
  525. ndbm_Cmd(clientData, interp, objc, objv)
  526. ClientData clientData; /* DB handle */
  527. Tcl_Interp *interp; /* Interpreter */
  528. int objc; /* How many arguments? */
  529. Tcl_Obj *CONST objv[]; /* The argument objects */
  530. {
  531. static char *ndbcmds[] = {
  532. "clearerr",
  533. "close",
  534. "delete",
  535. "dirfno",
  536. "error",
  537. "fetch",
  538. "firstkey",
  539. "nextkey",
  540. "pagfno",
  541. "rdonly",
  542. "store",
  543. NULL
  544. };
  545. enum ndbcmds {
  546. NDBCLRERR,
  547. NDBCLOSE,
  548. NDBDELETE,
  549. NDBDIRFNO,
  550. NDBERR,
  551. NDBFETCH,
  552. NDBFIRST,
  553. NDBNEXT,
  554. NDBPAGFNO,
  555. NDBRDONLY,
  556. NDBSTORE
  557. };
  558. DBM *dbp;
  559. DBTCL_INFO *dbip;
  560. Tcl_Obj *res;
  561. int cmdindex, result, ret;
  562. Tcl_ResetResult(interp);
  563. dbp = (DBM *)clientData;
  564. dbip = _PtrToInfo((void *)dbp);
  565. result = TCL_OK;
  566. if (objc <= 1) {
  567. Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
  568. return (TCL_ERROR);
  569. }
  570. if (dbp == NULL) {
  571. Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC);
  572. return (TCL_ERROR);
  573. }
  574. if (dbip == NULL) {
  575. Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC);
  576. return (TCL_ERROR);
  577. }
  578. /*
  579.  * Get the command name index from the object based on the dbcmds
  580.  * defined above.
  581.  */
  582. if (Tcl_GetIndexFromObj(interp,
  583.     objv[1], ndbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  584. return (IS_HELP(objv[1]));
  585. res = NULL;
  586. switch ((enum ndbcmds)cmdindex) {
  587. case NDBCLOSE:
  588. _debug_check();
  589. dbm_close(dbp);
  590. (void)Tcl_DeleteCommand(interp, dbip->i_name);
  591. _DeleteInfo(dbip);
  592. res = Tcl_NewIntObj(0);
  593. break;
  594. case NDBDELETE:
  595. case NDBFETCH:
  596. case NDBFIRST:
  597. case NDBNEXT:
  598. case NDBSTORE:
  599. result = bdb_DbmCommand(interp, objc, objv, DBTCL_NDBM, dbp);
  600. break;
  601. case NDBCLRERR:
  602. /*
  603.  * No args for this.  Error if there are some.
  604.  */
  605. if (objc > 2) {
  606. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  607. return (TCL_ERROR);
  608. }
  609. _debug_check();
  610. ret = dbm_clearerr(dbp);
  611. if (ret)
  612. _ReturnSetup(interp, ret, "clearerr");
  613. else
  614. res = Tcl_NewIntObj(ret);
  615. break;
  616. case NDBDIRFNO:
  617. /*
  618.  * No args for this.  Error if there are some.
  619.  */
  620. if (objc > 2) {
  621. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  622. return (TCL_ERROR);
  623. }
  624. _debug_check();
  625. ret = dbm_dirfno(dbp);
  626. res = Tcl_NewIntObj(ret);
  627. break;
  628. case NDBPAGFNO:
  629. /*
  630.  * No args for this.  Error if there are some.
  631.  */
  632. if (objc > 2) {
  633. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  634. return (TCL_ERROR);
  635. }
  636. _debug_check();
  637. ret = dbm_pagfno(dbp);
  638. res = Tcl_NewIntObj(ret);
  639. break;
  640. case NDBERR:
  641. /*
  642.  * No args for this.  Error if there are some.
  643.  */
  644. if (objc > 2) {
  645. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  646. return (TCL_ERROR);
  647. }
  648. _debug_check();
  649. ret = dbm_error(dbp);
  650. Tcl_SetErrno(ret);
  651. Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
  652. break;
  653. case NDBRDONLY:
  654. /*
  655.  * No args for this.  Error if there are some.
  656.  */
  657. if (objc > 2) {
  658. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  659. return (TCL_ERROR);
  660. }
  661. _debug_check();
  662. ret = dbm_rdonly(dbp);
  663. if (ret)
  664. _ReturnSetup(interp, ret, "rdonly");
  665. else
  666. res = Tcl_NewIntObj(ret);
  667. break;
  668. }
  669. /*
  670.  * Only set result if we have a res.  Otherwise, lower
  671.  * functions have already done so.
  672.  */
  673. if (result == TCL_OK && res)
  674. Tcl_SetObjResult(interp, res);
  675. return (result);
  676. }
  677. /*
  678.  * bdb_RandCommand --
  679.  * Implements rand* functions.
  680.  *
  681.  * PUBLIC: int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  682.  */
  683. int
  684. bdb_RandCommand(interp, objc, objv)
  685. Tcl_Interp *interp; /* Interpreter */
  686. int objc; /* How many arguments? */
  687. Tcl_Obj *CONST objv[]; /* The argument objects */
  688. {
  689. static char *rcmds[] = {
  690. "rand", "random_int", "srand",
  691. NULL
  692. };
  693. enum rcmds {
  694. RRAND, RRAND_INT, RSRAND
  695. };
  696. long t;
  697. int cmdindex, hi, lo, result, ret;
  698. Tcl_Obj *res;
  699. char msg[MSG_SIZE];
  700. result = TCL_OK;
  701. /*
  702.  * Get the command name index from the object based on the cmds
  703.  * defined above.  This SHOULD NOT fail because we already checked
  704.  * in the 'berkdb' command.
  705.  */
  706. if (Tcl_GetIndexFromObj(interp,
  707.     objv[1], rcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  708. return (IS_HELP(objv[1]));
  709. res = NULL;
  710. switch ((enum rcmds)cmdindex) {
  711. case RRAND:
  712. /*
  713.  * Must be 0 args.  Error if different.
  714.  */
  715. if (objc != 2) {
  716. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  717. return (TCL_ERROR);
  718. }
  719. ret = rand();
  720. res = Tcl_NewIntObj(ret);
  721. break;
  722. case RRAND_INT:
  723. /*
  724.  * Must be 4 args.  Error if different.
  725.  */
  726. if (objc != 4) {
  727. Tcl_WrongNumArgs(interp, 2, objv, "lo hi");
  728. return (TCL_ERROR);
  729. }
  730. result = Tcl_GetIntFromObj(interp, objv[2], &lo);
  731. if (result != TCL_OK)
  732. break;
  733. result = Tcl_GetIntFromObj(interp, objv[3], &hi);
  734. if (result == TCL_OK) {
  735. #ifndef RAND_MAX
  736. #define RAND_MAX 0x7fffffff
  737. #endif
  738. t = rand();
  739. if (t > RAND_MAX) {
  740. snprintf(msg, MSG_SIZE,
  741.     "Max random is higher than %ldn",
  742.     (long)RAND_MAX);
  743. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  744. result = TCL_ERROR;
  745. break;
  746. }
  747. _debug_check();
  748. ret = (int)(((double)t / ((double)(RAND_MAX) + 1)) *
  749.     (hi - lo + 1));
  750. ret += lo;
  751. res = Tcl_NewIntObj(ret);
  752. }
  753. break;
  754. case RSRAND:
  755. /*
  756.  * Must be 1 arg.  Error if different.
  757.  */
  758. if (objc != 3) {
  759. Tcl_WrongNumArgs(interp, 2, objv, "seed");
  760. return (TCL_ERROR);
  761. }
  762. result = Tcl_GetIntFromObj(interp, objv[2], &lo);
  763. if (result == TCL_OK) {
  764. srand((u_int)lo);
  765. res = Tcl_NewIntObj(0);
  766. }
  767. break;
  768. }
  769. /*
  770.  * Only set result if we have a res.  Otherwise, lower
  771.  * functions have already done so.
  772.  */
  773. if (result == TCL_OK && res)
  774. Tcl_SetObjResult(interp, res);
  775. return (result);
  776. }
  777. /*
  778.  *
  779.  * tcl_Mutex --
  780.  * Opens an env mutex.
  781.  *
  782.  * PUBLIC: int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *,
  783.  * PUBLIC:    DBTCL_INFO *));
  784.  */
  785. int
  786. tcl_Mutex(interp, objc, objv, envp, envip)
  787. Tcl_Interp *interp;             /* Interpreter */
  788. int objc;                       /* How many arguments? */
  789. Tcl_Obj *CONST objv[];          /* The argument objects */
  790. DB_ENV *envp; /* Environment pointer */
  791. DBTCL_INFO *envip; /* Info pointer */
  792. {
  793. DBTCL_INFO *ip;
  794. Tcl_Obj *res;
  795. _MUTEX_DATA *md;
  796. int i, mode, nitems, result, ret;
  797. char newname[MSG_SIZE];
  798. md = NULL;
  799. result = TCL_OK;
  800. mode = nitems = ret = 0;
  801. memset(newname, 0, MSG_SIZE);
  802. if (objc != 4) {
  803. Tcl_WrongNumArgs(interp, 2, objv, "mode nitems");
  804. return (TCL_ERROR);
  805. }
  806. result = Tcl_GetIntFromObj(interp, objv[2], &mode);
  807. if (result != TCL_OK)
  808. return (TCL_ERROR);
  809. result = Tcl_GetIntFromObj(interp, objv[3], &nitems);
  810. if (result != TCL_OK)
  811. return (TCL_ERROR);
  812. snprintf(newname, sizeof(newname),
  813.     "%s.mutex%d", envip->i_name, envip->i_envmutexid);
  814. ip = _NewInfo(interp, NULL, newname, I_MUTEX);
  815. if (ip == NULL) {
  816. Tcl_SetResult(interp, "Could not set up info",
  817.     TCL_STATIC);
  818. return (TCL_ERROR);
  819. }
  820. /*
  821.  * Set up mutex.
  822.  */
  823. /*
  824.  * Map in the region.
  825.  *
  826.  * XXX
  827.  * We don't bother doing this "right", i.e., using the shalloc
  828.  * functions, just grab some memory knowing that it's correctly
  829.  * aligned.
  830.  */
  831. _debug_check();
  832. if (__os_calloc(NULL, 1, sizeof(_MUTEX_DATA), &md) != 0)
  833. goto posixout;
  834. md->env = envp;
  835. md->n_mutex = nitems;
  836. md->size = sizeof(_MUTEX_ENTRY) * nitems;
  837. md->reginfo.type = REGION_TYPE_MUTEX;
  838. md->reginfo.id = INVALID_REGION_TYPE;
  839. md->reginfo.mode = mode;
  840. md->reginfo.flags = REGION_CREATE_OK | REGION_JOIN_OK;
  841. if ((ret = __db_r_attach(envp, &md->reginfo, md->size)) != 0)
  842. goto posixout;
  843. md->marray = md->reginfo.addr;
  844. /* Initialize a created region. */
  845. if (F_ISSET(&md->reginfo, REGION_CREATE))
  846. for (i = 0; i < nitems; i++) {
  847. md->marray[i].val = 0;
  848. if ((ret =
  849.     __db_mutex_init(envp, &md->marray[i].m, i, 0)) != 0)
  850. goto posixout;
  851. }
  852. R_UNLOCK(envp, &md->reginfo);
  853. /*
  854.  * Success.  Set up return.  Set up new info
  855.  * and command widget for this mutex.
  856.  */
  857. envip->i_envmutexid++;
  858. ip->i_parent = envip;
  859. _SetInfoData(ip, md);
  860. Tcl_CreateObjCommand(interp, newname,
  861.     (Tcl_ObjCmdProc *)mutex_Cmd, (ClientData)md, NULL);
  862. res = Tcl_NewStringObj(newname, strlen(newname));
  863. Tcl_SetObjResult(interp, res);
  864. return (TCL_OK);
  865. posixout:
  866. if (ret > 0)
  867. Tcl_PosixError(interp);
  868. result = _ReturnSetup(interp, ret, "mutex");
  869. _DeleteInfo(ip);
  870. if (md != NULL) {
  871. if (md->reginfo.addr != NULL)
  872. (void)__db_r_detach(md->env,
  873.     &md->reginfo, F_ISSET(&md->reginfo, REGION_CREATE));
  874. __os_free(md, sizeof(*md));
  875. }
  876. return (result);
  877. }
  878. /*
  879.  * mutex_Cmd --
  880.  * Implements the "mutex" widget.
  881.  */
  882. static int
  883. mutex_Cmd(clientData, interp, objc, objv)
  884. ClientData clientData;          /* Mutex handle */
  885. Tcl_Interp *interp;             /* Interpreter */
  886. int objc;                       /* How many arguments? */
  887. Tcl_Obj *CONST objv[];          /* The argument objects */
  888. {
  889. static char *mxcmds[] = {
  890. "close",
  891. "get",
  892. "getval",
  893. "release",
  894. "setval",
  895. NULL
  896. };
  897. enum mxcmds {
  898. MXCLOSE,
  899. MXGET,
  900. MXGETVAL,
  901. MXRELE,
  902. MXSETVAL
  903. };
  904. DB_ENV *dbenv;
  905. DBTCL_INFO *envip, *mpip;
  906. _MUTEX_DATA *mp;
  907. Tcl_Obj *res;
  908. int cmdindex, id, result, newval;
  909. Tcl_ResetResult(interp);
  910. mp = (_MUTEX_DATA *)clientData;
  911. mpip = _PtrToInfo((void *)mp);
  912. envip = mpip->i_parent;
  913. dbenv = envip->i_envp;
  914. result = TCL_OK;
  915. if (mp == NULL) {
  916. Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
  917. return (TCL_ERROR);
  918. }
  919. if (mpip == NULL) {
  920. Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC);
  921. return (TCL_ERROR);
  922. }
  923. /*
  924.  * Get the command name index from the object based on the dbcmds
  925.  * defined above.
  926.  */
  927. if (Tcl_GetIndexFromObj(interp,
  928.     objv[1], mxcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  929. return (IS_HELP(objv[1]));
  930. res = NULL;
  931. switch ((enum mxcmds)cmdindex) {
  932. case MXCLOSE:
  933. if (objc != 2) {
  934. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  935. return (TCL_ERROR);
  936. }
  937. _debug_check();
  938. (void)__db_r_detach(mp->env, &mp->reginfo, 0);
  939. res = Tcl_NewIntObj(0);
  940. (void)Tcl_DeleteCommand(interp, mpip->i_name);
  941. _DeleteInfo(mpip);
  942. __os_free(mp, sizeof(*mp));
  943. break;
  944. case MXRELE:
  945. /*
  946.  * Check for 1 arg.  Error if different.
  947.  */
  948. if (objc != 3) {
  949. Tcl_WrongNumArgs(interp, 2, objv, "id");
  950. return (TCL_ERROR);
  951. }
  952. result = Tcl_GetIntFromObj(interp, objv[2], &id);
  953. if (result != TCL_OK)
  954. break;
  955. MUTEX_UNLOCK(dbenv, &mp->marray[id].m);
  956. res = Tcl_NewIntObj(0);
  957. break;
  958. case MXGET:
  959. /*
  960.  * Check for 1 arg.  Error if different.
  961.  */
  962. if (objc != 3) {
  963. Tcl_WrongNumArgs(interp, 2, objv, "id");
  964. return (TCL_ERROR);
  965. }
  966. result = Tcl_GetIntFromObj(interp, objv[2], &id);
  967. if (result != TCL_OK)
  968. break;
  969. MUTEX_LOCK(dbenv, &mp->marray[id].m, mp->env->lockfhp);
  970. res = Tcl_NewIntObj(0);
  971. break;
  972. case MXGETVAL:
  973. /*
  974.  * Check for 1 arg.  Error if different.
  975.  */
  976. if (objc != 3) {
  977. Tcl_WrongNumArgs(interp, 2, objv, "id");
  978. return (TCL_ERROR);
  979. }
  980. result = Tcl_GetIntFromObj(interp, objv[2], &id);
  981. if (result != TCL_OK)
  982. break;
  983. res = Tcl_NewIntObj(mp->marray[id].val);
  984. break;
  985. case MXSETVAL:
  986. /*
  987.  * Check for 2 args.  Error if different.
  988.  */
  989. if (objc != 4) {
  990. Tcl_WrongNumArgs(interp, 2, objv, "id val");
  991. return (TCL_ERROR);
  992. }
  993. result = Tcl_GetIntFromObj(interp, objv[2], &id);
  994. if (result != TCL_OK)
  995. break;
  996. result = Tcl_GetIntFromObj(interp, objv[3], &newval);
  997. if (result != TCL_OK)
  998. break;
  999. mp->marray[id].val = newval;
  1000. res = Tcl_NewIntObj(0);
  1001. break;
  1002. }
  1003. /*
  1004.  * Only set result if we have a res.  Otherwise, lower
  1005.  * functions have already done so.
  1006.  */
  1007. if (result == TCL_OK && res)
  1008. Tcl_SetObjResult(interp, res);
  1009. return (result);
  1010. }