⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclhistory.c

📁 tcl源码详细资料
💻 C
📖 第 1 页 / 共 2 页
字号:
 * * Side effects: *	RevPtr is added to iPtr's revision list. * *---------------------------------------------------------------------- */static voidInsertRev(iPtr, revPtr)    Interp *iPtr;			/* Interpreter to use. */    register HistoryRev *revPtr;	/* Revision to add to iPtr's list. */{    register HistoryRev *curPtr;    register HistoryRev *prevPtr;    for (curPtr = iPtr->revPtr, prevPtr = NULL; curPtr != NULL;	    prevPtr = curPtr, curPtr = curPtr->nextPtr) {	/*	 * If this revision includes the new one (or vice versa) then	 * just eliminate the one that is a subset of the other.	 */	if ((revPtr->firstIndex <= curPtr->firstIndex)		&& (revPtr->lastIndex >= curPtr->firstIndex)) {	    curPtr->firstIndex = revPtr->firstIndex;	    curPtr->lastIndex = revPtr->lastIndex;	    curPtr->newSize = revPtr->newSize;	    ckfree(curPtr->newBytes);	    curPtr->newBytes = revPtr->newBytes;	    ckfree((char *) revPtr);	    return;	}	if ((revPtr->firstIndex >= curPtr->firstIndex)		&& (revPtr->lastIndex <= curPtr->lastIndex)) {	    ckfree(revPtr->newBytes);	    ckfree((char *) revPtr);	    return;	}	if (revPtr->firstIndex < curPtr->firstIndex) {	    break;	}    }    /*     * Insert revPtr just after prevPtr.     */    if (prevPtr == NULL) {	revPtr->nextPtr = iPtr->revPtr;	iPtr->revPtr = revPtr;    } else {	revPtr->nextPtr = prevPtr->nextPtr;	prevPtr->nextPtr = revPtr;    }}/* *---------------------------------------------------------------------- * * RevCommand -- * *	This procedure is invoked by the "history" command to record *	a command revision.  See the comments at the beginning of the *	file for more information about revisions. * * Results: *	None. * * Side effects: *	Revision information is recorded. * *---------------------------------------------------------------------- */static voidRevCommand(iPtr, string)    register Interp *iPtr;	/* Interpreter in which to perform the				 * substitution. */    char *string;		/* String to substitute. */{    register HistoryRev *revPtr;    if ((iPtr->evalFirst == NULL) || (iPtr->revDisables > 0)) {	return;    }    revPtr = (HistoryRev *) ckalloc(sizeof(HistoryRev));    revPtr->firstIndex = iPtr->evalFirst - iPtr->historyFirst;    revPtr->lastIndex = iPtr->evalLast - iPtr->historyFirst;    revPtr->newSize = strlen(string);    revPtr->newBytes = (char *) ckalloc((unsigned) (revPtr->newSize+1));    strcpy(revPtr->newBytes, string);    InsertRev(iPtr, revPtr);}/* *---------------------------------------------------------------------- * * RevResult -- * *	This procedure is invoked by the "history" command to record *	a result revision.  See the comments at the beginning of the *	file for more information about revisions. * * Results: *	None. * * Side effects: *	Revision information is recorded. * *---------------------------------------------------------------------- */static voidRevResult(iPtr, string)    register Interp *iPtr;	/* Interpreter in which to perform the				 * substitution. */    char *string;		/* String to substitute. */{    register HistoryRev *revPtr;    char *evalFirst, *evalLast;    char *argv[2];    if ((iPtr->evalFirst == NULL) || (iPtr->revDisables > 0)) {	return;    }    /*     * Expand the replacement range to include the brackets that surround     * the command.  If there aren't any brackets (i.e. this command was     * invoked at top-level) then don't do any revision.  Also, if there     * are several commands in brackets, of which this is just one,     * then don't do any revision.     */    evalFirst = iPtr->evalFirst;    evalLast = iPtr->evalLast + 1;    while (1) {	if (evalFirst == iPtr->historyFirst) {	    return;	}	evalFirst--;	if (*evalFirst == '[') {	    break;	}	if (!isspace(*evalFirst)) {	    return;	}    }    if (*evalLast != ']') {	return;    }    revPtr = (HistoryRev *) ckalloc(sizeof(HistoryRev));    revPtr->firstIndex = evalFirst - iPtr->historyFirst;    revPtr->lastIndex = evalLast - iPtr->historyFirst;    argv[0] = string;    revPtr->newBytes = Tcl_Merge(1, argv);    revPtr->newSize = strlen(revPtr->newBytes);    InsertRev(iPtr, revPtr);}/* *---------------------------------------------------------------------- * * DoRevs -- * *	This procedure is called to apply the history revisions that *	have been recorded in iPtr. * * Results: *	None. * * Side effects: *	The most recent entry in the history for iPtr may be modified. * *---------------------------------------------------------------------- */static voidDoRevs(iPtr)    register Interp *iPtr;	/* Interpreter whose history is to				 * be modified. */{    register HistoryRev *revPtr;    register HistoryEvent *eventPtr;    char *newCommand, *p;    unsigned int size;    int bytesSeen, count;    if (iPtr->revPtr == NULL) {	return;    }    /*     * The revision is done in two passes.  The first pass computes the     * amount of space needed for the revised event, and the second pass     * pieces together the new event and frees up the revisions.     */    eventPtr = &iPtr->events[iPtr->curEvent];    size = strlen(eventPtr->command) + 1;    for (revPtr = iPtr->revPtr; revPtr != NULL; revPtr = revPtr->nextPtr) {	size -= revPtr->lastIndex + 1 - revPtr->firstIndex;	size += revPtr->newSize;    }    newCommand = (char *) ckalloc(size);    p = newCommand;    bytesSeen = 0;    for (revPtr = iPtr->revPtr; revPtr != NULL; ) {	HistoryRev *nextPtr = revPtr->nextPtr;	count = revPtr->firstIndex - bytesSeen;	if (count > 0) {	    strncpy(p, eventPtr->command + bytesSeen, count);	    p += count;	}	strncpy(p, revPtr->newBytes, revPtr->newSize);	p += revPtr->newSize;	bytesSeen = revPtr->lastIndex+1;	ckfree(revPtr->newBytes);	ckfree((char *) revPtr);	revPtr = nextPtr;    }    if (&p[strlen(&eventPtr->command[bytesSeen]) + 1] >	    &newCommand[size]) {	tracef("Assertion failed!\n");    }    strcpy(p, eventPtr->command + bytesSeen);    /*     * Replace the command in the event.     */    ckfree(eventPtr->command);    eventPtr->command = newCommand;    eventPtr->bytesAvl = size;    iPtr->revPtr = NULL;}/* *---------------------------------------------------------------------- * * GetEvent -- * *	Given a textual description of an event (see the manual page *	for legal values) find the corresponding event and return its *	command string. * * Results: *	The return value is a pointer to the event named by "string". *	If no such event exists, then NULL is returned and an error *	message is left in iPtr. * * Side effects: *	None. * *---------------------------------------------------------------------- */static HistoryEvent *GetEvent(iPtr, string)    register Interp *iPtr;	/* Interpreter in which to look. */    char *string;		/* Description of event. */{    long eventNum;    int index, length;    register HistoryEvent *eventPtr;    /*     * First check for a numeric specification of an event.     */    if (isdigit(*string) || (*string == '-')) {	if (Tcl_GetInt((Tcl_Interp *) iPtr, string, &eventNum) != TCL_OK) {	    return NULL;	}	if (eventNum < 0) {	    eventNum += iPtr->curEventNum;        }	if (eventNum > iPtr->curEventNum) {	    Tcl_AppendResult((Tcl_Interp *) iPtr, "event \"", string,		    "\" hasn't occurred yet", (char *) NULL);	    return NULL;	}	if ((eventNum <= iPtr->curEventNum-iPtr->numEvents)		|| (eventNum <= 0)) {	    Tcl_AppendResult((Tcl_Interp *) iPtr, "event \"", string,		    "\" is too far in the past", (char *) NULL);	    return NULL;	}	index = iPtr->curEvent + (eventNum - iPtr->curEventNum);	if (index < 0) {	    index += iPtr->numEvents;	}	return &iPtr->events[index];    }    /*     * Next, check for an event that contains the string as a prefix or     * that matches the string in the sense of Tcl_StringMatch.     */    length = strlen(string);    for (index = iPtr->curEvent - 1; ; index--) {	if (index < 0) {	    index += iPtr->numEvents;	}	if (index == iPtr->curEvent) {	    break;	}	eventPtr = &iPtr->events[index];	if ((strncmp(eventPtr->command, string, length) == 0)		|| Tcl_StringMatch(eventPtr->command, string)) {	    return eventPtr;	}    }    Tcl_AppendResult((Tcl_Interp *) iPtr, "no event matches \"", string,	    "\"", (char *) NULL);    return NULL;}/* *---------------------------------------------------------------------- * * SubsAndEval -- * *	Generate a new command by making a textual substitution in *	the "cmd" argument.  Then execute the new command. * * Results: *	The return value is a standard Tcl error. * * Side effects: *	History gets revised if the substitution is occurring on *	a recorded command line.  Also, the re-executed command *	may produce side-effects. * *---------------------------------------------------------------------- */static intSubsAndEval(iPtr, cmd, old, new)    register Interp *iPtr;	/* Interpreter in which to execute				 * new command. */    char *cmd;			/* Command in which to substitute. */    char *old;			/* String to search for in command. */    char *new;			/* Replacement string for "old". */{    char *src, *dst, *newCmd;    int count, oldLength, newLength, length, result;    /*     * Figure out how much space it will take to hold the     * substituted command (and complain if the old string     * doesn't appear in the original command).     */    oldLength = strlen(old);    newLength = strlen(new);    src = cmd;    count = 0;    while (1) {	src = strstr(src, old);	if (src == NULL) {	    break;	}	src += oldLength;	count++;    }    if (count == 0) {	Tcl_AppendResult((Tcl_Interp *) iPtr, "\"", old,		"\" doesn't appear in event", (char *) NULL);	return TCL_ERROR;    }    length = strlen(cmd) + count*(newLength - oldLength);    /*     * Generate a substituted command.     */    newCmd = (char *) ckalloc((unsigned) (length + 1));    dst = newCmd;    while (1) {	src = strstr(cmd, old);	if (src == NULL) {	    strcpy(dst, cmd);	    break;	}	strncpy(dst, cmd, src-cmd);	dst += src-cmd;	strcpy(dst, new);	dst += newLength;	cmd = src + oldLength;    }    RevCommand(iPtr, newCmd);    result = Tcl_Eval((Tcl_Interp *) iPtr, newCmd, 0, (char **) NULL);    ckfree(newCmd);    return result;}/* *---------------------------------------------------------------------- * * GetWords -- * *	Given a command string, return one or more words from the *	command string. * * Results: *	The return value is a pointer to a dynamically-allocated *	string containing the words of command specified by "words". *	If the word specifier has improper syntax then an error *	message is placed in iPtr->result and NULL is returned. * * Side effects: *	Memory is allocated.  It is the caller's responsibilty to *	free the returned string.. * *---------------------------------------------------------------------- */static char *GetWords(iPtr, command, words)    register Interp *iPtr;	/* Tcl interpreter in which to place				 * an error message if needed. */    char *command;		/* Command string. */    char *words;		/* Description of which words to extract				 * from the command.  Either num[-num] or				 * a pattern. */{    char *result;    char *start, *end, *dst;    register char *next;    int first;			/* First word desired. -1 means last word				 * only. */    int last;			/* Last word desired.  -1 means use everything				 * up to the end. */    int index;			/* Index of current word. */    char *pattern;    /*     * Figure out whether we're looking for a numerical range or for     * a pattern.     */    pattern = NULL;    first = 0;    last = -1;    if (*words == '$') {	if (words[1] != '\0') {	    goto error;	}	first = -1;    } else if (isdigit(*words)) {	first = strtoul(words, &start, 0);	if (*start == 0) {	    last = first;	} else if (*start == '-') {	    start++;	    if (*start == '$') {		start++;	    } else if (isdigit(*start)) {		last = strtoul(start, &start, 0);	    } else {		goto error;	    }	    if (*start != 0) {		goto error;	    }	}	if ((first > last) && (last != -1)) {	    goto error;	}    } else {	pattern = words;    }    /*     * Scan through the words one at a time, copying those that are     * relevant into the result string.  Allocate a result area large     * enough to hold all the words if necessary.     */    result = (char *) ckalloc((unsigned) (strlen(command) + 1));    dst = result;    for (next = command; isspace(*next); next++) {	/* Empty loop body:  just find start of first word. */    }    for (index = 0; *next != 0; index++) {	start = next;	end = TclWordEnd(next, 0);	if (*end != 0) {	    end++;	    for (next = end; isspace(*next); next++) {		/* Empty loop body:  just find start of next word. */	    }	}	if ((first > index) || ((first == -1) && (*next != 0))) {	    continue;	}	if ((last != -1) && (last < index)) {	    continue;	}	if (pattern != NULL) {	    int match;	    char savedChar = *end;	    *end = 0;	    match = Tcl_StringMatch(start, pattern);	    *end = savedChar;	    if (!match) {		continue;	    }	}	if (dst != result) {	    *dst = ' ';	    dst++;	}	strncpy(dst, start, (end-start));	dst += end-start;    }    *dst = 0;    /*     * Check for an out-of-range argument index.     */    if ((last >= index) || (first >= index)) {	ckfree(result);	Tcl_AppendResult((Tcl_Interp *) iPtr, "word selector \"", words,		"\" specified non-existent words", (char *) NULL);	return NULL;    }    return result;    error:    Tcl_AppendResult((Tcl_Interp *) iPtr, "bad word selector \"", words,	    "\":  should be num-num or pattern", (char *) NULL);    return NULL;}#elsestatic const char file_name[] = "tclHistory.c";#endif /* EXCLUDE_TCL */

⌨️ 快捷键说明

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