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