Replace all read_fd use with strbuf_read, and get rid of it.
[gitweb.git] / fast-import.c
index 71b89e2036eeacf265af470a76706add51f073d2..2c0bfb9fabb114305df2bbe6fc6b15284197951d 100644 (file)
@@ -269,6 +269,13 @@ typedef enum {
        WHENSPEC_NOW,
 } whenspec_type;
 
+struct recent_command
+{
+       struct recent_command *prev;
+       struct recent_command *next;
+       char *buf;
+};
+
 /* Configured limits on output */
 static unsigned long max_depth = 10;
 static off_t max_packsize = (1LL << 32) - 1;
@@ -333,8 +340,12 @@ static struct tag *last_tag;
 
 /* Input stream parsing */
 static whenspec_type whenspec = WHENSPEC_RAW;
-static struct strbuf command_buf;
+static struct strbuf command_buf = STRBUF_INIT;
 static int unread_command_buf;
+static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
+static struct recent_command *cmd_tail = &cmd_hist;
+static struct recent_command *rc_free;
+static unsigned int cmd_save = 100;
 static uintmax_t next_mark;
 static struct dbuf new_data;
 
@@ -364,12 +375,13 @@ static void write_branch_report(FILE *rpt, struct branch *b)
        fputc('\n', rpt);
 }
 
-static void write_crash_report(const char *err, va_list params)
+static void write_crash_report(const char *err)
 {
        char *loc = git_path("fast_import_crash_%d", getpid());
        FILE *rpt = fopen(loc, "w");
        struct branch *b;
        unsigned long lu;
+       struct recent_command *rc;
 
        if (!rpt) {
                error("can't write crash report %s: %s", loc, strerror(errno));
@@ -385,9 +397,21 @@ static void write_crash_report(const char *err, va_list params)
        fputc('\n', rpt);
 
        fputs("fatal: ", rpt);
-       vfprintf(rpt, err, params);
+       fputs(err, rpt);
        fputc('\n', rpt);
 
+       fputc('\n', rpt);
+       fputs("Most Recent Commands Before Crash\n", rpt);
+       fputs("---------------------------------\n", rpt);
+       for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
+               if (rc->next == &cmd_hist)
+                       fputs("* ", rpt);
+               else
+                       fputs("  ", rpt);
+               fputs(rc->buf, rpt);
+               fputc('\n', rpt);
+       }
+
        fputc('\n', rpt);
        fputs("Active Branch LRU\n", rpt);
        fputs("-----------------\n", rpt);
@@ -418,16 +442,17 @@ static void write_crash_report(const char *err, va_list params)
 static NORETURN void die_nicely(const char *err, va_list params)
 {
        static int zombie;
+       char message[2 * PATH_MAX];
 
+       vsnprintf(message, sizeof(message), err, params);
        fputs("fatal: ", stderr);
-       vfprintf(stderr, err, params);
+       fputs(message, stderr);
        fputc('\n', stderr);
 
        if (!zombie) {
                zombie = 1;
-               write_crash_report(err, params);
+               write_crash_report(message);
        }
-
        exit(128);
 }
 
@@ -1563,14 +1588,38 @@ static void dump_marks(void)
 static void read_next_command(void)
 {
        do {
-               if (unread_command_buf)
+               if (unread_command_buf) {
                        unread_command_buf = 0;
-               else
+                       if (command_buf.eof)
+                               return;
+               } else {
+                       struct recent_command *rc;
+
+                       strbuf_detach(&command_buf);
                        read_line(&command_buf, stdin, '\n');
-       } while (!command_buf.eof && command_buf.buf[0] == '#');
+                       if (command_buf.eof)
+                               return;
+
+                       rc = rc_free;
+                       if (rc)
+                               rc_free = rc->next;
+                       else {
+                               rc = cmd_hist.next;
+                               cmd_hist.next = rc->next;
+                               cmd_hist.next->prev = &cmd_hist;
+                               free(rc->buf);
+                       }
+
+                       rc->buf = command_buf.buf;
+                       rc->prev = cmd_tail;
+                       rc->next = cmd_hist.prev;
+                       rc->prev->next = rc;
+                       cmd_tail = rc;
+               }
+       } while (command_buf.buf[0] == '#');
 }
 
-static void skip_optional_lf()
+static void skip_optional_lf(void)
 {
        int term_char = fgetc(stdin);
        if (term_char != '\n' && term_char != EOF)
@@ -1589,17 +1638,16 @@ static void cmd_mark(void)
 
 static void *cmd_data (size_t *size)
 {
-       size_t length;
-       char *buffer;
+       struct strbuf buffer;
 
+       strbuf_init(&buffer, 0);
        if (prefixcmp(command_buf.buf, "data "))
                die("Expected 'data n' command, found: %s", command_buf.buf);
 
        if (!prefixcmp(command_buf.buf + 5, "<<")) {
                char *term = xstrdup(command_buf.buf + 5 + 2);
-               size_t sz = 8192, term_len = command_buf.len - 5 - 2;
-               length = 0;
-               buffer = xmalloc(sz);
+               size_t term_len = command_buf.len - 5 - 2;
+
                for (;;) {
                        read_line(&command_buf, stdin, '\n');
                        if (command_buf.eof)
@@ -1607,21 +1655,18 @@ static void *cmd_data (size_t *size)
                        if (term_len == command_buf.len
                                && !strcmp(term, command_buf.buf))
                                break;
-                       ALLOC_GROW(buffer, length + command_buf.len, sz);
-                       memcpy(buffer + length,
-                               command_buf.buf,
-                               command_buf.len - 1);
-                       length += command_buf.len - 1;
-                       buffer[length++] = '\n';
+                       strbuf_addbuf(&buffer, &command_buf);
+                       strbuf_addch(&buffer, '\n');
                }
                free(term);
        }
        else {
-               size_t n = 0;
+               size_t n = 0, length;
+
                length = strtoul(command_buf.buf + 5, NULL, 10);
-               buffer = xmalloc(length);
+
                while (n < length) {
-                       size_t s = fread(buffer + n, 1, length - n, stdin);
+                       size_t s = strbuf_fread(&buffer, length - n, stdin);
                        if (!s && feof(stdin))
                                die("EOF in data (%lu bytes remaining)",
                                        (unsigned long)(length - n));
@@ -1630,8 +1675,8 @@ static void *cmd_data (size_t *size)
        }
 
        skip_optional_lf();
-       *size = length;
-       return buffer;
+       *size = buffer.len;
+       return strbuf_detach(&buffer);
 }
 
 static int validate_raw_date(const char *src, char *result, int maxlen)
@@ -2051,7 +2096,7 @@ static void cmd_new_commit(void)
        }
 
        /* file_change* */
-       while (!command_buf.eof && command_buf.len > 1) {
+       while (!command_buf.eof && command_buf.len > 0) {
                if (!prefixcmp(command_buf.buf, "M "))
                        file_change_m(b);
                else if (!prefixcmp(command_buf.buf, "D "))
@@ -2206,7 +2251,7 @@ static void cmd_reset_branch(void)
        else
                b = new_branch(sp);
        read_next_command();
-       if (!cmd_from(b) && command_buf.len > 1)
+       if (!cmd_from(b) && command_buf.len > 0)
                unread_command_buf = 1;
 }
 
@@ -2223,7 +2268,7 @@ static void cmd_checkpoint(void)
 
 static void cmd_progress(void)
 {
-       fwrite(command_buf.buf, 1, command_buf.len - 1, stdout);
+       fwrite(command_buf.buf, 1, command_buf.len, stdout);
        fputc('\n', stdout);
        fflush(stdout);
        skip_optional_lf();
@@ -2269,11 +2314,11 @@ static const char fast_import_usage[] =
 
 int main(int argc, const char **argv)
 {
-       int i, show_stats = 1;
+       unsigned int i, show_stats = 1;
 
        git_config(git_default_config);
        alloc_objects(object_entry_alloc);
-       strbuf_init(&command_buf);
+       strbuf_init(&command_buf, 0);
        atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
        branch_table = xcalloc(branch_table_sz, sizeof(struct branch*));
        avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));
@@ -2323,6 +2368,11 @@ int main(int argc, const char **argv)
        if (i != argc)
                usage(fast_import_usage);
 
+       rc_free = pool_alloc(cmd_save * sizeof(*rc_free));
+       for (i = 0; i < (cmd_save - 1); i++)
+               rc_free[i].next = &rc_free[i + 1];
+       rc_free[cmd_save - 1].next = NULL;
+
        prepare_packed_git();
        start_packfile();
        set_die_routine(die_nicely);