00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <string.h>
00014 #include <mmxlight/base_evaluator.hpp>
00015 #include <mmxlight/shell.hpp>
00016 #include <basix/system.hpp>
00017 #include <basix/string.hpp>
00018 #include <basix/table.hpp>
00019 #include <basix/math_syntax.hpp>
00020
00021 #ifdef MMXLIGHT_HAVE_READLINE
00022 # if defined(MMXLIGHT_HAVE_READLINE_READLINE_H)
00023 # include <readline/readline.h>
00024 # else
00025 # include <readline.h>
00026 # endif
00027 # if defined(MMXLIGHT_HAVE_READLINE_HISTORY_H)
00028 # include <readline/history.h>
00029 # else
00030 # include <history.h>
00031 # endif
00032 #endif
00033
00034 namespace mmx {
00035
00036
00037
00038
00039
00040 static bool
00041 raw_read_line (string& line) {
00042 char c;
00043 line = "";
00044 while (busy (mmin)) {
00045 mmin >> c;
00046 if (c == '\n' || c == '\r')
00047 return true;
00048 line << c;
00049 }
00050 return false;
00051 }
00052
00053 #ifdef MMXLIGHT_HAVE_READLINE
00054
00055 static bool
00056 read_line (string prompt, string& sline) {
00057 char* line;
00058 char* _prompt= as_charp (prompt);
00059 line = readline (_prompt);
00060 free_charp (_prompt);
00061 if (line == NULL) {
00062 sline = "";
00063 return false;
00064 }
00065 sline = string(line);
00066 free (line);
00067 return true;
00068 }
00069
00070 void
00071 itf_save_history () {
00072 string dir= user_dir ();
00073 if (dir == "") return;
00074 string file_name = dir * "/var/history";
00075 char* _f = as_charp (file_name);
00076 write_history (_f);
00077 history_truncate_file (_f, history_len);
00078 free_charp (_f);
00079 }
00080
00081 void
00082 itf_load_history () {
00083 string dir = user_dir ();
00084 if (dir == "") return;
00085 string file_name = dir * "/var/history";
00086 char* _f = as_charp (file_name);
00087 history_truncate_file (_f, history_len);
00088 read_history (_f);
00089 free_charp (_f);
00090 }
00091
00092 #else
00093
00094 static bool
00095 itf_read_line (string prompt, string& line) {
00096 mmout << prompt << flush_now;
00097 return raw_read_line (line);
00098 }
00099
00100 void
00101 itf_save_history () {}
00102
00103 void
00104 itf_load_history () {}
00105
00106 #endif // MMXLIGHT_HAVE_READLINE
00107
00108 void
00109 itf_save_session (void) {
00110 nat i;
00111 string dir = user_dir ();
00112 string contents = "";
00113 char z = 0;
00114 if (dir == "") return;
00115 string file_name = dir * "/var/session";
00116 for (i = 0; i < get_interactive_number (); ++i) {
00117 contents << get_interactive_source (i);
00118 contents << z << "\n";
00119 }
00120 save (file_name, contents);
00121 }
00122
00123 vector<string>
00124 itf_restore_session (void) {
00125 string dir = user_dir ();
00126 string file_name = dir * "/var/session";
00127 string data;
00128 load (file_name, data);
00129 store_interactive_number (0);
00130 string sep= "\n\n"; sep[0]= '\0';
00131 vector<string> inputs= tokenize (data, sep);
00132 vector<string> v;
00133 for (nat i=0; i<N(inputs); i++) {
00134 v << tokenize (inputs[i], "\n", true);
00135 store_interactive_source (inputs[i]);
00136 }
00137 return v;
00138 }
00139
00140
00141
00142
00143
00144 #ifdef MMXLIGHT_HAVE_READLINE
00145
00146 static char*
00147 duplicate (char *s) {
00148
00149 char* r= (char*) malloc (strlen (s) + 1);
00150 strcpy (r, s);
00151 return r;
00152 }
00153
00154
00155
00156
00157 static char *
00158 completion_generator (const char* text, int state) {
00159 static nat text_len;
00160 static list<string> current_list;
00161 iterator<string> iter;
00162 string name;
00163 char *tmp, *copiedname;
00164
00165
00166
00167
00168 if (!state) {
00169 current_list = identifiers_list
00170 * completion_list (get_environment (current_ev));
00171 text_len = strlen (text);
00172 }
00173
00174
00175 while (!is_nil(current_list)) {
00176 name = car (current_list);
00177 current_list = cdr (current_list);
00178 tmp = as_charp (name);
00179 if (strncmp (tmp, text, text_len) == 0) {
00180
00181 copiedname = duplicate (tmp);
00182 free_charp (tmp);
00183
00184 return copiedname;
00185 }
00186 else {
00187 int dot;
00188 for (dot= text_len-1; dot>=0 && text[dot] != '.'; dot--);
00189 if (dot >= 0 && strncmp (text + dot, tmp, text_len - dot) == 0) {
00190 char* r= (char*) malloc (dot + strlen (tmp) + 1);
00191 strncpy (r, text, dot);
00192 strcpy (r + dot, tmp);
00193 free_charp (tmp);
00194 return r;
00195 }
00196 else free_charp (tmp);
00197 }
00198 }
00199
00200
00201 return ((char *)NULL);
00202 }
00203
00204
00205
00206
00207
00208
00209 static char **
00210 complete (const char *text, int start, int end) {
00211 char **matches;
00212
00213 #if defined(RL_VERSION_MAJOR) && RL_VERSION_MAJOR >= 4
00214 rl_completion_append_character = '\0';
00215 #endif
00216 matches = (char **)NULL;
00217 matches = rl_completion_matches(text, completion_generator);
00218 return (matches);
00219 }
00220 #endif // MMXLIGHT_HAVE_READLINE
00221
00222
00223
00224
00225
00226 #ifdef MMXLIGHT_HAVE_READLINE
00227
00228 static bool fed;
00229
00230 static int
00231 passive_newline(int a, int b) {
00232 (void) a;
00233 (void) b;
00234 rl_crlf ();
00235 rl_on_new_line ();
00236 fed = false;
00237 rl_done = 1;
00238 return 0;
00239 }
00240
00241 static int
00242 active_newline(int a, int b) {
00243 (void) a;
00244 (void) b;
00245 rl_crlf ();
00246 rl_on_new_line ();
00247 fed = true;
00248 rl_done = 1;
00249 return 0;
00250 }
00251
00252 #endif // MMXLIGHT_HAVE_READLINE
00253
00254 #ifdef MMXLIGHT_HAVE_READLINE
00255
00256 bool
00257 itf_terminal_input (string& buffer) {
00258 string prompt, promptc;
00259 string s;
00260 bool b;
00261 nat i, size;
00262 vector<string> v;
00263 char* tmp;
00264 buffer = "";
00265 fed = false;
00266 size = 0;
00267
00268 HIST_ENTRY* last_entry;
00269 HISTORY_STATE* history = history_get_history_state ();
00270
00271 if (quiet_flag) {
00272 prompt = "";
00273 promptc= "";
00274 }
00275 else {
00276 string next= as_string (get_interactive_number () + 1);
00277 prompt = next * "] ";
00278 promptc = "";
00279 for (i=0; i < N(next); i++)
00280 promptc << " ";
00281 promptc << "] ";
00282 }
00283
00284
00285 while (true) {
00286 if (completion_flag)
00287 rl_attempted_completion_function = complete;
00288 rl_bind_key (RETURN, active_newline);
00289 rl_bind_key (META(RETURN), passive_newline);
00290
00291 b = read_line (prompt, s);
00292 v << s;
00293 size += N(s);
00294 buffer << s << "\n";
00295 if (N(s) > 0) {
00296 tmp = as_charp(s);
00297 if (history->length == 0)
00298 last_entry = NULL;
00299 else
00300 last_entry = history -> entries[history->length-1];
00301 if ((last_entry == NULL) ||
00302 ((last_entry != NULL) && (strcmp (tmp, last_entry->line) != 0))) {
00303 add_history (tmp);
00304 itf_save_history ();
00305 itf_save_session ();
00306 }
00307 free_charp (tmp);
00308 }
00309 if (fed || !b) {
00310 if (size > 0)
00311 store_interactive_source (recompose (v, "\n"));
00312 else
00313 buffer = "";
00314 itf_save_history ();
00315 itf_save_session ();
00316 return b;
00317 }
00318 prompt = promptc;
00319 }
00320 }
00321
00322 #else
00323
00324 bool
00325 itf_terminal_input (string& buffer) {
00326 vector<string> v;
00327 string prompt;
00328 bool b;
00329 buffer = "";
00330
00331
00332 if (quiet_flag)
00333 prompt = "";
00334 else
00335 prompt = as_string (get_interactive_number () + 1) * "] ";
00336 b = itf_read_line (prompt, buffer);
00337 if (N(buffer) != 0) {
00338 v << buffer;
00339 store_interactive_source (recompose (v, "\n"));
00340 buffer << "\n";
00341 }
00342 return b;
00343 }
00344 #endif // MMXLIGHT_HAVE_READLINE
00345
00346 bool
00347 itf_terminal_batch_input (string& buffer) {
00348 string s;
00349 bool b;
00350 vector<string> v;
00351 buffer = "";
00352 while (true) {
00353 b = raw_read_line (s);
00354 buffer << s << "\n";
00355 v << s;
00356 if (!b) {
00357 store_interactive_source (recompose (v, "\n"));
00358 return b;
00359 }
00360 }
00361 }
00362
00363 }