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

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_db_pkg.c,v 11.76 2001/01/19 18:02:36 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <tcl.h>
  16. #endif
  17. #define DB_DBM_HSEARCH 1
  18. #include "db_int.h"
  19. #include "tcl_db.h"
  20. /*
  21.  * Prototypes for procedures defined later in this file:
  22.  */
  23. static int berkdb_Cmd __P((ClientData, Tcl_Interp *, int,
  24.     Tcl_Obj * CONST*));
  25. static int bdb_EnvOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  26.     DBTCL_INFO *, DB_ENV **));
  27. static int bdb_DbOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  28.     DBTCL_INFO *, DB **));
  29. static int bdb_DbRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  30. static int bdb_DbRename __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  31. static int bdb_DbUpgrade __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  32. static int bdb_DbVerify __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  33. static int bdb_Version __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  34. static int bdb_Handles __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  35. /*
  36.  * Db_tcl_Init --
  37.  *
  38.  * This is a package initialization procedure, which is called by Tcl when
  39.  * this package is to be added to an interpreter.  The name is based on the
  40.  * name of the shared library, currently libdb_tcl-X.Y.so, which Tcl uses
  41.  * to determine the name of this function.
  42.  */
  43. int
  44. Db_tcl_Init(interp)
  45. Tcl_Interp *interp; /* Interpreter in which the package is
  46.  * to be made available. */
  47. {
  48. int code;
  49. code = Tcl_PkgProvide(interp, "Db_tcl", "1.0");
  50. if (code != TCL_OK)
  51. return (code);
  52. Tcl_CreateObjCommand(interp, "berkdb", (Tcl_ObjCmdProc *)berkdb_Cmd,
  53.     (ClientData)0, NULL);
  54. /*
  55.  * Create shared global debugging variables
  56.  */
  57. Tcl_LinkVar(interp, "__debug_on", (char *)&__debug_on, TCL_LINK_INT);
  58. Tcl_LinkVar(interp, "__debug_print", (char *)&__debug_print,
  59.     TCL_LINK_INT);
  60. Tcl_LinkVar(interp, "__debug_stop", (char *)&__debug_stop,
  61.     TCL_LINK_INT);
  62. Tcl_LinkVar(interp, "__debug_test", (char *)&__debug_test,
  63.     TCL_LINK_INT);
  64. LIST_INIT(&__db_infohead);
  65. return (TCL_OK);
  66. }
  67. /*
  68.  * berkdb_cmd --
  69.  * Implements the "berkdb" command.
  70.  * This command supports three sub commands:
  71.  * berkdb version - Returns a list {major minor patch}
  72.  * berkdb env - Creates a new DB_ENV and returns a binding
  73.  *   to a new command of the form dbenvX, where X is an
  74.  *   integer starting at 0 (dbenv0, dbenv1, ...)
  75.  * berkdb open - Creates a new DB (optionally within
  76.  *   the given environment.  Returns a binding to a new
  77.  *   command of the form dbX, where X is an integer
  78.  *   starting at 0 (db0, db1, ...)
  79.  */
  80. static int
  81. berkdb_Cmd(notused, interp, objc, objv)
  82. ClientData notused; /* Not used. */
  83. Tcl_Interp *interp; /* Interpreter */
  84. int objc; /* How many arguments? */
  85. Tcl_Obj *CONST objv[]; /* The argument objects */
  86. {
  87. static char *berkdbcmds[] = {
  88. "dbremove",
  89. "dbrename",
  90. "dbverify",
  91. "env",
  92. "envremove",
  93. "handles",
  94. "open",
  95. "upgrade",
  96. "version",
  97. /* All below are compatibility functions */
  98. "hcreate", "hsearch", "hdestroy",
  99. "dbminit", "fetch", "store",
  100. "delete", "firstkey", "nextkey",
  101. "ndbm_open", "dbmclose",
  102. /* All below are convenience functions */
  103. "rand", "random_int", "srand",
  104. "debug_check",
  105. NULL
  106. };
  107. /*
  108.  * All commands enums below ending in X are compatibility
  109.  */
  110. enum berkdbcmds {
  111. BDB_DBREMOVE,
  112. BDB_DBRENAME,
  113. BDB_DBVERIFY,
  114. BDB_ENV,
  115. BDB_ENVREMOVE,
  116. BDB_HANDLES,
  117. BDB_OPEN,
  118. BDB_UPGRADE,
  119. BDB_VERSION,
  120. BDB_HCREATEX, BDB_HSEARCHX, BDB_HDESTROYX,
  121. BDB_DBMINITX, BDB_FETCHX, BDB_STOREX,
  122. BDB_DELETEX, BDB_FIRSTKEYX, BDB_NEXTKEYX,
  123. BDB_NDBMOPENX, BDB_DBMCLOSEX,
  124. BDB_RANDX, BDB_RAND_INTX, BDB_SRANDX,
  125. BDB_DBGCKX
  126. };
  127. static int env_id = 0;
  128. static int db_id = 0;
  129. static int ndbm_id = 0;
  130. DB *dbp;
  131. DBM *ndbmp;
  132. DBTCL_INFO *ip;
  133. DB_ENV *envp;
  134. Tcl_Obj *res;
  135. int cmdindex, result;
  136. char newname[MSG_SIZE];
  137. COMPQUIET(notused, NULL);
  138. Tcl_ResetResult(interp);
  139. memset(newname, 0, MSG_SIZE);
  140. result = TCL_OK;
  141. if (objc <= 1) {
  142. Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
  143. return (TCL_ERROR);
  144. }
  145. /*
  146.  * Get the command name index from the object based on the berkdbcmds
  147.  * defined above.
  148.  */
  149. if (Tcl_GetIndexFromObj(interp,
  150.     objv[1], berkdbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  151. return (IS_HELP(objv[1]));
  152. res = NULL;
  153. switch ((enum berkdbcmds)cmdindex) {
  154. case BDB_VERSION:
  155. _debug_check();
  156. result = bdb_Version(interp, objc, objv);
  157. break;
  158. case BDB_HANDLES:
  159. result = bdb_Handles(interp, objc, objv);
  160. break;
  161. case BDB_ENV:
  162. snprintf(newname, sizeof(newname), "env%d", env_id);
  163. ip = _NewInfo(interp, NULL, newname, I_ENV);
  164. if (ip != NULL) {
  165. result = bdb_EnvOpen(interp, objc, objv, ip, &envp);
  166. if (result == TCL_OK && envp != NULL) {
  167. env_id++;
  168. Tcl_CreateObjCommand(interp, newname,
  169.     (Tcl_ObjCmdProc *)env_Cmd,
  170.     (ClientData)envp, NULL);
  171. /* Use ip->i_name - newname is overwritten */
  172. res =
  173.     Tcl_NewStringObj(newname, strlen(newname));
  174. _SetInfoData(ip, envp);
  175. } else
  176. _DeleteInfo(ip);
  177. } else {
  178. Tcl_SetResult(interp, "Could not set up info",
  179.     TCL_STATIC);
  180. result = TCL_ERROR;
  181. }
  182. break;
  183. case BDB_DBREMOVE:
  184. result = bdb_DbRemove(interp, objc, objv);
  185. break;
  186. case BDB_DBRENAME:
  187. result = bdb_DbRename(interp, objc, objv);
  188. break;
  189. case BDB_UPGRADE:
  190. result = bdb_DbUpgrade(interp, objc, objv);
  191. break;
  192. case BDB_DBVERIFY:
  193. result = bdb_DbVerify(interp, objc, objv);
  194. break;
  195. case BDB_ENVREMOVE:
  196. result = tcl_EnvRemove(interp, objc, objv, NULL, NULL);
  197. break;
  198. case BDB_OPEN:
  199. snprintf(newname, sizeof(newname), "db%d", db_id);
  200. ip = _NewInfo(interp, NULL, newname, I_DB);
  201. if (ip != NULL) {
  202. result = bdb_DbOpen(interp, objc, objv, ip, &dbp);
  203. if (result == TCL_OK && dbp != NULL) {
  204. db_id++;
  205. Tcl_CreateObjCommand(interp, newname,
  206.     (Tcl_ObjCmdProc *)db_Cmd,
  207.     (ClientData)dbp, NULL);
  208. /* Use ip->i_name - newname is overwritten */
  209. res =
  210.     Tcl_NewStringObj(newname, strlen(newname));
  211. _SetInfoData(ip, dbp);
  212. } else
  213. _DeleteInfo(ip);
  214. } else {
  215. Tcl_SetResult(interp, "Could not set up info",
  216.     TCL_STATIC);
  217. result = TCL_ERROR;
  218. }
  219. break;
  220. case BDB_HCREATEX:
  221. case BDB_HSEARCHX:
  222. case BDB_HDESTROYX:
  223. result = bdb_HCommand(interp, objc, objv);
  224. break;
  225. case BDB_DBMINITX:
  226. case BDB_DBMCLOSEX:
  227. case BDB_FETCHX:
  228. case BDB_STOREX:
  229. case BDB_DELETEX:
  230. case BDB_FIRSTKEYX:
  231. case BDB_NEXTKEYX:
  232. result = bdb_DbmCommand(interp, objc, objv, DBTCL_DBM, NULL);
  233. break;
  234. case BDB_NDBMOPENX:
  235. snprintf(newname, sizeof(newname), "ndbm%d", ndbm_id);
  236. ip = _NewInfo(interp, NULL, newname, I_NDBM);
  237. if (ip != NULL) {
  238. result = bdb_NdbmOpen(interp, objc, objv, &ndbmp);
  239. if (result == TCL_OK) {
  240. ndbm_id++;
  241. Tcl_CreateObjCommand(interp, newname,
  242.     (Tcl_ObjCmdProc *)ndbm_Cmd,
  243.     (ClientData)ndbmp, NULL);
  244. /* Use ip->i_name - newname is overwritten */
  245. res =
  246.     Tcl_NewStringObj(newname, strlen(newname));
  247. _SetInfoData(ip, ndbmp);
  248. } else
  249. _DeleteInfo(ip);
  250. } else {
  251. Tcl_SetResult(interp, "Could not set up info",
  252.     TCL_STATIC);
  253. result = TCL_ERROR;
  254. }
  255. break;
  256. case BDB_RANDX:
  257. case BDB_RAND_INTX:
  258. case BDB_SRANDX:
  259. result = bdb_RandCommand(interp, objc, objv);
  260. break;
  261. case BDB_DBGCKX:
  262. _debug_check();
  263. res = Tcl_NewIntObj(0);
  264. break;
  265. }
  266. /*
  267.  * For each different arg call different function to create
  268.  * new commands (or if version, get/return it).
  269.  */
  270. if (result == TCL_OK && res != NULL)
  271. Tcl_SetObjResult(interp, res);
  272. return (result);
  273. }
  274. /*
  275.  * bdb_EnvOpen -
  276.  * Implements the environment open command.
  277.  * There are many, many options to the open command.
  278.  * Here is the general flow:
  279.  *
  280.  * 1.  Call db_env_create to create the env handle.
  281.  * 2.  Parse args tracking options.
  282.  * 3.  Make any pre-open setup calls necessary.
  283.  * 4.  Call DBENV->open to open the env.
  284.  * 5.  Return env widget handle to user.
  285.  */
  286. static int
  287. bdb_EnvOpen(interp, objc, objv, ip, env)
  288. Tcl_Interp *interp; /* Interpreter */
  289. int objc; /* How many arguments? */
  290. Tcl_Obj *CONST objv[]; /* The argument objects */
  291. DBTCL_INFO *ip; /* Our internal info */
  292. DB_ENV **env; /* Environment pointer */
  293. {
  294. static char *envopen[] = {
  295. "-cachesize",
  296. "-cdb",
  297. "-cdb_alldb",
  298. "-client_timeout",
  299. "-create",
  300. "-data_dir",
  301. "-errfile",
  302. "-errpfx",
  303. "-home",
  304. "-lock",
  305. "-lock_conflict",
  306. "-lock_detect",
  307. "-lock_max",
  308. "-lock_max_locks",
  309. "-lock_max_lockers",
  310. "-lock_max_objects",
  311. "-log",
  312. "-log_buffer",
  313. "-log_dir",
  314. "-log_max",
  315. "-mmapsize",
  316. "-mode",
  317. "-nommap",
  318. "-private",
  319. "-recover",
  320. "-recover_fatal",
  321. "-region_init",
  322. "-server",
  323. "-server_timeout",
  324. "-shm_key",
  325. "-system_mem",
  326. "-tmp_dir",
  327. "-txn",
  328. "-txn_max",
  329. "-txn_timestamp",
  330. "-use_environ",
  331. "-use_environ_root",
  332. "-verbose",
  333. NULL
  334. };
  335. /*
  336.  * !!!
  337.  * These have to be in the same order as the above,
  338.  * which is close to but not quite alphabetical.
  339.  */
  340. enum envopen {
  341. ENV_CACHESIZE,
  342. ENV_CDB,
  343. ENV_CDB_ALLDB,
  344. ENV_CLIENT_TO,
  345. ENV_CREATE,
  346. ENV_DATA_DIR,
  347. ENV_ERRFILE,
  348. ENV_ERRPFX,
  349. ENV_HOME,
  350. ENV_LOCK,
  351. ENV_CONFLICT,
  352. ENV_DETECT,
  353. ENV_LOCK_MAX,
  354. ENV_LOCK_MAX_LOCKS,
  355. ENV_LOCK_MAX_LOCKERS,
  356. ENV_LOCK_MAX_OBJECTS,
  357. ENV_LOG,
  358. ENV_LOG_BUFFER,
  359. ENV_LOG_DIR,
  360. ENV_LOG_MAX,
  361. ENV_MMAPSIZE,
  362. ENV_MODE,
  363. ENV_NOMMAP,
  364. ENV_PRIVATE,
  365. ENV_RECOVER,
  366. ENV_RECOVER_FATAL,
  367. ENV_REGION_INIT,
  368. ENV_SERVER,
  369. ENV_SERVER_TO,
  370. ENV_SHM_KEY,
  371. ENV_SYSTEM_MEM,
  372. ENV_TMP_DIR,
  373. ENV_TXN,
  374. ENV_TXN_MAX,
  375. ENV_TXN_TIME,
  376. ENV_USE_ENVIRON,
  377. ENV_USE_ENVIRON_ROOT,
  378. ENV_VERBOSE
  379. };
  380. Tcl_Obj **myobjv, **myobjv1;
  381. time_t time;
  382. u_int32_t detect, gbytes, bytes, ncaches, open_flags, set_flag, size;
  383. u_int8_t *conflicts;
  384. int i, intarg, itmp, j, logbufset, logmaxset;
  385. int mode, myobjc, nmodes, optindex, result, ret, temp;
  386. long client_to, server_to, shm;
  387. char *arg, *home, *server;
  388. result = TCL_OK;
  389. mode = 0;
  390. set_flag = 0;
  391. home = NULL;
  392. /*
  393.  * XXX
  394.  * If/when our Tcl interface becomes thread-safe, we should enable
  395.  * DB_THREAD here.  Note that DB_THREAD currently does not work
  396.  * with log_get -next, -prev;  if we wish to enable DB_THREAD,
  397.  * those must either be made thread-safe first or we must come up with
  398.  * a workaround.  (We used to specify DB_THREAD if and only if
  399.  * logging was not configured.)
  400.  */
  401. open_flags = DB_JOINENV;
  402. logmaxset = logbufset = 0;
  403. if (objc <= 2) {
  404. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  405. return (TCL_ERROR);
  406. }
  407. /*
  408.  * Server code must go before the call to db_env_create.
  409.  */
  410. server = NULL;
  411. server_to = client_to = 0;
  412. i = 2;
  413. while (i < objc) {
  414. if (Tcl_GetIndexFromObj(interp, objv[i++], envopen, "option",
  415.     TCL_EXACT, &optindex) != TCL_OK) {
  416. Tcl_ResetResult(interp);
  417. continue;
  418. }
  419. switch ((enum envopen)optindex) {
  420. case ENV_SERVER:
  421. if (i >= objc) {
  422. Tcl_WrongNumArgs(interp, 2, objv,
  423.     "?-server hostname");
  424. result = TCL_ERROR;
  425. break;
  426. }
  427. server = Tcl_GetStringFromObj(objv[i++], NULL);
  428. break;
  429. case ENV_SERVER_TO:
  430. if (i >= objc) {
  431. Tcl_WrongNumArgs(interp, 2, objv,
  432.     "?-server_to secs");
  433. result = TCL_ERROR;
  434. break;
  435. }
  436. result = Tcl_GetLongFromObj(interp, objv[i++],
  437.     &server_to);
  438. break;
  439. case ENV_CLIENT_TO:
  440. if (i >= objc) {
  441. Tcl_WrongNumArgs(interp, 2, objv,
  442.     "?-client_to secs");
  443. result = TCL_ERROR;
  444. break;
  445. }
  446. result = Tcl_GetLongFromObj(interp, objv[i++],
  447.     &client_to);
  448. break;
  449. default:
  450. break;
  451. }
  452. }
  453. if (server != NULL) {
  454. ret = db_env_create(env, DB_CLIENT);
  455. if (ret)
  456. return (_ReturnSetup(interp, ret, "db_env_create"));
  457. (*env)->set_errpfx((*env), ip->i_name);
  458. (*env)->set_errcall((*env), _ErrorFunc);
  459. if ((ret = (*env)->set_server((*env), server,
  460.     client_to, server_to, 0)) != 0) {
  461. result = TCL_ERROR;
  462. goto error;
  463. }
  464. } else {
  465. /*
  466.  * Create the environment handle before parsing the args
  467.  * since we'll be modifying the environment as we parse.
  468.  */
  469. ret = db_env_create(env, 0);
  470. if (ret)
  471. return (_ReturnSetup(interp, ret, "db_env_create"));
  472. (*env)->set_errpfx((*env), ip->i_name);
  473. (*env)->set_errcall((*env), _ErrorFunc);
  474. }
  475. /*
  476.  * Get the command name index from the object based on the bdbcmds
  477.  * defined above.
  478.  */
  479. i = 2;
  480. while (i < objc) {
  481. if (Tcl_GetIndexFromObj(interp, objv[i], envopen, "option",
  482.     TCL_EXACT, &optindex) != TCL_OK) {
  483. result = IS_HELP(objv[i]);
  484. goto error;
  485. }
  486. i++;
  487. switch ((enum envopen)optindex) {
  488. case ENV_SERVER:
  489. case ENV_SERVER_TO:
  490. case ENV_CLIENT_TO:
  491. /*
  492.  * Already handled these, skip them and their arg.
  493.  */
  494. i++;
  495. break;
  496. case ENV_CDB:
  497. FLD_SET(open_flags, DB_INIT_CDB | DB_INIT_MPOOL);
  498. FLD_CLR(open_flags, DB_JOINENV);
  499. break;
  500. case ENV_CDB_ALLDB:
  501. FLD_SET(set_flag, DB_CDB_ALLDB);
  502. break;
  503. case ENV_LOCK:
  504. FLD_SET(open_flags, DB_INIT_LOCK | DB_INIT_MPOOL);
  505. FLD_CLR(open_flags, DB_JOINENV);
  506. break;
  507. case ENV_LOG:
  508. FLD_SET(open_flags, DB_INIT_LOG | DB_INIT_MPOOL);
  509. FLD_CLR(open_flags, DB_JOINENV);
  510. break;
  511. case ENV_TXN:
  512. FLD_SET(open_flags, DB_INIT_LOCK |
  513.     DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN);
  514. FLD_CLR(open_flags, DB_JOINENV);
  515. /* Make sure we have an arg to check against! */
  516. if (i < objc) {
  517. arg = Tcl_GetStringFromObj(objv[i], NULL);
  518. if (strcmp(arg, "nosync") == 0) {
  519. FLD_SET(set_flag, DB_TXN_NOSYNC);
  520. i++;
  521. }
  522. }
  523. break;
  524. case ENV_CREATE:
  525. FLD_SET(open_flags, DB_CREATE | DB_INIT_MPOOL);
  526. FLD_CLR(open_flags, DB_JOINENV);
  527. break;
  528. case ENV_HOME:
  529. /* Make sure we have an arg to check against! */
  530. if (i >= objc) {
  531. Tcl_WrongNumArgs(interp, 2, objv,
  532.     "?-home dir?");
  533. result = TCL_ERROR;
  534. break;
  535. }
  536. home = Tcl_GetStringFromObj(objv[i++], NULL);
  537. break;
  538. case ENV_MODE:
  539. if (i >= objc) {
  540. Tcl_WrongNumArgs(interp, 2, objv,
  541.     "?-mode mode?");
  542. result = TCL_ERROR;
  543. break;
  544. }
  545. /*
  546.  * Don't need to check result here because
  547.  * if TCL_ERROR, the error message is already
  548.  * set up, and we'll bail out below.  If ok,
  549.  * the mode is set and we go on.
  550.  */
  551. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  552. break;
  553. case ENV_NOMMAP:
  554. FLD_SET(set_flag, DB_NOMMAP);
  555. break;
  556. case ENV_PRIVATE:
  557. FLD_SET(open_flags, DB_PRIVATE | DB_INIT_MPOOL);
  558. FLD_CLR(open_flags, DB_JOINENV);
  559. break;
  560. case ENV_RECOVER:
  561. FLD_SET(open_flags, DB_RECOVER);
  562. break;
  563. case ENV_RECOVER_FATAL:
  564. FLD_SET(open_flags, DB_RECOVER_FATAL);
  565. break;
  566. case ENV_SYSTEM_MEM:
  567. FLD_SET(open_flags, DB_SYSTEM_MEM);
  568. break;
  569. case ENV_USE_ENVIRON_ROOT:
  570. FLD_SET(open_flags, DB_USE_ENVIRON_ROOT);
  571. break;
  572. case ENV_USE_ENVIRON:
  573. FLD_SET(open_flags, DB_USE_ENVIRON);
  574. break;
  575. case ENV_VERBOSE:
  576. result = Tcl_ListObjGetElements(interp, objv[i],
  577.     &myobjc, &myobjv);
  578. if (result == TCL_OK)
  579. i++;
  580. else
  581. break;
  582. if (myobjc != 2) {
  583. Tcl_WrongNumArgs(interp, 2, objv,
  584.     "?-verbose {which on|off}?");
  585. result = TCL_ERROR;
  586. break;
  587. }
  588. result = tcl_EnvVerbose(interp, *env,
  589.     myobjv[0], myobjv[1]);
  590. break;
  591. case ENV_REGION_INIT:
  592. _debug_check();
  593. ret = db_env_set_region_init(1);
  594. result = _ReturnSetup(interp, ret, "region_init");
  595. break;
  596. case ENV_CACHESIZE:
  597. result = Tcl_ListObjGetElements(interp, objv[i],
  598.     &myobjc, &myobjv);
  599. if (result == TCL_OK)
  600. i++;
  601. else
  602. break;
  603. j = 0;
  604. if (myobjc != 3) {
  605. Tcl_WrongNumArgs(interp, 2, objv,
  606.     "?-cachesize {gbytes bytes ncaches}?");
  607. result = TCL_ERROR;
  608. break;
  609. }
  610. result = Tcl_GetIntFromObj(interp, myobjv[0], &itmp);
  611. gbytes = itmp;
  612. if (result != TCL_OK)
  613. break;
  614. result = Tcl_GetIntFromObj(interp, myobjv[1], &itmp);
  615. bytes = itmp;
  616. if (result != TCL_OK)
  617. break;
  618. result = Tcl_GetIntFromObj(interp, myobjv[2], &itmp);
  619. ncaches = itmp;
  620. if (result != TCL_OK)
  621. break;
  622. _debug_check();
  623. ret = (*env)->set_cachesize(*env, gbytes, bytes,
  624.     ncaches);
  625. result = _ReturnSetup(interp, ret, "set_cachesize");
  626. break;
  627. case ENV_MMAPSIZE:
  628. if (i >= objc) {
  629. Tcl_WrongNumArgs(interp, 2, objv,
  630.     "?-mmapsize size?");
  631. result = TCL_ERROR;
  632. break;
  633. }
  634. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  635. if (result == TCL_OK) {
  636. _debug_check();
  637. ret = (*env)->set_mp_mmapsize(*env,
  638.     (size_t)intarg);
  639. result = _ReturnSetup(interp, ret, "mmapsize");
  640. }
  641. break;
  642. case ENV_SHM_KEY:
  643. if (i >= objc) {
  644. Tcl_WrongNumArgs(interp, 2, objv,
  645.     "?-shm_key key?");
  646. result = TCL_ERROR;
  647. break;
  648. }
  649. result = Tcl_GetLongFromObj(interp, objv[i++], &shm);
  650. if (result == TCL_OK) {
  651. _debug_check();
  652. ret = (*env)->set_shm_key(*env, shm);
  653. result = _ReturnSetup(interp, ret, "shm_key");
  654. }
  655. break;
  656. case ENV_LOG_MAX:
  657. if (i >= objc) {
  658. Tcl_WrongNumArgs(interp, 2, objv,
  659.     "?-log_max max?");
  660. result = TCL_ERROR;
  661. break;
  662. }
  663. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  664. if (result == TCL_OK && logbufset) {
  665. _debug_check();
  666. ret = (*env)->set_lg_max(*env,
  667.     (u_int32_t)intarg);
  668. result = _ReturnSetup(interp, ret, "log_max");
  669. logbufset = 0;
  670. } else
  671. logmaxset = intarg;
  672. break;
  673. case ENV_LOG_BUFFER:
  674. if (i >= objc) {
  675. Tcl_WrongNumArgs(interp, 2, objv,
  676.     "?-log_buffer size?");
  677. result = TCL_ERROR;
  678. break;
  679. }
  680. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  681. if (result == TCL_OK) {
  682. _debug_check();
  683. ret = (*env)->set_lg_bsize(*env,
  684.     (u_int32_t)intarg);
  685. result = _ReturnSetup(interp, ret, "log_bsize");
  686. logbufset = 1;
  687. if (logmaxset) {
  688. _debug_check();
  689. ret = (*env)->set_lg_max(*env,
  690.     (u_int32_t)logmaxset);
  691. result = _ReturnSetup(interp, ret,
  692.     "log_max");
  693. logmaxset = 0;
  694. logbufset = 0;
  695. }
  696. }
  697. break;
  698. case ENV_CONFLICT:
  699. /*
  700.  * Get conflict list.  List is:
  701.  * {nmodes {matrix}}
  702.  *
  703.  * Where matrix must be nmodes*nmodes big.
  704.  * Set up conflicts array to pass.
  705.  */
  706. result = Tcl_ListObjGetElements(interp, objv[i],
  707.     &myobjc, &myobjv);
  708. if (result == TCL_OK)
  709. i++;
  710. else
  711. break;
  712. if (myobjc != 2) {
  713. Tcl_WrongNumArgs(interp, 2, objv,
  714.     "?-lock_conflict {nmodes {matrix}}?");
  715. result = TCL_ERROR;
  716. break;
  717. }
  718. result = Tcl_GetIntFromObj(interp, myobjv[0], &nmodes);
  719. if (result != TCL_OK)
  720. break;
  721. result = Tcl_ListObjGetElements(interp, myobjv[1],
  722.     &myobjc, &myobjv1);
  723. if (myobjc != (nmodes * nmodes)) {
  724. Tcl_WrongNumArgs(interp, 2, objv,
  725.     "?-lock_conflict {nmodes {matrix}}?");
  726. result = TCL_ERROR;
  727. break;
  728. }
  729. size = sizeof(u_int8_t) * nmodes*nmodes;
  730. ret = __os_malloc(*env, size, NULL, &conflicts);
  731. if (ret != 0) {
  732. result = TCL_ERROR;
  733. break;
  734. }
  735. for (j = 0; j < myobjc; j++) {
  736. result = Tcl_GetIntFromObj(interp, myobjv1[j],
  737.     &temp);
  738. conflicts[j] = temp;
  739. if (result != TCL_OK) {
  740. __os_free(conflicts, size);
  741. break;
  742. }
  743. }
  744. _debug_check();
  745. ret = (*env)->set_lk_conflicts(*env,
  746.     (u_int8_t *)conflicts, nmodes);
  747. __os_free(conflicts, size);
  748. result = _ReturnSetup(interp, ret, "set_lk_conflicts");
  749. break;
  750. case ENV_DETECT:
  751. if (i >= objc) {
  752. Tcl_WrongNumArgs(interp, 2, objv,
  753.     "?-lock_detect policy?");
  754. result = TCL_ERROR;
  755. break;
  756. }
  757. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  758. if (strcmp(arg, "default") == 0)
  759. detect = DB_LOCK_DEFAULT;
  760. else if (strcmp(arg, "oldest") == 0)
  761. detect = DB_LOCK_OLDEST;
  762. else if (strcmp(arg, "youngest") == 0)
  763. detect = DB_LOCK_YOUNGEST;
  764. else if (strcmp(arg, "random") == 0)
  765. detect = DB_LOCK_RANDOM;
  766. else {
  767. Tcl_AddErrorInfo(interp,
  768.     "lock_detect: illegal policy");
  769. result = TCL_ERROR;
  770. break;
  771. }
  772. _debug_check();
  773. ret = (*env)->set_lk_detect(*env, detect);
  774. result = _ReturnSetup(interp, ret, "lock_detect");
  775. break;
  776. case ENV_LOCK_MAX:
  777. case ENV_LOCK_MAX_LOCKS:
  778. case ENV_LOCK_MAX_LOCKERS:
  779. case ENV_LOCK_MAX_OBJECTS:
  780. if (i >= objc) {
  781. Tcl_WrongNumArgs(interp, 2, objv,
  782.     "?-lock_max max?");
  783. result = TCL_ERROR;
  784. break;
  785. }
  786. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  787. if (result == TCL_OK) {
  788. _debug_check();
  789. switch ((enum envopen)optindex) {
  790. case ENV_LOCK_MAX:
  791. ret = (*env)->set_lk_max(*env,
  792.     (u_int32_t)intarg);
  793. break;
  794. case ENV_LOCK_MAX_LOCKS:
  795. ret = (*env)->set_lk_max_locks(*env,
  796.     (u_int32_t)intarg);
  797. break;
  798. case ENV_LOCK_MAX_LOCKERS:
  799. ret = (*env)->set_lk_max_lockers(*env,
  800.     (u_int32_t)intarg);
  801. break;
  802. case ENV_LOCK_MAX_OBJECTS:
  803. ret = (*env)->set_lk_max_objects(*env,
  804.      (u_int32_t)intarg);
  805. break;
  806. default:
  807. break;
  808. }
  809. result = _ReturnSetup(interp, ret, "lock_max");
  810. }
  811. break;
  812. case ENV_TXN_MAX:
  813. if (i >= objc) {
  814. Tcl_WrongNumArgs(interp, 2, objv,
  815.     "?-txn_max max?");
  816. result = TCL_ERROR;
  817. break;
  818. }
  819. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  820. if (result == TCL_OK) {
  821. _debug_check();
  822. ret = (*env)->set_tx_max(*env,
  823.     (u_int32_t)intarg);
  824. result = _ReturnSetup(interp, ret, "txn_max");
  825. }
  826. break;
  827. case ENV_TXN_TIME:
  828. if (i >= objc) {
  829. Tcl_WrongNumArgs(interp, 2, objv,
  830.     "?-txn_timestamp time?");
  831. result = TCL_ERROR;
  832. break;
  833. }
  834. result = Tcl_GetLongFromObj(interp, objv[i++],
  835.     (long *)&time);
  836. if (result == TCL_OK) {
  837. _debug_check();
  838. ret = (*env)->set_tx_timestamp(*env, &time);
  839. result = _ReturnSetup(interp, ret,
  840.     "txn_timestamp");
  841. }
  842. break;
  843. case ENV_ERRFILE:
  844. if (i >= objc) {
  845. Tcl_WrongNumArgs(interp, 2, objv,
  846.     "-errfile file");
  847. result = TCL_ERROR;
  848. break;
  849. }
  850. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  851. /*
  852.  * If the user already set one, close it.
  853.  */
  854. if (ip->i_err != NULL)
  855. fclose(ip->i_err);
  856. ip->i_err = fopen(arg, "a");
  857. if (ip->i_err != NULL) {
  858. _debug_check();
  859. (*env)->set_errfile(*env, ip->i_err);
  860. }
  861. break;
  862. case ENV_ERRPFX:
  863. if (i >= objc) {
  864. Tcl_WrongNumArgs(interp, 2, objv,
  865.     "-errpfx prefix");
  866. result = TCL_ERROR;
  867. break;
  868. }
  869. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  870. /*
  871.  * If the user already set one, free it.
  872.  */
  873. if (ip->i_errpfx != NULL)
  874. __os_freestr(ip->i_errpfx);
  875. if ((ret =
  876.     __os_strdup(*env, arg, &ip->i_errpfx)) != 0) {
  877. result = _ReturnSetup(interp, ret,
  878.     "__os_strdup");
  879. break;
  880. }
  881. if (ip->i_errpfx != NULL) {
  882. _debug_check();
  883. (*env)->set_errpfx(*env, ip->i_errpfx);
  884. }
  885. break;
  886. case ENV_DATA_DIR:
  887. if (i >= objc) {
  888. Tcl_WrongNumArgs(interp, 2, objv,
  889.     "-data_dir dir");
  890. result = TCL_ERROR;
  891. break;
  892. }
  893. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  894. _debug_check();
  895. ret = (*env)->set_data_dir(*env, arg);
  896. result = _ReturnSetup(interp, ret, "set_data_dir");
  897. break;
  898. case ENV_LOG_DIR:
  899. if (i >= objc) {
  900. Tcl_WrongNumArgs(interp, 2, objv,
  901.     "-log_dir dir");
  902. result = TCL_ERROR;
  903. break;
  904. }
  905. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  906. _debug_check();
  907. ret = (*env)->set_lg_dir(*env, arg);
  908. result = _ReturnSetup(interp, ret, "set_lg_dir");
  909. break;
  910. case ENV_TMP_DIR:
  911. if (i >= objc) {
  912. Tcl_WrongNumArgs(interp, 2, objv,
  913.     "-tmp_dir dir");
  914. result = TCL_ERROR;
  915. break;
  916. }
  917. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  918. _debug_check();
  919. ret = (*env)->set_tmp_dir(*env, arg);
  920. result = _ReturnSetup(interp, ret, "set_tmp_dir");
  921. break;
  922. }
  923. /*
  924.  * If, at any time, parsing the args we get an error,
  925.  * bail out and return.
  926.  */
  927. if (result != TCL_OK)
  928. goto error;
  929. }
  930. /*
  931.  * We have to check this here.  We want to set the log buffer
  932.  * size first, if it is specified.  So if the user did so,
  933.  * then we took care of it above.  But, if we get out here and
  934.  * logmaxset is non-zero, then they set the log_max without
  935.  * resetting the log buffer size, so we now have to do the
  936.  * call to set_lg_max, since we didn't do it above.
  937.  */
  938. if (logmaxset) {
  939. _debug_check();
  940. ret = (*env)->set_lg_max(*env, (u_int32_t)logmaxset);
  941. result = _ReturnSetup(interp, ret, "log_max");
  942. }
  943. if (result != TCL_OK)
  944. goto error;
  945. if (set_flag) {
  946. ret = (*env)->set_flags(*env, set_flag, 1);
  947. result = _ReturnSetup(interp, ret, "set_flags");
  948. if (result == TCL_ERROR)
  949. goto error;
  950. /*
  951.  * If we are successful, clear the result so that the
  952.  * return from set_flags isn't part of the result.
  953.  */
  954. Tcl_ResetResult(interp);
  955. }
  956. /*
  957.  * When we get here, we have already parsed all of our args
  958.  * and made all our calls to set up the environment.  Everything
  959.  * is okay so far, no errors, if we get here.
  960.  *
  961.  * Now open the environment.
  962.  */
  963. _debug_check();
  964. ret = (*env)->open(*env, home, open_flags, mode);
  965. result = _ReturnSetup(interp, ret, "env open");
  966. error:
  967. if (result == TCL_ERROR) {
  968. if (ip->i_err) {
  969. fclose(ip->i_err);
  970. ip->i_err = NULL;
  971. }
  972. (void)(*env)->close(*env, 0);
  973. *env = NULL;
  974. }
  975. return (result);
  976. }
  977. /*
  978.  * bdb_DbOpen --
  979.  * Implements the "db_create/db_open" command.
  980.  * There are many, many options to the open command.
  981.  * Here is the general flow:
  982.  *
  983.  * 0.  Preparse args to determine if we have -env.
  984.  * 1.  Call db_create to create the db handle.
  985.  * 2.  Parse args tracking options.
  986.  * 3.  Make any pre-open setup calls necessary.
  987.  * 4.  Call DB->open to open the database.
  988.  * 5.  Return db widget handle to user.
  989.  */
  990. static int
  991. bdb_DbOpen(interp, objc, objv, ip, dbp)
  992. Tcl_Interp *interp; /* Interpreter */
  993. int objc; /* How many arguments? */
  994. Tcl_Obj *CONST objv[]; /* The argument objects */
  995. DBTCL_INFO *ip; /* Our internal info */
  996. DB **dbp; /* DB handle */
  997. {
  998. static char *bdbenvopen[] = {
  999. "-env", NULL
  1000. };
  1001. enum bdbenvopen {
  1002. TCL_DB_ENV0
  1003. };
  1004. static char *bdbopen[] = {
  1005. "-btree",
  1006. "-cachesize",
  1007. "-create",
  1008. "-delim",
  1009. "-dup",
  1010. "-dupsort",
  1011. "-env",
  1012. "-errfile",
  1013. "-errpfx",
  1014. "-excl",
  1015. "-extent",
  1016. "-ffactor",
  1017. "-hash",
  1018. "-len",
  1019. "-lorder",
  1020. "-minkey",
  1021. "-mode",
  1022. "-nelem",
  1023. "-nommap",
  1024. "-pad",
  1025. "-pagesize",
  1026. "-queue",
  1027. "-rdonly",
  1028. "-recno",
  1029. "-recnum",
  1030. "-renumber",
  1031. "-revsplitoff",
  1032. "-snapshot",
  1033. "-source",
  1034. "-truncate",
  1035. "-test",
  1036. "-unknown",
  1037. "--",
  1038. NULL
  1039. };
  1040. enum bdbopen {
  1041. TCL_DB_BTREE,
  1042. TCL_DB_CACHESIZE,
  1043. TCL_DB_CREATE,
  1044. TCL_DB_DELIM,
  1045. TCL_DB_DUP,
  1046. TCL_DB_DUPSORT,
  1047. TCL_DB_ENV,
  1048. TCL_DB_ERRFILE,
  1049. TCL_DB_ERRPFX,
  1050. TCL_DB_EXCL,
  1051. TCL_DB_EXTENT,
  1052. TCL_DB_FFACTOR,
  1053. TCL_DB_HASH,
  1054. TCL_DB_LEN,
  1055. TCL_DB_LORDER,
  1056. TCL_DB_MINKEY,
  1057. TCL_DB_MODE,
  1058. TCL_DB_NELEM,
  1059. TCL_DB_NOMMAP,
  1060. TCL_DB_PAD,
  1061. TCL_DB_PAGESIZE,
  1062. TCL_DB_QUEUE,
  1063. TCL_DB_RDONLY,
  1064. TCL_DB_RECNO,
  1065. TCL_DB_RECNUM,
  1066. TCL_DB_RENUMBER,
  1067. TCL_DB_REVSPLIT,
  1068. TCL_DB_SNAPSHOT,
  1069. TCL_DB_SOURCE,
  1070. TCL_DB_TRUNCATE,
  1071. TCL_DB_TEST,
  1072. TCL_DB_UNKNOWN,
  1073. TCL_DB_ENDARG
  1074. };
  1075. DBTCL_INFO *envip, *errip;
  1076. DBTYPE type;
  1077. DB_ENV *envp;
  1078. Tcl_Obj **myobjv;
  1079. u_int32_t gbytes, bytes, ncaches, open_flags;
  1080. int endarg, i, intarg, itmp, j, mode, myobjc;
  1081. int optindex, result, ret, set_err, set_flag, set_pfx, subdblen;
  1082. u_char *subdbtmp;
  1083. char *arg, *db, *subdb;
  1084. extern u_int32_t __ham_test __P((DB *, const void *, u_int32_t));
  1085. type = DB_UNKNOWN;
  1086. endarg = mode = set_err = set_flag = set_pfx = 0;
  1087. result = TCL_OK;
  1088. subdbtmp = NULL;
  1089. db = subdb = NULL;
  1090. /*
  1091.  * XXX
  1092.  * If/when our Tcl interface becomes thread-safe, we should enable
  1093.  * DB_THREAD here.  See comment in bdb_EnvOpen().
  1094.  */
  1095. open_flags = 0;
  1096. envp = NULL;
  1097. if (objc < 2) {
  1098. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  1099. return (TCL_ERROR);
  1100. }
  1101. /*
  1102.  * We must first parse for the environment flag, since that
  1103.  * is needed for db_create.  Then create the db handle.
  1104.  */
  1105. i = 2;
  1106. while (i < objc) {
  1107. if (Tcl_GetIndexFromObj(interp, objv[i++], bdbenvopen,
  1108.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  1109. /*
  1110.  * Reset the result so we don't get
  1111.  * an errant error message if there is another error.
  1112.  */
  1113. Tcl_ResetResult(interp);
  1114. continue;
  1115. }
  1116. switch ((enum bdbenvopen)optindex) {
  1117. case TCL_DB_ENV0:
  1118. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1119. envp = NAME_TO_ENV(arg);
  1120. if (envp == NULL) {
  1121. Tcl_SetResult(interp,
  1122.     "db open: illegal environment", TCL_STATIC);
  1123. return (TCL_ERROR);
  1124. }
  1125. }
  1126. break;
  1127. }
  1128. /*
  1129.  * Create the db handle before parsing the args
  1130.  * since we'll be modifying the database options as we parse.
  1131.  */
  1132. ret = db_create(dbp, envp, 0);
  1133. if (ret)
  1134. return (_ReturnSetup(interp, ret, "db_create"));
  1135. /*
  1136.  * XXX Remove restriction when err stuff is not tied to env.
  1137.  *
  1138.  * The DB->set_err* functions actually overwrite in the
  1139.  * environment.  So, if we are explicitly using an env,
  1140.  * don't overwrite what we have already set up.  If we are
  1141.  * not using one, then we set up since we get a private
  1142.  * default env.
  1143.  */
  1144. /* XXX  - remove this conditional if/when err is not tied to env */
  1145. if (envp == NULL) {
  1146. (*dbp)->set_errpfx((*dbp), ip->i_name);
  1147. (*dbp)->set_errcall((*dbp), _ErrorFunc);
  1148. }
  1149. envip = _PtrToInfo(envp); /* XXX */
  1150. /*
  1151.  * If we are using an env, we keep track of err info in the env's ip.
  1152.  * Otherwise use the DB's ip.
  1153.  */
  1154. if (envip)
  1155. errip = envip;
  1156. else
  1157. errip = ip;
  1158. /*
  1159.  * Get the option name index from the object based on the args
  1160.  * defined above.
  1161.  */
  1162. i = 2;
  1163. while (i < objc) {
  1164. if (Tcl_GetIndexFromObj(interp, objv[i], bdbopen, "option",
  1165.     TCL_EXACT, &optindex) != TCL_OK) {
  1166. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1167. if (arg[0] == '-') {
  1168. result = IS_HELP(objv[i]);
  1169. goto error;
  1170. } else
  1171. Tcl_ResetResult(interp);
  1172. break;
  1173. }
  1174. i++;
  1175. switch ((enum bdbopen)optindex) {
  1176. case TCL_DB_ENV:
  1177. /*
  1178.  * Already parsed this, skip it and the env pointer.
  1179.  */
  1180. i++;
  1181. continue;
  1182. case TCL_DB_BTREE:
  1183. if (type != DB_UNKNOWN) {
  1184. Tcl_SetResult(interp,
  1185.     "Too many DB types specified", TCL_STATIC);
  1186. result = TCL_ERROR;
  1187. goto error;
  1188. }
  1189. type = DB_BTREE;
  1190. break;
  1191. case TCL_DB_HASH:
  1192. if (type != DB_UNKNOWN) {
  1193. Tcl_SetResult(interp,
  1194.     "Too many DB types specified", TCL_STATIC);
  1195. result = TCL_ERROR;
  1196. goto error;
  1197. }
  1198. type = DB_HASH;
  1199. break;
  1200. case TCL_DB_RECNO:
  1201. if (type != DB_UNKNOWN) {
  1202. Tcl_SetResult(interp,
  1203.     "Too many DB types specified", TCL_STATIC);
  1204. result = TCL_ERROR;
  1205. goto error;
  1206. }
  1207. type = DB_RECNO;
  1208. break;
  1209. case TCL_DB_QUEUE:
  1210. if (type != DB_UNKNOWN) {
  1211. Tcl_SetResult(interp,
  1212.     "Too many DB types specified", TCL_STATIC);
  1213. result = TCL_ERROR;
  1214. goto error;
  1215. }
  1216. type = DB_QUEUE;
  1217. break;
  1218. case TCL_DB_UNKNOWN:
  1219. if (type != DB_UNKNOWN) {
  1220. Tcl_SetResult(interp,
  1221.     "Too many DB types specified", TCL_STATIC);
  1222. result = TCL_ERROR;
  1223. goto error;
  1224. }
  1225. break;
  1226. case TCL_DB_CREATE:
  1227. open_flags |= DB_CREATE;
  1228. break;
  1229. case TCL_DB_EXCL:
  1230. open_flags |= DB_EXCL;
  1231. break;
  1232. case TCL_DB_RDONLY:
  1233. open_flags |= DB_RDONLY;
  1234. break;
  1235. case TCL_DB_TRUNCATE:
  1236. open_flags |= DB_TRUNCATE;
  1237. break;
  1238. case TCL_DB_TEST:
  1239. (*dbp)->set_h_hash(*dbp, __ham_test);
  1240. break;
  1241. case TCL_DB_MODE:
  1242. if (i >= objc) {
  1243. Tcl_WrongNumArgs(interp, 2, objv,
  1244.     "?-mode mode?");
  1245. result = TCL_ERROR;
  1246. break;
  1247. }
  1248. /*
  1249.  * Don't need to check result here because
  1250.  * if TCL_ERROR, the error message is already
  1251.  * set up, and we'll bail out below.  If ok,
  1252.  * the mode is set and we go on.
  1253.  */
  1254. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  1255. break;
  1256. case TCL_DB_NOMMAP:
  1257. open_flags |= DB_NOMMAP;
  1258. break;
  1259. case TCL_DB_DUP:
  1260. set_flag |= DB_DUP;
  1261. break;
  1262. case TCL_DB_DUPSORT:
  1263. set_flag |= DB_DUPSORT;
  1264. break;
  1265. case TCL_DB_RECNUM:
  1266. set_flag |= DB_RECNUM;
  1267. break;
  1268. case TCL_DB_RENUMBER:
  1269. set_flag |= DB_RENUMBER;
  1270. break;
  1271. case TCL_DB_REVSPLIT:
  1272. set_flag |= DB_REVSPLITOFF;
  1273. break;
  1274. case TCL_DB_SNAPSHOT:
  1275. set_flag |= DB_SNAPSHOT;
  1276. break;
  1277. case TCL_DB_FFACTOR:
  1278. if (i >= objc) {
  1279. Tcl_WrongNumArgs(interp, 2, objv,
  1280.     "-ffactor density");
  1281. result = TCL_ERROR;
  1282. break;
  1283. }
  1284. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1285. if (result == TCL_OK) {
  1286. _debug_check();
  1287. ret = (*dbp)->set_h_ffactor(*dbp,
  1288.     (u_int32_t)intarg);
  1289. result = _ReturnSetup(interp, ret,
  1290.     "set_h_ffactor");
  1291. }
  1292. break;
  1293. case TCL_DB_NELEM:
  1294. if (i >= objc) {
  1295. Tcl_WrongNumArgs(interp, 2, objv,
  1296.     "-nelem nelem");
  1297. result = TCL_ERROR;
  1298. break;
  1299. }
  1300. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1301. if (result == TCL_OK) {
  1302. _debug_check();
  1303. ret = (*dbp)->set_h_nelem(*dbp,
  1304.     (u_int32_t)intarg);
  1305. result = _ReturnSetup(interp, ret,
  1306.     "set_h_nelem");
  1307. }
  1308. break;
  1309. case TCL_DB_LORDER:
  1310. if (i >= objc) {
  1311. Tcl_WrongNumArgs(interp, 2, objv,
  1312.     "-lorder 1234|4321");
  1313. result = TCL_ERROR;
  1314. break;
  1315. }
  1316. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1317. if (result == TCL_OK) {
  1318. _debug_check();
  1319. ret = (*dbp)->set_lorder(*dbp,
  1320.     (u_int32_t)intarg);
  1321. result = _ReturnSetup(interp, ret,
  1322.     "set_lorder");
  1323. }
  1324. break;
  1325. case TCL_DB_DELIM:
  1326. if (i >= objc) {
  1327. Tcl_WrongNumArgs(interp, 2, objv,
  1328.     "-delim delim");
  1329. result = TCL_ERROR;
  1330. break;
  1331. }
  1332. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1333. if (result == TCL_OK) {
  1334. _debug_check();
  1335. ret = (*dbp)->set_re_delim(*dbp, intarg);
  1336. result = _ReturnSetup(interp, ret,
  1337.     "set_re_delim");
  1338. }
  1339. break;
  1340. case TCL_DB_LEN:
  1341. if (i >= objc) {
  1342. Tcl_WrongNumArgs(interp, 2, objv,
  1343.     "-len length");
  1344. result = TCL_ERROR;
  1345. break;
  1346. }
  1347. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1348. if (result == TCL_OK) {
  1349. _debug_check();
  1350. ret = (*dbp)->set_re_len(*dbp,
  1351.     (u_int32_t)intarg);
  1352. result = _ReturnSetup(interp, ret,
  1353.     "set_re_len");
  1354. }
  1355. break;
  1356. case TCL_DB_PAD:
  1357. if (i >= objc) {
  1358. Tcl_WrongNumArgs(interp, 2, objv,
  1359.     "-pad pad");
  1360. result = TCL_ERROR;
  1361. break;
  1362. }
  1363. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1364. if (result == TCL_OK) {
  1365. _debug_check();
  1366. ret = (*dbp)->set_re_pad(*dbp, intarg);
  1367. result = _ReturnSetup(interp, ret,
  1368.     "set_re_pad");
  1369. }
  1370. break;
  1371. case TCL_DB_SOURCE:
  1372. if (i >= objc) {
  1373. Tcl_WrongNumArgs(interp, 2, objv,
  1374.     "-source file");
  1375. result = TCL_ERROR;
  1376. break;
  1377. }
  1378. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1379. _debug_check();
  1380. ret = (*dbp)->set_re_source(*dbp, arg);
  1381. result = _ReturnSetup(interp, ret, "set_re_source");
  1382. break;
  1383. case TCL_DB_EXTENT:
  1384. if (i >= objc) {
  1385. Tcl_WrongNumArgs(interp, 2, objv,
  1386.     "-extent size");
  1387. result = TCL_ERROR;
  1388. break;
  1389. }
  1390. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1391. if (result == TCL_OK) {
  1392. _debug_check();
  1393. ret = (*dbp)->set_q_extentsize(*dbp,
  1394.     (u_int32_t)intarg);
  1395. result = _ReturnSetup(interp, ret,
  1396.     "set_q_extentsize");
  1397. }
  1398. break;
  1399. case TCL_DB_MINKEY:
  1400. if (i >= objc) {
  1401. Tcl_WrongNumArgs(interp, 2, objv,
  1402.     "-minkey minkey");
  1403. result = TCL_ERROR;
  1404. break;
  1405. }
  1406. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1407. if (result == TCL_OK) {
  1408. _debug_check();
  1409. ret = (*dbp)->set_bt_minkey(*dbp, intarg);
  1410. result = _ReturnSetup(interp, ret,
  1411.     "set_bt_minkey");
  1412. }
  1413. break;
  1414. case TCL_DB_CACHESIZE:
  1415. result = Tcl_ListObjGetElements(interp, objv[i++],
  1416.     &myobjc, &myobjv);
  1417. if (result != TCL_OK)
  1418. break;
  1419. j = 0;
  1420. if (myobjc != 3) {
  1421. Tcl_WrongNumArgs(interp, 2, objv,
  1422.     "?-cachesize {gbytes bytes ncaches}?");
  1423. result = TCL_ERROR;
  1424. break;
  1425. }
  1426. result = Tcl_GetIntFromObj(interp, myobjv[0], &itmp);
  1427. gbytes = itmp;
  1428. if (result != TCL_OK)
  1429. break;
  1430. result = Tcl_GetIntFromObj(interp, myobjv[1], &itmp);
  1431. bytes = itmp;
  1432. if (result != TCL_OK)
  1433. break;
  1434. result = Tcl_GetIntFromObj(interp, myobjv[2], &itmp);
  1435. ncaches = itmp;
  1436. if (result != TCL_OK)
  1437. break;
  1438. _debug_check();
  1439. ret = (*dbp)->set_cachesize(*dbp, gbytes, bytes,
  1440.     ncaches);
  1441. result = _ReturnSetup(interp, ret,
  1442.     "set_cachesize");
  1443. break;
  1444. case TCL_DB_PAGESIZE:
  1445. if (i >= objc) {
  1446. Tcl_WrongNumArgs(interp, 2, objv,
  1447.     "?-pagesize size?");
  1448. result = TCL_ERROR;
  1449. break;
  1450. }
  1451. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1452. if (result == TCL_OK) {
  1453. _debug_check();
  1454. ret = (*dbp)->set_pagesize(*dbp,
  1455.     (size_t)intarg);
  1456. result = _ReturnSetup(interp, ret,
  1457.     "set pagesize");
  1458. }
  1459. break;
  1460. case TCL_DB_ERRFILE:
  1461. if (i >= objc) {
  1462. Tcl_WrongNumArgs(interp, 2, objv,
  1463.     "-errfile file");
  1464. result = TCL_ERROR;
  1465. break;
  1466. }
  1467. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1468. /*
  1469.  * If the user already set one, close it.
  1470.  */
  1471. if (errip->i_err != NULL)
  1472. fclose(errip->i_err);
  1473. errip->i_err = fopen(arg, "a");
  1474. if (errip->i_err != NULL) {
  1475. _debug_check();
  1476. (*dbp)->set_errfile(*dbp, errip->i_err);
  1477. set_err = 1;
  1478. }
  1479. break;
  1480. case TCL_DB_ERRPFX:
  1481. if (i >= objc) {
  1482. Tcl_WrongNumArgs(interp, 2, objv,
  1483.     "-errpfx prefix");
  1484. result = TCL_ERROR;
  1485. break;
  1486. }
  1487. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1488. /*
  1489.  * If the user already set one, free it.
  1490.  */
  1491. if (errip->i_errpfx != NULL)
  1492. __os_freestr(errip->i_errpfx);
  1493. if ((ret = __os_strdup((*dbp)->dbenv,
  1494.     arg, &errip->i_errpfx)) != 0) {
  1495. result = _ReturnSetup(interp, ret,
  1496.     "__os_strdup");
  1497. break;
  1498. }
  1499. if (errip->i_errpfx != NULL) {
  1500. _debug_check();
  1501. (*dbp)->set_errpfx(*dbp, errip->i_errpfx);
  1502. set_pfx = 1;
  1503. }
  1504. break;
  1505. case TCL_DB_ENDARG:
  1506. endarg = 1;
  1507. break;
  1508. } /* switch */
  1509. /*
  1510.  * If, at any time, parsing the args we get an error,
  1511.  * bail out and return.
  1512.  */
  1513. if (result != TCL_OK)
  1514. goto error;
  1515. if (endarg)
  1516. break;
  1517. }
  1518. if (result != TCL_OK)
  1519. goto error;
  1520. /*
  1521.  * Any args we have left, (better be 0, 1 or 2 left) are
  1522.  * file names.  If we have 0, then an in-memory db.  If
  1523.  * there is 1, a db name, if 2 a db and subdb name.
  1524.  */
  1525. if (i != objc) {
  1526. /*
  1527.  * Dbs must be NULL terminated file names, but subdbs can
  1528.  * be anything.  Use Strings for the db name and byte
  1529.  * arrays for the subdb.
  1530.  */
  1531. db = Tcl_GetStringFromObj(objv[i++], NULL);
  1532. if (i != objc) {
  1533. subdbtmp =
  1534.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  1535. if ((ret = __os_malloc(envp,
  1536.    subdblen + 1, NULL, &subdb)) != 0) {
  1537. Tcl_SetResult(interp, db_strerror(ret),
  1538.     TCL_STATIC);
  1539. return (0);
  1540. }
  1541. memcpy(subdb, subdbtmp, subdblen);
  1542. subdb[subdblen] = '';
  1543. }
  1544. }
  1545. if (set_flag) {
  1546. ret = (*dbp)->set_flags(*dbp, set_flag);
  1547. result = _ReturnSetup(interp, ret, "set_flags");
  1548. if (result == TCL_ERROR)
  1549. goto error;
  1550. /*
  1551.  * If we are successful, clear the result so that the
  1552.  * return from set_flags isn't part of the result.
  1553.  */
  1554. Tcl_ResetResult(interp);
  1555. }
  1556. /*
  1557.  * When we get here, we have already parsed all of our args and made
  1558.  * all our calls to set up the database.  Everything is okay so far,
  1559.  * no errors, if we get here.
  1560.  */
  1561. _debug_check();
  1562. /* Open the database. */
  1563. ret = (*dbp)->open(*dbp, db, subdb, type, open_flags, mode);
  1564. result = _ReturnSetup(interp, ret, "db open");
  1565. error:
  1566. if (subdb)
  1567. __os_free(subdb, subdblen + 1);
  1568. if (result == TCL_ERROR) {
  1569. /*
  1570.  * If we opened and set up the error file in the environment
  1571.  * on this open, but we failed for some other reason, clean
  1572.  * up and close the file.
  1573.  *
  1574.  * XXX when err stuff isn't tied to env, change to use ip,
  1575.  * instead of envip.  Also, set_err is irrelevant when that
  1576.  * happens.  It will just read:
  1577.  * if (ip->i_err)
  1578.  * fclose(ip->i_err);
  1579.  */
  1580. if (set_err && errip && errip->i_err != NULL) {
  1581. fclose(errip->i_err);
  1582. errip->i_err = NULL;
  1583. }
  1584. if (set_pfx && errip && errip->i_errpfx != NULL) {
  1585. __os_freestr(errip->i_errpfx);
  1586. errip->i_errpfx = NULL;
  1587. }
  1588. (void)(*dbp)->close(*dbp, 0);
  1589. *dbp = NULL;
  1590. }
  1591. return (result);
  1592. }
  1593. /*
  1594.  * bdb_DbRemove --
  1595.  * Implements the DB->remove command.
  1596.  */
  1597. static int
  1598. bdb_DbRemove(interp, objc, objv)
  1599. Tcl_Interp *interp; /* Interpreter */
  1600. int objc; /* How many arguments? */
  1601. Tcl_Obj *CONST objv[]; /* The argument objects */
  1602. {
  1603. static char *bdbrem[] = {
  1604. "-env", "--", NULL
  1605. };
  1606. enum bdbrem {
  1607. TCL_DBREM_ENV,
  1608. TCL_DBREM_ENDARG
  1609. };
  1610. DB_ENV *envp;
  1611. DB *dbp;
  1612. int endarg, i, optindex, result, ret, subdblen;
  1613. u_char *subdbtmp;
  1614. char *arg, *db, *subdb;
  1615. envp = NULL;
  1616. dbp = NULL;
  1617. result = TCL_OK;
  1618. subdbtmp = NULL;
  1619. db = subdb = NULL;
  1620. endarg = 0;
  1621. if (objc < 2) {
  1622. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?");
  1623. return (TCL_ERROR);
  1624. }
  1625. /*
  1626.  * We must first parse for the environment flag, since that
  1627.  * is needed for db_create.  Then create the db handle.
  1628.  */
  1629. i = 2;
  1630. while (i < objc) {
  1631. if (Tcl_GetIndexFromObj(interp, objv[i], bdbrem,
  1632.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  1633. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1634. if (arg[0] == '-') {
  1635. result = IS_HELP(objv[i]);
  1636. goto error;
  1637. } else
  1638. Tcl_ResetResult(interp);
  1639. break;
  1640. }
  1641. i++;
  1642. switch ((enum bdbrem)optindex) {
  1643. case TCL_DBREM_ENV:
  1644. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1645. envp = NAME_TO_ENV(arg);
  1646. if (envp == NULL) {
  1647. Tcl_SetResult(interp,
  1648.     "db remove: illegal environment",
  1649.     TCL_STATIC);
  1650. return (TCL_ERROR);
  1651. }
  1652. break;
  1653. case TCL_DBREM_ENDARG:
  1654. endarg = 1;
  1655. break;
  1656. }
  1657. /*
  1658.  * If, at any time, parsing the args we get an error,
  1659.  * bail out and return.
  1660.  */
  1661. if (result != TCL_OK)
  1662. goto error;
  1663. if (endarg)
  1664. break;
  1665. }
  1666. if (result != TCL_OK)
  1667. goto error;
  1668. /*
  1669.  * Any args we have left, (better be 1 or 2 left) are
  1670.  * file names. If there is 1, a db name, if 2 a db and subdb name.
  1671.  */
  1672. if ((i != (objc - 1)) || (i != (objc - 2))) {
  1673. /*
  1674.  * Dbs must be NULL terminated file names, but subdbs can
  1675.  * be anything.  Use Strings for the db name and byte
  1676.  * arrays for the subdb.
  1677.  */
  1678. db = Tcl_GetStringFromObj(objv[i++], NULL);
  1679. if (i != objc) {
  1680. subdbtmp =
  1681.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  1682. if ((ret = __os_malloc(envp, subdblen + 1,
  1683.     NULL, &subdb)) != 0) { Tcl_SetResult(interp,
  1684.     db_strerror(ret), TCL_STATIC);
  1685. return (0);
  1686. }
  1687. memcpy(subdb, subdbtmp, subdblen);
  1688. subdb[subdblen] = '';
  1689. }
  1690. } else {
  1691. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?");
  1692. result = TCL_ERROR;
  1693. goto error;
  1694. }
  1695. ret = db_create(&dbp, envp, 0);
  1696. if (ret) {
  1697. result = _ReturnSetup(interp, ret, "db_create");
  1698. goto error;
  1699. }
  1700. /*
  1701.  * No matter what, we NULL out dbp after this call.
  1702.  */
  1703. ret = dbp->remove(dbp, db, subdb, 0);
  1704. result = _ReturnSetup(interp, ret, "db remove");
  1705. dbp = NULL;
  1706. error:
  1707. if (subdb)
  1708. __os_free(subdb, subdblen + 1);
  1709. if (result == TCL_ERROR && dbp)
  1710. (void)dbp->close(dbp, 0);
  1711. return (result);
  1712. }
  1713. /*
  1714.  * bdb_DbRename --
  1715.  * Implements the DB->rename command.
  1716.  */
  1717. static int
  1718. bdb_DbRename(interp, objc, objv)
  1719. Tcl_Interp *interp; /* Interpreter */
  1720. int objc; /* How many arguments? */
  1721. Tcl_Obj *CONST objv[]; /* The argument objects */
  1722. {
  1723. static char *bdbmv[] = {
  1724. "-env", "--", NULL
  1725. };
  1726. enum bdbmv {
  1727. TCL_DBMV_ENV,
  1728. TCL_DBMV_ENDARG
  1729. };
  1730. DB_ENV *envp;
  1731. DB *dbp;
  1732. int endarg, i, newlen, optindex, result, ret, subdblen;
  1733. u_char *subdbtmp;
  1734. char *arg, *db, *newname, *subdb;
  1735. envp = NULL;
  1736. dbp = NULL;
  1737. result = TCL_OK;
  1738. subdbtmp = NULL;
  1739. db = newname = subdb = NULL;
  1740. endarg = 0;
  1741. if (objc < 2) {
  1742. Tcl_WrongNumArgs(interp,
  1743. 3, objv, "?args? filename ?database? ?newname?");
  1744. return (TCL_ERROR);
  1745. }
  1746. /*
  1747.  * We must first parse for the environment flag, since that
  1748.  * is needed for db_create.  Then create the db handle.
  1749.  */
  1750. i = 2;
  1751. while (i < objc) {
  1752. if (Tcl_GetIndexFromObj(interp, objv[i], bdbmv,
  1753.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  1754. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1755. if (arg[0] == '-') {
  1756. result = IS_HELP(objv[i]);
  1757. goto error;
  1758. } else
  1759. Tcl_ResetResult(interp);
  1760. break;
  1761. }
  1762. i++;
  1763. switch ((enum bdbmv)optindex) {
  1764. case TCL_DBMV_ENV:
  1765. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1766. envp = NAME_TO_ENV(arg);
  1767. if (envp == NULL) {
  1768. Tcl_SetResult(interp,
  1769.     "db rename: illegal environment",
  1770.     TCL_STATIC);
  1771. return (TCL_ERROR);
  1772. }
  1773. break;
  1774. case TCL_DBMV_ENDARG:
  1775. endarg = 1;
  1776. break;
  1777. }
  1778. /*
  1779.  * If, at any time, parsing the args we get an error,
  1780.  * bail out and return.
  1781.  */
  1782. if (result != TCL_OK)
  1783. goto error;
  1784. if (endarg)
  1785. break;
  1786. }
  1787. if (result != TCL_OK)
  1788. goto error;
  1789. /*
  1790.  * Any args we have left, (better be 2 or 3 left) are
  1791.  * file names. If there is 2, a file name, if 3 a file and db name.
  1792.  */
  1793. if ((i != (objc - 2)) || (i != (objc - 3))) {
  1794. /*
  1795.  * Dbs must be NULL terminated file names, but subdbs can
  1796.  * be anything.  Use Strings for the db name and byte
  1797.  * arrays for the subdb.
  1798.  */
  1799. db = Tcl_GetStringFromObj(objv[i++], NULL);
  1800. if (i == objc - 2) {
  1801. subdbtmp =
  1802.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  1803. if ((ret = __os_malloc(envp, subdblen + 1,
  1804.     NULL, &subdb)) != 0) {
  1805. Tcl_SetResult(interp,
  1806.     db_strerror(ret), TCL_STATIC);
  1807. return (0);
  1808. }
  1809. memcpy(subdb, subdbtmp, subdblen);
  1810. subdb[subdblen] = '';
  1811. }
  1812. subdbtmp =
  1813.     Tcl_GetByteArrayFromObj(objv[i++], &newlen);
  1814. if ((ret = __os_malloc(envp, newlen + 1,
  1815.     NULL, &newname)) != 0) {
  1816. Tcl_SetResult(interp,
  1817.     db_strerror(ret), TCL_STATIC);
  1818. return (0);
  1819. }
  1820. memcpy(newname, subdbtmp, newlen);
  1821. newname[newlen] = '';
  1822. } else {
  1823. Tcl_WrongNumArgs(interp, 3, objv, "?args? filename ?database? ?newname?");
  1824. result = TCL_ERROR;
  1825. goto error;
  1826. }
  1827. ret = db_create(&dbp, envp, 0);
  1828. if (ret) {
  1829. result = _ReturnSetup(interp, ret, "db_create");
  1830. goto error;
  1831. }
  1832. /*
  1833.  * No matter what, we NULL out dbp after this call.
  1834.  */
  1835. ret = dbp->rename(dbp, db, subdb, newname, 0);
  1836. result = _ReturnSetup(interp, ret, "db rename");
  1837. dbp = NULL;
  1838. error:
  1839. if (subdb)
  1840. __os_free(subdb, subdblen + 1);
  1841. if (newname)
  1842. __os_free(newname, newlen + 1);
  1843. if (result == TCL_ERROR && dbp)
  1844. (void)dbp->close(dbp, 0);
  1845. return (result);
  1846. }
  1847. /*
  1848.  * bdb_DbVerify --
  1849.  * Implements the DB->verify command.
  1850.  */
  1851. static int
  1852. bdb_DbVerify(interp, objc, objv)
  1853. Tcl_Interp *interp; /* Interpreter */
  1854. int objc; /* How many arguments? */
  1855. Tcl_Obj *CONST objv[]; /* The argument objects */
  1856. {
  1857. static char *bdbverify[] = {
  1858. "-env", "-errfile", "-errpfx", "--", NULL
  1859. };
  1860. enum bdbvrfy {
  1861. TCL_DBVRFY_ENV,
  1862. TCL_DBVRFY_ERRFILE,
  1863. TCL_DBVRFY_ERRPFX,
  1864. TCL_DBVRFY_ENDARG
  1865. };
  1866. DB_ENV *envp;
  1867. DB *dbp;
  1868. FILE *errf;
  1869. int endarg, i, optindex, result, ret, flags;
  1870. char *arg, *db, *errpfx;
  1871. envp = NULL;
  1872. dbp = NULL;
  1873. result = TCL_OK;
  1874. db = errpfx = NULL;
  1875. errf = NULL;
  1876. flags = endarg = 0;
  1877. if (objc < 2) {
  1878. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  1879. return (TCL_ERROR);
  1880. }
  1881. /*
  1882.  * We must first parse for the environment flag, since that
  1883.  * is needed for db_create.  Then create the db handle.
  1884.  */
  1885. i = 2;
  1886. while (i < objc) {
  1887. if (Tcl_GetIndexFromObj(interp, objv[i], bdbverify,
  1888.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  1889. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1890. if (arg[0] == '-') {
  1891. result = IS_HELP(objv[i]);
  1892. goto error;
  1893. } else
  1894. Tcl_ResetResult(interp);
  1895. break;
  1896. }
  1897. i++;
  1898. switch ((enum bdbvrfy)optindex) {
  1899. case TCL_DBVRFY_ENV:
  1900. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1901. envp = NAME_TO_ENV(arg);
  1902. if (envp == NULL) {
  1903. Tcl_SetResult(interp,
  1904.     "db verify: illegal environment",
  1905.     TCL_STATIC);
  1906. result = TCL_ERROR;
  1907. break;
  1908. }
  1909. break;
  1910. case TCL_DBVRFY_ERRFILE:
  1911. if (i >= objc) {
  1912. Tcl_WrongNumArgs(interp, 2, objv,
  1913.     "-errfile file");
  1914. result = TCL_ERROR;
  1915. break;
  1916. }
  1917. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1918. /*
  1919.  * If the user already set one, close it.
  1920.  */
  1921. if (errf != NULL)
  1922. fclose(errf);
  1923. errf = fopen(arg, "a");
  1924. break;
  1925. case TCL_DBVRFY_ERRPFX:
  1926. if (i >= objc) {
  1927. Tcl_WrongNumArgs(interp, 2, objv,
  1928.     "-errpfx prefix");
  1929. result = TCL_ERROR;
  1930. break;
  1931. }
  1932. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1933. /*
  1934.  * If the user already set one, free it.
  1935.  */
  1936. if (errpfx != NULL)
  1937. __os_freestr(errpfx);
  1938. if ((ret = __os_strdup(NULL, arg, &errpfx)) != 0) {
  1939. result = _ReturnSetup(interp, ret,
  1940.     "__os_strdup");
  1941. break;
  1942. }
  1943. break;
  1944. case TCL_DBVRFY_ENDARG:
  1945. endarg = 1;
  1946. break;
  1947. }
  1948. /*
  1949.  * If, at any time, parsing the args we get an error,
  1950.  * bail out and return.
  1951.  */
  1952. if (result != TCL_OK)
  1953. goto error;
  1954. if (endarg)
  1955. break;
  1956. }
  1957. if (result != TCL_OK)
  1958. goto error;
  1959. /*
  1960.  * The remaining arg is the db filename.
  1961.  */
  1962. if (i == (objc - 1))
  1963. db = Tcl_GetStringFromObj(objv[i++], NULL);
  1964. else {
  1965. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  1966. result = TCL_ERROR;
  1967. goto error;
  1968. }
  1969. ret = db_create(&dbp, envp, 0);
  1970. if (ret) {
  1971. result = _ReturnSetup(interp, ret, "db_create");
  1972. goto error;
  1973. }
  1974. if (errf != NULL)
  1975. dbp->set_errfile(dbp, errf);
  1976. if (errpfx != NULL)
  1977. dbp->set_errpfx(dbp, errpfx);
  1978. ret = dbp->verify(dbp, db, NULL, NULL, flags);
  1979. result = _ReturnSetup(interp, ret, "db verify");
  1980. error:
  1981. if (errf != NULL)
  1982. fclose(errf);
  1983. if (errpfx != NULL)
  1984. __os_freestr(errpfx);
  1985. if (dbp)
  1986. (void)dbp->close(dbp, 0);
  1987. return (result);
  1988. }
  1989. /*
  1990.  * bdb_Version --
  1991.  * Implements the version command.
  1992.  */
  1993. static int
  1994. bdb_Version(interp, objc, objv)
  1995. Tcl_Interp *interp; /* Interpreter */
  1996. int objc; /* How many arguments? */
  1997. Tcl_Obj *CONST objv[]; /* The argument objects */
  1998. {
  1999. static char *bdbver[] = {
  2000. "-string", NULL
  2001. };
  2002. enum bdbver {
  2003. TCL_VERSTRING
  2004. };
  2005. int i, optindex, maj, min, patch, result, string, verobjc;
  2006. char *arg, *v;
  2007. Tcl_Obj *res, *verobjv[3];
  2008. result = TCL_OK;
  2009. string = 0;
  2010. if (objc < 2) {
  2011. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  2012. return (TCL_ERROR);
  2013. }
  2014. /*
  2015.  * We must first parse for the environment flag, since that
  2016.  * is needed for db_create.  Then create the db handle.
  2017.  */
  2018. i = 2;
  2019. while (i < objc) {
  2020. if (Tcl_GetIndexFromObj(interp, objv[i], bdbver,
  2021.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2022. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2023. if (arg[0] == '-') {
  2024. result = IS_HELP(objv[i]);
  2025. goto error;
  2026. } else
  2027. Tcl_ResetResult(interp);
  2028. break;
  2029. }
  2030. i++;
  2031. switch ((enum bdbver)optindex) {
  2032. case TCL_VERSTRING:
  2033. string = 1;
  2034. break;
  2035. }
  2036. /*
  2037.  * If, at any time, parsing the args we get an error,
  2038.  * bail out and return.
  2039.  */
  2040. if (result != TCL_OK)
  2041. goto error;
  2042. }
  2043. if (result != TCL_OK)
  2044. goto error;
  2045. v = db_version(&maj, &min, &patch);
  2046. if (string)
  2047. res = Tcl_NewStringObj(v, strlen(v));
  2048. else {
  2049. verobjc = 3;
  2050. verobjv[0] = Tcl_NewIntObj(maj);
  2051. verobjv[1] = Tcl_NewIntObj(min);
  2052. verobjv[2] = Tcl_NewIntObj(patch);
  2053. res = Tcl_NewListObj(verobjc, verobjv);
  2054. }
  2055. Tcl_SetObjResult(interp, res);
  2056. error:
  2057. return (result);
  2058. }
  2059. /*
  2060.  * bdb_Handles --
  2061.  * Implements the handles command.
  2062.  */
  2063. static int
  2064. bdb_Handles(interp, objc, objv)
  2065. Tcl_Interp *interp; /* Interpreter */
  2066. int objc; /* How many arguments? */
  2067. Tcl_Obj *CONST objv[]; /* The argument objects */
  2068. {
  2069. DBTCL_INFO *p;
  2070. Tcl_Obj *res, *handle;
  2071. /*
  2072.  * No args.  Error if we have some
  2073.  */
  2074. if (objc != 2) {
  2075. Tcl_WrongNumArgs(interp, 2, objv, "");
  2076. return (TCL_ERROR);
  2077. }
  2078. res = Tcl_NewListObj(0, NULL);
  2079. for (p = LIST_FIRST(&__db_infohead); p != NULL;
  2080.     p = LIST_NEXT(p, entries)) {
  2081. handle = Tcl_NewStringObj(p->i_name, strlen(p->i_name));
  2082. if (Tcl_ListObjAppendElement(interp, res, handle) != TCL_OK)
  2083. return (TCL_ERROR);
  2084. }
  2085. Tcl_SetObjResult(interp, res);
  2086. return (TCL_OK);
  2087. }
  2088. /*
  2089.  * bdb_DbUpgrade --
  2090.  * Implements the DB->upgrade command.
  2091.  */
  2092. static int
  2093. bdb_DbUpgrade(interp, objc, objv)
  2094. Tcl_Interp *interp; /* Interpreter */
  2095. int objc; /* How many arguments? */
  2096. Tcl_Obj *CONST objv[]; /* The argument objects */
  2097. {
  2098. static char *bdbupg[] = {
  2099. "-dupsort", "-env", "--", NULL
  2100. };
  2101. enum bdbupg {
  2102. TCL_DBUPG_DUPSORT,
  2103. TCL_DBUPG_ENV,
  2104. TCL_DBUPG_ENDARG
  2105. };
  2106. DB_ENV *envp;
  2107. DB *dbp;
  2108. int endarg, i, optindex, result, ret, flags;
  2109. char *arg, *db;
  2110. envp = NULL;
  2111. dbp = NULL;
  2112. result = TCL_OK;
  2113. db = NULL;
  2114. flags = endarg = 0;
  2115. if (objc < 2) {
  2116. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2117. return (TCL_ERROR);
  2118. }
  2119. i = 2;
  2120. while (i < objc) {
  2121. if (Tcl_GetIndexFromObj(interp, objv[i], bdbupg,
  2122.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2123. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2124. if (arg[0] == '-') {
  2125. result = IS_HELP(objv[i]);
  2126. goto error;
  2127. } else
  2128. Tcl_ResetResult(interp);
  2129. break;
  2130. }
  2131. i++;
  2132. switch ((enum bdbupg)optindex) {
  2133. case TCL_DBUPG_DUPSORT:
  2134. flags |= DB_DUPSORT;
  2135. break;
  2136. case TCL_DBUPG_ENV:
  2137. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2138. envp = NAME_TO_ENV(arg);
  2139. if (envp == NULL) {
  2140. Tcl_SetResult(interp,
  2141.     "db upgrade: illegal environment",
  2142.     TCL_STATIC);
  2143. return (TCL_ERROR);
  2144. }
  2145. break;
  2146. case TCL_DBUPG_ENDARG:
  2147. endarg = 1;
  2148. break;
  2149. }
  2150. /*
  2151.  * If, at any time, parsing the args we get an error,
  2152.  * bail out and return.
  2153.  */
  2154. if (result != TCL_OK)
  2155. goto error;
  2156. if (endarg)
  2157. break;
  2158. }
  2159. if (result != TCL_OK)
  2160. goto error;
  2161. /*
  2162.  * The remaining arg is the db filename.
  2163.  */
  2164. if (i == (objc - 1))
  2165. db = Tcl_GetStringFromObj(objv[i++], NULL);
  2166. else {
  2167. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2168. result = TCL_ERROR;
  2169. goto error;
  2170. }
  2171. ret = db_create(&dbp, envp, 0);
  2172. if (ret) {
  2173. result = _ReturnSetup(interp, ret, "db_create");
  2174. goto error;
  2175. }
  2176. ret = dbp->upgrade(dbp, db, flags);
  2177. result = _ReturnSetup(interp, ret, "db upgrade");
  2178. error:
  2179. if (dbp)
  2180. (void)dbp->close(dbp, 0);
  2181. return (result);
  2182. }