Blame


1 d51419bf 2004-02-09 devnull #include <u.h>
2 d51419bf 2004-02-09 devnull #include <libc.h>
3 d51419bf 2004-02-09 devnull #include "complete.h"
4 d51419bf 2004-02-09 devnull
5 d51419bf 2004-02-09 devnull static int
6 d51419bf 2004-02-09 devnull longestprefixlength(char *a, char *b, int n)
7 d51419bf 2004-02-09 devnull {
8 d51419bf 2004-02-09 devnull int i, w;
9 d51419bf 2004-02-09 devnull Rune ra, rb;
10 d51419bf 2004-02-09 devnull
11 d51419bf 2004-02-09 devnull for(i=0; i<n; i+=w){
12 d51419bf 2004-02-09 devnull w = chartorune(&ra, a);
13 d51419bf 2004-02-09 devnull chartorune(&rb, b);
14 d51419bf 2004-02-09 devnull if(ra != rb)
15 d51419bf 2004-02-09 devnull break;
16 d51419bf 2004-02-09 devnull a += w;
17 d51419bf 2004-02-09 devnull b += w;
18 d51419bf 2004-02-09 devnull }
19 d51419bf 2004-02-09 devnull return i;
20 d51419bf 2004-02-09 devnull }
21 d51419bf 2004-02-09 devnull
22 d51419bf 2004-02-09 devnull void
23 d51419bf 2004-02-09 devnull freecompletion(Completion *c)
24 d51419bf 2004-02-09 devnull {
25 d51419bf 2004-02-09 devnull if(c){
26 d51419bf 2004-02-09 devnull free(c->filename);
27 d51419bf 2004-02-09 devnull free(c);
28 d51419bf 2004-02-09 devnull }
29 d51419bf 2004-02-09 devnull }
30 d51419bf 2004-02-09 devnull
31 d51419bf 2004-02-09 devnull static int
32 d51419bf 2004-02-09 devnull strpcmp(const void *va, const void *vb)
33 d51419bf 2004-02-09 devnull {
34 d51419bf 2004-02-09 devnull char *a, *b;
35 d51419bf 2004-02-09 devnull
36 d51419bf 2004-02-09 devnull a = *(char**)va;
37 d51419bf 2004-02-09 devnull b = *(char**)vb;
38 d51419bf 2004-02-09 devnull return strcmp(a, b);
39 d51419bf 2004-02-09 devnull }
40 d51419bf 2004-02-09 devnull
41 d51419bf 2004-02-09 devnull Completion*
42 d51419bf 2004-02-09 devnull complete(char *dir, char *s)
43 d51419bf 2004-02-09 devnull {
44 5a8e63b2 2004-02-29 devnull long i, l, n, nfile, len, nbytes;
45 d51419bf 2004-02-09 devnull int fd, minlen;
46 d51419bf 2004-02-09 devnull Dir *dirp;
47 d51419bf 2004-02-09 devnull char **name, *p;
48 d51419bf 2004-02-09 devnull ulong* mode;
49 d51419bf 2004-02-09 devnull Completion *c;
50 d51419bf 2004-02-09 devnull
51 d51419bf 2004-02-09 devnull if(strchr(s, '/') != nil){
52 d51419bf 2004-02-09 devnull werrstr("slash character in name argument to complete()");
53 d51419bf 2004-02-09 devnull return nil;
54 d51419bf 2004-02-09 devnull }
55 d51419bf 2004-02-09 devnull
56 d51419bf 2004-02-09 devnull fd = open(dir, OREAD);
57 d51419bf 2004-02-09 devnull if(fd < 0)
58 d51419bf 2004-02-09 devnull return nil;
59 d51419bf 2004-02-09 devnull
60 d51419bf 2004-02-09 devnull n = dirreadall(fd, &dirp);
61 5a8e63b2 2004-02-29 devnull if(n <= 0){
62 5a8e63b2 2004-02-29 devnull close(fd);
63 d51419bf 2004-02-09 devnull return nil;
64 5a8e63b2 2004-02-29 devnull }
65 d51419bf 2004-02-09 devnull
66 d51419bf 2004-02-09 devnull /* find longest string, for allocation */
67 d51419bf 2004-02-09 devnull len = 0;
68 d51419bf 2004-02-09 devnull for(i=0; i<n; i++){
69 d51419bf 2004-02-09 devnull l = strlen(dirp[i].name) + 1 + 1; /* +1 for / +1 for \0 */
70 d51419bf 2004-02-09 devnull if(l > len)
71 d51419bf 2004-02-09 devnull len = l;
72 d51419bf 2004-02-09 devnull }
73 d51419bf 2004-02-09 devnull
74 d51419bf 2004-02-09 devnull name = malloc(n*sizeof(char*));
75 d51419bf 2004-02-09 devnull mode = malloc(n*sizeof(ulong));
76 d51419bf 2004-02-09 devnull c = malloc(sizeof(Completion) + len);
77 d51419bf 2004-02-09 devnull if(name == nil || mode == nil || c == nil)
78 d51419bf 2004-02-09 devnull goto Return;
79 d51419bf 2004-02-09 devnull memset(c, 0, sizeof(Completion));
80 d51419bf 2004-02-09 devnull
81 d51419bf 2004-02-09 devnull /* find the matches */
82 d51419bf 2004-02-09 devnull len = strlen(s);
83 5a8e63b2 2004-02-29 devnull nfile = 0;
84 d51419bf 2004-02-09 devnull minlen = 1000000;
85 d51419bf 2004-02-09 devnull for(i=0; i<n; i++)
86 d51419bf 2004-02-09 devnull if(strncmp(s, dirp[i].name, len) == 0){
87 5a8e63b2 2004-02-29 devnull name[nfile] = dirp[i].name;
88 5a8e63b2 2004-02-29 devnull mode[nfile] = dirp[i].mode;
89 d51419bf 2004-02-09 devnull if(minlen > strlen(dirp[i].name))
90 d51419bf 2004-02-09 devnull minlen = strlen(dirp[i].name);
91 5a8e63b2 2004-02-29 devnull nfile++;
92 d51419bf 2004-02-09 devnull }
93 d51419bf 2004-02-09 devnull
94 5a8e63b2 2004-02-29 devnull if(nfile > 0) {
95 d51419bf 2004-02-09 devnull /* report interesting results */
96 d51419bf 2004-02-09 devnull /* trim length back to longest common initial string */
97 5a8e63b2 2004-02-29 devnull for(i=1; i<nfile; i++)
98 d51419bf 2004-02-09 devnull minlen = longestprefixlength(name[0], name[i], minlen);
99 d51419bf 2004-02-09 devnull
100 d51419bf 2004-02-09 devnull /* build the answer */
101 5a8e63b2 2004-02-29 devnull c->complete = (nfile == 1);
102 d51419bf 2004-02-09 devnull c->advance = c->complete || (minlen > len);
103 d51419bf 2004-02-09 devnull c->string = (char*)(c+1);
104 d51419bf 2004-02-09 devnull memmove(c->string, name[0]+len, minlen-len);
105 d51419bf 2004-02-09 devnull if(c->complete)
106 d51419bf 2004-02-09 devnull c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
107 d51419bf 2004-02-09 devnull c->string[minlen - len] = '\0';
108 5a8e63b2 2004-02-29 devnull c->nmatch = nfile;
109 d51419bf 2004-02-09 devnull } else {
110 d51419bf 2004-02-09 devnull /* no match, so return all possible strings */
111 d51419bf 2004-02-09 devnull for(i=0; i<n; i++){
112 d51419bf 2004-02-09 devnull name[i] = dirp[i].name;
113 d51419bf 2004-02-09 devnull mode[i] = dirp[i].mode;
114 d51419bf 2004-02-09 devnull }
115 5a8e63b2 2004-02-29 devnull nfile = n;
116 5a8e63b2 2004-02-29 devnull c->nmatch = 0;
117 d51419bf 2004-02-09 devnull }
118 d51419bf 2004-02-09 devnull
119 d51419bf 2004-02-09 devnull /* attach list of names */
120 5a8e63b2 2004-02-29 devnull nbytes = nfile * sizeof(char*);
121 5a8e63b2 2004-02-29 devnull for(i=0; i<nfile; i++)
122 d51419bf 2004-02-09 devnull nbytes += strlen(name[i]) + 1 + 1;
123 d51419bf 2004-02-09 devnull c->filename = malloc(nbytes);
124 d51419bf 2004-02-09 devnull if(c->filename == nil)
125 d51419bf 2004-02-09 devnull goto Return;
126 5a8e63b2 2004-02-29 devnull p = (char*)(c->filename + nfile);
127 5a8e63b2 2004-02-29 devnull for(i=0; i<nfile; i++){
128 d51419bf 2004-02-09 devnull c->filename[i] = p;
129 d51419bf 2004-02-09 devnull strcpy(p, name[i]);
130 d51419bf 2004-02-09 devnull p += strlen(p);
131 d51419bf 2004-02-09 devnull if(mode[i] & DMDIR)
132 d51419bf 2004-02-09 devnull *p++ = '/';
133 d51419bf 2004-02-09 devnull *p++ = '\0';
134 d51419bf 2004-02-09 devnull }
135 5a8e63b2 2004-02-29 devnull c->nfile = nfile;
136 d51419bf 2004-02-09 devnull qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
137 d51419bf 2004-02-09 devnull
138 d51419bf 2004-02-09 devnull Return:
139 d51419bf 2004-02-09 devnull free(name);
140 d51419bf 2004-02-09 devnull free(mode);
141 d51419bf 2004-02-09 devnull free(dirp);
142 5a8e63b2 2004-02-29 devnull close(fd);
143 d51419bf 2004-02-09 devnull return c;
144 d51419bf 2004-02-09 devnull }