Fix tree viewing again; introduced by string safety patch
[tig] / tig.c
diff --git a/tig.c b/tig.c
index e78c26c..29f64da 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -145,16 +145,22 @@ set_from_int_map(struct int_map *map, size_t map_size,
  */
 
 static inline void
-string_ncopy(char *dst, const char *src, size_t dstlen)
+string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
 {
-       strncpy(dst, src, dstlen - 1);
-       dst[dstlen - 1] = 0;
+       if (srclen > dstlen - 1)
+               srclen = dstlen - 1;
 
+       strncpy(dst, src, srclen);
+       dst[srclen] = 0;
 }
 
-/* Shorthand for safely copying into a fixed buffer. */
+/* Shorthands for safely copying into a fixed buffer. */
+
 #define string_copy(dst, src) \
-       string_ncopy(dst, src, sizeof(dst))
+       string_ncopy_do(dst, sizeof(dst), src, sizeof(dst))
+
+#define string_ncopy(dst, src, srclen) \
+       string_ncopy_do(dst, sizeof(dst), src, srclen)
 
 static char *
 chomp_string(char *name)
@@ -675,7 +681,7 @@ static struct keybinding default_keybindings[] = {
        { 'd',          REQ_VIEW_DIFF },
        { 'l',          REQ_VIEW_LOG },
        { 't',          REQ_VIEW_TREE },
-       { 'b',          REQ_VIEW_BLOB },
+       { 'f',          REQ_VIEW_BLOB },
        { 'p',          REQ_VIEW_PAGER },
        { 'h',          REQ_VIEW_HELP },
 
@@ -1186,7 +1192,7 @@ struct view {
 
        /* Searching */
        char grep[SIZEOF_STR];  /* Search string */
-       regex_t regex;          /* Pre-compiled regex */
+       regex_t *regex;         /* Pre-compiled regex */
 
        /* If non-NULL, points to the view that opened this view. If this view
         * is closed tig will switch back to the parent view. */
@@ -1674,17 +1680,21 @@ search_view(struct view *view, enum request request, const char *search)
 {
        int regex_err;
 
-       if (*view->grep) {
-               regfree(&view->regex);
+       if (view->regex) {
+               regfree(view->regex);
                *view->grep = 0;
+       } else {
+               view->regex = calloc(1, sizeof(*view->regex));
+               if (!view->regex)
+                       return;
        }
 
-       regex_err = regcomp(&view->regex, search, REG_EXTENDED);
+       regex_err = regcomp(view->regex, search, REG_EXTENDED);
        if (regex_err != 0) {
                char buf[SIZEOF_STR] = "unknown error";
 
-               regerror(regex_err, &view->regex, buf, sizeof(buf));
-               report("Search failed: %s", buf);;
+               regerror(regex_err, view->regex, buf, sizeof(buf));
+               report("Search failed: %s", buf);
                return;
        }
 
@@ -1731,8 +1741,7 @@ begin_update(struct view *view)
                if (strcmp(view->vid, view->id))
                        opt_path[0] = 0;
 
-               if (snprintf(view->cmd, sizeof(view->cmd), format, id, opt_path)
-                   >= sizeof(view->cmd))
+               if (!string_format(view->cmd, format, id, opt_path))
                        return FALSE;
 
        } else {
@@ -2205,8 +2214,7 @@ pager_draw(struct view *view, struct line *line, unsigned int lineno)
                        string_copy(ref_commit, view->ref);
 
                } else if (type == LINE_TREE_DIR || type == LINE_TREE_FILE) {
-                       strncpy(view->ref, text + STRING_SIZE("100644 blob "), 41);
-                       view->ref[40] = 0;
+                       string_ncopy(view->ref, text + STRING_SIZE("100644 blob "), 40);
                        string_copy(ref_blob, view->ref);
                }
 
@@ -2329,10 +2337,14 @@ add_pager_refs(struct view *view, struct line *line)
 
        if (!is_tag && view == VIEW(REQ_VIEW_DIFF)) {
 try_add_describe_ref:
+               /* Add <tag>-g<commit_id> "fake" reference. */
                if (!add_describe_ref(buf, &bufpos, commit_id, sep))
                        return;
        }
 
+       if (bufpos == 0)
+               return;
+
        if (!realloc_lines(view, view->line_size + 1))
                return;
 
@@ -2400,7 +2412,7 @@ pager_grep(struct view *view, struct line *line)
        if (!*text)
                return FALSE;
 
-       if (regexec(&view->regex, text, 1, &pmatch, 0) == REG_NOMATCH)
+       if (regexec(view->regex, text, 1, &pmatch, 0) == REG_NOMATCH)
                return FALSE;
 
        return TRUE;
@@ -2452,6 +2464,7 @@ tree_read(struct view *view, char *text)
        char buf[SIZEOF_STR];
        unsigned long pos;
        enum line_type type;
+       bool first_read = view->lines == 0;
 
        if (textlen <= SIZEOF_TREE_ATTR)
                return FALSE;
@@ -2459,10 +2472,9 @@ tree_read(struct view *view, char *text)
        type = text[STRING_SIZE("100644 ")] == 't'
             ? LINE_TREE_DIR : LINE_TREE_FILE;
 
-       /* The first time around ... */
-       if (!view->lines) {
+       if (first_read) {
                /* Add path info line */
-               if (snprintf(buf, sizeof(buf), "Directory path /%s", opt_path) < sizeof(buf) &&
+               if (string_format(buf, "Directory path /%s", opt_path) &&
                    realloc_lines(view, view->line_size + 1) &&
                    pager_read(view, buf))
                        view->line[view->lines - 1].type = LINE_DEFAULT;
@@ -2471,7 +2483,7 @@ tree_read(struct view *view, char *text)
 
                /* Insert "link" to parent directory. */
                if (*opt_path &&
-                   snprintf(buf, sizeof(buf), TREE_UP_FORMAT, view->ref) < sizeof(buf) &&
+                   string_format(buf, TREE_UP_FORMAT, view->ref) &&
                    realloc_lines(view, view->line_size + 1) &&
                    pager_read(view, buf))
                        view->line[view->lines - 1].type = LINE_TREE_DIR;
@@ -2518,6 +2530,10 @@ tree_read(struct view *view, char *text)
        if (!pager_read(view, text))
                return FALSE;
 
+       /* Move the current line to the first tree entry. */
+       if (first_read)
+               view->lineno++;
+
        view->line[view->lines - 1].type = type;
        return TRUE;
 }
@@ -2544,9 +2560,13 @@ tree_enter(struct view *view, struct line *line)
 
                } else {
                        size_t pathlen = strlen(opt_path);
+                       size_t origlen = pathlen;
                        char *basename = data + SIZEOF_TREE_ATTR;
 
-                       string_format_from(opt_path, &pathlen, "%s/", basename);
+                       if (!string_format_from(opt_path, &pathlen, "%s/", basename)) {
+                               opt_path[origlen] = 0;
+                               return TRUE;
+                       }
                }
 
                /* Trees and subtrees share the same ID, so they are not not
@@ -2868,7 +2888,7 @@ main_grep(struct view *view, struct line *line)
                        return FALSE;
                }
 
-               if (regexec(&view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
+               if (regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
                        return TRUE;
        }
 
@@ -3416,7 +3436,7 @@ main(int argc, char *argv[])
 
        if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
                opt_iconv = iconv_open(opt_codeset, opt_encoding);
-               if (opt_iconv == (iconv_t) -1)
+               if (opt_iconv == ICONV_NONE)
                        die("Failed to initialize character set conversion");
        }