summaryrefslogtreecommitdiffstats
path: root/generic/tclPkg.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclPkg.c')
-rw-r--r--generic/tclPkg.c1202
1 files changed, 391 insertions, 811 deletions
diff --git a/generic/tclPkg.c b/generic/tclPkg.c
index 82860a6..52f33c3 100644
--- a/generic/tclPkg.c
+++ b/generic/tclPkg.c
@@ -4,8 +4,8 @@
* This file implements package and version control for Tcl via the
* "package" command and a few C APIs.
*
- * Copyright © 1996 Sun Microsystems, Inc.
- * Copyright © 2006 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+ * Copyright (c) 1996 Sun Microsystems, Inc.
+ * Copyright (c) 2006 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -17,10 +17,6 @@
#include "tclInt.h"
-MODULE_SCOPE char *tclEmptyStringRep;
-
-char *tclEmptyStringRep = &tclEmptyString;
-
/*
* Each invocation of the "package ifneeded" command creates a structure of
* the following type, which is used to load the package into the interpreter
@@ -32,24 +28,10 @@ typedef struct PkgAvail {
char *script; /* Script to invoke to provide this version of
* the package. Malloc'ed and protected by
* Tcl_Preserve and Tcl_Release. */
- char *pkgIndex; /* Full file name of pkgIndex file */
struct PkgAvail *nextPtr; /* Next in list of available versions of the
* same package. */
} PkgAvail;
-typedef struct PkgName {
- struct PkgName *nextPtr; /* Next in list of package names being
- * initialized. */
- char name[TCLFLEXARRAY];
-} PkgName;
-
-typedef struct PkgFiles {
- PkgName *names; /* Package names being initialized. Must be
- * first field. */
- Tcl_HashTable table; /* Table which contains files for each
- * package. */
-} PkgFiles;
-
/*
* For each package that is known in any way to an interpreter, there is one
* record of the following type. These records are stored in the
@@ -58,24 +40,15 @@ typedef struct PkgFiles {
*/
typedef struct Package {
- Tcl_Obj *version;
+ char *version; /* Version that has been supplied in this
+ * interpreter via "package provide"
+ * (malloc'ed). NULL means the package doesn't
+ * exist in this interpreter yet. */
PkgAvail *availPtr; /* First in list of all available versions of
* this package. */
- const void *clientData; /* Client data. */
+ ClientData clientData; /* Client data. */
} Package;
-typedef struct Require {
- void *clientDataPtr;
- const char *name;
- Package *pkgPtr;
- char *versionToProvide;
-} Require;
-
-typedef struct RequireProcArgs {
- const char *name;
- void *clientDataPtr;
-} RequireProcArgs;
-
/*
* Prototypes for functions defined in this file:
*/
@@ -96,25 +69,19 @@ static void AddRequirementsToResult(Tcl_Interp *interp, int reqc,
static void AddRequirementsToDString(Tcl_DString *dstring,
int reqc, Tcl_Obj *const reqv[]);
static Package * FindPackage(Tcl_Interp *interp, const char *name);
-static int PkgRequireCore(ClientData data[], Tcl_Interp *interp, int result);
-static int PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result);
-static int PkgRequireCoreCleanup(ClientData data[], Tcl_Interp *interp, int result);
-static int PkgRequireCoreStep1(ClientData data[], Tcl_Interp *interp, int result);
-static int PkgRequireCoreStep2(ClientData data[], Tcl_Interp *interp, int result);
-static int TclNRPkgRequireProc(ClientData clientData, Tcl_Interp *interp, int reqc, Tcl_Obj *const reqv[]);
-static int SelectPackage(ClientData data[], Tcl_Interp *interp, int result);
-static int SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result);
-static int TclNRPackageObjCmdCleanup(ClientData data[], Tcl_Interp *interp, int result);
+static const char * PkgRequireCore(Tcl_Interp *interp, const char *name,
+ int reqc, Tcl_Obj *const reqv[],
+ ClientData *clientDataPtr);
/*
* Helper macros.
*/
#define DupBlock(v,s,len) \
- ((v) = (char *)ckalloc(len), memcpy((v),(s),(len)))
+ ((v) = ckalloc(len), memcpy((v),(s),(len)))
#define DupString(v,s) \
do { \
- size_t local__len = strlen(s) + 1; \
+ unsigned local__len = (unsigned) (strlen(s) + 1); \
DupBlock((v),(s),local__len); \
} while (0)
@@ -156,7 +123,7 @@ Tcl_PkgProvideEx(
* available. */
const char *name, /* Name of package. */
const char *version, /* Version string for package. */
- const void *clientData) /* clientdata for this package (normally used
+ ClientData clientData) /* clientdata for this package (normally used
* for C callback function table) */
{
Package *pkgPtr;
@@ -165,13 +132,12 @@ Tcl_PkgProvideEx(
pkgPtr = FindPackage(interp, name);
if (pkgPtr->version == NULL) {
- pkgPtr->version = Tcl_NewStringObj(version, -1);
- Tcl_IncrRefCount(pkgPtr->version);
+ DupString(pkgPtr->version, version);
pkgPtr->clientData = clientData;
return TCL_OK;
}
- if (CheckVersionAndConvert(interp, Tcl_GetString(pkgPtr->version), &pvi,
+ if (CheckVersionAndConvert(interp, pkgPtr->version, &pvi,
NULL) != TCL_OK) {
return TCL_ERROR;
} else if (CheckVersionAndConvert(interp, version, &vi, NULL) != TCL_OK) {
@@ -189,10 +155,8 @@ Tcl_PkgProvideEx(
}
return TCL_OK;
}
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "conflicting versions provided for package \"%s\": %s, then %s",
- name, Tcl_GetString(pkgPtr->version), version));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT", (void *)NULL);
+ Tcl_AppendResult(interp, "conflicting versions provided for package \"",
+ name, "\": ", pkgPtr->version, ", then ", version, NULL);
return TCL_ERROR;
}
@@ -223,78 +187,6 @@ Tcl_PkgProvideEx(
*----------------------------------------------------------------------
*/
-static void
-PkgFilesCleanupProc(
- ClientData clientData,
- TCL_UNUSED(Tcl_Interp *))
-{
- PkgFiles *pkgFiles = (PkgFiles *) clientData;
- Tcl_HashSearch search;
- Tcl_HashEntry *entry;
-
- while (pkgFiles->names) {
- PkgName *name = pkgFiles->names;
-
- pkgFiles->names = name->nextPtr;
- ckfree(name);
- }
- entry = Tcl_FirstHashEntry(&pkgFiles->table, &search);
- while (entry) {
- Tcl_Obj *obj = (Tcl_Obj *)Tcl_GetHashValue(entry);
-
- Tcl_DecrRefCount(obj);
- entry = Tcl_NextHashEntry(&search);
- }
- Tcl_DeleteHashTable(&pkgFiles->table);
- ckfree(pkgFiles);
- return;
-}
-
-void *
-TclInitPkgFiles(
- Tcl_Interp *interp)
-{
- /*
- * If assocdata "tclPkgFiles" doesn't exist yet, create it.
- */
-
- PkgFiles *pkgFiles = (PkgFiles *)Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
-
- if (!pkgFiles) {
- pkgFiles = (PkgFiles *)ckalloc(sizeof(PkgFiles));
- pkgFiles->names = NULL;
- Tcl_InitHashTable(&pkgFiles->table, TCL_STRING_KEYS);
- Tcl_SetAssocData(interp, "tclPkgFiles", PkgFilesCleanupProc, pkgFiles);
- }
- return pkgFiles;
-}
-
-void
-TclPkgFileSeen(
- Tcl_Interp *interp,
- const char *fileName)
-{
- PkgFiles *pkgFiles = (PkgFiles *)
- Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
-
- if (pkgFiles && pkgFiles->names) {
- const char *name = pkgFiles->names->name;
- Tcl_HashTable *table = &pkgFiles->table;
- int isNew;
- Tcl_HashEntry *entry = (Tcl_HashEntry *)Tcl_CreateHashEntry(table, name, &isNew);
- Tcl_Obj *list;
-
- if (isNew) {
- TclNewObj(list);
- Tcl_SetHashValue(entry, list);
- Tcl_IncrRefCount(list);
- } else {
- list = (Tcl_Obj *)Tcl_GetHashValue(entry);
- }
- Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(fileName, -1));
- }
-}
-
#undef Tcl_PkgRequire
const char *
Tcl_PkgRequire(
@@ -320,7 +212,7 @@ Tcl_PkgRequireEx(
int exact, /* Non-zero means that only the particular
* version given is acceptable. Zero means use
* the latest compatible version. */
- void *clientDataPtr) /* Used to return the client data for this
+ ClientData *clientDataPtr) /* Used to return the client data for this
* package. If it is NULL then the client data
* is not returned. This is unchanged if this
* call fails for any reason. */
@@ -364,12 +256,12 @@ Tcl_PkgRequireEx(
*
* Second, how does this work? If we reach this point, then the global
* variable tclEmptyStringRep has the value NULL. Compare that with
- * the definition of tclEmptyStringRep near the top of this file. It
- * clearly should not have the value NULL; it should point to the char
- * tclEmptyString. If we see it having the value NULL, then somehow we
- * are seeing a Tcl library that isn't completely initialized, and
- * that's an indicator for the error condition described above.
- * (Further explanation is welcome.)
+ * the definition of tclEmptyStringRep near the top of the file
+ * generic/tclObj.c. It clearly should not have the value NULL; it
+ * should point to the char tclEmptyString. If we see it having the
+ * value NULL, then somehow we are seeing a Tcl library that isn't
+ * completely initialized, and that's an indicator for the error
+ * condition described above. (Further explanation is welcome.)
*
* Third, so what do we do about it? This situation indicates the
* package we just loaded wasn't properly compiled to be stub-enabled,
@@ -381,15 +273,21 @@ Tcl_PkgRequireEx(
* After all, two Tcl libraries can't be a good thing!)
*
* Trouble is that's going to be tricky. We're now using a Tcl library
- * that's not fully initialized. Functions in it may not work
- * reliably, so be very careful about adding any other calls here
- * without checking how they behave when initialization is incomplete.
+ * that's not fully initialized. In particular, it doesn't have a
+ * proper value for tclEmptyStringRep. The Tcl_Obj system heavily
+ * depends on the value of tclEmptyStringRep and all of Tcl depends
+ * (increasingly) on the Tcl_Obj system, we need to correct that flaw
+ * before making the calls to set the interpreter result to the error
+ * message. That's the only flaw corrected; other problems with
+ * initialization of the Tcl library are not remedied, so be very
+ * careful about adding any other calls here without checking how they
+ * behave when initialization is incomplete.
*/
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "Cannot load package \"%s\" in standalone executable:"
- " This package is not compiled with stub support", name));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNSTUBBED", (void *)NULL);
+ tclEmptyStringRep = &tclEmptyString;
+ Tcl_AppendResult(interp, "Cannot load package \"", name,
+ "\" in standalone executable: This package is not "
+ "compiled with stub support", NULL);
return NULL;
}
@@ -398,10 +296,7 @@ Tcl_PkgRequireEx(
*/
if (version == NULL) {
- if (Tcl_PkgRequireProc(interp, name, 0, NULL, clientDataPtr) == TCL_OK) {
- result = Tcl_GetString(Tcl_GetObjResult(interp));
- Tcl_ResetResult(interp);
- }
+ result = PkgRequireCore(interp, name, 0, NULL, clientDataPtr);
} else {
if (exact && TCL_OK
!= CheckVersionAndConvert(interp, version, NULL, NULL)) {
@@ -409,15 +304,13 @@ Tcl_PkgRequireEx(
}
ov = Tcl_NewStringObj(version, -1);
if (exact) {
- Tcl_AppendStringsToObj(ov, "-", version, (void *)NULL);
+ Tcl_AppendStringsToObj(ov, "-", version, NULL);
}
Tcl_IncrRefCount(ov);
- if (Tcl_PkgRequireProc(interp, name, 1, &ov, clientDataPtr) == TCL_OK) {
- result = Tcl_GetString(Tcl_GetObjResult(interp));
- Tcl_ResetResult(interp);
- }
+ result = PkgRequireCore(interp, name, 1, &ov, clientDataPtr);
TclDecrRefCount(ov);
}
+
return result;
}
@@ -430,522 +323,317 @@ Tcl_PkgRequireProc(
* version. */
Tcl_Obj *const reqv[], /* 0 means to use the latest version
* available. */
- void *clientDataPtr)
+ ClientData *clientDataPtr)
{
- RequireProcArgs args;
-
- args.name = name;
- args.clientDataPtr = clientDataPtr;
- return Tcl_NRCallObjProc(interp,
- TclNRPkgRequireProc, (void *) &args, reqc, reqv);
-}
-
-static int
-TclNRPkgRequireProc(
- ClientData clientData,
- Tcl_Interp *interp,
- int reqc,
- Tcl_Obj *const reqv[])
-{
- RequireProcArgs *args = (RequireProcArgs *)clientData;
-
- Tcl_NRAddCallback(interp,
- PkgRequireCore, (void *) args->name, INT2PTR(reqc), (void *) reqv,
- args->clientDataPtr);
- return TCL_OK;
-}
+ const char *result =
+ PkgRequireCore(interp, name, reqc, reqv, clientDataPtr);
-static int
-PkgRequireCore(
- ClientData data[],
- Tcl_Interp *interp,
- TCL_UNUSED(int))
-{
- const char *name = (const char *)data[0];
- int reqc = PTR2INT(data[1]);
- Tcl_Obj **reqv = (Tcl_Obj **)data[2];
- int code = CheckAllRequirements(interp, reqc, reqv);
- Require *reqPtr;
-
- if (code != TCL_OK) {
- return code;
- }
- reqPtr = (Require *)ckalloc(sizeof(Require));
- Tcl_NRAddCallback(interp, PkgRequireCoreCleanup, reqPtr, NULL, NULL, NULL);
- reqPtr->clientDataPtr = data[3];
- reqPtr->name = name;
- reqPtr->pkgPtr = FindPackage(interp, name);
- if (reqPtr->pkgPtr->version == NULL) {
- Tcl_NRAddCallback(interp,
- SelectPackage, reqPtr, INT2PTR(reqc), reqv,
- (void *)PkgRequireCoreStep1);
- } else {
- Tcl_NRAddCallback(interp,
- PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), reqv, NULL);
+ if (result == NULL) {
+ return TCL_ERROR;
}
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
return TCL_OK;
}
-static int
-PkgRequireCoreStep1(
- ClientData data[],
- Tcl_Interp *interp,
- TCL_UNUSED(int))
+static const char *
+PkgRequireCore(
+ Tcl_Interp *interp, /* Interpreter in which package is now
+ * available. */
+ const char *name, /* Name of desired package. */
+ int reqc, /* Requirements constraining the desired
+ * version. */
+ Tcl_Obj *const reqv[], /* 0 means to use the latest version
+ * available. */
+ ClientData *clientDataPtr)
{
+ Interp *iPtr = (Interp *) interp;
+ Package *pkgPtr;
+ PkgAvail *availPtr, *bestPtr, *bestStablePtr;
+ char *availVersion, *bestVersion;
+ /* Internal rep. of versions */
+ int availStable, code, satisfies, pass;
+ char *script, *pkgVersionI;
Tcl_DString command;
- char *script;
- Require *reqPtr = (Require *)data[0];
- int reqc = PTR2INT(data[1]);
- Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
- const char *name = reqPtr->name /* Name of desired package. */;
- /*
- * If we've got the package in the DB already, go on to actually loading
- * it.
- */
-
- if (reqPtr->pkgPtr->version != NULL) {
- Tcl_NRAddCallback(interp,
- PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
- return TCL_OK;
+ if (TCL_OK != CheckAllRequirements(interp, reqc, reqv)) {
+ return NULL;
}
/*
- * The package is not in the database. If there is a "package unknown"
- * command, invoke it.
+ * It can take up to three passes to find the package: one pass to run the
+ * "package unknown" script, one to run the "package ifneeded" script for
+ * a specific version, and a final pass to lookup the package loaded by
+ * the "package ifneeded" script.
*/
- script = ((Interp *) interp)->packageUnknown;
- if (script == NULL) {
+ for (pass=1 ;; pass++) {
+ pkgPtr = FindPackage(interp, name);
+ if (pkgPtr->version != NULL) {
+ break;
+ }
+
/*
- * No package unknown script. Move on to finalizing.
+ * Check whether we're already attempting to load some version of this
+ * package (circular dependency detection).
*/
- Tcl_NRAddCallback(interp,
- PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
- return TCL_OK;
- }
-
- /*
- * Invoke the "package unknown" script synchronously.
- */
-
- Tcl_DStringInit(&command);
- Tcl_DStringAppend(&command, script, -1);
- Tcl_DStringAppendElement(&command, name);
- AddRequirementsToDString(&command, reqc, reqv);
-
- Tcl_NRAddCallback(interp,
- PkgRequireCoreStep2, reqPtr, INT2PTR(reqc), (void *) reqv, NULL);
- Tcl_NREvalObj(interp,
- Tcl_NewStringObj(Tcl_DStringValue(&command),
- Tcl_DStringLength(&command)),
- TCL_EVAL_GLOBAL);
- Tcl_DStringFree(&command);
- return TCL_OK;
-}
-
-static int
-PkgRequireCoreStep2(
- ClientData data[],
- Tcl_Interp *interp,
- int result)
-{
- Require *reqPtr = (Require *)data[0];
- int reqc = PTR2INT(data[1]);
- Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
- const char *name = reqPtr->name; /* Name of desired package. */
-
- if ((result != TCL_OK) && (result != TCL_ERROR)) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad return code: %d", result));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", (void *)NULL);
- result = TCL_ERROR;
- }
- if (result == TCL_ERROR) {
- Tcl_AddErrorInfo(interp,
- "\n (\"package unknown\" script)");
- return result;
- }
- Tcl_ResetResult(interp);
-
- /*
- * pkgPtr may now be invalid, so refresh it.
- */
+ if (pkgPtr->clientData != NULL) {
+ Tcl_AppendResult(interp, "circular package dependency: "
+ "attempt to provide ", name, " ",
+ (char *) pkgPtr->clientData, " requires ", name, NULL);
+ AddRequirementsToResult(interp, reqc, reqv);
+ return NULL;
+ }
- reqPtr->pkgPtr = FindPackage(interp, name);
- Tcl_NRAddCallback(interp,
- SelectPackage, reqPtr, INT2PTR(reqc), reqv,
- (void *)PkgRequireCoreFinal);
- return TCL_OK;
-}
+ /*
+ * The package isn't yet present. Search the list of available
+ * versions and invoke the script for the best available version. We
+ * are actually locating the best, and the best stable version. One of
+ * them is then chosen based on the selection mode.
+ */
-static int
-PkgRequireCoreFinal(
- ClientData data[],
- Tcl_Interp *interp,
- TCL_UNUSED(int))
-{
- Require *reqPtr = (Require *)data[0];
- int reqc = PTR2INT(data[1]), satisfies;
- Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
- char *pkgVersionI;
- void *clientDataPtr = reqPtr->clientDataPtr;
- const char *name = reqPtr->name; /* Name of desired package. */
-
- if (reqPtr->pkgPtr->version == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't find package %s", name));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNFOUND", (void *)NULL);
- AddRequirementsToResult(interp, reqc, reqv);
- return TCL_ERROR;
- }
+ bestPtr = NULL;
+ bestStablePtr = NULL;
+ bestVersion = NULL;
- /*
- * Ensure that the provided version meets the current requirements.
- */
+ for (availPtr = pkgPtr->availPtr; availPtr != NULL;
+ availPtr = availPtr->nextPtr) {
+ if (CheckVersionAndConvert(interp, availPtr->version,
+ &availVersion, &availStable) != TCL_OK) {
+ /*
+ * The provided version number has invalid syntax. This
+ * should not happen. This should have been caught by the
+ * 'package ifneeded' registering the package.
+ */
- if (reqc != 0) {
- CheckVersionAndConvert(interp, Tcl_GetString(reqPtr->pkgPtr->version),
- &pkgVersionI, NULL);
- satisfies = SomeRequirementSatisfied(pkgVersionI, reqc, reqv);
+ continue;
+ }
- ckfree(pkgVersionI);
+ if (bestPtr != NULL) {
+ int res = CompareVersions(availVersion, bestVersion, NULL);
- if (!satisfies) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "version conflict for package \"%s\": have %s, need",
- name, Tcl_GetString(reqPtr->pkgPtr->version)));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT",
- (void *)NULL);
- AddRequirementsToResult(interp, reqc, reqv);
- return TCL_ERROR;
- }
- }
+ /*
+ * Note: Use internal reps!
+ */
- if (clientDataPtr) {
- const void **ptr = (const void **) clientDataPtr;
+ if (res <= 0) {
+ /*
+ * The version of the package sought is not as good as the
+ * currently selected version. Ignore it.
+ */
- *ptr = reqPtr->pkgPtr->clientData;
- }
- Tcl_SetObjResult(interp, reqPtr->pkgPtr->version);
- return TCL_OK;
-}
+ ckfree(availVersion);
+ availVersion = NULL;
+ continue;
+ }
+ }
-static int
-PkgRequireCoreCleanup(
- ClientData data[],
- TCL_UNUSED(Tcl_Interp *),
- int result)
-{
- ckfree(data[0]);
- return result;
-}
-
-static int
-SelectPackage(
- ClientData data[],
- Tcl_Interp *interp,
- TCL_UNUSED(int))
-{
- PkgAvail *availPtr, *bestPtr, *bestStablePtr;
- char *availVersion, *bestVersion, *bestStableVersion;
- /* Internal rep. of versions */
- int availStable, satisfies;
- Require *reqPtr = (Require *)data[0];
- int reqc = PTR2INT(data[1]);
- Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
- const char *name = reqPtr->name;
- Package *pkgPtr = reqPtr->pkgPtr;
- Interp *iPtr = (Interp *) interp;
+ /* We have found a version which is better than our max. */
- /*
- * Check whether we're already attempting to load some version of this
- * package (circular dependency detection).
- */
+ if (reqc > 0) {
+ /* Check satisfaction of requirements. */
- if (pkgPtr->clientData != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "circular package dependency:"
- " attempt to provide %s %s requires %s",
- name, (char *) pkgPtr->clientData, name));
- AddRequirementsToResult(interp, reqc, reqv);
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "CIRCULARITY", (void *)NULL);
- return TCL_ERROR;
- }
+ satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv);
+ if (!satisfies) {
+ ckfree(availVersion);
+ availVersion = NULL;
+ continue;
+ }
+ }
- /*
- * The package isn't yet present. Search the list of available versions
- * and invoke the script for the best available version. We are actually
- * locating the best, and the best stable version. One of them is then
- * chosen based on the selection mode.
- */
+ bestPtr = availPtr;
- bestPtr = NULL;
- bestStablePtr = NULL;
- bestVersion = NULL;
- bestStableVersion = NULL;
+ if (bestVersion != NULL) {
+ ckfree(bestVersion);
+ }
+ bestVersion = availVersion;
- for (availPtr = pkgPtr->availPtr; availPtr != NULL;
- availPtr = availPtr->nextPtr) {
- if (CheckVersionAndConvert(interp, availPtr->version,
- &availVersion, &availStable) != TCL_OK) {
/*
- * The provided version number has invalid syntax. This should not
- * happen. This should have been caught by the 'package ifneeded'
- * registering the package.
+ * If this new best version is stable then it also has to be
+ * better than the max stable version found so far.
*/
- continue;
+ if (availStable) {
+ bestStablePtr = availPtr;
+ }
+ }
+
+ if (bestVersion != NULL) {
+ ckfree(bestVersion);
}
/*
- * Check satisfaction of requirements before considering the current
- * version further.
+ * Now choose a version among the two best. For 'latest' we simply
+ * take (actually keep) the best. For 'stable' we take the best
+ * stable, if there is any, or the best if there is nothing stable.
*/
- if (reqc > 0) {
- satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv);
- if (!satisfies) {
- ckfree(availVersion);
- availVersion = NULL;
- continue;
- }
+ if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
+ && (bestStablePtr != NULL)) {
+ bestPtr = bestStablePtr;
}
if (bestPtr != NULL) {
- int res = CompareVersions(availVersion, bestVersion, NULL);
-
/*
- * Note: Used internal reps in the comparison!
+ * We found an ifneeded script for the package. Be careful while
+ * executing it: this could cause reentrancy, so (a) protect the
+ * script itself from deletion and (b) don't assume that bestPtr
+ * will still exist when the script completes.
*/
- if (res > 0) {
- /*
- * The version of the package sought is better than the
- * currently selected version.
- */
-
- ckfree(bestVersion);
- bestVersion = NULL;
- goto newbest;
+ const char *versionToProvide = bestPtr->version;
+ script = bestPtr->script;
+
+ pkgPtr->clientData = (ClientData) versionToProvide;
+ Tcl_Preserve((ClientData) script);
+ Tcl_Preserve((ClientData) versionToProvide);
+ code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL);
+ Tcl_Release((ClientData) script);
+
+ pkgPtr = FindPackage(interp, name);
+ if (code == TCL_OK) {
+ Tcl_ResetResult(interp);
+ if (pkgPtr->version == NULL) {
+ code = TCL_ERROR;
+ Tcl_AppendResult(interp, "attempt to provide package ",
+ name, " ", versionToProvide,
+ " failed: no version of package ", name,
+ " provided", NULL);
+ } else {
+ char *pvi, *vi;
+
+ if (CheckVersionAndConvert(interp, pkgPtr->version, &pvi,
+ NULL) != TCL_OK) {
+ code = TCL_ERROR;
+ } else if (CheckVersionAndConvert(interp,
+ versionToProvide, &vi, NULL) != TCL_OK) {
+ ckfree(pvi);
+ code = TCL_ERROR;
+ } else {
+ int res = CompareVersions(pvi, vi, NULL);
+
+ ckfree(pvi);
+ ckfree(vi);
+ if (res != 0) {
+ code = TCL_ERROR;
+ Tcl_AppendResult(interp,
+ "attempt to provide package ", name, " ",
+ versionToProvide, " failed: package ",
+ name, " ", pkgPtr->version,
+ " provided instead", NULL);
+ }
+ }
+ }
+ } else if (code != TCL_ERROR) {
+ Tcl_Obj *codePtr = Tcl_NewIntObj(code);
+
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "attempt to provide package ", name,
+ " ", versionToProvide, " failed: bad return code: ",
+ TclGetString(codePtr), NULL);
+ TclDecrRefCount(codePtr);
+ code = TCL_ERROR;
}
- } else {
- newbest:
- /*
- * We have found a version which is better than our max.
- */
- bestPtr = availPtr;
- CheckVersionAndConvert(interp, bestPtr->version, &bestVersion, NULL);
- }
-
- if (!availStable) {
- ckfree(availVersion);
- availVersion = NULL;
- continue;
- }
-
- if (bestStablePtr != NULL) {
- int res = CompareVersions(availVersion, bestStableVersion, NULL);
-
- /*
- * Note: Used internal reps in the comparison!
- */
+ if (code == TCL_ERROR) {
+ Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
+ "\n (\"package ifneeded %s %s\" script)",
+ name, versionToProvide));
+ }
+ Tcl_Release((ClientData) versionToProvide);
- if (res > 0) {
+ if (code != TCL_OK) {
/*
- * This stable version of the package sought is better than
- * the currently selected stable version.
+ * Take a non-TCL_OK code from the script as an indication the
+ * package wasn't loaded properly, so the package system
+ * should not remember an improper load.
+ *
+ * This is consistent with our returning NULL. If we're not
+ * willing to tell our caller we got a particular version, we
+ * shouldn't store that version for telling future callers
+ * either.
*/
- ckfree(bestStableVersion);
- bestStableVersion = NULL;
- goto newstable;
+ if (pkgPtr->version != NULL) {
+ ckfree(pkgPtr->version);
+ pkgPtr->version = NULL;
+ }
+ pkgPtr->clientData = NULL;
+ return NULL;
}
- } else {
- newstable:
- /*
- * We have found a stable version which is better than our max
- * stable.
- */
- bestStablePtr = availPtr;
- CheckVersionAndConvert(interp, bestStablePtr->version,
- &bestStableVersion, NULL);
+ break;
}
- ckfree(availVersion);
- availVersion = NULL;
- } /* end for */
-
- /*
- * Clean up memorized internal reps, if any.
- */
-
- if (bestVersion != NULL) {
- ckfree(bestVersion);
- bestVersion = NULL;
- }
-
- if (bestStableVersion != NULL) {
- ckfree(bestStableVersion);
- bestStableVersion = NULL;
- }
-
- /*
- * Now choose a version among the two best. For 'latest' we simply take
- * (actually keep) the best. For 'stable' we take the best stable, if
- * there is any, or the best if there is nothing stable.
- */
-
- if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
- && (bestStablePtr != NULL)) {
- bestPtr = bestStablePtr;
- }
-
- if (bestPtr == NULL) {
- Tcl_NRAddCallback(interp,
- (Tcl_NRPostProc *)data[3], reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
- } else {
/*
- * We found an ifneeded script for the package. Be careful while
- * executing it: this could cause reentrancy, so (a) protect the
- * script itself from deletion and (b) don't assume that bestPtr will
- * still exist when the script completes.
+ * The package is not in the database. If there is a "package unknown"
+ * command, invoke it (but only on the first pass; after that, we
+ * should not get here in the first place).
*/
- char *versionToProvide = bestPtr->version;
- PkgFiles *pkgFiles;
- PkgName *pkgName;
-
- Tcl_Preserve(versionToProvide);
- pkgPtr->clientData = versionToProvide;
-
- pkgFiles = (PkgFiles *)TclInitPkgFiles(interp);
-
- /*
- * Push "ifneeded" package name in "tclPkgFiles" assocdata.
- */
+ if (pass > 1) {
+ break;
+ }
- pkgName = (PkgName *)ckalloc(offsetof(PkgName, name) + 1 + strlen(name));
- pkgName->nextPtr = pkgFiles->names;
- strcpy(pkgName->name, name);
- pkgFiles->names = pkgName;
- if (bestPtr->pkgIndex) {
- TclPkgFileSeen(interp, bestPtr->pkgIndex);
+ script = ((Interp *) interp)->packageUnknown;
+ if (script != NULL) {
+ Tcl_DStringInit(&command);
+ Tcl_DStringAppend(&command, script, -1);
+ Tcl_DStringAppendElement(&command, name);
+ AddRequirementsToDString(&command, reqc, reqv);
+
+ code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
+ Tcl_DStringFree(&command);
+
+ if ((code != TCL_OK) && (code != TCL_ERROR)) {
+ Tcl_Obj *codePtr = Tcl_NewIntObj(code);
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "bad return code: ",
+ TclGetString(codePtr), NULL);
+ Tcl_DecrRefCount(codePtr);
+ code = TCL_ERROR;
+ }
+ if (code == TCL_ERROR) {
+ Tcl_AddErrorInfo(interp,
+ "\n (\"package unknown\" script)");
+ return NULL;
+ }
+ Tcl_ResetResult(interp);
}
- reqPtr->versionToProvide = versionToProvide;
- Tcl_NRAddCallback(interp,
- SelectPackageFinal, reqPtr, INT2PTR(reqc), (void *)reqv,
- data[3]);
- Tcl_NREvalObj(interp, Tcl_NewStringObj(bestPtr->script, -1),
- TCL_EVAL_GLOBAL);
}
- return TCL_OK;
-}
-
-static int
-SelectPackageFinal(
- ClientData data[],
- Tcl_Interp *interp,
- int result)
-{
- Require *reqPtr = (Require *)data[0];
- int reqc = PTR2INT(data[1]);
- Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
- const char *name = reqPtr->name;
- char *versionToProvide = reqPtr->versionToProvide;
+
+ if (pkgPtr->version == NULL) {
+ Tcl_AppendResult(interp, "can't find package ", name, NULL);
+ AddRequirementsToResult(interp, reqc, reqv);
+ return NULL;
+ }
/*
- * Pop the "ifneeded" package name from "tclPkgFiles" assocdata
+ * At this point we know that the package is present. Make sure that the
+ * provided version meets the current requirements.
*/
- PkgFiles *pkgFiles = (PkgFiles *)Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
- PkgName *pkgName = pkgFiles->names;
- pkgFiles->names = pkgName->nextPtr;
- ckfree(pkgName);
-
- reqPtr->pkgPtr = FindPackage(interp, name);
- if (result == TCL_OK) {
- Tcl_ResetResult(interp);
- if (reqPtr->pkgPtr->version == NULL) {
- result = TCL_ERROR;
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "attempt to provide package %s %s failed:"
- " no version of package %s provided",
- name, versionToProvide, name));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNPROVIDED",
- (void *)NULL);
- } else {
- char *pvi, *vi;
-
- if (TCL_OK != CheckVersionAndConvert(interp,
- Tcl_GetString(reqPtr->pkgPtr->version), &pvi, NULL)) {
- result = TCL_ERROR;
- } else if (CheckVersionAndConvert(interp,
- versionToProvide, &vi, NULL) != TCL_OK) {
- ckfree(pvi);
- result = TCL_ERROR;
- } else {
- int res = CompareVersions(pvi, vi, NULL);
-
- ckfree(pvi);
- ckfree(vi);
- if (res != 0) {
- result = TCL_ERROR;
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "attempt to provide package %s %s failed:"
- " package %s %s provided instead",
- name, versionToProvide,
- name, Tcl_GetString(reqPtr->pkgPtr->version)));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE",
- "WRONGPROVIDE", (void *)NULL);
- }
- }
- }
- } else if (result != TCL_ERROR) {
- Tcl_Obj *codePtr;
-
- TclNewIntObj(codePtr, result);
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "attempt to provide package %s %s failed:"
- " bad return code: %s",
- name, versionToProvide, TclGetString(codePtr)));
- Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", (void *)NULL);
- TclDecrRefCount(codePtr);
- result = TCL_ERROR;
- }
+ if (reqc == 0) {
+ satisfies = 1;
+ } else {
+ CheckVersionAndConvert(interp, pkgPtr->version, &pkgVersionI, NULL);
+ satisfies = SomeRequirementSatisfied(pkgVersionI, reqc, reqv);
- if (result == TCL_ERROR) {
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (\"package ifneeded %s %s\" script)",
- name, versionToProvide));
+ ckfree(pkgVersionI);
}
- Tcl_Release(versionToProvide);
-
- if (result != TCL_OK) {
- /*
- * Take a non-TCL_OK code from the script as an indication the package
- * wasn't loaded properly, so the package system should not remember
- * an improper load.
- *
- * This is consistent with our returning NULL. If we're not willing to
- * tell our caller we got a particular version, we shouldn't store
- * that version for telling future callers either.
- */
- if (reqPtr->pkgPtr->version != NULL) {
- Tcl_DecrRefCount(reqPtr->pkgPtr->version);
- reqPtr->pkgPtr->version = NULL;
+ if (satisfies) {
+ if (clientDataPtr) {
+ *clientDataPtr = pkgPtr->clientData;
}
- reqPtr->pkgPtr->clientData = NULL;
- return result;
+ return pkgPtr->version;
}
- Tcl_NRAddCallback(interp,
- (Tcl_NRPostProc *)data[3], reqPtr, INT2PTR(reqc), (void *) reqv, NULL);
- return TCL_OK;
+ Tcl_AppendResult(interp, "version conflict for package \"", name,
+ "\": have ", pkgPtr->version, ", need", NULL);
+ AddRequirementsToResult(interp, reqc, reqv);
+ return NULL;
}
/*
@@ -994,7 +682,7 @@ Tcl_PkgPresentEx(
int exact, /* Non-zero means that only the particular
* version given is acceptable. Zero means use
* the latest compatible version. */
- void *clientDataPtr) /* Used to return the client data for this
+ ClientData *clientDataPtr) /* Used to return the client data for this
* package. If it is NULL then the client data
* is not returned. This is unchanged if this
* call fails for any reason. */
@@ -1005,7 +693,7 @@ Tcl_PkgPresentEx(
hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name);
if (hPtr) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
if (pkgPtr->version != NULL) {
/*
* At this point we know that the package is present. Make sure
@@ -1018,20 +706,19 @@ Tcl_PkgPresentEx(
if (foundVersion == NULL) {
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PACKAGE", name,
- (void *)NULL);
+ NULL);
}
return foundVersion;
}
}
if (version != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "package %s %s is not present", name, version));
+ Tcl_AppendResult(interp, "package ", name, " ", version,
+ " is not present", NULL);
} else {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "package %s is not present", name));
+ Tcl_AppendResult(interp, "package ", name, " is not present", NULL);
}
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PACKAGE", name, (void *)NULL);
+ Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PACKAGE", name, NULL);
return NULL;
}
@@ -1051,47 +738,37 @@ Tcl_PkgPresentEx(
*
*----------------------------------------------------------------------
*/
-int
-Tcl_PackageObjCmd(
- ClientData clientData,
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- return Tcl_NRCallObjProc(interp, TclNRPackageObjCmd, clientData, objc, objv);
-}
+ /* ARGSUSED */
int
-TclNRPackageObjCmd(
- TCL_UNUSED(ClientData),
+Tcl_PackageObjCmd(
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
- static const char *const pkgOptions[] = {
- "files", "forget", "ifneeded", "names", "prefer",
- "present", "provide", "require", "unknown", "vcompare",
- "versions", "vsatisfies", NULL
+ static const char *pkgOptions[] = {
+ "forget", "ifneeded", "names", "prefer", "present",
+ "provide", "require", "unknown", "vcompare", "versions",
+ "vsatisfies", NULL
};
- enum pkgOptionsEnum {
- PKG_FILES, PKG_FORGET, PKG_IFNEEDED, PKG_NAMES, PKG_PREFER,
- PKG_PRESENT, PKG_PROVIDE, PKG_REQUIRE, PKG_UNKNOWN, PKG_VCOMPARE,
- PKG_VERSIONS, PKG_VSATISFIES
+ enum pkgOptions {
+ PKG_FORGET, PKG_IFNEEDED, PKG_NAMES, PKG_PREFER, PKG_PRESENT,
+ PKG_PROVIDE, PKG_REQUIRE, PKG_UNKNOWN, PKG_VCOMPARE, PKG_VERSIONS,
+ PKG_VSATISFIES
};
Interp *iPtr = (Interp *) interp;
- int optionIndex, exact, i, newobjc, satisfies;
+ int optionIndex, exact, i, satisfies;
PkgAvail *availPtr, *prevPtr;
Package *pkgPtr;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
Tcl_HashTable *tablePtr;
const char *version;
- const char *argv2, *argv3, *argv4;
- char *iva = NULL, *ivb = NULL;
- Tcl_Obj *objvListPtr, **newObjvPtr;
+ char *argv2, *argv3, *argv4, *iva = NULL, *ivb = NULL;
if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
@@ -1099,61 +776,29 @@ TclNRPackageObjCmd(
&optionIndex) != TCL_OK) {
return TCL_ERROR;
}
- switch ((enum pkgOptionsEnum) optionIndex) {
- case PKG_FILES: {
- PkgFiles *pkgFiles;
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "package");
- return TCL_ERROR;
- }
- pkgFiles = (PkgFiles *) Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
- if (pkgFiles) {
- Tcl_HashEntry *entry =
- Tcl_FindHashEntry(&pkgFiles->table, Tcl_GetString(objv[2]));
- if (entry) {
- Tcl_SetObjResult(interp, (Tcl_Obj *)Tcl_GetHashValue(entry));
- }
- }
- break;
- }
+ switch ((enum pkgOptions) optionIndex) {
case PKG_FORGET: {
- const char *keyString;
- PkgFiles *pkgFiles = (PkgFiles *)
- Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
+ char *keyString;
for (i = 2; i < objc; i++) {
keyString = TclGetString(objv[i]);
- if (pkgFiles) {
- hPtr = Tcl_FindHashEntry(&pkgFiles->table, keyString);
- if (hPtr) {
- Tcl_Obj *obj = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
- Tcl_DeleteHashEntry(hPtr);
- Tcl_DecrRefCount(obj);
- }
- }
-
hPtr = Tcl_FindHashEntry(&iPtr->packageTable, keyString);
if (hPtr == NULL) {
continue;
}
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
Tcl_DeleteHashEntry(hPtr);
if (pkgPtr->version != NULL) {
- Tcl_DecrRefCount(pkgPtr->version);
+ ckfree(pkgPtr->version);
}
while (pkgPtr->availPtr != NULL) {
availPtr = pkgPtr->availPtr;
pkgPtr->availPtr = availPtr->nextPtr;
- Tcl_EventuallyFree(availPtr->version, TCL_DYNAMIC);
- Tcl_EventuallyFree(availPtr->script, TCL_DYNAMIC);
- if (availPtr->pkgIndex) {
- Tcl_EventuallyFree(availPtr->pkgIndex, TCL_DYNAMIC);
- availPtr->pkgIndex = NULL;
- }
- ckfree(availPtr);
+ Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC);
+ Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC);
+ ckfree((char *) availPtr);
}
- ckfree(pkgPtr);
+ ckfree((char *) pkgPtr);
}
break;
}
@@ -1176,11 +821,11 @@ TclNRPackageObjCmd(
ckfree(argv3i);
return TCL_OK;
}
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
} else {
pkgPtr = FindPackage(interp, argv2);
}
- argv3 = TclGetStringFromObj(objv[3], &length);
+ argv3 = Tcl_GetStringFromObj(objv[3], &length);
for (availPtr = pkgPtr->availPtr, prevPtr = NULL; availPtr != NULL;
prevPtr = availPtr, availPtr = availPtr->nextPtr) {
@@ -1193,18 +838,13 @@ TclNRPackageObjCmd(
res = CompareVersions(avi, argv3i, NULL);
ckfree(avi);
- if (res == 0) {
+ if (res == 0){
if (objc == 4) {
ckfree(argv3i);
- Tcl_SetObjResult(interp,
- Tcl_NewStringObj(availPtr->script, -1));
+ Tcl_SetResult(interp, availPtr->script, TCL_VOLATILE);
return TCL_OK;
}
- Tcl_EventuallyFree(availPtr->script, TCL_DYNAMIC);
- if (availPtr->pkgIndex) {
- Tcl_EventuallyFree(availPtr->pkgIndex, TCL_DYNAMIC);
- availPtr->pkgIndex = NULL;
- }
+ Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC);
break;
}
}
@@ -1214,9 +854,8 @@ TclNRPackageObjCmd(
return TCL_OK;
}
if (availPtr == NULL) {
- availPtr = (PkgAvail *)ckalloc(sizeof(PkgAvail));
- availPtr->pkgIndex = NULL;
- DupBlock(availPtr->version, argv3, length + 1);
+ availPtr = (PkgAvail *) ckalloc(sizeof(PkgAvail));
+ DupBlock(availPtr->version, argv3, (unsigned) length + 1);
if (prevPtr == NULL) {
availPtr->nextPtr = pkgPtr->availPtr;
@@ -1226,37 +865,26 @@ TclNRPackageObjCmd(
prevPtr->nextPtr = availPtr;
}
}
- if (iPtr->scriptFile) {
- argv4 = TclGetStringFromObj(iPtr->scriptFile, &length);
- DupBlock(availPtr->pkgIndex, argv4, length + 1);
- }
- argv4 = TclGetStringFromObj(objv[4], &length);
- DupBlock(availPtr->script, argv4, length + 1);
+ argv4 = Tcl_GetStringFromObj(objv[4], &length);
+ DupBlock(availPtr->script, argv4, (unsigned) length + 1);
break;
}
case PKG_NAMES:
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return TCL_ERROR;
- } else {
- Tcl_Obj *resultObj;
-
- TclNewObj(resultObj);
- tablePtr = &iPtr->packageTable;
- for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
- hPtr = Tcl_NextHashEntry(&search)) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
- if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {
- Tcl_ListObjAppendElement(NULL,resultObj, Tcl_NewStringObj(
- (char *)Tcl_GetHashKey(tablePtr, hPtr), -1));
- }
+ }
+ tablePtr = &iPtr->packageTable;
+ for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
+ hPtr = Tcl_NextHashEntry(&search)) {
+ pkgPtr = Tcl_GetHashValue(hPtr);
+ if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {
+ Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr));
}
- Tcl_SetObjResult(interp, resultObj);
}
break;
case PKG_PRESENT: {
const char *name;
-
if (objc < 3) {
goto require;
}
@@ -1274,7 +902,7 @@ TclNRPackageObjCmd(
hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name);
if (hPtr != NULL) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
if (pkgPtr->version != NULL) {
goto require;
}
@@ -1309,9 +937,9 @@ TclNRPackageObjCmd(
if (objc == 3) {
hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
if (hPtr != NULL) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
if (pkgPtr->version != NULL) {
- Tcl_SetObjResult(interp, pkgPtr->version);
+ Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE);
}
}
return TCL_OK;
@@ -1326,7 +954,7 @@ TclNRPackageObjCmd(
if (objc < 3) {
requireSyntax:
Tcl_WrongNumArgs(interp, 2, objv,
- "?-exact? package ?requirement ...?");
+ "?-exact? package ?requirement...?");
return TCL_ERROR;
}
@@ -1335,6 +963,7 @@ TclNRPackageObjCmd(
argv2 = TclGetString(objv[2]);
if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
Tcl_Obj *ov;
+ int res;
if (objc != 5) {
goto requireSyntax;
@@ -1351,48 +980,20 @@ TclNRPackageObjCmd(
*/
ov = Tcl_NewStringObj(version, -1);
- Tcl_AppendStringsToObj(ov, "-", version, (void *)NULL);
+ Tcl_AppendStringsToObj(ov, "-", version, NULL);
version = NULL;
argv3 = TclGetString(objv[3]);
- Tcl_IncrRefCount(objv[3]);
-
- objvListPtr = Tcl_NewListObj(0, NULL);
- Tcl_IncrRefCount(objvListPtr);
- Tcl_ListObjAppendElement(interp, objvListPtr, ov);
- TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
-
- Tcl_NRAddCallback(interp,
- TclNRPackageObjCmdCleanup, objv[3], objvListPtr, NULL,NULL);
- Tcl_NRAddCallback(interp,
- PkgRequireCore, (void *) argv3, INT2PTR(newobjc),
- newObjvPtr, NULL);
- return TCL_OK;
- } else {
- Tcl_Obj *const *newobjv = objv + 3;
- newobjc = objc - 3;
+ Tcl_IncrRefCount(ov);
+ res = Tcl_PkgRequireProc(interp, argv3, 1, &ov, NULL);
+ TclDecrRefCount(ov);
+ return res;
+ } else {
if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {
return TCL_ERROR;
}
- objvListPtr = Tcl_NewListObj(0, NULL);
- Tcl_IncrRefCount(objvListPtr);
- Tcl_IncrRefCount(objv[2]);
- for (i = 0; i < newobjc; i++) {
- /*
- * Tcl_Obj structures may have come from another interpreter,
- * so duplicate them.
- */
- Tcl_ListObjAppendElement(interp, objvListPtr,
- Tcl_DuplicateObj(newobjv[i]));
- }
- TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
- Tcl_NRAddCallback(interp,
- TclNRPackageObjCmdCleanup, objv[2], objvListPtr, NULL,NULL);
- Tcl_NRAddCallback(interp,
- PkgRequireCore, (void *) argv2, INT2PTR(newobjc),
- newObjvPtr, NULL);
- return TCL_OK;
+ return Tcl_PkgRequireProc(interp, argv2, objc-3, objv+3, NULL);
}
break;
case PKG_UNKNOWN: {
@@ -1400,18 +1001,17 @@ TclNRPackageObjCmd(
if (objc == 2) {
if (iPtr->packageUnknown != NULL) {
- Tcl_SetObjResult(interp,
- Tcl_NewStringObj(iPtr->packageUnknown, -1));
+ Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE);
}
} else if (objc == 3) {
if (iPtr->packageUnknown != NULL) {
ckfree(iPtr->packageUnknown);
}
- argv2 = TclGetStringFromObj(objv[2], &length);
+ argv2 = Tcl_GetStringFromObj(objv[2], &length);
if (argv2[0] == 0) {
iPtr->packageUnknown = NULL;
} else {
- DupBlock(iPtr->packageUnknown, argv2, length+1);
+ DupBlock(iPtr->packageUnknown, argv2, (unsigned) length+1);
}
} else {
Tcl_WrongNumArgs(interp, 2, objv, "?command?");
@@ -1420,7 +1020,7 @@ TclNRPackageObjCmd(
break;
}
case PKG_PREFER: {
- static const char *const pkgPreferOptions[] = {
+ static const char *pkgPreferOptions[] = {
"latest", "stable", NULL
};
@@ -1481,7 +1081,7 @@ TclNRPackageObjCmd(
*/
Tcl_SetObjResult(interp,
- Tcl_NewWideIntObj(CompareVersions(iva, ivb, NULL)));
+ Tcl_NewIntObj(CompareVersions(iva, ivb, NULL)));
ckfree(iva);
ckfree(ivb);
break;
@@ -1489,28 +1089,23 @@ TclNRPackageObjCmd(
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "package");
return TCL_ERROR;
- } else {
- Tcl_Obj *resultObj;
-
- TclNewObj(resultObj);
- argv2 = TclGetString(objv[2]);
- hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
- if (hPtr != NULL) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
- for (availPtr = pkgPtr->availPtr; availPtr != NULL;
- availPtr = availPtr->nextPtr) {
- Tcl_ListObjAppendElement(NULL, resultObj,
- Tcl_NewStringObj(availPtr->version, -1));
- }
+ }
+ argv2 = TclGetString(objv[2]);
+ hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
+ if (hPtr != NULL) {
+ pkgPtr = Tcl_GetHashValue(hPtr);
+ for (availPtr = pkgPtr->availPtr; availPtr != NULL;
+ availPtr = availPtr->nextPtr) {
+ Tcl_AppendElement(interp, availPtr->version);
}
- Tcl_SetObjResult(interp, resultObj);
}
break;
case PKG_VSATISFIES: {
char *argv2i = NULL;
if (objc < 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "version ?requirement ...?");
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "version requirement requirement...");
return TCL_ERROR;
}
@@ -1533,17 +1128,6 @@ TclNRPackageObjCmd(
}
return TCL_OK;
}
-
-static int
-TclNRPackageObjCmdCleanup(
- ClientData data[],
- TCL_UNUSED(Tcl_Interp *),
- int result)
-{
- TclDecrRefCount((Tcl_Obj *) data[0]);
- TclDecrRefCount((Tcl_Obj *) data[1]);
- return result;
-}
/*
*----------------------------------------------------------------------
@@ -1575,13 +1159,13 @@ FindPackage(
hPtr = Tcl_CreateHashEntry(&iPtr->packageTable, name, &isNew);
if (isNew) {
- pkgPtr = (Package *)ckalloc(sizeof(Package));
+ pkgPtr = (Package *) ckalloc(sizeof(Package));
pkgPtr->version = NULL;
pkgPtr->availPtr = NULL;
pkgPtr->clientData = NULL;
Tcl_SetHashValue(hPtr, pkgPtr);
} else {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
}
return pkgPtr;
}
@@ -1605,7 +1189,7 @@ FindPackage(
void
TclFreePackageInfo(
- Interp *iPtr) /* Interpreter that is being deleted. */
+ Interp *iPtr) /* Interpereter that is being deleted. */
{
Package *pkgPtr;
Tcl_HashSearch search;
@@ -1614,22 +1198,18 @@ TclFreePackageInfo(
for (hPtr = Tcl_FirstHashEntry(&iPtr->packageTable, &search);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
- pkgPtr = (Package *)Tcl_GetHashValue(hPtr);
+ pkgPtr = Tcl_GetHashValue(hPtr);
if (pkgPtr->version != NULL) {
- Tcl_DecrRefCount(pkgPtr->version);
+ ckfree(pkgPtr->version);
}
while (pkgPtr->availPtr != NULL) {
availPtr = pkgPtr->availPtr;
pkgPtr->availPtr = availPtr->nextPtr;
- Tcl_EventuallyFree(availPtr->version, TCL_DYNAMIC);
- Tcl_EventuallyFree(availPtr->script, TCL_DYNAMIC);
- if (availPtr->pkgIndex) {
- Tcl_EventuallyFree(availPtr->pkgIndex, TCL_DYNAMIC);
- availPtr->pkgIndex = NULL;
- }
- ckfree(availPtr);
+ Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC);
+ Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC);
+ ckfree((char *) availPtr);
}
- ckfree(pkgPtr);
+ ckfree((char *) pkgPtr);
}
Tcl_DeleteHashTable(&iPtr->packageTable);
if (iPtr->packageUnknown != NULL) {
@@ -1671,9 +1251,9 @@ CheckVersionAndConvert(
int hasunstable = 0;
/*
* 4* assuming that each char is a separator (a,b become ' -x ').
- * 4+ to have space for an additional -2 at the end
+ * 4+ to have spce for an additional -2 at the end
*/
- char *ibuf = (char *)ckalloc(4 + 4*strlen(string));
+ char *ibuf = ckalloc(4 + 4*strlen(string));
char *ip = ibuf;
/*
@@ -1696,7 +1276,7 @@ CheckVersionAndConvert(
*ip++ = *p;
- for (prevChar = *p, p++; (*p != 0) && (*p != '+'); p++) {
+ for (prevChar = *p, p++; *p != 0; p++) {
if (!isdigit(UCHAR(*p)) && /* INTL: digit */
((*p!='.' && *p!='a' && *p!='b') ||
((hasunstable && (*p=='a' || *p=='b')) ||
@@ -1751,9 +1331,8 @@ CheckVersionAndConvert(
error:
ckfree(ibuf);
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "expected version number but got \"%s\"", string));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "VERSION", (void *)NULL);
+ Tcl_AppendResult(interp, "expected version number but got \"", string,
+ "\"", NULL);
return TCL_ERROR;
}
@@ -1782,7 +1361,7 @@ CompareVersions(
* of version numbers). */
int *isMajorPtr) /* If non-null, the word pointed to is filled
* in with a 0/1 value. 1 means that the
- * difference occurred in the first element. */
+ * difference occured in the first element. */
{
int thisIsMajor, res, flip;
char *s1, *e1, *s2, *e2, o1, o2;
@@ -2000,10 +1579,10 @@ CheckRequirement(
char *dash = NULL, *buf;
- dash = strchr(string, '+') ? NULL : (char *)strchr(string, '-');
+ dash = strchr(string, '-');
if (dash == NULL) {
/*
- * '+' found or no dash found: has to be a simple version.
+ * No dash found, has to be a simple version.
*/
return CheckVersionAndConvert(interp, string, NULL, NULL);
@@ -2014,9 +1593,8 @@ CheckRequirement(
* More dashes found after the first. This is wrong.
*/
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "expected versionMin-versionMax but got \"%s\"", string));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "VERSIONRANGE", (void *)NULL);
+ Tcl_AppendResult(interp, "expected versionMin-versionMax but got \"",
+ string, "\"", NULL);
return TCL_ERROR;
}
@@ -2067,17 +1645,19 @@ AddRequirementsToResult(
Tcl_Obj *const reqv[]) /* 0 means to use the latest version
* available. */
{
- Tcl_Obj *result = Tcl_GetObjResult(interp);
- int i, length;
+ if (reqc > 0) {
+ int i;
- for (i = 0; i < reqc; i++) {
- const char *v = TclGetStringFromObj(reqv[i], &length);
+ for (i = 0; i < reqc; i++) {
+ int length;
+ char *v = Tcl_GetStringFromObj(reqv[i], &length);
- if ((length & 0x1) && (v[length/2] == '-')
- && (strncmp(v, v+((length+1)/2), length/2) == 0)) {
- Tcl_AppendPrintfToObj(result, " exactly %s", v+((length+1)/2));
- } else {
- Tcl_AppendPrintfToObj(result, " %s", v);
+ if ((length & 0x1) && (v[length/2] == '-')
+ && (strncmp(v, v+((length+1)/2), length/2) == 0)) {
+ Tcl_AppendResult(interp, " exactly ", v+((length+1)/2), NULL);
+ } else {
+ Tcl_AppendResult(interp, " ", v, NULL);
+ }
}
}
}
@@ -2106,15 +1686,15 @@ AddRequirementsToDString(
Tcl_Obj *const reqv[]) /* 0 means to use the latest version
* available. */
{
- int i;
-
if (reqc > 0) {
+ int i;
+
for (i = 0; i < reqc; i++) {
- TclDStringAppendLiteral(dsPtr, " ");
- TclDStringAppendObj(dsPtr, reqv[i]);
+ Tcl_DStringAppend(dsPtr, " ", 1);
+ Tcl_DStringAppend(dsPtr, TclGetString(reqv[i]), -1);
}
} else {
- TclDStringAppendLiteral(dsPtr, " 0-");
+ Tcl_DStringAppend(dsPtr, " 0-", -1);
}
}
@@ -2188,7 +1768,7 @@ RequirementSatisfied(
int satisfied, res;
char *dash = NULL, *buf, *min, *max;
- dash = (char *)strchr(req, '-');
+ dash = strchr(req, '-');
if (dash == NULL) {
/*
* No dash found, is a simple version, fallback to regular check. The
@@ -2235,7 +1815,7 @@ RequirementSatisfied(
/*
* We have both min and max, and generate their internal reps. When
- * identical we compare as is, otherwise we pad with 'a0' to over the range
+ * identical we compare as is, otherwise we pad with 'a0' to ove the range
* a bit.
*/
@@ -2284,7 +1864,7 @@ Tcl_PkgInitStubsCheck(
{
const char *actualVersion = Tcl_PkgPresent(interp, "Tcl", version, 0);
- if ((exact&1) && actualVersion) {
+ if (exact && actualVersion) {
const char *p = version;
int count = 0;