tclcmdah.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,394 行 · 第 1/5 页
C
2,394 行
static intGetStatBuf(interp, objPtr, statProc, statPtr) Tcl_Interp *interp; /* Interp for error return. May be NULL. */ Tcl_Obj *objPtr; /* Path name to examine. */ Tcl_FSStatProc *statProc; /* Either stat() or lstat() depending on * desired behavior. */ Tcl_StatBuf *statPtr; /* Filled with info about file obtained by * calling (*statProc)(). */{ int status; if (Tcl_FSConvertToPathType(interp, objPtr) != TCL_OK) { return TCL_ERROR; } status = (*statProc)(objPtr, statPtr); if (status < 0) { if (interp != NULL) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(objPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } return TCL_OK;}/* *---------------------------------------------------------------------- * * 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's 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. */ Tcl_StatBuf *statPtr; /* Pointer to buffer containing * stat data to store in varName. */{ Tcl_Obj *var = Tcl_NewStringObj(varName, -1); Tcl_Obj *field = Tcl_NewObj(); Tcl_Obj *value; register unsigned short mode; /* * Assume Tcl_ObjSetVar2() does not keep a copy of the field name! */#define STORE_ARY(fieldName, object) \ Tcl_SetStringObj(field, (fieldName), -1); \ value = (object); \ if (Tcl_ObjSetVar2(interp,var,field,value,TCL_LEAVE_ERR_MSG) == NULL) { \ Tcl_DecrRefCount(var); \ Tcl_DecrRefCount(field); \ Tcl_DecrRefCount(value); \ return TCL_ERROR; \ } Tcl_IncrRefCount(var); Tcl_IncrRefCount(field); STORE_ARY("dev", Tcl_NewLongObj((long)statPtr->st_dev)); /* * Watch out porters; the inode is meant to be an *unsigned* value, * so the cast might fail when there isn't a real arithmentic 'long * long' type... */ STORE_ARY("ino", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_ino)); STORE_ARY("nlink", Tcl_NewLongObj((long)statPtr->st_nlink)); STORE_ARY("uid", Tcl_NewLongObj((long)statPtr->st_uid)); STORE_ARY("gid", Tcl_NewLongObj((long)statPtr->st_gid)); STORE_ARY("size", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_size));#ifdef HAVE_ST_BLOCKS STORE_ARY("blocks",Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_blocks));#endif STORE_ARY("atime", Tcl_NewLongObj((long)statPtr->st_atime)); STORE_ARY("mtime", Tcl_NewLongObj((long)statPtr->st_mtime)); STORE_ARY("ctime", Tcl_NewLongObj((long)statPtr->st_ctime)); mode = (unsigned short) statPtr->st_mode; STORE_ARY("mode", Tcl_NewIntObj(mode)); STORE_ARY("type", Tcl_NewStringObj(GetTypeFromMode(mode), -1));#undef STORE_ARY Tcl_DecrRefCount(var); Tcl_DecrRefCount(field); 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_ForObjCmd -- * * 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_ForObjCmd(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, value; if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "start test next command"); return TCL_ERROR; } result = Tcl_EvalObjEx(interp, objv[1], 0); if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)"); } return result; } while (1) { /* * We need to reset the result before passing it off to * Tcl_ExprBooleanObj. Otherwise, any error message will be appended * to the result of the last evaluation. */ Tcl_ResetResult(interp); result = Tcl_ExprBooleanObj(interp, objv[2], &value); if (result != TCL_OK) { return result; } if (!value) { break; } result = Tcl_EvalObjEx(interp, objv[4], 0); if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"for\" body line %d)",interp->errorLine); Tcl_AddErrorInfo(interp, msg); } break; } result = Tcl_EvalObjEx(interp, objv[3], 0); 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]; int varcListArray[STATIC_LIST_SIZE]; Tcl_Obj **varvListArray[STATIC_LIST_SIZE]; int argcListArray[STATIC_LIST_SIZE]; Tcl_Obj **argvListArray[STATIC_LIST_SIZE]; int *index = indexArray; /* Array of value list indices */ int *varcList = varcListArray; /* # loop variables per list */ Tcl_Obj ***varvList = varvListArray; /* Array of var name lists */ int *argcList = argcListArray; /* Array of value list sizes */ Tcl_Obj ***argvList = argvListArray; /* Array of value lists */ 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; varvList[i] = (Tcl_Obj **) NULL; argcList[i] = 0; argvList[i] = (Tcl_Obj **) NULL; } /* * Break up the value lists and variable lists into elements */ maxj = 0; for (i = 0; i < numLists; i++) { result = Tcl_ListObjGetElements(interp, argObjv[1+i*2], &varcList[i], &varvList[i]); if (result != TCL_OK) { goto done; } if (varcList[i] < 1) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "foreach varlist is empty", -1); result = TCL_ERROR; goto done; } result = Tcl_ListObjGetElements(interp, argObjv[2+i*2], &argcList[i], &argvList[i]); if (result != TCL_OK) { goto done; } j = argcList[i] / varcList[i]; if ((argcList[i] % varcList[i]) != 0) { j++; } if (j > maxj) { maxj = j; } } /* * Iterate maxj times through the lists in parallel * If some value lists run out of values, set loop vars to "" */ bodyPtr = argObjv[objc-1]; for (j = 0; j < maxj; j++) { for (i = 0; i < numLists; i++) { /* * Refetch the list members; we assume that the sizes are * the same, but the array of elements might be different * if the internal rep of the objects has been lost and * recreated (it is too difficult to accurately tell when * this happens, which can lead to some wierd crashes, * like Bug #494348...) */ result = Tcl_ListObjGetElements(interp, argObjv[1+i*2], &varcList[i], &varvList[i]); if (result != TCL_OK) { panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i); } result = Tcl_ListObjGetElements(interp, argObjv[2+i*2], &argcList[i], &argvList[i]); if (result != TCL_OK) { panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i); } for (v = 0; v < varcList[i]; v++) { int k = index[i]++; Tcl_Obj *valuePtr, *varValuePtr; int isEmptyObj = 0; if (k < argcList[i]) { valuePtr = argvList[i][k]; } else { valuePtr = Tcl_NewObj(); /* empty string */ isEmptyObj = 1; } varValuePtr = Tcl_ObjSetVar2(interp, varvList[i][v], NULL, valuePtr, 0); if (varValuePtr == NULL) { if (isEmptyObj) { Tcl_DecrRefCount(valuePtr); } Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't set loop variable: \"", Tcl_GetString(varvList[i][v]), "\"", (char *) NULL); result = TCL_ERROR; goto done; } } } result = Tcl_EvalObjEx(interp, bodyPtr, 0); if (result != TCL_OK) { if (result == TCL_CONTINUE) { result = TCL_OK; } else if (result == TCL_BREAK) { result = TCL_OK; break; } else if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"foreach\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); break; } else { break; } } } if (result == TCL_OK) { Tcl_ResetResult(interp); } done: if (numLists > STATIC_LIST_SIZE) { ckfree((char *) index); ckfree((char *) varcList); ckfree((char *) argcList); ckfree((char *) varvList); ckfree((char *) argvList); } if (argObjv != argObjStorage) { ckfree((char *) argObjv); } return result;#undef STATIC_LIST_SIZE#undef NUM_ARGS}/* *---------------------------------------------------------------------- * * Tcl_FormatObjCmd -- * * This procedure is invoked to process the "format" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */intTcl_FormatObjCmd(dummy, interp, objc, objv)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?