]>
Commit | Line | Data |
---|---|---|
7912c070 PB |
1 | /* |
2 | * GIT - The information manager from hell | |
3 | * | |
4 | * Copyright (C) Linus Torvalds, 2005 | |
5 | */ | |
6 | #include "cache.h" | |
7 | ||
e99d59ff LT |
8 | static int line_termination = '\n'; |
9 | static int recursive = 0; | |
aa1c48df JH |
10 | |
11 | struct path_prefix { | |
12 | struct path_prefix *prev; | |
13 | const char *name; | |
14 | }; | |
15 | ||
6d3a5077 JM |
16 | #define DEBUG(fmt, ...) |
17 | ||
18 | static int string_path_prefix(char *buff, size_t blen, struct path_prefix *prefix) | |
19 | { | |
20 | int len = 0; | |
21 | if (prefix) { | |
22 | if (prefix->prev) { | |
23 | len = string_path_prefix(buff,blen,prefix->prev); | |
24 | buff += len; | |
25 | blen -= len; | |
26 | if (blen > 0) { | |
27 | *buff = '/'; | |
28 | len++; | |
29 | buff++; | |
30 | blen--; | |
31 | } | |
32 | } | |
33 | strncpy(buff,prefix->name,blen); | |
34 | return len + strlen(prefix->name); | |
35 | } | |
36 | ||
37 | return 0; | |
38 | } | |
39 | ||
aa1c48df | 40 | static void print_path_prefix(struct path_prefix *prefix) |
7912c070 | 41 | { |
aa1c48df | 42 | if (prefix) { |
6d3a5077 | 43 | if (prefix->prev) { |
aa1c48df | 44 | print_path_prefix(prefix->prev); |
6d3a5077 JM |
45 | putchar('/'); |
46 | } | |
aa1c48df | 47 | fputs(prefix->name, stdout); |
aa1c48df JH |
48 | } |
49 | } | |
50 | ||
6d3a5077 JM |
51 | /* |
52 | * return: | |
53 | * -1 if prefix is *not* a subset of path | |
54 | * 0 if prefix == path | |
55 | * 1 if prefix is a subset of path | |
56 | */ | |
57 | static int pathcmp(const char *path, struct path_prefix *prefix) | |
58 | { | |
59 | char buff[PATH_MAX]; | |
60 | int len,slen; | |
61 | ||
62 | if (prefix == NULL) | |
63 | return 1; | |
64 | ||
65 | len = string_path_prefix(buff, sizeof buff, prefix); | |
66 | slen = strlen(path); | |
67 | ||
68 | if (slen < len) | |
69 | return -1; | |
70 | ||
71 | if (strncmp(path,buff,len) == 0) { | |
72 | if (slen == len) | |
73 | return 0; | |
74 | else | |
75 | return 1; | |
76 | } | |
77 | ||
78 | return -1; | |
79 | } | |
80 | ||
81 | /* | |
82 | * match may be NULL, or a *sorted* list of paths | |
83 | */ | |
aa1c48df | 84 | static void list_recursive(void *buffer, |
bf0f910d | 85 | const char *type, |
23b127ed | 86 | unsigned long size, |
6d3a5077 JM |
87 | struct path_prefix *prefix, |
88 | char **match, int matches) | |
aa1c48df JH |
89 | { |
90 | struct path_prefix this_prefix; | |
91 | this_prefix.prev = prefix; | |
7912c070 | 92 | |
7912c070 | 93 | if (strcmp(type, "tree")) |
2de381f9 | 94 | die("expected a 'tree' node"); |
aa1c48df | 95 | |
6d3a5077 JM |
96 | if (matches) |
97 | recursive = 1; | |
98 | ||
7912c070 | 99 | while (size) { |
aa1c48df | 100 | int namelen = strlen(buffer)+1; |
6d3a5077 | 101 | void *eltbuf = NULL; |
aa1c48df JH |
102 | char elttype[20]; |
103 | unsigned long eltsize; | |
104 | unsigned char *sha1 = buffer + namelen; | |
105 | char *path = strchr(buffer, ' ') + 1; | |
7912c070 | 106 | unsigned int mode; |
6d3a5077 JM |
107 | const char *matched = NULL; |
108 | int mtype = -1; | |
109 | int mindex; | |
7912c070 | 110 | |
aa1c48df | 111 | if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1) |
2de381f9 | 112 | die("corrupt 'tree' file"); |
7912c070 | 113 | buffer = sha1 + 20; |
aa1c48df JH |
114 | size -= namelen + 20; |
115 | ||
6d3a5077 JM |
116 | this_prefix.name = path; |
117 | for ( mindex = 0; mindex < matches; mindex++) { | |
118 | mtype = pathcmp(match[mindex],&this_prefix); | |
119 | if (mtype >= 0) { | |
120 | matched = match[mindex]; | |
121 | break; | |
122 | } | |
123 | } | |
124 | ||
125 | /* | |
126 | * If we're not matching, or if this is an exact match, | |
127 | * print out the info | |
128 | */ | |
129 | if (!matches || (matched != NULL && mtype == 0)) { | |
2eab945e | 130 | printf("%06o %s %s\t", mode, |
6d3a5077 JM |
131 | S_ISDIR(mode) ? "tree" : "blob", |
132 | sha1_to_hex(sha1)); | |
133 | print_path_prefix(&this_prefix); | |
134 | putchar(line_termination); | |
135 | } | |
aa1c48df | 136 | |
0f2303f7 JH |
137 | if (! recursive || ! S_ISDIR(mode)) |
138 | continue; | |
139 | ||
6d3a5077 JM |
140 | if (matches && ! matched) |
141 | continue; | |
142 | ||
0f2303f7 JH |
143 | if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) { |
144 | error("cannot read %s", sha1_to_hex(sha1)); | |
145 | continue; | |
aa1c48df | 146 | } |
6d3a5077 JM |
147 | |
148 | /* If this is an exact directory match, we may have | |
149 | * directory files following this path. Match on them. | |
150 | * Otherwise, we're at a pach subcomponent, and we need | |
151 | * to try to match again. | |
152 | */ | |
153 | if (mtype == 0) | |
154 | mindex++; | |
155 | ||
156 | list_recursive(eltbuf, elttype, eltsize, &this_prefix, &match[mindex], matches-mindex); | |
aa1c48df | 157 | free(eltbuf); |
7912c070 | 158 | } |
aa1c48df JH |
159 | } |
160 | ||
6d3a5077 JM |
161 | static int qcmp(const void *a, const void *b) |
162 | { | |
163 | return strcmp(*(char **)a, *(char **)b); | |
164 | } | |
165 | ||
166 | static int list(unsigned char *sha1,char **path) | |
aa1c48df JH |
167 | { |
168 | void *buffer; | |
169 | unsigned long size; | |
6d3a5077 JM |
170 | int npaths; |
171 | ||
172 | for (npaths = 0; path[npaths] != NULL; npaths++) | |
173 | ; | |
174 | ||
175 | qsort(path,npaths,sizeof(char *),qcmp); | |
aa1c48df | 176 | |
e99d59ff | 177 | buffer = read_object_with_reference(sha1, "tree", &size, NULL); |
aa1c48df JH |
178 | if (!buffer) |
179 | die("unable to read sha1 file"); | |
6d3a5077 | 180 | list_recursive(buffer, "tree", size, NULL, path, npaths); |
c599caca | 181 | free(buffer); |
7912c070 PB |
182 | return 0; |
183 | } | |
184 | ||
6d3a5077 | 185 | static const char *ls_tree_usage = "git-ls-tree [-r] [-z] <key> [paths...]"; |
aa1c48df | 186 | |
7912c070 PB |
187 | int main(int argc, char **argv) |
188 | { | |
189 | unsigned char sha1[20]; | |
190 | ||
aa1c48df JH |
191 | while (1 < argc && argv[1][0] == '-') { |
192 | switch (argv[1][1]) { | |
193 | case 'z': | |
194 | line_termination = 0; | |
195 | break; | |
196 | case 'r': | |
197 | recursive = 1; | |
198 | break; | |
199 | default: | |
0f2303f7 | 200 | usage(ls_tree_usage); |
aa1c48df JH |
201 | } |
202 | argc--; argv++; | |
203 | } | |
204 | ||
6d3a5077 | 205 | if (argc < 2) |
0f2303f7 | 206 | usage(ls_tree_usage); |
3c249c95 | 207 | if (get_sha1(argv[1], sha1) < 0) |
0f2303f7 | 208 | usage(ls_tree_usage); |
6d3a5077 | 209 | if (list(sha1, &argv[2]) < 0) |
2de381f9 | 210 | die("list failed"); |
7912c070 PB |
211 | return 0; |
212 | } |