3 * String auto-completion routines
6 * Copyright (C) 1996-2000,2007 Michael R. Elkins <me@mutt.org>
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
24 * @page complete String auto-completion routines
26 * String auto-completion routines
35 #include "mutt/mutt.h"
41 #include "imap/imap.h"
44 #include "nntp/nntp.h"
48 * mutt_complete - Attempt to complete a partial pathname
49 * @param buf Buffer containing pathname
50 * @param buflen Length of buffer
52 * @retval -1 if no matches
54 * Given a partial pathname, fill in as much of the rest of the path as is
57 int mutt_complete(char *buf, size_t buflen)
61 struct dirent *de = NULL;
64 struct Buffer *dirpart = NULL;
65 struct Buffer *exp_dirpart = NULL;
66 struct Buffer *filepart = NULL;
67 struct Buffer *tmp = NULL;
69 struct Buffer *imap_path = NULL;
73 mutt_debug(LL_DEBUG2, "completing %s\n", buf);
77 return nntp_complete(buf, buflen);
81 imap_path = mutt_buffer_pool_get();
82 /* we can use '/' as a delimiter, imap_complete rewrites it */
83 if ((*buf == '=') || (*buf == '+') || (*buf == '!'))
86 p = NONULL(C_Spoolfile);
90 mutt_buffer_concat_path(imap_path, p, buf + 1);
93 mutt_buffer_strcpy(imap_path, buf);
95 if (imap_path_probe(mutt_b2s(imap_path), NULL) == MUTT_IMAP)
97 rc = imap_complete(buf, buflen, mutt_b2s(imap_path));
98 mutt_buffer_pool_release(&imap_path);
102 mutt_buffer_pool_release(&imap_path);
105 dirpart = mutt_buffer_pool_get();
106 exp_dirpart = mutt_buffer_pool_get();
107 filepart = mutt_buffer_pool_get();
108 tmp = mutt_buffer_pool_get();
110 if ((*buf == '=') || (*buf == '+') || (*buf == '!'))
112 mutt_buffer_addch(dirpart, *buf);
114 mutt_buffer_strcpy(exp_dirpart, NONULL(C_Spoolfile));
116 mutt_buffer_strcpy(exp_dirpart, NONULL(C_Folder));
117 p = strrchr(buf, '/');
120 mutt_buffer_concatn_path(tmp, mutt_b2s(exp_dirpart), mutt_buffer_len(exp_dirpart),
121 buf + 1, (size_t)(p - buf - 1));
122 mutt_buffer_strcpy(exp_dirpart, mutt_b2s(tmp));
123 mutt_buffer_substrcpy(dirpart, buf, p + 1);
124 mutt_buffer_strcpy(filepart, p + 1);
127 mutt_buffer_strcpy(filepart, buf + 1);
128 dirp = opendir(mutt_b2s(exp_dirpart));
132 p = strrchr(buf, '/');
135 if (p == buf) /* absolute path */
138 mutt_buffer_strcpy(dirpart, "/");
139 mutt_buffer_strcpy(filepart, p);
140 dirp = opendir(mutt_b2s(dirpart));
144 mutt_buffer_substrcpy(dirpart, buf, p);
145 mutt_buffer_strcpy(filepart, p + 1);
146 mutt_buffer_strcpy(exp_dirpart, mutt_b2s(dirpart));
147 mutt_buffer_expand_path(exp_dirpart);
148 dirp = opendir(mutt_b2s(exp_dirpart));
153 /* no directory name, so assume current directory. */
154 mutt_buffer_strcpy(filepart, buf);
161 mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", mutt_b2s(exp_dirpart),
162 strerror(errno), errno);
166 /* special case to handle when there is no filepart yet. find the first
167 * file/directory which is not "." or ".." */
168 len = mutt_buffer_len(filepart);
171 while ((de = readdir(dirp)))
173 if ((mutt_str_strcmp(".", de->d_name) != 0) &&
174 (mutt_str_strcmp("..", de->d_name) != 0))
176 mutt_buffer_strcpy(filepart, de->d_name);
183 while ((de = readdir(dirp)))
185 if (mutt_str_strncmp(de->d_name, mutt_b2s(filepart), len) == 0)
189 char *cp = filepart->data;
191 for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
193 if (*cp != de->d_name[i])
197 mutt_buffer_fix_dptr(filepart);
203 mutt_buffer_strcpy(filepart, de->d_name);
205 /* check to see if it is a directory */
206 if (!mutt_buffer_is_empty(dirpart))
208 mutt_buffer_strcpy(tmp, mutt_b2s(exp_dirpart));
209 mutt_buffer_addch(tmp, '/');
212 mutt_buffer_reset(tmp);
213 mutt_buffer_addstr(tmp, mutt_b2s(filepart));
214 if ((stat(mutt_b2s(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
215 mutt_buffer_addch(filepart, '/');
222 if (!mutt_buffer_is_empty(dirpart))
224 mutt_str_strfcpy(buf, mutt_b2s(dirpart), buflen);
225 if ((mutt_str_strcmp("/", mutt_b2s(dirpart)) != 0) &&
226 (mutt_b2s(dirpart)[0] != '=') && (mutt_b2s(dirpart)[0] != '+'))
228 mutt_str_strfcpy(buf + strlen(buf), "/", buflen - strlen(buf));
230 mutt_str_strfcpy(buf + strlen(buf), mutt_b2s(filepart), buflen - strlen(buf));
233 mutt_str_strfcpy(buf, mutt_b2s(filepart), buflen);
236 mutt_buffer_pool_release(&dirpart);
237 mutt_buffer_pool_release(&exp_dirpart);
238 mutt_buffer_pool_release(&filepart);
239 mutt_buffer_pool_release(&tmp);
241 return init ? 0 : -1;