]>
git.proxmox.com Git - libgit2.git/blob - src/signature.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "repository.h"
11 #include "git2/common.h"
13 void git_signature_free(git_signature
*sig
)
20 git__free(sig
->email
);
25 static const char *skip_leading_spaces(const char *buffer
, const char *buffer_end
)
27 while (*buffer
== ' ' && buffer
< buffer_end
)
33 static const char *skip_trailing_spaces(const char *buffer_start
, const char *buffer_end
)
35 while (*buffer_end
== ' ' && buffer_end
> buffer_start
)
41 static int signature_error(const char *msg
)
43 giterr_set(GITERR_INVALID
, "Failed to parse signature - %s", msg
);
47 static int process_trimming(const char *input
, char **storage
, const char *input_end
, int fail_when_empty
)
49 const char *left
, *right
;
50 size_t trimmed_input_length
;
54 left
= skip_leading_spaces(input
, input_end
);
55 right
= skip_trailing_spaces(input
, input_end
- 1);
59 return signature_error("input is either empty of contains only spaces");
64 trimmed_input_length
= right
- left
+ 1;
66 *storage
= git__malloc(trimmed_input_length
+ 1);
67 GITERR_CHECK_ALLOC(*storage
);
69 memcpy(*storage
, left
, trimmed_input_length
);
70 (*storage
)[trimmed_input_length
] = 0;
75 int git_signature_new(git_signature
**sig_out
, const char *name
, const char *email
, git_time_t time
, int offset
)
78 git_signature
*p
= NULL
;
80 assert(name
&& email
);
84 p
= git__calloc(1, sizeof(git_signature
));
85 GITERR_CHECK_ALLOC(p
);
87 if ((error
= process_trimming(name
, &p
->name
, name
+ strlen(name
), 1)) < 0 ||
88 (error
= process_trimming(email
, &p
->email
, email
+ strlen(email
), 1)) < 0)
90 git_signature_free(p
);
95 p
->when
.offset
= offset
;
102 git_signature
*git_signature_dup(const git_signature
*sig
)
105 if (git_signature_new(&new, sig
->name
, sig
->email
, sig
->when
.time
, sig
->when
.offset
) < 0)
110 int git_signature_now(git_signature
**sig_out
, const char *name
, const char *email
)
114 struct tm
*utc_tm
, *local_tm
;
116 struct tm _utc
, _local
;
122 utc_tm
= p_gmtime_r(&now
, &_utc
);
123 local_tm
= p_localtime_r(&now
, &_local
);
125 offset
= mktime(local_tm
) - mktime(utc_tm
);
128 /* mktime takes care of setting tm_isdst correctly */
129 if (local_tm
->tm_isdst
)
132 if (git_signature_new(&sig
, name
, email
, now
, (int)offset
) < 0)
140 static int timezone_error(const char *msg
)
142 giterr_set(GITERR_INVALID
, "Failed to parse TZ offset - %s", msg
);
146 static int parse_timezone_offset(const char *buffer
, int *offset_out
)
149 int mins
, hours
, offset
;
151 const char *offset_start
;
152 const char *offset_end
;
154 offset_start
= buffer
;
156 if (*offset_start
== '\n') {
161 if (offset_start
[0] != '-' && offset_start
[0] != '+')
162 return timezone_error("does not start with '+' or '-'");
164 if (offset_start
[1] < '0' || offset_start
[1] > '9')
165 return timezone_error("expected initial digit");
167 if (git__strtol32(&dec_offset
, offset_start
+ 1, &offset_end
, 10) < 0)
168 return timezone_error("not a valid number");
170 if (offset_end
- offset_start
!= 5)
171 return timezone_error("invalid length");
173 if (dec_offset
> 1400)
174 return timezone_error("value too large");
176 hours
= dec_offset
/ 100;
177 mins
= dec_offset
% 100;
179 if (hours
> 14) // see http://www.worldtimezone.com/faq.html
180 return timezone_error("hour value too large");
183 return timezone_error("minutes value too large");
185 offset
= (hours
* 60) + mins
;
187 if (offset_start
[0] == '-')
190 *offset_out
= offset
;
195 static int process_next_token(const char **buffer_out
, char **storage
,
196 const char *token_end
, const char *right_boundary
)
198 int error
= process_trimming(*buffer_out
, storage
, token_end
, 0);
202 *buffer_out
= token_end
+ 1;
204 if (*buffer_out
> right_boundary
)
205 return signature_error("signature is too short");
210 static const char *scan_for_previous_token(const char *buffer
, const char *left_boundary
)
214 if (buffer
<= left_boundary
)
217 start
= skip_trailing_spaces(left_boundary
, buffer
);
219 /* Search for previous occurence of space */
220 while (start
[-1] != ' ' && start
> left_boundary
)
226 static int parse_time(git_time_t
*time_out
, const char *buffer
)
231 if (*buffer
== '+' || *buffer
== '-') {
232 giterr_set(GITERR_INVALID
, "Failed while parsing time. '%s' actually looks like a timezone offset.", buffer
);
236 error
= git__strtol32(&time
, buffer
, &buffer
, 10);
239 *time_out
= (git_time_t
)time
;
244 int git_signature__parse(git_signature
*sig
, const char **buffer_out
,
245 const char *buffer_end
, const char *header
, char ender
)
247 const char *buffer
= *buffer_out
;
248 const char *line_end
, *name_end
, *email_end
, *tz_start
, *time_start
;
251 memset(sig
, 0x0, sizeof(git_signature
));
253 if ((line_end
= memchr(buffer
, ender
, buffer_end
- buffer
)) == NULL
)
254 return signature_error("no newline given");
257 const size_t header_len
= strlen(header
);
259 if (memcmp(buffer
, header
, header_len
) != 0)
260 return signature_error("expected prefix doesn't match actual");
262 buffer
+= header_len
;
265 if (buffer
> line_end
)
266 return signature_error("signature too short");
268 if ((name_end
= strchr(buffer
, '<')) == NULL
)
269 return signature_error("character '<' not allowed in signature");
271 if ((email_end
= strchr(name_end
, '>')) == NULL
)
272 return signature_error("character '>' not allowed in signature");
274 if (email_end
< name_end
)
275 return signature_error("malformed e-mail");
277 error
= process_next_token(&buffer
, &sig
->name
, name_end
, line_end
);
281 error
= process_next_token(&buffer
, &sig
->email
, email_end
, line_end
);
285 tz_start
= scan_for_previous_token(line_end
- 1, buffer
);
287 if (tz_start
== NULL
)
288 goto clean_exit
; /* No timezone nor date */
290 time_start
= scan_for_previous_token(tz_start
- 1, buffer
);
291 if (time_start
== NULL
|| parse_time(&sig
->when
.time
, time_start
) < 0) {
292 /* The tz_start might point at the time */
293 parse_time(&sig
->when
.time
, tz_start
);
297 if (parse_timezone_offset(tz_start
, &sig
->when
.offset
) < 0) {
298 sig
->when
.time
= 0; /* Bogus timezone, we reset the time */
302 *buffer_out
= line_end
+ 1;
306 void git_signature__writebuf(git_buf
*buf
, const char *header
, const git_signature
*sig
)
308 int offset
, hours
, mins
;
311 offset
= sig
->when
.offset
;
312 sign
= (sig
->when
.offset
< 0) ? '-' : '+';
320 git_buf_printf(buf
, "%s%s <%s> %u %c%02d%02d\n",
321 header
? header
: "", sig
->name
, sig
->email
,
322 (unsigned)sig
->when
.time
, sign
, hours
, mins
);