strbuf_setlen(): do not barf on setting length of an empty buffer to 0
[gitweb.git] / builtin-apply.c
index db337f1aca48d7f7ec8b5e3c4c9230621d346d81..01c9d60642d0faa9ea91d0d39b32985890e1ec7f 100644 (file)
@@ -163,15 +163,14 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
        fputs(pre, output);
        if (patch->old_name && patch->new_name &&
            strcmp(patch->old_name, patch->new_name)) {
-               write_name_quoted(NULL, 0, patch->old_name, 1, output);
+               quote_c_style(patch->old_name, NULL, output, 0);
                fputs(" => ", output);
-               write_name_quoted(NULL, 0, patch->new_name, 1, output);
-       }
-       else {
+               quote_c_style(patch->new_name, NULL, output, 0);
+       } else {
                const char *n = patch->new_name;
                if (!n)
                        n = patch->old_name;
-               write_name_quoted(NULL, 0, n, 1, output);
+               quote_c_style(n, NULL, output, 0);
        }
        fputs(post, output);
 }
@@ -231,35 +230,33 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
 {
        int len;
        const char *start = line;
-       char *name;
 
        if (*line == '"') {
+               struct strbuf name;
+
                /* Proposed "new-style" GNU patch/diff format; see
                 * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
                 */
-               name = unquote_c_style(line, NULL);
-               if (name) {
-                       char *cp = name;
-                       while (p_value) {
+               strbuf_init(&name, 0);
+               if (!unquote_c_style(&name, line, NULL)) {
+                       char *cp;
+
+                       for (cp = name.buf; p_value; p_value--) {
                                cp = strchr(cp, '/');
                                if (!cp)
                                        break;
                                cp++;
-                               p_value--;
                        }
                        if (cp) {
                                /* name can later be freed, so we need
                                 * to memmove, not just return cp
                                 */
-                               memmove(name, cp, strlen(cp) + 1);
+                               strbuf_remove(&name, 0, cp - name.buf);
                                free(def);
-                               return name;
-                       }
-                       else {
-                               free(name);
-                               name = NULL;
+                               return name.buf;
                        }
                }
+               strbuf_release(&name);
        }
 
        for (;;) {
@@ -567,29 +564,30 @@ static const char *stop_at_slash(const char *line, int llen)
  */
 static char *git_header_name(char *line, int llen)
 {
-       int len;
        const char *name;
        const char *second = NULL;
+       size_t len;
 
        line += strlen("diff --git ");
        llen -= strlen("diff --git ");
 
        if (*line == '"') {
                const char *cp;
-               char *first = unquote_c_style(line, &second);
-               if (!first)
-                       return NULL;
+               struct strbuf first;
+               struct strbuf sp;
+
+               strbuf_init(&first, 0);
+               strbuf_init(&sp, 0);
+
+               if (unquote_c_style(&first, line, &second))
+                       goto free_and_fail1;
 
                /* advance to the first slash */
-               cp = stop_at_slash(first, strlen(first));
-               if (!cp || cp == first) {
-                       /* we do not accept absolute paths */
-               free_first_and_fail:
-                       free(first);
-                       return NULL;
-               }
-               len = strlen(cp+1);
-               memmove(first, cp+1, len+1); /* including NUL */
+               cp = stop_at_slash(first.buf, first.len);
+               /* we do not accept absolute paths */
+               if (!cp || cp == first.buf)
+                       goto free_and_fail1;
+               strbuf_remove(&first, 0, cp + 1 - first.buf);
 
                /* second points at one past closing dq of name.
                 * find the second name.
@@ -598,40 +596,40 @@ static char *git_header_name(char *line, int llen)
                        second++;
 
                if (line + llen <= second)
-                       goto free_first_and_fail;
+                       goto free_and_fail1;
                if (*second == '"') {
-                       char *sp = unquote_c_style(second, NULL);
-                       if (!sp)
-                               goto free_first_and_fail;
-                       cp = stop_at_slash(sp, strlen(sp));
-                       if (!cp || cp == sp) {
-                       free_both_and_fail:
-                               free(sp);
-                               goto free_first_and_fail;
-                       }
+                       if (unquote_c_style(&sp, second, NULL))
+                               goto free_and_fail1;
+                       cp = stop_at_slash(sp.buf, sp.len);
+                       if (!cp || cp == sp.buf)
+                               goto free_and_fail1;
                        /* They must match, otherwise ignore */
-                       if (strcmp(cp+1, first))
-                               goto free_both_and_fail;
-                       free(sp);
-                       return first;
+                       if (strcmp(cp + 1, first.buf))
+                               goto free_and_fail1;
+                       strbuf_release(&sp);
+                       return first.buf;
                }
 
                /* unquoted second */
                cp = stop_at_slash(second, line + llen - second);
                if (!cp || cp == second)
-                       goto free_first_and_fail;
+                       goto free_and_fail1;
                cp++;
-               if (line + llen - cp != len + 1 ||
-                   memcmp(first, cp, len))
-                       goto free_first_and_fail;
-               return first;
+               if (line + llen - cp != first.len + 1 ||
+                   memcmp(first.buf, cp, first.len))
+                       goto free_and_fail1;
+               return first.buf;
+
+       free_and_fail1:
+               strbuf_release(&first);
+               strbuf_release(&sp);
+               return NULL;
        }
 
        /* unquoted first name */
        name = stop_at_slash(line, llen);
        if (!name || name == line)
                return NULL;
-
        name++;
 
        /* since the first name is unquoted, a dq if exists must be
@@ -639,28 +637,30 @@ static char *git_header_name(char *line, int llen)
         */
        for (second = name; second < line + llen; second++) {
                if (*second == '"') {
-                       const char *cp = second;
+                       struct strbuf sp;
                        const char *np;
-                       char *sp = unquote_c_style(second, NULL);
-
-                       if (!sp)
-                               return NULL;
-                       np = stop_at_slash(sp, strlen(sp));
-                       if (!np || np == sp) {
-                       free_second_and_fail:
-                               free(sp);
-                               return NULL;
-                       }
+
+                       strbuf_init(&sp, 0);
+                       if (unquote_c_style(&sp, second, NULL))
+                               goto free_and_fail2;
+
+                       np = stop_at_slash(sp.buf, sp.len);
+                       if (!np || np == sp.buf)
+                               goto free_and_fail2;
                        np++;
-                       len = strlen(np);
-                       if (len < cp - name &&
+
+                       len = sp.buf + sp.len - np;
+                       if (len < second - name &&
                            !strncmp(np, name, len) &&
                            isspace(name[len])) {
                                /* Good */
-                               memmove(sp, np, len + 1);
-                               return sp;
+                               strbuf_remove(&sp, 0, np - sp.buf);
+                               return sp.buf;
                        }
-                       goto free_second_and_fail;
+
+               free_and_fail2:
+                       strbuf_release(&sp);
+                       return NULL;
                }
        }
 
@@ -1378,61 +1378,50 @@ static const char minuses[]= "--------------------------------------------------
 
 static void show_stats(struct patch *patch)
 {
-       const char *prefix = "";
-       char *name = patch->new_name;
-       char *qname = NULL;
-       int len, max, add, del, total;
-
-       if (!name)
-               name = patch->old_name;
+       struct strbuf qname;
+       char *cp = patch->new_name ? patch->new_name : patch->old_name;
+       int max, add, del;
 
-       if (0 < (len = quote_c_style(name, NULL, NULL, 0))) {
-               qname = xmalloc(len + 1);
-               quote_c_style(name, qname, NULL, 0);
-               name = qname;
-       }
+       strbuf_init(&qname, 0);
+       quote_c_style(cp, &qname, NULL, 0);
 
        /*
         * "scale" the filename
         */
-       len = strlen(name);
        max = max_len;
        if (max > 50)
                max = 50;
-       if (len > max) {
-               char *slash;
-               prefix = "...";
-               max -= 3;
-               name += len - max;
-               slash = strchr(name, '/');
-               if (slash)
-                       name = slash;
+
+       if (qname.len > max) {
+               cp = strchr(qname.buf + qname.len + 3 - max, '/');
+               if (!cp)
+                       cp = qname.buf + qname.len + 3 - max;
+               strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
+       }
+
+       if (patch->is_binary) {
+               printf(" %-*s |  Bin\n", max, qname.buf);
+               strbuf_release(&qname);
+               return;
        }
-       len = max;
+
+       printf(" %-*s |", max, qname.buf);
+       strbuf_release(&qname);
 
        /*
         * scale the add/delete
         */
-       max = max_change;
-       if (max + len > 70)
-               max = 70 - len;
-
+       max = max + max_change > 70 ? 70 - max : max_change;
        add = patch->lines_added;
        del = patch->lines_deleted;
-       total = add + del;
 
        if (max_change > 0) {
-               total = (total * max + max_change / 2) / max_change;
+               int total = ((add + del) * max + max_change / 2) / max_change;
                add = (add * max + max_change / 2) / max_change;
                del = total - add;
        }
-       if (patch->is_binary)
-               printf(" %s%-*s |  Bin\n", prefix, len, name);
-       else
-               printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
-                      len, name, patch->lines_added + patch->lines_deleted,
-                      add, pluses, del, minuses);
-       free(qname);
+       printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
+               add, pluses, del, minuses);
 }
 
 static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
@@ -2227,13 +2216,8 @@ static void numstat_patch_list(struct patch *patch)
                if (patch->is_binary)
                        printf("-\t-\t");
                else
-                       printf("%d\t%d\t",
-                              patch->lines_added, patch->lines_deleted);
-               if (line_termination && quote_c_style(name, NULL, NULL, 0))
-                       quote_c_style(name, NULL, stdout, 0);
-               else
-                       fputs(name, stdout);
-               putchar(line_termination);
+                       printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+               write_name_quoted(name, stdout, line_termination);
        }
 }