From 175785e5ff7395be8a458694a7df0511ac14e948 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 18 Apr 2005 11:39:48 -0700 Subject: [PATCH] [PATCH] Implementations of parsing functions This implements the parsing functions. Signed-Off-By: Daniel Barkalow Signed-off-by: Linus Torvalds --- blob.c | 24 ++++++++++++++ commit.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ object.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tree.c | 67 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 blob.c create mode 100644 commit.c create mode 100644 object.c create mode 100644 tree.c diff --git a/blob.c b/blob.c new file mode 100644 index 0000000000..35031af62b --- /dev/null +++ b/blob.c @@ -0,0 +1,24 @@ +#include "blob.h" +#include "cache.h" +#include + +const char *blob_type = "blob"; + +struct blob *lookup_blob(unsigned char *sha1) +{ + struct object *obj = lookup_object(sha1); + if (!obj) { + struct blob *ret = malloc(sizeof(struct blob)); + memset(ret, 0, sizeof(struct blob)); + created_object(sha1, &ret->object); + ret->object.type = blob_type; + ret->object.parsed = 1; + return ret; + } + if (obj->parsed && obj->type != blob_type) { + error("Object %s is a %s, not a blob", + sha1_to_hex(sha1), obj->type); + return NULL; + } + return (struct blob *) obj; +} diff --git a/commit.c b/commit.c new file mode 100644 index 0000000000..eda45d7e15 --- /dev/null +++ b/commit.c @@ -0,0 +1,85 @@ +#include "commit.h" +#include "cache.h" +#include + +const char *commit_type = "commit"; + +struct commit *lookup_commit(unsigned char *sha1) +{ + struct object *obj = lookup_object(sha1); + if (!obj) { + struct commit *ret = malloc(sizeof(struct commit)); + memset(ret, 0, sizeof(struct commit)); + created_object(sha1, &ret->object); + return ret; + } + if (obj->parsed && obj->type != commit_type) { + error("Object %s is a %s, not a commit", + sha1_to_hex(sha1), obj->type); + return NULL; + } + return (struct commit *) obj; +} + +static unsigned long parse_commit_date(const char *buf) +{ + unsigned long date; + + if (memcmp(buf, "author", 6)) + return 0; + while (*buf++ != '\n') + /* nada */; + if (memcmp(buf, "committer", 9)) + return 0; + while (*buf++ != '>') + /* nada */; + date = strtoul(buf, NULL, 10); + if (date == ULONG_MAX) + date = 0; + return date; +} + +int parse_commit(struct commit *item) +{ + char type[20]; + void * buffer, *bufptr; + unsigned long size; + unsigned char parent[20]; + if (item->object.parsed) + return 0; + item->object.parsed = 1; + buffer = bufptr = read_sha1_file(item->object.sha1, type, &size); + if (!buffer) + return error("Could not read %s", + sha1_to_hex(item->object.sha1)); + if (strcmp(type, commit_type)) + return error("Object %s not a commit", + sha1_to_hex(item->object.sha1)); + item->object.type = commit_type; + get_sha1_hex(bufptr + 5, parent); + item->tree = lookup_tree(parent); + add_ref(&item->object, &item->tree->object); + bufptr += 46; /* "tree " + "hex sha1" + "\n" */ + while (!memcmp(bufptr, "parent ", 7) && + !get_sha1_hex(bufptr + 7, parent)) { + struct commit_list *new_parent = + malloc(sizeof(struct commit_list)); + new_parent->next = item->parents; + new_parent->item = lookup_commit(parent); + add_ref(&item->object, &new_parent->item->object); + item->parents = new_parent; + bufptr += 48; + } + item->date = parse_commit_date(bufptr); + free(buffer); + return 0; +} + +void free_commit_list(struct commit_list *list) +{ + while (list) { + struct commit_list *temp = list; + list = temp->next; + free(temp); + } +} diff --git a/object.c b/object.c new file mode 100644 index 0000000000..cfa2337641 --- /dev/null +++ b/object.c @@ -0,0 +1,96 @@ +#include "object.h" +#include "cache.h" +#include +#include + +struct object **objs; +int nr_objs; +static int obj_allocs; + +static int find_object(unsigned char *sha1) +{ + int first = 0, last = nr_objs; + + while (first < last) { + int next = (first + last) / 2; + struct object *obj = objs[next]; + int cmp; + + cmp = memcmp(sha1, obj->sha1, 20); + if (!cmp) + return next; + if (cmp < 0) { + last = next; + continue; + } + first = next+1; + } + return -first-1; +} + +struct object *lookup_object(unsigned char *sha1) +{ + int pos = find_object(sha1); + if (pos >= 0) + return objs[pos]; + return NULL; +} + +void created_object(unsigned char *sha1, struct object *obj) +{ + int pos = find_object(sha1); + + obj->parsed = 0; + memcpy(obj->sha1, sha1, 20); + obj->type = NULL; + obj->refs = NULL; + obj->used = 0; + + if (pos >= 0) + die("Inserting %s twice\n", sha1_to_hex(sha1)); + pos = -pos-1; + + if (obj_allocs == nr_objs) { + obj_allocs = alloc_nr(obj_allocs); + objs = realloc(objs, obj_allocs * sizeof(struct object *)); + } + + /* Insert it into the right place */ + memmove(objs + pos + 1, objs + pos, (nr_objs - pos) * + sizeof(struct object *)); + + objs[pos] = obj; + nr_objs++; +} + +void add_ref(struct object *refer, struct object *target) +{ + struct object_list **pp = &refer->refs; + struct object_list *p; + + while ((p = *pp) != NULL) { + if (p->item == target) + return; + pp = &p->next; + } + + target->used = 1; + p = malloc(sizeof(*p)); + p->item = target; + p->next = NULL; + *pp = p; +} + +void mark_reachable(struct object *obj, unsigned int mask) +{ + struct object_list *p = obj->refs; + + /* If we've been here already, don't bother */ + if (obj->flags & mask) + return; + obj->flags |= mask; + while (p) { + mark_reachable(p->item, mask); + p = p->next; + } +} diff --git a/tree.c b/tree.c new file mode 100644 index 0000000000..1aee098117 --- /dev/null +++ b/tree.c @@ -0,0 +1,67 @@ +#include "tree.h" +#include "blob.h" +#include "cache.h" +#include + +const char *tree_type = "tree"; + +struct tree *lookup_tree(unsigned char *sha1) +{ + struct object *obj = lookup_object(sha1); + if (!obj) { + struct tree *ret = malloc(sizeof(struct tree)); + memset(ret, 0, sizeof(struct tree)); + created_object(sha1, &ret->object); + return ret; + } + if (obj->parsed && obj->type != tree_type) { + error("Object %s is a %s, not a tree", + sha1_to_hex(sha1), obj->type); + return NULL; + } + return (struct tree *) obj; +} + +int parse_tree(struct tree *item) +{ + char type[20]; + void *buffer, *bufptr; + unsigned long size; + if (item->object.parsed) + return 0; + item->object.parsed = 1; + item->object.type = tree_type; + buffer = bufptr = read_sha1_file(item->object.sha1, type, &size); + if (!buffer) + return error("Could not read %s", + sha1_to_hex(item->object.sha1)); + if (strcmp(type, tree_type)) + return error("Object %s not a tree", + sha1_to_hex(item->object.sha1)); + while (size) { + struct object *obj; + int len = 1+strlen(bufptr); + unsigned char *file_sha1 = bufptr + len; + char *path = strchr(bufptr, ' '); + unsigned int mode; + if (size < len + 20 || !path || + sscanf(bufptr, "%o", &mode) != 1) + return -1; + + /* Warn about trees that don't do the recursive thing.. */ + if (strchr(path, '/')) { + item->has_full_path = 1; + } + + bufptr += len + 20; + size -= len + 20; + + if (S_ISDIR(mode)) { + obj = &lookup_tree(file_sha1)->object; + } else { + obj = &lookup_blob(file_sha1)->object; + } + add_ref(&item->object, obj); + } + return 0; +}