tclcmdmz.c

来自「tcl是工具命令语言」· C语言 代码 · 共 2,428 行 · 第 1/5 页

C
2,428
字号
	eflags |= TCL_REG_NOTBOL;	if (offset >= stringLength) {	    break;	}    }    /*     * Set the interpreter's object result to an integer object     * with value 1 if -all wasn't specified, otherwise it's all-1     * (the number of times through the while - 1).     * Get the resultPtr again as the Tcl_ObjSetVar2 above may have     * cause the result to change. [Patch #558324] (watson).     */    if (!doinline) {	resultPtr = Tcl_GetObjResult(interp);	Tcl_SetIntObj(resultPtr, (all ? all-1 : 1));    }    return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_RegsubObjCmd -- * *	This procedure is invoked to process the "regsub" 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_RegsubObjCmd(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 idx, result, cflags, all, wlen, wsublen, numMatches, offset;    int start, end, subStart, subEnd, match;    Tcl_RegExp regExpr;    Tcl_RegExpInfo info;    Tcl_Obj *resultPtr, *subPtr, *objPtr;    Tcl_UniChar ch, *wsrc, *wfirstChar, *wstring, *wsubspec, *wend;    static CONST char *options[] = {	"-all",		"-nocase",	"-expanded",	"-line",	"-linestop",	"-lineanchor",	"-start",	"--",		NULL    };    enum options {	REGSUB_ALL,	REGSUB_NOCASE,	REGSUB_EXPANDED,	REGSUB_LINE,	REGSUB_LINESTOP, REGSUB_LINEANCHOR,	REGSUB_START,	REGSUB_LAST    };    cflags = TCL_REG_ADVANCED;    all = 0;    offset = 0;    resultPtr = NULL;    for (idx = 1; idx < objc; idx++) {	char *name;	int index;		name = Tcl_GetString(objv[idx]);	if (name[0] != '-') {	    break;	}	if (Tcl_GetIndexFromObj(interp, objv[idx], options, "switch",		TCL_EXACT, &index) != TCL_OK) {	    return TCL_ERROR;	}	switch ((enum options) index) {	    case REGSUB_ALL: {		all = 1;		break;	    }	    case REGSUB_NOCASE: {		cflags |= TCL_REG_NOCASE;		break;	    }	    case REGSUB_EXPANDED: {		cflags |= TCL_REG_EXPANDED;		break;	    }	    case REGSUB_LINE: {		cflags |= TCL_REG_NEWLINE;		break;	    }	    case REGSUB_LINESTOP: {		cflags |= TCL_REG_NLSTOP;		break;	    }	    case REGSUB_LINEANCHOR: {		cflags |= TCL_REG_NLANCH;		break;	    }	    case REGSUB_START: {		if (++idx >= objc) {		    goto endOfForLoop;		}		if (Tcl_GetIntFromObj(interp, objv[idx], &offset) != TCL_OK) {		    return TCL_ERROR;		}		if (offset < 0) {		    offset = 0;		}		break;	    }	    case REGSUB_LAST: {		idx++;		goto endOfForLoop;	    }	}    }    endOfForLoop:    if (objc-idx < 3 || objc-idx > 4) {	Tcl_WrongNumArgs(interp, 1, objv,		"?switches? exp string subSpec ?varName?");	return TCL_ERROR;    }    objc -= idx;    objv += idx;    if (all && (offset == 0)	    && (strpbrk(Tcl_GetString(objv[2]), "&\\") == NULL)	    && (strpbrk(Tcl_GetString(objv[0]), "*+?{}()[].\\|^$") == NULL)) {	/*	 * This is a simple one pair string map situation.  We make use of	 * a slightly modified version of the one pair STR_MAP code.	 */	int slen, nocase;	int (*strCmpFn)_ANSI_ARGS_((CONST Tcl_UniChar *, CONST Tcl_UniChar *,		unsigned long));	Tcl_UniChar *p, wsrclc;	numMatches = 0;	nocase     = (cflags & TCL_REG_NOCASE);	strCmpFn   = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp;	wsrc     = Tcl_GetUnicodeFromObj(objv[0], &slen);	wstring  = Tcl_GetUnicodeFromObj(objv[1], &wlen);	wsubspec = Tcl_GetUnicodeFromObj(objv[2], &wsublen);	wend     = wstring + wlen - (slen ? slen - 1 : 0);	result   = TCL_OK;	if (slen == 0) {	    /*	     * regsub behavior for "" matches between each character.	     * 'string map' skips the "" case.	     */	    if (wstring < wend) {		resultPtr = Tcl_NewUnicodeObj(wstring, 0);		Tcl_IncrRefCount(resultPtr);		for (; wstring < wend; wstring++) {		    Tcl_AppendUnicodeToObj(resultPtr, wsubspec, wsublen);		    Tcl_AppendUnicodeToObj(resultPtr, wstring, 1);		    numMatches++;		}		wlen = 0;	    }	} else {	    wsrclc = Tcl_UniCharToLower(*wsrc);	    for (p = wfirstChar = wstring; wstring < wend; wstring++) {		if (((*wstring == *wsrc) ||			(nocase && (Tcl_UniCharToLower(*wstring) ==				wsrclc))) &&			((slen == 1) || (strCmpFn(wstring, wsrc,				(unsigned long) slen) == 0))) {		    if (numMatches == 0) {			resultPtr = Tcl_NewUnicodeObj(wstring, 0);			Tcl_IncrRefCount(resultPtr);		    }		    if (p != wstring) {			Tcl_AppendUnicodeToObj(resultPtr, p, wstring - p);			p = wstring + slen;		    } else {			p += slen;		    }		    wstring = p - 1;		    Tcl_AppendUnicodeToObj(resultPtr, wsubspec, wsublen);		    numMatches++;		}	    }	    if (numMatches) {		wlen    = wfirstChar + wlen - p;		wstring = p;	    }	}	objPtr = NULL;	subPtr = NULL;	goto regsubDone;    }    regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags);    if (regExpr == NULL) {	return TCL_ERROR;    }    /*     * Make sure to avoid problems where the objects are shared.  This     * can cause RegExpObj <> UnicodeObj shimmering that causes data     * corruption.  [Bug #461322]     */    if (objv[1] == objv[0]) {	objPtr = Tcl_DuplicateObj(objv[1]);    } else {	objPtr = objv[1];    }    wstring = Tcl_GetUnicodeFromObj(objPtr, &wlen);    if (objv[2] == objv[0]) {	subPtr = Tcl_DuplicateObj(objv[2]);    } else {	subPtr = objv[2];    }    wsubspec = Tcl_GetUnicodeFromObj(subPtr, &wsublen);    result = TCL_OK;    /*     * The following loop is to handle multiple matches within the     * same source string;  each iteration handles one match and its     * corresponding substitution.  If "-all" hasn't been specified     * then the loop body only gets executed once.     */    numMatches = 0;    for ( ; offset < wlen; ) {	/*	 * The flags argument is set if string is part of a larger string,	 * so that "^" won't match.	 */	match = Tcl_RegExpExecObj(interp, regExpr, objPtr, offset,		10 /* matches */, ((offset > 0) ? TCL_REG_NOTBOL : 0));	if (match < 0) {	    result = TCL_ERROR;	    goto done;	}	if (match == 0) {	    break;	}	if (numMatches == 0) {	    resultPtr = Tcl_NewUnicodeObj(wstring, 0);	    Tcl_IncrRefCount(resultPtr);	    if (offset > 0) {		/*		 * Copy the initial portion of the string in if an offset		 * was specified.		 */		Tcl_AppendUnicodeToObj(resultPtr, wstring, offset);	    }	}	numMatches++;	/*	 * Copy the portion of the source string before the match to the	 * result variable.	 */	Tcl_RegExpGetInfo(regExpr, &info);	start = info.matches[0].start;	end = info.matches[0].end;	Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, start);	/*	 * Append the subSpec argument to the variable, making appropriate	 * substitutions.  This code is a bit hairy because of the backslash	 * conventions and because the code saves up ranges of characters in	 * subSpec to reduce the number of calls to Tcl_SetVar.	 */	wsrc = wfirstChar = wsubspec;	wend = wsubspec + wsublen;	for (ch = *wsrc; wsrc != wend; wsrc++, ch = *wsrc) {	    if (ch == '&') {		idx = 0;	    } else if (ch == '\\') {		ch = wsrc[1];		if ((ch >= '0') && (ch <= '9')) {		    idx = ch - '0';		} else if ((ch == '\\') || (ch == '&')) {		    *wsrc = ch;		    Tcl_AppendUnicodeToObj(resultPtr, wfirstChar,			    wsrc - wfirstChar + 1);		    *wsrc = '\\';		    wfirstChar = wsrc + 2;		    wsrc++;		    continue;		} else {		    continue;		}	    } else {		continue;	    }	    if (wfirstChar != wsrc) {		Tcl_AppendUnicodeToObj(resultPtr, wfirstChar,			wsrc - wfirstChar);	    }	    if (idx <= info.nsubs) {		subStart = info.matches[idx].start;		subEnd = info.matches[idx].end;		if ((subStart >= 0) && (subEnd >= 0)) {		    Tcl_AppendUnicodeToObj(resultPtr,			    wstring + offset + subStart, subEnd - subStart);		}	    }	    if (*wsrc == '\\') {		wsrc++;	    }	    wfirstChar = wsrc + 1;	}	if (wfirstChar != wsrc) {	    Tcl_AppendUnicodeToObj(resultPtr, wfirstChar, wsrc - wfirstChar);	}	if (end == 0) {	    /*	     * Always consume at least one character of the input string	     * in order to prevent infinite loops.	     */	    Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1);	    offset++;	} else {	    offset += end;	}	if (!all) {	    break;	}    }    /*     * Copy the portion of the source string after the last match to the     * result variable.     */    regsubDone:    if (numMatches == 0) {	/*	 * On zero matches, just ignore the offset, since it shouldn't	 * matter to us in this case, and the user may have skewed it.	 */	resultPtr = objv[1];	Tcl_IncrRefCount(resultPtr);    } else if (offset < wlen) {	Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, wlen - offset);    }    if (objc == 4) {	if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) {	    Tcl_AppendResult(interp, "couldn't set variable \"",		    Tcl_GetString(objv[3]), "\"", (char *) NULL);	    result = TCL_ERROR;	} else {	    /*	     * Set the interpreter's object result to an integer object	     * holding the number of matches. 	     */	    Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches);	}    } else {	/*	 * No varname supplied, so just return the modified string.	 */	Tcl_SetObjResult(interp, resultPtr);    }    done:    if (objPtr && (objv[1] == objv[0])) { Tcl_DecrRefCount(objPtr); }    if (subPtr && (objv[2] == objv[0])) { Tcl_DecrRefCount(subPtr); }    if (resultPtr) { Tcl_DecrRefCount(resultPtr); }    return result;}/* *---------------------------------------------------------------------- * * Tcl_RenameObjCmd -- * *	This procedure is invoked to process the "rename" 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_RenameObjCmd(dummy, interp, objc, objv)    ClientData dummy;		/* Arbitrary value passed to the command. */    Tcl_Interp *interp;		/* Current interpreter. */    int objc;			/* Number of arguments. */    Tcl_Obj *CONST objv[];	/* Argument objects. */{    char *oldName, *newName;        if (objc != 3) {	Tcl_WrongNumArgs(interp, 1, objv, "oldName newName");	return TCL_ERROR;    }    oldName = Tcl_GetString(objv[1]);    newName = Tcl_GetString(objv[2]);    return TclRenameCommand(interp, oldName, newName);}/* *---------------------------------------------------------------------- * * Tcl_ReturnObjCmd -- * *	This object-based procedure is invoked to process the "return" 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_ReturnObjCmd(dummy, interp, objc, objv)    ClientData dummy;		/* Not used. */    Tcl_Interp *interp;		/* Current interpreter. */    int objc;			/* Number of arguments. */    Tcl_Obj *CONST objv[];	/* Argument objects. */{    Interp *iPtr = (Interp *) interp;    int optionLen, argLen, code, result;    if (iPtr->errorInfo != NULL) {	ckfree(iPtr->errorInfo);	iPtr->errorInfo = NULL;    }    if (iPtr->errorCode != NULL) {	ckfree(iPtr->errorCode);	iPtr->errorCode = NULL;    }    code = TCL_OK;        for (objv++, objc--;  objc > 1;  objv += 2, objc -= 2) {	char *option = Tcl_GetStringFromObj(objv[0], &optionLen);	char *arg = Tcl_GetStringFromObj(objv[1], &argLen);    		if (strcmp(option, "-code") == 0) {	    register int c = arg[0];	    if ((c == 'o') && (strcmp(arg, "ok") == 0)) {		code = TCL_OK;	    } else if ((c == 'e') && (strcmp(arg, "error") == 0)) {		code = TCL_ERROR;	    } else if ((c == 'r') && (strcmp(arg, "return") == 0)) {		code = TCL_RETURN;	    } else if ((c == 'b') && (strcmp(arg, "break") == 0)) {		code = TCL_BREAK;	    } else if ((c == 'c') && (strcmp(arg, "continue") == 0)) {		code = TCL_CONTINUE;	    } else {		result = Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[1],		        &code);		if (result != TCL_OK) {		    Tcl_ResetResult(interp);		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),			    "bad completion code \"",			    Tcl_GetString(objv[1]),

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?