1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1996-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <cstdlib> 31 #include <cstring> 32 33 #include <string> 34 35 #include "cmd-edit.h" 36 #include "cmd-hist.h" 37 #include "file-ops.h" 38 #include "file-stat.h" 39 #include "lo-error.h" 40 #include "lo-utils.h" 41 #include "oct-env.h" 42 #include "oct-mutex.h" 43 #include "oct-time.h" 44 #include "quit.h" 45 #include "singleton-cleanup.h" 46 #include "strdup-wrapper.h" 47 #include "unistd-wrappers.h" 48 49 #if defined (USE_READLINE) 50 #include <cstdio> 51 52 #include "oct-rl-edit.h" 53 #endif 54 55 namespace octave 56 { 57 char * do_completer_word_break_hook (); 58 59 command_editor *command_editor::s_instance = nullptr; 60 61 std::set<command_editor::startup_hook_fcn> command_editor::startup_hook_set; 62 63 std::set<command_editor::pre_input_hook_fcn> command_editor::pre_input_hook_set; 64 65 std::set<command_editor::event_hook_fcn> command_editor::event_hook_set; 66 67 static mutex event_hook_lock; 68 69 #if defined (USE_READLINE) 70 71 class 72 gnu_readline : public command_editor 73 { 74 public: 75 76 typedef command_editor::startup_hook_fcn startup_hook_fcn; 77 78 typedef command_editor::pre_input_hook_fcn pre_input_hook_fcn; 79 80 typedef command_editor::event_hook_fcn event_hook_fcn; 81 82 typedef command_editor::completion_fcn completion_fcn; 83 84 gnu_readline (void); 85 86 ~gnu_readline (void) = default; 87 88 void do_set_name (const std::string& n); 89 90 std::string do_readline (const std::string& prompt, bool& eof); 91 92 void do_set_input_stream (FILE *f); 93 94 FILE * do_get_input_stream (void); 95 96 void do_set_output_stream (FILE *f); 97 98 FILE * do_get_output_stream (void); 99 100 void do_redisplay (void); 101 102 int do_terminal_rows (void); 103 104 int do_terminal_cols (void); 105 106 void do_clear_screen (bool skip_redisplay); 107 108 void do_resize_terminal (void); 109 110 void do_set_screen_size (int ht, int wd); 111 112 std::string newline_chars (void); 113 114 void do_restore_terminal_state (void); 115 116 void do_blink_matching_paren (bool flag); 117 118 bool do_erase_empty_line (bool flag); 119 120 void do_set_basic_word_break_characters (const std::string& s); 121 122 void do_set_completer_word_break_characters (const std::string& s); 123 124 void do_set_basic_quote_characters (const std::string& s); 125 126 void do_set_filename_quote_characters (const std::string& s); 127 128 void do_set_completer_quote_characters (const std::string& s); 129 130 void do_set_completion_append_character (char c); 131 132 void do_set_completion_function (completion_fcn f); 133 134 void do_set_quoting_function (quoting_fcn f); 135 136 void do_set_dequoting_function (dequoting_fcn f); 137 138 void do_set_char_is_quoted_function (char_is_quoted_fcn f); 139 140 void do_set_user_accept_line_function (user_accept_line_fcn f); 141 142 completion_fcn do_get_completion_function (void) const; 143 144 quoting_fcn do_get_quoting_function (void) const; 145 146 dequoting_fcn do_get_dequoting_function (void) const; 147 148 char_is_quoted_fcn do_get_char_is_quoted_function (void) const; 149 150 user_accept_line_fcn do_get_user_accept_line_function (void) const; 151 152 string_vector 153 do_generate_filename_completions (const std::string& text); 154 155 std::string do_get_line_buffer (void) const; 156 157 std::string do_get_current_line (void) const; 158 159 char do_get_prev_char (int) const; 160 161 void do_replace_line (const std::string& text, bool clear_undo); 162 163 void do_kill_full_line (void); 164 165 void do_insert_text (const std::string& text); 166 167 void do_newline (void); 168 169 void do_accept_line (void); 170 171 bool do_undo (void); 172 173 void do_clear_undo_list (void); 174 175 void set_startup_hook (startup_hook_fcn f); 176 177 void restore_startup_hook (void); 178 179 void set_pre_input_hook (pre_input_hook_fcn f); 180 181 void restore_pre_input_hook (void); 182 183 void set_event_hook (event_hook_fcn f); 184 185 void restore_event_hook (void); 186 187 void do_restore_event_hook (void); 188 189 void do_read_init_file (const std::string& file); 190 191 void do_re_read_init_file (void); 192 193 bool do_filename_completion_desired (bool); 194 195 bool do_filename_quoting_desired (bool); 196 197 bool do_prefer_env_winsize (bool); 198 199 void do_interrupt (bool); 200 201 void do_handle_interrupt_signal (void); 202 203 static int operate_and_get_next (int, int); 204 205 static int history_search_backward (int, int); 206 207 static int history_search_forward (int, int); 208 209 private: 210 211 startup_hook_fcn previous_startup_hook; 212 213 pre_input_hook_fcn previous_pre_input_hook; 214 215 event_hook_fcn previous_event_hook; 216 217 completion_fcn completion_function; 218 219 quoting_fcn quoting_function; 220 221 dequoting_fcn dequoting_function; 222 223 char_is_quoted_fcn char_is_quoted_function; 224 225 user_accept_line_fcn user_accept_line_function; 226 227 static std::string completer_quote_characters; 228 229 static char * command_generator (const char *text, int state); 230 231 static char * command_quoter (char *text, int match_type, char *quote_pointer); 232 static char * command_dequoter (char *text, int match_type); 233 234 static int command_char_is_quoted (char *text, int index); 235 236 static int command_accept_line (int count, int key); 237 238 static char ** command_completer (const char *text, int start, int end); 239 240 static char * do_completer_word_break_hook (); 241 }; 242 243 std::string gnu_readline::completer_quote_characters = ""; 244 gnu_readline()245 gnu_readline::gnu_readline () 246 : command_editor (), previous_startup_hook (nullptr), 247 previous_pre_input_hook (nullptr), 248 previous_event_hook (nullptr), completion_function (nullptr), 249 quoting_function (nullptr), dequoting_function (nullptr), 250 char_is_quoted_function (nullptr), user_accept_line_function (nullptr) 251 { 252 // FIXME: need interface to rl_add_defun, rl_initialize, and 253 // a function to set rl_terminal_name 254 255 std::string term = sys::env::getenv ("TERM"); 256 257 octave_rl_set_terminal_name (term.c_str ()); 258 259 octave_rl_initialize (); 260 261 do_blink_matching_paren (true); 262 263 // Bind operate-and-get-next. 264 265 octave_rl_add_defun ("operate-and-get-next", 266 gnu_readline::operate_and_get_next, 267 octave_rl_ctrl ('O')); 268 } 269 270 void do_set_name(const std::string & nm)271 gnu_readline::do_set_name (const std::string& nm) 272 { 273 ::octave_rl_set_name (nm.c_str ()); 274 } 275 276 std::string do_readline(const std::string & prompt,bool & eof)277 gnu_readline::do_readline (const std::string& prompt, bool& eof) 278 { 279 std::string retval; 280 281 eof = false; 282 283 const char *p = prompt.c_str (); 284 285 char *line = ::octave_rl_readline (p); 286 287 if (line) 288 { 289 retval = line; 290 291 free (line); 292 } 293 else 294 eof = true; 295 296 return retval; 297 } 298 299 void do_set_input_stream(FILE * f)300 gnu_readline::do_set_input_stream (FILE *f) 301 { 302 ::octave_rl_set_input_stream (f); 303 } 304 305 FILE * do_get_input_stream(void)306 gnu_readline::do_get_input_stream (void) 307 { 308 return ::octave_rl_get_input_stream (); 309 } 310 311 void do_set_output_stream(FILE * f)312 gnu_readline::do_set_output_stream (FILE *f) 313 { 314 ::octave_rl_set_output_stream (f); 315 } 316 317 FILE * do_get_output_stream(void)318 gnu_readline::do_get_output_stream (void) 319 { 320 return ::octave_rl_get_output_stream (); 321 } 322 323 void do_redisplay(void)324 gnu_readline::do_redisplay (void) 325 { 326 ::octave_rl_redisplay (); 327 } 328 329 // GNU readline handles SIGWINCH, so these values have a good chance 330 // of being correct even if the window changes size (they may be 331 // wrong if, for example, the luser changes the window size while the 332 // pager is running, and the signal is handled by the pager instead of 333 // us. 334 335 int do_terminal_rows(void)336 gnu_readline::do_terminal_rows (void) 337 { 338 int sh = ::octave_rl_screen_height (); 339 340 return sh > 0 ? sh : 24; 341 } 342 343 int do_terminal_cols(void)344 gnu_readline::do_terminal_cols (void) 345 { 346 int sw = ::octave_rl_screen_width (); 347 348 return sw > 0 ? sw : 80; 349 } 350 351 void do_clear_screen(bool skip_redisplay)352 gnu_readline::do_clear_screen (bool skip_redisplay) 353 { 354 ::octave_rl_clear_screen (skip_redisplay); 355 } 356 357 void do_resize_terminal(void)358 gnu_readline::do_resize_terminal (void) 359 { 360 ::octave_rl_resize_terminal (); 361 } 362 363 void do_set_screen_size(int ht,int wd)364 gnu_readline::do_set_screen_size (int ht, int wd) 365 { 366 ::octave_rl_set_screen_size (ht, wd); 367 } 368 369 std::string newline_chars(void)370 gnu_readline::newline_chars (void) 371 { 372 return "\r\n"; 373 } 374 375 void do_restore_terminal_state(void)376 gnu_readline::do_restore_terminal_state (void) 377 { 378 ::octave_rl_restore_terminal_state (); 379 } 380 381 void do_blink_matching_paren(bool flag)382 gnu_readline::do_blink_matching_paren (bool flag) 383 { 384 ::octave_rl_enable_paren_matching (flag ? 1 : 0); 385 } 386 387 bool do_erase_empty_line(bool flag)388 gnu_readline::do_erase_empty_line (bool flag) 389 { 390 return ::octave_rl_erase_empty_line (flag ? 1 : 0); 391 } 392 393 void do_set_basic_word_break_characters(const std::string & s)394 gnu_readline::do_set_basic_word_break_characters (const std::string& s) 395 { 396 ::octave_rl_set_basic_word_break_characters (s.c_str ()); 397 } 398 399 void do_set_completer_word_break_characters(const std::string & s)400 gnu_readline::do_set_completer_word_break_characters (const std::string& s) 401 { 402 ::octave_rl_set_completer_word_break_characters (s.c_str ()); 403 404 ::octave_rl_set_completion_word_break_hook 405 (gnu_readline::do_completer_word_break_hook); 406 407 } 408 409 void do_set_basic_quote_characters(const std::string & s)410 gnu_readline::do_set_basic_quote_characters (const std::string& s) 411 { 412 ::octave_rl_set_basic_quote_characters (s.c_str ()); 413 } 414 415 void do_set_filename_quote_characters(const std::string & s)416 gnu_readline::do_set_filename_quote_characters (const std::string& s) 417 { 418 ::octave_rl_set_filename_quote_characters (s.c_str ()); 419 } 420 421 void do_set_completer_quote_characters(const std::string & s)422 gnu_readline::do_set_completer_quote_characters (const std::string& s) 423 { 424 completer_quote_characters = s; 425 } 426 427 void do_set_completion_append_character(char c)428 gnu_readline::do_set_completion_append_character (char c) 429 { 430 ::octave_rl_set_completion_append_character (c); 431 } 432 433 void do_set_completion_function(completion_fcn f)434 gnu_readline::do_set_completion_function (completion_fcn f) 435 { 436 completion_function = f; 437 438 rl_attempted_completion_fcn_ptr fp 439 = (f ? gnu_readline::command_completer : nullptr); 440 441 ::octave_rl_set_completion_function (fp); 442 } 443 444 void do_set_quoting_function(quoting_fcn f)445 gnu_readline::do_set_quoting_function (quoting_fcn f) 446 { 447 quoting_function = f; 448 449 rl_quoting_fcn_ptr fp 450 = (f ? gnu_readline::command_quoter : nullptr); 451 452 ::octave_rl_set_quoting_function (fp); 453 } 454 455 void do_set_dequoting_function(dequoting_fcn f)456 gnu_readline::do_set_dequoting_function (dequoting_fcn f) 457 { 458 dequoting_function = f; 459 460 rl_dequoting_fcn_ptr fp 461 = (f ? gnu_readline::command_dequoter : nullptr); 462 463 ::octave_rl_set_dequoting_function (fp); 464 } 465 466 void do_set_char_is_quoted_function(char_is_quoted_fcn f)467 gnu_readline::do_set_char_is_quoted_function (char_is_quoted_fcn f) 468 { 469 char_is_quoted_function = f; 470 471 rl_char_is_quoted_fcn_ptr fp 472 = (f ? gnu_readline::command_char_is_quoted : nullptr); 473 474 ::octave_rl_set_char_is_quoted_function (fp); 475 } 476 477 void do_set_user_accept_line_function(user_accept_line_fcn f)478 gnu_readline::do_set_user_accept_line_function (user_accept_line_fcn f) 479 { 480 user_accept_line_function = f; 481 482 if (f) 483 octave_rl_add_defun ("accept-line", gnu_readline::command_accept_line, 484 ::octave_rl_ctrl ('M')); 485 else 486 octave_rl_add_defun ("accept-line", ::octave_rl_newline, 487 ::octave_rl_ctrl ('M')); 488 } 489 490 gnu_readline::completion_fcn do_get_completion_function(void) const491 gnu_readline::do_get_completion_function (void) const 492 { 493 return completion_function; 494 } 495 496 gnu_readline::quoting_fcn do_get_quoting_function(void) const497 gnu_readline::do_get_quoting_function (void) const 498 { 499 return quoting_function; 500 } 501 502 gnu_readline::dequoting_fcn do_get_dequoting_function(void) const503 gnu_readline::do_get_dequoting_function (void) const 504 { 505 return dequoting_function; 506 } 507 508 gnu_readline::char_is_quoted_fcn do_get_char_is_quoted_function(void) const509 gnu_readline::do_get_char_is_quoted_function (void) const 510 { 511 return char_is_quoted_function; 512 } 513 514 gnu_readline::user_accept_line_fcn do_get_user_accept_line_function(void) const515 gnu_readline::do_get_user_accept_line_function (void) const 516 { 517 return user_accept_line_function; 518 } 519 520 // True if the last "word" of the string line (delimited by delim) is 521 // an existing directory. Used by do_completer_word_break_hook. 522 523 static bool looks_like_filename(const char * line,char delim)524 looks_like_filename (const char *line, char delim) 525 { 526 bool retval = false; 527 528 const char *s = strrchr (line, delim); 529 530 if (s) 531 { 532 // Remove incomplete component. 533 const char *f = strrchr (line, sys::file_ops::dir_sep_char ()); 534 535 if (f && (s[1] == '~' || f != s)) 536 { 537 // For something like "A /b", f==s; don't assume a file. 538 539 std::string candidate_filename = s+1; 540 541 candidate_filename = candidate_filename.substr (0, f - s); 542 543 // Handles any complete ~<username>, but doesn't expand usernames. 544 545 if (candidate_filename[0] == '~') 546 candidate_filename 547 = sys::file_ops::tilde_expand (candidate_filename); 548 549 sys::file_stat fs (candidate_filename); 550 551 retval = fs.is_dir (); 552 } 553 } 554 555 return retval; 556 } 557 558 // Decide whether to interpret partial commands like "abc/def" as a 559 // filename or division. Return the set of delimiters appropriate for 560 // the decision. 561 562 char * do_completer_word_break_hook()563 gnu_readline::do_completer_word_break_hook () 564 { 565 static char *dir_sep = octave_strdup_wrapper (" '\""); 566 567 std::string word; 568 std::string line = get_line_buffer (); 569 570 // For now, assume space or quote delimiter for file names. 571 const char *l = line.c_str (); 572 573 if (looks_like_filename (l, ' ') || looks_like_filename (l, '\'') 574 || looks_like_filename (l, '"')) 575 { 576 ::octave_rl_set_completer_quote_characters 577 (completer_quote_characters.c_str ()); 578 579 return dir_sep; 580 } 581 else 582 { 583 ::octave_rl_set_completer_quote_characters (""); 584 585 return octave_rl_get_completer_word_break_characters (); 586 } 587 } 588 589 string_vector do_generate_filename_completions(const std::string & text)590 gnu_readline::do_generate_filename_completions (const std::string& text) 591 { 592 string_vector retval; 593 594 int n = 0; 595 int count = 0; 596 597 char *fn = nullptr; 598 599 while (1) 600 { 601 fn = ::octave_rl_filename_completion_function (text.c_str (), count); 602 603 if (fn) 604 { 605 if (count == n) 606 { 607 // Famous last words: Most large directories will not 608 // have more than a few hundred files, so we should not 609 // resize too many times even if the growth is linear... 610 n += 100; 611 retval.resize (n); 612 } 613 614 retval[count++] = fn; 615 616 free (fn); 617 } 618 else 619 break; 620 } 621 622 retval.resize (count); 623 624 return retval; 625 } 626 627 std::string do_get_line_buffer(void) const628 gnu_readline::do_get_line_buffer (void) const 629 { 630 return ::octave_rl_line_buffer (); 631 } 632 633 std::string do_get_current_line(void) const634 gnu_readline::do_get_current_line (void) const 635 { 636 std::string retval; 637 char *buf = ::octave_rl_copy_line (); 638 retval = buf; 639 free (buf); 640 return retval; 641 } 642 643 // Return the character (offset+1) to the left of the cursor, 644 // or '\0' if the cursor is at the start of the line. 645 char do_get_prev_char(int offset) const646 gnu_readline::do_get_prev_char (int offset) const 647 { 648 const char *buf = ::octave_rl_line_buffer (); 649 int p = ::octave_rl_point (); 650 651 return p > offset ? buf[p - offset - 1] : '\0'; 652 } 653 654 void do_replace_line(const std::string & text,bool clear_undo)655 gnu_readline::do_replace_line (const std::string& text, bool clear_undo) 656 { 657 ::octave_rl_replace_line (text.c_str (), clear_undo); 658 } 659 660 void do_kill_full_line(void)661 gnu_readline::do_kill_full_line (void) 662 { 663 ::octave_rl_kill_full_line (); 664 } 665 666 void do_insert_text(const std::string & text)667 gnu_readline::do_insert_text (const std::string& text) 668 { 669 ::octave_rl_insert_text (text.c_str ()); 670 } 671 672 void do_newline(void)673 gnu_readline::do_newline (void) 674 { 675 ::octave_rl_newline (1, '\n'); 676 } 677 678 void do_accept_line(void)679 gnu_readline::do_accept_line (void) 680 { 681 command_accept_line (1, '\n'); 682 } 683 684 bool do_undo(void)685 gnu_readline::do_undo (void) 686 { 687 return ::octave_rl_do_undo (); 688 } 689 690 void do_clear_undo_list()691 gnu_readline::do_clear_undo_list () 692 { 693 ::octave_rl_clear_undo_list (); 694 } 695 696 void set_startup_hook(startup_hook_fcn f)697 gnu_readline::set_startup_hook (startup_hook_fcn f) 698 { 699 previous_startup_hook = ::octave_rl_get_startup_hook (); 700 701 if (f != previous_startup_hook) 702 ::octave_rl_set_startup_hook (f); 703 } 704 705 void restore_startup_hook(void)706 gnu_readline::restore_startup_hook (void) 707 { 708 ::octave_rl_set_startup_hook (previous_startup_hook); 709 } 710 711 void set_pre_input_hook(pre_input_hook_fcn f)712 gnu_readline::set_pre_input_hook (pre_input_hook_fcn f) 713 { 714 previous_pre_input_hook = ::octave_rl_get_pre_input_hook (); 715 716 if (f != previous_pre_input_hook) 717 ::octave_rl_set_pre_input_hook (f); 718 } 719 720 void restore_pre_input_hook(void)721 gnu_readline::restore_pre_input_hook (void) 722 { 723 ::octave_rl_set_pre_input_hook (previous_pre_input_hook); 724 } 725 726 void set_event_hook(event_hook_fcn f)727 gnu_readline::set_event_hook (event_hook_fcn f) 728 { 729 previous_event_hook = octave_rl_get_event_hook (); 730 731 ::octave_rl_set_event_hook (f); 732 } 733 734 void restore_event_hook(void)735 gnu_readline::restore_event_hook (void) 736 { 737 ::octave_rl_set_event_hook (previous_event_hook); 738 } 739 740 void do_read_init_file(const std::string & file)741 gnu_readline::do_read_init_file (const std::string& file) 742 { 743 ::octave_rl_read_init_file (file.c_str ()); 744 } 745 746 void do_re_read_init_file(void)747 gnu_readline::do_re_read_init_file (void) 748 { 749 ::octave_rl_re_read_init_file (); 750 } 751 752 bool do_filename_completion_desired(bool arg)753 gnu_readline::do_filename_completion_desired (bool arg) 754 { 755 return ::octave_rl_filename_completion_desired (arg); 756 } 757 758 bool do_filename_quoting_desired(bool arg)759 gnu_readline::do_filename_quoting_desired (bool arg) 760 { 761 return ::octave_rl_filename_quoting_desired (arg); 762 } 763 764 bool do_prefer_env_winsize(bool arg)765 gnu_readline::do_prefer_env_winsize (bool arg) 766 { 767 return ::octave_rl_prefer_env_winsize (arg); 768 } 769 770 void do_interrupt(bool arg)771 gnu_readline::do_interrupt (bool arg) 772 { 773 ::octave_rl_done (arg); 774 } 775 776 void do_handle_interrupt_signal(void)777 gnu_readline::do_handle_interrupt_signal (void) 778 { 779 octave_signal_caught = 0; 780 octave_interrupt_state = 0; 781 782 ::octave_rl_recover_from_interrupt (); 783 784 throw interrupt_exception (); 785 } 786 787 int operate_and_get_next(int,int)788 gnu_readline::operate_and_get_next (int /* count */, int /* c */) 789 { 790 // Accept the current line. 791 792 command_editor::accept_line (); 793 794 // Find the current line, and find the next line to use. 795 796 int x_where = command_history::where (); 797 798 int x_length = command_history::length (); 799 800 if ((command_history::is_stifled () 801 && (x_length >= command_history::max_input_history ())) 802 || (x_where >= x_length - 1)) 803 command_history::set_mark (x_where); 804 else 805 command_history::set_mark (x_where + 1); 806 807 command_editor::add_startup_hook (command_history::goto_mark); 808 809 return 0; 810 } 811 812 int history_search_backward(int count,int c)813 gnu_readline::history_search_backward (int count, int c) 814 { 815 return octave_rl_history_search_backward (count, c); 816 } 817 818 int history_search_forward(int count,int c)819 gnu_readline::history_search_forward (int count, int c) 820 { 821 return octave_rl_history_search_forward (count, c); 822 } 823 824 char * command_generator(const char * text,int state)825 gnu_readline::command_generator (const char *text, int state) 826 { 827 char *retval = nullptr; 828 829 completion_fcn f = command_editor::get_completion_function (); 830 831 std::string tmp = f (text, state); 832 833 std::size_t len = tmp.length (); 834 835 if (len > 0) 836 { 837 retval = static_cast<char *> (std::malloc (len+1)); 838 839 if (retval) 840 strcpy (retval, tmp.c_str ()); 841 } 842 843 return retval; 844 } 845 846 char * command_quoter(char * text,int matches,char * qcp)847 gnu_readline::command_quoter (char *text, int matches, char *qcp) 848 { 849 char *retval = nullptr; 850 851 quoting_fcn f = command_editor::get_quoting_function (); 852 853 std::string tmp = f (text, matches, *qcp); 854 855 std::size_t len = tmp.length (); 856 857 if (len > 0) 858 { 859 retval = static_cast<char *> (std::malloc (len+1)); 860 861 if (retval) 862 strcpy (retval, tmp.c_str ()); 863 } 864 865 return retval; 866 } 867 868 char * command_dequoter(char * text,int quote)869 gnu_readline::command_dequoter (char *text, int quote) 870 { 871 char *retval = nullptr; 872 873 dequoting_fcn f = command_editor::get_dequoting_function (); 874 875 std::string tmp = f (text, quote); 876 877 std::size_t len = tmp.length (); 878 879 if (len > 0) 880 { 881 retval = static_cast<char *> (std::malloc (len+1)); 882 883 if (retval) 884 strcpy (retval, tmp.c_str ()); 885 } 886 887 return retval; 888 } 889 890 int command_char_is_quoted(char * text,int quote)891 gnu_readline::command_char_is_quoted (char *text, int quote) 892 { 893 char_is_quoted_fcn f = command_editor::get_char_is_quoted_function (); 894 895 return f (text, quote); 896 } 897 898 int command_accept_line(int count,int key)899 gnu_readline::command_accept_line (int count, int key) 900 { 901 user_accept_line_fcn f = command_editor::get_user_accept_line_function (); 902 903 if (f) 904 f (::octave_rl_line_buffer ()); 905 906 ::octave_rl_redisplay (); 907 908 return ::octave_rl_newline (count, key); 909 } 910 911 char ** command_completer(const char * text,int,int)912 gnu_readline::command_completer (const char *text, int, int) 913 { 914 char **matches 915 = ::octave_rl_completion_matches (text, gnu_readline::command_generator); 916 917 return matches; 918 } 919 920 #endif 921 922 class 923 default_command_editor : public command_editor 924 { 925 public: 926 default_command_editor(void)927 default_command_editor (void) 928 : command_editor (), input_stream (stdin), output_stream (stdout) { } 929 930 // No copying! 931 932 default_command_editor (const default_command_editor&) = delete; 933 934 default_command_editor& operator = (const default_command_editor&) = delete; 935 936 ~default_command_editor (void) = default; 937 938 std::string do_readline (const std::string& prompt, bool& eof); 939 940 void do_set_input_stream (FILE *f); 941 942 FILE * do_get_input_stream (void); 943 944 void do_set_output_stream (FILE *f); 945 946 FILE * do_get_output_stream (void); 947 948 string_vector do_generate_filename_completions (const std::string& text); 949 950 std::string do_get_line_buffer (void) const; 951 952 std::string do_get_current_line (void) const; 953 954 char do_get_prev_char (int) const; 955 956 void do_replace_line (const std::string& text, bool clear_undo); 957 958 void do_kill_full_line (void); 959 960 void do_insert_text (const std::string& text); 961 962 void do_newline (void); 963 964 void do_accept_line (void); 965 966 private: 967 968 FILE *input_stream; 969 970 FILE *output_stream; 971 }; 972 973 std::string do_readline(const std::string & prompt,bool & eof)974 default_command_editor::do_readline (const std::string& prompt, bool& eof) 975 { 976 std::fputs (prompt.c_str (), output_stream); 977 std::fflush (output_stream); 978 979 return octave_fgetl (input_stream, eof); 980 } 981 982 void do_set_input_stream(FILE * f)983 default_command_editor::do_set_input_stream (FILE *f) 984 { 985 input_stream = f; 986 } 987 988 FILE * do_get_input_stream(void)989 default_command_editor::do_get_input_stream (void) 990 { 991 return input_stream; 992 } 993 994 void do_set_output_stream(FILE * f)995 default_command_editor::do_set_output_stream (FILE *f) 996 { 997 output_stream = f; 998 } 999 1000 FILE * do_get_output_stream(void)1001 default_command_editor::do_get_output_stream (void) 1002 { 1003 return output_stream; 1004 } 1005 1006 string_vector do_generate_filename_completions(const std::string &)1007 default_command_editor::do_generate_filename_completions (const std::string&) 1008 { 1009 // FIXME 1010 return string_vector (); 1011 } 1012 1013 std::string do_get_line_buffer(void) const1014 default_command_editor::do_get_line_buffer (void) const 1015 { 1016 return ""; 1017 } 1018 1019 std::string do_get_current_line(void) const1020 default_command_editor::do_get_current_line (void) const 1021 { 1022 // FIXME 1023 return ""; 1024 } 1025 1026 char do_get_prev_char(int) const1027 default_command_editor::do_get_prev_char (int) const 1028 { 1029 return '\0'; 1030 } 1031 1032 void do_replace_line(const std::string &,bool)1033 default_command_editor::do_replace_line (const std::string&, bool) 1034 { 1035 // FIXME 1036 } 1037 1038 void do_kill_full_line(void)1039 default_command_editor::do_kill_full_line (void) 1040 { 1041 // FIXME 1042 } 1043 1044 void do_insert_text(const std::string &)1045 default_command_editor::do_insert_text (const std::string&) 1046 { 1047 // FIXME 1048 } 1049 1050 void do_newline(void)1051 default_command_editor::do_newline (void) 1052 { 1053 // FIXME 1054 } 1055 1056 void do_accept_line(void)1057 default_command_editor::do_accept_line (void) 1058 { 1059 // FIXME 1060 } 1061 1062 bool instance_ok(void)1063 command_editor::instance_ok (void) 1064 { 1065 bool retval = true; 1066 1067 if (! s_instance) 1068 { 1069 make_command_editor (); 1070 1071 if (s_instance) 1072 { 1073 s_instance->set_event_hook (event_handler); 1074 1075 singleton_cleanup_list::add (cleanup_instance); 1076 } 1077 } 1078 1079 if (! s_instance) 1080 (*current_liboctave_error_handler) 1081 ("unable to create command history object!"); 1082 1083 return retval; 1084 } 1085 1086 void make_command_editor(void)1087 command_editor::make_command_editor (void) 1088 { 1089 #if defined (USE_READLINE) 1090 s_instance = new gnu_readline (); 1091 #else 1092 s_instance = new default_command_editor (); 1093 #endif 1094 } 1095 1096 void force_default_editor(void)1097 command_editor::force_default_editor (void) 1098 { 1099 delete s_instance; 1100 s_instance = new default_command_editor (); 1101 } 1102 1103 void set_initial_input(const std::string & text)1104 command_editor::set_initial_input (const std::string& text) 1105 { 1106 if (instance_ok ()) 1107 s_instance->m_initial_input = text; 1108 } 1109 1110 int insert_initial_input(void)1111 command_editor::insert_initial_input (void) 1112 { 1113 return instance_ok () ? s_instance->do_insert_initial_input () : 0; 1114 } 1115 1116 int startup_handler(void)1117 command_editor::startup_handler (void) 1118 { 1119 // Iterate over a copy of the set to avoid problems if a hook 1120 // function attempts to remove itself from the startup_hook_set. 1121 1122 std::set<startup_hook_fcn> hook_set = startup_hook_set; 1123 1124 for (startup_hook_fcn f : hook_set) 1125 { 1126 if (f) 1127 f (); 1128 } 1129 1130 return 0; 1131 } 1132 1133 int pre_input_handler(void)1134 command_editor::pre_input_handler (void) 1135 { 1136 // Iterate over copy of the set to avoid problems if a hook function 1137 // attempts to remove itself from the pre_input_hook_set. 1138 1139 std::set<pre_input_hook_fcn> hook_set = pre_input_hook_set; 1140 1141 for (pre_input_hook_fcn f : hook_set) 1142 { 1143 if (f) 1144 f (); 1145 } 1146 1147 return 0; 1148 } 1149 1150 int event_handler(void)1151 command_editor::event_handler (void) 1152 { 1153 if (octave_interrupt_state) 1154 handle_interrupt_signal (); 1155 1156 event_hook_lock.lock (); 1157 1158 std::set<event_hook_fcn> hook_set (event_hook_set); 1159 1160 event_hook_lock.unlock (); 1161 1162 for (event_hook_fcn f : hook_set) 1163 { 1164 if (f) 1165 f (); 1166 } 1167 1168 return 0; 1169 } 1170 1171 void set_name(const std::string & n)1172 command_editor::set_name (const std::string& n) 1173 { 1174 if (instance_ok ()) 1175 s_instance->do_set_name (n); 1176 } 1177 1178 std::string readline(const std::string & prompt)1179 command_editor::readline (const std::string& prompt) 1180 { 1181 bool eof; 1182 1183 return readline (prompt, eof); 1184 } 1185 1186 std::string readline(const std::string & prompt,bool & eof)1187 command_editor::readline (const std::string& prompt, bool& eof) 1188 { 1189 std::string retval; 1190 1191 if (instance_ok ()) 1192 { 1193 if (! s_instance->m_initial_input.empty ()) 1194 add_pre_input_hook (command_editor::insert_initial_input); 1195 1196 retval = s_instance->do_readline (prompt, eof); 1197 } 1198 1199 return retval; 1200 } 1201 1202 void set_input_stream(FILE * f)1203 command_editor::set_input_stream (FILE *f) 1204 { 1205 if (instance_ok ()) 1206 s_instance->do_set_input_stream (f); 1207 } 1208 1209 FILE * get_input_stream(void)1210 command_editor::get_input_stream (void) 1211 { 1212 return instance_ok () ? s_instance->do_get_input_stream () : nullptr; 1213 } 1214 1215 void set_output_stream(FILE * f)1216 command_editor::set_output_stream (FILE *f) 1217 { 1218 if (instance_ok ()) 1219 s_instance->do_set_output_stream (f); 1220 } 1221 1222 FILE * get_output_stream(void)1223 command_editor::get_output_stream (void) 1224 { 1225 return instance_ok () ? s_instance->do_get_output_stream () : nullptr; 1226 } 1227 1228 void redisplay(void)1229 command_editor::redisplay (void) 1230 { 1231 if (instance_ok ()) 1232 s_instance->do_redisplay (); 1233 } 1234 1235 int terminal_rows(void)1236 command_editor::terminal_rows (void) 1237 { 1238 return instance_ok () ? s_instance->do_terminal_rows () : -1; 1239 } 1240 1241 int terminal_cols(void)1242 command_editor::terminal_cols (void) 1243 { 1244 return instance_ok () ? s_instance->do_terminal_cols () : -1; 1245 } 1246 1247 void clear_screen(bool skip_redisplay)1248 command_editor::clear_screen (bool skip_redisplay) 1249 { 1250 if (instance_ok ()) 1251 s_instance->do_clear_screen (skip_redisplay); 1252 } 1253 1254 void resize_terminal(void)1255 command_editor::resize_terminal (void) 1256 { 1257 if (instance_ok ()) 1258 s_instance->do_resize_terminal (); 1259 } 1260 1261 void set_screen_size(int ht,int wd)1262 command_editor::set_screen_size (int ht, int wd) 1263 { 1264 if (instance_ok ()) 1265 s_instance->do_set_screen_size (ht, wd); 1266 } 1267 1268 std::string decode_prompt_string(const std::string & s)1269 command_editor::decode_prompt_string (const std::string& s) 1270 { 1271 return instance_ok () ? s_instance->do_decode_prompt_string (s) : ""; 1272 } 1273 1274 int current_command_number(void)1275 command_editor::current_command_number (void) 1276 { 1277 return instance_ok () ? s_instance->m_command_number : 0; 1278 } 1279 1280 void reset_current_command_number(int n)1281 command_editor::reset_current_command_number (int n) 1282 { 1283 if (instance_ok ()) 1284 s_instance->m_command_number = n; 1285 } 1286 1287 void increment_current_command_number(void)1288 command_editor::increment_current_command_number (void) 1289 { 1290 if (instance_ok ()) 1291 s_instance->m_command_number++; 1292 } 1293 1294 void restore_terminal_state(void)1295 command_editor::restore_terminal_state (void) 1296 { 1297 if (instance_ok ()) 1298 s_instance->do_restore_terminal_state (); 1299 } 1300 1301 void blink_matching_paren(bool flag)1302 command_editor::blink_matching_paren (bool flag) 1303 { 1304 if (instance_ok ()) 1305 s_instance->do_blink_matching_paren (flag); 1306 } 1307 1308 bool erase_empty_line(bool flag)1309 command_editor::erase_empty_line (bool flag) 1310 { 1311 return instance_ok () ? s_instance->do_erase_empty_line (flag) : false; 1312 } 1313 1314 void set_basic_word_break_characters(const std::string & s)1315 command_editor::set_basic_word_break_characters (const std::string& s) 1316 { 1317 if (instance_ok ()) 1318 s_instance->do_set_basic_word_break_characters (s); 1319 } 1320 1321 void set_completer_word_break_characters(const std::string & s)1322 command_editor::set_completer_word_break_characters (const std::string& s) 1323 { 1324 if (instance_ok ()) 1325 s_instance->do_set_completer_word_break_characters (s); 1326 } 1327 1328 void set_basic_quote_characters(const std::string & s)1329 command_editor::set_basic_quote_characters (const std::string& s) 1330 { 1331 if (instance_ok ()) 1332 s_instance->do_set_basic_quote_characters (s); 1333 } 1334 1335 void set_filename_quote_characters(const std::string & s)1336 command_editor::set_filename_quote_characters (const std::string& s) 1337 { 1338 if (instance_ok ()) 1339 s_instance->do_set_filename_quote_characters (s); 1340 } 1341 1342 void set_completer_quote_characters(const std::string & s)1343 command_editor::set_completer_quote_characters (const std::string& s) 1344 { 1345 if (instance_ok ()) 1346 s_instance->do_set_completer_quote_characters (s); 1347 } 1348 1349 void set_completion_append_character(char c)1350 command_editor::set_completion_append_character (char c) 1351 { 1352 if (instance_ok ()) 1353 s_instance->do_set_completion_append_character (c); 1354 } 1355 1356 void set_completion_function(completion_fcn f)1357 command_editor::set_completion_function (completion_fcn f) 1358 { 1359 if (instance_ok ()) 1360 s_instance->do_set_completion_function (f); 1361 } 1362 1363 void set_quoting_function(quoting_fcn f)1364 command_editor::set_quoting_function (quoting_fcn f) 1365 { 1366 if (instance_ok ()) 1367 s_instance->do_set_quoting_function (f); 1368 } 1369 1370 void set_dequoting_function(dequoting_fcn f)1371 command_editor::set_dequoting_function (dequoting_fcn f) 1372 { 1373 if (instance_ok ()) 1374 s_instance->do_set_dequoting_function (f); 1375 } 1376 1377 void set_char_is_quoted_function(char_is_quoted_fcn f)1378 command_editor::set_char_is_quoted_function (char_is_quoted_fcn f) 1379 { 1380 if (instance_ok ()) 1381 s_instance->do_set_char_is_quoted_function (f); 1382 } 1383 1384 void set_user_accept_line_function(user_accept_line_fcn f)1385 command_editor::set_user_accept_line_function (user_accept_line_fcn f) 1386 { 1387 if (instance_ok ()) 1388 s_instance->do_set_user_accept_line_function (f); 1389 } 1390 1391 command_editor::completion_fcn get_completion_function(void)1392 command_editor::get_completion_function (void) 1393 { 1394 return instance_ok () ? s_instance->do_get_completion_function () : nullptr; 1395 } 1396 1397 command_editor::quoting_fcn get_quoting_function(void)1398 command_editor::get_quoting_function (void) 1399 { 1400 return instance_ok () ? s_instance->do_get_quoting_function () : nullptr; 1401 } 1402 1403 command_editor::dequoting_fcn get_dequoting_function(void)1404 command_editor::get_dequoting_function (void) 1405 { 1406 return instance_ok () ? s_instance->do_get_dequoting_function () : nullptr; 1407 } 1408 1409 command_editor::char_is_quoted_fcn get_char_is_quoted_function(void)1410 command_editor::get_char_is_quoted_function (void) 1411 { 1412 return (instance_ok () 1413 ? s_instance->do_get_char_is_quoted_function () : nullptr); 1414 } 1415 1416 command_editor::user_accept_line_fcn get_user_accept_line_function(void)1417 command_editor::get_user_accept_line_function (void) 1418 { 1419 return (instance_ok () 1420 ? s_instance->do_get_user_accept_line_function () : nullptr); 1421 } 1422 1423 string_vector generate_filename_completions(const std::string & text)1424 command_editor::generate_filename_completions (const std::string& text) 1425 { 1426 return (instance_ok () 1427 ? s_instance->do_generate_filename_completions (text) 1428 : string_vector ()); 1429 } 1430 1431 std::string get_line_buffer(void)1432 command_editor::get_line_buffer (void) 1433 { 1434 return instance_ok () ? s_instance->do_get_line_buffer () : ""; 1435 } 1436 1437 std::string get_current_line(void)1438 command_editor::get_current_line (void) 1439 { 1440 return instance_ok () ? s_instance->do_get_current_line () : ""; 1441 } 1442 1443 // Return the character (offset+1) to the left of the cursor, 1444 // or '\0' if the cursor is at the start of the line. 1445 char get_prev_char(int offset)1446 command_editor::get_prev_char (int offset) 1447 { 1448 return instance_ok () ? s_instance->do_get_prev_char (offset) : '\0'; 1449 } 1450 1451 void replace_line(const std::string & text,bool clear_undo)1452 command_editor::replace_line (const std::string& text, bool clear_undo) 1453 { 1454 if (instance_ok ()) 1455 s_instance->do_replace_line (text, clear_undo); 1456 } 1457 1458 void kill_full_line(void)1459 command_editor::kill_full_line (void) 1460 { 1461 if (instance_ok ()) 1462 s_instance->do_kill_full_line (); 1463 } 1464 1465 void insert_text(const std::string & text)1466 command_editor::insert_text (const std::string& text) 1467 { 1468 if (instance_ok ()) 1469 s_instance->do_insert_text (text); 1470 } 1471 1472 void newline(void)1473 command_editor::newline (void) 1474 { 1475 if (instance_ok ()) 1476 s_instance->do_newline (); 1477 } 1478 1479 void accept_line(void)1480 command_editor::accept_line (void) 1481 { 1482 if (instance_ok ()) 1483 s_instance->do_accept_line (); 1484 } 1485 1486 bool undo(void)1487 command_editor::undo (void) 1488 { 1489 return instance_ok () ? s_instance->do_undo () : false; 1490 } 1491 1492 void clear_undo_list(void)1493 command_editor::clear_undo_list (void) 1494 { 1495 if (instance_ok ()) 1496 s_instance->do_clear_undo_list (); 1497 } 1498 1499 void add_startup_hook(startup_hook_fcn f)1500 command_editor::add_startup_hook (startup_hook_fcn f) 1501 { 1502 if (instance_ok ()) 1503 { 1504 startup_hook_set.insert (f); 1505 1506 s_instance->set_startup_hook (startup_handler); 1507 } 1508 } 1509 1510 void remove_startup_hook(startup_hook_fcn f)1511 command_editor::remove_startup_hook (startup_hook_fcn f) 1512 { 1513 if (instance_ok ()) 1514 { 1515 auto p = startup_hook_set.find (f); 1516 1517 if (p != startup_hook_set.end ()) 1518 startup_hook_set.erase (p); 1519 1520 if (startup_hook_set.empty ()) 1521 s_instance->restore_startup_hook (); 1522 } 1523 } 1524 1525 void add_pre_input_hook(pre_input_hook_fcn f)1526 command_editor::add_pre_input_hook (pre_input_hook_fcn f) 1527 { 1528 if (instance_ok ()) 1529 { 1530 pre_input_hook_set.insert (f); 1531 1532 s_instance->set_pre_input_hook (pre_input_handler); 1533 } 1534 } 1535 1536 void remove_pre_input_hook(pre_input_hook_fcn f)1537 command_editor::remove_pre_input_hook (pre_input_hook_fcn f) 1538 { 1539 if (instance_ok ()) 1540 { 1541 auto p = pre_input_hook_set.find (f); 1542 1543 if (p != pre_input_hook_set.end ()) 1544 pre_input_hook_set.erase (p); 1545 1546 if (pre_input_hook_set.empty ()) 1547 s_instance->restore_pre_input_hook (); 1548 } 1549 } 1550 1551 void add_event_hook(event_hook_fcn f)1552 command_editor::add_event_hook (event_hook_fcn f) 1553 { 1554 autolock guard (event_hook_lock); 1555 1556 event_hook_set.insert (f); 1557 } 1558 1559 void remove_event_hook(event_hook_fcn f)1560 command_editor::remove_event_hook (event_hook_fcn f) 1561 { 1562 autolock guard (event_hook_lock); 1563 1564 auto p = event_hook_set.find (f); 1565 1566 if (p != event_hook_set.end ()) 1567 event_hook_set.erase (p); 1568 1569 } 1570 1571 void run_event_hooks(void)1572 command_editor::run_event_hooks (void) 1573 { 1574 event_handler (); 1575 } 1576 1577 void read_init_file(const std::string & file_arg)1578 command_editor::read_init_file (const std::string& file_arg) 1579 { 1580 if (instance_ok ()) 1581 { 1582 std::string file = sys::file_ops::tilde_expand (file_arg); 1583 1584 s_instance->do_read_init_file (file); 1585 } 1586 } 1587 1588 void re_read_init_file(void)1589 command_editor::re_read_init_file (void) 1590 { 1591 if (instance_ok ()) 1592 s_instance->do_re_read_init_file (); 1593 } 1594 1595 bool filename_completion_desired(bool arg)1596 command_editor::filename_completion_desired (bool arg) 1597 { 1598 return (instance_ok () 1599 ? s_instance->do_filename_completion_desired (arg) : false); 1600 } 1601 1602 bool filename_quoting_desired(bool arg)1603 command_editor::filename_quoting_desired (bool arg) 1604 { 1605 return (instance_ok ()) 1606 ? s_instance->do_filename_quoting_desired (arg) : false; 1607 } 1608 1609 bool prefer_env_winsize(bool arg)1610 command_editor::prefer_env_winsize (bool arg) 1611 { 1612 return instance_ok () ? s_instance->do_prefer_env_winsize (arg) : false; 1613 } 1614 1615 bool interrupt(bool arg)1616 command_editor::interrupt (bool arg) 1617 { 1618 bool retval; 1619 1620 if (instance_ok ()) 1621 { 1622 // Return the current interrupt state. 1623 retval = s_instance->m_interrupted; 1624 1625 s_instance->do_interrupt (arg); 1626 1627 s_instance->m_interrupted = arg; 1628 } 1629 else 1630 retval = false; 1631 1632 return retval; 1633 } 1634 1635 void interrupt_event_loop(bool arg)1636 command_editor::interrupt_event_loop (bool arg) 1637 { 1638 if (instance_ok ()) 1639 s_instance->do_interrupt_event_loop (arg); 1640 } 1641 1642 bool event_loop_interrupted(void)1643 command_editor::event_loop_interrupted (void) 1644 { 1645 return instance_ok () ? s_instance->do_event_loop_interrupted () : false; 1646 } 1647 1648 void handle_interrupt_signal(void)1649 command_editor::handle_interrupt_signal (void) 1650 { 1651 if (instance_ok ()) 1652 s_instance->do_handle_interrupt_signal (); 1653 } 1654 1655 // Return a string which will be printed as a prompt. The string may 1656 // contain special characters which are decoded as follows: 1657 // 1658 // \a bell (ascii 07) 1659 // \d the date 1660 // \e escape (ascii 033) 1661 // \h the hostname up to the first '.' 1662 // \H the hostname 1663 // \n CRLF 1664 // \r CR 1665 // \s the name of the shell (program) 1666 // \t the time 1667 // \T the time in 12-hour hh:mm:ss format 1668 // \@ the time in 12-hour hh:mm am/pm format 1669 // \A the time in 24-hour hh:mm format 1670 // \u your username 1671 // \w the current working directory 1672 // \W the last element of PWD 1673 // \! the history number of this command 1674 // \# the command number of this command 1675 // \$ a $ or a # if you are root 1676 // \nnn character code nnn in octal 1677 // \\ a backslash 1678 // \[ begin a sequence of non-printing chars 1679 // \] end a sequence of non-printing chars 1680 1681 std::string do_decode_prompt_string(const std::string & s)1682 command_editor::do_decode_prompt_string (const std::string& s) 1683 { 1684 std::string retval; 1685 std::string tmpstr; 1686 std::size_t i = 0; 1687 std::size_t slen = s.length (); 1688 int c; 1689 1690 while (i < slen) 1691 { 1692 c = s[i]; 1693 1694 i++; 1695 1696 if (c == '\\') 1697 { 1698 c = s[i]; 1699 1700 switch (c) 1701 { 1702 case '0': 1703 case '1': 1704 case '2': 1705 case '3': 1706 case '4': 1707 case '5': 1708 case '6': 1709 case '7': 1710 // Maybe convert an octal number. 1711 { 1712 int n = read_octal (s.substr (i, 3)); 1713 1714 tmpstr = '\\'; 1715 1716 if (n != -1) 1717 { 1718 tmpstr[0] = n; 1719 i += 2; // i++ makes this += 3 later 1720 } 1721 1722 break; 1723 } 1724 1725 case 'a': 1726 { 1727 tmpstr = '\a'; 1728 1729 break; 1730 } 1731 1732 case 'd': 1733 case 't': 1734 case 'T': 1735 case '@': 1736 case 'A': 1737 // Make the current time/date into a string. 1738 { 1739 sys::localtime now; 1740 1741 if (c == 'd') 1742 tmpstr = now.strftime ("%a %b %d"); 1743 else if (c == 't') 1744 tmpstr = now.strftime ("%H:%M:%S"); 1745 else if (c == 'T') 1746 tmpstr = now.strftime ("%I:%M:%S"); 1747 else if (c == '@') 1748 tmpstr = now.strftime ("%I:%M %p"); 1749 else // (c == 'A') 1750 tmpstr = now.strftime ("%H:%M"); 1751 1752 break; 1753 } 1754 1755 case 'e': 1756 { 1757 tmpstr = '\033'; 1758 1759 break; 1760 } 1761 1762 case 'h': 1763 { 1764 tmpstr = sys::env::get_host_name (); 1765 1766 std::size_t pos = tmpstr.find ('.'); 1767 1768 if (pos != std::string::npos) 1769 tmpstr.resize (pos); 1770 1771 break; 1772 } 1773 1774 case 'H': 1775 { 1776 tmpstr = sys::env::get_host_name (); 1777 1778 break; 1779 } 1780 1781 case 'n': 1782 { 1783 tmpstr = newline_chars (); 1784 1785 break; 1786 } 1787 1788 case 'r': 1789 { 1790 tmpstr = '\r'; 1791 1792 break; 1793 } 1794 1795 case 's': 1796 { 1797 tmpstr = sys::env::get_program_name (); 1798 tmpstr = sys::env::base_pathname (tmpstr); 1799 1800 break; 1801 } 1802 1803 case 'u': 1804 { 1805 tmpstr = sys::env::get_user_name (); 1806 1807 break; 1808 } 1809 1810 case 'w': 1811 case 'W': 1812 { 1813 try 1814 { 1815 tmpstr = sys::env::get_current_directory (); 1816 } 1817 catch (const execution_exception&) 1818 { 1819 tmpstr = ""; 1820 } 1821 1822 std::string home_dir = sys::env::get_home_directory (); 1823 1824 if (c == 'W' && (home_dir.empty () || tmpstr != home_dir)) 1825 { 1826 if (tmpstr != "/" && tmpstr != "//") 1827 { 1828 std::size_t pos = tmpstr.rfind ('/'); 1829 1830 if (pos != std::string::npos && pos != 0) 1831 tmpstr = tmpstr.substr (pos + 1); 1832 } 1833 } 1834 else 1835 tmpstr = sys::env::polite_directory_format (tmpstr); 1836 1837 break; 1838 } 1839 1840 case '!': 1841 { 1842 char number_buffer[32]; 1843 int num = command_history::current_number (); 1844 if (num > 0) 1845 sprintf (number_buffer, "%d", num); 1846 else 1847 strcpy (number_buffer, "!"); 1848 tmpstr = number_buffer; 1849 1850 break; 1851 } 1852 1853 case '#': 1854 { 1855 char number_buffer[32]; 1856 sprintf (number_buffer, "%d", m_command_number); 1857 tmpstr = number_buffer; 1858 1859 break; 1860 } 1861 1862 case '$': 1863 { 1864 tmpstr = (octave_geteuid_wrapper () == 0 ? '#' : '$'); 1865 break; 1866 } 1867 1868 #if defined (USE_READLINE) 1869 case '[': 1870 case ']': 1871 { 1872 tmpstr.resize (1); 1873 1874 tmpstr[0] = ((c == '[') 1875 ? ::octave_rl_prompt_start_ignore () 1876 : ::octave_rl_prompt_end_ignore ()); 1877 1878 break; 1879 } 1880 #endif 1881 1882 case '\\': 1883 { 1884 tmpstr = '\\'; 1885 1886 break; 1887 } 1888 1889 default: 1890 { 1891 tmpstr = "\\ "; 1892 tmpstr[1] = c; 1893 1894 break; 1895 } 1896 } 1897 1898 retval.append (tmpstr); 1899 i++; // Move past processed escape character 1900 } 1901 else 1902 retval += c; 1903 } 1904 1905 return retval; 1906 } 1907 1908 int do_insert_initial_input(void)1909 command_editor::do_insert_initial_input (void) 1910 { 1911 std::string input = m_initial_input; 1912 1913 m_initial_input = ""; 1914 1915 do_insert_text (input); 1916 1917 // Is it really right to redisplay here? 1918 do_redisplay (); 1919 1920 return 0; 1921 } 1922 1923 // Return the octal number parsed from STRING, or -1 to indicate that 1924 // the string contained a bad number. 1925 1926 int read_octal(const std::string & s)1927 command_editor::read_octal (const std::string& s) 1928 { 1929 int result = 0; 1930 int digits = 0; 1931 1932 std::size_t i = 0; 1933 std::size_t slen = s.length (); 1934 1935 while (i < slen && s[i] >= '0' && s[i] < '8') 1936 { 1937 digits++; 1938 result = (result * 8) + s[i] - '0'; 1939 i++; 1940 } 1941 1942 if (! digits || result > 0777 || i < slen) 1943 result = -1; 1944 1945 return result; 1946 } 1947 1948 void error(int err_num)1949 command_editor::error (int err_num) 1950 { 1951 (*current_liboctave_error_handler) ("%s", std::strerror (err_num)); 1952 } 1953 1954 void error(const std::string & s)1955 command_editor::error (const std::string& s) 1956 { 1957 (*current_liboctave_error_handler) ("%s", s.c_str ()); 1958 } 1959 } 1960