From b118ed69d3be39aec1971aebc5ca6a613bb8741e Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Mon, 2 Jan 2017 21:11:53 -0800 Subject: [PATCH] convert narrow stderr output to wide forms On some platforms, notably GNU libc, you cannot mix narrow and wide stdio functions on a stream like stdout or stderr. Doing so will drop the output of one or the other. This change makes all output to the stderr stream consistently use the wide forms. This change also converts some fprintf(stderr,...) calls to debug() calls where appropriate. Fixes #3692 --- src/common.cpp | 29 +++++--------- src/common.h | 60 +++++++++++++-------------- src/env_universal_common.cpp | 23 ++++++----- src/exec.cpp | 4 -- src/fish_indent.cpp | 4 +- src/fish_key_reader.cpp | 78 ++++++++++++++++++------------------ src/fish_tests.cpp | 27 +++++-------- src/highlight.cpp | 2 +- src/input.cpp | 2 +- src/io.cpp | 22 +++++----- src/iothread.cpp | 3 +- src/parse_constants.h | 8 ++-- src/parse_execution.cpp | 18 ++++----- src/parse_productions.cpp | 10 ++--- src/parse_tree.cpp | 25 ++++++------ src/parser.cpp | 3 +- src/path.cpp | 2 +- src/postfork.cpp | 17 ++++---- src/proc.cpp | 2 +- src/reader.cpp | 6 +-- src/screen.cpp | 2 +- 21 files changed, 165 insertions(+), 182 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 5de756383..bdc476ec2 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -541,9 +541,7 @@ bool should_suppress_stderr_for_tests() { static bool should_debug(int level) { if (level > debug_level) return false; - if (should_suppress_stderr_for_tests()) return false; - return true; } @@ -1534,9 +1532,8 @@ int create_directory(const wcstring &d) { } __attribute__((noinline)) void bugreport() { - debug(1, _(L"This is a bug. Break on bugreport to debug. " - L"If you can reproduce it, please send a bug report to %s."), - PACKAGE_BUGREPORT); + debug(0, _(L"This is a bug. Break on bugreport to debug.")); + debug(0, _(L"If you can reproduce it, please send a bug report to %s."), PACKAGE_BUGREPORT); } wcstring format_size(long long sz) { @@ -1722,28 +1719,24 @@ bool is_main_thread() { void assert_is_main_thread(const char *who) { if (!is_main_thread() && !thread_asserts_cfg_for_testing) { - fprintf(stderr, - "Warning: %s called off of main thread. Break on debug_thread_error to debug.\n", - who); + debug(0, "%s called off of main thread.", who); + debug(0, "Break on debug_thread_error to debug."); debug_thread_error(); } } void assert_is_not_forked_child(const char *who) { if (is_forked_child()) { - fprintf(stderr, - "Warning: %s called in a forked child. Break on debug_thread_error to debug.\n", - who); + debug(0, "%s called in a forked child.", who); + debug(0, "Break on debug_thread_error to debug."); debug_thread_error(); } } void assert_is_background_thread(const char *who) { if (is_main_thread() && !thread_asserts_cfg_for_testing) { - fprintf(stderr, - "Warning: %s called on the main thread (may block!). Break on debug_thread_error " - "to debug.\n", - who); + debug(0, "%s called on the main thread (may block!).", who); + debug(0, "Break on debug_thread_error to debug."); debug_thread_error(); } } @@ -1751,10 +1744,8 @@ void assert_is_background_thread(const char *who) { void assert_is_locked(void *vmutex, const char *who, const char *caller) { pthread_mutex_t *mutex = static_cast(vmutex); if (0 == pthread_mutex_trylock(mutex)) { - fprintf(stderr, - "Warning: %s is not locked when it should be in '%s'. Break on debug_thread_error " - "to debug.\n", - who, caller); + debug(0, "%s is not locked when it should be in '%s'", who, caller); + debug(0, "Break on debug_thread_error to debug."); debug_thread_error(); pthread_mutex_unlock(mutex); } diff --git a/src/common.h b/src/common.h index 09edff927..f0ec546df 100644 --- a/src/common.h +++ b/src/common.h @@ -143,6 +143,26 @@ inline bool selection_direction_is_cardinal(selection_direction_t dir) { } } +/// Issue a debug message with printf-style string formating and automatic line breaking. The string +/// will begin with the string \c program_name, followed by a colon and a whitespace. +/// +/// Because debug is often called to tell the user about an error, before using wperror to give a +/// specific error message, debug will never ever modify the value of errno. +/// +/// \param level the priority of the message. Lower number means higher priority. Messages with a +/// priority_number higher than \c debug_level will be ignored.. +/// \param msg the message format string. +/// +/// Example: +/// +/// debug( 1, L"Pi = %.3f", M_PI ); +/// +/// will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that +/// program_name is 'fish'. +void __attribute__((noinline)) debug(int level, const char *msg, ...) + __attribute__((format(printf, 2, 3))); +void __attribute__((noinline)) debug(int level, const wchar_t *msg, ...); + /// Helper macro for errors. #define VOMIT_ON_FAILURE(a) \ do { \ @@ -157,12 +177,12 @@ inline bool selection_direction_is_cardinal(selection_direction_t dir) { VOMIT_ABORT(err, #a); \ } \ } while (0) -#define VOMIT_ABORT(err, str) \ - do { \ - int code = (err); \ - fprintf(stderr, "%s failed on line %d in file %s: %d (%s)\n", str, __LINE__, __FILE__, \ - code, strerror(code)); \ - abort(); \ +#define VOMIT_ABORT(err, str) \ + do { \ + int code = (err); \ + debug(0, "%s failed on line %d in file %s: %d (%s)", str, __LINE__, __FILE__, code, \ + strerror(code)); \ + abort(); \ } while (0) /// Exits without invoking destructors (via _exit), useful for code after fork. @@ -224,11 +244,10 @@ extern bool has_working_tty_timestamps; } /// Exit program at once after emitting an error message. -#define DIE(msg) \ - { \ - fprintf(stderr, "fish: %s on line %ld of file %s, shutting down fish\n", msg, \ - (long)__LINE__, __FILE__); \ - FATAL_EXIT(); \ +#define DIE(msg) \ + { \ + debug(0, "%s on line %ld of file %s, shutting down fish", msg, (long)__LINE__, __FILE__); \ + FATAL_EXIT(); \ } /// Exit program at once, leaving an error message about running out of memory. @@ -659,25 +678,6 @@ ssize_t write_loop(int fd, const char *buff, size_t count); /// error. ssize_t read_loop(int fd, void *buff, size_t count); -/// Issue a debug message with printf-style string formating and automatic line breaking. The string -/// will begin with the string \c program_name, followed by a colon and a whitespace. -/// -/// Because debug is often called to tell the user about an error, before using wperror to give a -/// specific error message, debug will never ever modify the value of errno. -/// -/// \param level the priority of the message. Lower number means higher priority. Messages with a -/// priority_number higher than \c debug_level will be ignored.. -/// \param msg the message format string. -/// -/// Example: -/// -/// debug( 1, L"Pi = %.3f", M_PI ); -/// -/// will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that -/// program_name is 'fish'. -void __attribute__((noinline)) debug(int level, const char *msg, ...) - __attribute__((format(printf, 2, 3))); -void __attribute__((noinline)) debug(int level, const wchar_t *msg, ...); /// Replace special characters with backslash escape sequences. Newline is replaced with \n, etc. /// diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index de47fe07b..d60bb705c 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -95,7 +95,8 @@ static const wcstring default_vars_path() { return vars_filename_in_directory(path); } -/// Check, and create if necessary, a secure runtime path Derived from tmux.c in tmux +#if !defined(__APPLE__) && !defined(__CYGWIN__) +/// Check, and create if necessary, a secure runtime path. Derived from tmux.c in tmux /// (http://tmux.sourceforge.net/). static int check_runtime_path(const char *path) { // Copyright (c) 2007 Nicholas Marriott @@ -143,9 +144,8 @@ static wcstring get_runtime_path() { std::string tmpdir = "/tmp/fish."; tmpdir.append(uname); if (check_runtime_path(tmpdir.c_str()) != 0) { - debug(0, - L"Runtime path not available. Try deleting the directory %s and restarting fish.", - tmpdir.c_str()); + debug(0, L"Runtime path not available."); + debug(0, L"Try deleting the directory %s and restarting fish.", tmpdir.c_str()); } else { result = str2wcstring(tmpdir); } @@ -159,6 +159,7 @@ static wcstring default_named_pipe_path() { // Note that vars_filename_in_directory returns empty string when passed the empty string. return vars_filename_in_directory(get_runtime_path()); } +#endif /// Test if the message msg contains the command cmd. static bool match(const wchar_t *msg, const wchar_t *cmd) { @@ -1121,10 +1122,8 @@ class universal_notifier_notifyd_t : public universal_notifier_t { uint32_t status = notify_register_file_descriptor(name.c_str(), &this->notify_fd, 0, &this->token); if (status != NOTIFY_STATUS_OK) { - fprintf(stderr, - "Warning: notify_register_file_descriptor() failed with status %u. Universal " - "variable notifications may not be received.", - status); + debug(1, "notify_register_file_descriptor() failed with status %u.", status); + debug(1, "Universal variable notifications may not be received."); } if (this->notify_fd >= 0) { // Mark us for non-blocking reads, and CLO_EXEC. @@ -1184,8 +1183,10 @@ class universal_notifier_notifyd_t : public universal_notifier_t { #endif }; -#define NAMED_PIPE_FLASH_DURATION_USEC (1000000 / 10) -#define SUSTAINED_READABILITY_CLEANUP_DURATION_USEC (1000000 * 5) +#if !defined(__APPLE__) && !defined(__CYGWIN__) +#define NAMED_PIPE_FLASH_DURATION_USEC (1e5) +#define SUSTAINED_READABILITY_CLEANUP_DURATION_USEC (5 * 1e6) +#endif // Named-pipe based notifier. All clients open the same named pipe for reading and writing. The // pipe's readability status is a trigger to enter polling mode. @@ -1347,7 +1348,7 @@ class universal_notifier_named_pipe_t : public universal_notifier_t { #else // this class isn't valid on this system public: universal_notifier_named_pipe_t(const wchar_t *test_path) { - auto x = test_path; // silence "unused parameter" warning + static_cast(test_path); DIE("universal_notifier_named_pipe_t cannot be used on this system"); } #endif diff --git a/src/exec.cpp b/src/exec.cpp index 0e26cfb14..26f5d9165 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -1131,16 +1131,12 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, const int prev_status = proc_get_last_status(); bool split_output = false; - // fprintf(stderr, "subcmd %ls\n", cmd.c_str()); - const env_var_t ifs = env_get_string(L"IFS"); - if (!ifs.missing_or_empty()) { split_output = true; } is_subshell = 1; - int subcommand_status = -1; // assume the worst // IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index 8605e4ead..80235a2df 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -491,7 +491,7 @@ int main(int argc, char *argv[]) { case output_type_file: { FILE *fh = fopen(output_location, "w"); if (fh) { - fputs(wcs2str(output_wtext), fh); + fputws(output_wtext.c_str(), fh); fclose(fh); exit(0); } else { @@ -511,6 +511,6 @@ int main(int argc, char *argv[]) { } } - fputs(colored_output.c_str(), stdout); + fputws(str2wcstring(colored_output).c_str(), stdout); return 0; } diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index 04375c00a..b767bfa18 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -34,10 +34,10 @@ struct config_paths_t determine_config_directory_paths(const char *argv0); -static const char *ctrl_symbolic_names[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\a", - "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "\\e", NULL, NULL, NULL, NULL}; +static const wchar_t *ctrl_symbolic_names[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, L"\\a", L"\\b", L"\\t", L"\\n", + L"\\v", L"\\f", L"\\r", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, L"\\e", NULL, NULL, NULL, NULL}; static bool keep_running = true; /// Return true if the recent sequence of characters indicates the user wants to exit the program. @@ -51,12 +51,12 @@ static bool should_exit(wchar_t wc) { recent_chars[3] = c; if (c == shell_modes.c_cc[VINTR]) { if (recent_chars[2] == shell_modes.c_cc[VINTR]) return true; - fprintf(stderr, "Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VINTR] + 0x40); + fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VINTR] + 0x40); return false; } if (c == shell_modes.c_cc[VEOF]) { if (recent_chars[2] == shell_modes.c_cc[VEOF]) return true; - fprintf(stderr, "Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VEOF] + 0x40); + fwprintf(stderr, L"Press [ctrl-%c] again to exit\n", shell_modes.c_cc[VEOF] + 0x40); return false; } return memcmp(recent_chars, "exit", 4) == 0 || memcmp(recent_chars, "quit", 4) == 0; @@ -116,46 +116,48 @@ static bool must_escape(wchar_t wc) { } } -static char *char_to_symbol(wchar_t wc, bool bind_friendly) { - static char buf[128]; +static wchar_t *char_to_symbol(wchar_t wc, bool bind_friendly) { +#define BUF_LEN 64 + static wchar_t buf[BUF_LEN]; - if (wc < ' ') { + if (wc < L' ') { // ASCII control character. if (ctrl_symbolic_names[wc]) { if (bind_friendly) { - snprintf(buf, sizeof(buf), "%s", ctrl_symbolic_names[wc]); + swprintf(buf, BUF_LEN, L"%ls", ctrl_symbolic_names[wc]); } else { - snprintf(buf, sizeof(buf), "\\c%c (or %s)", wc + 64, ctrl_symbolic_names[wc]); + swprintf(buf, BUF_LEN, L"\\c%c (or %ls)", wc + 0x40, ctrl_symbolic_names[wc]); } } else { - snprintf(buf, sizeof(buf), "\\c%c", wc + 64); + swprintf(buf, BUF_LEN, L"\\c%c", wc + 0x40); } - } else if (wc == ' ') { + } else if (wc == L' ') { // The "space" character. if (bind_friendly) { - snprintf(buf, sizeof(buf), "\\x%X", wc); + swprintf(buf, BUF_LEN, L"\\x%X", ' '); } else { - snprintf(buf, sizeof(buf), "\\x%X (aka \"space\")", wc); + swprintf(buf, BUF_LEN, L"\\x%X (aka \"space\")", ' '); } } else if (wc == 0x7F) { // The "del" character. if (bind_friendly) { - snprintf(buf, sizeof(buf), "\\x%X", wc); + swprintf(buf, BUF_LEN, L"\\x%X", 0x7F); } else { - snprintf(buf, sizeof(buf), "\\x%X (aka \"del\")", wc); + swprintf(buf, BUF_LEN, L"\\x%X (aka \"del\")", 0x7F); } } else if (wc < 0x80) { // ASCII characters that are not control characters. if (bind_friendly && must_escape(wc)) { - snprintf(buf, sizeof(buf), "\\%c", wc); + swprintf(buf, BUF_LEN, L"\\%c", wc); } else { - snprintf(buf, sizeof(buf), "%c", wc); + swprintf(buf, BUF_LEN, L"%c", wc); } } else if (wc <= 0xFFFF) { - snprintf(buf, sizeof(buf), "\\u%04X", wc); + swprintf(buf, BUF_LEN, L"\\u%04X", (int)wc); } else { - snprintf(buf, sizeof(buf), "\\U%06X", wc); + swprintf(buf, BUF_LEN, L"\\U%06X", (int)wc); } + return buf; } @@ -165,17 +167,17 @@ static void add_char_to_bind_command(wchar_t wc, std::vector &bind_char static void output_bind_command(std::vector &bind_chars) { if (bind_chars.size()) { - fputs("bind ", stdout); + fputws(L"bind ", stdout); for (size_t i = 0; i < bind_chars.size(); i++) { - fputs(char_to_symbol(bind_chars[i], true), stdout); + fputws(char_to_symbol(bind_chars[i], true), stdout); } - fputs(" 'do something'\n", stdout); + fputws(L" 'do something'\n", stdout); bind_chars.clear(); } } static void output_info_about_char(wchar_t wc) { - fprintf(stderr, "hex: %4X char: %s\n", wc, char_to_symbol(wc, false)); + fwprintf(stderr, L"hex: %4X char: %ls\n", wc, char_to_symbol(wc, false)); } static bool output_matching_key_name(wchar_t wc) { @@ -193,11 +195,11 @@ static double output_elapsed_time(double prev_tstamp, bool first_char_seen) { double now = timef(); long long int delta_tstamp_us = 1000000 * (now - prev_tstamp); - if (delta_tstamp_us >= 200000 && first_char_seen) putc('\n', stderr); + if (delta_tstamp_us >= 200000 && first_char_seen) fputwc(L'\n', stderr); if (delta_tstamp_us >= 1000000) { - fprintf(stderr, " "); + fwprintf(stderr, L" "); } else { - fprintf(stderr, "(%3lld.%03lld ms) ", delta_tstamp_us / 1000, delta_tstamp_us % 1000); + fwprintf(stderr, L"(%3lld.%03lld ms) ", delta_tstamp_us / 1000, delta_tstamp_us % 1000); } return now; } @@ -208,7 +210,7 @@ static void process_input(bool continuous_mode) { double prev_tstamp = 0.0; std::vector bind_chars; - fprintf(stderr, "Press a key\n\n"); + fwprintf(stderr, L"Press a key\n\n"); while (keep_running) { wchar_t wc; if (reader_interrupted()) { @@ -232,7 +234,7 @@ static void process_input(bool continuous_mode) { } if (should_exit(wc)) { - fprintf(stderr, "\nExiting at your request.\n"); + fwprintf(stderr, L"\nExiting at your request.\n"); break; } @@ -295,11 +297,11 @@ static void setup_and_process_keys(bool continuous_mode) { install_our_signal_handlers(); if (continuous_mode) { - fprintf(stderr, "\n"); - fprintf(stderr, "To terminate this program type \"exit\" or \"quit\" in this window,\n"); - fprintf(stderr, "or press [ctrl-%c] or [ctrl-%c] twice in a row.\n", - shell_modes.c_cc[VINTR] + 0x40, shell_modes.c_cc[VEOF] + 0x40); - fprintf(stderr, "\n"); + fwprintf(stderr, L"\n"); + fwprintf(stderr, L"To terminate this program type \"exit\" or \"quit\" in this window,\n"); + fwprintf(stderr, L"or press [ctrl-%c] or [ctrl-%c] twice in a row.\n", + shell_modes.c_cc[VINTR] + 0x40, shell_modes.c_cc[VEOF] + 0x40); + fwprintf(stderr, L"\n"); } process_input(continuous_mode); @@ -323,7 +325,7 @@ int main(int argc, char **argv) { while (!error && (opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (opt) { case 0: { - fprintf(stderr, "getopt_long() unexpectedly returned zero\n"); + fwprintf(stderr, L"getopt_long() unexpectedly returned zero\n"); error = true; break; } @@ -378,12 +380,12 @@ int main(int argc, char **argv) { argc -= optind; if (argc != 0) { - fprintf(stderr, "Expected no arguments, got %d\n", argc); + fwprintf(stderr, L"Expected no arguments, got %d\n", argc); return 1; } if (!isatty(STDIN_FILENO)) { - fprintf(stderr, "Stdin must be attached to a tty.\n"); + fwprintf(stderr, L"Stdin must be attached to a tty.\n"); return 1; } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 387cd73e3..714de42c1 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -766,19 +766,10 @@ static void test_cancellation() { // we cancel we expect no output. test_1_cancellation(L"echo (while true ; echo blah ; end)"); - fprintf(stderr, "."); - // Nasty infinite loop that doesn't actually execute anything. test_1_cancellation(L"echo (while true ; end) (while true ; end) (while true ; end)"); - fprintf(stderr, "."); - test_1_cancellation(L"while true ; end"); - fprintf(stderr, "."); - test_1_cancellation(L"for i in (while true ; end) ; end"); - fprintf(stderr, "."); - - fprintf(stderr, "\n"); // Restore signal handling. proc_pop_interactive(); @@ -1645,8 +1636,8 @@ struct pager_layout_testcase_t { wcstring text = sd.line(0).to_string(); if (text != expected) { - fprintf(stderr, "width %zu got <%ls>, expected <%ls>\n", this->width, text.c_str(), - expected.c_str()); + fwprintf(stderr, L"width %zu got <%ls>, expected <%ls>\n", this->width, + text.c_str(), expected.c_str()); } do_test(text == expected); } @@ -2175,8 +2166,8 @@ static void test_1_completion(wcstring line, const wcstring &completion, complet wcstring result = completion_apply_to_command_line(completion, flags, line, &cursor_pos, append_only); if (result != expected) { - fprintf(stderr, "line %ld: %ls + %ls -> [%ls], expected [%ls]\n", source_line, line.c_str(), - completion.c_str(), result.c_str(), expected.c_str()); + fwprintf(stderr, L"line %ld: %ls + %ls -> [%ls], expected [%ls]\n", source_line, + line.c_str(), completion.c_str(), result.c_str(), expected.c_str()); } do_test(result == expected); do_test(cursor_pos == out_cursor_pos); @@ -2501,7 +2492,7 @@ static void test_universal() { } if (system("rm -Rf /tmp/fish_uvars_test")) err(L"rm failed"); - putc('\n', stderr); + fputwc(L'\n', stderr); } static bool callback_data_less_than(const callback_data_t &a, const callback_data_t &b) { @@ -3225,7 +3216,7 @@ static void test_new_parser_fuzzing(void) { bool log_it = true; unsigned long max_len = 5; for (unsigned long len = 0; len < max_len; len++) { - if (log_it) fprintf(stderr, "%lu / %lu...", len, max_len); + if (log_it) fwprintf(stderr, L"%lu / %lu...", len, max_len); // We wish to look at all permutations of 4 elements of 'fuzzes' (with replacement). // Construct an int and keep incrementing it. @@ -3234,7 +3225,7 @@ static void test_new_parser_fuzzing(void) { &src)) { parse_tree_from_string(src, parse_flag_continue_after_error, &node_tree, &errors); } - if (log_it) fprintf(stderr, "done (%lu)\n", permutation); + if (log_it) fwprintf(stderr, L"done (%lu)\n", permutation); } double end = timef(); if (log_it) say(L"All fuzzed in %f seconds!", end - start); @@ -4121,8 +4112,8 @@ int main(int argc, char **argv) { exit(-1); } if (!strcmp(wd, "/")) { - fprintf(stderr, - "Unable to find 'tests' directory, which should contain file test.fish\n"); + fwprintf(stderr, + L"Unable to find 'tests' directory, which should contain file test.fish\n"); exit(EXIT_FAILURE); } if (chdir(dirname(wd)) < 0) { diff --git a/src/highlight.cpp b/src/highlight.cpp index a1cd1a646..3019db942 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -1031,7 +1031,7 @@ const highlighter_t::color_array_t &highlighter_t::highlight() { #if 0 // Disabled for the 2.2.0 release: https://github.com/fish-shell/fish-shell/issues/1809. const wcstring dump = parse_dump_tree(parse_tree, buff); - fprintf(stderr, "%ls\n", dump.c_str()); + fwprintf(stderr, L"%ls\n", dump.c_str()); #endif // Walk the node tree. diff --git a/src/input.cpp b/src/input.cpp index 537889214..cfd409cdc 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -374,7 +374,7 @@ int input_init() { } else { debug(0, _(L"Using fallback terminal type '%ls'"), DEFAULT_TERM); } - putc('\n', stderr); + fputwc(L'\n', stderr); } input_terminfo_init(); diff --git a/src/io.cpp b/src/io.cpp index be33bcb12..5cdc5c336 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common.h" #include "exec.h" @@ -15,19 +16,20 @@ io_data_t::~io_data_t() {} -void io_close_t::print() const { fprintf(stderr, "close %d\n", fd); } +void io_close_t::print() const { fwprintf(stderr, L"close %d\n", fd); } -void io_fd_t::print() const { fprintf(stderr, "FD map %d -> %d\n", old_fd, fd); } +void io_fd_t::print() const { fwprintf(stderr, L"FD map %d -> %d\n", old_fd, fd); } -void io_file_t::print() const { fprintf(stderr, "file (%s)\n", filename_cstr); } +void io_file_t::print() const { fwprintf(stderr, L"file (%s)\n", filename_cstr); } void io_pipe_t::print() const { - fprintf(stderr, "pipe {%d, %d} (input: %s)\n", pipe_fd[0], pipe_fd[1], is_input ? "yes" : "no"); + fwprintf(stderr, L"pipe {%d, %d} (input: %s)\n", pipe_fd[0], pipe_fd[1], + is_input ? "yes" : "no"); } void io_buffer_t::print() const { - fprintf(stderr, "buffer %p (input: %s, size %lu)\n", out_buffer_ptr(), is_input ? "yes" : "no", - (unsigned long)out_buffer_size()); + fwprintf(stderr, L"buffer %p (input: %s, size %lu)\n", out_buffer_ptr(), + is_input ? "yes" : "no", (unsigned long)out_buffer_size()); } void io_buffer_t::read() { @@ -139,21 +141,21 @@ void io_print(const io_chain_t &chain) { if (chain.empty()) { - fprintf(stderr, "Empty chain %p\n", &chain); + fwprintf(stderr, L"Empty chain %p\n", &chain); return; } - fprintf(stderr, "Chain %p (%ld items):\n", &chain, (long)chain.size()); + fwprintf(stderr, L"Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { const shared_ptr &io = chain.at(i); if (io.get() == NULL) { - fprintf(stderr, "\t(null)\n"); + fwprintf(stderr, L"\t(null)\n"); } else { - fprintf(stderr, "\t%lu: fd:%d, ", (unsigned long)i, io->fd); + fwprintf(stderr, L"\t%lu: fd:%d, ", (unsigned long)i, io->fd); io->print(); } } diff --git a/src/iothread.cpp b/src/iothread.cpp index e9279dae9..d80496bfc 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -228,7 +227,7 @@ void iothread_service_completion(void) { } else if (wakeup_byte == IO_SERVICE_RESULT_QUEUE) { iothread_service_result_queue(); } else { - fprintf(stderr, "Unknown wakeup byte %02x in %s\n", wakeup_byte, __FUNCTION__); + debug(0, "Unknown wakeup byte %02x in %s", wakeup_byte, __FUNCTION__); } } diff --git a/src/parse_constants.h b/src/parse_constants.h index 642a569ee..72b1a0089 100644 --- a/src/parse_constants.h +++ b/src/parse_constants.h @@ -6,10 +6,10 @@ #include "config.h" #define PARSE_ASSERT(a) assert(a) -#define PARSER_DIE() \ - do { \ - fprintf(stderr, "Parser dying!\n"); \ - exit_without_destructors(-1); \ +#define PARSER_DIE() \ + do { \ + debug(0, "Parser dying!"); \ + exit_without_destructors(-1); \ } while (0) // IMPORTANT: If the following enum table is modified you must also update token_enum_map below. diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 712626fab..3b10d2e08 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -441,7 +441,7 @@ parse_execution_result_t parse_execution_context_t::run_block_statement( break; } default: { - fprintf(stderr, "Unexpected block header: %ls\n", header.describe().c_str()); + debug(0, L"Unexpected block header: %ls\n", header.describe().c_str()); PARSER_DIE(); break; } @@ -700,7 +700,7 @@ parse_execution_result_t parse_execution_context_t::report_errors( const parse_error_list_t &error_list) const { if (!parser->cancellation_requested) { if (error_list.empty()) { - fprintf(stderr, "Bug: Error reported but no error text found."); + debug(0, "Error reported but no error text found."); } // Get a backtrace. @@ -708,7 +708,9 @@ parse_execution_result_t parse_execution_context_t::report_errors( parser->get_backtrace(src, error_list, &backtrace_and_desc); // Print it. - if (!should_suppress_stderr_for_tests()) fprintf(stderr, "%ls", backtrace_and_desc.c_str()); + if (!should_suppress_stderr_for_tests()) { + fwprintf(stderr, L"%ls", backtrace_and_desc.c_str()); + } } return parse_execution_errored; } @@ -1034,8 +1036,7 @@ bool parse_execution_context_t::determine_io_chain(const parse_node_t &statement } default: { // Should be unreachable. - fprintf(stderr, "Unexpected redirection type %ld. aborting.\n", - (long)redirect_type); + debug(0, "Unexpected redirection type %ld.", (long)redirect_type); PARSER_DIE(); break; } @@ -1133,8 +1134,8 @@ parse_execution_result_t parse_execution_context_t::populate_job_process( break; } default: { - fprintf(stderr, "'%ls' not handled by new parser yet\n", - specific_statement.describe().c_str()); + debug(0, L"'%ls' not handled by new parser yet.", + specific_statement.describe().c_str()); PARSER_DIE(); break; } @@ -1426,8 +1427,7 @@ parse_execution_result_t parse_execution_context_t::eval_node_at_offset( default: { // In principle, we could support other node types. However we never expect to be passed // them - see above. - fprintf(stderr, "Unexpected node %ls found in %s\n", node.describe().c_str(), - __FUNCTION__); + debug(0, "Unexpected node %ls found in %s", node.describe().c_str(), __FUNCTION__); PARSER_DIE(); break; } diff --git a/src/parse_productions.cpp b/src/parse_productions.cpp index dbbd84610..ffd998e11 100644 --- a/src/parse_productions.cpp +++ b/src/parse_productions.cpp @@ -481,21 +481,21 @@ const production_element_t *parse_productions::production_for_token(parse_token_ case parse_token_type_background: case parse_token_type_end: case parse_token_type_terminate: { - fprintf(stderr, "Terminal token type %ls passed to %s\n", - token_type_description(node_type), __FUNCTION__); + debug(0, "Terminal token type %ls passed to %s", token_type_description(node_type), + __FUNCTION__); PARSER_DIE(); break; } case parse_special_type_parse_error: case parse_special_type_tokenizer_error: case parse_special_type_comment: { - fprintf(stderr, "Special type %ls passed to %s\n", token_type_description(node_type), - __FUNCTION__); + debug(0, "Special type %ls passed to %s\n", token_type_description(node_type), + __FUNCTION__); PARSER_DIE(); break; } case token_type_invalid: { - fprintf(stderr, "token_type_invalid passed to %s\n", __FUNCTION__); + debug(0, "token_type_invalid passed to %s", __FUNCTION__); PARSER_DIE(); break; } diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index 7b8f065ef..f95ea1aa3 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -127,6 +127,7 @@ const wchar_t *token_type_description(parse_token_type_t type) { // This leaks memory but it should never be run unless we have a bug elsewhere in the code. const wcstring d = format_string(L"unknown_token_type_%ld", static_cast(type)); wchar_t *d2 = new wchar_t[d.size() + 1]; + // cppcheck-suppress memleak return std::wcscpy(d2, d.c_str()); } @@ -137,6 +138,7 @@ const wchar_t *keyword_description(parse_keyword_t type) { // This leaks memory but it should never be run unless we have a bug elsewhere in the code. const wcstring d = format_string(L"unknown_keyword_%ld", static_cast(type)); wchar_t *d2 = new wchar_t[d.size() + 1]; + // cppcheck-suppress memleak return std::wcscpy(d2, d.c_str()); } @@ -258,8 +260,7 @@ static inline parse_token_type_t parse_token_type_from_tokenizer_token( break; } default: { - fprintf(stderr, "Bad token type %d passed to %s\n", (int)tokenizer_token_type, - __FUNCTION__); + debug(0, "Bad token type %d passed to %s", (int)tokenizer_token_type, __FUNCTION__); DIE("bad token type"); break; } @@ -420,17 +421,17 @@ class parse_ll_t { bool logit = false; if (logit) { int count = 0; - fprintf(stderr, "Applying production:\n"); + fwprintf(stderr, L"Applying production:\n"); for (int i = 0;; i++) { production_element_t elem = production[i]; if (!production_element_is_valid(elem)) break; // all done, bail out parse_token_type_t type = production_element_type(elem); parse_keyword_t keyword = production_element_keyword(elem); - fprintf(stderr, "\t%ls <%ls>\n", token_type_description(type), - keyword_description(keyword)); + fwprintf(stderr, L"\t%ls <%ls>\n", token_type_description(type), + keyword_description(keyword)); count++; } - if (!count) fprintf(stderr, "\t\n"); + if (!count) fwprintf(stderr, L"\t\n"); } // Get the parent index. But we can't get the parent parse node yet, since it may be made @@ -537,9 +538,9 @@ void parse_ll_t::dump_stack(void) const { } } - fprintf(stderr, "Stack dump (%zu elements):\n", symbol_stack.size()); + fwprintf(stderr, L"Stack dump (%zu elements):\n", symbol_stack.size()); for (size_t idx = 0; idx < stack_lines.size(); idx++) { - fprintf(stderr, " %ls\n", stack_lines.at(idx).c_str()); + fwprintf(stderr, L" %ls\n", stack_lines.at(idx).c_str()); } } #endif @@ -927,7 +928,7 @@ bool parse_ll_t::top_node_handle_terminal_types(parse_token_t token) { void parse_ll_t::accept_tokens(parse_token_t token1, parse_token_t token2) { bool logit = false; if (logit) { - fprintf(stderr, "Accept token %ls\n", token1.describe().c_str()); + fwprintf(stderr, L"Accept token %ls\n", token1.describe().c_str()); } PARSE_ASSERT(token1.type >= FIRST_PARSE_TOKEN_TYPE); @@ -964,7 +965,7 @@ void parse_ll_t::accept_tokens(parse_token_t token1, parse_token_t token2) { if (top_node_handle_terminal_types(token1)) { if (logit) { - fprintf(stderr, "Consumed token %ls\n", token1.describe().c_str()); + fwprintf(stderr, L"Consumed token %ls\n", token1.describe().c_str()); } // consumed = true; break; @@ -1184,8 +1185,8 @@ bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t parse_flags, #if 0 //wcstring result = dump_tree(this->parser->nodes, str); - //fprintf(stderr, "Tree (%ld nodes):\n%ls", this->parser->nodes.size(), result.c_str()); - fprintf(stderr, "%lu nodes, node size %lu, %lu bytes\n", output->size(), sizeof(parse_node_t), + //fwprintf(stderr, L"Tree (%ld nodes):\n%ls", this->parser->nodes.size(), result.c_str()); + fwprintf(stderr, L"%lu nodes, node size %lu, %lu bytes\n", output->size(), sizeof(parse_node_t), output->size() * sizeof(parse_node_t)); #endif diff --git a/src/parser.cpp b/src/parser.cpp index 7ec47285c..21bd8777e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -615,8 +615,7 @@ int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t this->get_backtrace(cmd, error_list, &backtrace_and_desc); // Print it. - fprintf(stderr, "%ls", backtrace_and_desc.c_str()); - + fwprintf(stderr, L"%ls\n", backtrace_and_desc.c_str()); return 1; } return this->eval_acquiring_tree(cmd, io, block_type, moved_ref(tree)); diff --git a/src/path.cpp b/src/path.cpp index 1cfda620a..6465822ed 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -242,7 +242,7 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring & debug(0, _(L"The error was '%s'."), strerror(saved_errno)); debug(0, _(L"Please set $%ls to a directory where you have write access."), env_var); } - putc('\n', stderr); + fputwc(L'\n', stderr); } static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir, diff --git a/src/postfork.cpp b/src/postfork.cpp index 366c5ced8..41fe0e30b 100644 --- a/src/postfork.cpp +++ b/src/postfork.cpp @@ -11,6 +11,7 @@ #if FISH_USE_POSIX_SPAWN #include #endif +#include #include "common.h" #include "exec.h" @@ -141,7 +142,7 @@ static int handle_child_io(const io_chain_t &io_chain) { switch (io->io_mode) { case IO_CLOSE: { - if (log_redirections) fprintf(stderr, "%d: close %d\n", getpid(), io->fd); + if (log_redirections) fwprintf(stderr, L"%d: close %d\n", getpid(), io->fd); if (close(io->fd)) { debug_safe_int(0, "Failed to close file descriptor %s", io->fd); safe_perror("close"); @@ -180,7 +181,7 @@ static int handle_child_io(const io_chain_t &io_chain) { case IO_FD: { int old_fd = static_cast(io)->old_fd; if (log_redirections) - fprintf(stderr, "%d: fd dup %d to %d\n", getpid(), old_fd, io->fd); + fwprintf(stderr, L"%d: fd dup %d to %d\n", getpid(), old_fd, io->fd); // This call will sometimes fail, but that is ok, this is just a precausion. close(io->fd); @@ -200,14 +201,14 @@ static int handle_child_io(const io_chain_t &io_chain) { // fd). If it's 1, we're connecting to the write end (second pipe fd). unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1); #if 0 - debug( 0, L"%ls %ls on fd %d (%d %d)", write_pipe?L"write":L"read", - (io->io_mode == IO_BUFFER)?L"buffer":L"pipe", io->fd, io->pipe_fd[0], - io->pipe_fd[1]); + debug(0, L"%ls %ls on fd %d (%d %d)", write_pipe?L"write":L"read", + (io->io_mode == IO_BUFFER)?L"buffer":L"pipe", io->fd, io->pipe_fd[0], + io->pipe_fd[1]); #endif if (log_redirections) - fprintf(stderr, "%d: %s dup %d to %d\n", getpid(), - io->io_mode == IO_BUFFER ? "buffer" : "pipe", - io_pipe->pipe_fd[write_pipe_idx], io->fd); + fwprintf(stderr, L"%d: %s dup %d to %d\n", getpid(), + io->io_mode == IO_BUFFER ? "buffer" : "pipe", + io_pipe->pipe_fd[write_pipe_idx], io->fd); if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd) { debug_safe(1, LOCAL_PIPE_ERROR); safe_perror("dup2"); diff --git a/src/proc.cpp b/src/proc.cpp index 815a53084..3a392d56c 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -280,7 +280,7 @@ static void mark_process_status(process_t *p, int status) { } else { // This should never be reached. p->completed = 1; - fprintf(stderr, "Process %ld exited abnormally\n", (long)p->pid); + debug(1, "Process %ld exited abnormally", (long)p->pid); } } diff --git a/src/reader.cpp b/src/reader.cpp index 5121f7544..3e3c96aaf 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2424,7 +2424,7 @@ const wchar_t *reader_readline(int nchars) { is_interactive_read = 1; c = input_readch(); is_interactive_read = was_interactive_read; - // fprintf(stderr, "C: %lx\n", (long)c); + // fwprintf(stderr, L"C: %lx\n", (long)c); if (((!fish_reserved_codepoint(c))) && (c > 31) && (c != 127) && can_read(0)) { wchar_t arr[READAHEAD_MAX + 1]; @@ -2486,7 +2486,7 @@ const wchar_t *reader_readline(int nchars) { if (command_ends_paging(c, focused_on_search_field)) { clear_pager(); } - // fprintf(stderr, "\n\nchar: %ls\n\n", describe_char(c).c_str()); + // fwprintf(stderr, L"\n\nchar: %ls\n\n", describe_char(c).c_str()); switch (c) { // Go to beginning of line. @@ -2607,7 +2607,7 @@ const wchar_t *reader_readline(int nchars) { // up to the end of the token we're completing. const wcstring buffcpy = wcstring(cmdsub_begin, token_end); - // fprintf(stderr, "Complete (%ls)\n", buffcpy.c_str()); + // fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH; diff --git a/src/screen.cpp b/src/screen.cpp index 4336de082..ebbb74739 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -416,7 +416,7 @@ static void s_desired_append_char(screen_t *s, wchar_t b, int c, int indent, siz if ((s->desired.cursor.x + cw) > screen_width) { // Current line is soft wrapped (assuming we support it). s->desired.line(s->desired.cursor.y).is_soft_wrapped = true; - // fprintf(stderr, "\n\n1 Soft wrapping %d\n\n", s->desired.cursor.y); + // fwprintf(stderr, L"\n\n1 Soft wrapping %d\n\n", s->desired.cursor.y); line_no = (int)s->desired.line_count(); s->desired.add_line();