[9] | 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 | */
|
---|