tclmain.c

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

C
726
字号
		continue;	    }	    /* 	     * Either EOF, or an error on stdin; we're done	     */	    break;	}        /*         * Add the newline removed by Tcl_GetsObj back to the string.         */	if (Tcl_IsShared(commandPtr)) {	    Tcl_DecrRefCount(commandPtr);	    commandPtr = Tcl_DuplicateObj(commandPtr);	    Tcl_IncrRefCount(commandPtr);	}	Tcl_AppendToObj(commandPtr, "\n", 1);	if (!TclObjCommandComplete(commandPtr)) {	    prompt = PROMPT_CONTINUE;	    continue;	}	prompt = PROMPT_START;	code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);	inChannel = Tcl_GetStdChannel(TCL_STDIN);	outChannel = Tcl_GetStdChannel(TCL_STDOUT);	errChannel = Tcl_GetStdChannel(TCL_STDERR);	Tcl_DecrRefCount(commandPtr);	commandPtr = Tcl_NewObj();	Tcl_IncrRefCount(commandPtr);	if (code != TCL_OK) {	    if (errChannel) {		Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));		Tcl_WriteChars(errChannel, "\n", 1);	    }	} else if (tty) {	    resultPtr = Tcl_GetObjResult(interp);	    Tcl_IncrRefCount(resultPtr);	    Tcl_GetStringFromObj(resultPtr, &length);	    if ((length > 0) && outChannel) {		Tcl_WriteObj(outChannel, resultPtr);		Tcl_WriteChars(outChannel, "\n", 1);	    }	    Tcl_DecrRefCount(resultPtr);	}	if (mainLoopProc != NULL) {	    /*	     * If a main loop has been defined while running interactively,	     * we want to start a fileevent based prompt by establishing a	     * channel handler for stdin.	     */	    InteractiveState *isPtr = NULL;	    if (inChannel) {	        if (tty) {		    Prompt(interp, &prompt);	        }		isPtr = (InteractiveState *) 			ckalloc((int) sizeof(InteractiveState));		isPtr->input = inChannel;		isPtr->tty = tty;		isPtr->commandPtr = commandPtr;		isPtr->prompt = prompt;		isPtr->interp = interp;		Tcl_UnlinkVar(interp, "tcl_interactive");		Tcl_LinkVar(interp, "tcl_interactive", (char *) &(isPtr->tty),			TCL_LINK_BOOLEAN);		Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,			(ClientData) isPtr);	    }	    (*mainLoopProc)();	    mainLoopProc = NULL;	    if (inChannel) {		tty = isPtr->tty;		Tcl_UnlinkVar(interp, "tcl_interactive");		Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty,			TCL_LINK_BOOLEAN);		prompt = isPtr->prompt;		commandPtr = isPtr->commandPtr;		if (isPtr->input != (Tcl_Channel) NULL) {		    Tcl_DeleteChannelHandler(isPtr->input, StdinProc,			    (ClientData) isPtr);		}		ckfree((char *)isPtr);	    }	    inChannel = Tcl_GetStdChannel(TCL_STDIN);	    outChannel = Tcl_GetStdChannel(TCL_STDOUT);	    errChannel = Tcl_GetStdChannel(TCL_STDERR);	}#ifdef TCL_MEM_DEBUG	/*	 * This code here only for the (unsupported and deprecated)	 * [checkmem] command.	 */	if (tclMemDumpFileName != NULL) {	    mainLoopProc = NULL;	    Tcl_DeleteInterp(interp);	}#endif    }    done:    if ((exitCode == 0) && (mainLoopProc != NULL)) {	/*	 * If everything has gone OK so far, call the main loop proc,	 * if it exists.  Packages (like Tk) can set it to start processing	 * events at this point.	 */	(*mainLoopProc)();	mainLoopProc = NULL;    }    if (commandPtr != NULL) {	Tcl_DecrRefCount(commandPtr);    }    /*     * Rather than calling exit, invoke the "exit" command so that     * users can replace "exit" with some other command to do additional     * cleanup on exit.  The Tcl_Eval call should never return.     */    if (!Tcl_InterpDeleted(interp)) {        sprintf(buffer, "exit %d", exitCode);        Tcl_Eval(interp, buffer);        /*         * If Tcl_Eval returns, trying to eval [exit], something         * unusual is happening.  Maybe interp has been deleted;         * maybe [exit] was redefined.  We still want to cleanup         * and exit.         */        if (!Tcl_InterpDeleted(interp)) {            Tcl_DeleteInterp(interp);        }    }    TclSetStartupScriptPath(NULL);    /*     * If we get here, the master interp has been deleted.  Allow     * its destruction with the last matching Tcl_Release.     */    Tcl_Release((ClientData) interp);    Tcl_Exit(exitCode);}/* *--------------------------------------------------------------- * * Tcl_SetMainLoop -- * *	Sets an alternative main loop procedure. * * Results: *	Returns the previously defined main loop procedure. * * Side effects: *	This procedure will be called before Tcl exits, allowing for *	the creation of an event loop. * *--------------------------------------------------------------- */voidTcl_SetMainLoop(proc)    Tcl_MainLoopProc *proc;{    mainLoopProc = proc;}/* *---------------------------------------------------------------------- * * StdinProc -- * *	This procedure is invoked by the event dispatcher whenever *	standard input becomes readable.  It grabs the next line of *	input characters, adds them to a command being assembled, and *	executes the command if it's complete. * * Results: *	None. * * Side effects: *	Could be almost arbitrary, depending on the command that's *	typed. * *---------------------------------------------------------------------- */    /* ARGSUSED */static voidStdinProc(clientData, mask)    ClientData clientData;		/* The state of interactive cmd line */    int mask;				/* Not used. */{    InteractiveState *isPtr = (InteractiveState *) clientData;    Tcl_Channel chan = isPtr->input;    Tcl_Obj *commandPtr = isPtr->commandPtr;    Tcl_Interp *interp = isPtr->interp;    int code, length;    if (Tcl_IsShared(commandPtr)) {	Tcl_DecrRefCount(commandPtr);	commandPtr = Tcl_DuplicateObj(commandPtr);	Tcl_IncrRefCount(commandPtr);    }    length = Tcl_GetsObj(chan, commandPtr);    if (length < 0) {	if (Tcl_InputBlocked(chan)) {	    return;	}	if (isPtr->tty) {	    /*	     * Would be better to find a way to exit the mainLoop?	     * Or perhaps evaluate [exit]?  Leaving as is for now due	     * to compatibility concerns.	     */	    Tcl_Exit(0);	}	Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) isPtr);	return;    }    if (Tcl_IsShared(commandPtr)) {	Tcl_DecrRefCount(commandPtr);	commandPtr = Tcl_DuplicateObj(commandPtr);	Tcl_IncrRefCount(commandPtr);    }    Tcl_AppendToObj(commandPtr, "\n", 1);    if (!TclObjCommandComplete(commandPtr)) {        isPtr->prompt = PROMPT_CONTINUE;        goto prompt;    }    isPtr->prompt = PROMPT_START;    /*     * Disable the stdin channel handler while evaluating the command;     * otherwise if the command re-enters the event loop we might     * process commands from stdin before the current command is     * finished.  Among other things, this will trash the text of the     * command being evaluated.     */    Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) isPtr);    code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);    isPtr->input = chan = Tcl_GetStdChannel(TCL_STDIN);    Tcl_DecrRefCount(commandPtr);    isPtr->commandPtr = commandPtr = Tcl_NewObj();    Tcl_IncrRefCount(commandPtr);    if (chan != (Tcl_Channel) NULL) {	Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,		(ClientData) isPtr);    }    if (code != TCL_OK) {	Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR);	if (errChannel != (Tcl_Channel) NULL) {	    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));	    Tcl_WriteChars(errChannel, "\n", 1);	}    } else if (isPtr->tty) {	Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);	Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);	Tcl_IncrRefCount(resultPtr);	Tcl_GetStringFromObj(resultPtr, &length);	if ((length >0) && (outChannel != (Tcl_Channel) NULL)) {	    Tcl_WriteObj(outChannel, resultPtr);	    Tcl_WriteChars(outChannel, "\n", 1);	}	Tcl_DecrRefCount(resultPtr);    }    /*     * If a tty stdin is still around, output a prompt.     */    prompt:    if (isPtr->tty && (isPtr->input != (Tcl_Channel) NULL)) {	Prompt(interp, &(isPtr->prompt));	isPtr->input = Tcl_GetStdChannel(TCL_STDIN);    }}/* *---------------------------------------------------------------------- * * Prompt -- * *	Issue a prompt on standard output, or invoke a script *	to issue the prompt. * * Results: *	None. * * Side effects: *	A prompt gets output, and a Tcl script may be evaluated *	in interp. * *---------------------------------------------------------------------- */static voidPrompt(interp, promptPtr)    Tcl_Interp *interp;			/* Interpreter to use for prompting. */    PromptType *promptPtr;		/* Points to type of prompt to print.					 * Filled with PROMPT_NONE after a					 * prompt is printed. */{    Tcl_Obj *promptCmdPtr;    int code;    Tcl_Channel outChannel, errChannel;    if (*promptPtr == PROMPT_NONE) {	return;    }    promptCmdPtr = Tcl_GetVar2Ex(interp,	    ((*promptPtr == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"),	    NULL, TCL_GLOBAL_ONLY);    if (Tcl_InterpDeleted(interp)) {	return;    }    if (promptCmdPtr == NULL) {	defaultPrompt:	outChannel = Tcl_GetStdChannel(TCL_STDOUT);	if ((*promptPtr == PROMPT_START)		&& (outChannel != (Tcl_Channel) NULL)) {	    Tcl_WriteChars(outChannel, "% ", 2);	}    } else {	code = Tcl_EvalObjEx(interp, promptCmdPtr, TCL_EVAL_GLOBAL);	if (code != TCL_OK) {	    Tcl_AddErrorInfo(interp,		    "\n    (script that generates prompt)");	    errChannel = Tcl_GetStdChannel(TCL_STDERR);            if (errChannel != (Tcl_Channel) NULL) {                Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));                Tcl_WriteChars(errChannel, "\n", 1);            }	    goto defaultPrompt;	}    }    outChannel = Tcl_GetStdChannel(TCL_STDOUT);    if (outChannel != (Tcl_Channel) NULL) {	Tcl_Flush(outChannel);    }    *promptPtr = PROMPT_NONE;}

⌨️ 快捷键说明

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