📄 tclcmdmz.c
字号:
/* * tclCmdMZ.c -- * * This file contains the top-level command routines for most of * the Tcl built-in commands whose names begin with the letters * M to Z. It contains only commands in the generic core (i.e. * those that don't depend much upon UNIX facilities). * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclCmdMZ.c 1.104 97/10/31 13:06:19 */#include "tclInt.h"#include "tclPort.h"#include "tclCompile.h"/* * Structure used to hold information about variable traces: */typedef struct { int flags; /* Operations for which Tcl command is * to be invoked. */ char *errMsg; /* Error message returned from Tcl command, * or NULL. Malloc'ed. */ int length; /* Number of non-NULL chars. in command. */ char command[4]; /* Space for Tcl command to invoke. Actual * size will be as large as necessary to * hold command. This field must be the * last in the structure, so that it can * be larger than 4 bytes. */} TraceVarInfo;/* * Forward declarations for procedures defined in this file: */static char * TraceVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags));/* *---------------------------------------------------------------------- * * Tcl_PwdCmd -- * * This procedure is invoked to process the "pwd" 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_PwdCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ char *dirName; if (argc != 1) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "\"", (char *) NULL); return TCL_ERROR; } dirName = TclGetCwd(interp); if (dirName == NULL) { return TCL_ERROR; } Tcl_SetResult(interp, dirName, TCL_VOLATILE); return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_RegexpCmd -- * * This procedure is invoked to process the "regexp" 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_RegexpCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ int noCase = 0; int indices = 0; Tcl_RegExp regExpr; char **argPtr, *string, *pattern, *start, *end; int match = 0; /* Initialization needed only to * prevent compiler warning. */ int i; Tcl_DString stringDString, patternDString; if (argc < 3) { wrongNumArgs: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?switches? exp string ?matchVar? ?subMatchVar ", "subMatchVar ...?\"", (char *) NULL); return TCL_ERROR; } argPtr = argv+1; argc--; while ((argc > 0) && (argPtr[0][0] == '-')) { if (strcmp(argPtr[0], "-indices") == 0) { indices = 1; } else if (strcmp(argPtr[0], "-nocase") == 0) { noCase = 1; } else if (strcmp(argPtr[0], "--") == 0) { argPtr++; argc--; break; } else { Tcl_AppendResult(interp, "bad switch \"", argPtr[0], "\": must be -indices, -nocase, or --", (char *) NULL); return TCL_ERROR; } argPtr++; argc--; } if (argc < 2) { goto wrongNumArgs; } /* * Convert the string and pattern to lower case, if desired, and * perform the matching operation. */ if (noCase) { register char *p; Tcl_DStringInit(&patternDString); Tcl_DStringAppend(&patternDString, argPtr[0], -1); pattern = Tcl_DStringValue(&patternDString); for (p = pattern; *p != 0; p++) { if (isupper(UCHAR(*p))) { *p = (char)tolower(UCHAR(*p)); } } Tcl_DStringInit(&stringDString); Tcl_DStringAppend(&stringDString, argPtr[1], -1); string = Tcl_DStringValue(&stringDString); for (p = string; *p != 0; p++) { if (isupper(UCHAR(*p))) { *p = (char)tolower(UCHAR(*p)); } } } else { pattern = argPtr[0]; string = argPtr[1]; } regExpr = Tcl_RegExpCompile(interp, pattern); if (regExpr != NULL) { match = Tcl_RegExpExec(interp, regExpr, string, string); } if (noCase) { Tcl_DStringFree(&stringDString); Tcl_DStringFree(&patternDString); } if (regExpr == NULL) { return TCL_ERROR; } if (match < 0) { return TCL_ERROR; } if (!match) { Tcl_SetResult(interp, "0", TCL_STATIC); return TCL_OK; } /* * If additional variable names have been specified, return * index information in those variables. */ argc -= 2; for (i = 0; i < argc; i++) { char *result, info[50]; Tcl_RegExpRange(regExpr, i, &start, &end); if (start == NULL) { if (indices) { result = Tcl_SetVar(interp, argPtr[i+2], "-1 -1", 0); } else { result = Tcl_SetVar(interp, argPtr[i+2], "", 0); } } else { if (indices) { sprintf(info, "%d %d", (int)(start - string), (int)(end - string - 1)); result = Tcl_SetVar(interp, argPtr[i+2], info, 0); } else { char savedChar, *first, *last; first = argPtr[1] + (start - string); last = argPtr[1] + (end - string); if (first == last) { /* don't modify argument */ result = Tcl_SetVar(interp, argPtr[i+2], "", 0); } else { savedChar = *last; *last = 0; result = Tcl_SetVar(interp, argPtr[i+2], first, 0); *last = savedChar; } } } if (result == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", argPtr[i+2], "\"", (char *) NULL); return TCL_ERROR; } } Tcl_SetResult(interp, "1", TCL_STATIC); return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_RegsubCmd -- * * 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_RegsubCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ int noCase = 0, all = 0; Tcl_RegExp regExpr; char *string, *pattern, *p, *firstChar, **argPtr; int match, code, numMatches; char *start, *end, *subStart, *subEnd; register char *src, c; Tcl_DString stringDString, patternDString, resultDString; if (argc < 5) { wrongNumArgs: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?switches? exp string subSpec varName\"", (char *) NULL); return TCL_ERROR; } argPtr = argv+1; argc--; while (argPtr[0][0] == '-') { if (strcmp(argPtr[0], "-nocase") == 0) { noCase = 1; } else if (strcmp(argPtr[0], "-all") == 0) { all = 1; } else if (strcmp(argPtr[0], "--") == 0) { argPtr++; argc--; break; } else { Tcl_AppendResult(interp, "bad switch \"", argPtr[0], "\": must be -all, -nocase, or --", (char *) NULL); return TCL_ERROR; } argPtr++; argc--; } if (argc != 4) { goto wrongNumArgs; } /* * Convert the string and pattern to lower case, if desired. */ if (noCase) { Tcl_DStringInit(&patternDString); Tcl_DStringAppend(&patternDString, argPtr[0], -1); pattern = Tcl_DStringValue(&patternDString); for (p = pattern; *p != 0; p++) { if (isupper(UCHAR(*p))) { *p = (char)tolower(UCHAR(*p)); } } Tcl_DStringInit(&stringDString); Tcl_DStringAppend(&stringDString, argPtr[1], -1); string = Tcl_DStringValue(&stringDString); for (p = string; *p != 0; p++) { if (isupper(UCHAR(*p))) { *p = (char)tolower(UCHAR(*p)); } } } else { pattern = argPtr[0]; string = argPtr[1]; } Tcl_DStringInit(&resultDString); regExpr = Tcl_RegExpCompile(interp, pattern); if (regExpr == NULL) { code = TCL_ERROR; goto done; } /* * 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 (p = string; *p != 0; ) { match = Tcl_RegExpExec(interp, regExpr, p, string); if (match < 0) { code = TCL_ERROR; goto done; } if (!match) { break; } numMatches += 1; /* * Copy the portion of the source string before the match to the * result variable. */ Tcl_RegExpRange(regExpr, 0, &start, &end); Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), start - p); /* * 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. */ for (src = firstChar = argPtr[2], c = *src; c != 0; src++, c = *src) { int index; if (c == '&') { index = 0; } else if (c == '\\') { c = src[1]; if ((c >= '0') && (c <= '9')) { index = c - '0'; } else if ((c == '\\') || (c == '&')) { *src = c; src[1] = 0; Tcl_DStringAppend(&resultDString, firstChar, -1); *src = '\\'; src[1] = c; firstChar = src+2; src++; continue; } else { continue; } } else { continue; } if (firstChar != src) { c = *src; *src = 0; Tcl_DStringAppend(&resultDString, firstChar, -1); *src = c; } Tcl_RegExpRange(regExpr, index, &subStart, &subEnd); if ((subStart != NULL) && (subEnd != NULL)) { char *first, *last, saved; first = argPtr[1] + (subStart - string); last = argPtr[1] + (subEnd - string); saved = *last; *last = 0; Tcl_DStringAppend(&resultDString, first, -1); *last = saved; } if (*src == '\\') { src++; } firstChar = src+1; } if (firstChar != src) { Tcl_DStringAppend(&resultDString, firstChar, -1); } if (end == p) { /* * Always consume at least one character of the input string * in order to prevent infinite loops. */ Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), 1); p = end + 1; } else { p = end; } if (!all) { break; } } /* * Copy the portion of the source string after the last match to the * result variable. */ if ((*p != 0) || (numMatches == 0)) { Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), -1); } if (Tcl_SetVar(interp, argPtr[3], Tcl_DStringValue(&resultDString), 0) == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", argPtr[3], "\"", (char *) NULL); code = TCL_ERROR; } else { char buf[40]; TclFormatInt(buf, numMatches); Tcl_SetResult(interp, buf, TCL_VOLATILE); code = TCL_OK; } done: if (noCase) { Tcl_DStringFree(&stringDString); Tcl_DStringFree(&patternDString); } Tcl_DStringFree(&resultDString); return code;}/* *---------------------------------------------------------------------- * * 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_GetStringFromObj(objv[1], (int *) NULL); newName = Tcl_GetStringFromObj(objv[2], (int *) NULL); 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; /* * THIS FAILS IF AN OBJECT CONTAINS AN EMBEDDED NULL. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -