commit - 8641a33271eb0cef324fbeb4440485de8f433134
commit + 557d33657977f5752a77f1ac50dc51aaab381f41
blob - 8afaab18b7d71f4b1b6d555d34c39d3d3df20166
blob + ca273f088abf440f2971a8633e52b3f2fe3bb8c9
--- tog/tog.c
+++ tog/tog.c
FILE *cin;
FILE *cout;
FILE *f;
-};
+} tog_io;
+static int using_mock_io;
#define TOG_SCREEN_DUMP "SCREENDUMP"
#define TOG_SCREEN_DUMP_LEN (sizeof(TOG_SCREEN_DUMP) - 1)
cbreak();
noecho();
nodelay(v->window, TRUE);
- if (!fast_refresh)
+ if (!fast_refresh && !using_mock_io)
halfdelay(10);
if (ret == ERR)
return NULL;
static const struct got_error *
view_input(struct tog_view **new, int *done, struct tog_view *view,
- struct tog_view_list_head *views, struct tog_io *tog_io, int fast_refresh)
+ struct tog_view_list_head *views, int fast_refresh)
{
const struct got_error *err = NULL;
struct tog_view *v;
if (errcode)
return got_error_set_errno(errcode, "pthread_mutex_unlock");
- if (tog_io && tog_io->f) {
- err = tog_read_script_key(tog_io->f, &ch, done);
+ if (using_mock_io) {
+ err = tog_read_script_key(tog_io.f, &ch, done);
if (err)
return err;
} else if (view->count && --view->count) {
}
static const struct got_error *
-tog_io_close(struct tog_io *tog_io)
+tog_io_close(void)
{
const struct got_error *err = NULL;
- if (tog_io->cin && fclose(tog_io->cin) == EOF)
- err = got_ferror(tog_io->cin, GOT_ERR_IO);
- if (tog_io->cout && fclose(tog_io->cout) == EOF && err == NULL)
- err = got_ferror(tog_io->cout, GOT_ERR_IO);
- if (tog_io->f && fclose(tog_io->f) == EOF && err == NULL)
- err = got_ferror(tog_io->f, GOT_ERR_IO);
- free(tog_io);
- tog_io = NULL;
+ if (tog_io.cin && fclose(tog_io.cin) == EOF)
+ err = got_ferror(tog_io.cin, GOT_ERR_IO);
+ if (tog_io.cout && fclose(tog_io.cout) == EOF && err == NULL)
+ err = got_ferror(tog_io.cout, GOT_ERR_IO);
+ if (tog_io.f && fclose(tog_io.f) == EOF && err == NULL)
+ err = got_ferror(tog_io.f, GOT_ERR_IO);
return err;
}
static const struct got_error *
-view_loop(struct tog_view *view, struct tog_io *tog_io)
+view_loop(struct tog_view *view)
{
const struct got_error *err = NULL;
struct tog_view_list_head views;
while (!TAILQ_EMPTY(&views) && !done && !tog_thread_error &&
!tog_fatal_signal_received()) {
/* Refresh fast during initialization, then become slower. */
- if (fast_refresh && --fast_refresh == 0)
+ if (fast_refresh && --fast_refresh == 0 && !using_mock_io)
halfdelay(10); /* switch to once per second */
- err = view_input(&new_view, &done, view, &views, tog_io,
- fast_refresh);
+ err = view_input(&new_view, &done, view, &views, fast_refresh);
if (err)
break;
}
}
- if (s->thread_args.commits_needed == 0)
+ if (s->thread_args.commits_needed == 0 && !using_mock_io)
halfdelay(10); /* disable fast refresh */
if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) {
struct tog_log_thread_args *ta = &view->state.log.thread_args;
int errcode;
- halfdelay(1); /* fast refresh while loading commits */
+ if (!using_mock_io)
+ halfdelay(1); /* fast refresh while loading commits */
while (!ta->log_complete && !tog_thread_error &&
(ta->commits_needed > 0 || ta->load_all)) {
}
static const struct got_error *
-init_mock_term(struct tog_io **tog_io, const char *test_script_path)
+init_mock_term(const char *test_script_path)
{
const struct got_error *err = NULL;
- struct tog_io *io;
- if (*tog_io)
- *tog_io = NULL;
-
if (test_script_path == NULL || *test_script_path == '\0')
return got_error_msg(GOT_ERR_IO, "GOT_TOG_TEST not defined");
- io = calloc(1, sizeof(*io));
- if (io == NULL)
- return got_error_from_errno("calloc");
-
- io->f = fopen(test_script_path, "re");
- if (io->f == NULL) {
+ tog_io.f = fopen(test_script_path, "re");
+ if (tog_io.f == NULL) {
err = got_error_from_errno_fmt("fopen: %s",
test_script_path);
goto done;
}
/* test mode, we don't want any output */
- io->cout = fopen("/dev/null", "w+");
- if (io->cout == NULL) {
+ tog_io.cout = fopen("/dev/null", "w+");
+ if (tog_io.cout == NULL) {
err = got_error_from_errno("fopen: /dev/null");
goto done;
}
- io->cin = fopen("/dev/tty", "r+");
- if (io->cin == NULL) {
+ tog_io.cin = fopen("/dev/tty", "r+");
+ if (tog_io.cin == NULL) {
err = got_error_from_errno("fopen: /dev/tty");
goto done;
}
- if (fseeko(io->f, 0L, SEEK_SET) == -1) {
+ if (fseeko(tog_io.f, 0L, SEEK_SET) == -1) {
err = got_error_from_errno("fseeko");
goto done;
}
* XXX Perhaps we should define "xterm" as the terminal
* type for standardised testing instead of using $TERM?
*/
- if (newterm(NULL, io->cout, io->cin) == NULL)
+ if (newterm(NULL, tog_io.cout, tog_io.cin) == NULL)
err = got_error_msg(GOT_ERR_IO,
"newterm: failed to initialise curses");
+
+ using_mock_io = 1;
done:
if (err)
- tog_io_close(io);
- else
- *tog_io = io;
+ tog_io_close();
return err;
}
-static const struct got_error *
-init_curses(struct tog_io **tog_io)
+static void
+init_curses(void)
{
- const struct got_error *err = NULL;
- const char *test_script_path;
-
/*
* Override default signal handlers before starting ncurses.
* This should prevent ncurses from installing its own
signal(SIGINT, tog_sigint);
signal(SIGTERM, tog_sigterm);
- test_script_path = getenv("GOT_TOG_TEST");
- if (test_script_path != NULL) {
- err = init_mock_term(tog_io, test_script_path);
- if (err)
- return err;
- } else
- initscr();
+ if (using_mock_io) /* In test mode we use a fake terminal */
+ return;
+ initscr();
+
cbreak();
- halfdelay(1); /* Do fast refresh while initial view is loading. */
+ halfdelay(1); /* Fast refresh while initial view is loading. */
noecho();
nonl();
intrflush(stdscr, FALSE);
use_default_colors();
}
- return NULL;
+ return;
}
static const struct got_error *
const char *head_ref_name = NULL;
int ch, log_branches = 0;
struct tog_view *view;
- struct tog_io *tog_io = NULL;
int *pack_fds = NULL;
while ((ch = getopt(argc, argv, "bc:r:")) != -1) {
if (error)
goto done;
- error = init_curses(&tog_io);
- if (error)
- goto done;
+ init_curses();
error = apply_unveil(got_repo_get_path(repo),
worktree ? got_worktree_get_root_path(worktree) : NULL);
got_worktree_close(worktree);
worktree = NULL;
}
- error = view_loop(view, tog_io);
+ error = view_loop(view);
done:
free(in_repo_path);
free(repo_path);
if (error == NULL)
error = pack_err;
}
- if (tog_io != NULL) {
- io_err = tog_io_close(tog_io);
+ if (using_mock_io) {
+ io_err = tog_io_close();
if (error == NULL)
error = io_err;
}
s->parent_view = parent_view;
s->repo = repo;
- if (has_colors() && getenv("TOG_COLORS") != NULL) {
+ if (has_colors() && getenv("TOG_COLORS") != NULL && !using_mock_io) {
int rc;
rc = init_pair(GOT_DIFF_LINE_MINUS,
int ch, force_text_diff = 0;
const char *errstr;
struct tog_view *view;
- struct tog_io *tog_io = NULL;
int *pack_fds = NULL;
while ((ch = getopt(argc, argv, "aC:r:w")) != -1) {
if (error)
goto done;
- error = init_curses(&tog_io);
- if (error)
- goto done;
+ init_curses();
error = apply_unveil(got_repo_get_path(repo), NULL);
if (error)
ignore_whitespace, force_text_diff, NULL, repo);
if (error)
goto done;
- error = view_loop(view, tog_io);
+ error = view_loop(view);
done:
free(label1);
free(label2);
if (error == NULL)
error = pack_err;
}
- if (tog_io != NULL) {
- io_err = tog_io_close(tog_io);
+ if (using_mock_io) {
+ io_err = tog_io_close();
if (error == NULL)
error = io_err;
}
if (errcode)
return got_error_set_errno(errcode, "pthread_create");
- halfdelay(1); /* fast refresh while annotating */
+ if (!using_mock_io)
+ halfdelay(1); /* fast refresh while annotating */
}
- if (s->blame_complete)
+ if (s->blame_complete && !using_mock_io)
halfdelay(10); /* disable fast refresh */
err = draw_blame(view);
char *commit_id_str = NULL;
int ch;
struct tog_view *view;
- struct tog_io *tog_io = NULL;
int *pack_fds = NULL;
while ((ch = getopt(argc, argv, "c:r:")) != -1) {
if (error)
goto done;
- error = init_curses(&tog_io);
- if (error)
- goto done;
+ init_curses();
error = apply_unveil(got_repo_get_path(repo), NULL);
if (error)
got_worktree_close(worktree);
worktree = NULL;
}
- error = view_loop(view, tog_io);
+ error = view_loop(view);
done:
free(repo_path);
free(in_repo_path);
if (error == NULL)
error = pack_err;
}
- if (tog_io != NULL) {
- io_err = tog_io_close(tog_io);
+ if (using_mock_io) {
+ io_err = tog_io_close();
if (error == NULL)
error = io_err;
}
const char *head_ref_name = NULL;
int ch;
struct tog_view *view;
- struct tog_io *tog_io = NULL;
int *pack_fds = NULL;
while ((ch = getopt(argc, argv, "c:r:")) != -1) {
if (error)
goto done;
- error = init_curses(&tog_io);
- if (error)
- goto done;
+ init_curses();
error = apply_unveil(got_repo_get_path(repo), NULL);
if (error)
got_worktree_close(worktree);
worktree = NULL;
}
- error = view_loop(view, tog_io);
+ error = view_loop(view);
done:
free(repo_path);
free(cwd);
if (error == NULL)
error = pack_err;
}
- if (tog_io != NULL) {
- io_err = tog_io_close(tog_io);
+ if (using_mock_io) {
+ io_err = tog_io_close();
if (error == NULL)
error = io_err;
}
char *cwd = NULL, *repo_path = NULL;
int ch;
struct tog_view *view;
- struct tog_io *tog_io = NULL;
int *pack_fds = NULL;
while ((ch = getopt(argc, argv, "r:")) != -1) {
if (error != NULL)
goto done;
- error = init_curses(&tog_io);
- if (error)
- goto done;
+ init_curses();
error = apply_unveil(got_repo_get_path(repo), NULL);
if (error)
got_worktree_close(worktree);
worktree = NULL;
}
- error = view_loop(view, tog_io);
+ error = view_loop(view);
done:
free(repo_path);
free(cwd);
if (error == NULL)
error = pack_err;
}
- if (tog_io != NULL) {
- io_err = tog_io_close(tog_io);
+ if (using_mock_io) {
+ io_err = tog_io_close();
if (error == NULL)
error = io_err;
}
{ NULL, 0, NULL, 0}
};
char *diff_algo_str = NULL;
+ const char *test_script_path;
setlocale(LC_CTYPE, "");
-#if !defined(PROFILE) && !defined(TOG_REGRESS)
+ /*
+ * Test mode init must happen before pledge() because "tty" will
+ * not allow TTY-related ioctls to occur via regular files.
+ */
+ test_script_path = getenv("GOT_TOG_TEST");
+ if (test_script_path != NULL) {
+ error = init_mock_term(test_script_path);
+ if (error) {
+ fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
+ return 1;
+ }
+ }
+
+#if !defined(PROFILE)
if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil",
NULL) == -1)
err(1, "pledge");