ls-tree.c 4.1 KB
Newer Older
P
Petr Baudis 已提交
1 2 3 4 5 6 7
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 */
#include "cache.h"

L
Linus Torvalds 已提交
8 9
static int line_termination = '\n';
static int recursive = 0;
J
Junio C Hamano 已提交
10 11 12 13 14 15

struct path_prefix {
	struct path_prefix *prev;
	const char *name;
};

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#define DEBUG(fmt, ...)	

static int string_path_prefix(char *buff, size_t blen, struct path_prefix *prefix)
{
	int len = 0;
	if (prefix) {
		if (prefix->prev) {
			len = string_path_prefix(buff,blen,prefix->prev);
			buff += len;
			blen -= len;
			if (blen > 0) {
				*buff = '/';
				len++;
				buff++;
				blen--;
			}
		}
		strncpy(buff,prefix->name,blen);
		return len + strlen(prefix->name);
	}

	return 0;
}

J
Junio C Hamano 已提交
40
static void print_path_prefix(struct path_prefix *prefix)
P
Petr Baudis 已提交
41
{
J
Junio C Hamano 已提交
42
	if (prefix) {
43
		if (prefix->prev) {
J
Junio C Hamano 已提交
44
			print_path_prefix(prefix->prev);
45 46
			putchar('/');
		}
J
Junio C Hamano 已提交
47 48 49 50
		fputs(prefix->name, stdout);
	}
}

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/*
 * return:
 * 	-1 if prefix is *not* a subset of path
 * 	 0 if prefix == path
 * 	 1 if prefix is a subset of path
 */
static int pathcmp(const char *path, struct path_prefix *prefix)
{
	char buff[PATH_MAX];
	int len,slen;

	if (prefix == NULL)
		return 1;

	len = string_path_prefix(buff, sizeof buff, prefix);
	slen = strlen(path);

	if (slen < len)
		return -1;

	if (strncmp(path,buff,len) == 0) {
		if (slen == len)
			return 0;
		else
			return 1;
	}

	return -1;
}	

/*
 * match may be NULL, or a *sorted* list of paths
 */
J
Junio C Hamano 已提交
84
static void list_recursive(void *buffer,
85
			   const char *type,
86
			   unsigned long size,
87 88
			   struct path_prefix *prefix,
			   char **match, int matches)
J
Junio C Hamano 已提交
89 90 91
{
	struct path_prefix this_prefix;
	this_prefix.prev = prefix;
P
Petr Baudis 已提交
92 93

	if (strcmp(type, "tree"))
94
		die("expected a 'tree' node");
J
Junio C Hamano 已提交
95

96 97 98
	if (matches)
		recursive = 1;

P
Petr Baudis 已提交
99
	while (size) {
J
Junio C Hamano 已提交
100
		int namelen = strlen(buffer)+1;
101
		void *eltbuf = NULL;
J
Junio C Hamano 已提交
102 103 104 105
		char elttype[20];
		unsigned long eltsize;
		unsigned char *sha1 = buffer + namelen;
		char *path = strchr(buffer, ' ') + 1;
P
Petr Baudis 已提交
106
		unsigned int mode;
107 108 109
		const char *matched = NULL;
		int mtype = -1;
		int mindex;
P
Petr Baudis 已提交
110

J
Junio C Hamano 已提交
111
		if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1)
112
			die("corrupt 'tree' file");
P
Petr Baudis 已提交
113
		buffer = sha1 + 20;
J
Junio C Hamano 已提交
114 115
		size -= namelen + 20;

116 117 118 119 120 121 122 123 124 125 126 127 128 129
		this_prefix.name = path;
		for ( mindex = 0; mindex < matches; mindex++) {
			mtype = pathcmp(match[mindex],&this_prefix);
			if (mtype >= 0) {
				matched = match[mindex];
				break;
			}
		}

		/*
		 * If we're not matching, or if this is an exact match,
		 * print out the info
		 */
		if (!matches || (matched != NULL && mtype == 0)) {
130
			printf("%06o %s %s\t", mode,
131 132 133 134 135
			       S_ISDIR(mode) ? "tree" : "blob",
			       sha1_to_hex(sha1));
			print_path_prefix(&this_prefix);
			putchar(line_termination);
		}
J
Junio C Hamano 已提交
136

137 138 139
		if (! recursive || ! S_ISDIR(mode))
			continue;

140 141 142
		if (matches && ! matched)
			continue;

143 144 145
		if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) {
			error("cannot read %s", sha1_to_hex(sha1));
			continue;
J
Junio C Hamano 已提交
146
		}
147 148 149 150 151 152 153 154 155 156

		/* If this is an exact directory match, we may have
		 * directory files following this path. Match on them.
		 * Otherwise, we're at a pach subcomponent, and we need
		 * to try to match again.
		 */
		if (mtype == 0)
			mindex++;

		list_recursive(eltbuf, elttype, eltsize, &this_prefix, &match[mindex], matches-mindex);
J
Junio C Hamano 已提交
157
		free(eltbuf);
P
Petr Baudis 已提交
158
	}
J
Junio C Hamano 已提交
159 160
}

161 162 163 164 165 166
static int qcmp(const void *a, const void *b)
{
	return strcmp(*(char **)a, *(char **)b);
}

static int list(unsigned char *sha1,char **path)
J
Junio C Hamano 已提交
167 168 169
{
	void *buffer;
	unsigned long size;
170 171 172 173 174 175
	int npaths;

	for (npaths = 0; path[npaths] != NULL; npaths++)
		;

	qsort(path,npaths,sizeof(char *),qcmp);
J
Junio C Hamano 已提交
176

L
Linus Torvalds 已提交
177
	buffer = read_object_with_reference(sha1, "tree", &size, NULL);
J
Junio C Hamano 已提交
178 179
	if (!buffer)
		die("unable to read sha1 file");
180
	list_recursive(buffer, "tree", size, NULL, path, npaths);
I
Ingo Molnar 已提交
181
	free(buffer);
P
Petr Baudis 已提交
182 183 184
	return 0;
}

185
static const char *ls_tree_usage = "git-ls-tree [-r] [-z] <key> [paths...]";
J
Junio C Hamano 已提交
186

P
Petr Baudis 已提交
187 188 189 190
int main(int argc, char **argv)
{
	unsigned char sha1[20];

J
Junio C Hamano 已提交
191 192 193 194 195 196 197 198 199
	while (1 < argc && argv[1][0] == '-') {
		switch (argv[1][1]) {
		case 'z':
			line_termination = 0;
			break;
		case 'r':
			recursive = 1;
			break;
		default:
200
			usage(ls_tree_usage);
J
Junio C Hamano 已提交
201 202 203 204
		}
		argc--; argv++;
	}

205
	if (argc < 2)
206
		usage(ls_tree_usage);
207
	if (get_sha1(argv[1], sha1) < 0)
208
		usage(ls_tree_usage);
209
	if (list(sha1, &argv[2]) < 0)
210
		die("list failed");
P
Petr Baudis 已提交
211 212
	return 0;
}