Peter Hagervall | baffc0e | 2007-07-15 01:14:45 +0200 | [diff] [blame] | 1 | #include "builtin.h" |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 2 | #include "cache.h" |
| 3 | #include "refs.h" |
| 4 | #include "object.h" |
| 5 | #include "tag.h" |
| 6 | #include "commit.h" |
| 7 | #include "tree.h" |
| 8 | #include "blob.h" |
| 9 | #include "quote.h" |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 10 | #include "parse-options.h" |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 11 | |
| 12 | /* Quoting styles */ |
| 13 | #define QUOTE_NONE 0 |
| 14 | #define QUOTE_SHELL 1 |
| 15 | #define QUOTE_PERL 2 |
Johannes Sixt | c9ecf4f | 2007-12-06 13:24:39 +0100 | [diff] [blame] | 16 | #define QUOTE_PYTHON 4 |
| 17 | #define QUOTE_TCL 8 |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 18 | |
| 19 | typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type; |
| 20 | |
| 21 | struct atom_value { |
| 22 | const char *s; |
| 23 | unsigned long ul; /* used for sorting when not FIELD_STR */ |
| 24 | }; |
| 25 | |
| 26 | struct ref_sort { |
| 27 | struct ref_sort *next; |
| 28 | int atom; /* index into used_atom array */ |
| 29 | unsigned reverse : 1; |
| 30 | }; |
| 31 | |
| 32 | struct refinfo { |
| 33 | char *refname; |
| 34 | unsigned char objectname[20]; |
| 35 | struct atom_value *value; |
| 36 | }; |
| 37 | |
| 38 | static struct { |
| 39 | const char *name; |
| 40 | cmp_type cmp_type; |
| 41 | } valid_atom[] = { |
| 42 | { "refname" }, |
| 43 | { "objecttype" }, |
| 44 | { "objectsize", FIELD_ULONG }, |
| 45 | { "objectname" }, |
| 46 | { "tree" }, |
Junio C Hamano | 9e1a2ac | 2007-10-02 15:09:41 -0700 | [diff] [blame] | 47 | { "parent" }, |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 48 | { "numparent", FIELD_ULONG }, |
| 49 | { "object" }, |
| 50 | { "type" }, |
| 51 | { "tag" }, |
| 52 | { "author" }, |
| 53 | { "authorname" }, |
| 54 | { "authoremail" }, |
| 55 | { "authordate", FIELD_TIME }, |
| 56 | { "committer" }, |
| 57 | { "committername" }, |
| 58 | { "committeremail" }, |
| 59 | { "committerdate", FIELD_TIME }, |
| 60 | { "tagger" }, |
| 61 | { "taggername" }, |
| 62 | { "taggeremail" }, |
| 63 | { "taggerdate", FIELD_TIME }, |
Junio C Hamano | 3175aa1 | 2006-10-28 13:33:46 -0700 | [diff] [blame] | 64 | { "creator" }, |
| 65 | { "creatordate", FIELD_TIME }, |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 66 | { "subject" }, |
| 67 | { "body" }, |
| 68 | { "contents" }, |
| 69 | }; |
| 70 | |
| 71 | /* |
| 72 | * An atom is a valid field atom listed above, possibly prefixed with |
| 73 | * a "*" to denote deref_tag(). |
| 74 | * |
| 75 | * We parse given format string and sort specifiers, and make a list |
| 76 | * of properties that we need to extract out of objects. refinfo |
| 77 | * structure will hold an array of values extracted that can be |
| 78 | * indexed with the "atom number", which is an index into this |
| 79 | * array. |
| 80 | */ |
| 81 | static const char **used_atom; |
| 82 | static cmp_type *used_atom_type; |
| 83 | static int used_atom_cnt, sort_atom_limit, need_tagged; |
| 84 | |
| 85 | /* |
| 86 | * Used to parse format string and sort specifiers |
| 87 | */ |
| 88 | static int parse_atom(const char *atom, const char *ep) |
| 89 | { |
| 90 | const char *sp; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 91 | int i, at; |
| 92 | |
| 93 | sp = atom; |
| 94 | if (*sp == '*' && sp < ep) |
| 95 | sp++; /* deref */ |
| 96 | if (ep <= sp) |
| 97 | die("malformed field name: %.*s", (int)(ep-atom), atom); |
| 98 | |
| 99 | /* Do we have the atom already used elsewhere? */ |
| 100 | for (i = 0; i < used_atom_cnt; i++) { |
| 101 | int len = strlen(used_atom[i]); |
| 102 | if (len == ep - atom && !memcmp(used_atom[i], atom, len)) |
| 103 | return i; |
| 104 | } |
| 105 | |
| 106 | /* Is the atom a valid one? */ |
| 107 | for (i = 0; i < ARRAY_SIZE(valid_atom); i++) { |
| 108 | int len = strlen(valid_atom[i].name); |
Andy Parkins | b64265c | 2007-09-28 15:17:39 +0100 | [diff] [blame] | 109 | /* |
| 110 | * If the atom name has a colon, strip it and everything after |
| 111 | * it off - it specifies the format for this entry, and |
| 112 | * shouldn't be used for checking against the valid_atom |
| 113 | * table. |
| 114 | */ |
| 115 | const char *formatp = strchr(sp, ':'); |
Junio C Hamano | 070f691 | 2007-10-02 14:31:37 -0700 | [diff] [blame] | 116 | if (!formatp || ep < formatp) |
Andy Parkins | b64265c | 2007-09-28 15:17:39 +0100 | [diff] [blame] | 117 | formatp = ep; |
| 118 | if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len)) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 119 | break; |
| 120 | } |
| 121 | |
| 122 | if (ARRAY_SIZE(valid_atom) <= i) |
| 123 | die("unknown field name: %.*s", (int)(ep-atom), atom); |
| 124 | |
| 125 | /* Add it in, including the deref prefix */ |
| 126 | at = used_atom_cnt; |
| 127 | used_atom_cnt++; |
| 128 | used_atom = xrealloc(used_atom, |
| 129 | (sizeof *used_atom) * used_atom_cnt); |
| 130 | used_atom_type = xrealloc(used_atom_type, |
| 131 | (sizeof(*used_atom_type) * used_atom_cnt)); |
Pierre Habouzit | 182af83 | 2007-09-16 00:32:36 +0200 | [diff] [blame] | 132 | used_atom[at] = xmemdupz(atom, ep - atom); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 133 | used_atom_type[at] = valid_atom[i].cmp_type; |
| 134 | return at; |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | * In a format string, find the next occurrence of %(atom). |
| 139 | */ |
| 140 | static const char *find_next(const char *cp) |
| 141 | { |
| 142 | while (*cp) { |
| 143 | if (*cp == '%') { |
| 144 | /* %( is the start of an atom; |
Pavel Roskin | 3dff537 | 2007-02-03 23:49:16 -0500 | [diff] [blame] | 145 | * %% is a quoted per-cent. |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 146 | */ |
| 147 | if (cp[1] == '(') |
| 148 | return cp; |
| 149 | else if (cp[1] == '%') |
| 150 | cp++; /* skip over two % */ |
| 151 | /* otherwise this is a singleton, literal % */ |
| 152 | } |
| 153 | cp++; |
| 154 | } |
| 155 | return NULL; |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Make sure the format string is well formed, and parse out |
| 160 | * the used atoms. |
| 161 | */ |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 162 | static int verify_format(const char *format) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 163 | { |
| 164 | const char *cp, *sp; |
| 165 | for (cp = format; *cp && (sp = find_next(cp)); ) { |
| 166 | const char *ep = strchr(sp, ')'); |
| 167 | if (!ep) |
Michele Ballabio | 8e0fbe6 | 2008-02-25 00:16:04 +0100 | [diff] [blame] | 168 | return error("malformed format string %s", sp); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 169 | /* sp points at "%(" and ep points at the closing ")" */ |
| 170 | parse_atom(sp + 2, ep); |
| 171 | cp = ep + 1; |
| 172 | } |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 173 | return 0; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | /* |
| 177 | * Given an object name, read the object data and size, and return a |
| 178 | * "struct object". If the object data we are returning is also borrowed |
| 179 | * by the "struct object" representation, set *eaten as well---it is a |
| 180 | * signal from parse_object_buffer to us not to free the buffer. |
| 181 | */ |
| 182 | static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten) |
| 183 | { |
Nicolas Pitre | 21666f1 | 2007-02-26 14:55:59 -0500 | [diff] [blame] | 184 | enum object_type type; |
| 185 | void *buf = read_sha1_file(sha1, &type, sz); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 186 | |
| 187 | if (buf) |
| 188 | *obj = parse_object_buffer(sha1, type, *sz, buf, eaten); |
| 189 | else |
| 190 | *obj = NULL; |
| 191 | return buf; |
| 192 | } |
| 193 | |
| 194 | /* See grab_values */ |
| 195 | static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 196 | { |
| 197 | int i; |
| 198 | |
| 199 | for (i = 0; i < used_atom_cnt; i++) { |
| 200 | const char *name = used_atom[i]; |
| 201 | struct atom_value *v = &val[i]; |
| 202 | if (!!deref != (*name == '*')) |
| 203 | continue; |
| 204 | if (deref) |
| 205 | name++; |
| 206 | if (!strcmp(name, "objecttype")) |
Nicolas Pitre | df84366 | 2007-02-26 14:55:58 -0500 | [diff] [blame] | 207 | v->s = typename(obj->type); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 208 | else if (!strcmp(name, "objectsize")) { |
| 209 | char *s = xmalloc(40); |
| 210 | sprintf(s, "%lu", sz); |
| 211 | v->ul = sz; |
| 212 | v->s = s; |
| 213 | } |
| 214 | else if (!strcmp(name, "objectname")) { |
| 215 | char *s = xmalloc(41); |
| 216 | strcpy(s, sha1_to_hex(obj->sha1)); |
| 217 | v->s = s; |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | /* See grab_values */ |
| 223 | static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 224 | { |
| 225 | int i; |
| 226 | struct tag *tag = (struct tag *) obj; |
| 227 | |
| 228 | for (i = 0; i < used_atom_cnt; i++) { |
| 229 | const char *name = used_atom[i]; |
| 230 | struct atom_value *v = &val[i]; |
| 231 | if (!!deref != (*name == '*')) |
| 232 | continue; |
| 233 | if (deref) |
| 234 | name++; |
| 235 | if (!strcmp(name, "tag")) |
| 236 | v->s = tag->tag; |
Jeff King | 87412ec | 2008-06-25 12:08:15 -0400 | [diff] [blame] | 237 | else if (!strcmp(name, "type") && tag->tagged) |
| 238 | v->s = typename(tag->tagged->type); |
| 239 | else if (!strcmp(name, "object") && tag->tagged) { |
| 240 | char *s = xmalloc(41); |
| 241 | strcpy(s, sha1_to_hex(tag->tagged->sha1)); |
| 242 | v->s = s; |
| 243 | } |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 244 | } |
| 245 | } |
| 246 | |
| 247 | static int num_parents(struct commit *commit) |
| 248 | { |
| 249 | struct commit_list *parents; |
| 250 | int i; |
| 251 | |
| 252 | for (i = 0, parents = commit->parents; |
| 253 | parents; |
| 254 | parents = parents->next) |
| 255 | i++; |
| 256 | return i; |
| 257 | } |
| 258 | |
| 259 | /* See grab_values */ |
| 260 | static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 261 | { |
| 262 | int i; |
| 263 | struct commit *commit = (struct commit *) obj; |
| 264 | |
| 265 | for (i = 0; i < used_atom_cnt; i++) { |
| 266 | const char *name = used_atom[i]; |
| 267 | struct atom_value *v = &val[i]; |
| 268 | if (!!deref != (*name == '*')) |
| 269 | continue; |
| 270 | if (deref) |
| 271 | name++; |
| 272 | if (!strcmp(name, "tree")) { |
| 273 | char *s = xmalloc(41); |
| 274 | strcpy(s, sha1_to_hex(commit->tree->object.sha1)); |
| 275 | v->s = s; |
| 276 | } |
| 277 | if (!strcmp(name, "numparent")) { |
| 278 | char *s = xmalloc(40); |
Junio C Hamano | 9e1a2ac | 2007-10-02 15:09:41 -0700 | [diff] [blame] | 279 | v->ul = num_parents(commit); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 280 | sprintf(s, "%lu", v->ul); |
| 281 | v->s = s; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 282 | } |
| 283 | else if (!strcmp(name, "parent")) { |
| 284 | int num = num_parents(commit); |
| 285 | int i; |
| 286 | struct commit_list *parents; |
Junio C Hamano | 9e1a2ac | 2007-10-02 15:09:41 -0700 | [diff] [blame] | 287 | char *s = xmalloc(41 * num + 1); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 288 | v->s = s; |
| 289 | for (i = 0, parents = commit->parents; |
| 290 | parents; |
Junio C Hamano | 9e1a2ac | 2007-10-02 15:09:41 -0700 | [diff] [blame] | 291 | parents = parents->next, i = i + 41) { |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 292 | struct commit *parent = parents->item; |
| 293 | strcpy(s+i, sha1_to_hex(parent->object.sha1)); |
| 294 | if (parents->next) |
| 295 | s[i+40] = ' '; |
| 296 | } |
Junio C Hamano | 9e1a2ac | 2007-10-02 15:09:41 -0700 | [diff] [blame] | 297 | if (!i) |
| 298 | *s = '\0'; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 299 | } |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz) |
| 304 | { |
| 305 | const char *eol; |
| 306 | while (*buf) { |
| 307 | if (!strncmp(buf, who, wholen) && |
| 308 | buf[wholen] == ' ') |
| 309 | return buf + wholen + 1; |
| 310 | eol = strchr(buf, '\n'); |
| 311 | if (!eol) |
| 312 | return ""; |
| 313 | eol++; |
Christian Couder | a74fa11 | 2007-11-12 05:37:25 +0100 | [diff] [blame] | 314 | if (*eol == '\n') |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 315 | return ""; /* end of header */ |
| 316 | buf = eol; |
| 317 | } |
| 318 | return ""; |
| 319 | } |
| 320 | |
Shawn O. Pearce | 3a55602 | 2007-03-06 20:44:17 -0500 | [diff] [blame] | 321 | static const char *copy_line(const char *buf) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 322 | { |
Johan Herland | 94e02e7 | 2008-09-28 00:24:36 +0200 | [diff] [blame] | 323 | const char *eol = strchrnul(buf, '\n'); |
Pierre Habouzit | 182af83 | 2007-09-16 00:32:36 +0200 | [diff] [blame] | 324 | return xmemdupz(buf, eol - buf); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 325 | } |
| 326 | |
Shawn O. Pearce | 3a55602 | 2007-03-06 20:44:17 -0500 | [diff] [blame] | 327 | static const char *copy_name(const char *buf) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 328 | { |
Pierre Habouzit | 182af83 | 2007-09-16 00:32:36 +0200 | [diff] [blame] | 329 | const char *cp; |
Junio C Hamano | 6b30852 | 2007-09-19 01:52:59 -0700 | [diff] [blame] | 330 | for (cp = buf; *cp && *cp != '\n'; cp++) { |
Pierre Habouzit | 182af83 | 2007-09-16 00:32:36 +0200 | [diff] [blame] | 331 | if (!strncmp(cp, " <", 2)) |
| 332 | return xmemdupz(buf, cp - buf); |
| 333 | } |
| 334 | return ""; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 335 | } |
| 336 | |
Shawn O. Pearce | 3a55602 | 2007-03-06 20:44:17 -0500 | [diff] [blame] | 337 | static const char *copy_email(const char *buf) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 338 | { |
| 339 | const char *email = strchr(buf, '<'); |
| 340 | const char *eoemail = strchr(email, '>'); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 341 | if (!email || !eoemail) |
| 342 | return ""; |
Pierre Habouzit | 182af83 | 2007-09-16 00:32:36 +0200 | [diff] [blame] | 343 | return xmemdupz(email, eoemail + 1 - email); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 344 | } |
| 345 | |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 346 | static void grab_date(const char *buf, struct atom_value *v, const char *atomname) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 347 | { |
| 348 | const char *eoemail = strstr(buf, "> "); |
| 349 | char *zone; |
| 350 | unsigned long timestamp; |
| 351 | long tz; |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 352 | enum date_mode date_mode = DATE_NORMAL; |
| 353 | const char *formatp; |
| 354 | |
| 355 | /* |
| 356 | * We got here because atomname ends in "date" or "date<something>"; |
| 357 | * it's not possible that <something> is not ":<format>" because |
| 358 | * parse_atom() wouldn't have allowed it, so we can assume that no |
| 359 | * ":" means no format is specified, and use the default. |
| 360 | */ |
| 361 | formatp = strchr(atomname, ':'); |
| 362 | if (formatp != NULL) { |
| 363 | formatp++; |
| 364 | date_mode = parse_date_format(formatp); |
| 365 | } |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 366 | |
| 367 | if (!eoemail) |
| 368 | goto bad; |
| 369 | timestamp = strtoul(eoemail + 2, &zone, 10); |
| 370 | if (timestamp == ULONG_MAX) |
| 371 | goto bad; |
| 372 | tz = strtol(zone, NULL, 10); |
| 373 | if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) |
| 374 | goto bad; |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 375 | v->s = xstrdup(show_date(timestamp, tz, date_mode)); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 376 | v->ul = timestamp; |
| 377 | return; |
| 378 | bad: |
| 379 | v->s = ""; |
| 380 | v->ul = 0; |
| 381 | } |
| 382 | |
| 383 | /* See grab_values */ |
| 384 | static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 385 | { |
| 386 | int i; |
| 387 | int wholen = strlen(who); |
| 388 | const char *wholine = NULL; |
| 389 | |
| 390 | for (i = 0; i < used_atom_cnt; i++) { |
| 391 | const char *name = used_atom[i]; |
| 392 | struct atom_value *v = &val[i]; |
| 393 | if (!!deref != (*name == '*')) |
| 394 | continue; |
| 395 | if (deref) |
| 396 | name++; |
| 397 | if (strncmp(who, name, wholen)) |
| 398 | continue; |
| 399 | if (name[wholen] != 0 && |
| 400 | strcmp(name + wholen, "name") && |
| 401 | strcmp(name + wholen, "email") && |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 402 | prefixcmp(name + wholen, "date")) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 403 | continue; |
| 404 | if (!wholine) |
| 405 | wholine = find_wholine(who, wholen, buf, sz); |
| 406 | if (!wholine) |
| 407 | return; /* no point looking for it */ |
| 408 | if (name[wholen] == 0) |
| 409 | v->s = copy_line(wholine); |
| 410 | else if (!strcmp(name + wholen, "name")) |
| 411 | v->s = copy_name(wholine); |
| 412 | else if (!strcmp(name + wholen, "email")) |
| 413 | v->s = copy_email(wholine); |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 414 | else if (!prefixcmp(name + wholen, "date")) |
| 415 | grab_date(wholine, v, name); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 416 | } |
Junio C Hamano | 3175aa1 | 2006-10-28 13:33:46 -0700 | [diff] [blame] | 417 | |
| 418 | /* For a tag or a commit object, if "creator" or "creatordate" is |
| 419 | * requested, do something special. |
| 420 | */ |
| 421 | if (strcmp(who, "tagger") && strcmp(who, "committer")) |
| 422 | return; /* "author" for commit object is not wanted */ |
| 423 | if (!wholine) |
| 424 | wholine = find_wholine(who, wholen, buf, sz); |
| 425 | if (!wholine) |
| 426 | return; |
| 427 | for (i = 0; i < used_atom_cnt; i++) { |
| 428 | const char *name = used_atom[i]; |
| 429 | struct atom_value *v = &val[i]; |
| 430 | if (!!deref != (*name == '*')) |
| 431 | continue; |
| 432 | if (deref) |
| 433 | name++; |
| 434 | |
Andy Parkins | d392e71 | 2007-09-28 15:17:45 +0100 | [diff] [blame] | 435 | if (!prefixcmp(name, "creatordate")) |
| 436 | grab_date(wholine, v, name); |
Junio C Hamano | 3175aa1 | 2006-10-28 13:33:46 -0700 | [diff] [blame] | 437 | else if (!strcmp(name, "creator")) |
| 438 | v->s = copy_line(wholine); |
| 439 | } |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 440 | } |
| 441 | |
| 442 | static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body) |
| 443 | { |
| 444 | while (*buf) { |
| 445 | const char *eol = strchr(buf, '\n'); |
| 446 | if (!eol) |
| 447 | return; |
| 448 | if (eol[1] == '\n') { |
| 449 | buf = eol + 1; |
| 450 | break; /* found end of header */ |
| 451 | } |
| 452 | buf = eol + 1; |
| 453 | } |
| 454 | while (*buf == '\n') |
| 455 | buf++; |
| 456 | if (!*buf) |
| 457 | return; |
| 458 | *sub = buf; /* first non-empty line */ |
| 459 | buf = strchr(buf, '\n'); |
Junio C Hamano | e276c26 | 2008-08-20 12:29:27 -0700 | [diff] [blame] | 460 | if (!buf) { |
| 461 | *body = ""; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 462 | return; /* no body */ |
Junio C Hamano | e276c26 | 2008-08-20 12:29:27 -0700 | [diff] [blame] | 463 | } |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 464 | while (*buf == '\n') |
| 465 | buf++; /* skip blank between subject and body */ |
| 466 | *body = buf; |
| 467 | } |
| 468 | |
| 469 | /* See grab_values */ |
| 470 | static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 471 | { |
| 472 | int i; |
| 473 | const char *subpos = NULL, *bodypos = NULL; |
| 474 | |
| 475 | for (i = 0; i < used_atom_cnt; i++) { |
| 476 | const char *name = used_atom[i]; |
| 477 | struct atom_value *v = &val[i]; |
| 478 | if (!!deref != (*name == '*')) |
| 479 | continue; |
| 480 | if (deref) |
| 481 | name++; |
| 482 | if (strcmp(name, "subject") && |
| 483 | strcmp(name, "body") && |
| 484 | strcmp(name, "contents")) |
| 485 | continue; |
| 486 | if (!subpos) |
| 487 | find_subpos(buf, sz, &subpos, &bodypos); |
| 488 | if (!subpos) |
| 489 | return; |
| 490 | |
| 491 | if (!strcmp(name, "subject")) |
| 492 | v->s = copy_line(subpos); |
| 493 | else if (!strcmp(name, "body")) |
Petr Baudis | f829063 | 2006-11-18 03:56:52 +0100 | [diff] [blame] | 494 | v->s = xstrdup(bodypos); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 495 | else if (!strcmp(name, "contents")) |
Petr Baudis | f829063 | 2006-11-18 03:56:52 +0100 | [diff] [blame] | 496 | v->s = xstrdup(subpos); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 497 | } |
| 498 | } |
| 499 | |
| 500 | /* We want to have empty print-string for field requests |
| 501 | * that do not apply (e.g. "authordate" for a tag object) |
| 502 | */ |
| 503 | static void fill_missing_values(struct atom_value *val) |
| 504 | { |
| 505 | int i; |
| 506 | for (i = 0; i < used_atom_cnt; i++) { |
| 507 | struct atom_value *v = &val[i]; |
| 508 | if (v->s == NULL) |
| 509 | v->s = ""; |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | /* |
| 514 | * val is a list of atom_value to hold returned values. Extract |
| 515 | * the values for atoms in used_atom array out of (obj, buf, sz). |
| 516 | * when deref is false, (obj, buf, sz) is the object that is |
| 517 | * pointed at by the ref itself; otherwise it is the object the |
| 518 | * ref (which is a tag) refers to. |
| 519 | */ |
| 520 | static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) |
| 521 | { |
| 522 | grab_common_values(val, deref, obj, buf, sz); |
| 523 | switch (obj->type) { |
| 524 | case OBJ_TAG: |
| 525 | grab_tag_values(val, deref, obj, buf, sz); |
| 526 | grab_sub_body_contents(val, deref, obj, buf, sz); |
| 527 | grab_person("tagger", val, deref, obj, buf, sz); |
| 528 | break; |
| 529 | case OBJ_COMMIT: |
| 530 | grab_commit_values(val, deref, obj, buf, sz); |
| 531 | grab_sub_body_contents(val, deref, obj, buf, sz); |
| 532 | grab_person("author", val, deref, obj, buf, sz); |
| 533 | grab_person("committer", val, deref, obj, buf, sz); |
| 534 | break; |
| 535 | case OBJ_TREE: |
| 536 | // grab_tree_values(val, deref, obj, buf, sz); |
| 537 | break; |
| 538 | case OBJ_BLOB: |
| 539 | // grab_blob_values(val, deref, obj, buf, sz); |
| 540 | break; |
| 541 | default: |
| 542 | die("Eh? Object of type %d?", obj->type); |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | /* |
| 547 | * Parse the object referred by ref, and grab needed value. |
| 548 | */ |
| 549 | static void populate_value(struct refinfo *ref) |
| 550 | { |
| 551 | void *buf; |
| 552 | struct object *obj; |
| 553 | int eaten, i; |
| 554 | unsigned long size; |
| 555 | const unsigned char *tagged; |
| 556 | |
| 557 | ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); |
| 558 | |
| 559 | buf = get_obj(ref->objectname, &obj, &size, &eaten); |
| 560 | if (!buf) |
| 561 | die("missing object %s for %s", |
| 562 | sha1_to_hex(ref->objectname), ref->refname); |
| 563 | if (!obj) |
| 564 | die("parse_object_buffer failed on %s for %s", |
| 565 | sha1_to_hex(ref->objectname), ref->refname); |
| 566 | |
| 567 | /* Fill in specials first */ |
| 568 | for (i = 0; i < used_atom_cnt; i++) { |
| 569 | const char *name = used_atom[i]; |
| 570 | struct atom_value *v = &ref->value[i]; |
| 571 | if (!strcmp(name, "refname")) |
| 572 | v->s = ref->refname; |
| 573 | else if (!strcmp(name, "*refname")) { |
| 574 | int len = strlen(ref->refname); |
| 575 | char *s = xmalloc(len + 4); |
| 576 | sprintf(s, "%s^{}", ref->refname); |
| 577 | v->s = s; |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | grab_values(ref->value, 0, obj, buf, size); |
| 582 | if (!eaten) |
| 583 | free(buf); |
| 584 | |
| 585 | /* If there is no atom that wants to know about tagged |
| 586 | * object, we are done. |
| 587 | */ |
| 588 | if (!need_tagged || (obj->type != OBJ_TAG)) |
| 589 | return; |
| 590 | |
| 591 | /* If it is a tag object, see if we use a value that derefs |
| 592 | * the object, and if we do grab the object it refers to. |
| 593 | */ |
| 594 | tagged = ((struct tag *)obj)->tagged->sha1; |
| 595 | |
| 596 | /* NEEDSWORK: This derefs tag only once, which |
| 597 | * is good to deal with chains of trust, but |
| 598 | * is not consistent with what deref_tag() does |
| 599 | * which peels the onion to the core. |
| 600 | */ |
| 601 | buf = get_obj(tagged, &obj, &size, &eaten); |
| 602 | if (!buf) |
| 603 | die("missing object %s for %s", |
| 604 | sha1_to_hex(tagged), ref->refname); |
| 605 | if (!obj) |
| 606 | die("parse_object_buffer failed on %s for %s", |
| 607 | sha1_to_hex(tagged), ref->refname); |
| 608 | grab_values(ref->value, 1, obj, buf, size); |
| 609 | if (!eaten) |
| 610 | free(buf); |
| 611 | } |
| 612 | |
| 613 | /* |
| 614 | * Given a ref, return the value for the atom. This lazily gets value |
| 615 | * out of the object by calling populate value. |
| 616 | */ |
| 617 | static void get_value(struct refinfo *ref, int atom, struct atom_value **v) |
| 618 | { |
| 619 | if (!ref->value) { |
| 620 | populate_value(ref); |
| 621 | fill_missing_values(ref->value); |
| 622 | } |
| 623 | *v = &ref->value[atom]; |
| 624 | } |
| 625 | |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 626 | struct grab_ref_cbdata { |
| 627 | struct refinfo **grab_array; |
| 628 | const char **grab_pattern; |
| 629 | int grab_cnt; |
| 630 | }; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 631 | |
| 632 | /* |
| 633 | * A call-back given to for_each_ref(). It is unfortunate that we |
| 634 | * need to use global variables to pass extra information to this |
| 635 | * function. |
| 636 | */ |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 637 | static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 638 | { |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 639 | struct grab_ref_cbdata *cb = cb_data; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 640 | struct refinfo *ref; |
| 641 | int cnt; |
| 642 | |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 643 | if (*cb->grab_pattern) { |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 644 | const char **pattern; |
| 645 | int namelen = strlen(refname); |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 646 | for (pattern = cb->grab_pattern; *pattern; pattern++) { |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 647 | const char *p = *pattern; |
| 648 | int plen = strlen(p); |
| 649 | |
| 650 | if ((plen <= namelen) && |
| 651 | !strncmp(refname, p, plen) && |
| 652 | (refname[plen] == '\0' || |
Björn Steinbrink | 114ef90 | 2008-08-28 04:14:02 +0200 | [diff] [blame] | 653 | refname[plen] == '/' || |
| 654 | p[plen-1] == '/')) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 655 | break; |
| 656 | if (!fnmatch(p, refname, FNM_PATHNAME)) |
| 657 | break; |
| 658 | } |
| 659 | if (!*pattern) |
| 660 | return 0; |
| 661 | } |
| 662 | |
| 663 | /* We do not open the object yet; sort may only need refname |
| 664 | * to do its job and the resulting list may yet to be pruned |
| 665 | * by maxcount logic. |
| 666 | */ |
| 667 | ref = xcalloc(1, sizeof(*ref)); |
| 668 | ref->refname = xstrdup(refname); |
| 669 | hashcpy(ref->objectname, sha1); |
| 670 | |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 671 | cnt = cb->grab_cnt; |
| 672 | cb->grab_array = xrealloc(cb->grab_array, |
| 673 | sizeof(*cb->grab_array) * (cnt + 1)); |
| 674 | cb->grab_array[cnt++] = ref; |
| 675 | cb->grab_cnt = cnt; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 676 | return 0; |
| 677 | } |
| 678 | |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 679 | static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b) |
| 680 | { |
| 681 | struct atom_value *va, *vb; |
| 682 | int cmp; |
| 683 | cmp_type cmp_type = used_atom_type[s->atom]; |
| 684 | |
| 685 | get_value(a, s->atom, &va); |
| 686 | get_value(b, s->atom, &vb); |
| 687 | switch (cmp_type) { |
| 688 | case FIELD_STR: |
| 689 | cmp = strcmp(va->s, vb->s); |
| 690 | break; |
| 691 | default: |
| 692 | if (va->ul < vb->ul) |
| 693 | cmp = -1; |
| 694 | else if (va->ul == vb->ul) |
| 695 | cmp = 0; |
| 696 | else |
| 697 | cmp = 1; |
| 698 | break; |
| 699 | } |
| 700 | return (s->reverse) ? -cmp : cmp; |
| 701 | } |
| 702 | |
| 703 | static struct ref_sort *ref_sort; |
| 704 | static int compare_refs(const void *a_, const void *b_) |
| 705 | { |
| 706 | struct refinfo *a = *((struct refinfo **)a_); |
| 707 | struct refinfo *b = *((struct refinfo **)b_); |
| 708 | struct ref_sort *s; |
| 709 | |
| 710 | for (s = ref_sort; s; s = s->next) { |
| 711 | int cmp = cmp_ref_sort(s, a, b); |
| 712 | if (cmp) |
| 713 | return cmp; |
| 714 | } |
| 715 | return 0; |
| 716 | } |
| 717 | |
| 718 | static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs) |
| 719 | { |
| 720 | ref_sort = sort; |
| 721 | qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs); |
| 722 | } |
| 723 | |
| 724 | static void print_value(struct refinfo *ref, int atom, int quote_style) |
| 725 | { |
| 726 | struct atom_value *v; |
| 727 | get_value(ref, atom, &v); |
| 728 | switch (quote_style) { |
| 729 | case QUOTE_NONE: |
| 730 | fputs(v->s, stdout); |
| 731 | break; |
| 732 | case QUOTE_SHELL: |
| 733 | sq_quote_print(stdout, v->s); |
| 734 | break; |
| 735 | case QUOTE_PERL: |
| 736 | perl_quote_print(stdout, v->s); |
| 737 | break; |
| 738 | case QUOTE_PYTHON: |
| 739 | python_quote_print(stdout, v->s); |
| 740 | break; |
Shawn O. Pearce | 5558e55 | 2007-01-28 02:39:13 -0500 | [diff] [blame] | 741 | case QUOTE_TCL: |
| 742 | tcl_quote_print(stdout, v->s); |
| 743 | break; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 744 | } |
| 745 | } |
| 746 | |
| 747 | static int hex1(char ch) |
| 748 | { |
| 749 | if ('0' <= ch && ch <= '9') |
| 750 | return ch - '0'; |
| 751 | else if ('a' <= ch && ch <= 'f') |
| 752 | return ch - 'a' + 10; |
| 753 | else if ('A' <= ch && ch <= 'F') |
| 754 | return ch - 'A' + 10; |
| 755 | return -1; |
| 756 | } |
| 757 | static int hex2(const char *cp) |
| 758 | { |
| 759 | if (cp[0] && cp[1]) |
| 760 | return (hex1(cp[0]) << 4) | hex1(cp[1]); |
| 761 | else |
| 762 | return -1; |
| 763 | } |
| 764 | |
| 765 | static void emit(const char *cp, const char *ep) |
| 766 | { |
| 767 | while (*cp && (!ep || cp < ep)) { |
| 768 | if (*cp == '%') { |
| 769 | if (cp[1] == '%') |
| 770 | cp++; |
| 771 | else { |
| 772 | int ch = hex2(cp + 1); |
| 773 | if (0 <= ch) { |
| 774 | putchar(ch); |
| 775 | cp += 3; |
| 776 | continue; |
| 777 | } |
| 778 | } |
| 779 | } |
| 780 | putchar(*cp); |
| 781 | cp++; |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | static void show_ref(struct refinfo *info, const char *format, int quote_style) |
| 786 | { |
| 787 | const char *cp, *sp, *ep; |
| 788 | |
| 789 | for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) { |
| 790 | ep = strchr(sp, ')'); |
| 791 | if (cp < sp) |
| 792 | emit(cp, sp); |
| 793 | print_value(info, parse_atom(sp + 2, ep), quote_style); |
| 794 | } |
| 795 | if (*cp) { |
| 796 | sp = cp + strlen(cp); |
| 797 | emit(cp, sp); |
| 798 | } |
| 799 | putchar('\n'); |
| 800 | } |
| 801 | |
| 802 | static struct ref_sort *default_sort(void) |
| 803 | { |
| 804 | static const char cstr_name[] = "refname"; |
| 805 | |
| 806 | struct ref_sort *sort = xcalloc(1, sizeof(*sort)); |
| 807 | |
| 808 | sort->next = NULL; |
| 809 | sort->atom = parse_atom(cstr_name, cstr_name + strlen(cstr_name)); |
| 810 | return sort; |
| 811 | } |
| 812 | |
Stephan Beyer | 186458b | 2008-07-24 01:09:35 +0200 | [diff] [blame] | 813 | static int opt_parse_sort(const struct option *opt, const char *arg, int unset) |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 814 | { |
| 815 | struct ref_sort **sort_tail = opt->value; |
| 816 | struct ref_sort *s; |
| 817 | int len; |
| 818 | |
| 819 | if (!arg) /* should --no-sort void the list ? */ |
| 820 | return -1; |
| 821 | |
| 822 | *sort_tail = s = xcalloc(1, sizeof(*s)); |
| 823 | sort_tail = &s->next; |
| 824 | |
| 825 | if (*arg == '-') { |
| 826 | s->reverse = 1; |
| 827 | arg++; |
| 828 | } |
| 829 | len = strlen(arg); |
| 830 | s->atom = parse_atom(arg, arg+len); |
| 831 | return 0; |
| 832 | } |
| 833 | |
| 834 | static char const * const for_each_ref_usage[] = { |
Stephan Beyer | 1b1dd23 | 2008-07-13 15:36:15 +0200 | [diff] [blame] | 835 | "git for-each-ref [options] [<pattern>]", |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 836 | NULL |
| 837 | }; |
| 838 | |
| 839 | int cmd_for_each_ref(int argc, const char **argv, const char *prefix) |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 840 | { |
| 841 | int i, num_refs; |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 842 | const char *format = "%(objectname) %(objecttype)\t%(refname)"; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 843 | struct ref_sort *sort = NULL, **sort_tail = &sort; |
Pierre Habouzit | 9fac800 | 2007-11-07 11:20:29 +0100 | [diff] [blame] | 844 | int maxcount = 0, quote_style = 0; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 845 | struct refinfo **refs; |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 846 | struct grab_ref_cbdata cbdata; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 847 | |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 848 | struct option opts[] = { |
Pierre Habouzit | 9fac800 | 2007-11-07 11:20:29 +0100 | [diff] [blame] | 849 | OPT_BIT('s', "shell", "e_style, |
| 850 | "quote placeholders suitably for shells", QUOTE_SHELL), |
| 851 | OPT_BIT('p', "perl", "e_style, |
| 852 | "quote placeholders suitably for perl", QUOTE_PERL), |
| 853 | OPT_BIT(0 , "python", "e_style, |
| 854 | "quote placeholders suitably for python", QUOTE_PYTHON), |
| 855 | OPT_BIT(0 , "tcl", "e_style, |
| 856 | "quote placeholders suitably for tcl", QUOTE_TCL), |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 857 | |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 858 | OPT_GROUP(""), |
| 859 | OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"), |
| 860 | OPT_STRING( 0 , "format", &format, "format", "format to use for the output"), |
Lars Hjemli | c899a57 | 2007-11-10 17:47:54 +0100 | [diff] [blame] | 861 | OPT_CALLBACK(0 , "sort", sort_tail, "key", |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 862 | "field name to sort on", &opt_parse_sort), |
| 863 | OPT_END(), |
| 864 | }; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 865 | |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 866 | parse_options(argc, argv, opts, for_each_ref_usage, 0); |
| 867 | if (maxcount < 0) { |
| 868 | error("invalid --count argument: `%d'", maxcount); |
| 869 | usage_with_options(for_each_ref_usage, opts); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 870 | } |
Pierre Habouzit | 9fac800 | 2007-11-07 11:20:29 +0100 | [diff] [blame] | 871 | if (HAS_MULTI_BITS(quote_style)) { |
Johannes Sixt | c9ecf4f | 2007-12-06 13:24:39 +0100 | [diff] [blame] | 872 | error("more than one quoting style?"); |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 873 | usage_with_options(for_each_ref_usage, opts); |
| 874 | } |
| 875 | if (verify_format(format)) |
| 876 | usage_with_options(for_each_ref_usage, opts); |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 877 | |
| 878 | if (!sort) |
| 879 | sort = default_sort(); |
| 880 | sort_atom_limit = used_atom_cnt; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 881 | |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 882 | memset(&cbdata, 0, sizeof(cbdata)); |
Pierre Habouzit | c3428da | 2007-10-13 20:40:46 +0200 | [diff] [blame] | 883 | cbdata.grab_pattern = argv; |
Junio C Hamano | 340adb8 | 2006-09-21 00:29:37 -0700 | [diff] [blame] | 884 | for_each_ref(grab_single_ref, &cbdata); |
| 885 | refs = cbdata.grab_array; |
| 886 | num_refs = cbdata.grab_cnt; |
Junio C Hamano | 9f613dd | 2006-09-15 13:30:02 -0700 | [diff] [blame] | 887 | |
| 888 | for (i = 0; i < used_atom_cnt; i++) { |
| 889 | if (used_atom[i][0] == '*') { |
| 890 | need_tagged = 1; |
| 891 | break; |
| 892 | } |
| 893 | } |
| 894 | |
| 895 | sort_refs(sort, refs, num_refs); |
| 896 | |
| 897 | if (!maxcount || num_refs < maxcount) |
| 898 | maxcount = num_refs; |
| 899 | for (i = 0; i < maxcount; i++) |
| 900 | show_ref(refs[i], format, quote_style); |
| 901 | return 0; |
| 902 | } |