ls-tree: major rewrite to do pathspec

git-ls-tree should be rewritten to use a pathspec the same way everybody
else does. Right now it's the odd man out: if you do

	git-ls-tree HEAD divers/char drivers/

it will show the same files _twice_, which is not how pathspecs in general
work.

How about this patch? It breaks some of the git-ls-tree tests, but it
makes git-ls-tree work a lot more like other git pathspec commands, and it
removes more than 150 lines by re-using the recursive tree traversal (but
the "-d" flag is gone for good, so I'm not pushing this too hard).

		Linus
diff --git a/tree.c b/tree.c
index 8b42a07..043f032 100644
--- a/tree.c
+++ b/tree.c
@@ -9,9 +9,16 @@
 
 static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-	int len = strlen(pathname);
-	unsigned int size = cache_entry_size(baselen + len);
-	struct cache_entry *ce = xmalloc(size);
+	int len;
+	unsigned int size;
+	struct cache_entry *ce;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = strlen(pathname);
+	size = cache_entry_size(baselen + len);
+	ce = xmalloc(size);
 
 	memset(ce, 0, size);
 
@@ -67,9 +74,10 @@
 	return 0;
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
-			       const char *base, int baselen,
-			       int stage, const char **match)
+int read_tree_recursive(void *buffer, unsigned long size,
+			const char *base, int baselen,
+			int stage, const char **match,
+			read_tree_fn_t fn)
 {
 	while (size) {
 		int len = strlen(buffer)+1;
@@ -86,6 +94,14 @@
 		if (!match_tree_entry(base, baselen, path, mode, match))
 			continue;
 
+		switch (fn(sha1, base, baselen, path, mode, stage)) {
+		case 0:
+			continue;
+		case READ_TREE_RECURSIVE:
+			break;;
+		default:
+			return -1;
+		}
 		if (S_ISDIR(mode)) {
 			int retval;
 			int pathlen = strlen(path);
@@ -106,22 +122,20 @@
 			retval = read_tree_recursive(eltbuf, eltsize,
 						     newbase,
 						     baselen + pathlen + 1,
-						     stage, match);
+						     stage, match, fn);
 			free(eltbuf);
 			free(newbase);
 			if (retval)
 				return -1;
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
-			return -1;
 	}
 	return 0;
 }
 
 int read_tree(void *buffer, unsigned long size, int stage, const char **match)
 {
-	return read_tree_recursive(buffer, size, "", 0, stage, match);
+	return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
 }
 
 struct tree *lookup_tree(const unsigned char *sha1)