Instead of storing a list of refnames in append_ref, a list of structures is created. Each of these stores the refname and a symbolic constant representing its type. The creation of the list is filtered based on a command line switch; no switch means "local branches only", "-r" means "remote branches only" (as they always did); but now "-a" means "local branches or remote branches". As a side effect, the list is now not global, but allocated in print_ref_list() where it used. Also a memory leak is plugged, the memory allocated during the list creation was never freed. This is now done in the new function, tidy_ref_list() Signed-off-by: Andy Parkins <andyparkins@xxxxxxxxx> --- builtin-branch.c | 95 +++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 77 insertions(+), 18 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 368b68e..6dd33ee 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -79,46 +79,100 @@ static void delete_branches(int argc, co } } -static int ref_index, ref_alloc; -static char **ref_list; +#define REF_UNKNOWN_TYPE 0x00 +#define REF_LOCAL_BRANCH 0x01 +#define REF_REMOTE_BRANCH 0x02 +#define REF_TAG 0x04 + +struct ref_item { + char *name; + unsigned int type; +}; + +struct ref_list { + int index, alloc; + struct ref_item *list; + int type_wanted; +}; static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { - if (ref_index >= ref_alloc) { - ref_alloc = alloc_nr(ref_alloc); - ref_list = xrealloc(ref_list, ref_alloc * sizeof(char *)); + struct ref_list *ref_list = (struct ref_list*)(cb_data); + struct ref_item *newitem; + int type = REF_UNKNOWN_TYPE; + + /* Detect type */ + if (!strncmp(refname, "refs/heads/", 11)) { + type = REF_LOCAL_BRANCH; + refname += 11; + } else if (!strncmp(refname, "refs/remotes/", 13)) { + type = REF_REMOTE_BRANCH; + refname += 13; + } else if (!strncmp(refname, "refs/tags/", 10)) { + type = REF_TAG; + refname += 10; + } + + /* Don't add type the caller doesn't want */ + if ((type & ref_list->type_wanted) == 0) { + return 0; + } + + /* Resize buffer */ + if (ref_list->index >= ref_list->alloc) { + ref_list->alloc = alloc_nr(ref_list->alloc); + ref_list->list = xrealloc(ref_list->list, + ref_list->alloc * sizeof(struct ref_item)); } - ref_list[ref_index++] = xstrdup(refname); + /* Record the new item */ + newitem = &(ref_list->list[ref_list->index++]); + newitem->name = xstrdup(refname); + newitem->type = type; return 0; } +static int tidy_ref_list( struct ref_list *ref_list ) +{ + int i; + for (i = 0; i < ref_list->index; i++) { + free( ref_list->list[i].name ); + } + free( ref_list->list ); +} + static int ref_cmp(const void *r1, const void *r2) { + struct ref_item *c1 = (struct ref_item*)(r1), + *c2 = (struct ref_item*)(r2); + if( c1->type != c2->type ) + return c1->type - c2->type; return strcmp(*(char **)r1, *(char **)r2); } -static void print_ref_list(int remote_only) +static void print_ref_list( int type_wanted ) { int i; char c; + struct ref_list ref_list; - if (remote_only) - for_each_remote_ref(append_ref, NULL); - else - for_each_branch_ref(append_ref, NULL); + memset( &ref_list, 0, sizeof( ref_list ) ); + ref_list.type_wanted = type_wanted; + for_each_ref(append_ref, &ref_list); - qsort(ref_list, ref_index, sizeof(char *), ref_cmp); + qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); - for (i = 0; i < ref_index; i++) { + for (i = 0; i < ref_list.index; i++) { c = ' '; - if (!strcmp(ref_list[i], head)) + if (!strcmp(ref_list.list[i].name, head)) c = '*'; - printf("%c %s\n", c, ref_list[i]); + printf("%c %s\n", c, ref_list.list[i].name); } + + tidy_ref_list( &ref_list ); } static void create_branch(const char *name, const char *start, @@ -160,9 +214,10 @@ static void create_branch(const char *na int cmd_branch(int argc, const char **argv, const char *prefix) { - int delete = 0, force_delete = 0, force_create = 0, remote_only = 0; + int delete = 0, force_delete = 0, force_create = 0; int reflog = 0; int i; + int type_wanted = REF_LOCAL_BRANCH; git_config(git_default_config); @@ -189,7 +244,11 @@ int cmd_branch(int argc, const char **ar continue; } if (!strcmp(arg, "-r")) { - remote_only = 1; + type_wanted = REF_REMOTE_BRANCH; + continue; + } + if (!strcmp(arg, "-a")) { + type_wanted = REF_LOCAL_BRANCH | REF_REMOTE_BRANCH; continue; } if (!strcmp(arg, "-l")) { @@ -209,7 +268,7 @@ int cmd_branch(int argc, const char **ar if (delete) delete_branches(argc - i, argv + i, force_delete); else if (i == argc) - print_ref_list(remote_only); + print_ref_list(type_wanted); else if (i == argc - 1) create_branch(argv[i], head, force_create, reflog); else if (i == argc - 2) -- 1.4.3.2 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html