NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
complete.c File Reference

String auto-completion routines. More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "imap/lib.h"
#include "nntp/lib.h"
#include "globals.h"
#include "muttlib.h"
+ Include dependency graph for complete.c:

Go to the source code of this file.

Functions

int mutt_complete (struct CompletionData *cd, struct Buffer *buf)
 Attempt to complete a partial pathname.
 

Detailed Description

String auto-completion routines.

Authors
  • Michael R. Elkins

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file complete.c.

Function Documentation

◆ mutt_complete()

int mutt_complete ( struct CompletionData cd,
struct Buffer buf 
)

Attempt to complete a partial pathname.

Parameters
cdCompletion Data
bufBuffer containing pathname
Return values
0Ok
-1No matches

Given a partial pathname, fill in as much of the rest of the path as is unique.

Definition at line 55 of file complete.c.

56{
57 const char *p = NULL;
58 DIR *dir = NULL;
59 struct dirent *de = NULL;
60 int init = 0;
61 size_t len;
62 struct Buffer *dirpart = NULL;
63 struct Buffer *exp_dirpart = NULL;
64 struct Buffer *filepart = NULL;
65 struct Buffer *tmp = NULL;
66 struct Buffer *imap_path = NULL;
67 int rc;
68
69 mutt_debug(LL_DEBUG2, "completing %s\n", buf_string(buf));
70
71 if (OptNews)
72 return nntp_complete(buf);
73
74 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
75 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
76
77 imap_path = buf_pool_get();
78 /* we can use '/' as a delimiter, imap_complete rewrites it */
79 char ch = buf_at(buf, 0);
80 if ((ch == '=') || (ch == '+') || (ch == '!'))
81 {
82 if (ch == '!')
83 p = NONULL(c_spool_file);
84 else
85 p = NONULL(c_folder);
86
87 buf_concat_path(imap_path, p, buf_string(buf) + 1);
88 }
89 else
90 {
91 buf_copy(imap_path, buf);
92 }
93
94 if (imap_path_probe(buf_string(imap_path), NULL) == MUTT_IMAP)
95 {
96 rc = imap_complete(buf, buf_string(imap_path));
97 buf_pool_release(&imap_path);
98 return rc;
99 }
100
101 buf_pool_release(&imap_path);
102
103 dirpart = buf_pool_get();
104 exp_dirpart = buf_pool_get();
105 filepart = buf_pool_get();
106 tmp = buf_pool_get();
107
108 ch = buf_at(buf, 0);
109 if ((ch == '=') || (ch == '+') || (ch == '!'))
110 {
111 buf_addch(dirpart, ch);
112 if (ch == '!')
113 buf_strcpy(exp_dirpart, NONULL(c_spool_file));
114 else
115 buf_strcpy(exp_dirpart, NONULL(c_folder));
116 p = strrchr(buf_string(buf), '/');
117 if (p)
118 {
119 buf_concatn_path(tmp, buf_string(exp_dirpart), buf_len(exp_dirpart),
120 buf_string(buf) + 1, (size_t) (p - buf_string(buf) - 1));
121 buf_copy(exp_dirpart, tmp);
122 buf_substrcpy(dirpart, buf_string(buf), p + 1);
123 buf_strcpy(filepart, p + 1);
124 }
125 else
126 {
127 buf_strcpy(filepart, buf_string(buf) + 1);
128 }
130 }
131 else
132 {
133 p = strrchr(buf_string(buf), '/');
134 if (p)
135 {
136 if (p == buf_string(buf)) /* absolute path */
137 {
138 p = buf_string(buf) + 1;
139 buf_strcpy(dirpart, "/");
140 buf_strcpy(filepart, p);
142 }
143 else
144 {
145 buf_substrcpy(dirpart, buf_string(buf), p);
146 buf_strcpy(filepart, p + 1);
147 buf_copy(exp_dirpart, dirpart);
148 buf_expand_path(exp_dirpart);
150 }
151 }
152 else
153 {
154 /* no directory name, so assume current directory. */
155 buf_strcpy(filepart, buf_string(buf));
157 }
158 }
159
160 if (!dir)
161 {
162 mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", buf_string(exp_dirpart),
163 strerror(errno), errno);
164 goto cleanup;
165 }
166
167 /* special case to handle when there is no filepart yet. find the first
168 * file/directory which is not "." or ".." */
169 len = buf_len(filepart);
170 if (len == 0)
171 {
172 while ((de = readdir(dir)))
173 {
174 if (!mutt_str_equal(".", de->d_name) && !mutt_str_equal("..", de->d_name))
175 {
176 buf_strcpy(filepart, de->d_name);
177 init++;
178 break;
179 }
180 }
181 }
182
183 while ((de = readdir(dir)))
184 {
185 if (mutt_strn_equal(de->d_name, buf_string(filepart), len))
186 {
187 if (init)
188 {
189 char *cp = filepart->data;
190
191 for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
192 {
193 if (*cp != de->d_name[i])
194 break;
195 }
196 *cp = '\0';
197 buf_fix_dptr(filepart);
198 }
199 else
200 {
201 struct stat st = { 0 };
202
203 buf_strcpy(filepart, de->d_name);
204
205 /* check to see if it is a directory */
206 if (buf_is_empty(dirpart))
207 {
208 buf_reset(tmp);
209 }
210 else
211 {
212 buf_copy(tmp, exp_dirpart);
213 buf_addch(tmp, '/');
214 }
215 buf_addstr(tmp, buf_string(filepart));
216 if ((stat(buf_string(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
217 buf_addch(filepart, '/');
218 init = 1;
219 }
220 }
221 }
222 closedir(dir);
223
224 if (buf_is_empty(dirpart))
225 {
226 buf_copy(buf, filepart);
227 }
228 else
229 {
230 buf_copy(buf, dirpart);
231 if (!mutt_str_equal("/", buf_string(dirpart)) &&
232 (buf_string(dirpart)[0] != '=') && (buf_string(dirpart)[0] != '+'))
233 {
234 buf_addstr(buf, "/");
235 }
236 buf_addstr(buf, buf_string(filepart));
237 }
238
239cleanup:
240 buf_pool_release(&dirpart);
241 buf_pool_release(&exp_dirpart);
242 buf_pool_release(&filepart);
243 buf_pool_release(&tmp);
244
245 return init ? 0 : -1;
246}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:638
size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen, const char *fname, size_t fnamelen)
Join a directory name and a filename.
Definition: buffer.c:521
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:484
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:452
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:616
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:75
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2327
int imap_complete(struct Buffer *buf, const char *path)
Try to complete an IMAP folder path.
Definition: imap.c:1262
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:497
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:329
int nntp_complete(struct Buffer *buf)
Auto-complete NNTP newsgroups.
Definition: complete.c:45
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function: