Skip to content

Commit 4b340cf

Browse files
committed
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 <[email protected]>
1 parent 0dbe659 commit 4b340cf

File tree

3 files changed

+104
-44
lines changed

3 files changed

+104
-44
lines changed

cache.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,22 @@ extern const char *fmt_name(const char *name, const char *email);
928928
extern const char *git_editor(void);
929929
extern const char *git_pager(int stdout_is_tty);
930930

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+
931947
struct checkout {
932948
const char *base_dir;
933949
int base_dir_len;

ident.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,74 @@ static int copy(char *buf, size_t size, int offset, const char *src)
220220
return offset;
221221
}
222222

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+
223291
static const char *env_hint =
224292
"\n"
225293
"*** Please tell me who you are.\n"

pretty.c

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -531,41 +531,24 @@ static size_t format_person_part(struct strbuf *sb, char part,
531531
{
532532
/* currently all placeholders have same length */
533533
const int placeholder_len = 2;
534-
int start, end, tz = 0;
534+
int tz;
535535
unsigned long date = 0;
536-
char *ep;
537-
const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
538536
char person_name[1024];
539537
char person_mail[1024];
538+
struct ident_split s;
539+
const char *name_start, *name_end, *mail_start, *mail_end;
540540

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)
551542
goto skip;
552543

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;
565548

566549
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);
569552
mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
570553
name_start = person_name;
571554
name_end = name_start + strlen(person_name);
@@ -581,28 +564,20 @@ static size_t format_person_part(struct strbuf *sb, char part,
581564
return placeholder_len;
582565
}
583566

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)
591568
goto skip;
592569

570+
date = strtoul(s.date_begin, NULL, 10);
571+
593572
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);
595574
return placeholder_len;
596575
}
597576

598577
/* 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;
606581

607582
switch (part) {
608583
case 'd': /* date */
@@ -621,8 +596,9 @@ static size_t format_person_part(struct strbuf *sb, char part,
621596

622597
skip:
623598
/*
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.
626602
*/
627603
if (part == 'n' || part == 'e' || part == 't' || part == 'd'
628604
|| part == 'D' || part == 'r' || part == 'i')

0 commit comments

Comments
 (0)