tcl_internal.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:16k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2001
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_internal.c,v 11.54 2002/08/15 02:47:46 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. #include "db_int.h"
  18. #include "dbinc/tcl_db.h"
  19. #include "dbinc/db_page.h"
  20. #include "dbinc/db_am.h"
  21. #include "dbinc_auto/db_ext.h"
  22. /*
  23.  *
  24.  * internal.c --
  25.  *
  26.  * This file contains internal functions we need to maintain
  27.  * state for our Tcl interface.
  28.  *
  29.  * NOTE: This all uses a linear linked list.  If we end up with
  30.  * too many info structs such that this is a performance hit, it
  31.  * should be redone using hashes or a list per type.  The assumption
  32.  * is that the user won't have more than a few dozen info structs
  33.  * in operation at any given point in time.  Even a complicated
  34.  * application with a few environments, nested transactions, locking,
  35.  * and several databases open, using cursors should not have a
  36.  * negative performance impact, in terms of searching the list to
  37.  * get/manipulate the info structure.
  38.  */
  39. /*
  40.  * Prototypes for procedures defined later in this file:
  41.  */
  42. static void tcl_flag_callback __P((u_int32_t, const FN *, void *));
  43. /*
  44.  * Private structure type used to pass both an interp and an object into
  45.  * a callback's single void *.
  46.  */
  47. struct __tcl_callback_bundle {
  48. Tcl_Interp *interp;
  49. Tcl_Obj *obj;
  50. };
  51. #define GLOB_CHAR(c) ((c) == '*' || (c) == '?')
  52. /*
  53.  * PUBLIC: DBTCL_INFO *_NewInfo __P((Tcl_Interp *,
  54.  * PUBLIC:    void *, char *, enum INFOTYPE));
  55.  *
  56.  * _NewInfo --
  57.  *
  58.  * This function will create a new info structure and fill it in
  59.  * with the name and pointer, id and type.
  60.  */
  61. DBTCL_INFO *
  62. _NewInfo(interp, anyp, name, type)
  63. Tcl_Interp *interp;
  64. void *anyp;
  65. char *name;
  66. enum INFOTYPE type;
  67. {
  68. DBTCL_INFO *p;
  69. int i, ret;
  70. if ((ret = __os_malloc(NULL, sizeof(DBTCL_INFO), &p)) != 0) {
  71. Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
  72. return (NULL);
  73. }
  74. if ((ret = __os_strdup(NULL, name, &p->i_name)) != 0) {
  75. Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
  76. __os_free(NULL, p);
  77. return (NULL);
  78. }
  79. p->i_interp = interp;
  80. p->i_anyp = anyp;
  81. p->i_data = 0;
  82. p->i_data2 = 0;
  83. p->i_type = type;
  84. p->i_parent = NULL;
  85. p->i_err = NULL;
  86. p->i_errpfx = NULL;
  87. p->i_lockobj.data = NULL;
  88. p->i_btcompare = NULL;
  89. p->i_dupcompare = NULL;
  90. p->i_hashproc = NULL;
  91. p->i_second_call = NULL;
  92. p->i_rep_eid = NULL;
  93. p->i_rep_send = NULL;
  94. for (i = 0; i < MAX_ID; i++)
  95. p->i_otherid[i] = 0;
  96. LIST_INSERT_HEAD(&__db_infohead, p, entries);
  97. return (p);
  98. }
  99. /*
  100.  * PUBLIC: void *_NameToPtr __P((CONST char *));
  101.  */
  102. void *
  103. _NameToPtr(name)
  104. CONST char *name;
  105. {
  106. DBTCL_INFO *p;
  107. for (p = LIST_FIRST(&__db_infohead); p != NULL;
  108.     p = LIST_NEXT(p, entries))
  109. if (strcmp(name, p->i_name) == 0)
  110. return (p->i_anyp);
  111. return (NULL);
  112. }
  113. /*
  114.  * PUBLIC: DBTCL_INFO *_PtrToInfo __P((CONST void *));
  115.  */
  116. DBTCL_INFO *
  117. _PtrToInfo(ptr)
  118. CONST void *ptr;
  119. {
  120. DBTCL_INFO *p;
  121. for (p = LIST_FIRST(&__db_infohead); p != NULL;
  122.     p = LIST_NEXT(p, entries))
  123. if (p->i_anyp == ptr)
  124. return (p);
  125. return (NULL);
  126. }
  127. /*
  128.  * PUBLIC: DBTCL_INFO *_NameToInfo __P((CONST char *));
  129.  */
  130. DBTCL_INFO *
  131. _NameToInfo(name)
  132. CONST char *name;
  133. {
  134. DBTCL_INFO *p;
  135. for (p = LIST_FIRST(&__db_infohead); p != NULL;
  136.     p = LIST_NEXT(p, entries))
  137. if (strcmp(name, p->i_name) == 0)
  138. return (p);
  139. return (NULL);
  140. }
  141. /*
  142.  * PUBLIC: void  _SetInfoData __P((DBTCL_INFO *, void *));
  143.  */
  144. void
  145. _SetInfoData(p, data)
  146. DBTCL_INFO *p;
  147. void *data;
  148. {
  149. if (p == NULL)
  150. return;
  151. p->i_anyp = data;
  152. return;
  153. }
  154. /*
  155.  * PUBLIC: void  _DeleteInfo __P((DBTCL_INFO *));
  156.  */
  157. void
  158. _DeleteInfo(p)
  159. DBTCL_INFO *p;
  160. {
  161. if (p == NULL)
  162. return;
  163. LIST_REMOVE(p, entries);
  164. if (p->i_lockobj.data != NULL)
  165. __os_free(NULL, p->i_lockobj.data);
  166. if (p->i_err != NULL) {
  167. fclose(p->i_err);
  168. p->i_err = NULL;
  169. }
  170. if (p->i_errpfx != NULL)
  171. __os_free(NULL, p->i_errpfx);
  172. if (p->i_btcompare != NULL)
  173. Tcl_DecrRefCount(p->i_btcompare);
  174. if (p->i_dupcompare != NULL)
  175. Tcl_DecrRefCount(p->i_dupcompare);
  176. if (p->i_hashproc != NULL)
  177. Tcl_DecrRefCount(p->i_hashproc);
  178. if (p->i_second_call != NULL)
  179. Tcl_DecrRefCount(p->i_second_call);
  180. if (p->i_rep_eid != NULL)
  181. Tcl_DecrRefCount(p->i_rep_eid);
  182. if (p->i_rep_send != NULL)
  183. Tcl_DecrRefCount(p->i_rep_send);
  184. __os_free(NULL, p->i_name);
  185. __os_free(NULL, p);
  186. return;
  187. }
  188. /*
  189.  * PUBLIC: int _SetListElem __P((Tcl_Interp *,
  190.  * PUBLIC:    Tcl_Obj *, void *, int, void *, int));
  191.  */
  192. int
  193. _SetListElem(interp, list, elem1, e1cnt, elem2, e2cnt)
  194. Tcl_Interp *interp;
  195. Tcl_Obj *list;
  196. void *elem1, *elem2;
  197. int e1cnt, e2cnt;
  198. {
  199. Tcl_Obj *myobjv[2], *thislist;
  200. int myobjc;
  201. myobjc = 2;
  202. myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, e1cnt);
  203. myobjv[1] = Tcl_NewByteArrayObj((u_char *)elem2, e2cnt);
  204. thislist = Tcl_NewListObj(myobjc, myobjv);
  205. if (thislist == NULL)
  206. return (TCL_ERROR);
  207. return (Tcl_ListObjAppendElement(interp, list, thislist));
  208. }
  209. /*
  210.  * PUBLIC: int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, int));
  211.  */
  212. int
  213. _SetListElemInt(interp, list, elem1, elem2)
  214. Tcl_Interp *interp;
  215. Tcl_Obj *list;
  216. void *elem1;
  217. int elem2;
  218. {
  219. Tcl_Obj *myobjv[2], *thislist;
  220. int myobjc;
  221. myobjc = 2;
  222. myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, strlen((char *)elem1));
  223. myobjv[1] = Tcl_NewIntObj(elem2);
  224. thislist = Tcl_NewListObj(myobjc, myobjv);
  225. if (thislist == NULL)
  226. return (TCL_ERROR);
  227. return (Tcl_ListObjAppendElement(interp, list, thislist));
  228. }
  229. /*
  230.  * PUBLIC: int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *,
  231.  * PUBLIC:     db_recno_t, u_char *, int));
  232.  */
  233. int
  234. _SetListRecnoElem(interp, list, elem1, elem2, e2size)
  235. Tcl_Interp *interp;
  236. Tcl_Obj *list;
  237. db_recno_t elem1;
  238. u_char *elem2;
  239. int e2size;
  240. {
  241. Tcl_Obj *myobjv[2], *thislist;
  242. int myobjc;
  243. myobjc = 2;
  244. myobjv[0] = Tcl_NewLongObj((long)elem1);
  245. myobjv[1] = Tcl_NewByteArrayObj(elem2, e2size);
  246. thislist = Tcl_NewListObj(myobjc, myobjv);
  247. if (thislist == NULL)
  248. return (TCL_ERROR);
  249. return (Tcl_ListObjAppendElement(interp, list, thislist));
  250. }
  251. /*
  252.  * _Set3DBTList --
  253.  * This is really analogous to both _SetListElem and
  254.  * _SetListRecnoElem--it's used for three-DBT lists returned by
  255.  * DB->pget and DBC->pget().  We'd need a family of four functions
  256.  * to handle all the recno/non-recno cases, however, so we make
  257.  * this a little more aware of the internals and do the logic inside.
  258.  *
  259.  * XXX
  260.  * One of these days all these functions should probably be cleaned up
  261.  * to eliminate redundancy and bring them into the standard DB
  262.  * function namespace.
  263.  *
  264.  * PUBLIC: int _Set3DBTList __P((Tcl_Interp *, Tcl_Obj *, DBT *, int,
  265.  * PUBLIC:     DBT *, int, DBT *));
  266.  */
  267. int
  268. _Set3DBTList(interp, list, elem1, is1recno, elem2, is2recno, elem3)
  269. Tcl_Interp *interp;
  270. Tcl_Obj *list;
  271. DBT *elem1, *elem2, *elem3;
  272. int is1recno, is2recno;
  273. {
  274. Tcl_Obj *myobjv[3], *thislist;
  275. if (is1recno)
  276. myobjv[0] = Tcl_NewLongObj((long)*(db_recno_t *)elem1->data);
  277. else
  278. myobjv[0] =
  279.     Tcl_NewByteArrayObj((u_char *)elem1->data, elem1->size);
  280. if (is2recno)
  281. myobjv[1] = Tcl_NewLongObj((long)*(db_recno_t *)elem2->data);
  282. else
  283. myobjv[1] =
  284.     Tcl_NewByteArrayObj((u_char *)elem2->data, elem2->size);
  285. myobjv[2] = Tcl_NewByteArrayObj((u_char *)elem3->data, elem3->size);
  286. thislist = Tcl_NewListObj(3, myobjv);
  287. if (thislist == NULL)
  288. return (TCL_ERROR);
  289. return (Tcl_ListObjAppendElement(interp, list, thislist));
  290. }
  291. /*
  292.  * _SetMultiList -- build a list for return from multiple get.
  293.  *
  294.  * PUBLIC: int _SetMultiList __P((Tcl_Interp *,
  295.  * PUBLIC:     Tcl_Obj *, DBT *, DBT*, int, int));
  296.  */
  297. int
  298. _SetMultiList(interp, list, key, data, type, flag)
  299. Tcl_Interp *interp;
  300. Tcl_Obj *list;
  301. DBT *key, *data;
  302. int type, flag;
  303. {
  304. db_recno_t recno;
  305. u_int32_t dlen, klen;
  306. int result;
  307. void *pointer, *dp, *kp;
  308. recno = 0;
  309. dlen = 0;
  310. kp = NULL;
  311. DB_MULTIPLE_INIT(pointer, data);
  312. result = TCL_OK;
  313. if (type == DB_RECNO || type == DB_QUEUE)
  314. recno = *(db_recno_t *) key->data;
  315. else
  316. kp = key->data;
  317. klen = key->size;
  318. do {
  319. if (flag & DB_MULTIPLE_KEY) {
  320. if (type == DB_RECNO || type == DB_QUEUE)
  321. DB_MULTIPLE_RECNO_NEXT(pointer,
  322.     data, recno, dp, dlen);
  323. else
  324. DB_MULTIPLE_KEY_NEXT(pointer,
  325.     data, kp, klen, dp, dlen);
  326. } else
  327. DB_MULTIPLE_NEXT(pointer, data, dp, dlen);
  328. if (pointer == NULL)
  329. break;
  330. if (type == DB_RECNO || type == DB_QUEUE) {
  331. result =
  332.     _SetListRecnoElem(interp, list, recno, dp, dlen);
  333. recno++;
  334. } else
  335. result = _SetListElem(interp, list, kp, klen, dp, dlen);
  336. } while (result == TCL_OK);
  337. return (result);
  338. }
  339. /*
  340.  * PUBLIC: int _GetGlobPrefix __P((char *, char **));
  341.  */
  342. int
  343. _GetGlobPrefix(pattern, prefix)
  344. char *pattern;
  345. char **prefix;
  346. {
  347. int i, j;
  348. char *p;
  349. /*
  350.  * Duplicate it, we get enough space and most of the work is done.
  351.  */
  352. if (__os_strdup(NULL, pattern, prefix) != 0)
  353. return (1);
  354. p = *prefix;
  355. for (i = 0, j = 0; p[i] && !GLOB_CHAR(p[i]); i++, j++)
  356. /*
  357.  * Check for an escaped character and adjust
  358.  */
  359. if (p[i] == '\' && p[i+1]) {
  360. p[j] = p[i+1];
  361. i++;
  362. } else
  363. p[j] = p[i];
  364. p[j] = 0;
  365. return (0);
  366. }
  367. /*
  368.  * PUBLIC: int _ReturnSetup __P((Tcl_Interp *, int, int, char *));
  369.  */
  370. int
  371. _ReturnSetup(interp, ret, ok, errmsg)
  372. Tcl_Interp *interp;
  373. int ret, ok;
  374. char *errmsg;
  375. {
  376. char *msg;
  377. if (ret > 0)
  378. return (_ErrorSetup(interp, ret, errmsg));
  379. /*
  380.  * We either have success or a DB error.  If a DB error, set up the
  381.  * string.  We return an error if not one of the errors we catch.
  382.  * If anyone wants to reset the result to return anything different,
  383.  * then the calling function is responsible for doing so via
  384.  * Tcl_ResetResult or another Tcl_SetObjResult.
  385.  */
  386. if (ret == 0) {
  387. Tcl_SetResult(interp, "0", TCL_STATIC);
  388. return (TCL_OK);
  389. }
  390. msg = db_strerror(ret);
  391. Tcl_AppendResult(interp, msg, NULL);
  392. if (ok)
  393. return (TCL_OK);
  394. else {
  395. Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL);
  396. return (TCL_ERROR);
  397. }
  398. }
  399. /*
  400.  * PUBLIC: int _ErrorSetup __P((Tcl_Interp *, int, char *));
  401.  */
  402. int
  403. _ErrorSetup(interp, ret, errmsg)
  404. Tcl_Interp *interp;
  405. int ret;
  406. char *errmsg;
  407. {
  408. Tcl_SetErrno(ret);
  409. Tcl_AppendResult(interp, errmsg, ":", Tcl_PosixError(interp), NULL);
  410. return (TCL_ERROR);
  411. }
  412. /*
  413.  * PUBLIC: void _ErrorFunc __P((CONST char *, char *));
  414.  */
  415. void
  416. _ErrorFunc(pfx, msg)
  417. CONST char *pfx;
  418. char *msg;
  419. {
  420. DBTCL_INFO *p;
  421. Tcl_Interp *interp;
  422. int size;
  423. char *err;
  424. p = _NameToInfo(pfx);
  425. if (p == NULL)
  426. return;
  427. interp = p->i_interp;
  428. size = strlen(pfx) + strlen(msg) + 4;
  429. /*
  430.  * If we cannot allocate enough to put together the prefix
  431.  * and message then give them just the message.
  432.  */
  433. if (__os_malloc(NULL, size, &err) != 0) {
  434. Tcl_AddErrorInfo(interp, msg);
  435. Tcl_AppendResult(interp, msg, "n", NULL);
  436. return;
  437. }
  438. snprintf(err, size, "%s: %s", pfx, msg);
  439. Tcl_AddErrorInfo(interp, err);
  440. Tcl_AppendResult(interp, err, "n", NULL);
  441. __os_free(NULL, err);
  442. return;
  443. }
  444. #define INVALID_LSNMSG "Invalid LSN with %d parts. Should have 2.n"
  445. /*
  446.  * PUBLIC: int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *));
  447.  */
  448. int
  449. _GetLsn(interp, obj, lsn)
  450. Tcl_Interp *interp;
  451. Tcl_Obj *obj;
  452. DB_LSN *lsn;
  453. {
  454. Tcl_Obj **myobjv;
  455. char msg[MSG_SIZE];
  456. int myobjc, result;
  457. u_int32_t tmp;
  458. result = Tcl_ListObjGetElements(interp, obj, &myobjc, &myobjv);
  459. if (result == TCL_ERROR)
  460. return (result);
  461. if (myobjc != 2) {
  462. result = TCL_ERROR;
  463. snprintf(msg, MSG_SIZE, INVALID_LSNMSG, myobjc);
  464. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  465. return (result);
  466. }
  467. result = _GetUInt32(interp, myobjv[0], &tmp);
  468. if (result == TCL_ERROR)
  469. return (result);
  470. lsn->file = tmp;
  471. result = _GetUInt32(interp, myobjv[1], &tmp);
  472. lsn->offset = tmp;
  473. return (result);
  474. }
  475. /*
  476.  * _GetUInt32 --
  477.  * Get a u_int32_t from a Tcl object.  Tcl_GetIntFromObj does the
  478.  * right thing most of the time, but on machines where a long is 8 bytes
  479.  * and an int is 4 bytes, it errors on integers between the maximum
  480.  * int32_t and the maximum u_int32_t.  This is correct, but we generally
  481.  * want a u_int32_t in the end anyway, so we use Tcl_GetLongFromObj and do
  482.  * the bounds checking ourselves.
  483.  *
  484.  * This code looks much like Tcl_GetIntFromObj, only with a different
  485.  * bounds check.  It's essentially Tcl_GetUnsignedIntFromObj, which
  486.  * unfortunately doesn't exist.
  487.  *
  488.  * PUBLIC: int _GetUInt32 __P((Tcl_Interp *, Tcl_Obj *, u_int32_t *));
  489.  */
  490. int
  491. _GetUInt32(interp, obj, resp)
  492. Tcl_Interp *interp;
  493. Tcl_Obj *obj;
  494. u_int32_t *resp;
  495. {
  496. int result;
  497. long ltmp;
  498. result = Tcl_GetLongFromObj(interp, obj, &ltmp);
  499. if (result != TCL_OK)
  500. return (result);
  501. if ((unsigned long)ltmp != (u_int32_t)ltmp) {
  502. if (interp != NULL) {
  503. Tcl_ResetResult(interp);
  504. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  505.     "integer value too large for u_int32_t", -1);
  506. }
  507. return (TCL_ERROR);
  508. }
  509. *resp = (u_int32_t)ltmp;
  510. return (TCL_OK);
  511. }
  512. /*
  513.  * tcl_flag_callback --
  514.  * Callback for db_pr.c functions that contain the FN struct mapping
  515.  * flag values to meaningful strings.  This function appends a Tcl_Obj
  516.  * containing each pertinent flag string to the specified Tcl list.
  517.  */
  518. static void
  519. tcl_flag_callback(flags, fn, vtcbp)
  520. u_int32_t flags;
  521. const FN *fn;
  522. void *vtcbp;
  523. {
  524. const FN *fnp;
  525. Tcl_Interp *interp;
  526. Tcl_Obj *newobj, *listobj;
  527. int result;
  528. struct __tcl_callback_bundle *tcbp;
  529. tcbp = (struct __tcl_callback_bundle *)vtcbp;
  530. interp = tcbp->interp;
  531. listobj = tcbp->obj;
  532. for (fnp = fn; fnp->mask != 0; ++fnp)
  533. if (LF_ISSET(fnp->mask)) {
  534. newobj = Tcl_NewStringObj(fnp->name, strlen(fnp->name));
  535. result =
  536.     Tcl_ListObjAppendElement(interp, listobj, newobj);
  537. /*
  538.  * Tcl_ListObjAppendElement is defined to return TCL_OK
  539.  * unless listobj isn't actually a list (or convertible
  540.  * into one).  If this is the case, we screwed up badly
  541.  * somehow.
  542.  */
  543. DB_ASSERT(result == TCL_OK);
  544. }
  545. }
  546. /*
  547.  * _GetFlagsList --
  548.  * Get a new Tcl object, containing a list of the string values
  549.  * associated with a particular set of flag values, given a function
  550.  * that can extract the right names for the right flags.
  551.  *
  552.  * PUBLIC: Tcl_Obj *_GetFlagsList __P((Tcl_Interp *, u_int32_t,
  553.  * PUBLIC:     void (*)(u_int32_t, void *,
  554.  * PUBLIC:     void (*)(u_int32_t, const FN *, void *))));
  555.  */
  556. Tcl_Obj *
  557. _GetFlagsList(interp, flags, func)
  558. Tcl_Interp *interp;
  559. u_int32_t flags;
  560. void (*func)
  561.     __P((u_int32_t, void *, void (*)(u_int32_t, const FN *, void *)));
  562. {
  563. Tcl_Obj *newlist;
  564. struct __tcl_callback_bundle tcb;
  565. newlist = Tcl_NewObj();
  566. memset(&tcb, 0, sizeof(tcb));
  567. tcb.interp = interp;
  568. tcb.obj = newlist;
  569. func(flags, &tcb, tcl_flag_callback);
  570. return (newlist);
  571. }
  572. int __debug_stop, __debug_on, __debug_print, __debug_test;
  573. /*
  574.  * PUBLIC: void _debug_check  __P((void));
  575.  */
  576. void
  577. _debug_check()
  578. {
  579. if (__debug_on == 0)
  580. return;
  581. if (__debug_print != 0) {
  582. printf("r%7d:", __debug_on);
  583. fflush(stdout);
  584. }
  585. if (__debug_on++ == __debug_test || __debug_stop)
  586. __db_loadme();
  587. }
  588. /*
  589.  * XXX
  590.  * Tcl 8.1+ Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj bug.
  591.  *
  592.  * There is a bug in Tcl 8.1+ and byte arrays in that if it happens
  593.  * to use an object as both a byte array and something else like
  594.  * an int, and you've done a Tcl_GetByteArrayFromObj, then you
  595.  * do a Tcl_GetIntFromObj, your memory is deleted.
  596.  *
  597.  * Workaround is for all byte arrays we want to use, if it can be
  598.  * represented as an integer, we copy it so that we don't lose the
  599.  * memory.
  600.  */
  601. /*
  602.  * PUBLIC: int _CopyObjBytes  __P((Tcl_Interp *, Tcl_Obj *obj, void **,
  603.  * PUBLIC:     u_int32_t *, int *));
  604.  */
  605. int
  606. _CopyObjBytes(interp, obj, newp, sizep, freep)
  607. Tcl_Interp *interp;
  608. Tcl_Obj *obj;
  609. void **newp;
  610. u_int32_t *sizep;
  611. int *freep;
  612. {
  613. void *tmp, *new;
  614. int i, len, ret;
  615. /*
  616.  * If the object is not an int, then just return the byte
  617.  * array because it won't be transformed out from under us.
  618.  * If it is a number, we need to copy it.
  619.  */
  620. *freep = 0;
  621. ret = Tcl_GetIntFromObj(interp, obj, &i);
  622. tmp = Tcl_GetByteArrayFromObj(obj, &len);
  623. *sizep = len;
  624. if (ret == TCL_ERROR) {
  625. Tcl_ResetResult(interp);
  626. *newp = tmp;
  627. return (0);
  628. }
  629. /*
  630.  * If we get here, we have an integer that might be reused
  631.  * at some other point so we cannot count on GetByteArray
  632.  * keeping our pointer valid.
  633.  */
  634. if ((ret = __os_malloc(NULL, len, &new)) != 0)
  635. return (ret);
  636. memcpy(new, tmp, len);
  637. *newp = new;
  638. *freep = 1;
  639. return (0);
  640. }