1 | /* $Revision: 1.1.1.1 $
|
---|
2 | **
|
---|
3 | ** History and file completion functions for editline library.
|
---|
4 | */
|
---|
5 | #include "editline.h"
|
---|
6 |
|
---|
7 |
|
---|
8 | #if defined(NEED_STRDUP)
|
---|
9 | /*
|
---|
10 | ** Return an allocated copy of a string.
|
---|
11 | */
|
---|
12 | char *
|
---|
13 | strdup(p)
|
---|
14 | char *p;
|
---|
15 | {
|
---|
16 | char *new;
|
---|
17 |
|
---|
18 | if ((new = NEW(char, strlen(p) + 1)) != NULL)
|
---|
19 | (void)strcpy(new, p);
|
---|
20 | return new;
|
---|
21 | }
|
---|
22 | #endif /* defined(NEED_STRDUP) */
|
---|
23 |
|
---|
24 | /*
|
---|
25 | ** strcmp-like sorting predicate for qsort.
|
---|
26 | */
|
---|
27 | STATIC int
|
---|
28 | compare(p1, p2)
|
---|
29 | CONST void *p1;
|
---|
30 | CONST void *p2;
|
---|
31 | {
|
---|
32 | CONST char **v1;
|
---|
33 | CONST char **v2;
|
---|
34 |
|
---|
35 | v1 = (CONST char **)p1;
|
---|
36 | v2 = (CONST char **)p2;
|
---|
37 | return strcmp(*v1, *v2);
|
---|
38 | }
|
---|
39 |
|
---|
40 | /*
|
---|
41 | ** Fill in *avp with an array of names that match file, up to its length.
|
---|
42 | ** Ignore . and .. .
|
---|
43 | */
|
---|
44 | STATIC int
|
---|
45 | FindMatches(dir, file, avp)
|
---|
46 | char *dir;
|
---|
47 | char *file;
|
---|
48 | char ***avp;
|
---|
49 | {
|
---|
50 | char **av;
|
---|
51 | char **new;
|
---|
52 | char *p;
|
---|
53 | DIR *dp;
|
---|
54 | DIRENTRY *ep;
|
---|
55 | SIZE_T ac;
|
---|
56 | SIZE_T len;
|
---|
57 | SIZE_T choices;
|
---|
58 | SIZE_T total;
|
---|
59 | #define MAX_TOTAL (256 << sizeof(char *))
|
---|
60 |
|
---|
61 | if ((dp = opendir(dir)) == NULL)
|
---|
62 | return 0;
|
---|
63 |
|
---|
64 | av = NULL;
|
---|
65 | ac = 0;
|
---|
66 | len = strlen(file);
|
---|
67 | choices = 0;
|
---|
68 | total = 0;
|
---|
69 | while ((ep = readdir(dp)) != NULL) {
|
---|
70 | p = ep->d_name;
|
---|
71 | if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
|
---|
72 | continue;
|
---|
73 | if (len && strncmp(p, file, len) != 0)
|
---|
74 | continue;
|
---|
75 |
|
---|
76 | choices++;
|
---|
77 | if ((total += strlen(p)) > MAX_TOTAL) {
|
---|
78 | /* This is a bit too much. */
|
---|
79 | while (ac > 0) DISPOSE(av[--ac]);
|
---|
80 | continue;
|
---|
81 | }
|
---|
82 |
|
---|
83 | if ((ac % MEM_INC) == 0) {
|
---|
84 | if ((new = NEW(char*, ac + MEM_INC)) == NULL) {
|
---|
85 | total = 0;
|
---|
86 | break;
|
---|
87 | }
|
---|
88 | if (ac) {
|
---|
89 | COPYFROMTO(new, av, ac * sizeof (char **));
|
---|
90 | DISPOSE(av);
|
---|
91 | }
|
---|
92 | *avp = av = new;
|
---|
93 | }
|
---|
94 |
|
---|
95 | if ((av[ac] = strdup(p)) == NULL) {
|
---|
96 | if (ac == 0)
|
---|
97 | DISPOSE(av);
|
---|
98 | total = 0;
|
---|
99 | break;
|
---|
100 | }
|
---|
101 | ac++;
|
---|
102 | }
|
---|
103 |
|
---|
104 | /* Clean up and return. */
|
---|
105 | (void)closedir(dp);
|
---|
106 | if (total > MAX_TOTAL) {
|
---|
107 | char many[sizeof(total) * 3];
|
---|
108 | p = many + sizeof(many);
|
---|
109 | *--p = '\0';
|
---|
110 | while (choices > 0) {
|
---|
111 | *--p = '0' + choices % 10;
|
---|
112 | choices /= 10;
|
---|
113 | }
|
---|
114 | while (p > many + sizeof(many) - 8) *--p = ' ';
|
---|
115 | if ((p = strdup(p)) != NULL) av[ac++] = p;
|
---|
116 | if ((p = strdup("choices")) != NULL) av[ac++] = p;
|
---|
117 | } else {
|
---|
118 | if (ac)
|
---|
119 | qsort(av, ac, sizeof (char **), compare);
|
---|
120 | }
|
---|
121 | return ac;
|
---|
122 | }
|
---|
123 |
|
---|
124 | /*
|
---|
125 | ** Split a pathname into allocated directory and trailing filename parts.
|
---|
126 | */
|
---|
127 | STATIC int
|
---|
128 | SplitPath(path, dirpart, filepart)
|
---|
129 | char *path;
|
---|
130 | char **dirpart;
|
---|
131 | char **filepart;
|
---|
132 | {
|
---|
133 | static char DOT[] = ".";
|
---|
134 | char *dpart;
|
---|
135 | char *fpart;
|
---|
136 |
|
---|
137 | if ((fpart = strrchr(path, '/')) == NULL) {
|
---|
138 | if ((dpart = strdup(DOT)) == NULL)
|
---|
139 | return -1;
|
---|
140 | if ((fpart = strdup(path)) == NULL) {
|
---|
141 | DISPOSE(dpart);
|
---|
142 | return -1;
|
---|
143 | }
|
---|
144 | }
|
---|
145 | else {
|
---|
146 | if ((dpart = strdup(path)) == NULL)
|
---|
147 | return -1;
|
---|
148 | dpart[fpart - path + 1] = '\0';
|
---|
149 | if ((fpart = strdup(++fpart)) == NULL) {
|
---|
150 | DISPOSE(dpart);
|
---|
151 | return -1;
|
---|
152 | }
|
---|
153 | }
|
---|
154 | *dirpart = dpart;
|
---|
155 | *filepart = fpart;
|
---|
156 | return 0;
|
---|
157 | }
|
---|
158 |
|
---|
159 | /*
|
---|
160 | ** Attempt to complete the pathname, returning an allocated copy.
|
---|
161 | ** Fill in *unique if we completed it, or set it to 0 if ambiguous.
|
---|
162 | */
|
---|
163 | char *
|
---|
164 | rl_complete(pathname, unique)
|
---|
165 | char *pathname;
|
---|
166 | int *unique;
|
---|
167 | {
|
---|
168 | char **av;
|
---|
169 | char *dir;
|
---|
170 | char *file;
|
---|
171 | char *new;
|
---|
172 | char *p;
|
---|
173 | SIZE_T ac;
|
---|
174 | SIZE_T end;
|
---|
175 | SIZE_T i;
|
---|
176 | SIZE_T j;
|
---|
177 | SIZE_T len;
|
---|
178 |
|
---|
179 | if (SplitPath(pathname, &dir, &file) < 0)
|
---|
180 | return NULL;
|
---|
181 | if ((ac = FindMatches(dir, file, &av)) == 0) {
|
---|
182 | DISPOSE(dir);
|
---|
183 | DISPOSE(file);
|
---|
184 | return NULL;
|
---|
185 | }
|
---|
186 |
|
---|
187 | p = NULL;
|
---|
188 | len = strlen(file);
|
---|
189 | if (ac == 1) {
|
---|
190 | /* Exactly one match -- finish it off. */
|
---|
191 | *unique = 1;
|
---|
192 | j = strlen(av[0]) - len + 2;
|
---|
193 | if ((p = NEW(char, j + 1)) != NULL) {
|
---|
194 | COPYFROMTO(p, av[0] + len, j);
|
---|
195 | if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
|
---|
196 | (void)strcpy(new, dir);
|
---|
197 | (void)strcat(new, "/");
|
---|
198 | (void)strcat(new, av[0]);
|
---|
199 | rl_add_slash(new, p);
|
---|
200 | DISPOSE(new);
|
---|
201 | }
|
---|
202 | }
|
---|
203 | }
|
---|
204 | else {
|
---|
205 | *unique = 0;
|
---|
206 | if (len) {
|
---|
207 | /* Find largest matching substring. */
|
---|
208 | for (i = len, end = strlen(av[0]); i < end; i++)
|
---|
209 | for (j = 1; j < ac; j++)
|
---|
210 | if (av[0][i] != av[j][i])
|
---|
211 | goto breakout;
|
---|
212 | breakout:
|
---|
213 | if (i > len) {
|
---|
214 | j = i - len + 1;
|
---|
215 | if ((p = NEW(char, j)) != NULL) {
|
---|
216 | COPYFROMTO(p, av[0] + len, j);
|
---|
217 | p[j - 1] = '\0';
|
---|
218 | }
|
---|
219 | }
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 | /* Clean up and return. */
|
---|
224 | DISPOSE(dir);
|
---|
225 | DISPOSE(file);
|
---|
226 | for (i = 0; i < ac; i++)
|
---|
227 | DISPOSE(av[i]);
|
---|
228 | DISPOSE(av);
|
---|
229 | return p;
|
---|
230 | }
|
---|
231 |
|
---|
232 | /*
|
---|
233 | ** Return all possible completions.
|
---|
234 | */
|
---|
235 | int
|
---|
236 | rl_list_possib(pathname, avp)
|
---|
237 | char *pathname;
|
---|
238 | char ***avp;
|
---|
239 | {
|
---|
240 | char *dir;
|
---|
241 | char *file;
|
---|
242 | int ac;
|
---|
243 |
|
---|
244 | if (SplitPath(pathname, &dir, &file) < 0)
|
---|
245 | return 0;
|
---|
246 | ac = FindMatches(dir, file, avp);
|
---|
247 | DISPOSE(dir);
|
---|
248 | DISPOSE(file);
|
---|
249 | return ac;
|
---|
250 | }
|
---|
251 |
|
---|
252 | /*
|
---|
253 | * $PchId: complete.c,v 1.3 1996/02/22 21:18:51 philip Exp $
|
---|
254 | */
|
---|