Commit 5cccfa89 by Vicent Marti

Merge branch 'timezone-offset' of https://github.com/nulltoken/libgit2 into timezone

parents e0d9e12e b76d984e
...@@ -159,6 +159,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int ...@@ -159,6 +159,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
return error; return error;
commit->commit_time = commit->committer->time; commit->commit_time = commit->committer->time;
commit->commit_timezone_offset = commit->committer->timezone_offset;
/* parse commit message */ /* parse commit message */
while (buffer <= buffer_end && *buffer == '\n') while (buffer <= buffer_end && *buffer == '\n')
...@@ -249,6 +250,19 @@ time_t git_commit_time(git_commit *commit) ...@@ -249,6 +250,19 @@ time_t git_commit_time(git_commit *commit)
return commit->commit_time; return commit->commit_time;
} }
int git_commit_timezone_offset(git_commit *commit)
{
assert(commit);
if (commit->commit_timezone_offset)
return commit->commit_timezone_offset;
if (!commit->object.in_memory)
git_commit__parse_full(commit);
return commit->commit_timezone_offset;
}
unsigned int git_commit_parentcount(git_commit *commit) unsigned int git_commit_parentcount(git_commit *commit)
{ {
assert(commit); assert(commit);
...@@ -269,24 +283,24 @@ void git_commit_set_tree(git_commit *commit, git_tree *tree) ...@@ -269,24 +283,24 @@ void git_commit_set_tree(git_commit *commit, git_tree *tree)
commit->tree = tree; commit->tree = tree;
} }
void git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time) void git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time, int offset)
{ {
assert(commit && name && email); assert(commit && name && email);
commit->object.modified = 1; commit->object.modified = 1;
CHECK_FULL_PARSE(); CHECK_FULL_PARSE();
git_person__free(commit->author); git_person__free(commit->author);
commit->author = git_person__new(name, email, time); commit->author = git_person__new(name, email, time, offset);
} }
void git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time) void git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time, int offset)
{ {
assert(commit && name && email); assert(commit && name && email);
commit->object.modified = 1; commit->object.modified = 1;
CHECK_FULL_PARSE(); CHECK_FULL_PARSE();
git_person__free(commit->committer); git_person__free(commit->committer);
commit->committer = git_person__new(name, email, time); commit->committer = git_person__new(name, email, time, offset);
commit->commit_time = time; commit->commit_time = time;
} }
......
...@@ -12,6 +12,8 @@ struct git_commit { ...@@ -12,6 +12,8 @@ struct git_commit {
git_object object; git_object object;
time_t commit_time; time_t commit_time;
int commit_timezone_offset;
git_vector parents; git_vector parents;
git_tree *tree; git_tree *tree;
......
...@@ -93,6 +93,13 @@ GIT_EXTERN(const char *) git_commit_message(git_commit *commit); ...@@ -93,6 +93,13 @@ GIT_EXTERN(const char *) git_commit_message(git_commit *commit);
GIT_EXTERN(time_t) git_commit_time(git_commit *commit); GIT_EXTERN(time_t) git_commit_time(git_commit *commit);
/** /**
* Get the commit timezone offset (i.e. committer's preferred timezone) of a commit.
* @param commit a previously loaded commit.
* @return positive or negative timezone offset, in minutes from UTC
*/
GIT_EXTERN(int) git_commit_timezone_offset(git_commit *commit);
/**
* Get the committer of a commit. * Get the committer of a commit.
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the committer of a commit * @return the committer of a commit
...@@ -150,8 +157,9 @@ GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message) ...@@ -150,8 +157,9 @@ GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message)
* @param name name of the new committer * @param name name of the new committer
* @param email email of the new committer * @param email email of the new committer
* @param time time when the committer committed the commit * @param time time when the committer committed the commit
* @param offset committer positive or negative timezone offset, in minutes from UTC
*/ */
GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time); GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time, int offset);
/** /**
* Set the author of a commit * Set the author of a commit
...@@ -159,8 +167,9 @@ GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const char *name, ...@@ -159,8 +167,9 @@ GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const char *name,
* @param name name of the new author * @param name name of the new author
* @param email email of the new author * @param email email of the new author
* @param time time when the author created the commit * @param time time when the author created the commit
* @param offset author positive or negative timezone offset, in minutes from UTC
*/ */
GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time); GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time, int offset);
/** /**
* Set the tree which is pointed to by a commit * Set the tree which is pointed to by a commit
......
...@@ -143,6 +143,7 @@ typedef struct git_person git_person; ...@@ -143,6 +143,7 @@ typedef struct git_person git_person;
const char *git_person_name(git_person *person); const char *git_person_name(git_person *person);
const char *git_person_email(git_person *person); const char *git_person_email(git_person *person);
time_t git_person_time(git_person *person); time_t git_person_time(git_person *person);
int git_person_timezone_offset(git_person *person);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -125,8 +125,9 @@ GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name); ...@@ -125,8 +125,9 @@ GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name);
* @param name the name of the new tagger * @param name the name of the new tagger
* @param email the email of the new tagger * @param email the email of the new tagger
* @param time the time when the tag was created * @param time the time when the tag was created
* @param offset tagger positive or negative timezone offset, in minutes from UTC
*/ */
GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time); GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time, int offset);
/** /**
* Set the message of a tag * Set the message of a tag
......
...@@ -38,7 +38,7 @@ void git_person__free(git_person *person) ...@@ -38,7 +38,7 @@ void git_person__free(git_person *person)
free(person); free(person);
} }
git_person *git_person__new(const char *name, const char *email, time_t time) git_person *git_person__new(const char *name, const char *email, time_t time, int offset)
{ {
git_person *p; git_person *p;
...@@ -48,6 +48,7 @@ git_person *git_person__new(const char *name, const char *email, time_t time) ...@@ -48,6 +48,7 @@ git_person *git_person__new(const char *name, const char *email, time_t time)
p->name = git__strdup(name); p->name = git__strdup(name);
p->email = git__strdup(email); p->email = git__strdup(email);
p->time = time; p->time = time;
p->timezone_offset = offset;
if (p->name == NULL || p->email == NULL) if (p->name == NULL || p->email == NULL)
goto cleanup; goto cleanup;
...@@ -74,6 +75,57 @@ time_t git_person_time(git_person *person) ...@@ -74,6 +75,57 @@ time_t git_person_time(git_person *person)
return person->time; return person->time;
} }
int git_person_timezone_offset(git_person *person)
{
return person->timezone_offset;
}
int git_person__parse_timezone_offset(const char *buffer, int *offset_out)
{
int offset, dec_offset;
int mins, hours;
const char* offset_start;
char* offset_end;
offset_start = buffer + 1;
if (*offset_start == '\n')
{
*offset_out = 0;
return GIT_SUCCESS;
}
if (offset_start[0] != '-' && offset_start[0] != '+')
return GIT_EOBJCORRUPTED;
dec_offset = strtol(offset_start + 1, &offset_end, 10);
if (offset_end - offset_start != 5)
return GIT_EOBJCORRUPTED;
hours = dec_offset / 100;
mins = dec_offset % 100;
if (hours > 14) // see http://www.worldtimezone.com/faq.html
return GIT_EOBJCORRUPTED;
if (mins > 59)
return GIT_EOBJCORRUPTED;
offset = (hours * 60) + mins;
if (offset_start[0] == '-')
{
offset *= -1;
}
*offset_out = offset;
return GIT_SUCCESS;
}
int git_person__parse(git_person *person, char **buffer_out, int git_person__parse(git_person *person, char **buffer_out,
const char *buffer_end, const char *header) const char *buffer_end, const char *header)
{ {
...@@ -82,6 +134,7 @@ int git_person__parse(git_person *person, char **buffer_out, ...@@ -82,6 +134,7 @@ int git_person__parse(git_person *person, char **buffer_out,
int name_length, email_length; int name_length, email_length;
char *buffer = *buffer_out; char *buffer = *buffer_out;
char *line_end, *name_end, *email_end; char *line_end, *name_end, *email_end;
int offset = 0;
memset(person, 0x0, sizeof(git_person)); memset(person, 0x0, sizeof(git_person));
...@@ -128,13 +181,30 @@ int git_person__parse(git_person *person, char **buffer_out, ...@@ -128,13 +181,30 @@ int git_person__parse(git_person *person, char **buffer_out,
if (person->time == 0) if (person->time == 0)
return GIT_EOBJCORRUPTED; return GIT_EOBJCORRUPTED;
if (git_person__parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)
return GIT_EOBJCORRUPTED;
person->timezone_offset = offset;
*buffer_out = (line_end + 1); *buffer_out = (line_end + 1);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_person__write(git_odb_source *src, const char *header, const git_person *person) int git_person__write(git_odb_source *src, const char *header, const git_person *person)
{ {
return git__source_printf(src, "%s %s <%s> %u\n", header, person->name, person->email, person->time); char *sign;
int offset, hours, mins;
offset = person->timezone_offset;
sign = (person->timezone_offset < 0) ? "-" : "+";
if (offset < 0)
offset = -offset;
hours = offset / 60;
mins = offset % 60;
return git__source_printf(src, "%s %s <%s> %u %s%02d%02d\n", header, person->name, person->email, person->time, sign, hours, mins);
} }
...@@ -10,10 +10,11 @@ struct git_person { ...@@ -10,10 +10,11 @@ struct git_person {
char *name; /**< Full name */ char *name; /**< Full name */
char *email; /**< Email address */ char *email; /**< Email address */
time_t time; /**< Time when this person committed the change */ time_t time; /**< Time when this person committed the change */
int timezone_offset; /**< Time zone offset in minutes. Can be either positive or negative. */
}; };
void git_person__free(git_person *person); void git_person__free(git_person *person);
git_person *git_person__new(const char *name, const char *email, time_t time); git_person *git_person__new(const char *name, const char *email, time_t time, int offset);
int git_person__parse(git_person *person, char **buffer_out, const char *buffer_end, const char *header); int git_person__parse(git_person *person, char **buffer_out, const char *buffer_end, const char *header);
int git_person__write(git_odb_source *src, const char *header, const git_person *person); int git_person__write(git_odb_source *src, const char *header, const git_person *person);
......
...@@ -97,13 +97,13 @@ const git_person *git_tag_tagger(git_tag *t) ...@@ -97,13 +97,13 @@ const git_person *git_tag_tagger(git_tag *t)
return t->tagger; return t->tagger;
} }
void git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time) void git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time, int offset)
{ {
assert(tag && name && email); assert(tag && name && email);
tag->object.modified = 1; tag->object.modified = 1;
git_person__free(tag->tagger); git_person__free(tag->tagger);
tag->tagger = git_person__new(name, email, time); tag->tagger = git_person__new(name, email, time, offset);
} }
const char *git_tag_message(git_tag *t) const char *git_tag_message(git_tag *t)
......
...@@ -131,7 +131,7 @@ END_TEST ...@@ -131,7 +131,7 @@ END_TEST
BEGIN_TEST(parse_person_test) BEGIN_TEST(parse_person_test)
#define TEST_PERSON_PASS(_string, _header, _name, _email, _time) { \ #define TEST_PERSON_PASS(_string, _header, _name, _email, _time, _offset) { \
char *ptr = _string; \ char *ptr = _string; \
size_t len = strlen(_string);\ size_t len = strlen(_string);\
git_person person = {NULL, NULL, 0}; \ git_person person = {NULL, NULL, 0}; \
...@@ -139,6 +139,7 @@ BEGIN_TEST(parse_person_test) ...@@ -139,6 +139,7 @@ BEGIN_TEST(parse_person_test)
must_be_true(strcmp(_name, person.name) == 0);\ must_be_true(strcmp(_name, person.name) == 0);\
must_be_true(strcmp(_email, person.email) == 0);\ must_be_true(strcmp(_email, person.email) == 0);\
must_be_true(_time == person.time);\ must_be_true(_time == person.time);\
must_be_true(_offset == person.timezone_offset);\
free(person.name); free(person.email);\ free(person.name); free(person.email);\
} }
...@@ -151,25 +152,28 @@ BEGIN_TEST(parse_person_test) ...@@ -151,25 +152,28 @@ BEGIN_TEST(parse_person_test)
} }
TEST_PERSON_PASS( TEST_PERSON_PASS(
"author Vicent Marti <tanoku@gmail.com> 12345 \n", "author Vicent Marti <tanoku@gmail.com> 12345 \n",
"author ", "author ",
"Vicent Marti", "Vicent Marti",
"tanoku@gmail.com", "tanoku@gmail.com",
12345); 12345,
0);
TEST_PERSON_PASS( TEST_PERSON_PASS(
"author Vicent Marti <> 12345 \n", "author Vicent Marti <> 12345 \n",
"author ", "author ",
"Vicent Marti", "Vicent Marti",
"", "",
12345); 12345,
0);
TEST_PERSON_PASS( TEST_PERSON_PASS(
"author Vicent Marti <tanoku@gmail.com> 231301 +2020\n", "author Vicent Marti <tanoku@gmail.com> 231301 +1020\n",
"author ", "author ",
"Vicent Marti", "Vicent Marti",
"tanoku@gmail.com", "tanoku@gmail.com",
231301); 231301,
620);
TEST_PERSON_PASS( TEST_PERSON_PASS(
"author Vicent Marti with an outrageously long name \ "author Vicent Marti with an outrageously long name \
...@@ -178,7 +182,8 @@ BEGIN_TEST(parse_person_test) ...@@ -178,7 +182,8 @@ BEGIN_TEST(parse_person_test)
"Vicent Marti with an outrageously long name \ "Vicent Marti with an outrageously long name \
which will probably overflow the buffer", which will probably overflow the buffer",
"tanoku@gmail.com", "tanoku@gmail.com",
12345); 12345,
0);
TEST_PERSON_PASS( TEST_PERSON_PASS(
"author Vicent Marti <tanokuwithaveryveryverylongemail\ "author Vicent Marti <tanokuwithaveryveryverylongemail\
...@@ -187,7 +192,40 @@ BEGIN_TEST(parse_person_test) ...@@ -187,7 +192,40 @@ BEGIN_TEST(parse_person_test)
"Vicent Marti", "Vicent Marti",
"tanokuwithaveryveryverylongemail\ "tanokuwithaveryveryverylongemail\
whichwillprobablyvoverflowtheemailbuffer@gmail.com", whichwillprobablyvoverflowtheemailbuffer@gmail.com",
12345); 12345,
0);
TEST_PERSON_PASS(
"committer Vicent Marti <tanoku@gmail.com> 123456 +0000 \n",
"committer ",
"Vicent Marti",
"tanoku@gmail.com",
123456,
0);
TEST_PERSON_PASS(
"committer Vicent Marti <tanoku@gmail.com> 123456 +0100 \n",
"committer ",
"Vicent Marti",
"tanoku@gmail.com",
123456,
60);
TEST_PERSON_PASS(
"committer Vicent Marti <tanoku@gmail.com> 123456 -0100 \n",
"committer ",
"Vicent Marti",
"tanoku@gmail.com",
123456,
-60);
TEST_PERSON_FAIL(
"committer Vicent Marti <tanoku@gmail.com> 123456 -1500 \n",
"committer ");
TEST_PERSON_FAIL(
"committer Vicent Marti <tanoku@gmail.com> 123456 +0163 \n",
"committer ");
TEST_PERSON_FAIL( TEST_PERSON_FAIL(
"author Vicent Marti <tanoku@gmail.com> 12345 \n", "author Vicent Marti <tanoku@gmail.com> 12345 \n",
......
...@@ -42,8 +42,8 @@ BEGIN_TEST(writenew_test) ...@@ -42,8 +42,8 @@ BEGIN_TEST(writenew_test)
git_commit_add_parent(commit, parent); git_commit_add_parent(commit, parent);
/* Set other attributes */ /* Set other attributes */
git_commit_set_committer(commit, COMMITTER_NAME, COMMITTER_EMAIL, 123456789); git_commit_set_committer(commit, COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60);
git_commit_set_author(commit, COMMITTER_NAME, COMMITTER_EMAIL, 987654321); git_commit_set_author(commit, COMMITTER_NAME, COMMITTER_EMAIL, 987654321, 90);
git_commit_set_message(commit, COMMIT_MESSAGE); git_commit_set_message(commit, COMMIT_MESSAGE);
/* Check attributes were set correctly */ /* Check attributes were set correctly */
...@@ -52,13 +52,16 @@ BEGIN_TEST(writenew_test) ...@@ -52,13 +52,16 @@ BEGIN_TEST(writenew_test)
must_be_true(strcmp(author->name, COMMITTER_NAME) == 0); must_be_true(strcmp(author->name, COMMITTER_NAME) == 0);
must_be_true(strcmp(author->email, COMMITTER_EMAIL) == 0); must_be_true(strcmp(author->email, COMMITTER_EMAIL) == 0);
must_be_true(author->time == 987654321); must_be_true(author->time == 987654321);
must_be_true(author->time_offset == 90);
committer = git_commit_committer(commit); committer = git_commit_committer(commit);
must_be_true(committer != NULL); must_be_true(committer != NULL);
must_be_true(strcmp(committer->name, COMMITTER_NAME) == 0); must_be_true(strcmp(committer->name, COMMITTER_NAME) == 0);
must_be_true(strcmp(committer->email, COMMITTER_EMAIL) == 0); must_be_true(strcmp(committer->email, COMMITTER_EMAIL) == 0);
must_be_true(committer->time == 123456789); must_be_true(committer->time == 123456789);
must_be_true(committer->time_offset == 60);
must_be_true(git_commit_time(commit) == 123456789); must_be_true(git_commit_time(commit) == 123456789);
must_be_true(git_commit_time_offset(commit) == 60);
must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0); must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment