Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

tcl_internal.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: tcl_internal.c,v 12.3 2005/06/16 20:23:47 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <tcl.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "dbinc/tcl_db.h"
00022 #include "dbinc/db_page.h"
00023 #include "dbinc/db_am.h"
00024 
00025 /*
00026  *
00027  * internal.c --
00028  *
00029  *      This file contains internal functions we need to maintain
00030  *      state for our Tcl interface.
00031  *
00032  *      NOTE: This all uses a linear linked list.  If we end up with
00033  *      too many info structs such that this is a performance hit, it
00034  *      should be redone using hashes or a list per type.  The assumption
00035  *      is that the user won't have more than a few dozen info structs
00036  *      in operation at any given point in time.  Even a complicated
00037  *      application with a few environments, nested transactions, locking,
00038  *      and several databases open, using cursors should not have a
00039  *      negative performance impact, in terms of searching the list to
00040  *      get/manipulate the info structure.
00041  */
00042 
00043 #define GLOB_CHAR(c)    ((c) == '*' || (c) == '?')
00044 
00045 /*
00046  * PUBLIC: DBTCL_INFO *_NewInfo __P((Tcl_Interp *,
00047  * PUBLIC:    void *, char *, enum INFOTYPE));
00048  *
00049  * _NewInfo --
00050  *
00051  * This function will create a new info structure and fill it in
00052  * with the name and pointer, id and type.
00053  */
00054 DBTCL_INFO *
00055 _NewInfo(interp, anyp, name, type)
00056         Tcl_Interp *interp;
00057         void *anyp;
00058         char *name;
00059         enum INFOTYPE type;
00060 {
00061         DBTCL_INFO *p;
00062         int ret;
00063 
00064         if ((ret = __os_calloc(NULL, sizeof(DBTCL_INFO), 1, &p)) != 0) {
00065                 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
00066                 return (NULL);
00067         }
00068 
00069         if ((ret = __os_strdup(NULL, name, &p->i_name)) != 0) {
00070                 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
00071                 __os_free(NULL, p);
00072                 return (NULL);
00073         }
00074         p->i_interp = interp;
00075         p->i_anyp = anyp;
00076         p->i_type = type;
00077 
00078         LIST_INSERT_HEAD(&__db_infohead, p, entries);
00079         return (p);
00080 }
00081 
00082 /*
00083  * PUBLIC: void *_NameToPtr __P((CONST char *));
00084  */
00085 void    *
00086 _NameToPtr(name)
00087         CONST char *name;
00088 {
00089         DBTCL_INFO *p;
00090 
00091         for (p = LIST_FIRST(&__db_infohead); p != NULL;
00092             p = LIST_NEXT(p, entries))
00093                 if (strcmp(name, p->i_name) == 0)
00094                         return (p->i_anyp);
00095         return (NULL);
00096 }
00097 
00098 /*
00099  * PUBLIC: DBTCL_INFO *_PtrToInfo __P((CONST void *));
00100  */
00101 DBTCL_INFO *
00102 _PtrToInfo(ptr)
00103         CONST void *ptr;
00104 {
00105         DBTCL_INFO *p;
00106 
00107         for (p = LIST_FIRST(&__db_infohead); p != NULL;
00108             p = LIST_NEXT(p, entries))
00109                 if (p->i_anyp == ptr)
00110                         return (p);
00111         return (NULL);
00112 }
00113 
00114 /*
00115  * PUBLIC: DBTCL_INFO *_NameToInfo __P((CONST char *));
00116  */
00117 DBTCL_INFO *
00118 _NameToInfo(name)
00119         CONST char *name;
00120 {
00121         DBTCL_INFO *p;
00122 
00123         for (p = LIST_FIRST(&__db_infohead); p != NULL;
00124             p = LIST_NEXT(p, entries))
00125                 if (strcmp(name, p->i_name) == 0)
00126                         return (p);
00127         return (NULL);
00128 }
00129 
00130 /*
00131  * PUBLIC: void  _SetInfoData __P((DBTCL_INFO *, void *));
00132  */
00133 void
00134 _SetInfoData(p, data)
00135         DBTCL_INFO *p;
00136         void *data;
00137 {
00138         if (p == NULL)
00139                 return;
00140         p->i_anyp = data;
00141         return;
00142 }
00143 
00144 /*
00145  * PUBLIC: void  _DeleteInfo __P((DBTCL_INFO *));
00146  */
00147 void
00148 _DeleteInfo(p)
00149         DBTCL_INFO *p;
00150 {
00151         if (p == NULL)
00152                 return;
00153         LIST_REMOVE(p, entries);
00154         if (p->i_lockobj.data != NULL)
00155                 __os_free(NULL, p->i_lockobj.data);
00156         if (p->i_err != NULL && p->i_err != stderr) {
00157                 (void)fclose(p->i_err);
00158                 p->i_err = NULL;
00159         }
00160         if (p->i_errpfx != NULL)
00161                 __os_free(NULL, p->i_errpfx);
00162         if (p->i_btcompare != NULL)
00163                 Tcl_DecrRefCount(p->i_btcompare);
00164         if (p->i_dupcompare != NULL)
00165                 Tcl_DecrRefCount(p->i_dupcompare);
00166         if (p->i_hashproc != NULL)
00167                 Tcl_DecrRefCount(p->i_hashproc);
00168         if (p->i_second_call != NULL)
00169                 Tcl_DecrRefCount(p->i_second_call);
00170         if (p->i_rep_eid != NULL)
00171                 Tcl_DecrRefCount(p->i_rep_eid);
00172         if (p->i_rep_send != NULL)
00173                 Tcl_DecrRefCount(p->i_rep_send);
00174         __os_free(NULL, p->i_name);
00175         __os_free(NULL, p);
00176 
00177         return;
00178 }
00179 
00180 /*
00181  * PUBLIC: int _SetListElem __P((Tcl_Interp *,
00182  * PUBLIC:    Tcl_Obj *, void *, u_int32_t, void *, u_int32_t));
00183  */
00184 int
00185 _SetListElem(interp, list, elem1, e1cnt, elem2, e2cnt)
00186         Tcl_Interp *interp;
00187         Tcl_Obj *list;
00188         void *elem1, *elem2;
00189         u_int32_t e1cnt, e2cnt;
00190 {
00191         Tcl_Obj *myobjv[2], *thislist;
00192         int myobjc;
00193 
00194         myobjc = 2;
00195         myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, (int)e1cnt);
00196         myobjv[1] = Tcl_NewByteArrayObj((u_char *)elem2, (int)e2cnt);
00197         thislist = Tcl_NewListObj(myobjc, myobjv);
00198         if (thislist == NULL)
00199                 return (TCL_ERROR);
00200         return (Tcl_ListObjAppendElement(interp, list, thislist));
00201 
00202 }
00203 
00204 /*
00205  * PUBLIC: int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, long));
00206  */
00207 int
00208 _SetListElemInt(interp, list, elem1, elem2)
00209         Tcl_Interp *interp;
00210         Tcl_Obj *list;
00211         void *elem1;
00212         long elem2;
00213 {
00214         Tcl_Obj *myobjv[2], *thislist;
00215         int myobjc;
00216 
00217         myobjc = 2;
00218         myobjv[0] =
00219             Tcl_NewByteArrayObj((u_char *)elem1, (int)strlen((char *)elem1));
00220         myobjv[1] = Tcl_NewLongObj(elem2);
00221         thislist = Tcl_NewListObj(myobjc, myobjv);
00222         if (thislist == NULL)
00223                 return (TCL_ERROR);
00224         return (Tcl_ListObjAppendElement(interp, list, thislist));
00225 }
00226 
00227 /*
00228  * Don't compile this code if we don't have sequences compiled into the DB
00229  * library, it's likely because we don't have a 64-bit type, and trying to
00230  * use int64_t is going to result in syntax errors.
00231  */
00232 #ifdef HAVE_SEQUENCE
00233 /*
00234  * PUBLIC: int _SetListElemWideInt __P((Tcl_Interp *,
00235  * PUBLIC:     Tcl_Obj *, void *, int64_t));
00236  */
00237 int
00238 _SetListElemWideInt(interp, list, elem1, elem2)
00239         Tcl_Interp *interp;
00240         Tcl_Obj *list;
00241         void *elem1;
00242         int64_t elem2;
00243 {
00244         Tcl_Obj *myobjv[2], *thislist;
00245         int myobjc;
00246 
00247         myobjc = 2;
00248         myobjv[0] =
00249             Tcl_NewByteArrayObj((u_char *)elem1, (int)strlen((char *)elem1));
00250         myobjv[1] = Tcl_NewWideIntObj(elem2);
00251         thislist = Tcl_NewListObj(myobjc, myobjv);
00252         if (thislist == NULL)
00253                 return (TCL_ERROR);
00254         return (Tcl_ListObjAppendElement(interp, list, thislist));
00255 }
00256 #endif /* HAVE_SEQUENCE */
00257 
00258 /*
00259  * PUBLIC: int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *,
00260  * PUBLIC:     db_recno_t, u_char *, u_int32_t));
00261  */
00262 int
00263 _SetListRecnoElem(interp, list, elem1, elem2, e2size)
00264         Tcl_Interp *interp;
00265         Tcl_Obj *list;
00266         db_recno_t elem1;
00267         u_char *elem2;
00268         u_int32_t e2size;
00269 {
00270         Tcl_Obj *myobjv[2], *thislist;
00271         int myobjc;
00272 
00273         myobjc = 2;
00274         myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)elem1);
00275         myobjv[1] = Tcl_NewByteArrayObj(elem2, (int)e2size);
00276         thislist = Tcl_NewListObj(myobjc, myobjv);
00277         if (thislist == NULL)
00278                 return (TCL_ERROR);
00279         return (Tcl_ListObjAppendElement(interp, list, thislist));
00280 
00281 }
00282 
00283 /*
00284  * _Set3DBTList --
00285  *      This is really analogous to both _SetListElem and
00286  *      _SetListRecnoElem--it's used for three-DBT lists returned by
00287  *      DB->pget and DBC->pget().  We'd need a family of four functions
00288  *      to handle all the recno/non-recno cases, however, so we make
00289  *      this a little more aware of the internals and do the logic inside.
00290  *
00291  *      XXX
00292  *      One of these days all these functions should probably be cleaned up
00293  *      to eliminate redundancy and bring them into the standard DB
00294  *      function namespace.
00295  *
00296  * PUBLIC: int _Set3DBTList __P((Tcl_Interp *, Tcl_Obj *, DBT *, int,
00297  * PUBLIC:     DBT *, int, DBT *));
00298  */
00299 int
00300 _Set3DBTList(interp, list, elem1, is1recno, elem2, is2recno, elem3)
00301         Tcl_Interp *interp;
00302         Tcl_Obj *list;
00303         DBT *elem1, *elem2, *elem3;
00304         int is1recno, is2recno;
00305 {
00306 
00307         Tcl_Obj *myobjv[3], *thislist;
00308 
00309         if (is1recno)
00310                 myobjv[0] = Tcl_NewWideIntObj(
00311                     (Tcl_WideInt)*(db_recno_t *)elem1->data);
00312         else
00313                 myobjv[0] = Tcl_NewByteArrayObj(
00314                     (u_char *)elem1->data, (int)elem1->size);
00315 
00316         if (is2recno)
00317                 myobjv[1] = Tcl_NewWideIntObj(
00318                     (Tcl_WideInt)*(db_recno_t *)elem2->data);
00319         else
00320                 myobjv[1] = Tcl_NewByteArrayObj(
00321                     (u_char *)elem2->data, (int)elem2->size);
00322 
00323         myobjv[2] = Tcl_NewByteArrayObj(
00324             (u_char *)elem3->data, (int)elem3->size);
00325 
00326         thislist = Tcl_NewListObj(3, myobjv);
00327 
00328         if (thislist == NULL)
00329                 return (TCL_ERROR);
00330         return (Tcl_ListObjAppendElement(interp, list, thislist));
00331 }
00332 
00333 /*
00334  * _SetMultiList -- build a list for return from multiple get.
00335  *
00336  * PUBLIC: int _SetMultiList __P((Tcl_Interp *,
00337  * PUBLIC:          Tcl_Obj *, DBT *, DBT*, DBTYPE, u_int32_t));
00338  */
00339 int
00340 _SetMultiList(interp, list, key, data, type, flag)
00341         Tcl_Interp *interp;
00342         Tcl_Obj *list;
00343         DBT *key, *data;
00344         DBTYPE type;
00345         u_int32_t flag;
00346 {
00347         db_recno_t recno;
00348         u_int32_t dlen, klen;
00349         int result;
00350         void *pointer, *dp, *kp;
00351 
00352         recno = 0;
00353         dlen = 0;
00354         kp = NULL;
00355 
00356         DB_MULTIPLE_INIT(pointer, data);
00357         result = TCL_OK;
00358 
00359         if (type == DB_RECNO || type == DB_QUEUE)
00360                 recno = *(db_recno_t *) key->data;
00361         else
00362                 kp = key->data;
00363         klen = key->size;
00364         do {
00365                 if (flag & DB_MULTIPLE_KEY) {
00366                         if (type == DB_RECNO || type == DB_QUEUE)
00367                                 DB_MULTIPLE_RECNO_NEXT(pointer,
00368                                     data, recno, dp, dlen);
00369                         else
00370                                 DB_MULTIPLE_KEY_NEXT(pointer,
00371                                     data, kp, klen, dp, dlen);
00372                 } else
00373                         DB_MULTIPLE_NEXT(pointer, data, dp, dlen);
00374 
00375                 if (pointer == NULL)
00376                         break;
00377 
00378                 if (type == DB_RECNO || type == DB_QUEUE) {
00379                         result =
00380                             _SetListRecnoElem(interp, list, recno, dp, dlen);
00381                         recno++;
00382                         /* Wrap around and skip zero. */
00383                         if (recno == 0)
00384                                 recno++;
00385                 } else
00386                         result = _SetListElem(interp, list, kp, klen, dp, dlen);
00387         } while (result == TCL_OK);
00388 
00389         return (result);
00390 }
00391 /*
00392  * PUBLIC: int _GetGlobPrefix __P((char *, char **));
00393  */
00394 int
00395 _GetGlobPrefix(pattern, prefix)
00396         char *pattern;
00397         char **prefix;
00398 {
00399         int i, j;
00400         char *p;
00401 
00402         /*
00403          * Duplicate it, we get enough space and most of the work is done.
00404          */
00405         if (__os_strdup(NULL, pattern, prefix) != 0)
00406                 return (1);
00407 
00408         p = *prefix;
00409         for (i = 0, j = 0; p[i] && !GLOB_CHAR(p[i]); i++, j++)
00410                 /*
00411                  * Check for an escaped character and adjust
00412                  */
00413                 if (p[i] == '\\' && p[i+1]) {
00414                         p[j] = p[i+1];
00415                         i++;
00416                 } else
00417                         p[j] = p[i];
00418         p[j] = 0;
00419         return (0);
00420 }
00421 
00422 /*
00423  * PUBLIC: int _ReturnSetup __P((Tcl_Interp *, int, int, char *));
00424  */
00425 int
00426 _ReturnSetup(interp, ret, ok, errmsg)
00427         Tcl_Interp *interp;
00428         int ret, ok;
00429         char *errmsg;
00430 {
00431         char *msg;
00432 
00433         if (ret > 0)
00434                 return (_ErrorSetup(interp, ret, errmsg));
00435 
00436         /*
00437          * We either have success or a DB error.  If a DB error, set up the
00438          * string.  We return an error if not one of the errors we catch.
00439          * If anyone wants to reset the result to return anything different,
00440          * then the calling function is responsible for doing so via
00441          * Tcl_ResetResult or another Tcl_SetObjResult.
00442          */
00443         if (ret == 0) {
00444                 Tcl_SetResult(interp, "0", TCL_STATIC);
00445                 return (TCL_OK);
00446         }
00447 
00448         msg = db_strerror(ret);
00449         Tcl_AppendResult(interp, msg, NULL);
00450 
00451         if (ok)
00452                 return (TCL_OK);
00453         else {
00454                 Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL);
00455                 return (TCL_ERROR);
00456         }
00457 }
00458 
00459 /*
00460  * PUBLIC: int _ErrorSetup __P((Tcl_Interp *, int, char *));
00461  */
00462 int
00463 _ErrorSetup(interp, ret, errmsg)
00464         Tcl_Interp *interp;
00465         int ret;
00466         char *errmsg;
00467 {
00468         Tcl_SetErrno(ret);
00469         Tcl_AppendResult(interp, errmsg, ":", Tcl_PosixError(interp), NULL);
00470         return (TCL_ERROR);
00471 }
00472 
00473 /*
00474  * PUBLIC: void _ErrorFunc __P((const DB_ENV *, CONST char *, const char *));
00475  */
00476 void
00477 _ErrorFunc(dbenv, pfx, msg)
00478         const DB_ENV *dbenv;
00479         CONST char *pfx;
00480         const char *msg;
00481 {
00482         DBTCL_INFO *p;
00483         Tcl_Interp *interp;
00484         size_t size;
00485         char *err;
00486 
00487         COMPQUIET(dbenv, NULL);
00488 
00489         p = _NameToInfo(pfx);
00490         if (p == NULL)
00491                 return;
00492         interp = p->i_interp;
00493 
00494         size = strlen(pfx) + strlen(msg) + 4;
00495         /*
00496          * If we cannot allocate enough to put together the prefix
00497          * and message then give them just the message.
00498          */
00499         if (__os_malloc(NULL, size, &err) != 0) {
00500                 Tcl_AddErrorInfo(interp, msg);
00501                 Tcl_AppendResult(interp, msg, "\n", NULL);
00502                 return;
00503         }
00504         snprintf(err, size, "%s: %s", pfx, msg);
00505         Tcl_AddErrorInfo(interp, err);
00506         Tcl_AppendResult(interp, err, "\n", NULL);
00507         __os_free(NULL, err);
00508         return;
00509 }
00510 
00511 #define INVALID_LSNMSG "Invalid LSN with %d parts. Should have 2.\n"
00512 
00513 /*
00514  * PUBLIC: int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *));
00515  */
00516 int
00517 _GetLsn(interp, obj, lsn)
00518         Tcl_Interp *interp;
00519         Tcl_Obj *obj;
00520         DB_LSN *lsn;
00521 {
00522         Tcl_Obj **myobjv;
00523         char msg[MSG_SIZE];
00524         int myobjc, result;
00525         u_int32_t tmp;
00526 
00527         result = Tcl_ListObjGetElements(interp, obj, &myobjc, &myobjv);
00528         if (result == TCL_ERROR)
00529                 return (result);
00530         if (myobjc != 2) {
00531                 result = TCL_ERROR;
00532                 snprintf(msg, MSG_SIZE, INVALID_LSNMSG, myobjc);
00533                 Tcl_SetResult(interp, msg, TCL_VOLATILE);
00534                 return (result);
00535         }
00536         result = _GetUInt32(interp, myobjv[0], &tmp);
00537         if (result == TCL_ERROR)
00538                 return (result);
00539         lsn->file = tmp;
00540         result = _GetUInt32(interp, myobjv[1], &tmp);
00541         lsn->offset = tmp;
00542         return (result);
00543 }
00544 
00545 /*
00546  * _GetUInt32 --
00547  *      Get a u_int32_t from a Tcl object.  Tcl_GetIntFromObj does the
00548  * right thing most of the time, but on machines where a long is 8 bytes
00549  * and an int is 4 bytes, it errors on integers between the maximum
00550  * int32_t and the maximum u_int32_t.  This is correct, but we generally
00551  * want a u_int32_t in the end anyway, so we use Tcl_GetLongFromObj and do
00552  * the bounds checking ourselves.
00553  *
00554  * This code looks much like Tcl_GetIntFromObj, only with a different
00555  * bounds check.  It's essentially Tcl_GetUnsignedIntFromObj, which
00556  * unfortunately doesn't exist.
00557  *
00558  * PUBLIC: int _GetUInt32 __P((Tcl_Interp *, Tcl_Obj *, u_int32_t *));
00559  */
00560 int
00561 _GetUInt32(interp, obj, resp)
00562         Tcl_Interp *interp;
00563         Tcl_Obj *obj;
00564         u_int32_t *resp;
00565 {
00566         int result;
00567         long ltmp;
00568 
00569         result = Tcl_GetLongFromObj(interp, obj, &ltmp);
00570         if (result != TCL_OK)
00571                 return (result);
00572 
00573         if ((unsigned long)ltmp != (u_int32_t)ltmp) {
00574                 if (interp != NULL) {
00575                         Tcl_ResetResult(interp);
00576                         Tcl_AppendToObj(Tcl_GetObjResult(interp),
00577                             "integer value too large for u_int32_t", -1);
00578                 }
00579                 return (TCL_ERROR);
00580         }
00581 
00582         *resp = (u_int32_t)ltmp;
00583         return (TCL_OK);
00584 }
00585 
00586 /*
00587  * _GetFlagsList --
00588  *      Get a new Tcl object, containing a list of the string values
00589  * associated with a particular set of flag values.
00590  *
00591  * PUBLIC: Tcl_Obj *_GetFlagsList __P((Tcl_Interp *, u_int32_t, const FN *));
00592  */
00593 Tcl_Obj *
00594 _GetFlagsList(interp, flags, fnp)
00595         Tcl_Interp *interp;
00596         u_int32_t flags;
00597         const FN *fnp;
00598 {
00599         Tcl_Obj *newlist, *newobj;
00600         int result;
00601 
00602         newlist = Tcl_NewObj();
00603 
00604         /*
00605          * Append a Tcl_Obj containing each pertinent flag string to the
00606          * specified Tcl list.
00607          */
00608         for (; fnp->mask != 0; ++fnp)
00609                 if (LF_ISSET(fnp->mask)) {
00610                         newobj = NewStringObj(fnp->name, strlen(fnp->name));
00611                         result =
00612                             Tcl_ListObjAppendElement(interp, newlist, newobj);
00613 
00614                         /*
00615                          * Tcl_ListObjAppendElement is defined to return TCL_OK
00616                          * unless newlist isn't actually a list (or convertible
00617                          * into one).  If this is the case, we screwed up badly
00618                          * somehow.
00619                          */
00620                         DB_ASSERT(result == TCL_OK);
00621                 }
00622 
00623         return (newlist);
00624 }
00625 
00626 int __debug_stop, __debug_on, __debug_print, __debug_test;
00627 
00628 /*
00629  * PUBLIC: void _debug_check  __P((void));
00630  */
00631 void
00632 _debug_check()
00633 {
00634         if (__debug_on == 0)
00635                 return;
00636 
00637         if (__debug_print != 0) {
00638                 printf("\r%7d:", __debug_on);
00639                 (void)fflush(stdout);
00640         }
00641         if (__debug_on++ == __debug_test || __debug_stop)
00642                 __db_loadme();
00643 }
00644 
00645 /*
00646  * XXX
00647  * Tcl 8.1+ Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj bug.
00648  *
00649  * There is a bug in Tcl 8.1+ and byte arrays in that if it happens
00650  * to use an object as both a byte array and something else like
00651  * an int, and you've done a Tcl_GetByteArrayFromObj, then you
00652  * do a Tcl_GetIntFromObj, your memory is deleted.
00653  *
00654  * Workaround is for all byte arrays we want to use, if it can be
00655  * represented as an integer, we copy it so that we don't lose the
00656  * memory.
00657  */
00658 /*
00659  * PUBLIC: int _CopyObjBytes  __P((Tcl_Interp *, Tcl_Obj *obj, void *,
00660  * PUBLIC:     u_int32_t *, int *));
00661  */
00662 int
00663 _CopyObjBytes(interp, obj, newp, sizep, freep)
00664         Tcl_Interp *interp;
00665         Tcl_Obj *obj;
00666         void *newp;
00667         u_int32_t *sizep;
00668         int *freep;
00669 {
00670         void *tmp, *new;
00671         int i, len, ret;
00672 
00673         /*
00674          * If the object is not an int, then just return the byte
00675          * array because it won't be transformed out from under us.
00676          * If it is a number, we need to copy it.
00677          */
00678         *freep = 0;
00679         ret = Tcl_GetIntFromObj(interp, obj, &i);
00680         tmp = Tcl_GetByteArrayFromObj(obj, &len);
00681         *sizep = (u_int32_t)len;
00682         if (ret == TCL_ERROR) {
00683                 Tcl_ResetResult(interp);
00684                 *(void **)newp = tmp;
00685                 return (0);
00686         }
00687 
00688         /*
00689          * If we get here, we have an integer that might be reused
00690          * at some other point so we cannot count on GetByteArray
00691          * keeping our pointer valid.
00692          */
00693         if ((ret = __os_malloc(NULL, (size_t)len, &new)) != 0)
00694                 return (ret);
00695         memcpy(new, tmp, (size_t)len);
00696         *(void **)newp = new;
00697         *freep = 1;
00698         return (0);
00699 }

Generated on Sun Dec 25 12:14:52 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2