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 + -
显示快捷键?