📄 tclpkg.c
字号:
if (availPtr == NULL) { availPtr = (PkgAvail *) ckalloc(sizeof(PkgAvail)); availPtr->version = ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(availPtr->version, argv[3]); if (prevPtr == NULL) { availPtr->nextPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr; } else { availPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = availPtr; } } availPtr->script = ckalloc((unsigned) (strlen(argv[4]) + 1)); strcpy(availPtr->script, argv[4]); } else if ((c == 'n') && (strncmp(argv[1], "names", length) == 0)) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " names\"", (char *) NULL); return TCL_ERROR; } 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_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr)); } } } else if ((c == 'p') && (strncmp(argv[1], "provide", length) == 0)) { if ((argc != 3) && (argc != 4)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " provide package ?version?\"", (char *) NULL); return TCL_ERROR; } if (argc == 3) { hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv[2]); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE); } } return TCL_OK; } if (CheckVersion(interp, argv[3]) != TCL_OK) { return TCL_ERROR; } return Tcl_PkgProvide(interp, argv[2], argv[3]); } else if ((c == 'r') && (strncmp(argv[1], "require", length) == 0)) { if (argc < 3) { requireSyntax: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " require ?-exact? package ?version?\"", (char *) NULL); return TCL_ERROR; } if ((argv[2][0] == '-') && (strcmp(argv[2], "-exact") == 0)) { exact = 1; } else { exact = 0; } version = NULL; if (argc == (4+exact)) { version = argv[3+exact]; if (CheckVersion(interp, version) != TCL_OK) { return TCL_ERROR; } } else if ((argc != 3) || exact) { goto requireSyntax; } version = Tcl_PkgRequire(interp, argv[2+exact], version, exact); if (version == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, version, TCL_VOLATILE); } else if ((c == 'u') && (strncmp(argv[1], "unknown", length) == 0)) { if (argc == 2) { if (iPtr->packageUnknown != NULL) { Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE); } } else if (argc == 3) { if (iPtr->packageUnknown != NULL) { ckfree(iPtr->packageUnknown); } if (argv[2][0] == 0) { iPtr->packageUnknown = NULL; } else { iPtr->packageUnknown = (char *) ckalloc((unsigned) (strlen(argv[2]) + 1)); strcpy(iPtr->packageUnknown, argv[2]); } } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " unknown ?command?\"", (char *) NULL); return TCL_ERROR; } } else if ((c == 'v') && (strncmp(argv[1], "vcompare", length) == 0) && (length >= 2)) { if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " vcompare version1 version2\"", (char *) NULL); return TCL_ERROR; } if ((CheckVersion(interp, argv[2]) != TCL_OK) || (CheckVersion(interp, argv[3]) != TCL_OK)) { return TCL_ERROR; } TclFormatInt(buf, ComparePkgVersions(argv[2], argv[3], (int *) NULL)); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'v') && (strncmp(argv[1], "versions", length) == 0) && (length >= 2)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " versions package\"", (char *) NULL); return TCL_ERROR; } hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv[2]); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); for (availPtr = pkgPtr->availPtr; availPtr != NULL; availPtr = availPtr->nextPtr) { Tcl_AppendElement(interp, availPtr->version); } } } else if ((c == 'v') && (strncmp(argv[1], "vsatisfies", length) == 0) && (length >= 2)) { if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " vsatisfies version1 version2\"", (char *) NULL); return TCL_ERROR; } if ((CheckVersion(interp, argv[2]) != TCL_OK) || (CheckVersion(interp, argv[3]) != TCL_OK)) { return TCL_ERROR; } ComparePkgVersions(argv[2], argv[3], &satisfies); TclFormatInt(buf, satisfies); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": should be forget, ifneeded, names, ", "provide, require, unknown, vcompare, ", "versions, or vsatisfies", (char *) NULL); return TCL_ERROR; } return TCL_OK;}/* *---------------------------------------------------------------------- * * FindPackage -- * * This procedure finds the Package record for a particular package * in a particular interpreter, creating a record if one doesn't * already exist. * * Results: * The return value is a pointer to the Package record for the * package. * * Side effects: * A new Package record may be created. * *---------------------------------------------------------------------- */static Package *FindPackage(interp, name) Tcl_Interp *interp; /* Interpreter to use for package lookup. */ char *name; /* Name of package to fine. */{ Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; int new; Package *pkgPtr; hPtr = Tcl_CreateHashEntry(&iPtr->packageTable, name, &new); if (new) { pkgPtr = (Package *) ckalloc(sizeof(Package)); pkgPtr->version = NULL; pkgPtr->availPtr = NULL; Tcl_SetHashValue(hPtr, pkgPtr); } else { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); } return pkgPtr;}/* *---------------------------------------------------------------------- * * TclFreePackageInfo -- * * This procedure is called during interpreter deletion to * free all of the package-related information for the * interpreter. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */voidTclFreePackageInfo(iPtr) Interp *iPtr; /* Interpereter that is being deleted. */{ Package *pkgPtr; Tcl_HashSearch search; Tcl_HashEntry *hPtr; PkgAvail *availPtr; for (hPtr = Tcl_FirstHashEntry(&iPtr->packageTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { ckfree(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr->nextPtr; ckfree(availPtr->version); Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); ckfree((char *) availPtr); } ckfree((char *) pkgPtr); } Tcl_DeleteHashTable(&iPtr->packageTable); if (iPtr->packageUnknown != NULL) { ckfree(iPtr->packageUnknown); }}/* *---------------------------------------------------------------------- * * CheckVersion -- * * This procedure checks to see whether a version number has * valid syntax. * * Results: * If string is a properly formed version number the TCL_OK * is returned. Otherwise TCL_ERROR is returned and an error * message is left in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */static intCheckVersion(interp, string) Tcl_Interp *interp; /* Used for error reporting. */ char *string; /* Supposedly a version number, which is * groups of decimal digits separated * by dots. */{ char *p = string; if (!isdigit(UCHAR(*p))) { goto error; } for (p++; *p != 0; p++) { if (!isdigit(UCHAR(*p)) && (*p != '.')) { goto error; } } if (p[-1] != '.') { return TCL_OK; } error: Tcl_AppendResult(interp, "expected version number but got \"", string, "\"", (char *) NULL); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * ComparePkgVersions -- * * This procedure compares two version numbers. * * Results: * The return value is -1 if v1 is less than v2, 0 if the two * version numbers are the same, and 1 if v1 is greater than v2. * If *satPtr is non-NULL, the word it points to is filled in * with 1 if v2 >= v1 and both numbers have the same major number * or 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */static intComparePkgVersions(v1, v2, satPtr) char *v1, *v2; /* Versions strings, of form 2.1.3 (any * number of version numbers). */ int *satPtr; /* If non-null, the word pointed to is * filled in with a 0/1 value. 1 means * v1 "satisfies" v2: v1 is greater than * or equal to v2 and both version numbers * have the same major number. */{ int thisIsMajor, n1, n2; /* * Each iteration of the following loop processes one number from * each string, terminated by a ".". If those numbers don't match * then the comparison is over; otherwise, we loop back for the * next number. */ thisIsMajor = 1; while (1) { /* * Parse one decimal number from the front of each string. */ n1 = n2 = 0; while ((*v1 != 0) && (*v1 != '.')) { n1 = 10*n1 + (*v1 - '0'); v1++; } while ((*v2 != 0) && (*v2 != '.')) { n2 = 10*n2 + (*v2 - '0'); v2++; } /* * Compare and go on to the next version number if the * current numbers match. */ if (n1 != n2) { break; } if (*v1 != 0) { v1++; } else if (*v2 == 0) { break; } if (*v2 != 0) { v2++; } thisIsMajor = 0; } if (satPtr != NULL) { *satPtr = (n1 == n2) || ((n1 > n2) && !thisIsMajor); } if (n1 > n2) { return 1; } else if (n1 == n2) { return 0; } else { return -1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -