mirror of
https://github.com/git/git.git
synced 2024-11-27 12:03:55 +08:00
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>
This commit is contained in:
parent
0dbe6592cc
commit
4b340cfab9
16
cache.h
16
cache.h
@ -928,6 +928,22 @@ extern const char *fmt_name(const char *name, const char *email);
|
||||
extern const char *git_editor(void);
|
||||
extern const char *git_pager(int stdout_is_tty);
|
||||
|
||||
struct ident_split {
|
||||
const char *name_begin;
|
||||
const char *name_end;
|
||||
const char *mail_begin;
|
||||
const char *mail_end;
|
||||
const char *date_begin;
|
||||
const char *date_end;
|
||||
const char *tz_begin;
|
||||
const char *tz_end;
|
||||
};
|
||||
/*
|
||||
* Signals an success with 0, but time part of the result may be NULL
|
||||
* if the input lacks timestamp and zone
|
||||
*/
|
||||
extern int split_ident_line(struct ident_split *, const char *, int);
|
||||
|
||||
struct checkout {
|
||||
const char *base_dir;
|
||||
int base_dir_len;
|
||||
|
68
ident.c
68
ident.c
@ -220,6 +220,74 @@ static int copy(char *buf, size_t size, int offset, const char *src)
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse of fmt_ident(); given an ident line, split the fields
|
||||
* to allow the caller to parse it.
|
||||
* Signal a success by returning 0, but date/tz fields of the result
|
||||
* can still be NULL if the input line only has the name/email part
|
||||
* (e.g. reading from a reflog entry).
|
||||
*/
|
||||
int split_ident_line(struct ident_split *split, const char *line, int len)
|
||||
{
|
||||
const char *cp;
|
||||
size_t span;
|
||||
int status = -1;
|
||||
|
||||
memset(split, 0, sizeof(*split));
|
||||
|
||||
split->name_begin = line;
|
||||
for (cp = line; *cp && cp < line + len; cp++)
|
||||
if (*cp == '<') {
|
||||
split->mail_begin = cp + 1;
|
||||
break;
|
||||
}
|
||||
if (!split->mail_begin)
|
||||
return status;
|
||||
|
||||
for (cp = split->mail_begin - 2; line < cp; cp--)
|
||||
if (!isspace(*cp)) {
|
||||
split->name_end = cp + 1;
|
||||
break;
|
||||
}
|
||||
if (!split->name_end)
|
||||
return status;
|
||||
|
||||
for (cp = split->mail_begin; cp < line + len; cp++)
|
||||
if (*cp == '>') {
|
||||
split->mail_end = cp;
|
||||
break;
|
||||
}
|
||||
if (!split->mail_end)
|
||||
return status;
|
||||
|
||||
for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
|
||||
;
|
||||
if (line + len <= cp)
|
||||
goto person_only;
|
||||
split->date_begin = cp;
|
||||
span = strspn(cp, "0123456789");
|
||||
if (!span)
|
||||
goto person_only;
|
||||
split->date_end = split->date_begin + span;
|
||||
for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
|
||||
;
|
||||
if (line + len <= cp || (*cp != '+' && *cp != '-'))
|
||||
goto person_only;
|
||||
split->tz_begin = cp;
|
||||
span = strspn(cp + 1, "0123456789");
|
||||
if (!span)
|
||||
goto person_only;
|
||||
split->tz_end = split->tz_begin + 1 + span;
|
||||
return 0;
|
||||
|
||||
person_only:
|
||||
split->date_begin = NULL;
|
||||
split->date_end = NULL;
|
||||
split->tz_begin = NULL;
|
||||
split->tz_end = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *env_hint =
|
||||
"\n"
|
||||
"*** Please tell me who you are.\n"
|
||||
|
64
pretty.c
64
pretty.c
@ -531,41 +531,24 @@ static size_t format_person_part(struct strbuf *sb, char part,
|
||||
{
|
||||
/* currently all placeholders have same length */
|
||||
const int placeholder_len = 2;
|
||||
int start, end, tz = 0;
|
||||
int tz;
|
||||
unsigned long date = 0;
|
||||
char *ep;
|
||||
const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
|
||||
char person_name[1024];
|
||||
char person_mail[1024];
|
||||
struct ident_split s;
|
||||
const char *name_start, *name_end, *mail_start, *mail_end;
|
||||
|
||||
/* advance 'end' to point to email start delimiter */
|
||||
for (end = 0; end < len && msg[end] != '<'; end++)
|
||||
; /* do nothing */
|
||||
|
||||
/*
|
||||
* When end points at the '<' that we found, it should have
|
||||
* matching '>' later, which means 'end' must be strictly
|
||||
* below len - 1.
|
||||
*/
|
||||
if (end >= len - 2)
|
||||
if (split_ident_line(&s, msg, len) < 0)
|
||||
goto skip;
|
||||
|
||||
/* Seek for both name and email part */
|
||||
name_start = msg;
|
||||
name_end = msg+end;
|
||||
while (name_end > name_start && isspace(*(name_end-1)))
|
||||
name_end--;
|
||||
mail_start = msg+end+1;
|
||||
mail_end = mail_start;
|
||||
while (mail_end < msg_end && *mail_end != '>')
|
||||
mail_end++;
|
||||
if (mail_end == msg_end)
|
||||
goto skip;
|
||||
end = mail_end-msg;
|
||||
name_start = s.name_begin;
|
||||
name_end = s.name_end;
|
||||
mail_start = s.mail_begin;
|
||||
mail_end = s.mail_end;
|
||||
|
||||
if (part == 'N' || part == 'E') { /* mailmap lookup */
|
||||
strlcpy(person_name, name_start, name_end-name_start+1);
|
||||
strlcpy(person_mail, mail_start, mail_end-mail_start+1);
|
||||
strlcpy(person_name, name_start, name_end - name_start + 1);
|
||||
strlcpy(person_mail, mail_start, mail_end - mail_start + 1);
|
||||
mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
|
||||
name_start = person_name;
|
||||
name_end = name_start + strlen(person_name);
|
||||
@ -581,28 +564,20 @@ static size_t format_person_part(struct strbuf *sb, char part,
|
||||
return placeholder_len;
|
||||
}
|
||||
|
||||
/* advance 'start' to point to date start delimiter */
|
||||
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start >= len)
|
||||
goto skip;
|
||||
date = strtoul(msg + start, &ep, 10);
|
||||
if (msg + start == ep)
|
||||
if (!s.date_begin)
|
||||
goto skip;
|
||||
|
||||
date = strtoul(s.date_begin, NULL, 10);
|
||||
|
||||
if (part == 't') { /* date, UNIX timestamp */
|
||||
strbuf_add(sb, msg + start, ep - (msg + start));
|
||||
strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
|
||||
return placeholder_len;
|
||||
}
|
||||
|
||||
/* parse tz */
|
||||
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start + 1 < len) {
|
||||
tz = strtoul(msg + start + 1, NULL, 10);
|
||||
if (msg[start] == '-')
|
||||
tz = -tz;
|
||||
}
|
||||
tz = strtoul(s.tz_begin + 1, NULL, 10);
|
||||
if (*s.tz_begin == '-')
|
||||
tz = -tz;
|
||||
|
||||
switch (part) {
|
||||
case 'd': /* date */
|
||||
@ -621,8 +596,9 @@ static size_t format_person_part(struct strbuf *sb, char part,
|
||||
|
||||
skip:
|
||||
/*
|
||||
* bogus commit, 'sb' cannot be updated, but we still need to
|
||||
* compute a valid return value.
|
||||
* reading from either a bogus commit, or a reflog entry with
|
||||
* %gn, %ge, etc.; 'sb' cannot be updated, but we still need
|
||||
* to compute a valid return value.
|
||||
*/
|
||||
if (part == 'n' || part == 'e' || part == 't' || part == 'd'
|
||||
|| part == 'D' || part == 'r' || part == 'i')
|
||||
|
Loading…
Reference in New Issue
Block a user