1#include "cache.h"
2#include "tag.h"
3#include "commit.h"
4#include "tree.h"
5#include "blob.h"
67
const char *tag_type = "tag";
89
struct object *deref_tag(struct object *o, const char *warn, int warnlen)
10{
11while (o && o->type == OBJ_TAG)
12if (((struct tag *)o)->tagged)
13o = parse_object(((struct tag *)o)->tagged->sha1);
14else
15o = NULL;
16if (!o && warn) {
17if (!warnlen)
18warnlen = strlen(warn);
19error("missing object referenced by '%.*s'", warnlen, warn);
20}
21return o;
22}
2324
struct tag *lookup_tag(const unsigned char *sha1)
25{
26struct object *obj = lookup_object(sha1);
27if (!obj)
28return create_object(sha1, OBJ_TAG, alloc_tag_node());
29if (!obj->type)
30obj->type = OBJ_TAG;
31if (obj->type != OBJ_TAG) {
32error("Object %s is a %s, not a tag",
33sha1_to_hex(sha1), typename(obj->type));
34return NULL;
35}
36return (struct tag *) obj;
37}
3839
static unsigned long parse_tag_date(const char *buf, const char *tail)
40{
41const char *dateptr;
4243
while (buf < tail && *buf++ != '>')
44/* nada */;
45if (buf >= tail)
46return 0;
47dateptr = buf;
48while (buf < tail && *buf++ != '\n')
49/* nada */;
50if (buf >= tail)
51return 0;
52/* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
53return strtoul(dateptr, NULL, 10);
54}
5556
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
57{
58unsigned char sha1[20];
59char type[20];
60const char *bufptr = data;
61const char *tail = bufptr + size;
62const char *nl;
6364
if (item->object.parsed)
65return 0;
66item->object.parsed = 1;
6768
if (size < 64)
69return -1;
70if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
71return -1;
72bufptr += 48; /* "object " + sha1 + "\n" */
7374
if (prefixcmp(bufptr, "type "))
75return -1;
76bufptr += 5;
77nl = memchr(bufptr, '\n', tail - bufptr);
78if (!nl || sizeof(type) <= (nl - bufptr))
79return -1;
80strncpy(type, bufptr, nl - bufptr);
81type[nl - bufptr] = '\0';
82bufptr = nl + 1;
8384
if (!strcmp(type, blob_type)) {
85item->tagged = &lookup_blob(sha1)->object;
86} else if (!strcmp(type, tree_type)) {
87item->tagged = &lookup_tree(sha1)->object;
88} else if (!strcmp(type, commit_type)) {
89item->tagged = &lookup_commit(sha1)->object;
90} else if (!strcmp(type, tag_type)) {
91item->tagged = &lookup_tag(sha1)->object;
92} else {
93error("Unknown type %s", type);
94item->tagged = NULL;
95}
9697
if (prefixcmp(bufptr, "tag "))
98return -1;
99bufptr += 4;
100nl = memchr(bufptr, '\n', tail - bufptr);
101if (!nl)
102return -1;
103item->tag = xmemdupz(bufptr, nl - bufptr);
104bufptr = nl + 1;
105106
if (!prefixcmp(bufptr, "tagger "))
107item->date = parse_tag_date(bufptr, tail);
108else
109item->date = 0;
110111
return 0;
112}
113114
int parse_tag(struct tag *item)
115{
116enum object_type type;
117void *data;
118unsigned long size;
119int ret;
120121
if (item->object.parsed)
122return 0;
123data = read_sha1_file(item->object.sha1, &type, &size);
124if (!data)
125return error("Could not read %s",
126sha1_to_hex(item->object.sha1));
127if (type != OBJ_TAG) {
128free(data);
129return error("Object %s not a tag",
130sha1_to_hex(item->object.sha1));
131}
132ret = parse_tag_buffer(item, data, size);
133free(data);
134return ret;
135}