optimisation: Reuse ExprBool in Jim_GetBoolFromExpr()
[jimtcl.git] / jim-interactive.c
blob8a1809291646622303ed046882c9c997bc4094f7
1 #include <errno.h>
2 #include <string.h>
4 #include "jimautoconf.h"
5 #include <jim.h>
7 #ifdef USE_LINENOISE
8 #ifdef HAVE_UNISTD_H
9 #include <unistd.h>
10 #endif
11 #ifdef HAVE_SYS_STAT_H
12 #include <sys/stat.h>
13 #endif
14 #include "linenoise.h"
15 #else
16 #define MAX_LINE_LEN 512
17 #endif
19 /**
20 * Returns an allocated line, or NULL if EOF.
22 char *Jim_HistoryGetline(const char *prompt)
24 #ifdef USE_LINENOISE
25 return linenoise(prompt);
26 #else
27 int len;
28 char *line = malloc(MAX_LINE_LEN);
30 fputs(prompt, stdout);
31 fflush(stdout);
33 if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
34 free(line);
35 return NULL;
37 len = strlen(line);
38 if (len && line[len - 1] == '\n') {
39 line[len - 1] = '\0';
41 return line;
42 #endif
45 void Jim_HistoryLoad(const char *filename)
47 #ifdef USE_LINENOISE
48 linenoiseHistoryLoad(filename);
49 #endif
52 void Jim_HistoryAdd(const char *line)
54 #ifdef USE_LINENOISE
55 linenoiseHistoryAdd(line);
56 #endif
59 void Jim_HistorySave(const char *filename)
61 #ifdef USE_LINENOISE
62 #ifdef HAVE_UMASK
63 mode_t mask;
64 /* Just u=rw, but note that this is only effective for newly created files */
65 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
66 #endif
67 linenoiseHistorySave(filename);
68 #ifdef HAVE_UMASK
69 mask = umask(mask);
70 #endif
71 #endif
74 void Jim_HistoryShow(void)
76 #ifdef USE_LINENOISE
77 /* built-in history command */
78 int i;
79 int len;
80 char **history = linenoiseHistory(&len);
81 for (i = 0; i < len; i++) {
82 printf("%4d %s\n", i + 1, history[i]);
84 #endif
87 #ifdef USE_LINENOISE
88 struct JimCompletionInfo {
89 Jim_Interp *interp;
90 Jim_Obj *command;
93 void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
95 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
96 Jim_Obj *objv[2];
97 int ret;
99 objv[0] = info->command;
100 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
102 ret = Jim_EvalObjVector(info->interp, 2, objv);
104 /* XXX: Consider how best to handle errors here. bgerror? */
105 if (ret == JIM_OK) {
106 int i;
107 Jim_Obj *listObj = Jim_GetResult(info->interp);
108 int len = Jim_ListLength(info->interp, listObj);
109 for (i = 0; i < len; i++) {
110 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
114 #endif
116 int Jim_InteractivePrompt(Jim_Interp *interp)
118 int retcode = JIM_OK;
119 char *history_file = NULL;
120 #ifdef USE_LINENOISE
121 const char *home;
122 struct JimCompletionInfo compinfo;
124 home = getenv("HOME");
125 if (home && isatty(STDIN_FILENO)) {
126 int history_len = strlen(home) + sizeof("/.jim_history");
127 history_file = Jim_Alloc(history_len);
128 snprintf(history_file, history_len, "%s/.jim_history", home);
129 Jim_HistoryLoad(history_file);
132 compinfo.interp = interp;
133 compinfo.command = Jim_NewStringObj(interp, "tcl::autocomplete", -1);
134 Jim_IncrRefCount(compinfo.command);
136 /* Register a callback function for tab-completion. */
137 linenoiseSetCompletionCallback(JimCompletionCallback, &compinfo);
138 #endif
140 printf("Welcome to Jim version %d.%d\n",
141 JIM_VERSION / 100, JIM_VERSION % 100);
142 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
144 while (1) {
145 Jim_Obj *scriptObjPtr;
146 const char *result;
147 int reslen;
148 char prompt[20];
150 if (retcode != JIM_OK) {
151 const char *retcodestr = Jim_ReturnCode(retcode);
153 if (*retcodestr == '?') {
154 snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
156 else {
157 snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
160 else {
161 strcpy(prompt, ". ");
164 scriptObjPtr = Jim_NewStringObj(interp, "", 0);
165 Jim_IncrRefCount(scriptObjPtr);
166 while (1) {
167 char state;
168 char *line;
170 line = Jim_HistoryGetline(prompt);
171 if (line == NULL) {
172 if (errno == EINTR) {
173 continue;
175 Jim_DecrRefCount(interp, scriptObjPtr);
176 retcode = JIM_OK;
177 goto out;
179 if (Jim_Length(scriptObjPtr) != 0) {
180 /* Line continuation */
181 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
183 Jim_AppendString(interp, scriptObjPtr, line, -1);
184 free(line);
185 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
186 break;
188 snprintf(prompt, sizeof(prompt), "%c> ", state);
190 #ifdef USE_LINENOISE
191 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
192 /* built-in history command */
193 Jim_HistoryShow();
194 Jim_DecrRefCount(interp, scriptObjPtr);
195 continue;
198 Jim_HistoryAdd(Jim_String(scriptObjPtr));
199 if (history_file) {
200 Jim_HistorySave(history_file);
202 #endif
203 retcode = Jim_EvalObj(interp, scriptObjPtr);
204 Jim_DecrRefCount(interp, scriptObjPtr);
206 if (retcode == JIM_EXIT) {
207 break;
209 if (retcode == JIM_ERR) {
210 Jim_MakeErrorMessage(interp);
212 result = Jim_GetString(Jim_GetResult(interp), &reslen);
213 if (reslen) {
214 printf("%s\n", result);
217 out:
218 Jim_Free(history_file);
220 #ifdef USE_LINENOISE
221 Jim_DecrRefCount(interp, compinfo.command);
222 linenoiseSetCompletionCallback(NULL, NULL);
223 #endif
225 return retcode;