📄 tclcmdah.c
字号:
goto checkAccess; case FILE_EXISTS: if (objc != 3) { errorString = "exists name"; goto not3Args; } mode = F_OK; goto checkAccess; } /* * Lastly, check stuff that requires the file to be stat-ed. */ if (fileName == NULL) { result = TCL_ERROR; goto done; } switch (index) { case FILE_ATIME: if (objc != 3) { errorString = "atime name"; goto not3Args; } if (TclStat(fileName, &statBuf) == -1) { goto badStat; } Tcl_SetLongObj(resultPtr, (long) statBuf.st_atime); goto done; case FILE_ISDIRECTORY: if (objc != 3) { errorString = "isdirectory name"; goto not3Args; } statOp = 2; break; case FILE_ISFILE: if (objc != 3) { errorString = "isfile name"; goto not3Args; } statOp = 1; break; case FILE_LSTAT: if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "lstat name varName"); result = TCL_ERROR; goto done; } if (lstat(fileName, &statBuf) == -1) { Tcl_AppendStringsToObj(resultPtr, "couldn't lstat \"", Tcl_GetStringFromObj(objv[2], &length), "\": ", Tcl_PosixError(interp), (char *) NULL); result = TCL_ERROR; goto done; } result = StoreStatData(interp, Tcl_GetStringFromObj(objv[3], &length), &statBuf); goto done; case FILE_MTIME: if (objc != 3) { errorString = "mtime name"; goto not3Args; } if (TclStat(fileName, &statBuf) == -1) { goto badStat; } Tcl_SetLongObj(resultPtr, (long) statBuf.st_mtime); goto done; case FILE_OWNED: if (objc != 3) { errorString = "owned name"; goto not3Args; } statOp = 0; break; case FILE_READLINK: { char linkValue[MAXPATHLEN + 1]; int linkLength; if (objc != 3) { errorString = "readlink name"; goto not3Args; } /* * If S_IFLNK isn't defined it means that the machine doesn't * support symbolic links, so the file can't possibly be a * symbolic link. Generate an EINVAL error, which is what * happens on machines that do support symbolic links when * you invoke readlink on a file that isn't a symbolic link. */#ifndef S_IFLNK linkLength = -1; errno = EINVAL;#else linkLength = readlink(fileName, linkValue, sizeof(linkValue) - 1);#endif /* S_IFLNK */ if (linkLength == -1) { Tcl_AppendStringsToObj(resultPtr, "couldn't readlink \"", Tcl_GetStringFromObj(objv[2], &length), "\": ", Tcl_PosixError(interp), (char *) NULL); result = TCL_ERROR; goto done; } linkValue[linkLength] = 0; Tcl_SetStringObj(resultPtr, linkValue, linkLength); goto done; } case FILE_SIZE: if (objc != 3) { errorString = "size name"; goto not3Args; } if (TclStat(fileName, &statBuf) == -1) { goto badStat; } Tcl_SetLongObj(resultPtr, (long) statBuf.st_size); goto done; case FILE_STAT: if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "stat name varName"); result = TCL_ERROR; goto done; } if (TclStat(fileName, &statBuf) == -1) {badStat: Tcl_AppendStringsToObj(resultPtr, "couldn't stat \"", Tcl_GetStringFromObj(objv[2], &length), "\": ", Tcl_PosixError(interp), (char *) NULL); result = TCL_ERROR; goto done; } result = StoreStatData(interp, Tcl_GetStringFromObj(objv[3], &length), &statBuf); goto done; case FILE_TYPE: if (objc != 3) { errorString = "type name"; goto not3Args; } if (lstat(fileName, &statBuf) == -1) { goto badStat; } errorString = GetTypeFromMode((int) statBuf.st_mode); Tcl_SetStringObj(resultPtr, errorString, -1); goto done; } if (TclStat(fileName, &statBuf) == -1) { Tcl_SetBooleanObj(resultPtr, 0); goto done; } switch (statOp) { case 0: /* * For Windows and Macintosh, there are no user ids * associated with a file, so we always return 1. */#if (defined(__WIN32__) || defined(MAC_TCL)) mode = 1;#else mode = (geteuid() == statBuf.st_uid);#endif break; case 1: mode = S_ISREG(statBuf.st_mode); break; case 2: mode = S_ISDIR(statBuf.st_mode); break; } Tcl_SetBooleanObj(resultPtr, mode);done: Tcl_DStringFree(&buffer); return result;not3Args: Tcl_WrongNumArgs(interp, 1, objv, errorString); result = TCL_ERROR; goto done;}/* *---------------------------------------------------------------------- * * StoreStatData -- * * This is a utility procedure that breaks out the fields of a * "stat" structure and stores them in textual form into the * elements of an associative array. * * Results: * Returns a standard Tcl return value. If an error occurs then * a message is left in interp->result. * * Side effects: * Elements of the associative array given by "varName" are modified. * *---------------------------------------------------------------------- */static intStoreStatData(interp, varName, statPtr) Tcl_Interp *interp; /* Interpreter for error reports. */ char *varName; /* Name of associative array variable * in which to store stat results. */ struct stat *statPtr; /* Pointer to buffer containing * stat data to store in varName. */{ char string[30]; sprintf(string, "%ld", (long) statPtr->st_dev); if (Tcl_SetVar2(interp, varName, "dev", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_ino); if (Tcl_SetVar2(interp, varName, "ino", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_mode); if (Tcl_SetVar2(interp, varName, "mode", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_nlink); if (Tcl_SetVar2(interp, varName, "nlink", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_uid); if (Tcl_SetVar2(interp, varName, "uid", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_gid); if (Tcl_SetVar2(interp, varName, "gid", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%lu", (unsigned long) statPtr->st_size); if (Tcl_SetVar2(interp, varName, "size", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_atime); if (Tcl_SetVar2(interp, varName, "atime", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_mtime); if (Tcl_SetVar2(interp, varName, "mtime", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } sprintf(string, "%ld", (long) statPtr->st_ctime); if (Tcl_SetVar2(interp, varName, "ctime", string, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2(interp, varName, "type", GetTypeFromMode((int) statPtr->st_mode), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } return TCL_OK;}/* *---------------------------------------------------------------------- * * GetTypeFromMode -- * * Given a mode word, returns a string identifying the type of a * file. * * Results: * A static text string giving the file type from mode. * * Side effects: * None. * *---------------------------------------------------------------------- */static char *GetTypeFromMode(mode) int mode;{ if (S_ISREG(mode)) { return "file"; } else if (S_ISDIR(mode)) { return "directory"; } else if (S_ISCHR(mode)) { return "characterSpecial"; } else if (S_ISBLK(mode)) { return "blockSpecial"; } else if (S_ISFIFO(mode)) { return "fifo";#ifdef S_ISLNK } else if (S_ISLNK(mode)) { return "link";#endif#ifdef S_ISSOCK } else if (S_ISSOCK(mode)) { return "socket";#endif } return "unknown";}/* *---------------------------------------------------------------------- * * Tcl_ForCmd -- * * This procedure is invoked to process the "for" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "for" or the name * to which "for" was renamed: e.g., * "set z for; $z {set i 0} {$i<100} {incr i} {puts $i}" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */intTcl_ForCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ int result, value; if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " start test next command\"", (char *) NULL); return TCL_ERROR; } result = Tcl_Eval(interp, argv[1]); if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)"); } return result; } while (1) { result = Tcl_ExprBoolean(interp, argv[2], &value); if (result != TCL_OK) { return result; } if (!value) { break; } result = Tcl_Eval(interp, argv[4]); if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[60]; sprintf(msg, "\n (\"for\" body line %d)",interp->errorLine); Tcl_AddErrorInfo(interp, msg); } break; } result = Tcl_Eval(interp, argv[3]); if (result == TCL_BREAK) { break; } else if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" loop-end command)"); } return result; } } if (result == TCL_BREAK) { result = TCL_OK; } if (result == TCL_OK) { Tcl_ResetResult(interp); } return result;}/* *---------------------------------------------------------------------- * * Tcl_ForeachObjCmd -- * * This object-based procedure is invoked to process the "foreach" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */intTcl_ForeachObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */{ int result = TCL_OK; int i; /* i selects a value list */ int j, maxj; /* Number of loop iterations */ int v; /* v selects a loop variable */ int numLists; /* Count of value lists */ Tcl_Obj *bodyPtr; /* * We copy the argument object pointers into a local array to avoid * the problem that "objv" might become invalid. It is a pointer into * the evaluation stack and that stack might be grown and reallocated * if the loop body requires a large amount of stack space. */ #define NUM_ARGS 9 Tcl_Obj *(argObjStorage[NUM_ARGS]); Tcl_Obj **argObjv = argObjStorage; #define STATIC_LIST_SIZE 4 int indexArray[STATIC_LIST_SIZE]; /* Array of value list indices */ int varcListArray[STATIC_LIST_SIZE]; /* # loop variables per list */ Tcl_Obj **varvListArray[STATIC_LIST_SIZE]; /* Array of var name lists */ int argcListArray[STATIC_LIST_SIZE]; /* Array of value list sizes */ Tcl_Obj **argvListArray[STATIC_LIST_SIZE]; /* Array of value lists */ int *index = indexArray; int *varcList = varcListArray; Tcl_Obj ***varvList = varvListArray; int *argcList = argcListArray; Tcl_Obj ***argvList = argvListArray; if (objc < 4 || (objc%2 != 0)) { Tcl_WrongNumArgs(interp, 1, objv, "varList list ?varList list ...? command"); return TCL_ERROR; } /* * Create the object argument array "argObjv". Make sure argObjv is * large enough to hold the objc arguments. */ if (objc > NUM_ARGS) { argObjv = (Tcl_Obj **) ckalloc(objc * sizeof(Tcl_Obj *)); } for (i = 0; i < objc; i++) { argObjv[i] = objv[i]; } /* * Manage numList parallel value lists. * argvList[i] is a value list counted by argcList[i] * varvList[i] is the list of variables associated with the value list * varcList[i] is the number of variables associated with the value list * index[i] is the current pointer into the value list argvList[i] */ numLists = (objc-2)/2; if (numLists > STATIC_LIST_SIZE) { index = (int *) ckalloc(numLists * sizeof(int)); varcList = (int *) ckalloc(numLists * sizeof(int)); varvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **)); argcList = (int *) ckalloc(numLists * sizeof(int)); argvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **)); } for (i = 0; i < numLists; i++) { index[i] = 0; varcList[i] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -