]>
cvs.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxclp.c
4 * Interactive command loop, C and Tcl callable.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
14 *-----------------------------------------------------------------------------
15 * $Id: tclXcmdloop.c,v 2.0 1992/10/16 04:50:29 markd Rel $
16 *-----------------------------------------------------------------------------
23 * Pointer to eval procedure to use. This way bring in the history module
24 * from a library can be made optional. This only works because the calling
25 * sequence of Tcl_Eval is a superset of Tcl_RecordAndEval. This defaults
26 * to no history, set this variable to Tcl_RecordAndEval to use history.
29 int (*tclShellCmdEvalProc
) (Tcl_Interp
*, char *, int, char**) = Tcl_Eval
;
32 * Prototypes of internal functions.
35 IsSetVarCmd
_ANSI_ARGS_((Tcl_Interp
*interp
,
39 OutFlush
_ANSI_ARGS_((FILE *filePtr
));
42 Tcl_PrintResult
_ANSI_ARGS_((FILE *fp
,
47 OutputPrompt
_ANSI_ARGS_((Tcl_Interp
*interp
,
52 SetPromptVar
_ANSI_ARGS_((Tcl_Interp
*interp
,
55 char **oldHookValuePtr
));
59 *-----------------------------------------------------------------------------
63 * Determine if the current command is a `set' command that set
64 * a variable (i.e. two arguments). This routine should only be
65 * called if the command returned TCL_OK.
67 *-----------------------------------------------------------------------------
70 IsSetVarCmd (Tcl_Interp
*interp
, char *command
)
74 if ((!STRNEQU (command
, "set", 3)) || (!isspace (command
[3])))
75 return FALSE
; /* Quick check */
77 nextPtr
= TclWordEnd (command
, FALSE
);
80 nextPtr
= TclWordEnd (nextPtr
, FALSE
);
84 while (*nextPtr
!= '\0') {
85 if (!isspace (*nextPtr
))
93 *-----------------------------------------------------------------------------
97 * Flush a stdio file and check for errors.
99 *-----------------------------------------------------------------------------
102 OutFlush (FILE *filePtr
)
106 stat
= fflush (filePtr
);
107 if (ferror (filePtr
)) {
109 panic ("command loop: error writing to output file: %s\n",
116 *-----------------------------------------------------------------------------
124 * Takes an open file pointer, a return value and some result
125 * text. Prints the result text if the return value is TCL_OK,
126 * prints "Error:" and the result text if it's TCL_ERROR,
127 * else prints "Bad return code:" and the result text.
129 *-----------------------------------------------------------------------------
132 Tcl_PrintResult (FILE *fp
, int returnval
, char *resultText
)
135 if (returnval
== TCL_OK
) {
136 if (resultText
[0] != '\0') {
137 fputs (resultText
, fp
);
142 fputs ((returnval
== TCL_ERROR
) ? "Error" : "Bad return code", stderr
);
143 fputs (": ", stderr
);
144 fputs (resultText
, stderr
);
145 fputs ("\n", stderr
);
151 *-----------------------------------------------------------------------------
154 * Outputs a prompt by executing either the command string in
155 * TCLENV(topLevelPromptHook) or TCLENV(downLevelPromptHook).
157 *-----------------------------------------------------------------------------
160 OutputPrompt (Tcl_Interp
*interp
, FILE *outFP
, int topLevel
)
165 int promptDone
= FALSE
;
167 hookName
= topLevel
? "topLevelPromptHook"
168 : "downLevelPromptHook";
170 promptHook
= Tcl_GetVar2 (interp
, "TCLENV", hookName
, 1);
171 if ((promptHook
!= NULL
) && (promptHook
[0] != '\0')) {
172 result
= Tcl_Eval (interp
, promptHook
, 0, (char **)NULL
);
173 if (!((result
== TCL_OK
) || (result
== TCL_RETURN
))) {
174 fputs ("Error in prompt hook: ", stderr
);
175 fputs (interp
->result
, stderr
);
176 fputs ("\n", stderr
);
177 Tcl_PrintResult (outFP
, result
, interp
->result
);
179 fputs (interp
->result
, outFP
);
194 *-----------------------------------------------------------------------------
198 * Run a Tcl command loop. The command loop interactively prompts for,
199 * reads and executes commands. Two entries in the global array TCLENV
200 * contain prompt hooks. A prompt hook is Tcl code that is executed and
201 * its result is used as the prompt string. The element `topLevelPromptHook'
202 * is the hook that generates the main prompt. The element
203 * `downLevelPromptHook' is the hook to generate the prompt for reading
204 * continuation lines for incomplete commands. If a signal occurs while
205 * in the command loop, it is reset and ignored. EOF terminates the loop.
208 * o interp (I) - A pointer to the interpreter
209 * o inFile (I) - The file to read commands from.
210 * o outFile (I) - The file to write the prompts to.
211 * o evalProc (I) - The function to call to evaluate a command.
212 * Should be either Tcl_Eval or Tcl_RecordAndEval if history is desired.
213 * o options (I) - Currently unused.
214 *-----------------------------------------------------------------------------
217 Tcl_CommandLoop (Tcl_Interp
*interp
, FILE *inFile
, FILE *outFile
, int (*evalProc
)(Tcl_Interp
*, char *, int, char**), unsigned options
)
225 cmdBuf
= Tcl_CreateCmdBuf();
229 * If a signal came in, process it and drop any pending command.
231 if (tclReceivedSignal
) {
232 Tcl_CheckForSignal (interp
, TCL_OK
);
233 Tcl_DeleteCmdBuf(cmdBuf
);
234 cmdBuf
= Tcl_CreateCmdBuf();
238 * Output a prompt and input a command.
242 OutputPrompt (interp
, outFile
, topLevel
);
244 if (fgets (inputBuf
, sizeof (inputBuf
), inFile
) == NULL
) {
245 if (!feof(inFile
) && (errno
== EINTR
)) {
247 continue; /* Next command */
250 panic ("command loop: error on input file: %s\n",
254 cmd
= Tcl_AssembleCmd(cmdBuf
, inputBuf
);
258 continue; /* Next line */
261 * Finally have a complete command, go eval it and maybe output the
264 result
= (*evalProc
) (interp
, cmd
, 0, (char **)NULL
);
265 if (result
!= TCL_OK
|| !IsSetVarCmd (interp
, cmd
))
266 Tcl_PrintResult (outFile
, result
, interp
->result
);
270 Tcl_DeleteCmdBuf(cmdBuf
);
274 *-----------------------------------------------------------------------------
277 * Set one of the prompt hook variables, saving a copy of the old
278 * value, if it exists.
281 * o hookVarName (I) - The name of the prompt hook, which is an element
282 * of the TCLENV array. One of topLevelPromptHook or downLevelPromptHook.
283 * o newHookValue (I) - The new value for the prompt hook.
284 * o oldHookValuePtr (O) - If not NULL, then a pointer to a copy of the
285 * old prompt value is returned here. NULL is returned if there was not
286 * old value. This is a pointer to a malloc-ed string that must be
287 * freed when no longer needed.
289 * TCL_OK if the hook variable was set ok, TCL_ERROR if an error occured.
290 *-----------------------------------------------------------------------------
293 SetPromptVar (Tcl_Interp
*interp
, char *hookVarName
, char *newHookValue
, char **oldHookValuePtr
)
296 char *oldHookPtr
= NULL
;
298 if (oldHookValuePtr
!= NULL
) {
299 hookValue
= Tcl_GetVar2 (interp
, "TCLENV", hookVarName
,
301 if (hookValue
!= NULL
) {
302 oldHookPtr
= ckalloc (strlen (hookValue
) + 1);
303 strcpy (oldHookPtr
, hookValue
);
306 if (Tcl_SetVar2 (interp
, "TCLENV", hookVarName
, newHookValue
,
307 TCL_GLOBAL_ONLY
| TCL_LEAVE_ERR_MSG
) == NULL
) {
308 if (oldHookPtr
!= NULL
)
312 if (oldHookValuePtr
!= NULL
)
313 *oldHookValuePtr
= oldHookPtr
;
318 *-----------------------------------------------------------------------------
320 * Tcl_CommandloopCmd --
321 * Implements the TCL commandloop command:
322 * commandloop prompt prompt2
325 * Standard TCL results.
327 *-----------------------------------------------------------------------------
331 ClientData clientData
,
337 char *oldTopLevelHook
= NULL
;
338 char *oldDownLevelHook
= NULL
;
339 int result
= TCL_ERROR
;
342 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
343 " [prompt] [prompt2]", (char *) NULL
);
347 if (SetPromptVar (interp
, "topLevelPromptHook", argv
[1],
348 &oldTopLevelHook
) != TCL_OK
)
352 if (SetPromptVar (interp
, "downLevelPromptHook", argv
[2],
353 &oldDownLevelHook
) != TCL_OK
)
357 Tcl_CommandLoop (interp
, stdin
, stdout
, tclShellCmdEvalProc
, 0);
359 if (oldTopLevelHook
!= NULL
)
360 SetPromptVar (interp
, "topLevelPromptHook", oldTopLevelHook
, NULL
);
361 if (oldDownLevelHook
!= NULL
)
362 SetPromptVar (interp
, "downLevelPromptHook", oldDownLevelHook
, NULL
);
366 if (oldTopLevelHook
!= NULL
)
367 ckfree (oldTopLevelHook
);
368 if (oldDownLevelHook
!= NULL
)
369 ckfree (oldDownLevelHook
);