Mercurial > octave
changeset 25994:f881d3e271d2
eliminate global and file-scope static variables in oct-hist.cc
* interpreter.h, interpreter.cc (interpreter::m_history_system,
interpreter::get_history_system): New member variable and access
function.
* interpreter-private.h, interpreter-private.cc
(__get_history_system__): New function.
* oct-hist.h, oct-hist.cc: Rewrite to use class for
command history configuration variables and functions. Change all uses.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 31 Oct 2018 19:32:41 -0400 |
parents | f75bb9d659e0 |
children | 17b13616590d |
files | libgui/src/main-window.cc libinterp/corefcn/interpreter-private.cc libinterp/corefcn/interpreter-private.h libinterp/corefcn/interpreter.cc libinterp/corefcn/interpreter.h libinterp/corefcn/oct-hist.cc libinterp/corefcn/oct-hist.h libinterp/corefcn/syscalls.cc libinterp/parse-tree/lex.h libinterp/parse-tree/lex.ll libinterp/parse-tree/oct-parse.yy |
diffstat | 11 files changed, 570 insertions(+), 448 deletions(-) [+] |
line wrap: on
line diff
--- a/libgui/src/main-window.cc Wed Oct 31 18:22:23 2018 -0400 +++ b/libgui/src/main-window.cc Wed Oct 31 19:32:41 2018 -0400 @@ -2482,7 +2482,10 @@ { // INTERPRETER THREAD - Fhistory (ovl ("-c")); + history_system& history_sys + = __get_history_system__ ("main_window::clear_history_callback"); + + history_sys.do_history (ovl ("-c")); } void main_window::refresh_workspace_callback (void)
--- a/libinterp/corefcn/interpreter-private.cc Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/interpreter-private.cc Wed Oct 31 19:32:41 2018 -0400 @@ -37,6 +37,7 @@ #include "interpreter.h" #include "load-path.h" #include "load-save.h" +#include "oct-hist.h" #include "ov-classdef.h" #include "pager.h" #include "symtab.h" @@ -70,6 +71,13 @@ return interp.get_help_system (); } + history_system& __get_history_system__ (const std::string& who) + { + interpreter& interp = __get_interpreter__ (who); + + return interp.get_history_system (); + } + input_system& __get_input_system__ (const std::string& who) { interpreter& interp = __get_interpreter__ (who);
--- a/libinterp/corefcn/interpreter-private.h Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/interpreter-private.h Wed Oct 31 19:32:41 2018 -0400 @@ -39,6 +39,7 @@ class dynamic_loader; class gtk_manager; class help_system; + class history_system; class input_system; class interpreter; class load_path; @@ -53,6 +54,8 @@ extern help_system& __get_help_system__ (const std::string& who); + extern history_system& __get_history_system__ (const std::string& who); + extern input_system& __get_input_system__ (const std::string& who); extern load_path& __get_load_path__ (const std::string& who);
--- a/libinterp/corefcn/interpreter.cc Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/interpreter.cc Wed Oct 31 19:32:41 2018 -0400 @@ -362,6 +362,7 @@ m_help_system (*this), m_input_system (*this), m_output_system (*this), + m_history_system (*this), m_dynamic_loader (*this), m_load_path (), m_load_save_system (*this), @@ -563,7 +564,7 @@ command_history::ignore_entries (); } - ::initialize_history (read_history_file); + m_history_system.initialize (read_history_file); if (! m_app_context) command_history::ignore_entries (); @@ -1012,7 +1013,7 @@ OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); - OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); + OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ()); if (! command_history::ignoring_entries ()) OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); @@ -1178,6 +1179,8 @@ m_load_save_system.crash_dumps_octave_core (false); m_load_save_system.save_default_options ("-mat-binary"); + m_history_system.timestamp_format_string ("%%-- %D %I:%M %p --%%"); + Fbeep_on_error (octave_value (true)); Fconfirm_recursive_rmdir (octave_value (false)); @@ -1185,7 +1188,6 @@ Fdisable_permutation_matrix (octave_value (true)); Fdisable_range (octave_value (true)); Ffixed_point_format (octave_value (true)); - Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%")); Fprint_empty_dimensions (octave_value (false)); Fstruct_levels_to_print (octave_value (0));
--- a/libinterp/corefcn/interpreter.h Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/interpreter.h Wed Oct 31 19:32:41 2018 -0400 @@ -38,6 +38,7 @@ #include "input.h" #include "load-path.h" #include "load-save.h" +#include "oct-hist.h" #include "oct-stream.h" #include "ov-classdef.h" #include "ov-typeinfo.h" @@ -173,6 +174,11 @@ return m_output_system; } + history_system& get_history_system (void) + { + return m_history_system; + } + dynamic_loader& get_dynamic_loader (void) { return m_dynamic_loader; @@ -278,6 +284,8 @@ output_system m_output_system; + history_system m_history_system; + dynamic_loader m_dynamic_loader; load_path m_load_path;
--- a/libinterp/corefcn/oct-hist.cc Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/oct-hist.cc Wed Oct 31 19:32:41 2018 -0400 @@ -65,489 +65,496 @@ #include "utils.h" #include "variables.h" -// TRUE means input is coming from temporary history file. -bool input_from_tmp_history_file = false; - -static std::string -default_history_file (void) -{ - std::string file; - - std::string env_file = octave::sys::env::getenv ("OCTAVE_HISTFILE"); - - if (! env_file.empty ()) - file = env_file; - - if (file.empty ()) - file = octave::sys::file_ops::concat (octave::sys::env::get_home_directory (), - ".octave_hist"); - - return file; -} - -static int -default_history_size (void) -{ - int size = 1000; - - std::string env_size = octave::sys::env::getenv ("OCTAVE_HISTSIZE"); - - if (! env_size.empty ()) - { - int val; - - if (sscanf (env_size.c_str (), "%d", &val) == 1) - size = (val > 0 ? val : 0); - } - - return size; -} - -static std::string -default_history_timestamp_format (void) -{ - return - "# Octave " OCTAVE_VERSION ", %a %b %d %H:%M:%S %Y %Z <" - + octave::sys::env::get_user_name () - + '@' - + octave::sys::env::get_host_name () - + '>'; -} - -// The format of the timestamp marker written to the history file when -// Octave exits. -static std::string Vhistory_timestamp_format_string - = default_history_timestamp_format (); - -// Display, save, or load history. Stolen and modified from bash. -// -// Arg of -w FILENAME means write file, arg of -r FILENAME -// means read file, arg of -q means don't number lines. Arg of N -// means only display that many items. - -static string_vector -do_history (const octave_value_list& args, int nargout) -{ - bool numbered_output = nargout == 0; - - octave::unwind_protect frame; - - string_vector hlist; - - frame.add_fcn (octave::command_history::set_file, - octave::command_history::file ()); - - int nargin = args.length (); - - // Number of history lines to show (-1 = all) - int limit = -1; - - for (octave_idx_type i = 0; i < nargin; i++) - { - octave_value arg = args(i); - - std::string option; - - if (arg.is_string ()) - option = arg.string_value (); - else if (arg.isnumeric ()) - { - limit = arg.int_value (); - if (limit < 0) - limit = -limit; - continue; - } - else - err_wrong_type_arg ("history", arg); - - if (option == "-r" || option == "-w" || option == "-a" - || option == "-n") - { - if (i < nargin - 1) - { - std::string fname - = args(++i).xstring_value ("history: filename must be a string for %s option", - option.c_str ()); - - octave::command_history::set_file (fname); - } - else - octave::command_history::set_file (default_history_file ()); - - if (option == "-a") - // Append 'new' lines to file. - octave::command_history::append (); - - else if (option == "-w") - // Write entire history. - octave::command_history::write (); - - else if (option == "-r") - { - // Read entire file. - octave::command_history::read (); - octave_link::set_history (octave::command_history::list ()); - } - - else if (option == "-n") - { - // Read 'new' history from file. - octave::command_history::read_range (); - octave_link::set_history (octave::command_history::list ()); - } - - else - panic_impossible (); - - return hlist; - } - else if (option == "-c") - { - octave::command_history::clear (); - octave_link::clear_history (); - } - else if (option == "-q") - numbered_output = false; - else if (option == "--") - { - i++; - break; - } - else - { - // The last argument found in the command list that looks like - // an integer will be used - int tmp; - - if (sscanf (option.c_str (), "%d", &tmp) == 1) - { - if (tmp > 0) - limit = tmp; - else - limit = -tmp; - } - - else - { - if (option.length () > 0 && option[0] == '-') - error ("history: unrecognized option '%s'", option.c_str ()); - else - error ("history: bad non-numeric arg '%s'", option.c_str ()); - } - } - } - - hlist = octave::command_history::list (limit, numbered_output); - - int len = hlist.numel (); - - if (nargout == 0) - { - for (octave_idx_type i = 0; i < len; i++) - octave_stdout << hlist[i] << "\n"; - } - - return hlist; -} - -// Read the edited history lines from STREAM and return them -// one at a time. This can read unlimited length lines. The -// caller should free the storage. - -static char * -edit_history_readline (std::fstream& stream) -{ - char c; - int line_len = 128; - int lindex = 0; - char *line = new char [line_len]; - line[0] = '\0'; - - while (stream.get (c)) - { - if (lindex + 2 >= line_len) - { - char *tmp_line = new char [line_len += 128]; - strcpy (tmp_line, line); - delete [] line; - line = tmp_line; - } - - if (c == '\n') - { - line[lindex++] = '\n'; - line[lindex++] = '\0'; - return line; - } - else - line[lindex++] = c; - } - - if (! lindex) - { - delete [] line; - return nullptr; - } - - if (lindex + 2 >= line_len) - { - char *tmp_line = new char [lindex+3]; - strcpy (tmp_line, line); - delete [] line; - line = tmp_line; - } - - // Finish with newline if none in file. - - line[lindex++] = '\n'; - line[lindex++] = '\0'; - return line; -} - -static void -edit_history_add_hist (const std::string& line) +namespace octave { - if (! line.empty ()) - { - std::string tmp = line; + // Read the edited history lines from STREAM and return them + // one at a time. This can read unlimited length lines. The + // caller should free the storage. - int len = tmp.length (); + static char * + edit_history_readline (std::fstream& stream) + { + char c; + int line_len = 128; + int lindex = 0; + char *line = new char [line_len]; + line[0] = '\0'; - if (len > 0 && tmp[len-1] == '\n') - tmp.resize (len - 1); + while (stream.get (c)) + { + if (lindex + 2 >= line_len) + { + char *tmp_line = new char [line_len += 128]; + strcpy (tmp_line, line); + delete [] line; + line = tmp_line; + } - if (! tmp.empty ()) - if (octave::command_history::add (tmp)) - octave_link::append_history (tmp); - } -} + if (c == '\n') + { + line[lindex++] = '\n'; + line[lindex++] = '\0'; + return line; + } + else + line[lindex++] = c; + } -static bool -get_int_arg (const octave_value& arg, int& val) -{ - bool ok = true; + if (! lindex) + { + delete [] line; + return nullptr; + } - if (arg.is_string ()) - { - std::string tmp = arg.string_value (); + if (lindex + 2 >= line_len) + { + char *tmp_line = new char [lindex+3]; + strcpy (tmp_line, line); + delete [] line; + line = tmp_line; + } + + // Finish with newline if none in file. + + line[lindex++] = '\n'; + line[lindex++] = '\0'; + return line; + } - ok = sscanf (tmp.c_str (), "%d", &val) == 1; - } - else if (arg.isnumeric ()) - val = arg.int_value (); - else - ok = false; + static void + edit_history_add_hist (const std::string& line) + { + if (! line.empty ()) + { + std::string tmp = line; + + int len = tmp.length (); + + if (len > 0 && tmp[len-1] == '\n') + tmp.resize (len - 1); - return ok; -} + if (! tmp.empty ()) + if (octave::command_history::add (tmp)) + octave_link::append_history (tmp); + } + } -static std::string -mk_tmp_hist_file (const octave_value_list& args, - bool insert_curr, const char *warn_for) -{ - string_vector hlist = octave::command_history::list (); + static bool + get_int_arg (const octave_value& arg, int& val) + { + bool ok = true; - int hist_count = hlist.numel () - 1; // switch to zero-based indexing + if (arg.is_string ()) + { + std::string tmp = arg.string_value (); - // The current command line is already part of the history list by - // the time we get to this point. Delete the cmd from the list when - // executing 'edit_history' so that it doesn't show up in the history - // but the actual commands performed will. + ok = sscanf (tmp.c_str (), "%d", &val) == 1; + } + else if (arg.isnumeric ()) + val = arg.int_value (); + else + ok = false; - if (! insert_curr) - octave::command_history::remove (hist_count); + return ok; + } + + static std::string + mk_tmp_hist_file (const octave_value_list& args, + bool insert_curr, const char *warn_for) + { + string_vector hlist = octave::command_history::list (); + + int hist_count = hlist.numel () - 1; // switch to zero-based indexing - hist_count--; // skip last entry in history list + // The current command line is already part of the history list by + // the time we get to this point. Delete the cmd from the list when + // executing 'edit_history' so that it doesn't show up in the history + // but the actual commands performed will. - // If no numbers have been specified, the default is to edit the - // last command in the history list. + if (! insert_curr) + octave::command_history::remove (hist_count); + + hist_count--; // skip last entry in history list - int hist_beg = hist_count; - int hist_end = hist_count; + // If no numbers have been specified, the default is to edit the + // last command in the history list. + + int hist_beg = hist_count; + int hist_end = hist_count; - bool reverse = false; + bool reverse = false; + + // Process options. + + int nargin = args.length (); - // Process options. - - int nargin = args.length (); + if (nargin == 2) + { + if (! get_int_arg (args(0), hist_beg) + || ! get_int_arg (args(1), hist_end)) + error ("%s: arguments must be integers", warn_for); - if (nargin == 2) - { - if (! get_int_arg (args(0), hist_beg) - || ! get_int_arg (args(1), hist_end)) - error ("%s: arguments must be integers", warn_for); + if (hist_beg < 0) + hist_beg += (hist_count + 1); + else + hist_beg--; + if (hist_end < 0) + hist_end += (hist_count + 1); + else + hist_end--; + } + else if (nargin == 1) + { + if (! get_int_arg (args(0), hist_beg)) + error ("%s: argument must be an integer", warn_for); + + if (hist_beg < 0) + hist_beg += (hist_count + 1); + else + hist_beg--; + + hist_end = hist_beg; + } - if (hist_beg < 0) - hist_beg += (hist_count + 1); - else - hist_beg--; - if (hist_end < 0) - hist_end += (hist_count + 1); - else - hist_end--; - } - else if (nargin == 1) - { - if (! get_int_arg (args(0), hist_beg)) - error ("%s: argument must be an integer", warn_for); + if (hist_beg > hist_count || hist_end > hist_count) + error ("%s: history specification out of range", warn_for); + + if (hist_end < hist_beg) + { + std::swap (hist_end, hist_beg); + reverse = true; + } + + std::string name = octave::sys::tempnam ("", "oct-"); + + std::fstream file (name.c_str (), std::ios::out); - if (hist_beg < 0) - hist_beg += (hist_count + 1); - else - hist_beg--; + if (! file) + error ("%s: couldn't open temporary file '%s'", warn_for, + name.c_str ()); + + if (reverse) + { + for (int i = hist_end; i >= hist_beg; i--) + file << hlist[i] << "\n"; + } + else + { + for (int i = hist_beg; i <= hist_end; i++) + file << hlist[i] << "\n"; + } + + file.close (); + + return name; + } - hist_end = hist_beg; - } + static void + unlink_cleanup (const char *file) + { + octave_unlink_wrapper (file); + } - if (hist_beg > hist_count || hist_end > hist_count) - error ("%s: history specification out of range", warn_for); + history_system::history_system (interpreter& interp) + : m_interpreter (interp), m_input_from_tmp_file (false), + m_timestamp_format_string () + { } - if (hist_end < hist_beg) - { - std::swap (hist_end, hist_beg); - reverse = true; - } + void history_system::initialize (bool read_history_file) + { + command_history::initialize (read_history_file, default_file (), + default_size (), + sys::env::getenv ("OCTAVE_HISTCONTROL")); + + octave_link::set_history (command_history::list ()); + } - std::string name = octave::sys::tempnam ("", "oct-"); + void history_system::write_timestamp (void) + { + sys::localtime now; + + std::string timestamp = now.strftime (m_timestamp_format_string); + + if (! timestamp.empty ()) + if (command_history::add (timestamp)) + octave_link::append_history (timestamp); + } - std::fstream file (name.c_str (), std::ios::out); - - if (! file) - error ("%s: couldn't open temporary file '%s'", warn_for, - name.c_str ()); + octave_value + history_system::input_from_tmp_file (const octave_value_list& args, + int nargout) + { + return set_internal_variable (m_input_from_tmp_file, args, nargout, + "input_from_tmp_file"); + } - if (reverse) - { - for (int i = hist_end; i >= hist_beg; i--) - file << hlist[i] << "\n"; - } - else - { - for (int i = hist_beg; i <= hist_end; i++) - file << hlist[i] << "\n"; - } + octave_value + history_system::timestamp_format_string (const octave_value_list& args, + int nargout) + { + return set_internal_variable (m_timestamp_format_string, args, nargout, + "timestamp_format_string", false); + } + + // Display, save, or load history. Stolen and modified from bash. + // + // Arg of -w FILENAME means write file, arg of -r FILENAME + // means read file, arg of -q means don't number lines. Arg of N + // means only display that many items. + + string_vector history_system::do_history (const octave_value_list& args, + int nargout) + { + bool numbered_output = nargout == 0; + + unwind_protect frame; + + string_vector hlist; - file.close (); + frame.add_fcn (command_history::set_file, command_history::file ()); + + int nargin = args.length (); - return name; -} + // Number of history lines to show (-1 = all) + int limit = -1; + + for (octave_idx_type i = 0; i < nargin; i++) + { + octave_value arg = args(i); -static void -unlink_cleanup (const char *file) -{ - octave_unlink_wrapper (file); -} + std::string option; + + if (arg.is_string ()) + option = arg.string_value (); + else if (arg.isnumeric ()) + { + limit = arg.int_value (); + if (limit < 0) + limit = -limit; + continue; + } + else + err_wrong_type_arg ("history", arg); -static void -do_edit_history (octave::interpreter& interp, const octave_value_list& args) -{ - std::string name = mk_tmp_hist_file (args, false, "edit_history"); + if (option == "-r" || option == "-w" || option == "-a" + || option == "-n") + { + if (i < nargin - 1) + { + std::string fname + = args(++i).xstring_value ("history: filename must be a string for %s option", + option.c_str ()); - if (name.empty ()) - return; + command_history::set_file (fname); + } + else + command_history::set_file (default_file ()); + + if (option == "-a") + // Append 'new' lines to file. + command_history::append (); - // Call up our favorite editor on the file of commands. + else if (option == "-w") + // Write entire history. + command_history::write (); - octave::environment& env = interp.get_environment (); - std::string cmd = env.editor (); - cmd.append (R"( ")" + name + '"'); + else if (option == "-r") + { + // Read entire file. + command_history::read (); + octave_link::set_history (command_history::list ()); + } - // Ignore interrupts while we are off editing commands. Should we - // maybe avoid using system()? + else if (option == "-n") + { + // Read 'new' history from file. + command_history::read_range (); + octave_link::set_history (command_history::list ()); + } - volatile octave::interrupt_handler old_interrupt_handler - = octave::ignore_interrupts (); - - int status = system (cmd.c_str ()); - - octave::set_interrupt_handler (old_interrupt_handler); + else + panic_impossible (); - // Check if text edition was successfull. Abort the operation - // in case of failure. - if (status != EXIT_SUCCESS) - error ("edit_history: text editor command failed"); - - // Write the commands to the history file since source_file - // disables command line history while it executes. + return hlist; + } + else if (option == "-c") + { + command_history::clear (); + octave_link::clear_history (); + } + else if (option == "-q") + numbered_output = false; + else if (option == "--") + { + i++; + break; + } + else + { + // The last argument found in the command list that looks like + // an integer will be used + int tmp; - std::fstream file (name.c_str (), std::ios::in); + if (sscanf (option.c_str (), "%d", &tmp) == 1) + { + if (tmp > 0) + limit = tmp; + else + limit = -tmp; + } - char *line; - //int first = 1; - while ((line = edit_history_readline (file)) != nullptr) - { - // Skip blank lines. + else + { + if (option.length () > 0 && option[0] == '-') + error ("history: unrecognized option '%s'", option.c_str ()); + else + error ("history: bad non-numeric arg '%s'", option.c_str ()); + } + } + } - if (line[0] == '\n') - { - delete [] line; - continue; - } + hlist = command_history::list (limit, numbered_output); + + int len = hlist.numel (); + + if (nargout == 0) + { + for (octave_idx_type i = 0; i < len; i++) + octave_stdout << hlist[i] << "\n"; + } - edit_history_add_hist (line); + return hlist; + } + + void history_system::do_edit_history (const octave_value_list& args) + { + std::string name = mk_tmp_hist_file (args, false, "edit_history"); + + if (name.empty ()) + return; - delete [] line; - } + // Call up our favorite editor on the file of commands. + + environment& env = m_interpreter.get_environment (); + std::string cmd = env.editor (); + cmd.append (R"( ")" + name + '"'); - file.close (); + // Ignore interrupts while we are off editing commands. Should we + // maybe avoid using system()? + + volatile interrupt_handler old_interrupt_handler + = ignore_interrupts (); - octave::unwind_protect frame; + int status = system (cmd.c_str ()); + + set_interrupt_handler (old_interrupt_handler); - frame.add_fcn (unlink_cleanup, name.c_str ()); - frame.protect_var (input_from_tmp_history_file); + // Check if text edition was successfull. Abort the operation + // in case of failure. + if (status != EXIT_SUCCESS) + error ("edit_history: text editor command failed"); - input_from_tmp_history_file = true; + // Write the commands to the history file since source_file + // disables command line history while it executes. + + std::fstream file (name.c_str (), std::ios::in); - // FIXME: instead of sourcing a file, we should just iterate through - // the list of commands, parsing and executing them one at a time as - // if they were entered interactively. + char *line; + //int first = 1; + while ((line = edit_history_readline (file)) != nullptr) + { + // Skip blank lines. - octave::source_file (name); -} + if (line[0] == '\n') + { + delete [] line; + continue; + } + + edit_history_add_hist (line); -static void -do_run_history (const octave_value_list& args) -{ - std::string name = mk_tmp_hist_file (args, false, "run_history"); + delete [] line; + } + + file.close (); + + unwind_protect frame; - if (name.empty ()) - return; + frame.add_fcn (unlink_cleanup, name.c_str ()); + frame.protect_var (m_input_from_tmp_file); + + m_input_from_tmp_file = true; - octave::unwind_protect frame; + // FIXME: instead of sourcing a file, we should just iterate through + // the list of commands, parsing and executing them one at a time as + // if they were entered interactively. + + source_file (name); + } - frame.add_fcn (unlink_cleanup, name.c_str ()); - frame.protect_var (input_from_tmp_history_file); + void history_system::do_run_history (const octave_value_list& args) + { + std::string name = mk_tmp_hist_file (args, false, "run_history"); + + if (name.empty ()) + return; - input_from_tmp_history_file = true; + unwind_protect frame; + + frame.add_fcn (unlink_cleanup, name.c_str ()); + frame.protect_var (m_input_from_tmp_file); + + m_input_from_tmp_file = true; - // FIXME: instead of sourcing a file, we should just iterate through - // the list of commands, parsing and executing them one at a time as - // if they were entered interactively. + // FIXME: instead of sourcing a file, we should just iterate through + // the list of commands, parsing and executing them one at a time as + // if they were entered interactively. + + source_file (name); + } - octave::source_file (name); -} + std::string history_system::default_file (void) + { + std::string file; + + std::string env_file = sys::env::getenv ("OCTAVE_HISTFILE"); + + if (! env_file.empty ()) + file = env_file; -void -initialize_history (bool read_history_file) -{ - octave::command_history::initialize (read_history_file, - default_history_file (), - default_history_size (), - octave::sys::env::getenv ("OCTAVE_HISTCONTROL")); + if (file.empty ()) + file = sys::file_ops::concat (sys::env::get_home_directory (), + ".octave_hist"); + + return file; + } - octave_link::set_history (octave::command_history::list ()); -} + int history_system::default_size (void) + { + int size = 1000; + + std::string env_size = sys::env::getenv ("OCTAVE_HISTSIZE"); + + if (! env_size.empty ()) + { + int val; -void -octave_history_write_timestamp (void) -{ - octave::sys::localtime now; + if (sscanf (env_size.c_str (), "%d", &val) == 1) + size = (val > 0 ? val : 0); + } + + return size; + } - std::string timestamp = now.strftime (Vhistory_timestamp_format_string); - - if (! timestamp.empty ()) - if (octave::command_history::add (timestamp)) - octave_link::append_history (timestamp); + std::string history_system::default_timestamp_format (void) + { + return + "# Octave " OCTAVE_VERSION ", %a %b %d %H:%M:%S %Y %Z <" + + sys::env::get_user_name () + + '@' + + sys::env::get_host_name () + + '>'; + } } DEFMETHOD (edit_history, interp, args, , @@ -590,13 +597,15 @@ if (args.length () > 2) print_usage (); - do_edit_history (interp, args); + octave::history_system& history_sys = interp.get_history_system (); + + history_sys.do_edit_history (args); return ovl (); } -DEFUN (history, args, nargout, - doc: /* -*- texinfo -*- +DEFMETHOD (history, interp, args, nargout, + doc: /* -*- texinfo -*- @deftypefn {} {} history @deftypefnx {} {} history @var{opt1} @dots{} @deftypefnx {} {@var{h} =} history () @@ -639,15 +648,17 @@ { // FIXME: should this be limited to the top-level context? + octave::history_system& history_sys = interp.get_history_system (); + // Call do_history even if nargout is zero to display history list. - string_vector hlist = do_history (args, nargout); + string_vector hlist = history_sys.do_history (args, nargout); return nargout > 0 ? ovl (Cell (hlist)) : ovl (); } -DEFUN (run_history, args, , - doc: /* -*- texinfo -*- +DEFMETHOD (run_history, interp, args, , + doc: /* -*- texinfo -*- @deftypefn {} {} run_history @deftypefnx {} {} run_history @var{cmd_number} @deftypefnx {} {} run_history @var{first} @var{last} @@ -700,10 +711,12 @@ { // FIXME: should this be limited to the top-level context? + octave::history_system& history_sys = interp.get_history_system (); + if (args.length () > 2) print_usage (); - do_run_history (args); + history_sys.do_run_history (args); return ovl (); } @@ -800,8 +813,8 @@ return retval; } -DEFUN (history_timestamp_format_string, args, nargout, - doc: /* -*- texinfo -*- +DEFMETHOD (history_timestamp_format_string, interp, args, nargout, + doc: /* -*- texinfo -*- @deftypefn {} {@var{val} =} history_timestamp_format_string () @deftypefnx {} {@var{old_val} =} history_timestamp_format_string (@var{new_val}) @deftypefnx {} {} history_timestamp_format_string (@var{new_val}, "local") @@ -821,7 +834,9 @@ @seealso{strftime, history_file, history_size, history_save} @end deftypefn */) { - return SET_INTERNAL_VARIABLE (history_timestamp_format_string); + octave::history_system& history_sys = interp.get_history_system (); + + return history_sys.timestamp_format_string (args, nargout); } DEFUN (history_save, args, nargout,
--- a/libinterp/corefcn/oct-hist.h Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/oct-hist.h Wed Oct 31 19:32:41 2018 -0400 @@ -29,12 +29,83 @@ #include "cmd-hist.h" -extern void initialize_history (bool read_history_file = false); +namespace octave +{ + class history_system + { + public: + + history_system (interpreter& interp); + + history_system (const history_system&) = delete; + + history_system& operator = (const history_system&) = delete; + + ~history_system (void) = default; + + void initialize (bool read_history_file = false); + + void write_timestamp (void); + + octave_value input_from_tmp_file (const octave_value_list& args, + int nargout); + + bool input_from_tmp_file (void) const + { + return m_input_from_tmp_file; + } + + bool input_from_tmp_file (bool flag) + { + return set (m_input_from_tmp_file, flag); + } + + octave_value timestamp_format_string (const octave_value_list& args, + int nargout); + + std::string timestamp_format_string (void) const + { + return m_timestamp_format_string; + } -// Write timestamp to history file. -extern void octave_history_write_timestamp (void); + std::string timestamp_format_string (const std::string& file) + { + return set (m_timestamp_format_string, file); + } + + string_vector + do_history (const octave_value_list& args = octave_value_list (), + int nargout = 0); + + void do_edit_history (const octave_value_list& args = octave_value_list ()); + + void do_run_history (const octave_value_list& args = octave_value_list ()); + + private: + + interpreter& m_interpreter; + + // TRUE means input is coming from temporary history file. + bool m_input_from_tmp_file; -// TRUE means input is coming from temporary history file. -extern bool input_from_tmp_history_file; + // The format of the timestamp marker written to the history file when + // Octave exits. + std::string m_timestamp_format_string; + + static std::string default_file (void); + + static int default_size (void); + + static std::string default_timestamp_format (void); + + template <typename T> + T set (T& var, const T& new_val) + { + T old_val = var; + var = new_val; + return old_val; + } + }; +} #endif
--- a/libinterp/corefcn/syscalls.cc Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/corefcn/syscalls.cc Wed Oct 31 19:32:41 2018 -0400 @@ -141,8 +141,8 @@ return ovl (-1, ""); } -DEFUNX ("exec", Fexec, args, , - doc: /* -*- texinfo -*- +DEFMETHODX ("exec", Fexec, interp, args, , + doc: /* -*- texinfo -*- @deftypefn {} {[@var{err}, @var{msg}] =} exec (@var{file}, @var{args}) Replace current process with a new process. @@ -191,7 +191,9 @@ exec_args[0] = exec_file; } - octave_history_write_timestamp (); + octave::history_system& history_sys = interp.get_history_system (); + + history_sys.write_timestamp (); if (! octave::command_history::ignoring_entries ()) octave::command_history::clean_up_and_save ();
--- a/libinterp/parse-tree/lex.h Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/parse-tree/lex.h Wed Oct 31 19:32:41 2018 -0400 @@ -711,6 +711,8 @@ virtual bool input_from_eval_string (void) const { return false; } + bool input_from_tmp_history_file (void); + void push_start_state (int state); void pop_start_state (void);
--- a/libinterp/parse-tree/lex.ll Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/parse-tree/lex.ll Wed Oct 31 19:32:41 2018 -0400 @@ -3404,6 +3404,14 @@ } } + bool + base_lexer::input_from_tmp_history_file (void) + { + history_system& history_sys = m_interpreter.get_history_system (); + + return history_sys.input_from_tmp_file (); + } + void base_lexer::push_start_state (int state) {
--- a/libinterp/parse-tree/oct-parse.yy Wed Oct 31 18:22:23 2018 -0400 +++ b/libinterp/parse-tree/oct-parse.yy Wed Oct 31 19:32:41 2018 -0400 @@ -3414,7 +3414,7 @@ warning_with_id ("Octave:future-time-stamp", "time stamp for '%s' is in the future", nm.c_str ()); } - else if (! input_from_tmp_history_file + else if (! m_lexer.input_from_tmp_history_file () && ! m_lexer.m_force_script && m_lexer.m_reading_script_file && m_lexer.m_fcn_file_name == id_name)