mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-11 20:48:49 +00:00
lint: "collapsible if statements" warnings
This commit is contained in:
parent
a8c9019a39
commit
42458ff7ab
22 changed files with 349 additions and 446 deletions
|
@ -3284,11 +3284,10 @@ int builtin_run(parser_t &parser, const wchar_t *const *argv, io_streams_t &stre
|
||||||
cmd = (int (*)(parser_t & parser, io_streams_t & streams, const wchar_t *const *))(
|
cmd = (int (*)(parser_t & parser, io_streams_t & streams, const wchar_t *const *))(
|
||||||
data ? data->func : NULL);
|
data ? data->func : NULL);
|
||||||
|
|
||||||
if (argv[1] != NULL && !builtin_handles_help(argv[0])) {
|
if (argv[1] != NULL && !builtin_handles_help(argv[0]) && argv[2] == NULL &&
|
||||||
if (argv[2] == NULL && (parse_util_argument_is_help(argv[1], 0))) {
|
parse_util_argument_is_help(argv[1], 0)) {
|
||||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
builtin_print_help(parser, streams, argv[0], streams.out);
|
||||||
return STATUS_BUILTIN_OK;
|
return STATUS_BUILTIN_OK;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
|
|
|
@ -286,39 +286,35 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res && condition && wcslen(condition)) {
|
||||||
if (condition && wcslen(condition)) {
|
const wcstring condition_string = condition;
|
||||||
const wcstring condition_string = condition;
|
parse_error_list_t errors;
|
||||||
parse_error_list_t errors;
|
if (parse_util_detect_errors(condition_string, &errors,
|
||||||
if (parse_util_detect_errors(condition_string, &errors,
|
false /* do not accept incomplete */)) {
|
||||||
false /* do not accept incomplete */)) {
|
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", argv[0],
|
||||||
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", argv[0],
|
condition);
|
||||||
condition);
|
for (size_t i = 0; i < errors.size(); i++) {
|
||||||
for (size_t i = 0; i < errors.size(); i++) {
|
streams.err.append_format(L"\n%s: ", argv[0]);
|
||||||
streams.err.append_format(L"\n%s: ", argv[0]);
|
streams.err.append(errors.at(i).describe(condition_string));
|
||||||
streams.err.append(errors.at(i).describe(condition_string));
|
|
||||||
}
|
|
||||||
res = true;
|
|
||||||
}
|
}
|
||||||
|
res = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res && comp && wcslen(comp)) {
|
||||||
if (comp && wcslen(comp)) {
|
wcstring prefix;
|
||||||
wcstring prefix;
|
if (argv[0]) {
|
||||||
if (argv[0]) {
|
prefix.append(argv[0]);
|
||||||
prefix.append(argv[0]);
|
prefix.append(L": ");
|
||||||
prefix.append(L": ");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wcstring err_text;
|
wcstring err_text;
|
||||||
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
|
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
|
||||||
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n",
|
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n", argv[0],
|
||||||
argv[0], comp);
|
comp);
|
||||||
streams.err.append(err_text);
|
streams.err.append(err_text);
|
||||||
streams.err.push_back(L'\n');
|
streams.err.push_back(L'\n');
|
||||||
res = true;
|
res = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,19 +159,17 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
builtin_set_color_output.clear();
|
builtin_set_color_output.clear();
|
||||||
output_set_writer(set_color_builtin_outputter);
|
output_set_writer(set_color_builtin_outputter);
|
||||||
|
|
||||||
if (bold) {
|
if (bold && enter_bold_mode) {
|
||||||
if (enter_bold_mode) writembs(tparm(enter_bold_mode));
|
writembs(tparm(enter_bold_mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (underline) {
|
if (underline && enter_underline_mode) {
|
||||||
if (enter_underline_mode) writembs(enter_underline_mode);
|
writembs(enter_underline_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bgcolor != NULL) {
|
if (bgcolor != NULL && bg.is_normal()) {
|
||||||
if (bg.is_normal()) {
|
write_color(rgb_color_t::black(), false /* not is_fg */);
|
||||||
write_color(rgb_color_t::black(), false /* not is_fg */);
|
writembs(tparm(exit_attribute_mode));
|
||||||
writembs(tparm(exit_attribute_mode));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fg.is_none()) {
|
if (!fg.is_none()) {
|
||||||
|
@ -188,10 +186,8 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bgcolor != NULL) {
|
if (bgcolor != NULL && !bg.is_normal() && !bg.is_reset()) {
|
||||||
if (!bg.is_normal() && !bg.is_reset()) {
|
write_color(bg, false /* not is_fg */);
|
||||||
write_color(bg, false /* not is_fg */);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore saved writer function.
|
// Restore saved writer function.
|
||||||
|
|
|
@ -1505,7 +1505,7 @@ bool list_contains_string(const wcstring_list_t &list, const wcstring &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_directory(const wcstring &d) {
|
int create_directory(const wcstring &d) {
|
||||||
int ok = 0;
|
bool ok = false;
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
int stat_res = 0;
|
int stat_res = 0;
|
||||||
|
|
||||||
|
@ -1514,18 +1514,10 @@ int create_directory(const wcstring &d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat_res == 0) {
|
if (stat_res == 0) {
|
||||||
if (S_ISDIR(buf.st_mode)) {
|
if (S_ISDIR(buf.st_mode)) ok = true;
|
||||||
ok = 1;
|
} else if (errno == ENOENT) {
|
||||||
}
|
wcstring dir = wdirname(d);
|
||||||
} else {
|
if (!create_directory(dir) && !wmkdir(d, 0700)) ok = true;
|
||||||
if (errno == ENOENT) {
|
|
||||||
wcstring dir = wdirname(d);
|
|
||||||
if (!create_directory(dir)) {
|
|
||||||
if (!wmkdir(d, 0700)) {
|
|
||||||
ok = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok ? 0 : -1;
|
return ok ? 0 : -1;
|
||||||
|
|
|
@ -670,22 +670,22 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
|
||||||
std::vector<completion_t> possible_comp;
|
std::vector<completion_t> possible_comp;
|
||||||
|
|
||||||
if (use_command) {
|
if (use_command) {
|
||||||
if (expand_string(str_cmd, &this->completions,
|
expand_error_t result = expand_string(str_cmd, &this->completions,
|
||||||
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS | EXECUTABLES_ONLY |
|
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS |
|
||||||
this->expand_flags(),
|
EXECUTABLES_ONLY | this->expand_flags(),
|
||||||
NULL) != EXPAND_ERROR) {
|
NULL);
|
||||||
if (this->wants_descriptions()) {
|
if (result != EXPAND_ERROR && this->wants_descriptions()) {
|
||||||
this->complete_cmd_desc(str_cmd);
|
this->complete_cmd_desc(str_cmd);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (use_implicit_cd) {
|
|
||||||
if (!expand_string(str_cmd, &this->completions,
|
// WTF? This seems to be a noop.
|
||||||
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(),
|
if (use_implicit_cd &&
|
||||||
NULL)) {
|
!expand_string(str_cmd, &this->completions,
|
||||||
// Not valid as implicit cd.
|
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(), NULL)) {
|
||||||
}
|
// Not valid as implicit cd.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_cmd.find(L'/') == wcstring::npos && str_cmd.at(0) != L'~') {
|
if (str_cmd.find(L'/') == wcstring::npos && str_cmd.at(0) != L'~') {
|
||||||
if (use_function) {
|
if (use_function) {
|
||||||
wcstring_list_t names = function_get_names(str_cmd.at(0) == L'_');
|
wcstring_list_t names = function_get_names(str_cmd.at(0) == L'_');
|
||||||
|
@ -877,11 +877,10 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
||||||
if (this->type() == COMPLETE_DEFAULT) {
|
if (this->type() == COMPLETE_DEFAULT) {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
complete_load(cmd, true);
|
complete_load(cmd, true);
|
||||||
} else if (this->type() == COMPLETE_AUTOSUGGEST) {
|
} else if (this->type() == COMPLETE_AUTOSUGGEST &&
|
||||||
// Maybe load this command (on the main thread).
|
!completion_autoloader.has_tried_loading(cmd)) {
|
||||||
if (!completion_autoloader.has_tried_loading(cmd)) {
|
// Load this command (on the main thread).
|
||||||
iothread_perform_on_main(complete_load_no_reload, &cmd);
|
iothread_perform_on_main(complete_load_no_reload, &cmd);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a list of lists of all options that we care about.
|
// Make a list of lists of all options that we care about.
|
||||||
|
@ -927,13 +926,12 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
|
||||||
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
|
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
|
||||||
++oiter) {
|
++oiter) {
|
||||||
const complete_entry_opt_t *o = &*oiter;
|
const complete_entry_opt_t *o = &*oiter;
|
||||||
if (o->type == option_type_single_long) {
|
if (o->type == option_type_single_long && param_match(o, popt) &&
|
||||||
if (param_match(o, popt) && this->condition_test(o->condition)) {
|
this->condition_test(o->condition)) {
|
||||||
old_style_match = true;
|
old_style_match = true;
|
||||||
if (o->result_mode & NO_COMMON) use_common = false;
|
if (o->result_mode & NO_COMMON) use_common = false;
|
||||||
if (o->result_mode & NO_FILES) use_files = false;
|
if (o->result_mode & NO_FILES) use_files = false;
|
||||||
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -865,9 +865,7 @@ void env_push(bool new_scope) {
|
||||||
node->next = top;
|
node->next = top;
|
||||||
node->new_scope = new_scope;
|
node->new_scope = new_scope;
|
||||||
|
|
||||||
if (new_scope) {
|
if (new_scope && local_scope_exports(top)) mark_changed_exported();
|
||||||
if (local_scope_exports(top)) mark_changed_exported();
|
|
||||||
}
|
|
||||||
top = node;
|
top = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,7 +883,7 @@ void env_pop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (killme->new_scope) {
|
if (killme->new_scope) { //!OCLINT(collapsible if statements)
|
||||||
if (killme->exportv || local_scope_exports(killme->next)) mark_changed_exported();
|
if (killme->exportv || local_scope_exports(killme->next)) mark_changed_exported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -932,17 +932,16 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN],
|
||||||
|
|
||||||
if (getifaddrs(&ifap) == 0) {
|
if (getifaddrs(&ifap) == 0) {
|
||||||
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
|
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
|
||||||
if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK) {
|
bool is_af_link = p->ifa_addr && p->ifa_addr->sa_family == AF_LINK;
|
||||||
if (p->ifa_name && p->ifa_name[0] &&
|
if (is_af_link && p->ifa_name && p->ifa_name[0] &&
|
||||||
!strcmp((const char *)p->ifa_name, interface)) {
|
!strcmp((const char *)p->ifa_name, interface)) {
|
||||||
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
|
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
|
||||||
|
|
||||||
size_t alen = sdl.sdl_alen;
|
size_t alen = sdl.sdl_alen;
|
||||||
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
|
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
|
||||||
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
|
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
|
@ -1033,12 +1032,11 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the size, if it's too small.
|
// Set the size, if it's too small.
|
||||||
if (!errored && size < (off_t)sizeof(universal_notifier_shmem_t)) {
|
bool set_size = !errored && size < (off_t)sizeof(universal_notifier_shmem_t);
|
||||||
if (ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
|
if (set_size && ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
|
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
|
||||||
errored = true;
|
errored = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory map the region.
|
// Memory map the region.
|
||||||
|
@ -1237,10 +1235,12 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||||
int fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
int fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
||||||
if (fd < 0 && errno == ENOENT) {
|
if (fd < 0 && errno == ENOENT) {
|
||||||
// File doesn't exist, try creating it.
|
// File doesn't exist, try creating it.
|
||||||
if (mkfifo(narrow_path.c_str(), 0600) >= 0) {
|
int mkfifo_status = mkfifo(narrow_path.c_str(), 0600);
|
||||||
|
if (mkfifo_status != -1) {
|
||||||
fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
// Maybe open failed, maybe mkfifo failed.
|
// Maybe open failed, maybe mkfifo failed.
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
@ -1316,11 +1316,9 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
|
||||||
// it back. Nobody is expected to read it except us.
|
// it back. Nobody is expected to read it except us.
|
||||||
int pid_nbo = htonl(getpid());
|
int pid_nbo = htonl(getpid());
|
||||||
ssize_t amt_written = write(this->pipe_fd, &pid_nbo, sizeof pid_nbo);
|
ssize_t amt_written = write(this->pipe_fd, &pid_nbo, sizeof pid_nbo);
|
||||||
if (amt_written < 0) {
|
if (amt_written < 0 && errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
// Very unsual: the pipe is full!
|
||||||
// Very unsual: the pipe is full!
|
drain_excessive_data();
|
||||||
drain_excessive_data();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now schedule a read for some time in the future.
|
// Now schedule a read for some time in the future.
|
||||||
|
|
69
src/exec.cpp
69
src/exec.cpp
|
@ -353,7 +353,7 @@ static void internal_exec_helper(parser_t &parser, const wcstring &def, node_off
|
||||||
// foreground process group, we don't use posix_spawn if we're going to foreground the process. (If
|
// foreground process group, we don't use posix_spawn if we're going to foreground the process. (If
|
||||||
// we use fork(), we can call tcsetpgrp after the fork, before the exec, and avoid the race).
|
// we use fork(), we can call tcsetpgrp after the fork, before the exec, and avoid the race).
|
||||||
static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *process) {
|
static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *process) {
|
||||||
if (job_get_flag(job, JOB_CONTROL)) {
|
if (job_get_flag(job, JOB_CONTROL)) { //!OCLINT(collapsible if statements)
|
||||||
// We are going to use job control; therefore when we launch this job it will get its own
|
// We are going to use job control; therefore when we launch this job it will get its own
|
||||||
// process group ID. But will it be foregrounded?
|
// process group ID. But will it be foregrounded?
|
||||||
if (job_get_flag(job, JOB_TERMINAL) && job_get_flag(job, JOB_FOREGROUND)) {
|
if (job_get_flag(job, JOB_TERMINAL) && job_get_flag(job, JOB_FOREGROUND)) {
|
||||||
|
@ -913,45 +913,42 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
// output, so that we can truncate the file. Does not apply to /dev/null.
|
// output, so that we can truncate the file. Does not apply to /dev/null.
|
||||||
bool must_fork = redirection_is_to_real_file(stdout_io.get()) ||
|
bool must_fork = redirection_is_to_real_file(stdout_io.get()) ||
|
||||||
redirection_is_to_real_file(stderr_io.get());
|
redirection_is_to_real_file(stderr_io.get());
|
||||||
if (!must_fork) {
|
if (!must_fork && p->next == NULL) {
|
||||||
if (p->next == NULL) {
|
const bool stdout_is_to_buffer = stdout_io && stdout_io->io_mode == IO_BUFFER;
|
||||||
const bool stdout_is_to_buffer =
|
const bool no_stdout_output = stdout_buffer.empty();
|
||||||
stdout_io && stdout_io->io_mode == IO_BUFFER;
|
const bool no_stderr_output = stderr_buffer.empty();
|
||||||
const bool no_stdout_output = stdout_buffer.empty();
|
|
||||||
const bool no_stderr_output = stderr_buffer.empty();
|
|
||||||
|
|
||||||
if (no_stdout_output && no_stderr_output) {
|
if (no_stdout_output && no_stderr_output) {
|
||||||
// The builtin produced no output and is not inside of a pipeline. No
|
// The builtin produced no output and is not inside of a pipeline. No
|
||||||
// need to fork or even output anything.
|
// need to fork or even output anything.
|
||||||
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
|
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
|
||||||
p->argv0());
|
p->argv0());
|
||||||
fork_was_skipped = true;
|
fork_was_skipped = true;
|
||||||
} else if (no_stderr_output && stdout_is_to_buffer) {
|
} else if (no_stderr_output && stdout_is_to_buffer) {
|
||||||
// The builtin produced no stderr, and its stdout is going to an
|
// The builtin produced no stderr, and its stdout is going to an
|
||||||
// internal buffer. There is no need to fork. This helps out the
|
// internal buffer. There is no need to fork. This helps out the
|
||||||
// performance quite a bit in complex completion code.
|
// performance quite a bit in complex completion code.
|
||||||
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
|
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
|
||||||
p->argv0());
|
p->argv0());
|
||||||
|
|
||||||
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
|
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
|
||||||
const std::string res = wcs2string(builtin_io_streams->out.buffer());
|
const std::string res = wcs2string(builtin_io_streams->out.buffer());
|
||||||
|
|
||||||
io_buffer->out_buffer_append(res.data(), res.size());
|
io_buffer->out_buffer_append(res.data(), res.size());
|
||||||
fork_was_skipped = true;
|
fork_was_skipped = true;
|
||||||
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
|
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
|
||||||
// We are writing to normal stdout and stderr. Just do it - no need to
|
// We are writing to normal stdout and stderr. Just do it - no need to
|
||||||
// fork.
|
// fork.
|
||||||
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
|
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
|
||||||
p->argv0());
|
p->argv0());
|
||||||
const std::string outbuff = wcs2string(stdout_buffer);
|
const std::string outbuff = wcs2string(stdout_buffer);
|
||||||
const std::string errbuff = wcs2string(stderr_buffer);
|
const std::string errbuff = wcs2string(stderr_buffer);
|
||||||
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
|
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
|
||||||
errbuff.data(), errbuff.size());
|
errbuff.data(), errbuff.size());
|
||||||
if (!builtin_io_done && errno != EPIPE) {
|
if (!builtin_io_done && errno != EPIPE) {
|
||||||
show_stackframe(L'E');
|
show_stackframe(L'E');
|
||||||
}
|
|
||||||
fork_was_skipped = true;
|
|
||||||
}
|
}
|
||||||
|
fork_was_skipped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,10 +225,8 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc, size_t *offset)
|
||||||
const wcstring base_cmd = wbasename(cmd);
|
const wcstring base_cmd = wbasename(cmd);
|
||||||
|
|
||||||
bool result = string_prefixes_string(proc, base_cmd);
|
bool result = string_prefixes_string(proc, base_cmd);
|
||||||
if (result) {
|
// It's a match. Return the offset within the full command.
|
||||||
// It's a match. Return the offset within the full command.
|
if (result && offset) *offset = cmd.size() - base_cmd.size();
|
||||||
if (offset) *offset = cmd.size() - base_cmd.size();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,13 +630,11 @@ static bool expand_pid(const wcstring &instr_with_sep, expand_flags_t flags,
|
||||||
const size_t prev_count = out->size();
|
const size_t prev_count = out->size();
|
||||||
find_process(in + 1, flags, out);
|
find_process(in + 1, flags, out);
|
||||||
|
|
||||||
if (prev_count == out->size()) {
|
if (prev_count == out->size() && !(flags & EXPAND_FOR_COMPLETIONS)) {
|
||||||
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
|
// We failed to find anything.
|
||||||
// We failed to find anything.
|
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
|
||||||
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
|
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
|
||||||
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1025,21 +1021,19 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
|
||||||
tot_len = length_preceding_brackets + length_following_brackets;
|
tot_len = length_preceding_brackets + length_following_brackets;
|
||||||
item_begin = bracket_begin + 1;
|
item_begin = bracket_begin + 1;
|
||||||
for (const wchar_t *pos = (bracket_begin + 1); true; pos++) {
|
for (const wchar_t *pos = (bracket_begin + 1); true; pos++) {
|
||||||
if (bracket_count == 0) {
|
if (bracket_count == 0 && ((*pos == BRACKET_SEP) || (pos == bracket_end))) {
|
||||||
if ((*pos == BRACKET_SEP) || (pos == bracket_end)) {
|
assert(pos >= item_begin);
|
||||||
assert(pos >= item_begin);
|
size_t item_len = pos - item_begin;
|
||||||
size_t item_len = pos - item_begin;
|
|
||||||
|
|
||||||
wcstring whole_item;
|
wcstring whole_item;
|
||||||
whole_item.reserve(tot_len + item_len + 2);
|
whole_item.reserve(tot_len + item_len + 2);
|
||||||
whole_item.append(in, length_preceding_brackets);
|
whole_item.append(in, length_preceding_brackets);
|
||||||
whole_item.append(item_begin, item_len);
|
whole_item.append(item_begin, item_len);
|
||||||
whole_item.append(bracket_end + 1);
|
whole_item.append(bracket_end + 1);
|
||||||
expand_brackets(whole_item, flags, out, errors);
|
expand_brackets(whole_item, flags, out, errors);
|
||||||
|
|
||||||
item_begin = pos + 1;
|
item_begin = pos + 1;
|
||||||
if (pos == bracket_end) break;
|
if (pos == bracket_end) break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*pos == BRACKET_BEGIN) {
|
if (*pos == BRACKET_BEGIN) {
|
||||||
|
@ -1517,19 +1511,17 @@ expand_error_t expand_string(const wcstring &input, std::vector<completion_t> *o
|
||||||
|
|
||||||
bool expand_one(wcstring &string, expand_flags_t flags, parse_error_list_t *errors) {
|
bool expand_one(wcstring &string, expand_flags_t flags, parse_error_list_t *errors) {
|
||||||
std::vector<completion_t> completions;
|
std::vector<completion_t> completions;
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
if ((!(flags & EXPAND_FOR_COMPLETIONS)) && expand_is_clean(string)) {
|
if (!(flags & EXPAND_FOR_COMPLETIONS) && expand_is_clean(string)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors)) {
|
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors) &&
|
||||||
if (completions.size() == 1) {
|
completions.size() == 1) {
|
||||||
string = completions.at(0).completion;
|
string = completions.at(0).completion;
|
||||||
result = true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/fish-shell/fish-shell/issues/367
|
// https://github.com/fish-shell/fish-shell/issues/367
|
||||||
|
|
|
@ -311,8 +311,8 @@ wcstring_list_t function_get_names(int get_hidden) {
|
||||||
const wcstring &name = iter->first;
|
const wcstring &name = iter->first;
|
||||||
|
|
||||||
// Maybe skip hidden.
|
// Maybe skip hidden.
|
||||||
if (!get_hidden) {
|
if (!get_hidden && (name.empty() || name.at(0) == L'_')) {
|
||||||
if (name.empty() || name.at(0) == L'_') continue;
|
continue;
|
||||||
}
|
}
|
||||||
names.insert(name);
|
names.insert(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,19 +224,16 @@ static bool is_potential_cd_path(const wcstring &path, const wcstring &working_d
|
||||||
bool plain_statement_get_expanded_command(const wcstring &src, const parse_node_tree_t &tree,
|
bool plain_statement_get_expanded_command(const wcstring &src, const parse_node_tree_t &tree,
|
||||||
const parse_node_t &plain_statement, wcstring *out_cmd) {
|
const parse_node_t &plain_statement, wcstring *out_cmd) {
|
||||||
assert(plain_statement.type == symbol_plain_statement);
|
assert(plain_statement.type == symbol_plain_statement);
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
// Get the command.
|
// Get the command. Try expanding it. If we cannot, it's an error.
|
||||||
wcstring cmd;
|
wcstring cmd;
|
||||||
if (tree.command_for_plain_statement(plain_statement, src, &cmd)) {
|
if (tree.command_for_plain_statement(plain_statement, src, &cmd) &&
|
||||||
// Try expanding it. If we cannot, it's an error.
|
expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES | EXPAND_SKIP_JOBS)) {
|
||||||
if (expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES | EXPAND_SKIP_JOBS)) {
|
// Success, return the expanded string by reference.
|
||||||
// Success, return the expanded string by reference.
|
out_cmd->swap(cmd);
|
||||||
out_cmd->swap(cmd);
|
return true;
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background) {
|
rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background) {
|
||||||
|
@ -297,8 +294,6 @@ static bool has_expand_reserved(const wcstring &str) {
|
||||||
// (as a copied node), if any. This is used by autosuggestions.
|
// (as a copied node), if any. This is used by autosuggestions.
|
||||||
static bool autosuggest_parse_command(const wcstring &buff, wcstring *out_expanded_command,
|
static bool autosuggest_parse_command(const wcstring &buff, wcstring *out_expanded_command,
|
||||||
parse_node_t *out_last_arg) {
|
parse_node_t *out_last_arg) {
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
// Parse the buffer.
|
// Parse the buffer.
|
||||||
parse_node_tree_t parse_tree;
|
parse_node_tree_t parse_tree;
|
||||||
parse_tree_from_string(buff,
|
parse_tree_from_string(buff,
|
||||||
|
@ -308,21 +303,17 @@ static bool autosuggest_parse_command(const wcstring &buff, wcstring *out_expand
|
||||||
// Find the last statement.
|
// Find the last statement.
|
||||||
const parse_node_t *last_statement =
|
const parse_node_t *last_statement =
|
||||||
parse_tree.find_last_node_of_type(symbol_plain_statement, NULL);
|
parse_tree.find_last_node_of_type(symbol_plain_statement, NULL);
|
||||||
if (last_statement != NULL) {
|
if (last_statement != NULL && plain_statement_get_expanded_command(
|
||||||
if (plain_statement_get_expanded_command(buff, parse_tree, *last_statement,
|
buff, parse_tree, *last_statement, out_expanded_command)) {
|
||||||
out_expanded_command)) {
|
// Find the last argument. If we don't get one, return an invalid node.
|
||||||
// We got it.
|
const parse_node_t *last_arg =
|
||||||
result = true;
|
parse_tree.find_last_node_of_type(symbol_argument, last_statement);
|
||||||
|
if (last_arg != NULL) {
|
||||||
// Find the last argument. If we don't get one, return an invalid node.
|
*out_last_arg = *last_arg;
|
||||||
const parse_node_t *last_arg =
|
|
||||||
parse_tree.find_last_node_of_type(symbol_argument, last_statement);
|
|
||||||
if (last_arg != NULL) {
|
|
||||||
*out_last_arg = *last_arg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool autosuggest_validate_from_history(const history_item_t &item,
|
bool autosuggest_validate_from_history(const history_item_t &item,
|
||||||
|
@ -1163,18 +1154,15 @@ const highlighter_t::color_array_t &highlighter_t::highlight() {
|
||||||
// backspacing (and the cursor is just beyond the last token), we may still underline
|
// backspacing (and the cursor is just beyond the last token), we may still underline
|
||||||
// it.
|
// it.
|
||||||
if (this->cursor_pos >= node.source_start &&
|
if (this->cursor_pos >= node.source_start &&
|
||||||
this->cursor_pos - node.source_start <= node.source_length) {
|
this->cursor_pos - node.source_start <= node.source_length &&
|
||||||
// See if this is a valid path.
|
node_is_potential_path(buff, node, working_directory)) {
|
||||||
if (node_is_potential_path(buff, node, working_directory)) {
|
// It is, underline it.
|
||||||
// It is, underline it.
|
for (size_t i = node.source_start; i < node.source_start + node.source_length;
|
||||||
for (size_t i = node.source_start; i < node.source_start + node.source_length;
|
i++) {
|
||||||
i++) {
|
// Don't color highlight_spec_error because it looks dorky. For example,
|
||||||
// Don't color highlight_spec_error because it looks dorky. For example,
|
// trying to cd into a non-directory would show an underline and also red.
|
||||||
// trying to cd into a non-directory would show an underline and also red.
|
if (highlight_get_primary(this->color_array.at(i)) != highlight_spec_error) {
|
||||||
if (highlight_get_primary(this->color_array.at(i)) !=
|
this->color_array.at(i) |= highlight_modifier_valid_path;
|
||||||
highlight_spec_error) {
|
|
||||||
this->color_array.at(i) |= highlight_modifier_valid_path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,12 +272,8 @@ void set_color(rgb_color_t c, rgb_color_t c2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lastly, we set bold mode and underline mode correctly.
|
// Lastly, we set bold mode and underline mode correctly.
|
||||||
if ((enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set) {
|
if (is_bold && !was_bold && enter_bold_mode && strlen(enter_bold_mode) > 0 && !bg_set) {
|
||||||
if (is_bold && !was_bold) {
|
writembs(tparm(enter_bold_mode));
|
||||||
if (enter_bold_mode) {
|
|
||||||
writembs(tparm(enter_bold_mode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
was_bold = is_bold;
|
was_bold = is_bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1208,12 +1208,10 @@ parse_execution_result_t parse_execution_context_t::run_1_job(const parse_node_t
|
||||||
|
|
||||||
// Get terminal modes.
|
// Get terminal modes.
|
||||||
struct termios tmodes = {};
|
struct termios tmodes = {};
|
||||||
if (shell_is_interactive()) {
|
if (shell_is_interactive() && tcgetattr(STDIN_FILENO, &tmodes)) {
|
||||||
if (tcgetattr(STDIN_FILENO, &tmodes)) {
|
// Need real error handling here.
|
||||||
// Need real error handling here.
|
wperror(L"tcgetattr");
|
||||||
wperror(L"tcgetattr");
|
return parse_execution_errored;
|
||||||
return parse_execution_errored;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the eval_level for the duration of this command.
|
// Increment the eval_level for the duration of this command.
|
||||||
|
|
|
@ -500,11 +500,9 @@ const production_t *parse_productions::production_for_token(parse_token_type_t n
|
||||||
PARSE_ASSERT(resolver != NULL);
|
PARSE_ASSERT(resolver != NULL);
|
||||||
|
|
||||||
const production_t *result = resolver(input1, input2, out_tag);
|
const production_t *result = resolver(input1, input2, out_tag);
|
||||||
if (result == NULL) {
|
if (result == NULL && log_it) {
|
||||||
if (log_it) {
|
fprintf(stderr, "Node type '%ls' has no production for input '%ls' (in %s)\n",
|
||||||
fprintf(stderr, "Node type '%ls' has no production for input '%ls' (in %s)\n",
|
token_type_description(node_type), input1.describe().c_str(), __FUNCTION__);
|
||||||
token_type_description(node_type), input1.describe().c_str(), __FUNCTION__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1370,13 +1370,11 @@ const parse_node_t *parse_node_tree_t::find_last_node_of_type(parse_token_type_t
|
||||||
size_t idx = this->size();
|
size_t idx = this->size();
|
||||||
while (idx--) {
|
while (idx--) {
|
||||||
const parse_node_t &node = this->at(idx);
|
const parse_node_t &node = this->at(idx);
|
||||||
if (node.type == type) {
|
bool expected_type = (node.type == type);
|
||||||
// Types match. Check if it has the right parent.
|
if (expected_type && (parent == NULL || node_has_ancestor(*this, node, *parent))) {
|
||||||
if (parent == NULL || node_has_ancestor(*this, node, *parent)) {
|
// The types match and it has the right parent.
|
||||||
// Success
|
result = &node;
|
||||||
result = &node;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -471,7 +471,6 @@ void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_
|
||||||
size_t *offset, enum token_type *out_type) {
|
size_t *offset, enum token_type *out_type) {
|
||||||
size_t prev_pos = 0;
|
size_t prev_pos = 0;
|
||||||
wchar_t last_quote = '\0';
|
wchar_t last_quote = '\0';
|
||||||
int unfinished;
|
|
||||||
|
|
||||||
tokenizer_t tok(cmd.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
|
tokenizer_t tok(cmd.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS);
|
||||||
tok_t token;
|
tok_t token;
|
||||||
|
@ -488,30 +487,25 @@ void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_
|
||||||
wchar_t *cmd_tmp = wcsdup(cmd.c_str());
|
wchar_t *cmd_tmp = wcsdup(cmd.c_str());
|
||||||
cmd_tmp[pos] = 0;
|
cmd_tmp[pos] = 0;
|
||||||
size_t cmdlen = wcslen(cmd_tmp);
|
size_t cmdlen = wcslen(cmd_tmp);
|
||||||
unfinished = (cmdlen == 0);
|
bool finished = (cmdlen != 0);
|
||||||
if (!unfinished) {
|
if (finished) {
|
||||||
unfinished = (quote != 0);
|
finished = (quote == NULL);
|
||||||
|
if (finished && wcschr(L" \t\n\r", cmd_tmp[cmdlen - 1]) == 0) {
|
||||||
if (!unfinished) {
|
finished = (cmdlen == 1) || (cmd_tmp[cmdlen - 2] != L'\\');
|
||||||
if (wcschr(L" \t\n\r", cmd_tmp[cmdlen - 1]) != 0) {
|
|
||||||
if ((cmdlen == 1) || (cmd_tmp[cmdlen - 2] != L'\\')) {
|
|
||||||
unfinished = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quote) *quote = last_quote;
|
if (quote) *quote = last_quote;
|
||||||
|
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
if (!unfinished) {
|
if (finished) {
|
||||||
while ((cmd_tmp[prev_pos] != 0) && (wcschr(L";|", cmd_tmp[prev_pos]) != 0)) prev_pos++;
|
while ((cmd_tmp[prev_pos] != 0) && (wcschr(L";|", cmd_tmp[prev_pos]) != 0)) prev_pos++;
|
||||||
|
|
||||||
*offset = prev_pos;
|
*offset = prev_pos;
|
||||||
} else {
|
} else {
|
||||||
*offset = pos;
|
*offset = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(cmd_tmp);
|
free(cmd_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,22 +921,21 @@ static parser_test_error_bits_t detect_dollar_cmdsub_errors(size_t arg_src_offse
|
||||||
parse_error_list_t *out_errors) {
|
parse_error_list_t *out_errors) {
|
||||||
parser_test_error_bits_t result_bits = 0;
|
parser_test_error_bits_t result_bits = 0;
|
||||||
wcstring unescaped_arg_src;
|
wcstring unescaped_arg_src;
|
||||||
if (unescape_string(arg_src, &unescaped_arg_src, UNESCAPE_SPECIAL)) {
|
if (unescape_string(arg_src, &unescaped_arg_src, UNESCAPE_SPECIAL) &&
|
||||||
if (!unescaped_arg_src.empty()) {
|
!unescaped_arg_src.empty()) {
|
||||||
wchar_t last = unescaped_arg_src.at(unescaped_arg_src.size() - 1);
|
wchar_t last = unescaped_arg_src.at(unescaped_arg_src.size() - 1);
|
||||||
if (last == VARIABLE_EXPAND) {
|
if (last == VARIABLE_EXPAND) {
|
||||||
result_bits |= PARSER_TEST_ERROR;
|
result_bits |= PARSER_TEST_ERROR;
|
||||||
if (out_errors != NULL) {
|
if (out_errors != NULL) {
|
||||||
wcstring subcommand_first_token = tok_first(cmdsubst_src);
|
wcstring subcommand_first_token = tok_first(cmdsubst_src);
|
||||||
if (subcommand_first_token.empty()) {
|
if (subcommand_first_token.empty()) {
|
||||||
// e.g. $(). Report somthing.
|
// e.g. $(). Report somthing.
|
||||||
subcommand_first_token = L"...";
|
subcommand_first_token = L"...";
|
||||||
}
|
|
||||||
append_syntax_error(
|
|
||||||
out_errors,
|
|
||||||
arg_src_offset + arg_src.size() - 1, // global position of the dollar
|
|
||||||
ERROR_BAD_VAR_SUBCOMMAND1, truncate_string(subcommand_first_token).c_str());
|
|
||||||
}
|
}
|
||||||
|
append_syntax_error(
|
||||||
|
out_errors,
|
||||||
|
arg_src_offset + arg_src.size() - 1, // global position of the dollar
|
||||||
|
ERROR_BAD_VAR_SUBCOMMAND1, truncate_string(subcommand_first_token).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,9 @@ int set_child_group(job_t *j, process_t *p, int print_errors) {
|
||||||
j->pgid = p->pid;
|
j->pgid = p->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setpgid(p->pid, j->pgid)) {
|
if (setpgid(p->pid, j->pgid)) { //!OCLINT(collapsible if statements)
|
||||||
|
// TODO: Figure out why we're testing whether the pgid is correct after attempting to
|
||||||
|
// set it failed. This was added in commit 4e912ef8 from 2012-02-27.
|
||||||
if (getpgid(p->pid) != j->pgid && print_errors) {
|
if (getpgid(p->pid) != j->pgid && print_errors) {
|
||||||
char pid_buff[128];
|
char pid_buff[128];
|
||||||
char job_id_buff[128];
|
char job_id_buff[128];
|
||||||
|
@ -95,7 +97,8 @@ int set_child_group(job_t *j, process_t *p, int print_errors) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND)) {
|
if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND)) {
|
||||||
if (tcsetpgrp(0, j->pgid) && print_errors) {
|
int result = tcsetpgrp(0, j->pgid);
|
||||||
|
if (result == -1 && print_errors) {
|
||||||
char job_id_buff[64];
|
char job_id_buff[64];
|
||||||
char command_buff[64];
|
char command_buff[64];
|
||||||
format_long_safe(job_id_buff, j->job_id);
|
format_long_safe(job_id_buff, j->job_id);
|
||||||
|
@ -485,20 +488,14 @@ void safe_report_exec_error(int err, const char *actual_cmd, const char *const *
|
||||||
/// allocate memory, etc.
|
/// allocate memory, etc.
|
||||||
bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errlen) {
|
bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errlen) {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (out && outlen) {
|
if (out && outlen && write_loop(STDOUT_FILENO, out, outlen) < 0) {
|
||||||
if (write_loop(STDOUT_FILENO, out, outlen) < 0) {
|
int e = errno;
|
||||||
int e = errno;
|
debug_safe(0, "Error while writing to stdout");
|
||||||
debug_safe(0, "Error while writing to stdout");
|
safe_perror("write_loop");
|
||||||
safe_perror("write_loop");
|
success = false;
|
||||||
success = false;
|
errno = e;
|
||||||
errno = e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err && errlen) {
|
if (err && errlen && write_loop(STDERR_FILENO, err, errlen) < 0) success = false;
|
||||||
if (write_loop(STDERR_FILENO, err, errlen) < 0) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@ void print_help(const char *c, int fd) {
|
||||||
char cmd[CMD_LEN];
|
char cmd[CMD_LEN];
|
||||||
int printed = snprintf(cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd);
|
int printed = snprintf(cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd);
|
||||||
|
|
||||||
if (printed < CMD_LEN) {
|
if (printed < CMD_LEN && system(cmd) == -1) {
|
||||||
if ((system(cmd) == -1)) {
|
write_loop(2, HELP_ERR, strlen(HELP_ERR));
|
||||||
write_loop(2, HELP_ERR, strlen(HELP_ERR));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
143
src/proc.cpp
143
src/proc.cpp
|
@ -257,13 +257,9 @@ int job_signal(job_t *j, int signal) {
|
||||||
res = killpg(j->pgid, signal);
|
res = killpg(j->pgid, signal);
|
||||||
} else {
|
} else {
|
||||||
for (process_t *p = j->first_process; p; p = p->next) {
|
for (process_t *p = j->first_process; p; p = p->next) {
|
||||||
if (!p->completed) {
|
if (!p->completed && p->pid && kill(p->pid, signal)) {
|
||||||
if (p->pid) {
|
res = -1;
|
||||||
if (kill(p->pid, signal)) {
|
break;
|
||||||
res = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,10 +308,8 @@ static void handle_child_status(pid_t pid, int status) {
|
||||||
for (p = j->first_process; p; p = p->next) {
|
for (p = j->first_process; p; p = p->next) {
|
||||||
if (pid == p->pid) {
|
if (pid == p->pid) {
|
||||||
mark_process_status(p, status);
|
mark_process_status(p, status);
|
||||||
if (p->completed && prev != 0) {
|
if (p->completed && prev && !prev->completed && prev->pid) {
|
||||||
if (!prev->completed && prev->pid) {
|
kill(prev->pid, SIGPIPE);
|
||||||
kill(prev->pid, SIGPIPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
found_proc = true;
|
found_proc = true;
|
||||||
break;
|
break;
|
||||||
|
@ -568,61 +562,57 @@ int job_reap(bool allow_interactive) {
|
||||||
proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, p->pid,
|
proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, p->pid,
|
||||||
(WIFSIGNALED(s) ? -1 : WEXITSTATUS(s)));
|
(WIFSIGNALED(s) ? -1 : WEXITSTATUS(s)));
|
||||||
|
|
||||||
if (WIFSIGNALED(s)) {
|
// Ignore signal SIGPIPE.We issue it ourselves to the pipe writer when the pipe
|
||||||
// Ignore signal SIGPIPE.We issue it ourselves to the pipe writer when the pipe
|
// reader dies.
|
||||||
// reader dies.
|
if (WIFSIGNALED(s) && WTERMSIG(s) != SIGPIPE) {
|
||||||
if (WTERMSIG(s) != SIGPIPE) {
|
int proc_is_job = ((p == j->first_process) && (p->next == 0));
|
||||||
int proc_is_job = ((p == j->first_process) && (p->next == 0));
|
if (proc_is_job) job_set_flag(j, JOB_NOTIFIED, 1);
|
||||||
if (proc_is_job) job_set_flag(j, JOB_NOTIFIED, 1);
|
if (!job_get_flag(j, JOB_SKIP_NOTIFICATION)) {
|
||||||
if (!job_get_flag(j, JOB_SKIP_NOTIFICATION)) {
|
// Print nothing if we get SIGINT in the foreground process group, to avoid
|
||||||
// Print nothing if we get SIGINT in the foreground process group, to avoid
|
// spamming obvious stuff on the console (#1119). If we get SIGINT for the
|
||||||
// spamming obvious stuff on the console (#1119). If we get SIGINT for the
|
// foreground process, assume the user typed ^C and can see it working. It's
|
||||||
// foreground process, assume the user typed ^C and can see it working. It's
|
// possible they didn't, and the signal was delivered via pkill, etc., but
|
||||||
// possible they didn't, and the signal was delivered via pkill, etc., but
|
// the SIGINT/SIGTERM distinction is precisely to allow INT to be from a UI
|
||||||
// the SIGINT/SIGTERM distinction is precisely to allow INT to be from a UI
|
// and TERM to be programmatic, so this assumption is keeping with the
|
||||||
// and TERM to be programmatic, so this assumption is keeping with the
|
// design of signals. If echoctl is on, then the terminal will have written
|
||||||
// design of signals. If echoctl is on, then the terminal will have written
|
// ^C to the console. If off, it won't have. We don't echo ^C either way, so
|
||||||
// ^C to the console. If off, it won't have. We don't echo ^C either way, so
|
// as to respect the user's preference.
|
||||||
// as to respect the user's preference.
|
if (WTERMSIG(p->status) != SIGINT || !job_get_flag(j, JOB_FOREGROUND)) {
|
||||||
if (WTERMSIG(p->status) != SIGINT || !job_get_flag(j, JOB_FOREGROUND)) {
|
if (proc_is_job) {
|
||||||
if (proc_is_job) {
|
// We want to report the job number, unless it's the only job, in
|
||||||
// We want to report the job number, unless it's the only job, in
|
// which case we don't need to.
|
||||||
// which case we don't need to.
|
const wcstring job_number_desc =
|
||||||
const wcstring job_number_desc =
|
(job_count == 1) ? wcstring()
|
||||||
(job_count == 1) ? wcstring()
|
: format_string(L"Job %d, ", j->job_id);
|
||||||
: format_string(L"Job %d, ", j->job_id);
|
fwprintf(stdout, _(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"),
|
||||||
fwprintf(stdout,
|
program_name, job_number_desc.c_str(),
|
||||||
_(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"),
|
truncate_command(j->command()).c_str(),
|
||||||
program_name, job_number_desc.c_str(),
|
sig2wcs(WTERMSIG(p->status)),
|
||||||
truncate_command(j->command()).c_str(),
|
signal_get_desc(WTERMSIG(p->status)));
|
||||||
sig2wcs(WTERMSIG(p->status)),
|
} else {
|
||||||
signal_get_desc(WTERMSIG(p->status)));
|
const wcstring job_number_desc =
|
||||||
} else {
|
(job_count == 1) ? wcstring()
|
||||||
const wcstring job_number_desc =
|
: format_string(L"from job %d, ", j->job_id);
|
||||||
(job_count == 1) ? wcstring()
|
fwprintf(stdout, _(L"%ls: Process %d, \'%ls\' %ls\'%ls\' "
|
||||||
: format_string(L"from job %d, ", j->job_id);
|
L"terminated by signal %ls (%ls)"),
|
||||||
fwprintf(stdout, _(L"%ls: Process %d, \'%ls\' %ls\'%ls\' "
|
program_name, p->pid, p->argv0(), job_number_desc.c_str(),
|
||||||
L"terminated by signal %ls (%ls)"),
|
truncate_command(j->command()).c_str(),
|
||||||
program_name, p->pid, p->argv0(), job_number_desc.c_str(),
|
sig2wcs(WTERMSIG(p->status)),
|
||||||
truncate_command(j->command()).c_str(),
|
signal_get_desc(WTERMSIG(p->status)));
|
||||||
sig2wcs(WTERMSIG(p->status)),
|
|
||||||
signal_get_desc(WTERMSIG(p->status)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_term != NULL)
|
|
||||||
tputs(clr_eol, 1, &writeb);
|
|
||||||
else
|
|
||||||
fwprintf(stdout,
|
|
||||||
L"\x1b[K"); // no term set up - do clr_eol manually
|
|
||||||
|
|
||||||
fwprintf(stdout, L"\n");
|
|
||||||
}
|
}
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear status so it is not reported more than once.
|
if (cur_term != NULL)
|
||||||
p->status = 0;
|
tputs(clr_eol, 1, &writeb);
|
||||||
|
else
|
||||||
|
fwprintf(stdout, L"\x1b[K"); // no term set up - do clr_eol manually
|
||||||
|
|
||||||
|
fwprintf(stdout, L"\n");
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear status so it is not reported more than once.
|
||||||
|
p->status = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,13 +793,10 @@ static bool terminal_give_to_job(job_t *j, int cont) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cont) {
|
if (cont && tcsetattr(0, TCSADRAIN, &j->tmodes)) {
|
||||||
if (tcsetattr(0, TCSADRAIN, &j->tmodes)) {
|
debug(1, _(L"Could not send job %d ('%ls') to foreground"), j->job_id, j->command_wcstr());
|
||||||
debug(1, _(L"Could not send job %d ('%ls') to foreground"), j->job_id,
|
wperror(L"tcsetattr");
|
||||||
j->command_wcstr());
|
return false;
|
||||||
wperror(L"tcsetattr");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -944,15 +931,13 @@ void job_continue(job_t *j, bool cont) {
|
||||||
process_t *p = j->first_process;
|
process_t *p = j->first_process;
|
||||||
while (p->next) p = p->next;
|
while (p->next) p = p->next;
|
||||||
|
|
||||||
if (WIFEXITED(p->status) || WIFSIGNALED(p->status)) {
|
// Mark process status only if we are in the foreground and the last process in a pipe,
|
||||||
// Mark process status only if we are in the foreground and the last process in a
|
// and it is not a short circuited builtin.
|
||||||
// pipe, and it is not a short circuited builtin.
|
if ((WIFEXITED(p->status) || WIFSIGNALED(p->status)) && p->pid) {
|
||||||
if (p->pid) {
|
int status = proc_format_status(p->status);
|
||||||
int status = proc_format_status(p->status);
|
// wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE
|
||||||
// wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE
|
// )?!status:status, j->command);
|
||||||
// )?!status:status, j->command);
|
proc_set_last_status(job_get_flag(j, JOB_NEGATE) ? !status : status);
|
||||||
proc_set_last_status(job_get_flag(j, JOB_NEGATE) ? !status : status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -697,14 +697,13 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) {
|
||||||
wcstring_list_t lst;
|
wcstring_list_t lst;
|
||||||
|
|
||||||
proc_push_interactive(0);
|
proc_push_interactive(0);
|
||||||
if (exec_subshell(fish_title_command, lst, false /* do not apply exit status */) != -1) {
|
if (exec_subshell(fish_title_command, lst, false /* ignore exit status */) != -1 &&
|
||||||
if (!lst.empty()) {
|
!lst.empty()) {
|
||||||
writestr(L"\x1b]0;");
|
writestr(L"\x1b]0;");
|
||||||
for (size_t i = 0; i < lst.size(); i++) {
|
for (size_t i = 0; i < lst.size(); i++) {
|
||||||
writestr(lst.at(i).c_str());
|
writestr(lst.at(i).c_str());
|
||||||
}
|
|
||||||
writestr(L"\7");
|
|
||||||
}
|
}
|
||||||
|
writestr(L"\7");
|
||||||
}
|
}
|
||||||
proc_pop_interactive();
|
proc_pop_interactive();
|
||||||
set_color(rgb_color_t::reset(), rgb_color_t::reset());
|
set_color(rgb_color_t::reset(), rgb_color_t::reset());
|
||||||
|
@ -1531,10 +1530,8 @@ static bool check_for_orphaned_process(unsigned long loop_count, pid_t shell_pgi
|
||||||
// Try kill-0'ing the process whose pid corresponds to our process group ID. It's possible this
|
// Try kill-0'ing the process whose pid corresponds to our process group ID. It's possible this
|
||||||
// will fail because we don't have permission to signal it. But more likely it will fail because
|
// will fail because we don't have permission to signal it. But more likely it will fail because
|
||||||
// it no longer exists, and we are orphaned.
|
// it no longer exists, and we are orphaned.
|
||||||
if (loop_count % 64 == 0) {
|
if (loop_count % 64 == 0 && kill(shell_pgid, 0) < 0 && errno == ESRCH) {
|
||||||
if (kill(shell_pgid, 0) < 0 && errno == ESRCH) {
|
we_think_we_are_orphaned = true;
|
||||||
we_think_we_are_orphaned = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!we_think_we_are_orphaned && loop_count % 128 == 0) {
|
if (!we_think_we_are_orphaned && loop_count % 128 == 0) {
|
||||||
|
@ -1646,12 +1643,10 @@ static void reader_interactive_init() {
|
||||||
|
|
||||||
// Put ourselves in our own process group.
|
// Put ourselves in our own process group.
|
||||||
shell_pgid = getpid();
|
shell_pgid = getpid();
|
||||||
if (getpgrp() != shell_pgid) {
|
if (getpgrp() != shell_pgid && setpgid(shell_pgid, shell_pgid) < 0) {
|
||||||
if (setpgid(shell_pgid, shell_pgid) < 0) {
|
debug(1, _(L"Couldn't put the shell in its own process group"));
|
||||||
debug(1, _(L"Couldn't put the shell in its own process group"));
|
wperror(L"setpgid");
|
||||||
wperror(L"setpgid");
|
exit_without_destructors(1);
|
||||||
exit_without_destructors(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab control of the terminal.
|
// Grab control of the terminal.
|
||||||
|
@ -2438,42 +2433,40 @@ const wchar_t *reader_readline(int nchars) {
|
||||||
is_interactive_read = was_interactive_read;
|
is_interactive_read = was_interactive_read;
|
||||||
// fprintf(stderr, "C: %lx\n", (long)c);
|
// fprintf(stderr, "C: %lx\n", (long)c);
|
||||||
|
|
||||||
if (((!fish_reserved_codepoint(c))) && (c > 31) && (c != 127)) {
|
if (((!fish_reserved_codepoint(c))) && (c > 31) && (c != 127) && can_read(0)) {
|
||||||
if (can_read(0)) {
|
wchar_t arr[READAHEAD_MAX + 1];
|
||||||
wchar_t arr[READAHEAD_MAX + 1];
|
size_t i;
|
||||||
size_t i;
|
size_t limit = 0 < nchars ? std::min((size_t)nchars - data->command_line.size(),
|
||||||
size_t limit = 0 < nchars ? std::min((size_t)nchars - data->command_line.size(),
|
(size_t)READAHEAD_MAX)
|
||||||
(size_t)READAHEAD_MAX)
|
: READAHEAD_MAX;
|
||||||
: READAHEAD_MAX;
|
|
||||||
|
|
||||||
memset(arr, 0, sizeof(arr));
|
memset(arr, 0, sizeof(arr));
|
||||||
arr[0] = c;
|
arr[0] = c;
|
||||||
|
|
||||||
for (i = 1; i < limit; ++i) {
|
for (i = 1; i < limit; ++i) {
|
||||||
if (!can_read(0)) {
|
if (!can_read(0)) {
|
||||||
c = 0;
|
c = 0;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
// Only allow commands on the first key; otherwise, we might have data we
|
|
||||||
// need to insert on the commandline that the commmand might need to be able
|
|
||||||
// to see.
|
|
||||||
c = input_readch(false);
|
|
||||||
if ((!fish_reserved_codepoint(c)) && (c > 31) && (c != 127)) {
|
|
||||||
arr[i] = c;
|
|
||||||
c = 0;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// Only allow commands on the first key; otherwise, we might have data we
|
||||||
editable_line_t *el = data->active_edit_line();
|
// need to insert on the commandline that the commmand might need to be able
|
||||||
insert_string(el, arr, true);
|
// to see.
|
||||||
|
c = input_readch(false);
|
||||||
// End paging upon inserting into the normal command line.
|
if (!fish_reserved_codepoint(c) && c > 31 && c != 127) {
|
||||||
if (el == &data->command_line) {
|
arr[i] = c;
|
||||||
clear_pager();
|
c = 0;
|
||||||
}
|
} else
|
||||||
last_char = c;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editable_line_t *el = data->active_edit_line();
|
||||||
|
insert_string(el, arr, true);
|
||||||
|
|
||||||
|
// End paging upon inserting into the normal command line.
|
||||||
|
if (el == &data->command_line) {
|
||||||
|
clear_pager();
|
||||||
|
}
|
||||||
|
last_char = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c != 0) break;
|
if (c != 0) break;
|
||||||
|
|
10
src/util.cpp
10
src/util.cpp
|
@ -58,12 +58,10 @@ int wcsfilecmp(const wchar_t *a, const wchar_t *b) {
|
||||||
|
|
||||||
int res = wcsfilecmp(a + 1, b + 1);
|
int res = wcsfilecmp(a + 1, b + 1);
|
||||||
|
|
||||||
if (abs(res) < 2) {
|
// If no primary difference in rest of string use secondary difference on this element if
|
||||||
// No primary difference in rest of string. Use secondary difference on this element if
|
// found.
|
||||||
// found.
|
if (abs(res) < 2 && secondary_diff) {
|
||||||
if (secondary_diff) {
|
return secondary_diff > 0 ? 1 : -1;
|
||||||
return secondary_diff > 0 ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -328,14 +328,12 @@ static wcstring file_get_desc(const wcstring &filename, int lstat_res, const str
|
||||||
if (S_ISDIR(buf.st_mode)) {
|
if (S_ISDIR(buf.st_mode)) {
|
||||||
return COMPLETE_DIRECTORY_SYMLINK_DESC;
|
return COMPLETE_DIRECTORY_SYMLINK_DESC;
|
||||||
}
|
}
|
||||||
if (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
|
if (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) && waccess(filename, X_OK) == 0) {
|
||||||
if (waccess(filename, X_OK) == 0) {
|
// Weird group permissions and other such issues make it non-trivial to
|
||||||
// Weird group permissions and other such issues make it non-trivial to
|
// find out if we can actually execute a file using the result from
|
||||||
// find out if we can actually execute a file using the result from
|
// stat. It is much safer to use the access function, since it tells us
|
||||||
// stat. It is much safer to use the access function, since it tells us
|
// exactly what we want to know.
|
||||||
// exactly what we want to know.
|
return COMPLETE_EXEC_LINK_DESC;
|
||||||
return COMPLETE_EXEC_LINK_DESC;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return COMPLETE_SYMLINK_DESC;
|
return COMPLETE_SYMLINK_DESC;
|
||||||
|
@ -364,14 +362,12 @@ static wcstring file_get_desc(const wcstring &filename, int lstat_res, const str
|
||||||
} else if (S_ISDIR(buf.st_mode)) {
|
} else if (S_ISDIR(buf.st_mode)) {
|
||||||
return COMPLETE_DIRECTORY_DESC;
|
return COMPLETE_DIRECTORY_DESC;
|
||||||
} else {
|
} else {
|
||||||
if (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXGRP)) {
|
if (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXGRP) && waccess(filename, X_OK) == 0) {
|
||||||
if (waccess(filename, X_OK) == 0) {
|
// Weird group permissions and other such issues make it non-trivial to find out
|
||||||
// Weird group permissions and other such issues make it non-trivial to find out
|
// if we can actually execute a file using the result from stat. It is much
|
||||||
// if we can actually execute a file using the result from stat. It is much
|
// safer to use the access function, since it tells us exactly what we want to
|
||||||
// safer to use the access function, since it tells us exactly what we want to
|
// know.
|
||||||
// know.
|
return COMPLETE_EXEC_DESC;
|
||||||
return COMPLETE_EXEC_DESC;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,15 +411,14 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath, const wc
|
||||||
const bool is_directory = stat_res == 0 && S_ISDIR(stat_buf.st_mode);
|
const bool is_directory = stat_res == 0 && S_ISDIR(stat_buf.st_mode);
|
||||||
const bool is_executable = stat_res == 0 && S_ISREG(stat_buf.st_mode);
|
const bool is_executable = stat_res == 0 && S_ISREG(stat_buf.st_mode);
|
||||||
|
|
||||||
if (expand_flags & DIRECTORIES_ONLY) {
|
const bool need_directory = expand_flags & DIRECTORIES_ONLY;
|
||||||
if (!is_directory) {
|
if (need_directory && !is_directory) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (expand_flags & EXECUTABLES_ONLY) {
|
|
||||||
if (!is_executable || waccess(filepath, X_OK) != 0) {
|
const bool executables_only = expand_flags & EXECUTABLES_ONLY;
|
||||||
return false;
|
if (executables_only && (!is_executable || waccess(filepath, X_OK) != 0)) {
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the description.
|
// Compute the description.
|
||||||
|
|
Loading…
Reference in a new issue