diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2015-09-21 11:24:49 -0700 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2015-09-22 18:08:00 -0700 |
commit | c1bd3b5824027f23b41bbac77c5e28f856c5dc18 (patch) | |
tree | f406ad2f859df99f65c059f8c4019d5a2db1e459 /src/builtin.cpp | |
parent | fb615843b329b4d3c303b9cebe2af134a52b5bfd (diff) |
Eliminate global variables associated with builtin IO
This change eliminates global variables like stdout_buffer. Instead we wrap up
the IO information into a new struct io_streams_t, and thread that through
every builtin. This makes the intent clearer, gives us a place to hang new IO
data, and eliminates the ugly global state management like builtin_push_io.
Diffstat (limited to 'src/builtin.cpp')
-rw-r--r-- | src/builtin.cpp | 760 |
1 files changed, 314 insertions, 446 deletions
diff --git a/src/builtin.cpp b/src/builtin.cpp index e4f14160..a3e5eedb 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -92,7 +92,7 @@ struct builtin_data_t /** Function pointer tothe builtin implementation */ - int (*func)(parser_t &parser, wchar_t **argv); + int (*func)(parser_t &parser, io_streams_t &streams, wchar_t **argv); /** Description of what the builtin does */ @@ -112,54 +112,6 @@ bool builtin_data_t::operator<(const builtin_data_t *other) const return wcscmp(this->name, other->name) < 0; } -int builtin_out_redirect; -int builtin_err_redirect; - -/* Buffers for storing the output of builtin functions */ -wcstring stdout_buffer, stderr_buffer; - -const wcstring &get_stdout_buffer() -{ - ASSERT_IS_MAIN_THREAD(); - return stdout_buffer; -} - -const wcstring &get_stderr_buffer() -{ - ASSERT_IS_MAIN_THREAD(); - return stderr_buffer; -} - -void builtin_show_error(const wcstring &err) -{ - ASSERT_IS_MAIN_THREAD(); - stderr_buffer.append(err); -} - -/** - Stack containing builtin I/O for recursive builtin calls. -*/ -struct io_stack_elem_t -{ - int in; - wcstring out; - wcstring err; -}; -static std::stack<io_stack_elem_t, std::vector<io_stack_elem_t> > io_stack; - -/** - The file from which builtin functions should attempt to read, use - instead of stdin. -*/ -int builtin_stdin; - -/** - The underlying IO redirections behind the current builtin. This - should normally not be used - sb_out and friends are already - configured to handle everything. -*/ -static const io_chain_t *real_io; - /** Counts the number of non null pointers in the specified array */ @@ -175,23 +127,23 @@ int builtin_count_args(const wchar_t * const * argv) /** This function works like wperror, but it prints its result into - the sb_err string instead of to stderr. Used by the builtin + the streams.err string instead of to stderr. Used by the builtin commands. */ -static void builtin_wperror(const wchar_t *s) +static void builtin_wperror(const wchar_t *s, io_streams_t &streams) { - if (s != 0) + char *err = strerror(errno); + if (s != NULL) { - stderr_buffer.append(s); - stderr_buffer.append(L": "); + streams.err.append(s); + streams.err.append(L": "); } - char *err = strerror(errno); - if (err) + if (err != NULL) { const wcstring werr = str2wcstring(err); - stderr_buffer.append(werr); - stderr_buffer.push_back(L'\n'); + streams.err.append(werr); + streams.err.push_back(L'\n'); } } @@ -208,7 +160,7 @@ static int count_char(const wchar_t *str, wchar_t c) return res; } -wcstring builtin_help_get(parser_t &parser, const wchar_t *name) +wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t *name) { /* This won't ever work if no_exec is set */ if (no_exec) @@ -218,7 +170,7 @@ wcstring builtin_help_get(parser_t &parser, const wchar_t *name) wcstring out; const wcstring name_esc = escape_string(name, 1); wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str()); - if (!builtin_out_redirect && isatty(1)) + if (!streams.out_is_redirected && isatty(STDOUT_FILENO)) { // since we're using a subshell, __fish_print_help can't tell we're in // a terminal. Tell it ourselves. @@ -247,70 +199,71 @@ wcstring builtin_help_get(parser_t &parser, const wchar_t *name) */ -void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b) +void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, output_stream_t &b) { - if (&b == &stderr_buffer) + bool is_stderr = (&b == &streams.err); + if (is_stderr) { - stderr_buffer.append(parser.current_line()); + b.append(parser.current_line()); } - - const wcstring h = builtin_help_get(parser, cmd); - + + const wcstring h = builtin_help_get(parser, streams, cmd); + if (!h.size()) return; - + wchar_t *str = wcsdup(h.c_str()); if (str) { bool is_short = false; - if (&b == &stderr_buffer) + if (is_stderr) { - + /* - Interactive mode help to screen - only print synopsis if - the rest won't fit - */ - + Interactive mode help to screen - only print synopsis if + the rest won't fit + */ + int screen_height, lines; - + screen_height = common_get_height(); lines = count_char(str, L'\n'); - if (!get_is_interactive() || (lines > 2*screen_height/3)) + if (! get_is_interactive() || (lines > 2*screen_height/3)) { wchar_t *pos; int cut=0; int i; - + is_short = true; - + /* - First move down 4 lines - */ - + First move down 4 lines + */ + pos = str; for (i=0; (i<4) && pos && *pos; i++) { pos = wcschr(pos+1, L'\n'); } - + if (pos && *pos) { - + /* - Then find the next empty line - */ + Then find the next empty line + */ for (; *pos; pos++) { if (*pos == L'\n') { wchar_t *pos2; int is_empty = 1; - + for (pos2 = pos+1; *pos2; pos2++) { if (*pos2 == L'\n') break; - + if (*pos2 != L'\t' && *pos2 !=L' ') { is_empty = 0; @@ -320,8 +273,8 @@ void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b) if (is_empty) { /* - And cut it - */ + And cut it + */ *(pos2+1)=L'\0'; cut = 1; break; @@ -329,46 +282,47 @@ void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b) } } } - + /* - We did not find a good place to cut message to - shorten it - so we make sure we don't print - anything. - */ + We did not find a good place to cut message to + shorten it - so we make sure we don't print + anything. + */ if (!cut) { *str = 0; } - + } } - + b.append(str); if (is_short) { - append_format(b, _(L"%ls: Type 'help %ls' for related documentation\n\n"), cmd, cmd); + b.append_format(_(L"%ls: Type 'help %ls' for related documentation\n\n"), cmd, cmd); } - + free(str); } } + /** Perform error reporting for encounter with unknown option */ -static void builtin_unknown_option(parser_t &parser, const wchar_t *cmd, const wchar_t *opt) +static void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, const wchar_t *opt) { - append_format(stderr_buffer, BUILTIN_ERR_UNKNOWN, cmd, opt); - builtin_print_help(parser, cmd, stderr_buffer); + streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, opt); + builtin_print_help(parser, streams, cmd, streams.err); } /** Perform error reporting for encounter with missing argument */ -static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const wchar_t *opt) +static void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wchar_t *cmd, const wchar_t *opt) { - append_format(stderr_buffer, BUILTIN_ERR_MISSING, cmd, opt); - builtin_print_help(parser, cmd, stderr_buffer); + streams.err.append_format(BUILTIN_ERR_MISSING, cmd, opt); + builtin_print_help(parser, streams, cmd, streams.err); } /* @@ -401,16 +355,16 @@ static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const #include "builtin_printf.cpp" /* builtin_test lives in builtin_test.cpp */ -int builtin_test(parser_t &parser, wchar_t **argv); +int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv); /* builtin_string lives in builtin_string.cpp */ -int builtin_string(parser_t &parser, wchar_t **argv); +int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv); /** List a single key binding. Returns false if no binding with that sequence and mode exists. */ -static bool builtin_bind_list_one(const wcstring& seq, const wcstring& bind_mode) +static bool builtin_bind_list_one(const wcstring &seq, const wcstring &bind_mode, io_streams_t &streams) { std::vector<wcstring> ecmds; wcstring sets_mode; @@ -420,20 +374,20 @@ static bool builtin_bind_list_one(const wcstring& seq, const wcstring& bind_mode return false; } - stdout_buffer.append(L"bind"); + streams.out.append(L"bind"); // Append the mode flags if applicable if (bind_mode != DEFAULT_BIND_MODE) { const wcstring emode = escape_string(bind_mode, ESCAPE_ALL); - stdout_buffer.append(L" -M "); - stdout_buffer.append(emode); + streams.out.append(L" -M "); + streams.out.append(emode); } if (sets_mode != bind_mode) { const wcstring esets_mode = escape_string(sets_mode, ESCAPE_ALL); - stdout_buffer.append(L" -m "); - stdout_buffer.append(esets_mode); + streams.out.append(L" -m "); + streams.out.append(esets_mode); } // Append the name @@ -441,13 +395,13 @@ static bool builtin_bind_list_one(const wcstring& seq, const wcstring& bind_mode if (input_terminfo_get_name(seq, &tname)) { // Note that we show -k here because we have an input key name - append_format(stdout_buffer, L" -k %ls", tname.c_str()); + streams.out.append_format( L" -k %ls", tname.c_str()); } else { // No key name, so no -k; we show the escape sequence directly const wcstring eseq = escape_string(seq, ESCAPE_ALL); - append_format(stdout_buffer, L" %ls", eseq.c_str()); + streams.out.append_format( L" %ls", eseq.c_str()); } // Now show the list of commands @@ -455,10 +409,10 @@ static bool builtin_bind_list_one(const wcstring& seq, const wcstring& bind_mode { const wcstring &ecmd = ecmds.at(i); const wcstring escaped_ecmd = escape_string(ecmd, ESCAPE_ALL); - stdout_buffer.push_back(' '); - stdout_buffer.append(escaped_ecmd); + streams.out.push_back(' '); + streams.out.append(escaped_ecmd); } - stdout_buffer.push_back(L'\n'); + streams.out.push_back(L'\n'); return true; } @@ -466,7 +420,7 @@ static bool builtin_bind_list_one(const wcstring& seq, const wcstring& bind_mode /** List all current key bindings */ -static void builtin_bind_list(const wchar_t *bind_mode) +static void builtin_bind_list(const wchar_t *bind_mode, io_streams_t &streams) { const std::vector<input_mapping_name_t> lst = input_mapping_get_names(); @@ -479,7 +433,7 @@ static void builtin_bind_list(const wchar_t *bind_mode) continue; } - builtin_bind_list_one(it->seq, it->mode); + builtin_bind_list_one(it->seq, it->mode, streams); } } @@ -490,14 +444,14 @@ static void builtin_bind_list(const wchar_t *bind_mode) printed. If not set, only ones that are defined for this terminal are printed. */ -static void builtin_bind_key_names(int all) +static void builtin_bind_key_names(int all, io_streams_t &streams) { const wcstring_list_t names = input_terminfo_get_names(!all); for (size_t i=0; i<names.size(); i++) { const wcstring &name = names.at(i); - append_format(stdout_buffer, L"%ls\n", name.c_str()); + streams.out.append_format( L"%ls\n", name.c_str()); } } @@ -505,19 +459,19 @@ static void builtin_bind_key_names(int all) Print all the special key binding functions to string buffer used for standard output. */ -static void builtin_bind_function_names() +static void builtin_bind_function_names(io_streams_t &streams) { wcstring_list_t names = input_function_get_names(); for (size_t i=0; i<names.size(); i++) { const wchar_t *seq = names.at(i).c_str(); - append_format(stdout_buffer, L"%ls\n", seq); + streams.out.append_format( L"%ls\n", seq); } } // Wraps input_terminfo_get_sequence(), appending the correct error messages as needed. -static int get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq) +static int get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq, io_streams_t &streams) { if (input_terminfo_get_sequence(seq, out_seq)) { @@ -528,19 +482,19 @@ static int get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq) { case ENOENT: { - append_format(stderr_buffer, _(L"%ls: No key with name '%ls' found\n"), L"bind", eseq.c_str()); + streams.err.append_format(_(L"%ls: No key with name '%ls' found\n"), L"bind", eseq.c_str()); break; } case EILSEQ: { - append_format(stderr_buffer, _(L"%ls: Key with name '%ls' does not have any mapping\n"), L"bind", eseq.c_str()); + streams.err.append_format(_(L"%ls: Key with name '%ls' does not have any mapping\n"), L"bind", eseq.c_str()); break; } default: { - append_format(stderr_buffer, _(L"%ls: Unknown error trying to bind to key named '%ls'\n"), L"bind", eseq.c_str()); + streams.err.append_format(_(L"%ls: Unknown error trying to bind to key named '%ls'\n"), L"bind", eseq.c_str()); break; } } @@ -550,14 +504,15 @@ static int get_terminfo_sequence(const wchar_t *seq, wcstring *out_seq) /** Add specified key binding. */ -static int builtin_bind_add(const wchar_t *seq, const wchar_t **cmds, size_t cmds_len, - const wchar_t *mode, const wchar_t *sets_mode, int terminfo) +static int builtin_bind_add(const wchar_t *seq, const wchar_t * const *cmds, size_t cmds_len, + const wchar_t *mode, const wchar_t *sets_mode, int terminfo, + io_streams_t &streams) { if (terminfo) { wcstring seq2; - if (get_terminfo_sequence(seq, &seq2)) + if (get_terminfo_sequence(seq, &seq2, streams)) { input_mapping_add(seq2.c_str(), cmds, cmds_len, mode, sets_mode); } @@ -583,7 +538,7 @@ static int builtin_bind_add(const wchar_t *seq, const wchar_t **cmds, size_t cmd \param all if specified, _all_ key bindings will be erased \param mode if specified, only bindings from that mode will be erased. If not given and \c all is \c false, \c DEFAULT_BIND_MODE will be used. */ -static int builtin_bind_erase(wchar_t **seq, int all, const wchar_t *mode, int use_terminfo) +static int builtin_bind_erase(wchar_t **seq, int all, const wchar_t *mode, int use_terminfo, io_streams_t &streams) { if (all) { @@ -611,7 +566,7 @@ static int builtin_bind_erase(wchar_t **seq, int all, const wchar_t *mode, int u if (use_terminfo) { wcstring seq2; - if (get_terminfo_sequence(*seq++, &seq2)) + if (get_terminfo_sequence(*seq++, &seq2, streams)) { input_mapping_erase(seq2, mode); } @@ -634,7 +589,7 @@ static int builtin_bind_erase(wchar_t **seq, int all, const wchar_t *mode, int u /** The bind builtin, used for setting character sequences */ -static int builtin_bind(parser_t &parser, wchar_t **argv) +static int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; enum @@ -689,11 +644,10 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; @@ -706,7 +660,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) break; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 'k': @@ -732,7 +686,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; @@ -752,7 +706,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) case BIND_ERASE: { - if (builtin_bind_erase(&argv[w.woptind], all, bind_mode_given ? bind_mode : NULL, use_terminfo)) + if (builtin_bind_erase(&argv[w.woptind], all, bind_mode_given ? bind_mode : NULL, use_terminfo, streams)) { res = STATUS_BUILTIN_ERROR; } @@ -765,7 +719,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) { case 0: { - builtin_bind_list(bind_mode_given ? bind_mode : NULL); + builtin_bind_list(bind_mode_given ? bind_mode : NULL, streams); break; } @@ -774,7 +728,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) wcstring seq; if (use_terminfo) { - if (!get_terminfo_sequence(argv[w.woptind], &seq)) + if (!get_terminfo_sequence(argv[w.woptind], &seq, streams)) { res = STATUS_BUILTIN_ERROR; // get_terminfo_sequence already printed the error @@ -785,17 +739,17 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) { seq = argv[w.woptind]; } - if (!builtin_bind_list_one(seq, bind_mode)) + if (!builtin_bind_list_one(seq, bind_mode, streams)) { res = STATUS_BUILTIN_ERROR; wcstring eseq = escape_string(argv[w.woptind], 0); if (use_terminfo) { - append_format(stderr_buffer, _(L"%ls: No binding found for key '%ls'\n"), argv[0], eseq.c_str()); + streams.err.append_format(_(L"%ls: No binding found for key '%ls'\n"), argv[0], eseq.c_str()); } else { - append_format(stderr_buffer, _(L"%ls: No binding found for sequence '%ls'\n"), argv[0], eseq.c_str()); + streams.err.append_format(_(L"%ls: No binding found for sequence '%ls'\n"), argv[0], eseq.c_str()); } } break; @@ -803,7 +757,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) default: { - if (builtin_bind_add(argv[w.woptind], (const wchar_t **)argv + (w.woptind + 1), argc - (w.woptind + 1), bind_mode, sets_bind_mode, use_terminfo)) + if (builtin_bind_add(argv[w.woptind], argv + (w.woptind + 1), argc - (w.woptind + 1), bind_mode, sets_bind_mode, use_terminfo, streams)) { res = STATUS_BUILTIN_ERROR; } @@ -816,14 +770,14 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) case BIND_KEY_NAMES: { - builtin_bind_key_names(all); + builtin_bind_key_names(all, streams); break; } case BIND_FUNCTION_NAMES: { - builtin_bind_function_names(); + builtin_bind_function_names(streams); break; } @@ -831,7 +785,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) default: { res = STATUS_BUILTIN_ERROR; - append_format(stderr_buffer, _(L"%ls: Invalid state\n"), argv[0]); + streams.err.append_format(_(L"%ls: Invalid state\n"), argv[0]); break; } } @@ -843,7 +797,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) /** The block builtin, used for temporarily blocking events */ -static int builtin_block(parser_t &parser, wchar_t **argv) +static int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; enum @@ -902,15 +856,14 @@ static int builtin_block(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 'g': @@ -926,7 +879,7 @@ static int builtin_block(parser_t &parser, wchar_t **argv) break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -937,13 +890,13 @@ static int builtin_block(parser_t &parser, wchar_t **argv) { if (scope != UNSET) { - append_format(stderr_buffer, _(L"%ls: Can not specify scope when removing block\n"), argv[0]); + streams.err.append_format(_(L"%ls: Can not specify scope when removing block\n"), argv[0]); return STATUS_BUILTIN_ERROR; } if (parser.global_event_blocks.empty()) { - append_format(stderr_buffer, _(L"%ls: No blocks defined\n"), argv[0]); + streams.err.append_format(_(L"%ls: No blocks defined\n"), argv[0]); return STATUS_BUILTIN_ERROR; } parser.global_event_blocks.pop_front(); @@ -1000,7 +953,7 @@ static int builtin_block(parser_t &parser, wchar_t **argv) additional operational modes, such as printing a list of all builtins, printing help, etc. */ -static int builtin_builtin(parser_t &parser, wchar_t **argv) +static int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc=builtin_count_args(argv); int list=0; @@ -1040,16 +993,15 @@ static int builtin_builtin(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 'n': @@ -1057,7 +1009,7 @@ static int builtin_builtin(parser_t &parser, wchar_t **argv) break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -1073,8 +1025,8 @@ static int builtin_builtin(parser_t &parser, wchar_t **argv) { const wchar_t *el = names.at(i).c_str(); - stdout_buffer.append(el); - stdout_buffer.append(L"\n"); + streams.out.append(el); + streams.out.append(L"\n"); } } return STATUS_BUILTIN_OK; @@ -1083,7 +1035,7 @@ static int builtin_builtin(parser_t &parser, wchar_t **argv) /** Implementation of the builtin emit command, used to create events. */ -static int builtin_emit(parser_t &parser, wchar_t **argv) +static int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; int argc=builtin_count_args(argv); @@ -1118,19 +1070,18 @@ static int builtin_emit(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -1139,7 +1090,7 @@ static int builtin_emit(parser_t &parser, wchar_t **argv) if (!argv[w.woptind]) { - append_format(stderr_buffer, L"%ls: expected event name\n", argv[0]); + streams.err.append_format(L"%ls: expected event name\n", argv[0]); return STATUS_BUILTIN_ERROR; } const wchar_t *eventname = argv[w.woptind]; @@ -1154,7 +1105,7 @@ static int builtin_emit(parser_t &parser, wchar_t **argv) Implementation of the builtin 'command'. Actual command running is handled by the parser, this just processes the flags. */ -static int builtin_command(parser_t &parser, wchar_t **argv) +static int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; int argc=builtin_count_args(argv); @@ -1187,15 +1138,14 @@ static int builtin_command(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 's': @@ -1204,7 +1154,7 @@ static int builtin_command(parser_t &parser, wchar_t **argv) break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -1213,7 +1163,7 @@ static int builtin_command(parser_t &parser, wchar_t **argv) if (!print_path) { - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_ERROR; } @@ -1225,7 +1175,7 @@ static int builtin_command(parser_t &parser, wchar_t **argv) wcstring path; if (path_get_path(command_name, &path)) { - append_format(stdout_buffer, L"%ls\n", path.c_str()); + streams.out.append_format( L"%ls\n", path.c_str()); ++found; } } @@ -1237,7 +1187,7 @@ static int builtin_command(parser_t &parser, wchar_t **argv) only a placeholder that prints the help message. Useful for commands that live in the parser. */ -static int builtin_generic(parser_t &parser, wchar_t **argv) +static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; int argc=builtin_count_args(argv); @@ -1245,7 +1195,7 @@ static int builtin_generic(parser_t &parser, wchar_t **argv) /* Hackish - if we have no arguments other than the command, we are a "naked invocation" and we just print help */ if (argc == 1) { - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_ERROR; } @@ -1273,19 +1223,18 @@ static int builtin_generic(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -1295,12 +1244,12 @@ static int builtin_generic(parser_t &parser, wchar_t **argv) } /** - Output a definition of the specified function to the specified - string. Used by the functions builtin. + Return a definition of the specified function. Used by the functions builtin. */ -static void functions_def(const wcstring &name, wcstring &out) +static wcstring functions_def(const wcstring &name) { - CHECK(! name.empty(),); + CHECK(! name.empty(), L""); + wcstring out; wcstring desc, def; function_get_desc(name, &desc); @@ -1426,13 +1375,14 @@ static void functions_def(const wcstring &name, wcstring &out) out.push_back(L'\n'); } out.append(L"end\n"); + return out; } /** The functions builtin, used for listing and erasing functions. */ -static int builtin_functions(parser_t &parser, wchar_t **argv) +static int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; int i; @@ -1500,11 +1450,10 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; @@ -1526,7 +1475,7 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) break; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 'q': @@ -1538,7 +1487,7 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -1550,11 +1499,10 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) */ if ((erase + (!!desc) + list + query + copy) > 1) { - append_format(stderr_buffer, - _(L"%ls: Invalid combination of options\n"), + streams.err.append_format(_(L"%ls: Invalid combination of options\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -1572,22 +1520,20 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) if (argc-w.woptind != 1) { - append_format(stderr_buffer, - _(L"%ls: Expected exactly one function name\n"), + streams.err.append_format(_(L"%ls: Expected exactly one function name\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } func = argv[w.woptind]; if (!function_exists(func)) { - append_format(stderr_buffer, - _(L"%ls: Function '%ls' does not exist\n"), + streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), argv[0], func); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -1598,7 +1544,7 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) } else if (list || (argc==w.woptind)) { - int is_screen = !builtin_out_redirect && isatty(1); + int is_screen = !streams.out_is_redirected && isatty(STDOUT_FILENO); size_t i; wcstring_list_t names = function_get_names(show_hidden); std::sort(names.begin(), names.end()); @@ -1612,14 +1558,14 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) buff.append(L", "); } - write_screen(buff, stdout_buffer); + streams.out.append(reformat_for_screen(buff)); } else { for (i=0; i<names.size(); i++) { - stdout_buffer.append(names.at(i).c_str()); - stdout_buffer.append(L"\n"); + streams.out.append(names.at(i).c_str()); + streams.out.append(L"\n"); } } @@ -1632,10 +1578,9 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) if (argc-w.woptind != 2) { - append_format(stderr_buffer, - _(L"%ls: Expected exactly two names (current function name, and new function name)\n"), + streams.err.append_format(_(L"%ls: Expected exactly two names (current function name, and new function name)\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -1644,34 +1589,31 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) if (!function_exists(current_func)) { - append_format(stderr_buffer, - _(L"%ls: Function '%ls' does not exist\n"), + streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), argv[0], current_func.c_str()); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } if ((wcsfuncname(new_func) != 0) || parser_keywords_is_reserved(new_func)) { - append_format(stderr_buffer, - _(L"%ls: Illegal function name '%ls'\n"), + streams.err.append_format(_(L"%ls: Illegal function name '%ls'\n"), argv[0], new_func.c_str()); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } // keep things simple: don't allow existing names to be copy targets. if (function_exists(new_func)) { - append_format(stderr_buffer, - _(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), + streams.err.append_format(_(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), argv[0], new_func.c_str(), current_func.c_str()); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -1690,9 +1632,9 @@ static int builtin_functions(parser_t &parser, wchar_t **argv) if (!query) { if (i != w.woptind) - stdout_buffer.append(L"\n"); + streams.out.append(L"\n"); - functions_def(argv[i], stdout_buffer); + streams.out.append(functions_def(argv[i])); } } } @@ -1812,7 +1754,7 @@ static bool builtin_echo_parse_numeric_sequence(const wchar_t *str, size_t *cons We also support a new option -s to mean "no spaces" */ -static int builtin_echo(parser_t &parser, wchar_t **argv) +static int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) { /* Skip first arg */ if (! *argv++) @@ -1878,7 +1820,7 @@ static int builtin_echo(parser_t &parser, wchar_t **argv) { if (print_spaces && idx > 0) { - stdout_buffer.push_back(' '); + streams.out.push_back(' '); } const wchar_t *str = args_to_echo[idx]; @@ -1887,7 +1829,7 @@ static int builtin_echo(parser_t &parser, wchar_t **argv) if (! interpret_special_chars || str[j] != L'\\') { /* Not an escape */ - stdout_buffer.push_back(str[j]); + streams.out.push_back(str[j]); } else { @@ -1953,20 +1895,20 @@ static int builtin_echo(parser_t &parser, wchar_t **argv) if (continue_output) { - stdout_buffer.push_back(wc); + streams.out.push_back(wc); } } } } if (print_newline && continue_output) { - stdout_buffer.push_back('\n'); + streams.out.push_back('\n'); } return STATUS_BUILTIN_OK; } /** The pwd builtin. We don't respect -P to resolve symbolic links because we try to always resolve them. */ -static int builtin_pwd(parser_t &parser, wchar_t **argv) +static int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wchar_t dir_path[4096]; wchar_t *res = wgetcwd(dir_path, 4096); @@ -1976,14 +1918,14 @@ static int builtin_pwd(parser_t &parser, wchar_t **argv) } else { - stdout_buffer.append(dir_path); - stdout_buffer.push_back(L'\n'); + streams.out.append(dir_path); + streams.out.push_back(L'\n'); return STATUS_BUILTIN_OK; } } /** Adds a function to the function set. It calls into function.cpp to perform any heavy lifting. */ -int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstring &contents, int definition_line_offset, wcstring *out_err) +int define_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args, const wcstring &contents, int definition_line_offset, wcstring *out_err) { wgetopter_t w; assert(out_err != NULL); @@ -2209,7 +2151,7 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr } case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 1: @@ -2218,7 +2160,7 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); res = 1; break; @@ -2340,7 +2282,7 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr /** The random builtin. For generating random numbers. */ -static int builtin_random(parser_t &parser, wchar_t **argv) +static int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) { static int seeded=0; static struct drand48_data seed_buffer; @@ -2379,20 +2321,19 @@ static int builtin_random(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); break; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -2413,7 +2354,7 @@ static int builtin_random(parser_t &parser, wchar_t **argv) } lrand48_r(&seed_buffer, &res); - append_format(stdout_buffer, L"%ld\n", labs(res%32767)); + streams.out.append_format( L"%ld\n", labs(res%32767)); break; } @@ -2426,8 +2367,7 @@ static int builtin_random(parser_t &parser, wchar_t **argv) foo = wcstol(argv[w.woptind], &end, 10); if (errno || *end) { - append_format(stderr_buffer, - _(L"%ls: Seed value '%ls' is not a valid number\n"), + streams.err.append_format(_(L"%ls: Seed value '%ls' is not a valid number\n"), argv[0], argv[w.woptind]); @@ -2440,11 +2380,10 @@ static int builtin_random(parser_t &parser, wchar_t **argv) default: { - append_format(stderr_buffer, - _(L"%ls: Expected zero or one argument, got %d\n"), + streams.err.append_format(_(L"%ls: Expected zero or one argument, got %d\n"), argv[0], argc-w.woptind); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } } @@ -2455,7 +2394,7 @@ static int builtin_random(parser_t &parser, wchar_t **argv) /** The read builtin. Reads from stdin and stores the values in environment variables. */ -static int builtin_read(parser_t &parser, wchar_t **argv) +static int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; wcstring buff; @@ -2554,11 +2493,10 @@ static int builtin_read(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; @@ -2606,19 +2544,17 @@ static int builtin_read(parser_t &parser, wchar_t **argv) switch (errno) { case ERANGE: - append_format(stderr_buffer, - _(L"%ls: Argument '%ls' is out of range\n"), + streams.err.append_format( _(L"%ls: Argument '%ls' is out of range\n"), argv[0], w.woptarg); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; default: - append_format(stderr_buffer, - _(L"%ls: Argument '%ls' must be an integer\n"), + streams.err.append_format( _(L"%ls: Argument '%ls' must be an integer\n"), argv[0], w.woptarg); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } } @@ -2637,11 +2573,11 @@ static int builtin_read(parser_t &parser, wchar_t **argv) break; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case L'?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -2649,29 +2585,27 @@ static int builtin_read(parser_t &parser, wchar_t **argv) if ((place & ENV_UNEXPORT) && (place & ENV_EXPORT)) { - append_format(stderr_buffer, - BUILTIN_ERR_EXPUNEXP, + streams.err.append_format(BUILTIN_ERR_EXPUNEXP, argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } if ((place&ENV_LOCAL?1:0) + (place & ENV_GLOBAL?1:0) + (place & ENV_UNIVERSAL?1:0) > 1) { - append_format(stderr_buffer, - BUILTIN_ERR_GLOCAL, + streams.err.append_format(BUILTIN_ERR_GLOCAL, argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } if (array && w.woptind+1 != argc) { - append_format(stderr_buffer, _(L"%ls: --array option requires a single variable name.\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + streams.err.append_format(_(L"%ls: --array option requires a single variable name.\n"), argv[0]); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -2685,7 +2619,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) if (!wcslen(argv[i])) { - append_format(stderr_buffer, BUILTIN_ERR_VARNAME_ZERO, argv[0]); + streams.err.append_format(BUILTIN_ERR_VARNAME_ZERO, argv[0]); return STATUS_BUILTIN_ERROR; } @@ -2693,8 +2627,8 @@ static int builtin_read(parser_t &parser, wchar_t **argv) { if ((!iswalnum(*src)) && (*src != L'_')) { - append_format(stderr_buffer, BUILTIN_ERR_VARCHAR, argv[0], *src); - builtin_print_help(parser, argv[0], stderr_buffer); + streams.err.append_format(BUILTIN_ERR_VARCHAR, argv[0], *src); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } } @@ -2709,7 +2643,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) /* Check if we should read interactively using \c reader_readline() */ - if (isatty(0) && builtin_stdin == 0 && !split_null) + if (isatty(0) && streams.stdin_fd == STDIN_FILENO && !split_null) { const wchar_t *line; @@ -2770,7 +2704,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) while (!finished) { char b; - if (read_blocked(builtin_stdin, &b, 1) <= 0) + if (read_blocked(streams.stdin_fd, &b, 1) <= 0) { eof=1; break; @@ -2898,7 +2832,7 @@ static int builtin_read(parser_t &parser, wchar_t **argv) /** The status builtin. Gives various status information on fish. */ -static int builtin_status(parser_t &parser, wchar_t **argv) +static int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; enum @@ -2998,11 +2932,10 @@ static int builtin_status(parser_t &parser, wchar_t **argv) case 0: if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'c': @@ -3030,7 +2963,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv) break; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case 'j': @@ -3042,8 +2975,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv) job_control_mode = JOB_CONTROL_NONE; else { - append_format(stderr_buffer, - L"%ls: Invalid job control mode '%ls'\n", + streams.err.append_format(L"%ls: Invalid job control mode '%ls'\n", L"status", w.woptarg); res = 1; } @@ -3056,11 +2988,11 @@ static int builtin_status(parser_t &parser, wchar_t **argv) case ':': - builtin_missing_argument(parser, argv[0], argv[w.woptind-1]); + builtin_missing_argument(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } @@ -3079,14 +3011,14 @@ static int builtin_status(parser_t &parser, wchar_t **argv) if (!fn) fn = _(L"Standard input"); - append_format(stdout_buffer, L"%ls\n", fn); + streams.out.append_format( L"%ls\n", fn); break; } case CURRENT_LINE_NUMBER: { - append_format(stdout_buffer, L"%d\n", parser.get_lineno()); + streams.out.append_format( L"%d\n", parser.get_lineno()); break; } @@ -3113,22 +3045,21 @@ static int builtin_status(parser_t &parser, wchar_t **argv) case STACK_TRACE: { - parser.stack_trace(0, stdout_buffer); + streams.out.append(parser.stack_trace()); break; } case NORMAL: { if (is_login) - append_format(stdout_buffer, _(L"This is a login shell\n")); + streams.out.append_format( _(L"This is a login shell\n")); else - append_format(stdout_buffer, _(L"This is not a login shell\n")); + streams.out.append_format( _(L"This is not a login shell\n")); - append_format(stdout_buffer, _(L"Job control: %ls\n"), + streams.out.append_format( _(L"Job control: %ls\n"), job_control_mode==JOB_CONTROL_INTERACTIVE?_(L"Only on interactive jobs"): (job_control_mode==JOB_CONTROL_NONE ? _(L"Never") : _(L"Always"))); - - parser.stack_trace(0, stdout_buffer); + streams.out.append(parser.stack_trace()); break; } } @@ -3141,7 +3072,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv) /** The exit builtin. Calls reader_exit to exit and returns the value specified. */ -static int builtin_exit(parser_t &parser, wchar_t **argv) +static int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc = builtin_count_args(argv); @@ -3161,11 +3092,10 @@ static int builtin_exit(parser_t &parser, wchar_t **argv) ec = wcstol(argv[1],&end,10); if (errno || *end != 0) { - append_format(stderr_buffer, - _(L"%ls: Argument '%ls' must be an integer\n"), + streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), argv[0], argv[1]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } break; @@ -3173,11 +3103,10 @@ static int builtin_exit(parser_t &parser, wchar_t **argv) default: { - append_format(stderr_buffer, - BUILTIN_ERR_TOO_MANY_ARGUMENTS, + streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -3191,7 +3120,7 @@ static int builtin_exit(parser_t &parser, wchar_t **argv) or to $HOME if none is specified. The directory can be relative to any directory in the CDPATH variable. */ -static int builtin_cd(parser_t &parser, wchar_t **argv) +static int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) { env_var_t dir_in; wcstring dir; @@ -3203,8 +3132,7 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) dir_in = env_get_string(L"HOME"); if (dir_in.missing_or_empty()) { - append_format(stderr_buffer, - _(L"%ls: Could not find home directory\n"), + streams.err.append_format(_(L"%ls: Could not find home directory\n"), argv[0]); } } @@ -3223,30 +3151,26 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) { if (errno == ENOTDIR) { - append_format(stderr_buffer, - _(L"%ls: '%ls' is not a directory\n"), + streams.err.append_format(_(L"%ls: '%ls' is not a directory\n"), argv[0], dir_in.c_str()); } else if (errno == ENOENT) { - append_format(stderr_buffer, - _(L"%ls: The directory '%ls' does not exist\n"), + streams.err.append_format(_(L"%ls: The directory '%ls' does not exist\n"), argv[0], dir_in.c_str()); } else if (errno == EROTTEN) { - append_format(stderr_buffer, - _(L"%ls: '%ls' is a rotten symlink\n"), + streams.err.append_format(_(L"%ls: '%ls' is a rotten symlink\n"), argv[0], dir_in.c_str()); } else { - append_format(stderr_buffer, - _(L"%ls: Unknown error trying to locate directory '%ls'\n"), + streams.err.append_format(_(L"%ls: Unknown error trying to locate directory '%ls'\n"), argv[0], dir_in.c_str()); @@ -3255,7 +3179,7 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) if (!get_is_interactive()) { - stderr_buffer.append(parser.current_line()); + streams.err.append(parser.current_line()); } res = 1; @@ -3268,8 +3192,7 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) status = wstat(dir, &buffer); if (!status && S_ISDIR(buffer.st_mode)) { - append_format(stderr_buffer, - _(L"%ls: Permission denied: '%ls'\n"), + streams.err.append_format(_(L"%ls: Permission denied: '%ls'\n"), argv[0], dir.c_str()); @@ -3277,15 +3200,14 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) else { - append_format(stderr_buffer, - _(L"%ls: '%ls' is not a directory\n"), + streams.err.append_format(_(L"%ls: '%ls' is not a directory\n"), argv[0], dir.c_str()); } if (!get_is_interactive()) { - stderr_buffer.append(parser.current_line()); + streams.err.append(parser.current_line()); } res = 1; @@ -3293,7 +3215,7 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) else if (!env_set_pwd()) { res=1; - append_format(stderr_buffer, _(L"%ls: Could not set PWD variable\n"), argv[0]); + streams.err.append_format(_(L"%ls: Could not set PWD variable\n"), argv[0]); } return res; @@ -3303,11 +3225,11 @@ static int builtin_cd(parser_t &parser, wchar_t **argv) Implementation of the builtin count command, used to count the number of arguments sent to it. */ -static int builtin_count(parser_t &parser, wchar_t ** argv) +static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc; argc = builtin_count_args(argv); - append_format(stdout_buffer, L"%d\n", argc-1); + streams.out.append_format( L"%d\n", argc-1); return !(argc-1); } @@ -3315,7 +3237,7 @@ static int builtin_count(parser_t &parser, wchar_t ** argv) Implementation of the builtin contains command, used to check if a specified string is part of a list. */ -static int builtin_contains(parser_t &parser, wchar_t ** argv) +static int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t ** argv) { wgetopter_t w; int argc; @@ -3348,25 +3270,24 @@ static int builtin_contains(parser_t &parser, wchar_t ** argv) assert(opt_index >= 0 && (size_t)opt_index < sizeof long_options / sizeof *long_options); if (long_options[opt_index].flag != 0) break; - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], long_options[opt_index].name); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; case ':': - builtin_missing_argument(parser, argv[0], argv[w.woptind-1]); + builtin_missing_argument(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; case '?': - builtin_unknown_option(parser, argv[0], argv[w.woptind-1]); + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; case 'i': @@ -3379,7 +3300,7 @@ static int builtin_contains(parser_t &parser, wchar_t ** argv) needle = argv[w.woptind]; if (!needle) { - append_format(stderr_buffer, _(L"%ls: Key not specified\n"), argv[0]); + streams.err.append_format(_(L"%ls: Key not specified\n"), argv[0]); } @@ -3388,7 +3309,7 @@ static int builtin_contains(parser_t &parser, wchar_t ** argv) if (!wcscmp(needle, argv[i])) { - if (should_output_index) append_format(stdout_buffer, L"%d\n", i-w.woptind); + if (should_output_index) streams.out.append_format( L"%d\n", i-w.woptind); return 0; } } @@ -3400,7 +3321,7 @@ static int builtin_contains(parser_t &parser, wchar_t ** argv) /** The . (dot) builtin, sometimes called source. Evaluates the contents of a file. */ -static int builtin_source(parser_t &parser, wchar_t ** argv) +static int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { ASSERT_IS_MAIN_THREAD(); int fd; @@ -3416,30 +3337,30 @@ static int builtin_source(parser_t &parser, wchar_t ** argv) { fn = L"-"; fn_intern = fn; - fd = dup(builtin_stdin); + fd = dup(streams.stdin_fd); } else { if ((fd = wopen_cloexec(argv[1], O_RDONLY)) == -1) { - append_format(stderr_buffer, _(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]); - builtin_wperror(L"source"); + streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]); + builtin_wperror(L"source", streams); return STATUS_BUILTIN_ERROR; } if (fstat(fd, &buf) == -1) { close(fd); - append_format(stderr_buffer, _(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]); - builtin_wperror(L"source"); + streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), argv[0], argv[1]); + builtin_wperror(L"source", streams); return STATUS_BUILTIN_ERROR; } if (!S_ISREG(buf.st_mode)) { close(fd); - append_format(stderr_buffer, _(L"%ls: '%ls' is not a file\n"), argv[0], argv[1]); + streams.err.append_format(_(L"%ls: '%ls' is not a file\n"), argv[0], argv[1]); return STATUS_BUILTIN_ERROR; } @@ -3451,14 +3372,13 @@ static int builtin_source(parser_t &parser, wchar_t ** argv) env_set_argv((argc>2)?(argv+2):(argv+1)); - res = reader_read(fd, real_io ? *real_io : io_chain_t()); + res = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(); if (res) { - append_format(stderr_buffer, - _(L"%ls: Error while reading file '%ls'\n"), + streams.err.append_format(_(L"%ls: Error while reading file '%ls'\n"), argv[0], fn_intern == intern_static(L"-") ? L"<stdin>" : fn_intern); } @@ -3491,7 +3411,7 @@ static void make_first(job_t *j) /** Builtin for putting a job in the foreground */ -static int builtin_fg(parser_t &parser, wchar_t **argv) +static int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { job_t *j=NULL; @@ -3513,8 +3433,7 @@ static int builtin_fg(parser_t &parser, wchar_t **argv) } if (!j) { - append_format(stderr_buffer, - _(L"%ls: There are no suitable jobs\n"), + streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), argv[0]); } } @@ -3541,19 +3460,17 @@ static int builtin_fg(parser_t &parser, wchar_t **argv) if (found_job) { - append_format(stderr_buffer, - _(L"%ls: Ambiguous job\n"), + streams.err.append_format(_(L"%ls: Ambiguous job\n"), argv[0]); } else { - append_format(stderr_buffer, - _(L"%ls: '%ls' is not a job\n"), + streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[1]); } - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); j=0; @@ -3567,32 +3484,29 @@ static int builtin_fg(parser_t &parser, wchar_t **argv) if (*end || errno) { - append_format(stderr_buffer, - BUILTIN_ERR_NOT_NUMBER, + streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, argv[0], argv[1]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); } else { j = job_get_from_pid(pid); if (!j || !job_get_flag(j, JOB_CONSTRUCTED) || job_is_completed(j)) { - append_format(stderr_buffer, - _(L"%ls: No suitable job: %d\n"), + streams.err.append_format(_(L"%ls: No suitable job: %d\n"), argv[0], pid); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); j=0; } else if (!job_get_flag(j, JOB_CONTROL)) { - append_format(stderr_buffer, - _(L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n"), + streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n"), argv[0], pid, j->command_wcstr()); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); j=0; } } @@ -3600,10 +3514,9 @@ static int builtin_fg(parser_t &parser, wchar_t **argv) if (j) { - if (builtin_err_redirect) + if (streams.err_is_redirected) { - append_format(stderr_buffer, - FG_MSG, + streams.err.append_format(FG_MSG, j->job_id, j->command_wcstr()); } @@ -3636,31 +3549,28 @@ static int builtin_fg(parser_t &parser, wchar_t **argv) /** Helper function for builtin_bg() */ -static int send_to_bg(parser_t &parser, job_t *j, const wchar_t *name) +static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j, const wchar_t *name) { if (j == 0) { - append_format(stderr_buffer, - _(L"%ls: Unknown job '%ls'\n"), + streams.err.append_format(_(L"%ls: Unknown job '%ls'\n"), L"bg", name); - builtin_print_help(parser, L"bg", stderr_buffer); + builtin_print_help(parser, streams, L"bg", streams.err); return STATUS_BUILTIN_ERROR; } else if (!job_get_flag(j, JOB_CONTROL)) { - append_format(stderr_buffer, - _(L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n"), + streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n"), L"bg", j->job_id, j->command_wcstr()); - builtin_print_help(parser, L"bg", stderr_buffer); + builtin_print_help(parser, streams, L"bg", streams.err); return STATUS_BUILTIN_ERROR; } else { - append_format(stderr_buffer, - _(L"Send job %d '%ls' to background\n"), + streams.err.append_format(_(L"Send job %d '%ls' to background\n"), j->job_id, j->command_wcstr()); } @@ -3674,7 +3584,7 @@ static int send_to_bg(parser_t &parser, job_t *j, const wchar_t *name) /** Builtin for putting a job in the background */ -static int builtin_bg(parser_t &parser, wchar_t **argv) +static int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int res = STATUS_BUILTIN_OK; @@ -3692,14 +3602,13 @@ static int builtin_bg(parser_t &parser, wchar_t **argv) if (!j) { - append_format(stderr_buffer, - _(L"%ls: There are no suitable jobs\n"), + streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), argv[0]); res = 1; } else { - res = send_to_bg(parser, j, _(L"(default)")); + res = send_to_bg(parser, streams, j, _(L"(default)")); } } else @@ -3715,8 +3624,7 @@ static int builtin_bg(parser_t &parser, wchar_t **argv) pid = fish_wcstoi(argv[i], &end, 10); if (errno || pid < 0 || *end || !job_get_from_pid(pid)) { - append_format(stderr_buffer, - _(L"%ls: '%ls' is not a job\n"), + streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[i]); err = 1; @@ -3729,7 +3637,7 @@ static int builtin_bg(parser_t &parser, wchar_t **argv) for (i=1; !res && argv[i]; i++) { pid = fish_wcstoi(argv[i], 0, 10); - res |= send_to_bg(parser, job_get_from_pid(pid), *argv); + res |= send_to_bg(parser, streams, job_get_from_pid(pid), *argv); } } } @@ -3742,7 +3650,7 @@ static int builtin_bg(parser_t &parser, wchar_t **argv) This function handles both the 'continue' and the 'break' builtins that are used for loop control. */ -static int builtin_break_continue(parser_t &parser, wchar_t **argv) +static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int is_break = (wcscmp(argv[0],L"break")==0); int argc = builtin_count_args(argv); @@ -3750,12 +3658,11 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) if (argc != 1) { - append_format(stderr_buffer, - BUILTIN_ERR_UNKNOWN, + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], argv[1]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -3770,10 +3677,9 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) if (loop_idx >= parser.block_count()) { - append_format(stderr_buffer, - _(L"%ls: Not inside of loop\n"), + streams.err.append_format(_(L"%ls: Not inside of loop\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -3796,11 +3702,11 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) interactive debugger. */ -static int builtin_breakpoint(parser_t &parser, wchar_t **argv) +static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) { parser.push_block(new breakpoint_block_t()); - reader_read(STDIN_FILENO, real_io ? *real_io : io_chain_t()); + reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(); @@ -3811,7 +3717,7 @@ static int builtin_breakpoint(parser_t &parser, wchar_t **argv) /** Function for handling the \c return builtin */ -static int builtin_return(parser_t &parser, wchar_t **argv) +static int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc = builtin_count_args(argv); int status = proc_get_last_status(); @@ -3827,20 +3733,18 @@ static int builtin_return(parser_t &parser, wchar_t **argv) status = fish_wcstoi(argv[1],&end,10); if (errno || *end != 0) { - append_format(stderr_buffer, - _(L"%ls: Argument '%ls' must be an integer\n"), + streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), argv[0], argv[1]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } break; } default: - append_format(stderr_buffer, - _(L"%ls: Too many arguments\n"), + streams.err.append_format(_(L"%ls: Too many arguments\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -3855,10 +3759,9 @@ static int builtin_return(parser_t &parser, wchar_t **argv) if (function_block_idx >= parser.block_count()) { - append_format(stderr_buffer, - _(L"%ls: Not inside of function\n"), + streams.err.append_format(_(L"%ls: Not inside of function\n"), argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); + builtin_print_help(parser, streams, argv[0], streams.err); return STATUS_BUILTIN_ERROR; } @@ -3875,7 +3778,7 @@ static int builtin_return(parser_t &parser, wchar_t **argv) /** History of commands executed by user */ -static int builtin_history(parser_t &parser, wchar_t **argv) +static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc = builtin_count_args(argv); @@ -3934,15 +3837,15 @@ static int builtin_history(parser_t &parser, wchar_t **argv) merge_history = true; break; case 'h': - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; break; case '?': - append_format(stderr_buffer, BUILTIN_ERR_UNKNOWN, argv[0], argv[w.woptind-1]); + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; break; default: - append_format(stderr_buffer, BUILTIN_ERR_UNKNOWN, argv[0], argv[w.woptind-1]); + streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], argv[w.woptind-1]); return STATUS_BUILTIN_ERROR; } } @@ -3954,8 +3857,8 @@ static int builtin_history(parser_t &parser, wchar_t **argv) { wcstring full_history; history->get_string_representation(&full_history, wcstring(L"\n")); - stdout_buffer.append(full_history); - stdout_buffer.push_back('\n'); + streams.out.append(full_history); + streams.out.push_back('\n'); return STATUS_BUILTIN_OK; } @@ -3972,15 +3875,15 @@ static int builtin_history(parser_t &parser, wchar_t **argv) const wcstring &search_string = *iter; if (search_string.empty()) { - append_format(stderr_buffer, BUILTIN_ERR_COMBO2, argv[0], L"Use --search with either --contains or --prefix"); + streams.err.append_format(BUILTIN_ERR_COMBO2, argv[0], L"Use --search with either --contains or --prefix"); return res; } history_search_t searcher = history_search_t(*history, search_string, search_prefix?HISTORY_SEARCH_TYPE_PREFIX:HISTORY_SEARCH_TYPE_CONTAINS); while (searcher.go_backwards()) { - stdout_buffer.append(searcher.current_string()); - stdout_buffer.append(L"\n"); + streams.out.append(searcher.current_string()); + streams.out.append(L"\n"); res = STATUS_BUILTIN_OK; } } @@ -4016,7 +3919,7 @@ static int builtin_history(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } -int builtin_parse(parser_t &parser, wchar_t **argv) +int builtin_parse(parser_t &parser, io_streams_t &streams, wchar_t **argv) { struct sigaction act; sigemptyset(& act.sa_mask); @@ -4028,7 +3931,7 @@ int builtin_parse(parser_t &parser, wchar_t **argv) for (;;) { char buff[256]; - ssize_t amt = read_loop(builtin_stdin, buff, sizeof buff); + ssize_t amt = read_loop(streams.stdin_fd, buff, sizeof buff); if (amt <= 0) break; txt.insert(txt.end(), buff, buff + amt); } @@ -4040,30 +3943,30 @@ int builtin_parse(parser_t &parser, wchar_t **argv) bool success = parse_tree_from_string(src, parse_flag_include_comments, &parse_tree, &errors); if (! success) { - stdout_buffer.append(L"Parsing failed:\n"); + streams.out.append(L"Parsing failed:\n"); for (size_t i=0; i < errors.size(); i++) { - stdout_buffer.append(errors.at(i).describe(src)); - stdout_buffer.push_back(L'\n'); + streams.out.append(errors.at(i).describe(src)); + streams.out.push_back(L'\n'); } - stdout_buffer.append(L"(Reparsed with continue after error)\n"); + streams.out.append(L"(Reparsed with continue after error)\n"); parse_tree.clear(); errors.clear(); parse_tree_from_string(src, parse_flag_continue_after_error | parse_flag_include_comments, &parse_tree, &errors); } const wcstring dump = parse_dump_tree(parse_tree, src); - stdout_buffer.append(dump); + streams.out.append(dump); } return STATUS_BUILTIN_OK; } -int builtin_true(parser_t &parser, wchar_t **argv) +int builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_BUILTIN_OK; } -int builtin_false(parser_t &parser, wchar_t **argv) +int builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_BUILTIN_ERROR; } @@ -4179,23 +4082,21 @@ static int internal_help(const wchar_t *cmd) } -int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t &io) +int builtin_run(parser_t &parser, const wchar_t * const *argv, io_streams_t &streams) { - int (*cmd)(parser_t &parser, const wchar_t * const *argv)=0; + int (*cmd)(parser_t &parser, io_streams_t &streams, const wchar_t * const *argv)=NULL; - scoped_push<const io_chain_t*> set_real_io(&real_io, &io); - CHECK(argv, STATUS_BUILTIN_ERROR); CHECK(argv[0], STATUS_BUILTIN_ERROR); const builtin_data_t *data = builtin_lookup(argv[0]); - cmd = (int (*)(parser_t &parser, const wchar_t * const*))(data ? data->func : NULL); + cmd = (int (*)(parser_t &parser, io_streams_t &streams, const wchar_t * const*))(data ? data->func : NULL); if (argv[1] != 0 && !internal_help(argv[0])) { if (argv[2] == 0 && (parse_util_argument_is_help(argv[1], 0))) { - builtin_print_help(parser, argv[0], stdout_buffer); + builtin_print_help(parser, streams, argv[0], streams.out); return STATUS_BUILTIN_OK; } } @@ -4204,7 +4105,7 @@ int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t { int status; - status = cmd(parser, argv); + status = cmd(parser, streams, argv); return status; } @@ -4247,36 +4148,3 @@ wcstring builtin_get_desc(const wcstring &name) } return result; } - -void builtin_push_io(parser_t &parser, int in) -{ - ASSERT_IS_MAIN_THREAD(); - if (builtin_stdin != -1) - { - struct io_stack_elem_t elem = {builtin_stdin, stdout_buffer, stderr_buffer}; - io_stack.push(elem); - } - builtin_stdin = in; - stdout_buffer.clear(); - stderr_buffer.clear(); -} - -void builtin_pop_io(parser_t &parser) -{ - ASSERT_IS_MAIN_THREAD(); - builtin_stdin = 0; - if (! io_stack.empty()) - { - struct io_stack_elem_t &elem = io_stack.top(); - stderr_buffer = elem.err; - stdout_buffer = elem.out; - builtin_stdin = elem.in; - io_stack.pop(); - } - else - { - stdout_buffer.clear(); - stderr_buffer.clear(); - builtin_stdin = 0; - } -} |