root/complete.c

Revision 5092:83440e7b2e52, 5.0 kB (checked in by Michael Elkins <me@…>, 18 months ago)

bug #2871

Avoid altering the argument to mutt_complete() when completion fails. Previously, the trailing component of filename was removed each time the user pressed TAB.

Line 
1/*
2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3 *
4 *     This program is free software; you can redistribute it and/or modify
5 *     it under the terms of the GNU General Public License as published by
6 *     the Free Software Foundation; either version 2 of the License, or
7 *     (at your option) any later version.
8 *
9 *     This program is distributed in the hope that it will be useful,
10 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *     GNU General Public License for more details.
13 *
14 *     You should have received a copy of the GNU General Public License
15 *     along with this program; if not, write to the Free Software
16 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 */ 
18
19#if HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "mutt.h"
24#ifdef USE_IMAP
25#include "mailbox.h"
26#include "imap.h"
27#endif
28
29#include <dirent.h>
30#include <string.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <errno.h>
34
35/* given a partial pathname, this routine fills in as much of the rest of the
36 * path as is unique.
37 *
38 * return 0 if ok, -1 if no matches
39 */
40int mutt_complete (char *s, size_t slen)
41{
42  char *p;
43  DIR *dirp = NULL;
44  struct dirent *de;
45  int i ,init=0;
46  size_t len;
47  char dirpart[_POSIX_PATH_MAX], exp_dirpart[_POSIX_PATH_MAX];
48  char filepart[_POSIX_PATH_MAX];
49#ifdef USE_IMAP
50  char imap_path[LONG_STRING];
51
52  dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
53
54  /* we can use '/' as a delimiter, imap_complete rewrites it */
55  if (*s == '=' || *s == '+' || *s == '!')
56  {
57    if (*s == '!')
58      p = NONULL (Spoolfile);
59    else
60      p = NONULL (Maildir);
61
62    mutt_concat_path (imap_path, p, s+1, sizeof (imap_path));
63  }
64  else
65    strfcpy (imap_path, s, sizeof(imap_path));
66
67  if (mx_is_imap (imap_path))
68    return imap_complete (s, slen, imap_path);
69#endif
70 
71  if (*s == '=' || *s == '+' || *s == '!')
72  {
73    dirpart[0] = *s;
74    dirpart[1] = 0;
75    if (*s == '!')
76      strfcpy (exp_dirpart, NONULL (Spoolfile), sizeof (exp_dirpart));
77    else
78      strfcpy (exp_dirpart, NONULL (Maildir), sizeof (exp_dirpart));
79    if ((p = strrchr (s, '/')))
80    {
81      char buf[_POSIX_PATH_MAX];
82      if (mutt_concatn_path (buf, sizeof(buf), exp_dirpart, strlen(exp_dirpart), s + 1, (size_t)(p - s - 1)) == NULL) {
83              return -1;
84      }
85      strfcpy (exp_dirpart, buf, sizeof (exp_dirpart));
86      mutt_substrcpy(dirpart, s, p+1, sizeof(dirpart));
87      strfcpy (filepart, p + 1, sizeof (filepart));
88    }
89    else
90      strfcpy (filepart, s + 1, sizeof (filepart));
91    dirp = opendir (exp_dirpart);
92  }
93  else
94  {
95    if ((p = strrchr (s, '/')))
96    {
97      if (p == s) /* absolute path */
98      {
99        p = s + 1;
100        strfcpy (dirpart, "/", sizeof (dirpart));
101        exp_dirpart[0] = 0;
102        strfcpy (filepart, p, sizeof (filepart));
103        dirp = opendir (dirpart);
104      }
105      else
106      {
107        mutt_substrcpy(dirpart, s, p, sizeof(dirpart));
108        strfcpy (filepart, p + 1, sizeof (filepart));
109        strfcpy (exp_dirpart, dirpart, sizeof (exp_dirpart));
110        mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
111        dirp = opendir (exp_dirpart);
112      }
113    }
114    else
115    {
116      /* no directory name, so assume current directory. */
117      dirpart[0] = 0;
118      strfcpy (filepart, s, sizeof (filepart));
119      dirp = opendir (".");
120    }
121  }
122
123  if (dirp == NULL)
124  {
125    dprint (1, (debugfile, "mutt_complete(): %s: %s (errno %d).\n", exp_dirpart, strerror (errno), errno));
126    return (-1);
127  }
128
129  /*
130   * special case to handle when there is no filepart yet.  find the first
131   * file/directory which is not ``.'' or ``..''
132   */
133  if ((len = mutt_strlen (filepart)) == 0)
134  {
135    while ((de = readdir (dirp)) != NULL)
136    {
137      if (mutt_strcmp (".", de->d_name) != 0 && mutt_strcmp ("..", de->d_name) != 0)
138      {
139        strfcpy (filepart, de->d_name, sizeof (filepart));
140        init++;
141        break;
142      }
143    }
144  }
145
146  while ((de = readdir (dirp)) != NULL)
147  {
148    if (mutt_strncmp (de->d_name, filepart, len) == 0)
149    {
150      if (init)
151      {
152        for (i=0; filepart[i] && de->d_name[i]; i++)
153        {
154          if (filepart[i] != de->d_name[i])
155          {
156            filepart[i] = 0;
157            break;
158          }
159        }
160        filepart[i] = 0;
161      }
162      else
163      {
164        char buf[_POSIX_PATH_MAX];
165        struct stat st;
166
167        strfcpy (filepart, de->d_name, sizeof(filepart));
168
169        /* check to see if it is a directory */
170        if (dirpart[0])
171        {
172          strfcpy (buf, exp_dirpart, sizeof (buf));
173          strfcpy (buf + strlen (buf), "/", sizeof (buf) - strlen (buf));
174        }
175        else
176          buf[0] = 0;
177        strfcpy (buf + strlen (buf), filepart, sizeof (buf) - strlen (buf));
178        if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR))
179          strfcpy (filepart + strlen (filepart), "/",
180                   sizeof (filepart) - strlen (filepart));
181        init = 1;
182      }
183    }
184  }
185  closedir (dirp);
186
187  if (dirpart[0])
188  {
189    strfcpy (s, dirpart, slen);
190    if (mutt_strcmp ("/", dirpart) != 0 && dirpart[0] != '=' && dirpart[0] != '+')
191      strfcpy (s + strlen (s), "/", slen - strlen (s));
192    strfcpy (s + strlen (s), filepart, slen - strlen (s));
193  }
194  else
195    strfcpy (s, filepart, slen);
196
197  return (init ? 0 : -1);
198}
Note: See TracBrowser for help on using the browser.