Correct error checking
[tig] / tig.c
diff --git a/tig.c b/tig.c
index decc434..851503f 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -164,6 +164,27 @@ chomp_string(char *name)
        return name;
 }
 
+static bool
+string_nformat(char *buf, size_t bufsize, int *bufpos, const char *fmt, ...)
+{
+       va_list args;
+       int pos = bufpos ? *bufpos : 0;
+
+       va_start(args, fmt);
+       pos += vsnprintf(buf + pos, bufsize - pos, fmt, args);
+       va_end(args);
+
+       if (bufpos)
+               *bufpos = pos;
+
+       return pos >= bufsize ? FALSE : TRUE;
+}
+
+#define string_format(buf, fmt, args...) \
+       string_nformat(buf, sizeof(buf), NULL, fmt, args)
+
+#define string_format_from(buf, from, fmt, args...) \
+       string_nformat(buf, sizeof(buf), from, fmt, args)
 
 /* Shell quoting
  *
@@ -582,6 +603,7 @@ LINE(PP_MERGE,         "Merge: ",           COLOR_BLUE,     COLOR_DEFAULT,  0), \
 LINE(PP_DATE,     "Date:   ",          COLOR_YELLOW,   COLOR_DEFAULT,  0), \
 LINE(PP_ADATE,    "AuthorDate: ",      COLOR_YELLOW,   COLOR_DEFAULT,  0), \
 LINE(PP_CDATE,    "CommitDate: ",      COLOR_YELLOW,   COLOR_DEFAULT,  0), \
+LINE(PP_REFS,     "Refs: ",            COLOR_RED,      COLOR_DEFAULT,  0), \
 LINE(COMMIT,      "commit ",           COLOR_GREEN,    COLOR_DEFAULT,  0), \
 LINE(PARENT,      "parent ",           COLOR_BLUE,     COLOR_DEFAULT,  0), \
 LINE(TREE,        "tree ",             COLOR_BLUE,     COLOR_DEFAULT,  0), \
@@ -798,8 +820,7 @@ load_options(void)
        config_lineno = 0;
        config_errors = FALSE;
 
-       if (!home ||
-           snprintf(buf, sizeof(buf), "%s/.tigrc", home) >= sizeof(buf))
+       if (!home || !string_format(buf, "%s/.tigrc", home))
                return ERR;
 
        /* It's ok that the file doesn't exist. */
@@ -862,6 +883,7 @@ struct view {
        /* Buffering */
        unsigned long lines;    /* Total number of lines */
        struct line *line;      /* Line index */
+       unsigned long line_size;/* Total number of allocated lines */
        unsigned int digits;    /* Number of digits in the lines member. */
 
        /* Loading */
@@ -875,7 +897,7 @@ struct view_ops {
        /* Draw one line; @lineno must be < view->height. */
        bool (*draw)(struct view *view, struct line *line, unsigned int lineno);
        /* Read one line; updates view->line. */
-       bool (*read)(struct view *view, struct line *prev, char *data);
+       bool (*read)(struct view *view, char *data);
        /* Depending on view, change display based on current line. */
        bool (*enter)(struct view *view, struct line *line);
 };
@@ -1270,8 +1292,7 @@ begin_update(struct view *view)
        } else {
                const char *format = view->cmd_env ? view->cmd_env : view->cmd_fmt;
 
-               if (snprintf(view->cmd, sizeof(view->cmd), format,
-                            id, id, id, id, id) >= sizeof(view->cmd))
+               if (!string_format(view->cmd, format, id, id, id, id, id))
                        return FALSE;
        }
 
@@ -1309,12 +1330,24 @@ begin_update(struct view *view)
        return TRUE;
 }
 
+static struct line *
+realloc_lines(struct view *view, size_t line_size)
+{
+       struct line *tmp = realloc(view->line, sizeof(*view->line) * line_size);
+
+       if (!tmp)
+               return NULL;
+
+       view->line = tmp;
+       view->line_size = line_size;
+       return view->line;
+}
+
 static bool
 update_view(struct view *view)
 {
        char buffer[BUFSIZ];
        char *line;
-       struct line *tmp;
        /* The number of lines to read. If too low it will cause too much
         * redrawing (and possible flickering), if too high responsiveness
         * will suffer. */
@@ -1328,23 +1361,16 @@ update_view(struct view *view)
        if (view->offset + view->height >= view->lines)
                redraw_from = view->lines - view->offset;
 
-       tmp = realloc(view->line, sizeof(*view->line) * (view->lines + lines));
-       if (!tmp)
+       if (!realloc_lines(view, view->lines + lines))
                goto alloc_error;
 
-       view->line = tmp;
-
        while ((line = fgets(buffer, sizeof(buffer), view->pipe))) {
                int linelen = strlen(line);
 
-               struct line *prev = view->lines
-                                 ? &view->line[view->lines - 1]
-                                 : NULL;
-
                if (linelen)
                        line[linelen - 1] = 0;
 
-               if (!view->ops->read(view, prev, line))
+               if (!view->ops->read(view, line))
                        goto alloc_error;
 
                if (lines-- == 1)
@@ -1698,16 +1724,59 @@ pager_draw(struct view *view, struct line *line, unsigned int lineno)
        return TRUE;
 }
 
+static void
+add_pager_refs(struct view *view, struct line *line)
+{
+       char buf[1024];
+       char *data = line->data;
+       struct ref **refs;
+       int bufpos = 0, refpos = 0;
+       const char *sep = "Refs: ";
+
+       assert(line->type == LINE_COMMIT);
+
+       refs = get_refs(data + STRING_SIZE("commit "));
+       if (!refs)
+               return;
+
+       do {
+               struct ref *ref = refs[refpos];
+               char *fmt = ref->tag ? "%s[%s]" : "%s%s";
+
+               if (!string_format_from(buf, &bufpos, fmt, sep, ref->name))
+                       return;
+               sep = ", ";
+       } while (refs[refpos++]->next);
+
+       if (!realloc_lines(view, view->line_size + 1))
+               return;
+
+       line = &view->line[view->lines];
+       line->data = strdup(buf);
+       if (!line->data)
+               return;
+
+       line->type = LINE_PP_REFS;
+       view->lines++;
+}
+
 static bool
-pager_read(struct view *view, struct line *prev, char *line)
+pager_read(struct view *view, char *data)
 {
-       view->line[view->lines].data = strdup(line);
-       if (!view->line[view->lines].data)
-               return FALSE;
+       struct line *line = &view->line[view->lines];
 
-       view->line[view->lines].type = get_line_type(line);
+       line->data = strdup(data);
+       if (!line->data)
+               return FALSE;
 
+       line->type = get_line_type(line->data);
        view->lines++;
+
+       if (line->type == LINE_COMMIT &&
+           (view == VIEW(REQ_VIEW_DIFF) ||
+            view == VIEW(REQ_VIEW_LOG)))
+               add_pager_refs(view, line);
+
        return TRUE;
 }
 
@@ -1858,10 +1927,11 @@ main_draw(struct view *view, struct line *line, unsigned int lineno)
 
 /* Reads git log --pretty=raw output and parses it into the commit struct. */
 static bool
-main_read(struct view *view, struct line *prev, char *line)
+main_read(struct view *view, char *line)
 {
        enum line_type type = get_line_type(line);
-       struct commit *commit;
+       struct commit *commit = view->lines
+                             ? view->line[view->lines - 1].data : NULL;
 
        switch (type) {
        case LINE_COMMIT:
@@ -1881,11 +1951,9 @@ main_read(struct view *view, struct line *prev, char *line)
                char *ident = line + STRING_SIZE("author ");
                char *end = strchr(ident, '<');
 
-               if (!prev)
+               if (!commit)
                        break;
 
-               commit = prev->data;
-
                if (end) {
                        for (; end > ident && isspace(end[-1]); end--) ;
                        *end = 0;
@@ -1924,11 +1992,9 @@ main_read(struct view *view, struct line *prev, char *line)
                break;
        }
        default:
-               if (!prev)
+               if (!commit)
                        break;
 
-               commit = prev->data;
-
                /* Fill in the commit title if it has not already been set. */
                if (commit->title[0])
                        break;
@@ -2100,8 +2166,7 @@ get_key(enum request request)
                if (!seq)
                        seq = "'?'";
 
-               pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%s", sep, seq);
-               if (pos >= sizeof(buf))
+               if (!string_format_from(buf, &pos, "%s%s", sep, seq))
                        return "Too many keybindings!";
                sep = ", ";
        }
@@ -2129,23 +2194,22 @@ static void load_help_page(void)
                return;
        }
 
-       pager_read(view, NULL, "Quick reference for tig keybindings:");
+       pager_read(view, "Quick reference for tig keybindings:");
 
        for (i = 0; i < ARRAY_SIZE(req_info); i++) {
                char *key;
 
                if (!req_info[i].request) {
-                       pager_read(view, NULL, "");
-                       pager_read(view, NULL, req_info[i].help);
+                       pager_read(view, "");
+                       pager_read(view, req_info[i].help);
                        continue;
                }
 
                key = get_key(req_info[i].request);
-               if (snprintf(buf, sizeof(buf), "%-25s %s", key, req_info[i].help)
-                   >= sizeof(buf))
+               if (!string_format(buf, "%-25s %s", key, req_info[i].help))
                        continue;
 
-               pager_read(view, NULL, buf);
+               pager_read(view, buf);
        }
 }