ident.c: add split_ident_line() to parse formatted ident line
The commit formatting logic format_person_part() in pretty.c implements the logic to split an author/committer ident line into its parts, intermixed with logic to compute its output using these piece it computes. Separate the former out to a helper function split_ident_line() so that other codepath can use the same logic, and rewrite the function using the helper function. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Mar 11, 2012 at 01:25 UTC
4b340cfab9c7a18e39bc531d6a6ffaffdf95f62d
3 files changed
+104
-44
cache.h
+16
@@ -928,6 +928,22 @@ extern const char *fmt_name(const char *name, const char *email);
928
extern const char *git_editor(void);
929
extern const char *git_pager(int stdout_is_tty);
930
931
+struct ident_split {
932
+ const char *name_begin;
933
+ const char *name_end;
934
+ const char *mail_begin;
935
+ const char *mail_end;
936
+ const char *date_begin;
937
+ const char *date_end;
938
+ const char *tz_begin;
939
+ const char *tz_end;
940
+};
941
+/*
942
+ * Signals an success with 0, but time part of the result may be NULL
943
+ * if the input lacks timestamp and zone
944
+ */
945
+extern int split_ident_line(struct ident_split *, const char *, int);
946
+
947
struct checkout {
948
const char *base_dir;
949
int base_dir_len;
ident.c
+68
@@ -220,6 +220,74 @@ static int copy(char *buf, size_t size, int offset, const char *src)
220
return offset;
221
}
222
223
+/*
224
+ * Reverse of fmt_ident(); given an ident line, split the fields
225
+ * to allow the caller to parse it.
226
+ * Signal a success by returning 0, but date/tz fields of the result
227
+ * can still be NULL if the input line only has the name/email part
228
+ * (e.g. reading from a reflog entry).
229
+ */
230
+int split_ident_line(struct ident_split *split, const char *line, int len)
231
+{
232
+ const char *cp;
233
+ size_t span;
234
+ int status = -1;
235
+
236
+ memset(split, 0, sizeof(*split));
237
+
238
+ split->name_begin = line;
239
+ for (cp = line; *cp && cp < line + len; cp++)
240
+ if (*cp == '<') {
241
+ split->mail_begin = cp + 1;
242
+ break;
243
+ }
244
+ if (!split->mail_begin)
245
+ return status;
246
+
247
+ for (cp = split->mail_begin - 2; line < cp; cp--)
248
+ if (!isspace(*cp)) {
249
+ split->name_end = cp + 1;
250
+ break;
251
+ }
252
+ if (!split->name_end)
253
+ return status;
254
+
255
+ for (cp = split->mail_begin; cp < line + len; cp++)
256
+ if (*cp == '>') {
257
+ split->mail_end = cp;
258
+ break;
259
+ }
260
+ if (!split->mail_end)
261
+ return status;
262
+
263
+ for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
264
+ ;
265
+ if (line + len <= cp)
266
+ goto person_only;
267
+ split->date_begin = cp;
268
+ span = strspn(cp, "0123456789");
269
+ if (!span)
270
+ goto person_only;
271
+ split->date_end = split->date_begin + span;
272
+ for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
273
+ ;
274
+ if (line + len <= cp || (*cp != '+' && *cp != '-'))
275
+ goto person_only;
276
+ split->tz_begin = cp;
277
+ span = strspn(cp + 1, "0123456789");
278
+ if (!span)
279
+ goto person_only;
280
+ split->tz_end = split->tz_begin + 1 + span;
281
+ return 0;
282
+
283
+person_only:
284
+ split->date_begin = NULL;
285
+ split->date_end = NULL;
286
+ split->tz_begin = NULL;
287
+ split->tz_end = NULL;
288
+ return 0;
289
+}
290
+
291
static const char *env_hint =
292
"\n"
293
"*** Please tell me who you are.\n"
pretty.c
+20
-44
@@ -531,41 +531,24 @@ static size_t format_person_part(struct strbuf *sb, char part,
531
{
532
/* currently all placeholders have same length */
533
const int placeholder_len = 2;
534
- int start, end, tz = 0;
534
+ int tz;
535
unsigned long date = 0;
536
- char *ep;
537
- const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
536
char person_name[1024];
537
char person_mail[1024];
538
+ struct ident_split s;
539
+ const char *name_start, *name_end, *mail_start, *mail_end;
540
541
- /* advance 'end' to point to email start delimiter */
542
- for (end = 0; end < len && msg[end] != '<'; end++)
543
- ; /* do nothing */
544
-
545
- /*
546
- * When end points at the '<' that we found, it should have
547
- * matching '>' later, which means 'end' must be strictly
548
- * below len - 1.
549
- */
550
- if (end >= len - 2)
541
+ if (split_ident_line(&s, msg, len) < 0)
542
goto skip;
543
553
- /* Seek for both name and email part */
554
- name_start = msg;
555
- name_end = msg+end;
556
- while (name_end > name_start && isspace(*(name_end-1)))
557
- name_end--;
558
- mail_start = msg+end+1;
559
- mail_end = mail_start;
560
- while (mail_end < msg_end && *mail_end != '>')
561
- mail_end++;
562
- if (mail_end == msg_end)
563
- goto skip;
564
- end = mail_end-msg;
544
+ name_start = s.name_begin;
545
+ name_end = s.name_end;
546
+ mail_start = s.mail_begin;
547
+ mail_end = s.mail_end;
548
549
if (part == 'N' || part == 'E') { /* mailmap lookup */
567
- strlcpy(person_name, name_start, name_end-name_start+1);
568
- strlcpy(person_mail, mail_start, mail_end-mail_start+1);
550
+ strlcpy(person_name, name_start, name_end - name_start + 1);
551
+ strlcpy(person_mail, mail_start, mail_end - mail_start + 1);
552
mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
553
name_start = person_name;
554
name_end = name_start + strlen(person_name);
@@ -581,28 +564,20 @@ static size_t format_person_part(struct strbuf *sb, char part,
564
return placeholder_len;
565
}
566
584
- /* advance 'start' to point to date start delimiter */
585
- for (start = end + 1; start < len && isspace(msg[start]); start++)
586
- ; /* do nothing */
587
- if (start >= len)
588
- goto skip;
589
- date = strtoul(msg + start, &ep, 10);
590
- if (msg + start == ep)
567
+ if (!s.date_begin)
568
goto skip;
569
570
+ date = strtoul(s.date_begin, NULL, 10);
571
+
572
if (part == 't') { /* date, UNIX timestamp */
594
- strbuf_add(sb, msg + start, ep - (msg + start));
573
+ strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
574
return placeholder_len;
575
}
576
577
/* parse tz */
599
- for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
600
- ; /* do nothing */
601
- if (start + 1 < len) {
602
- tz = strtoul(msg + start + 1, NULL, 10);
603
- if (msg[start] == '-')
604
- tz = -tz;
605
- }
578
+ tz = strtoul(s.tz_begin + 1, NULL, 10);
579
+ if (*s.tz_begin == '-')
580
+ tz = -tz;
581
582
switch (part) {
583
case 'd': /* date */
@@ -621,8 +596,9 @@ static size_t format_person_part(struct strbuf *sb, char part,
596
597
skip:
598
/*
624
- * bogus commit, 'sb' cannot be updated, but we still need to
625
- * compute a valid return value.
599
+ * reading from either a bogus commit, or a reflog entry with
600
+ * %gn, %ge, etc.; 'sb' cannot be updated, but we still need
601
+ * to compute a valid return value.
602
*/
603
if (part == 'n' || part == 'e' || part == 't' || part == 'd'
604
|| part == 'D' || part == 'r' || part == 'i')