Code

Add missing NULL in blame_grep
[tig.git] / tig.c
diff --git a/tig.c b/tig.c
index 725ace02579782ab55d4b511cfd89c8c8fc2f19d..2a3ab3afc1f1f3b292cec1a8f5c2b7f76cdfae2b 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -161,6 +161,27 @@ typedef enum input_status (*input_handler)(void *data, char *buf, int c);
 static char *prompt_input(const char *prompt, input_handler handler, void *data);
 static bool prompt_yesno(const char *prompt);
 
+/*
+ * Allocation helpers ... Entering macro hell to never be seen again.
+ */
+
+#define DEFINE_ALLOCATOR(name, type, chunk_size)                               \
+static type *                                                                  \
+name(type **mem, size_t size, size_t increase)                                 \
+{                                                                              \
+       size_t num_chunks = (size + chunk_size - 1) / chunk_size;               \
+       size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
+       type *tmp = *mem;                                                       \
+                                                                               \
+       if (mem == NULL || num_chunks != num_chunks_new) {                      \
+               tmp = realloc(tmp, num_chunks_new * chunk_size * sizeof(type)); \
+               if (tmp)                                                        \
+                       *mem = tmp;                                             \
+       }                                                                       \
+                                                                               \
+       return tmp;                                                             \
+}
+
 /*
  * String helpers
  */
@@ -309,6 +330,17 @@ suffixcmp(const char *str, int slen, const char *suffix)
 }
 
 
+static const char *
+mkdate(const time_t *time)
+{
+       static char buf[DATE_COLS + 1];
+       struct tm tm;
+
+       gmtime_r(time, &tm);
+       return strftime(buf, sizeof(buf), DATE_FORMAT, &tm) ? buf : NULL;
+}
+
+
 static bool
 argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
 {
@@ -594,20 +626,14 @@ io_read(struct io *io, void *buf, size_t bufsize)
        } while (1);
 }
 
+DEFINE_ALLOCATOR(realloc_io_buf, char, BUFSIZ)
+
 static char *
 io_get(struct io *io, int c, bool can_read)
 {
        char *eol;
        ssize_t readsize;
 
-       if (!io->buf) {
-               io->buf = io->bufpos = malloc(BUFSIZ);
-               if (!io->buf)
-                       return NULL;
-               io->bufalloc = BUFSIZ;
-               io->bufsize = 0;
-       }
-
        while (TRUE) {
                if (io->bufsize > 0) {
                        eol = memchr(io->bufpos, c, io->bufsize);
@@ -636,6 +662,12 @@ io_get(struct io *io, int c, bool can_read)
                if (io->bufsize > 0 && io->bufpos > io->buf)
                        memmove(io->buf, io->bufpos, io->bufsize);
 
+               if (io->bufalloc == io->bufsize) {
+                       if (!realloc_io_buf(&io->buf, io->bufalloc, BUFSIZ))
+                               return NULL;
+                       io->bufalloc += BUFSIZ;
+               }
+
                io->bufpos = io->buf;
                readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
                if (io_error(io))
@@ -667,14 +699,14 @@ io_write(struct io *io, const void *buf, size_t bufsize)
 static bool
 io_read_buf(struct io *io, char buf[], size_t bufsize)
 {
-       bool error;
+       char *result = io_get(io, '\n', TRUE);
 
-       io->buf = io->bufpos = buf;
-       io->bufalloc = bufsize;
-       error = !io_get(io, '\n', TRUE) && io_error(io);
-       io->buf = NULL;
+       if (result) {
+               result = chomp_string(result);
+               string_ncopy_do(buf, bufsize, result, strlen(result));
+       }
 
-       return done_io(io) || error;
+       return done_io(io) && result;
 }
 
 static bool
@@ -1293,6 +1325,8 @@ struct run_request {
 static struct run_request *run_request;
 static size_t run_requests;
 
+DEFINE_ALLOCATOR(realloc_run_requests, struct run_request, 8)
+
 static enum request
 add_run_request(enum keymap keymap, int key, int argc, const char **argv)
 {
@@ -1301,11 +1335,9 @@ add_run_request(enum keymap keymap, int key, int argc, const char **argv)
        if (argc >= ARRAY_SIZE(req->argv) - 1)
                return REQ_NONE;
 
-       req = realloc(run_request, (run_requests + 1) * sizeof(*run_request));
-       if (!req)
+       if (!realloc_run_requests(&run_request, run_requests, 1))
                return REQ_NONE;
 
-       run_request = req;
        req = &run_request[run_requests];
        req->keymap = keymap;
        req->key = key;
@@ -1763,7 +1795,6 @@ struct view {
        /* Buffering */
        size_t lines;           /* Total number of lines */
        struct line *line;      /* Line index */
-       size_t line_alloc;      /* Total number of allocated lines */
        unsigned int digits;    /* Number of digits in the lines member. */
 
        /* Drawing */
@@ -1960,15 +1991,9 @@ draw_field(struct view *view, enum line_type type, const char *text, int len, bo
 }
 
 static bool
-draw_date(struct view *view, struct tm *time)
+draw_date(struct view *view, time_t *time)
 {
-       char buf[DATE_COLS];
-       char *date;
-       int timelen = 0;
-
-       if (time)
-               timelen = strftime(buf, sizeof(buf), DATE_FORMAT, time);
-       date = timelen ? buf : NULL;
+       const char *date = mkdate(time);
 
        return draw_field(view, LINE_DATE, date, DATE_COLS, FALSE);
 }
@@ -2032,9 +2057,7 @@ draw_lineno(struct view *view, unsigned int lineno)
        if (lineno == 1 || (lineno % opt_num_interval) == 0) {
                static char fmt[] = "%1ld";
 
-               if (view->digits <= 9)
-                       fmt[1] = '0' + digits3;
-
+               fmt[1] = '0' + (view->digits <= 9 ? digits3 : 1);
                if (string_format(number, fmt, lineno))
                        text = number;
        }
@@ -2499,6 +2522,19 @@ move_view(struct view *view, enum request request)
 
 static void search_view(struct view *view, enum request request);
 
+static bool
+grep_text(struct view *view, const char *text[])
+{
+       regmatch_t pmatch;
+       size_t i;
+
+       for (i = 0; text[i]; i++)
+               if (*text[i] &&
+                   regexec(view->regex, text[i], 1, &pmatch, 0) != REG_NOMATCH)
+                       return TRUE;
+       return FALSE;
+}
+
 static void
 select_view_line(struct view *view, unsigned long lineno)
 {
@@ -2615,7 +2651,6 @@ reset_view(struct view *view)
        view->yoffset = 0;
        view->lines  = 0;
        view->lineno = 0;
-       view->line_alloc = 0;
        view->vid[0] = 0;
        view->update_secs = 0;
 }
@@ -2786,36 +2821,6 @@ begin_update(struct view *view, bool refresh)
        return TRUE;
 }
 
-#define ITEM_CHUNK_SIZE 256
-static void *
-realloc_items(void *mem, size_t *size, size_t new_size, size_t item_size)
-{
-       size_t num_chunks = *size / ITEM_CHUNK_SIZE;
-       size_t num_chunks_new = (new_size + ITEM_CHUNK_SIZE - 1) / ITEM_CHUNK_SIZE;
-
-       if (mem == NULL || num_chunks != num_chunks_new) {
-               *size = num_chunks_new * ITEM_CHUNK_SIZE;
-               mem = realloc(mem, *size * item_size);
-       }
-
-       return mem;
-}
-
-static struct line *
-realloc_lines(struct view *view, size_t line_size)
-{
-       size_t alloc = view->line_alloc;
-       struct line *tmp = realloc_items(view->line, &alloc, line_size,
-                                        sizeof(*view->line));
-
-       if (!tmp)
-               return NULL;
-
-       view->line = tmp;
-       view->line_alloc = alloc;
-       return view->line;
-}
-
 static bool
 update_view(struct view *view)
 {
@@ -2906,12 +2911,14 @@ update_view(struct view *view)
        return TRUE;
 }
 
+DEFINE_ALLOCATOR(realloc_lines, struct line, 256)
+
 static struct line *
 add_line_data(struct view *view, void *data, enum line_type type)
 {
        struct line *line;
 
-       if (!realloc_lines(view, view->lines + 1))
+       if (!realloc_lines(&view->line, view->lines, 1))
                return NULL;
 
        line = &view->line[view->lines++];
@@ -3103,10 +3110,8 @@ view_driver(struct view *view, enum request request)
 {
        int i;
 
-       if (request == REQ_NONE) {
-               doupdate();
+       if (request == REQ_NONE)
                return TRUE;
-       }
 
        if (request > REQ_NONE) {
                open_run_request(request);
@@ -3332,6 +3337,44 @@ view_driver(struct view *view, enum request request)
  * View backend utilities
  */
 
+DEFINE_ALLOCATOR(realloc_authors, const char *, 256)
+
+/* Small author cache to reduce memory consumption. It uses binary
+ * search to lookup or find place to position new entries. No entries
+ * are ever freed. */
+static const char *
+get_author(const char *name)
+{
+       static const char **authors;
+       static size_t authors_size;
+       int from = 0, to = authors_size - 1;
+
+       while (from <= to) {
+               size_t pos = (to + from) / 2;
+               int cmp = strcmp(name, authors[pos]);
+
+               if (!cmp)
+                       return authors[pos];
+
+               if (cmp < 0)
+                       to = pos - 1;
+               else
+                       from = pos + 1;
+       }
+
+       if (!realloc_authors(&authors, authors_size, 1))
+               return NULL;
+       name = strdup(name);
+       if (!name)
+               return NULL;
+
+       memmove(authors + from + 1, authors + from, (authors_size - from) * sizeof(*authors));
+       authors[from] = name;
+       authors_size++;
+
+       return name;
+}
+
 static void
 parse_timezone(time_t *time, const char *zone)
 {
@@ -3352,7 +3395,7 @@ parse_timezone(time_t *time, const char *zone)
  *     author  <email@address.tld> 1138474660 +0100
  */
 static void
-parse_author_line(char *ident, char *author, size_t authorsize, struct tm *tm)
+parse_author_line(char *ident, const char **author, time_t *time)
 {
        char *nameend = strchr(ident, '<');
        char *emailend = strchr(ident, '>');
@@ -3367,18 +3410,17 @@ parse_author_line(char *ident, char *author, size_t authorsize, struct tm *tm)
                        ident = "Unknown";
        }
 
-       string_ncopy_do(author, authorsize, ident, strlen(ident));
+       *author = get_author(ident);
 
        /* Parse epoch and timezone */
        if (emailend && emailend[1] == ' ') {
                char *secs = emailend + 2;
                char *zone = strchr(secs, ' ');
-               time_t time = (time_t) atol(secs);
 
-               if (zone && strlen(zone) == STRING_SIZE(" +0700"))
-                       parse_timezone(&time, zone + 1);
+               *time = (time_t) atol(secs);
 
-               gmtime_r(&time, tm);
+               if (zone && strlen(zone) == STRING_SIZE(" +0700"))
+                       parse_timezone(time, zone + 1);
        }
 }
 
@@ -3410,7 +3452,6 @@ select_commit_parent(const char *id, char rev[SIZEOF_REV], const char *path)
        int parents;
 
        if (!run_io_buf(revlist_argv, buf, sizeof(buf)) ||
-           !*chomp_string(buf) ||
            (parents = (strlen(buf) / 40) - 1) < 0) {
                report("Failed to get parent information");
                return FALSE;
@@ -3460,13 +3501,9 @@ static bool
 add_describe_ref(char *buf, size_t *bufpos, const char *commit_id, const char *sep)
 {
        const char *describe_argv[] = { "git", "describe", commit_id, NULL };
-       char refbuf[SIZEOF_STR];
-       char *ref = NULL;
+       char ref[SIZEOF_STR];
 
-       if (run_io_buf(describe_argv, refbuf, sizeof(refbuf)))
-               ref = chomp_string(refbuf);
-
-       if (!ref || !*ref)
+       if (!run_io_buf(describe_argv, ref, sizeof(ref)) || !*ref)
                return TRUE;
 
        /* This is the only fatal call, since it can "corrupt" the buffer. */
@@ -3572,16 +3609,9 @@ pager_request(struct view *view, enum request request, struct line *line)
 static bool
 pager_grep(struct view *view, struct line *line)
 {
-       regmatch_t pmatch;
-       char *text = line->data;
-
-       if (!*text)
-               return FALSE;
-
-       if (regexec(view->regex, text, 1, &pmatch, 0) == REG_NOMATCH)
-               return FALSE;
+       const char *text[] = { line->data, NULL };
 
-       return TRUE;
+       return grep_text(view, text);
 }
 
 static void
@@ -3799,8 +3829,8 @@ push_tree_stack_entry(const char *name, unsigned long lineno)
 struct tree_entry {
        char id[SIZEOF_REV];
        mode_t mode;
-       struct tm time;                 /* Date from the author ident. */
-       char author[75];                /* Author of the commit. */
+       time_t time;                    /* Date from the author ident. */
+       const char *author;             /* Author of the commit. */
        char name[1];
 };
 
@@ -3843,8 +3873,8 @@ tree_entry(struct view *view, enum line_type type, const char *path,
 static bool
 tree_read_date(struct view *view, char *text, bool *read_date)
 {
-       static char author_name[SIZEOF_STR];
-       static struct tm author_time;
+       static const char *author_name;
+       static time_t author_time;
 
        if (!text && *read_date) {
                *read_date = FALSE;
@@ -3877,7 +3907,7 @@ tree_read_date(struct view *view, char *text, bool *read_date)
 
        } else if (*text == 'a' && get_line_type(text) == LINE_AUTHOR) {
                parse_author_line(text + STRING_SIZE("author "),
-                                 author_name, sizeof(author_name), &author_time);
+                                 &author_name, &author_time);
 
        } else if (*text == ':') {
                char *pos;
@@ -3900,12 +3930,12 @@ tree_read_date(struct view *view, char *text, bool *read_date)
                        struct line *line = &view->line[i];
                        struct tree_entry *entry = line->data;
 
-                       annotated += !!*entry->author;
-                       if (*entry->author || strcmp(entry->name, text))
+                       annotated += !!entry->author;
+                       if (entry->author || strcmp(entry->name, text))
                                continue;
 
-                       string_copy(entry->author, author_name);
-                       memcpy(&entry->time, &author_time, sizeof(entry->time));
+                       entry->author = author_name;
+                       entry->time = author_time;
                        line->dirty = 1;
                        break;
                }
@@ -3993,7 +4023,7 @@ tree_draw(struct view *view, struct line *line, unsigned int lineno)
                if (opt_author && draw_author(view, entry->author))
                        return TRUE;
 
-               if (opt_date && draw_date(view, *entry->author ? &entry->time : NULL))
+               if (opt_date && draw_date(view, entry->author ? &entry->time : NULL))
                        return TRUE;
        }
        if (draw_text(view, line->type, entry->name, TRUE))
@@ -4097,6 +4127,20 @@ tree_request(struct view *view, enum request request, struct line *line)
        return REQ_NONE;
 }
 
+static bool
+tree_grep(struct view *view, struct line *line)
+{
+       struct tree_entry *entry = line->data;
+       const char *text[] = {
+               entry->name,
+               opt_author ? entry->author : "",
+               opt_date ? mkdate(&entry->time) : "",
+               NULL
+       };
+
+       return grep_text(view, text);
+}
+
 static void
 tree_select(struct view *view, struct line *line)
 {
@@ -4124,7 +4168,7 @@ static struct view_ops tree_ops = {
        tree_read,
        tree_draw,
        tree_request,
-       pager_grep,
+       tree_grep,
        tree_select,
 };
 
@@ -4189,8 +4233,8 @@ static const char *blame_cat_file_argv[] = {
 struct blame_commit {
        char id[SIZEOF_REV];            /* SHA1 ID. */
        char title[128];                /* First line of the commit message. */
-       char author[75];                /* Author of the commit. */
-       struct tm time;                 /* Date from the author ident. */
+       const char *author;             /* Author of the commit. */
+       time_t time;                    /* Date from the author ident. */
        char filename[128];             /* Name of file. */
        bool has_previous;              /* Was a "previous" line detected. */
 };
@@ -4342,7 +4386,6 @@ blame_read(struct view *view, char *line)
 {
        static struct blame_commit *commit = NULL;
        static int blamed = 0;
-       static time_t author_time;
        static bool read_file = TRUE;
 
        if (read_file)
@@ -4367,14 +4410,13 @@ blame_read(struct view *view, char *line)
                              view->lines ? blamed * 100 / view->lines : 0);
 
        } else if (match_blame_header("author ", &line)) {
-               string_ncopy(commit->author, line, strlen(line));
+               commit->author = get_author(line);
 
        } else if (match_blame_header("author-time ", &line)) {
-               author_time = (time_t) atol(line);
+               commit->time = (time_t) atol(line);
 
        } else if (match_blame_header("author-tz ", &line)) {
-               parse_timezone(&author_time, line);
-               gmtime_r(&author_time, &commit->time);
+               parse_timezone(&commit->time, line);
 
        } else if (match_blame_header("summary ", &line)) {
                string_ncopy(commit->title, line, strlen(line));
@@ -4394,7 +4436,7 @@ static bool
 blame_draw(struct view *view, struct line *line, unsigned int lineno)
 {
        struct blame *blame = line->data;
-       struct tm *time = NULL;
+       time_t *time = NULL;
        const char *id = NULL, *author = NULL;
        char text[SIZEOF_STR];
 
@@ -4542,27 +4584,16 @@ blame_grep(struct view *view, struct line *line)
 {
        struct blame *blame = line->data;
        struct blame_commit *commit = blame->commit;
-       regmatch_t pmatch;
-
-#define MATCH(text, on)                                                        \
-       (on && *text && regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
-
-       if (commit) {
-               char buf[DATE_COLS + 1];
-
-               if (MATCH(commit->title, 1) ||
-                   MATCH(commit->author, opt_author) ||
-                   MATCH(commit->id, opt_date))
-                       return TRUE;
-
-               if (strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time) &&
-                   MATCH(buf, 1))
-                       return TRUE;
-       }
-
-       return MATCH(blame->text, 1);
+       const char *text[] = {
+               blame->text,
+               commit ? commit->title : "",
+               commit ? commit->id : "",
+               commit && opt_author ? commit->author : "",
+               commit && opt_date ? mkdate(&commit->time) : "",
+               NULL
+       };
 
-#undef MATCH
+       return grep_text(view, text);
 }
 
 static void
@@ -4615,6 +4646,8 @@ static enum line_type stage_line_type;
 static size_t stage_chunks;
 static int *stage_chunk;
 
+DEFINE_ALLOCATOR(realloc_ints, int, 32)
+
 /* This should work even for the "On branch" line. */
 static inline bool
 status_has_none(struct view *view, struct line *line)
@@ -4815,7 +4848,7 @@ status_update_onbranch(void)
                        if (string_format(buf, "%s/rebase-merge/head-name", opt_git_dir) &&
                            io_open(&io, buf) &&
                            io_read_buf(&io, buf, sizeof(buf))) {
-                               head = chomp_string(buf);
+                               head = buf;
                                if (!prefixcmp(head, "refs/heads/"))
                                        head += STRING_SIZE("refs/heads/");
                        }
@@ -5122,6 +5155,7 @@ status_update_files(struct view *view, struct line *line)
        struct line *pos = view->line + view->lines;
        int files = 0;
        int file, done;
+       int cursor_y, cursor_x;
 
        if (!status_update_prepare(&io, line->type))
                return FALSE;
@@ -5130,6 +5164,7 @@ status_update_files(struct view *view, struct line *line)
                files++;
 
        string_copy(buf, view->ref);
+       getsyx(cursor_y, cursor_x);
        for (file = 0, done = 5; result && file < files; line++, file++) {
                int almost_done = file * 100 / files;
 
@@ -5138,6 +5173,7 @@ status_update_files(struct view *view, struct line *line)
                        string_format(view->ref, "updating file %u of %u (%d%% done)",
                                      file, files, done);
                        update_view_title(view);
+                       setsyx(cursor_y, cursor_x);
                        doupdate();
                }
                result = status_update_write(&io, line->data, line->type);
@@ -5319,29 +5355,12 @@ static bool
 status_grep(struct view *view, struct line *line)
 {
        struct status *status = line->data;
-       enum { S_STATUS, S_NAME, S_END } state;
-       char buf[2] = "?";
-       regmatch_t pmatch;
-
-       if (!status)
-               return FALSE;
-
-       for (state = S_STATUS; state < S_END; state++) {
-               const char *text;
-
-               switch (state) {
-               case S_NAME:    text = status->new.name;        break;
-               case S_STATUS:
-                       buf[0] = status->status;
-                       text = buf;
-                       break;
 
-               default:
-                       return FALSE;
-               }
+       if (status) {
+               const char buf[2] = { status->status, 0 };
+               const char *text[] = { status->new.name, buf, NULL };
 
-               if (regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
-                       return TRUE;
+               return grep_text(view, text);
        }
 
        return FALSE;
@@ -5483,21 +5502,15 @@ stage_next(struct view *view, struct line *line)
        int i;
 
        if (!stage_chunks) {
-               static size_t alloc = 0;
-               int *tmp;
-
                for (line = view->line; line < view->line + view->lines; line++) {
                        if (line->type != LINE_DIFF_CHUNK)
                                continue;
 
-                       tmp = realloc_items(stage_chunk, &alloc,
-                                           stage_chunks, sizeof(*tmp));
-                       if (!tmp) {
+                       if (!realloc_ints(&stage_chunk, stage_chunks, 1)) {
                                report("Allocation failure");
                                return;
                        }
 
-                       stage_chunk = tmp;
                        stage_chunk[stage_chunks++] = line - view->line;
                }
        }
@@ -5610,8 +5623,8 @@ static struct view_ops stage_ops = {
 struct commit {
        char id[SIZEOF_REV];            /* SHA1 ID. */
        char title[128];                /* First line of the commit message. */
-       char author[75];                /* Author of the commit. */
-       struct tm time;                 /* Date from the author ident. */
+       const char *author;             /* Author of the commit. */
+       time_t time;                    /* Date from the author ident. */
        struct ref **refs;              /* Repository references. */
        chtype graph[SIZEOF_REVGRAPH];  /* Ancestry chain graphics. */
        size_t graph_size;              /* The width of the graph array. */
@@ -5837,7 +5850,7 @@ main_draw(struct view *view, struct line *line, unsigned int lineno)
 {
        struct commit *commit = line->data;
 
-       if (!*commit->author)
+       if (!commit->author)
                return FALSE;
 
        if (opt_date && draw_date(view, &commit->time))
@@ -5899,7 +5912,7 @@ main_read(struct view *view, char *line)
                if (view->lines > 0) {
                        commit = view->line[view->lines - 1].data;
                        view->line[view->lines - 1].dirty = 1;
-                       if (!*commit->author) {
+                       if (!commit->author) {
                                view->lines--;
                                free(commit);
                                graph->commit = NULL;
@@ -5950,8 +5963,7 @@ main_read(struct view *view, char *line)
 
        case LINE_AUTHOR:
                parse_author_line(line + STRING_SIZE("author "),
-                                 commit->author, sizeof(commit->author),
-                                 &commit->time);
+                                 &commit->author, &commit->time);
                update_rev_graph(view, graph);
                graph = graph->next;
                break;
@@ -6008,7 +6020,7 @@ grep_refs(struct ref **refs, regex_t *regex)
        regmatch_t pmatch;
        size_t i = 0;
 
-       if (!refs)
+       if (!opt_show_refs || !refs)
                return FALSE;
        do {
                if (regexec(regex, refs[i]->name, 1, &pmatch, 0) != REG_NOMATCH)
@@ -6022,42 +6034,14 @@ static bool
 main_grep(struct view *view, struct line *line)
 {
        struct commit *commit = line->data;
-       enum { S_TITLE, S_AUTHOR, S_DATE, S_REFS, S_END } state;
-       char buf[DATE_COLS + 1];
-       regmatch_t pmatch;
-
-       for (state = S_TITLE; state < S_END; state++) {
-               char *text;
-
-               switch (state) {
-               case S_TITLE:   text = commit->title;   break;
-               case S_AUTHOR:
-                       if (!opt_author)
-                               continue;
-                       text = commit->author;
-                       break;
-               case S_DATE:
-                       if (!opt_date)
-                               continue;
-                       if (!strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time))
-                               continue;
-                       text = buf;
-                       break;
-               case S_REFS:
-                       if (!opt_show_refs)
-                               continue;
-                       if (grep_refs(commit->refs, view->regex) == TRUE)
-                               return TRUE;
-                       continue;
-               default:
-                       return FALSE;
-               }
-
-               if (regexec(view->regex, text, 1, &pmatch, 0) != REG_NOMATCH)
-                       return TRUE;
-       }
+       const char *text[] = {
+               commit->title,
+               opt_author ? commit->author : "",
+               opt_date ? mkdate(&commit->time) : "",
+               NULL
+       };
 
-       return FALSE;
+       return grep_text(view, text) || grep_refs(commit->refs, view->regex);
 }
 
 static void
@@ -6528,14 +6512,16 @@ read_prompt(const char *prompt)
  */
 
 static struct ref *refs = NULL;
-static size_t refs_alloc = 0;
 static size_t refs_size = 0;
 
 /* Id <-> ref store */
 static struct ref ***id_refs = NULL;
-static size_t id_refs_alloc = 0;
 static size_t id_refs_size = 0;
 
+DEFINE_ALLOCATOR(realloc_refs, struct ref, 256)
+DEFINE_ALLOCATOR(realloc_refs_list, struct ref *, 8)
+DEFINE_ALLOCATOR(realloc_refs_lists, struct ref **, 8)
+
 static int
 compare_refs(const void *ref1_, const void *ref2_)
 {
@@ -6558,9 +6544,7 @@ compare_refs(const void *ref1_, const void *ref2_)
 static struct ref **
 get_refs(const char *id)
 {
-       struct ref ***tmp_id_refs;
        struct ref **ref_list = NULL;
-       size_t ref_list_alloc = 0;
        size_t ref_list_size = 0;
        size_t i;
 
@@ -6568,34 +6552,21 @@ get_refs(const char *id)
                if (!strcmp(id, id_refs[i][0]->id))
                        return id_refs[i];
 
-       tmp_id_refs = realloc_items(id_refs, &id_refs_alloc, id_refs_size + 1,
-                                   sizeof(*id_refs));
-       if (!tmp_id_refs)
+       if (!realloc_refs_lists(&id_refs, id_refs_size, 1))
                return NULL;
 
-       id_refs = tmp_id_refs;
-
        for (i = 0; i < refs_size; i++) {
-               struct ref **tmp;
-
                if (strcmp(id, refs[i].id))
                        continue;
 
-               tmp = realloc_items(ref_list, &ref_list_alloc,
-                                   ref_list_size + 1, sizeof(*ref_list));
-               if (!tmp) {
-                       if (ref_list)
-                               free(ref_list);
-                       return NULL;
-               }
+               if (!realloc_refs_list(&ref_list, ref_list_size, 1))
+                       return ref_list;
 
-               ref_list = tmp;
                ref_list[ref_list_size] = &refs[i];
                /* XXX: The properties of the commit chains ensures that we can
                 * safely modify the shared ref. The repo references will
                 * always be similar for the same id. */
                ref_list[ref_list_size]->next = 1;
-
                ref_list_size++;
        }
 
@@ -6659,8 +6630,8 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
 
                return OK;
        }
-       refs = realloc_items(refs, &refs_alloc, refs_size + 1, sizeof(*refs));
-       if (!refs)
+
+       if (!realloc_refs(&refs, refs_size, 1))
                return ERR;
 
        ref = &refs[refs_size++];
@@ -6683,6 +6654,9 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
 static int
 load_refs(void)
 {
+       const char *head_argv[] = {
+               "git", "symbolic-ref", "HEAD", NULL
+       };
        static const char *ls_remote_argv[SIZEOF_ARG] = {
                "git", "ls-remote", opt_git_dir, NULL
        };
@@ -6696,6 +6670,13 @@ load_refs(void)
        if (!*opt_git_dir)
                return OK;
 
+       if (run_io_buf(head_argv, opt_head, sizeof(opt_head)) &&
+           !prefixcmp(opt_head, "refs/heads/")) {
+               char *offset = opt_head + STRING_SIZE("refs/heads/");
+
+               memmove(opt_head, offset, strlen(offset) + 1);
+       }
+
        while (refs_size > 0)
                free(refs[--refs_size].name);
        while (id_refs_size > 0)
@@ -6838,23 +6819,11 @@ read_repo_info(char *name, size_t namelen, char *value, size_t valuelen)
 static int
 load_repo_info(void)
 {
-       const char *head_argv[] = {
-               "git", "symbolic-ref", "HEAD", NULL
-       };
        const char *rev_parse_argv[] = {
                "git", "rev-parse", "--git-dir", "--is-inside-work-tree",
                        "--show-cdup", "--show-prefix", NULL
        };
 
-       if (run_io_buf(head_argv, opt_head, sizeof(opt_head))) {
-               chomp_string(opt_head);
-               if (!prefixcmp(opt_head, "refs/heads/")) {
-                       char *offset = opt_head + STRING_SIZE("refs/heads/");
-
-                       memmove(opt_head, offset, strlen(offset) + 1);
-               }
-       }
-
        return run_io_load(rev_parse_argv, "=", read_repo_info);
 }