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 d51419bf 2004-02-09 devnull long i, l, n, nmatch, 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 d51419bf 2004-02-09 devnull if(n <= 0)
62 d51419bf 2004-02-09 devnull return nil;
63 d51419bf 2004-02-09 devnull
64 d51419bf 2004-02-09 devnull /* find longest string, for allocation */
65 d51419bf 2004-02-09 devnull len = 0;
66 d51419bf 2004-02-09 devnull for(i=0; i<n; i++){
67 d51419bf 2004-02-09 devnull l = strlen(dirp[i].name) + 1 + 1; /* +1 for / +1 for \0 */
68 d51419bf 2004-02-09 devnull if(l > len)
69 d51419bf 2004-02-09 devnull len = l;
70 d51419bf 2004-02-09 devnull }
71 d51419bf 2004-02-09 devnull
72 d51419bf 2004-02-09 devnull name = malloc(n*sizeof(char*));
73 d51419bf 2004-02-09 devnull mode = malloc(n*sizeof(ulong));
74 d51419bf 2004-02-09 devnull c = malloc(sizeof(Completion) + len);
75 d51419bf 2004-02-09 devnull if(name == nil || mode == nil || c == nil)
76 d51419bf 2004-02-09 devnull goto Return;
77 d51419bf 2004-02-09 devnull memset(c, 0, sizeof(Completion));
78 d51419bf 2004-02-09 devnull
79 d51419bf 2004-02-09 devnull /* find the matches */
80 d51419bf 2004-02-09 devnull len = strlen(s);
81 d51419bf 2004-02-09 devnull nmatch = 0;
82 d51419bf 2004-02-09 devnull minlen = 1000000;
83 d51419bf 2004-02-09 devnull for(i=0; i<n; i++)
84 d51419bf 2004-02-09 devnull if(strncmp(s, dirp[i].name, len) == 0){
85 d51419bf 2004-02-09 devnull name[nmatch] = dirp[i].name;
86 d51419bf 2004-02-09 devnull mode[nmatch] = dirp[i].mode;
87 d51419bf 2004-02-09 devnull if(minlen > strlen(dirp[i].name))
88 d51419bf 2004-02-09 devnull minlen = strlen(dirp[i].name);
89 d51419bf 2004-02-09 devnull nmatch++;
90 d51419bf 2004-02-09 devnull }
91 d51419bf 2004-02-09 devnull
92 d51419bf 2004-02-09 devnull if(nmatch > 0) {
93 d51419bf 2004-02-09 devnull /* report interesting results */
94 d51419bf 2004-02-09 devnull /* trim length back to longest common initial string */
95 d51419bf 2004-02-09 devnull for(i=1; i<nmatch; i++)
96 d51419bf 2004-02-09 devnull minlen = longestprefixlength(name[0], name[i], minlen);
97 d51419bf 2004-02-09 devnull
98 d51419bf 2004-02-09 devnull /* build the answer */
99 d51419bf 2004-02-09 devnull c->complete = (nmatch == 1);
100 d51419bf 2004-02-09 devnull c->advance = c->complete || (minlen > len);
101 d51419bf 2004-02-09 devnull c->string = (char*)(c+1);
102 d51419bf 2004-02-09 devnull memmove(c->string, name[0]+len, minlen-len);
103 d51419bf 2004-02-09 devnull if(c->complete)
104 d51419bf 2004-02-09 devnull c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
105 d51419bf 2004-02-09 devnull c->string[minlen - len] = '\0';
106 d51419bf 2004-02-09 devnull } else {
107 d51419bf 2004-02-09 devnull /* no match, so return all possible strings */
108 d51419bf 2004-02-09 devnull for(i=0; i<n; i++){
109 d51419bf 2004-02-09 devnull name[i] = dirp[i].name;
110 d51419bf 2004-02-09 devnull mode[i] = dirp[i].mode;
111 d51419bf 2004-02-09 devnull }
112 d51419bf 2004-02-09 devnull nmatch = n;
113 d51419bf 2004-02-09 devnull }
114 d51419bf 2004-02-09 devnull
115 d51419bf 2004-02-09 devnull /* attach list of names */
116 d51419bf 2004-02-09 devnull nbytes = nmatch * sizeof(char*);
117 d51419bf 2004-02-09 devnull for(i=0; i<nmatch; i++)
118 d51419bf 2004-02-09 devnull nbytes += strlen(name[i]) + 1 + 1;
119 d51419bf 2004-02-09 devnull c->filename = malloc(nbytes);
120 d51419bf 2004-02-09 devnull if(c->filename == nil)
121 d51419bf 2004-02-09 devnull goto Return;
122 d51419bf 2004-02-09 devnull p = (char*)(c->filename + nmatch);
123 d51419bf 2004-02-09 devnull for(i=0; i<nmatch; i++){
124 d51419bf 2004-02-09 devnull c->filename[i] = p;
125 d51419bf 2004-02-09 devnull strcpy(p, name[i]);
126 d51419bf 2004-02-09 devnull p += strlen(p);
127 d51419bf 2004-02-09 devnull if(mode[i] & DMDIR)
128 d51419bf 2004-02-09 devnull *p++ = '/';
129 d51419bf 2004-02-09 devnull *p++ = '\0';
130 d51419bf 2004-02-09 devnull }
131 d51419bf 2004-02-09 devnull c->nfile = nmatch;
132 d51419bf 2004-02-09 devnull qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
133 d51419bf 2004-02-09 devnull
134 d51419bf 2004-02-09 devnull Return:
135 d51419bf 2004-02-09 devnull free(name);
136 d51419bf 2004-02-09 devnull free(mode);
137 d51419bf 2004-02-09 devnull free(dirp);
138 d51419bf 2004-02-09 devnull return c;
139 d51419bf 2004-02-09 devnull }