From c1bd3b5824027f23b41bbac77c5e28f856c5dc18 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 21 Sep 2015 11:24:49 -0700 Subject: 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. --- src/builtin.cpp | 760 +++++++++++++++++++++++--------------------------------- 1 file changed, 314 insertions(+), 446 deletions(-) (limited to 'src/builtin.cpp') 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; - -/** - 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 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 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 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 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"" : 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 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; - } -} -- cgit v1.2.3