fish-shell/src/builtin_fg.cpp

116 lines
3.9 KiB
C++
Raw Normal View History

2017-06-14 20:45:57 +00:00
// Implementation of the fg builtin.
#include "config.h" // IWYU pragma: keep
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <cwchar>
2017-06-14 20:45:57 +00:00
#include "builtin.h"
#include "builtin_fg.h"
#include "common.h"
#include "env.h"
#include "fallback.h" // IWYU pragma: keep
#include "io.h"
#include "parser.h"
2017-06-14 20:45:57 +00:00
#include "proc.h"
#include "reader.h"
2017-06-17 03:42:33 +00:00
#include "tokenizer.h"
2017-06-17 04:00:24 +00:00
#include "wutil.h" // IWYU pragma: keep
2017-06-14 20:45:57 +00:00
/// Builtin for putting a job in the foreground.
int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
2017-06-17 03:42:33 +00:00
help_only_cmd_opts_t opts;
2017-06-14 20:45:57 +00:00
int optind;
2017-06-17 03:42:33 +00:00
int retval = parse_help_only_cmd_opts(opts, &optind, argc, argv, parser, streams);
2017-06-14 20:45:57 +00:00
if (retval != STATUS_CMD_OK) return retval;
if (opts.print_help) {
builtin_print_help(parser, streams, cmd, streams.out);
return STATUS_CMD_OK;
}
job_t *job = nullptr;
2017-06-14 20:45:57 +00:00
if (optind == argc) {
// Select last constructed job (I.e. first job in the job que) that is possible to put in
// the foreground.
for (auto j : jobs()) {
if (j->is_constructed() && (!j->is_completed()) &&
((j->is_stopped() || (!j->is_foreground())) &&
j->get_flag(job_flag_t::JOB_CONTROL))) {
job = j.get();
2017-06-14 20:45:57 +00:00
break;
}
}
if (!job) {
2017-06-14 20:45:57 +00:00
streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), cmd);
}
} else if (optind + 1 < argc) {
// Specifying more than one job to put to the foreground is a syntax error, we still
// try to locate the job argv[1], since we want to know if this is an ambigous job
// specification or if this is an malformed job id.
int pid;
bool found_job = false;
2017-06-14 20:45:57 +00:00
pid = fish_wcstoi(argv[optind]);
if (!(errno || pid < 0)) {
job = job_t::from_pid(pid);
if (job) found_job = true;
2017-06-14 20:45:57 +00:00
}
if (found_job) {
streams.err.append_format(_(L"%ls: Ambiguous job\n"), cmd);
} else {
streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), cmd, argv[optind]);
}
builtin_print_error_trailer(parser, streams.err, cmd);
2017-06-14 20:45:57 +00:00
job = 0;
2017-06-14 20:45:57 +00:00
} else {
int pid = abs(fish_wcstoi(argv[optind]));
if (errno) {
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[optind]);
builtin_print_error_trailer(parser, streams.err, cmd);
2017-06-14 20:45:57 +00:00
} else {
job = job_t::from_pid(pid);
if (!job || !job->is_constructed() || job->is_completed()) {
2017-06-14 20:45:57 +00:00
streams.err.append_format(_(L"%ls: No suitable job: %d\n"), cmd, pid);
job = nullptr;
} else if (!job->get_flag(job_flag_t::JOB_CONTROL)) {
2017-06-14 20:45:57 +00:00
streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to foreground because "
L"it is not under job control\n"),
cmd, pid, job->command_wcstr());
job = 0;
2017-06-14 20:45:57 +00:00
}
}
}
if (!job) {
2017-06-14 20:45:57 +00:00
return STATUS_INVALID_ARGS;
}
if (streams.err_is_redirected) {
streams.err.append_format(FG_MSG, job->job_id, job->command_wcstr());
2017-06-14 20:45:57 +00:00
} else {
// If we aren't redirecting, send output to real stderr, since stuff in sb_err won't get
// printed until the command finishes.
std::fwprintf(stderr, FG_MSG, job->job_id, job->command_wcstr());
2017-06-14 20:45:57 +00:00
}
const wcstring ft = tok_first(job->command());
//For compatibility with fish 2.0's $_, now replaced with `status current-command`
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
reader_write_title(job->command());
2017-06-14 20:45:57 +00:00
job->promote();
job->set_flag(job_flag_t::FOREGROUND, true);
2017-06-14 20:45:57 +00:00
job->continue_job(job->is_stopped());
2017-06-14 20:45:57 +00:00
return STATUS_CMD_OK;
}