Release 950122
[wine] / debugger / readline / complete.c
1 /*  $Revision: 1.3 $
2 **
3 **  History and file completion functions for editline library.
4 */
5 #include <stdlib.h>
6 #include "editline.h"
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
58     if ((dp = opendir(dir)) == NULL)
59         return 0;
60
61     av = NULL;
62     ac = 0;
63     len = strlen(file);
64     while ((ep = readdir(dp)) != NULL) {
65         p = ep->d_name;
66         if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
67             continue;
68         if (len && strncmp(p, file, len) != 0)
69             continue;
70
71         if ((ac % MEM_INC) == 0) {
72             if ((new = NEW(char*, ac + MEM_INC)) == NULL)
73                 break;
74             if (ac) {
75                 COPYFROMTO(new, av, ac * sizeof (char **));
76                 DISPOSE(av);
77             }
78             *avp = av = new;
79         }
80
81         if ((av[ac] = strdup(p)) == NULL) {
82             if (ac == 0)
83                 DISPOSE(av);
84             break;
85         }
86         ac++;
87     }
88
89     /* Clean up and return. */
90     (void)closedir(dp);
91     if (ac)
92         qsort(av, ac, sizeof (char **), compare);
93     return ac;
94 }
95
96 /*
97 **  Split a pathname into allocated directory and trailing filename parts.
98 */
99 STATIC int
100 SplitPath(path, dirpart, filepart)
101     char        *path;
102     char        **dirpart;
103     char        **filepart;
104 {
105     static char DOT[] = ".";
106     char        *dpart;
107     char        *fpart;
108
109     if ((fpart = strrchr(path, '/')) == NULL) {
110         if ((dpart = strdup(DOT)) == NULL)
111             return -1;
112         if ((fpart = strdup(path)) == NULL) {
113             DISPOSE(dpart);
114             return -1;
115         }
116     }
117     else {
118         if ((dpart = strdup(path)) == NULL)
119             return -1;
120         dpart[fpart - path] = '\0';
121         if ((fpart = strdup(++fpart)) == NULL) {
122             DISPOSE(dpart);
123             return -1;
124         }
125     }
126     *dirpart = dpart;
127     *filepart = fpart;
128     return 0;
129 }
130
131 /*
132 **  Attempt to complete the pathname, returning an allocated copy.
133 **  Fill in *unique if we completed it, or set it to 0 if ambiguous.
134 */
135 char *
136 rl_complete(pathname, unique)
137     char        *pathname;
138     int         *unique;
139 {
140     char        **av;
141     char        *dir;
142     char        *file;
143     char        *new;
144     char        *p;
145     SIZE_T      ac;
146     SIZE_T      end;
147     SIZE_T      i;
148     SIZE_T      j;
149     SIZE_T      len;
150
151     if (SplitPath(pathname, &dir, &file) < 0)
152         return NULL;
153     if ((ac = FindMatches(dir, file, &av)) == 0) {
154         DISPOSE(dir);
155         DISPOSE(file);
156         return NULL;
157     }
158
159     p = NULL;
160     len = strlen(file);
161     if (ac == 1) {
162         /* Exactly one match -- finish it off. */
163         *unique = 1;
164         j = strlen(av[0]) - len + 2;
165         if ((p = NEW(char, j + 1)) != NULL) {
166             COPYFROMTO(p, av[0] + len, j);
167             if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
168                 (void)strcpy(new, dir);
169                 (void)strcat(new, "/");
170                 (void)strcat(new, av[0]);
171                 rl_add_slash(new, p);
172                 DISPOSE(new);
173             }
174         }
175     }
176     else {
177         *unique = 0;
178         if (len) {
179             /* Find largest matching substring. */
180             for (i = len, end = strlen(av[0]); i < end; i++)
181                 for (j = 1; j < ac; j++)
182                     if (av[0][i] != av[j][i])
183                         goto breakout;
184   breakout:
185             if (i > len) {
186                 j = i - len + 1;
187                 if ((p = NEW(char, j)) != NULL) {
188                     COPYFROMTO(p, av[0] + len, j);
189                     p[j - 1] = '\0';
190                 }
191             }
192         }
193     }
194
195     /* Clean up and return. */
196     DISPOSE(dir);
197     DISPOSE(file);
198     for (i = 0; i < ac; i++)
199         DISPOSE(av[i]);
200     DISPOSE(av);
201     return p;
202 }
203
204 /*
205 **  Return all possible completions.
206 */
207 int
208 rl_list_possib(pathname, avp)
209     char        *pathname;
210     char        ***avp;
211 {
212     char        *dir;
213     char        *file;
214     int         ac;
215
216     if (SplitPath(pathname, &dir, &file) < 0)
217         return 0;
218     ac = FindMatches(dir, file, avp);
219     DISPOSE(dir);
220     DISPOSE(file);
221     return ac;
222 }