2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
10 static int line_termination
= '\n';
11 #define LS_RECURSIVE 1
12 #define LS_TREE_ONLY 2
13 static int ls_options
= 0;
15 static struct tree_entry_list root_entry
;
17 static void prepare_root(unsigned char *sha1
)
19 unsigned char rsha
[20];
22 struct tree
*root_tree
;
24 buf
= read_object_with_reference(sha1
, "tree", &size
, rsha
);
27 die("Could not read %s", sha1_to_hex(sha1
));
29 root_tree
= lookup_tree(rsha
);
31 die("Could not read %s", sha1_to_hex(sha1
));
33 /* Prepare a fake entry */
34 root_entry
.directory
= 1;
35 root_entry
.executable
= root_entry
.symlink
= 0;
36 root_entry
.mode
= S_IFDIR
;
38 root_entry
.item
.tree
= root_tree
;
39 root_entry
.parent
= NULL
;
42 static int prepare_children(struct tree_entry_list
*elem
)
46 if (!elem
->item
.tree
->object
.parsed
) {
47 struct tree_entry_list
*e
;
48 if (parse_tree(elem
->item
.tree
))
50 /* Set up the parent link */
51 for (e
= elem
->item
.tree
->entries
; e
; e
= e
->next
)
57 static struct tree_entry_list
*find_entry_0(struct tree_entry_list
*elem
,
64 while (path
< path_end
) {
65 if (prepare_children(elem
))
68 /* In elem->tree->entries, find the one that has name
69 * that matches what is between path and ep.
71 elem
= elem
->item
.tree
->entries
;
73 ep
= strchr(path
, '/');
74 if (!ep
|| path_end
<= ep
)
79 if ((strlen(elem
->name
) == len
) &&
80 !strncmp(elem
->name
, path
, len
))
84 if (path_end
<= ep
|| !elem
)
86 while (*ep
== '/' && ep
< path_end
)
93 static struct tree_entry_list
*find_entry(const char *path
,
96 /* Find tree element, descending from root, that
97 * corresponds to the named path, lazily expanding
98 * the tree if possible.
100 if (path
== path_end
) {
101 /* Special. This is the root level */
104 return find_entry_0(&root_entry
, path
, path_end
);
107 static void show_entry_name(struct tree_entry_list
*e
)
109 /* This is yucky. The root level is there for
110 * our convenience but we really want to do a
113 if (e
->parent
&& e
->parent
!= &root_entry
) {
114 show_entry_name(e
->parent
);
117 printf("%s", e
->name
);
120 static const char *entry_type(struct tree_entry_list
*e
)
122 return (e
->directory
? "tree" : "blob");
125 static const char *entry_hex(struct tree_entry_list
*e
)
127 return sha1_to_hex(e
->directory
128 ? e
->item
.tree
->object
.sha1
129 : e
->item
.blob
->object
.sha1
);
132 /* forward declaration for mutually recursive routines */
133 static int show_entry(struct tree_entry_list
*, int);
135 static int show_children(struct tree_entry_list
*e
, int level
)
137 if (prepare_children(e
))
138 die("internal error: ls-tree show_children called with non tree");
139 e
= e
->item
.tree
->entries
;
141 show_entry(e
, level
);
147 static int show_entry(struct tree_entry_list
*e
, int level
)
151 if (e
!= &root_entry
) {
152 printf("%06o %s %s ", e
->mode
, entry_type(e
),
155 putchar(line_termination
);
159 /* If this is a directory, we have the following cases:
160 * (1) This is the top-level request (explicit path from the
161 * command line, or "root" if there is no command line).
162 * a. Without any flag. We show direct children. We do not
164 * b. With -r. We do recurse into children.
165 * c. With -d. We do not recurse into children.
166 * (2) We came here because our caller is either (1-a) or
168 * a. Without any flag. We do not show our children (which
169 * are grandchildren for the original request).
170 * b. With -r. We continue to recurse into our children.
171 * c. With -d. We should not have come here to begin with.
173 if (level
== 0 && !(ls_options
& LS_TREE_ONLY
))
174 /* case (1)-a and (1)-b */
175 err
= err
| show_children(e
, level
+1);
176 else if (level
&& ls_options
& LS_RECURSIVE
)
178 err
= err
| show_children(e
, level
+1);
183 static int list_one(const char *path
, const char *path_end
)
186 struct tree_entry_list
*e
= find_entry(path
, path_end
);
188 /* traditionally ls-tree does not complain about
189 * missing path. We may change this later to match
190 * what "/bin/ls -a" does, which is to complain.
194 err
= err
| show_entry(e
, 0);
198 static int list(char **path
)
202 for (i
= 0; path
[i
]; i
++) {
203 int len
= strlen(path
[i
]);
204 while (0 <= len
&& path
[i
][len
] == '/')
206 err
= err
| list_one(path
[i
], path
[i
] + len
);
211 static const char *ls_tree_usage
=
212 "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
214 int main(int argc
, char **argv
)
216 static char *path0
[] = { "", NULL
};
218 unsigned char sha1
[20];
220 while (1 < argc
&& argv
[1][0] == '-') {
221 switch (argv
[1][1]) {
223 line_termination
= 0;
226 ls_options
|= LS_RECURSIVE
;
229 ls_options
|= LS_TREE_ONLY
;
232 usage(ls_tree_usage
);
238 usage(ls_tree_usage
);
239 if (get_sha1(argv
[1], sha1
) < 0)
240 usage(ls_tree_usage
);
242 path
= (argc
== 2) ? path0
: (argv
+ 2);