]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/tree.c
mothra: fix alt display resizing, filter control characters in panel entries, use...
[plan9front.git] / sys / src / cmd / hgfs / tree.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 char*
8 nodepath(char *s, char *e, Revnode *nd, int mangle)
9 {
10         static char *frogs[] = {
11                 "con", "prn", "aux", "nul",
12                 "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
13                 "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
14         };
15         char *p;
16         int i, l;
17
18         if(nd == nil || nd->name == nil)
19                 return s;
20
21         s = seprint(nodepath(s, e, nd->up, mangle), e, "/");
22         p = nd->name;
23         if(!mangle)
24                 return seprint(s, e, "%s", p);
25
26         for(i=0; i<nelem(frogs); i++){
27                 l = strlen(frogs[i]);
28                 if((strncmp(frogs[i], p, l) == 0) && (p[l] == 0 || p[l] == '.'))
29                         return seprint(s, e, "%.2s~%.2x%s", p, p[2], p+3);
30         }
31         for(; s+4 < e && *p; p++){
32                 if(*p == '_'){
33                         *s++ = '_';
34                         *s++ = '_';
35                 } else if(*p >= 'A' && *p <= 'Z'){
36                         *s++ = '_';
37                         *s++ = 'a' + (*p - 'A');
38                 } else if(*p >= 126 || strchr("\\:*?\"<>|", *p)){
39                         *s++ = '~';
40                         s = seprint(s, e, "%.2x", *p);
41                 } else
42                         *s++ = *p;
43         }
44         *s = 0;
45
46         return s;
47 }
48
49 Revnode*
50 mknode(char *name, uchar *hash, char mode)
51 {
52         Revnode *d;
53         char *s;
54
55         d = malloc(sizeof(*d) + (hash ? HASHSZ : 0) + (name ? strlen(name)+1 : 0));
56         memset(d, 0, sizeof(*d));
57         s = (char*)&d[1];
58         if(hash){
59                 d->path = hash2qid(hash);
60                 memmove(d->hash = (uchar*)s, hash, HASHSZ);
61                 s += HASHSZ;
62         }else
63                 d->path = 1;
64         if(name)
65                 strcpy(d->name = s, name);
66         d->mode = mode;
67         return d;
68 }
69
70 static void
71 addnode(Revnode *d, char *path, uchar *hash, char mode)
72 {
73         char *slash;
74         Revnode *c, *p;
75
76         while(path && *path){
77                 if(slash = strchr(path, '/'))
78                         *slash++ = 0;
79                 p = nil;
80                 for(c = d->down; c; p = c, c = c->next)
81                         if(strcmp(c->name, path) == 0)
82                                 break;
83                 if(c == nil){
84                         c = mknode(path, slash ? nil : hash, slash ? 0 : mode);
85                         c->up = d;
86                         if(p){
87                                 c->next = p->next;
88                                 p->next = c;
89                         } else {
90                                 c->next = d->down;
91                                 d->down = c;
92                         }
93                         if(!slash){
94                                 p = c;
95                                 while(d){
96                                         d->path += p->path;
97                                         p = d;
98                                         d = d->up;
99                                 }
100                         }
101                 }
102                 d = c;
103                 path = slash;
104         }
105 }
106
107 typedef struct Hashstr Hashstr;
108 struct Hashstr
109 {
110         Hashstr *next;
111         char    str[];
112 };
113
114 static ulong
115 hashstr(char *s)
116 {
117         ulong h, t;
118         char c;
119
120         h = 0;
121         while(c = *s++){
122                 t = h & 0xf8000000;
123                 h <<= 5;
124                 h ^= t>>27;
125                 h ^= (ulong)c;
126         }
127         return h;
128 }
129
130 static int
131 loadmanifest(Revnode *root, int fd, Hashstr **ht, int nh)
132 {
133         char buf[BUFSZ], *p, *e, *x;
134         uchar hash[HASHSZ];
135         int n;
136
137         p = buf;
138         e = buf + BUFSZ;
139         while((n = read(fd, p, e - p)) > 0){
140                 p += n;
141                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
142                         *e++ = 0;
143
144                         x = buf;
145                         x += strlen(x) + 1;
146                         hex2hash(x, hash);
147                         x += HASHSZ*2;
148
149                         if(ht == nil)
150                                 addnode(root, buf, hash, *x);
151                         else {
152                                 Hashstr *he;
153
154                                 for(he = ht[hashstr(buf) % nh]; he; he = he->next){
155                                         if(strcmp(he->str, buf) == 0){
156                                                 addnode(root, buf, hash, *x);
157                                                 break;
158                                         }
159                                 }
160                         }
161
162                         p -= e - buf;
163                         if(p > buf)
164                                 memmove(buf, e, p - buf);
165                 }
166                 e = buf + BUFSZ;
167         }
168         return 0;
169 }
170
171 static Revtree*
172 loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
173 {
174         Revtree *t;
175         int fd;
176
177         if((fd = revlogopentemp(manifest, hashrev(manifest, ri->mhash))) < 0)
178                 return nil;
179
180         t = malloc(sizeof(*t));
181         memset(t, 0, sizeof(*t));
182         incref(t);
183         t->root = mknode(nil, nil, 0);
184         if(loadmanifest(t->root, fd, ht, nh) < 0){
185                 close(fd);
186                 closerevtree(t);
187                 return nil;
188         }
189         close(fd);
190
191         return t;
192 }
193
194 Revtree*
195 loadfilestree(Revlog *, Revlog *manifest, Revinfo *ri)
196 {
197         return loadtree(manifest, ri, nil, 0);
198 }
199
200 Revtree*
201 loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri)
202 {
203         char buf[BUFSZ], *p, *e;
204         Hashstr *ht[256], *he, **hp;
205         int fd, n;
206         Revtree *t;
207         vlong off;
208
209         if((fd = revlogopentemp(changelog, hashrev(changelog, ri->chash))) < 0)
210                 return nil;
211
212         off = seek(fd, ri->logoff, 0);
213         if(off < 0){
214                 close(fd);
215                 return nil;
216         }
217
218         memset(ht, 0, sizeof(ht));
219
220         p = buf;
221         e = buf + BUFSZ;
222         while((off - ri->logoff) < ri->loglen){
223                 if((n = read(fd, p, e - p)) <= 0)
224                         break;
225                 p += n;
226                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
227                         *e++ = 0;
228
229                         he = malloc(sizeof(*he) + strlen(buf)+1);
230                         hp = &ht[hashstr(strcpy(he->str, buf)) % nelem(ht)];
231                         he->next = *hp;
232                         *hp = he;
233
234                         n = e - buf;
235                         p -= n;
236                         if(p > buf)
237                                 memmove(buf, e, p - buf);
238                         off += n;
239                 }
240                 e = buf + BUFSZ;
241         }
242         close(fd);
243
244         t = loadtree(manifest, ri, ht, nelem(ht));
245
246         for(hp = ht; hp != &ht[nelem(ht)]; hp++){
247                 while(he = *hp){
248                         *hp = he->next;
249                         free(he);
250                 }
251         }
252
253         return t;
254 }
255
256 static void
257 freenode(Revnode *nd)
258 {
259         if(nd == nil)
260                 return;
261         freenode(nd->down);
262         freenode(nd->next);
263         freenode(nd->before);
264         free(nd);
265 }
266
267 void
268 closerevtree(Revtree *t)
269 {
270         if(t == nil || decref(t))
271                 return;
272         freenode(t->root);
273         free(t);
274 }