Code

Fix segfault when starting tig in pager mode
[tig.git] / tig.c
diff --git a/tig.c b/tig.c
index d7752a2f9131b75d4f7b9a58edad7e1bffdfff12..ae335183f472645e08687af539be91ec2213fb36 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -684,15 +684,23 @@ argv_free(const char *argv[])
        argv[0] = NULL;
 }
 
+static size_t
+argv_size(const char **argv)
+{
+       int argc = 0;
+
+       while (argv && argv[argc])
+               argc++;
+
+       return argc;
+}
+
 DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
 
 static bool
 argv_append(const char ***argv, const char *arg)
 {
-       int argc = 0;
-
-       while (*argv && (*argv)[argc])
-               argc++;
+       size_t argc = argv_size(*argv);
 
        if (!argv_realloc(argv, argc, 2))
                return FALSE;
@@ -2308,7 +2316,7 @@ static struct view views[] = {
        VIEW_(BLAME,  "blame",  &blame_ops,  TRUE,  ref_commit),
        VIEW_(BRANCH, "branch", &branch_ops, TRUE,  ref_head),
        VIEW_(HELP,   "help",   &help_ops,   FALSE, ""),
-       VIEW_(PAGER,  "pager",  &pager_ops,  FALSE, "stdin"),
+       VIEW_(PAGER,  "pager",  &pager_ops,  FALSE, ""),
        VIEW_(STATUS, "status", &status_ops, TRUE,  ""),
        VIEW_(STAGE,  "stage",  &stage_ops,  TRUE,  ""),
 };
@@ -3200,17 +3208,17 @@ format_argv(const char ***dst_argv, const char *src_argv[], bool replace)
                const char *arg = src_argv[argc];
                size_t bufpos = 0;
 
-               if (!strcmp(arg, "%(file-args)")) {
+               if (!strcmp(arg, "%(fileargs)")) {
                        if (!argv_append_array(dst_argv, opt_file_args))
                                break;
                        continue;
 
-               } else if (!strcmp(arg, "%(diff-args)")) {
+               } else if (!strcmp(arg, "%(diffargs)")) {
                        if (!argv_append_array(dst_argv, opt_diff_args))
                                break;
                        continue;
 
-               } else if (!strcmp(arg, "%(rev-args)")) {
+               } else if (!strcmp(arg, "%(revargs)")) {
                        if (!argv_append_array(dst_argv, opt_rev_args))
                                break;
                        continue;
@@ -3700,6 +3708,13 @@ view_driver(struct view *view, enum request request)
                break;
 
        case REQ_VIEW_PAGER:
+               if (view == NULL) {
+                       if (!io_open(&VIEW(REQ_VIEW_PAGER)->io, ""))
+                               die("Failed to open stdin");
+                       open_view(view, request, OPEN_PREPARED);
+                       break;
+               }
+
                if (!VIEW(REQ_VIEW_PAGER)->pipe && !VIEW(REQ_VIEW_PAGER)->lines) {
                        report("No pager content, press %s to run command from prompt",
                               get_key(view->keymap, REQ_PROMPT));
@@ -4183,14 +4198,41 @@ static struct view_ops log_ops = {
 static const char *diff_argv[SIZEOF_ARG] = {
        "git", "show", "--pretty=fuller", "--no-color", "--root",
                "--patch-with-stat", "--find-copies-harder", "-C",
-               "%(diff-args)", "%(commit)", "--", "%(file-args)", NULL
+               "%(diffargs)", "%(commit)", "--", "%(fileargs)", NULL
 };
 
+static bool
+diff_read(struct view *view, char *data)
+{
+       if (!data) {
+               /* Fall back to retry if no diff will be shown. */
+               if (view->lines == 0 && opt_file_args) {
+                       int pos = argv_size(view->argv)
+                               - argv_size(opt_file_args) - 1;
+
+                       if (pos > 0 && !strcmp(view->argv[pos], "--")) {
+                               for (; view->argv[pos]; pos++) {
+                                       free((void *) view->argv[pos]);
+                                       view->argv[pos] = NULL;
+                               }
+
+                               if (view->pipe)
+                                       io_done(view->pipe);
+                               if (io_run(&view->io, IO_RD, view->dir, view->argv))
+                                       return FALSE;
+                       }
+               }
+               return TRUE;
+       }
+
+       return pager_read(view, data);
+}
+
 static struct view_ops diff_ops = {
        "line",
        diff_argv,
        NULL,
-       pager_read,
+       diff_read,
        pager_draw,
        pager_request,
        pager_grep,
@@ -6707,8 +6749,8 @@ update_rev_graph(struct view *view, struct rev_graph *graph)
 
 static const char *main_argv[SIZEOF_ARG] = {
        "git", "log", "--no-color", "--pretty=raw", "--parents",
-               "--topo-order", "%(diff-args)", "%(rev-args)",
-               "--", "%(file-args)", NULL
+               "--topo-order", "%(diffargs)", "%(revargs)",
+               "--", "%(fileargs)", NULL
 };
 
 static bool
@@ -7729,10 +7771,8 @@ parse_options(int argc, const char *argv[])
        const char **filter_argv = NULL;
        int i;
 
-       if (!isatty(STDIN_FILENO)) {
-               io_open(&VIEW(REQ_VIEW_PAGER)->io, "");
+       if (!isatty(STDIN_FILENO))
                return REQ_VIEW_PAGER;
-       }
 
        if (argc <= 1)
                return REQ_VIEW_MAIN;