add DB's pverhaul the tab completion code and a few related functions to
increase efficiency and support multibyte characters; also add a few miscellaneous tweaks of mine git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2309 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
daa533a767
commit
65e6ecb1d4
|
@ -149,6 +149,15 @@ CVS code -
|
||||||
get the value of totsize in a few more places. Changes to
|
get the value of totsize in a few more places. Changes to
|
||||||
read_line(), read_file(), do_delete(), do_input(),
|
read_line(), read_file(), do_delete(), do_input(),
|
||||||
get_totals(), and do_cursorpos(). (DLR)
|
get_totals(), and do_cursorpos(). (DLR)
|
||||||
|
- Overhaul the tab completion code and a few related functions
|
||||||
|
to increase efficiency and support multibyte characters. New
|
||||||
|
functions strrchrn() and is_dir(); changes to diralphasort(),
|
||||||
|
username_tab_completion(), cwd_tab_completion(), input_tab(),
|
||||||
|
tail(), and striponedir(); removal of append_slash_if_dir()
|
||||||
|
and check_wildcard_match(). (David Benbennick) DLR: Move the
|
||||||
|
routine to get the current user's home directory into the new
|
||||||
|
function get_homedir(), and use it where necessary. Also add
|
||||||
|
a few miscellaneous tweaks.
|
||||||
- cut.c:
|
- cut.c:
|
||||||
do_cut_text()
|
do_cut_text()
|
||||||
- If keep_cutbuffer is FALSE, only blow away the text in the
|
- If keep_cutbuffer is FALSE, only blow away the text in the
|
||||||
|
|
31
src/chars.c
31
src/chars.c
|
@ -41,13 +41,13 @@
|
||||||
|
|
||||||
/* Return TRUE if the value of c is in byte range, and FALSE
|
/* Return TRUE if the value of c is in byte range, and FALSE
|
||||||
* otherwise. */
|
* otherwise. */
|
||||||
bool is_byte(unsigned int c)
|
bool is_byte(int c)
|
||||||
{
|
{
|
||||||
return (c == (unsigned char)c);
|
return ((unsigned int)c == (unsigned char)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is equivalent to isalnum(). */
|
/* This function is equivalent to isalnum(). */
|
||||||
bool is_alnum_char(unsigned int c)
|
bool is_alnum_char(int c)
|
||||||
{
|
{
|
||||||
return isalnum(c);
|
return isalnum(c);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ bool is_alnum_wchar(wchar_t wc)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This function is equivalent to isblank(). */
|
/* This function is equivalent to isblank(). */
|
||||||
bool is_blank_char(unsigned int c)
|
bool is_blank_char(int c)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
#ifdef HAVE_ISBLANK
|
#ifdef HAVE_ISBLANK
|
||||||
|
@ -130,9 +130,10 @@ bool is_blank_wchar(wchar_t wc)
|
||||||
|
|
||||||
/* This function is equivalent to iscntrl(), except in that it also
|
/* This function is equivalent to iscntrl(), except in that it also
|
||||||
* handles control characters with their high bits set. */
|
* handles control characters with their high bits set. */
|
||||||
bool is_cntrl_char(unsigned int c)
|
bool is_cntrl_char(int c)
|
||||||
{
|
{
|
||||||
return (0 <= c && c < 32) || (127 <= c && c < 160);
|
return (-128 <= c && c < -96) || (0 <= c && c < 32) ||
|
||||||
|
(127 <= c && c < 160);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is equivalent to iscntrl() for multibyte characters,
|
/* This function is equivalent to iscntrl() for multibyte characters,
|
||||||
|
@ -273,7 +274,7 @@ int mb_cur_max(void)
|
||||||
/* Convert the value in chr to a multibyte character with the same
|
/* Convert the value in chr to a multibyte character with the same
|
||||||
* wide character value as chr. Return the multibyte character and its
|
* wide character value as chr. Return the multibyte character and its
|
||||||
* length. */
|
* length. */
|
||||||
char *make_mbchar(unsigned int chr, char *chr_mb, int *chr_mb_len)
|
char *make_mbchar(int chr, char *chr_mb, int *chr_mb_len)
|
||||||
{
|
{
|
||||||
assert(chr_mb != NULL && chr_mb_len != NULL);
|
assert(chr_mb != NULL && chr_mb_len != NULL);
|
||||||
|
|
||||||
|
@ -412,7 +413,7 @@ size_t move_mbleft(const char *buf, size_t pos)
|
||||||
#endif
|
#endif
|
||||||
, NULL);
|
, NULL);
|
||||||
|
|
||||||
if (pos_prev <= buf_mb_len)
|
if (pos_prev <= (size_t)buf_mb_len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pos_prev -= buf_mb_len;
|
pos_prev -= buf_mb_len;
|
||||||
|
@ -760,3 +761,17 @@ size_t mbstrnlen(const char *s, size_t maxlen)
|
||||||
nstrnlen(s, maxlen);
|
nstrnlen(s, maxlen);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the one-based position of the last occurrence of character c in
|
||||||
|
* the first n characters of s. Return 0 if c is not found. */
|
||||||
|
size_t strrchrn(const char *s, int c, size_t n)
|
||||||
|
{
|
||||||
|
assert(n <= strlen(s));
|
||||||
|
|
||||||
|
for (s += n - 1; n >= 1; n--, s--) {
|
||||||
|
if (c == *s)
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
603
src/files.c
603
src/files.c
|
@ -1911,6 +1911,7 @@ int do_writeout(bool exiting)
|
||||||
} /* while (TRUE) */
|
} /* while (TRUE) */
|
||||||
|
|
||||||
free(ans);
|
free(ans);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1920,71 +1921,96 @@ void do_writeout_void(void)
|
||||||
display_main_list();
|
display_main_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a malloc()ed string containing the actual directory, used
|
/* Return a malloc()ed string containing the actual directory, used to
|
||||||
* to convert ~user and ~/ notation... */
|
* convert ~user/ and ~/ notation. */
|
||||||
char *real_dir_from_tilde(const char *buf)
|
char *real_dir_from_tilde(const char *buf)
|
||||||
{
|
{
|
||||||
char *dirtmp = NULL;
|
char *dirtmp = NULL;
|
||||||
|
|
||||||
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (buf[0] == '~') {
|
if (buf[0] == '~') {
|
||||||
size_t i;
|
size_t i;
|
||||||
const struct passwd *userdata;
|
const char *tilde_dir;
|
||||||
|
|
||||||
/* Figure how how much of the str we need to compare */
|
/* Figure out how much of the str we need to compare. */
|
||||||
for (i = 1; buf[i] != '/' && buf[i] != '\0'; i++)
|
for (i = 1; buf[i] != '/' && buf[i] != '\0'; i++)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Determine home directory using getpwuid() or getpwent(),
|
/* Get the home directory. */
|
||||||
don't rely on $HOME */
|
if (i == 1) {
|
||||||
if (i == 1)
|
get_homedir();
|
||||||
userdata = getpwuid(geteuid());
|
tilde_dir = homedir;
|
||||||
else {
|
} else {
|
||||||
|
const struct passwd *userdata;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
userdata = getpwent();
|
userdata = getpwent();
|
||||||
} while (userdata != NULL &&
|
} while (userdata != NULL &&
|
||||||
strncmp(userdata->pw_name, buf + 1, i - 1) != 0);
|
strncmp(userdata->pw_name, buf + 1, i - 1) != 0);
|
||||||
}
|
|
||||||
endpwent();
|
endpwent();
|
||||||
|
tilde_dir = userdata->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
if (userdata != NULL) { /* User found */
|
if (tilde_dir != NULL) {
|
||||||
dirtmp = charalloc(strlen(userdata->pw_dir) +
|
dirtmp = charalloc(strlen(tilde_dir) + strlen(buf + i) + 1);
|
||||||
strlen(buf + i) + 1);
|
sprintf(dirtmp, "%s%s", tilde_dir, buf + i);
|
||||||
sprintf(dirtmp, "%s%s", userdata->pw_dir, &buf[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set a default value for dirtmp, in case the user's home directory
|
||||||
|
* isn't found. */
|
||||||
if (dirtmp == NULL)
|
if (dirtmp == NULL)
|
||||||
dirtmp = mallocstrcpy(dirtmp, buf);
|
dirtmp = mallocstrcpy(NULL, buf);
|
||||||
|
|
||||||
return dirtmp;
|
return dirtmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(DISABLE_TABCOMP) || !defined(DISABLE_BROWSER)
|
||||||
|
/* Our sort routine for file listings. Sort directories before
|
||||||
|
* filenames, alphabetically and ignoring case differences. Sort
|
||||||
|
* filenames the same way, except for ignoring an initial dot. */
|
||||||
|
int diralphasort(const void *va, const void *vb)
|
||||||
|
{
|
||||||
|
struct stat fileinfo;
|
||||||
|
const char *a = *(const char *const *)va;
|
||||||
|
const char *b = *(const char *const *)vb;
|
||||||
|
bool aisdir = stat(a, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
|
||||||
|
bool bisdir = stat(b, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
|
||||||
|
|
||||||
|
if (aisdir && !bisdir)
|
||||||
|
return -1;
|
||||||
|
if (!aisdir && bisdir)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (*a == '.')
|
||||||
|
a++;
|
||||||
|
if (*b == '.')
|
||||||
|
b++;
|
||||||
|
|
||||||
|
return strcasecmp(a, b);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DISABLE_TABCOMP
|
#ifndef DISABLE_TABCOMP
|
||||||
/* Tack a slash onto the string we're completing if it's a directory.
|
/* Is the given file a directory? */
|
||||||
* We assume there is room for one more character on the end of buf.
|
int is_dir(const char *buf)
|
||||||
* The return value says whether buf is a directory. */
|
|
||||||
int append_slash_if_dir(char *buf, bool *lastwastab, int *place)
|
|
||||||
{
|
{
|
||||||
char *dirptr = real_dir_from_tilde(buf);
|
char *dirptr = real_dir_from_tilde(buf);
|
||||||
struct stat fileinfo;
|
struct stat fileinfo;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
assert(dirptr != buf);
|
int ret = (stat(dirptr, &fileinfo) != -1 &&
|
||||||
|
S_ISDIR(fileinfo.st_mode));
|
||||||
|
|
||||||
if (stat(dirptr, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode)) {
|
assert(buf != NULL && dirptr != buf);
|
||||||
strncat(buf, "/", 1);
|
|
||||||
(*place)++;
|
|
||||||
/* now we start over again with # of tabs so far */
|
|
||||||
*lastwastab = FALSE;
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dirptr);
|
free(dirptr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* These functions (username_tab_completion(), cwd_tab_completion(), and
|
||||||
* These functions (username_tab_completion(), cwd_tab_completion(), and
|
|
||||||
* input_tab()) were taken from busybox 0.46 (cmdedit.c). Here is the
|
* input_tab()) were taken from busybox 0.46 (cmdedit.c). Here is the
|
||||||
* notice from that file:
|
* notice from that file:
|
||||||
*
|
*
|
||||||
|
@ -1999,46 +2025,38 @@ int append_slash_if_dir(char *buf, bool *lastwastab, int *place)
|
||||||
* You may use this code as you wish, so long as the original author(s)
|
* You may use this code as you wish, so long as the original author(s)
|
||||||
* are attributed in any redistributions of the source code.
|
* are attributed in any redistributions of the source code.
|
||||||
* This code is 'as is' with no warranty.
|
* This code is 'as is' with no warranty.
|
||||||
* This code may safely be consumed by a BSD or GPL license.
|
* This code may safely be consumed by a BSD or GPL license. */
|
||||||
*/
|
|
||||||
|
|
||||||
char **username_tab_completion(char *buf, int *num_matches)
|
/* We consider the first buflen characters of buf for ~username tab
|
||||||
|
* completion. */
|
||||||
|
char **username_tab_completion(const char *buf, size_t *num_matches,
|
||||||
|
size_t buflen)
|
||||||
{
|
{
|
||||||
char **matches = (char **)NULL;
|
char **matches = NULL;
|
||||||
char *matchline = NULL;
|
const struct passwd *userdata;
|
||||||
struct passwd *userdata;
|
|
||||||
|
assert(buf != NULL && num_matches != NULL && buflen > 0);
|
||||||
|
|
||||||
*num_matches = 0;
|
*num_matches = 0;
|
||||||
matches = (char **)nmalloc(BUFSIZ * sizeof(char *));
|
|
||||||
|
|
||||||
strcat(buf, "*");
|
|
||||||
|
|
||||||
while ((userdata = getpwent()) != NULL) {
|
while ((userdata = getpwent()) != NULL) {
|
||||||
|
if (strncmp(userdata->pw_name, buf + 1, buflen - 1) == 0) {
|
||||||
if (check_wildcard_match(userdata->pw_name, &buf[1])) {
|
/* Cool, found a match. Add it to the list. This makes a
|
||||||
|
* lot more sense to me (Chris) this way... */
|
||||||
/* Cool, found a match. Add it to the list
|
|
||||||
* This makes a lot more sense to me (Chris) this way...
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DISABLE_OPERATINGDIR
|
#ifndef DISABLE_OPERATINGDIR
|
||||||
/* ...unless the match exists outside the operating
|
/* ...unless the match exists outside the operating
|
||||||
directory, in which case just go to the next match */
|
* directory, in which case just go to the next match. */
|
||||||
|
if (check_operating_dir(userdata->pw_dir, TRUE))
|
||||||
if (operating_dir != NULL) {
|
|
||||||
if (check_operating_dir(userdata->pw_dir, TRUE) != 0)
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
matchline = charalloc(strlen(userdata->pw_name) + 2);
|
matches = (char **)nrealloc(matches, (*num_matches + 1) *
|
||||||
sprintf(matchline, "~%s", userdata->pw_name);
|
sizeof(char *));
|
||||||
matches[*num_matches] = matchline;
|
matches[*num_matches] =
|
||||||
|
charalloc(strlen(userdata->pw_name) + 2);
|
||||||
|
sprintf(matches[*num_matches], "~%s", userdata->pw_name);
|
||||||
++(*num_matches);
|
++(*num_matches);
|
||||||
|
|
||||||
/* If there's no more room, bail out */
|
|
||||||
if (*num_matches == BUFSIZ)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endpwent();
|
endpwent();
|
||||||
|
@ -2047,365 +2065,271 @@ char **username_tab_completion(char *buf, int *num_matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This was originally called exe_n_cwd_tab_completion, but we're not
|
/* This was originally called exe_n_cwd_tab_completion, but we're not
|
||||||
worried about executables, only filenames :> */
|
* worried about executables, only filenames :> */
|
||||||
|
char **cwd_tab_completion(const char *buf, size_t *num_matches, size_t
|
||||||
char **cwd_tab_completion(char *buf, int *num_matches)
|
buflen)
|
||||||
{
|
{
|
||||||
char *dirname, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
|
char *dirname = mallocstrcpy(NULL, buf);
|
||||||
char **matches = (char **)NULL;
|
char *filename;
|
||||||
|
#ifndef DISABLE_OPERATINGDIR
|
||||||
|
size_t dirnamelen;
|
||||||
|
#endif
|
||||||
|
size_t filenamelen;
|
||||||
|
char **matches = NULL;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *next;
|
const struct dirent *next;
|
||||||
|
|
||||||
matches = (char **)nmalloc(BUFSIZ * sizeof(char *));
|
assert(dirname != NULL && num_matches != NULL && buflen >= 0);
|
||||||
|
|
||||||
/* Stick a wildcard onto the buf, for later use */
|
*num_matches = 0;
|
||||||
strcat(buf, "*");
|
null_at(&dirname, buflen);
|
||||||
|
|
||||||
/* Okie, if there's a / in the buffer, strip out the directory part */
|
/* Okie, if there's a / in the buffer, strip out the directory
|
||||||
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
|
* part. */
|
||||||
dirname = charalloc(strlen(buf) + 1);
|
filename = strrchr(dirname, '/');
|
||||||
tmp = buf + strlen(buf);
|
if (filename != NULL) {
|
||||||
while (*tmp != '/' && tmp != buf)
|
char *tmpdirname = filename + 1;
|
||||||
tmp--;
|
|
||||||
|
|
||||||
tmp++;
|
|
||||||
|
|
||||||
strncpy(dirname, buf, tmp - buf + 1);
|
|
||||||
dirname[tmp - buf] = '\0';
|
|
||||||
|
|
||||||
|
filename = mallocstrcpy(NULL, tmpdirname);
|
||||||
|
*tmpdirname = '\0';
|
||||||
|
tmpdirname = dirname;
|
||||||
|
dirname = real_dir_from_tilde(dirname);
|
||||||
|
free(tmpdirname);
|
||||||
} else {
|
} else {
|
||||||
|
filename = dirname;
|
||||||
if ((dirname = getcwd(NULL, PATH_MAX + 1)) == NULL)
|
dirname = mallocstrcpy(NULL, "./");
|
||||||
return matches;
|
|
||||||
else
|
|
||||||
tmp = buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
assert(dirname[strlen(dirname) - 1] == '/');
|
||||||
fprintf(stderr, "\nDir = %s\n", dirname);
|
|
||||||
fprintf(stderr, "\nbuf = %s\n", buf);
|
|
||||||
fprintf(stderr, "\ntmp = %s\n", tmp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dirtmp = real_dir_from_tilde(dirname);
|
|
||||||
free(dirname);
|
|
||||||
dirname = dirtmp;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
fprintf(stderr, "\nDir = %s\n", dirname);
|
|
||||||
fprintf(stderr, "\nbuf = %s\n", buf);
|
|
||||||
fprintf(stderr, "\ntmp = %s\n", tmp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
dir = opendir(dirname);
|
dir = opendir(dirname);
|
||||||
|
|
||||||
if (dir == NULL) {
|
if (dir == NULL) {
|
||||||
/* Don't print an error, just shut up and return */
|
/* Don't print an error, just shut up and return. */
|
||||||
*num_matches = 0;
|
|
||||||
beep();
|
beep();
|
||||||
return matches;
|
free(filename);
|
||||||
|
free(dirname);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_OPERATINGDIR
|
||||||
|
dirnamelen = strlen(dirname);
|
||||||
|
#endif
|
||||||
|
filenamelen = strlen(filename);
|
||||||
|
|
||||||
while ((next = readdir(dir)) != NULL) {
|
while ((next = readdir(dir)) != NULL) {
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
|
fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
|
||||||
#endif
|
#endif
|
||||||
/* See if this matches */
|
/* See if this matches. */
|
||||||
if (check_wildcard_match(next->d_name, tmp)) {
|
if (strncmp(next->d_name, filename, filenamelen) == 0 &&
|
||||||
|
(*filename == '.' || (strcmp(next->d_name, ".") != 0 &&
|
||||||
/* Cool, found a match. Add it to the list
|
strcmp(next->d_name, "..") != 0))) {
|
||||||
* This makes a lot more sense to me (Chris) this way...
|
/* Cool, found a match. Add it to the list. This makes a
|
||||||
*/
|
* lot more sense to me (Chris) this way... */
|
||||||
|
|
||||||
#ifndef DISABLE_OPERATINGDIR
|
#ifndef DISABLE_OPERATINGDIR
|
||||||
/* ...unless the match exists outside the operating
|
/* ...unless the match exists outside the operating
|
||||||
directory, in which case just go to the next match; to
|
* directory, in which case just go to the next match. To
|
||||||
properly do operating directory checking, we have to add the
|
* properly do operating directory checking, we have to add
|
||||||
directory name to the beginning of the proposed match
|
* the directory name to the beginning of the proposed match
|
||||||
before we check it */
|
* before we check it. */
|
||||||
|
char *tmp2 = charalloc(strlen(dirname) +
|
||||||
|
strlen(next->d_name) + 1);
|
||||||
|
|
||||||
if (operating_dir != NULL) {
|
sprintf(tmp2, "%s%s", dirname, next->d_name);
|
||||||
tmp2 = charalloc(strlen(dirname) + strlen(next->d_name) + 2);
|
if (check_operating_dir(tmp2, TRUE)) {
|
||||||
strcpy(tmp2, dirname);
|
|
||||||
strcat(tmp2, "/");
|
|
||||||
strcat(tmp2, next->d_name);
|
|
||||||
if (check_operating_dir(tmp2, TRUE) != 0) {
|
|
||||||
free(tmp2);
|
free(tmp2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
free(tmp2);
|
free(tmp2);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tmp2 = NULL;
|
matches = (char **)nrealloc(matches, (*num_matches + 1) *
|
||||||
tmp2 = charalloc(strlen(next->d_name) + 1);
|
sizeof(char *));
|
||||||
strcpy(tmp2, next->d_name);
|
matches[*num_matches] = mallocstrcpy(NULL, next->d_name);
|
||||||
matches[*num_matches] = tmp2;
|
++(*num_matches);
|
||||||
++*num_matches;
|
|
||||||
|
|
||||||
/* If there's no more room, bail out */
|
|
||||||
if (*num_matches == BUFSIZ)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
free(dirname);
|
free(dirname);
|
||||||
|
free(filename);
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function now has an arg which refers to how much the statusbar
|
/* Do tab completion. This function now has an arg which refers to how
|
||||||
* (place) should be advanced, i.e. the new cursor pos. */
|
* much the statusbar cursor position (place) should be advanced. */
|
||||||
char *input_tab(char *buf, int place, bool *lastwastab, int *newplace,
|
char *input_tab(char *buf, size_t *place, bool *lastwastab, bool *list)
|
||||||
bool *list)
|
|
||||||
{
|
{
|
||||||
/* Do TAB completion */
|
size_t num_matches = 0;
|
||||||
static int num_matches = 0, match_matches = 0;
|
char **matches = NULL;
|
||||||
static char **matches = (char **)NULL;
|
|
||||||
int pos = place, i = 0, col = 0, editline = 0;
|
|
||||||
int longestname = 0, is_dir = 0;
|
|
||||||
char *foo;
|
|
||||||
|
|
||||||
*list = FALSE;
|
assert(buf != NULL && place != NULL && *place <= strlen(buf) && lastwastab != NULL && list != NULL);
|
||||||
|
|
||||||
if (*lastwastab == FALSE) {
|
*list = 0;
|
||||||
char *tmp, *copyto, *matchbuf;
|
|
||||||
|
|
||||||
*lastwastab = TRUE;
|
|
||||||
|
|
||||||
/* Make a local copy of the string -- up to the position of the
|
|
||||||
cursor */
|
|
||||||
matchbuf = charalloc(strlen(buf) + 2);
|
|
||||||
memset(matchbuf, '\0', strlen(buf) + 2);
|
|
||||||
|
|
||||||
strncpy(matchbuf, buf, place);
|
|
||||||
tmp = matchbuf;
|
|
||||||
|
|
||||||
/* skip any leading white space */
|
|
||||||
while (*tmp && is_blank_char(*tmp))
|
|
||||||
++tmp;
|
|
||||||
|
|
||||||
/* Free up any memory already allocated */
|
|
||||||
if (matches != NULL) {
|
|
||||||
for (i = i; i < num_matches; i++)
|
|
||||||
free(matches[i]);
|
|
||||||
free(matches);
|
|
||||||
matches = (char **)NULL;
|
|
||||||
num_matches = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the word starts with `~' and there is no slash in the word,
|
/* If the word starts with `~' and there is no slash in the word,
|
||||||
* then try completing this word as a username. */
|
* then try completing this word as a username. */
|
||||||
|
if (*place > 0 && *buf == '~') {
|
||||||
|
const char *bob = strchr(buf, '/');
|
||||||
|
|
||||||
/* If the original string begins with a tilde, and the part
|
if (bob == NULL || bob >= buf + *place)
|
||||||
we're trying to tab-complete doesn't contain a slash, copy
|
matches = username_tab_completion(buf, &num_matches,
|
||||||
the part we're tab-completing into buf, so tab completion
|
*place);
|
||||||
will result in buf's containing only the tab-completed
|
|
||||||
username. */
|
|
||||||
if (buf[0] == '~' && strchr(tmp, '/') == NULL) {
|
|
||||||
buf = mallocstrcpy(buf, tmp);
|
|
||||||
matches = username_tab_completion(tmp, &num_matches);
|
|
||||||
}
|
}
|
||||||
/* If we're in the middle of the original line, copy the string
|
|
||||||
only up to the cursor position into buf, so tab completion
|
|
||||||
will result in buf's containing only the tab-completed
|
|
||||||
path/filename. */
|
|
||||||
else if (strlen(buf) > strlen(tmp))
|
|
||||||
buf = mallocstrcpy(buf, tmp);
|
|
||||||
|
|
||||||
/* Try to match everything in the current working directory that
|
/* Match against files relative to the current working directory. */
|
||||||
* matches. */
|
|
||||||
if (matches == NULL)
|
if (matches == NULL)
|
||||||
matches = cwd_tab_completion(tmp, &num_matches);
|
matches = cwd_tab_completion(buf, &num_matches, *place);
|
||||||
|
|
||||||
/* Don't leak memory */
|
if (num_matches <= 0)
|
||||||
free(matchbuf);
|
beep();
|
||||||
|
else {
|
||||||
#ifdef DEBUG
|
size_t match, common_len = 0;
|
||||||
fprintf(stderr, "%d matches found...\n", num_matches);
|
size_t lastslash = strrchrn(buf, '/', *place);
|
||||||
#endif
|
/* Ignore the first match_strip characters of matches
|
||||||
/* Did we find exactly one match? */
|
* entries. The entries of matches are tilde expanded. */
|
||||||
switch (num_matches) {
|
char *mzero;
|
||||||
case 0:
|
|
||||||
blank_edit();
|
|
||||||
wrefresh(edit);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
|
|
||||||
buf = charealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
|
|
||||||
|
|
||||||
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
|
|
||||||
for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
|
|
||||||
tmp--);
|
|
||||||
tmp++;
|
|
||||||
} else
|
|
||||||
tmp = buf;
|
|
||||||
|
|
||||||
if (strcmp(tmp, matches[0]) == 0)
|
|
||||||
is_dir = append_slash_if_dir(buf, lastwastab, newplace);
|
|
||||||
|
|
||||||
if (is_dir != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
copyto = tmp;
|
|
||||||
for (pos = 0; *tmp == matches[0][pos] &&
|
|
||||||
pos <= strlen(matches[0]); pos++)
|
|
||||||
tmp++;
|
|
||||||
|
|
||||||
/* write out the matched name */
|
|
||||||
strncpy(copyto, matches[0], strlen(matches[0]) + 1);
|
|
||||||
*newplace += strlen(matches[0]) - pos;
|
|
||||||
|
|
||||||
/* if an exact match is typed in and Tab is pressed,
|
|
||||||
*newplace will now be negative; in that case, make it
|
|
||||||
zero, so that the cursor will stay where it is instead of
|
|
||||||
moving backward */
|
|
||||||
if (*newplace < 0)
|
|
||||||
*newplace = 0;
|
|
||||||
|
|
||||||
/* Is it a directory? */
|
|
||||||
append_slash_if_dir(buf, lastwastab, newplace);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Check to see if all matches share a beginning, and, if so,
|
|
||||||
tack it onto buf and then beep */
|
|
||||||
|
|
||||||
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
|
|
||||||
for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
|
|
||||||
tmp--);
|
|
||||||
tmp++;
|
|
||||||
} else
|
|
||||||
tmp = buf;
|
|
||||||
|
|
||||||
for (pos = 0; *tmp == matches[0][pos] && *tmp != '\0' &&
|
|
||||||
pos <= strlen(matches[0]); pos++)
|
|
||||||
tmp++;
|
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
match_matches = 0;
|
for (match = 1; match < num_matches; match++) {
|
||||||
|
if (matches[0][common_len] !=
|
||||||
for (i = 0; i < num_matches; i++) {
|
matches[match][common_len])
|
||||||
if (matches[i][pos] == 0)
|
|
||||||
break;
|
break;
|
||||||
else if (matches[i][pos] == matches[0][pos])
|
|
||||||
match_matches++;
|
|
||||||
}
|
}
|
||||||
if (match_matches == num_matches &&
|
|
||||||
(i == num_matches || matches[i] != 0)) {
|
if (match < num_matches || matches[0][common_len] == '\0')
|
||||||
/* All the matches have the same character at pos+1,
|
break;
|
||||||
so paste it into buf... */
|
|
||||||
buf = charealloc(buf, strlen(buf) + 2);
|
common_len++;
|
||||||
strncat(buf, matches[0] + pos, 1);
|
}
|
||||||
*newplace += 1;
|
|
||||||
pos++;
|
mzero = charalloc(lastslash + common_len + 1);
|
||||||
} else {
|
sprintf(mzero, "%.*s%.*s", lastslash, buf, common_len,
|
||||||
|
matches[0]);
|
||||||
|
|
||||||
|
common_len += lastslash;
|
||||||
|
|
||||||
|
assert(common_len >= *place);
|
||||||
|
|
||||||
|
if (num_matches == 1 && is_dir(mzero)) {
|
||||||
|
mzero[common_len] = '/';
|
||||||
|
common_len++;
|
||||||
|
assert(common_len > *place);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_matches > 1 && (common_len != *place ||
|
||||||
|
*lastwastab == FALSE))
|
||||||
beep();
|
beep();
|
||||||
|
|
||||||
|
/* If there is more match to display on the statusbar, show it.
|
||||||
|
* We reset lastwastab to FALSE: it requires hitting Tab twice
|
||||||
|
* in succession with no statusbar changes to see a match
|
||||||
|
* list. */
|
||||||
|
if (common_len != *place) {
|
||||||
|
size_t buflen = strlen(buf);
|
||||||
|
|
||||||
|
*lastwastab = FALSE;
|
||||||
|
buf = charealloc(buf, common_len + buflen - *place + 1);
|
||||||
|
charmove(buf + common_len, buf + *place, buflen - *place + 1);
|
||||||
|
strncpy(buf, mzero, common_len);
|
||||||
|
*place = common_len;
|
||||||
|
} else if (*lastwastab == FALSE || num_matches < 2)
|
||||||
|
*lastwastab = TRUE;
|
||||||
|
else {
|
||||||
|
int longest_name = 0, editline = 0;
|
||||||
|
size_t columns;
|
||||||
|
|
||||||
|
/* Now we show a list of the available choices. */
|
||||||
|
assert(num_matches > 1);
|
||||||
|
|
||||||
|
/* Sort the list. */
|
||||||
|
qsort(matches, num_matches, sizeof(char *), diralphasort);
|
||||||
|
|
||||||
|
for (match = 0; match < num_matches; match++) {
|
||||||
|
common_len = strnlenpt(matches[match], COLS - 1);
|
||||||
|
if (common_len > COLS - 1) {
|
||||||
|
longest_name = COLS - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (common_len > longest_name)
|
||||||
|
longest_name = common_len;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Ok -- the last char was a TAB. Since they
|
|
||||||
* just hit TAB again, print a list of all the
|
|
||||||
* available choices... */
|
|
||||||
if (matches != NULL && num_matches > 1) {
|
|
||||||
|
|
||||||
/* Blank the edit window, and print the matches out there */
|
assert(longest_name <= COLS - 1);
|
||||||
|
|
||||||
|
/* Each column will be longest_name + 2 characters wide,
|
||||||
|
* i.e, two spaces between columns, except that there will
|
||||||
|
* be only one space after the last column. */
|
||||||
|
columns = (COLS + 1) / (longest_name + 2);
|
||||||
|
|
||||||
|
/* Blank the edit window, and print the matches out
|
||||||
|
* there. */
|
||||||
blank_edit();
|
blank_edit();
|
||||||
wmove(edit, 0, 0);
|
wmove(edit, 0, 0);
|
||||||
|
|
||||||
editline = 0;
|
/* Disable el cursor. */
|
||||||
|
|
||||||
/* Figure out the length of the longest filename */
|
|
||||||
for (i = 0; i < num_matches; i++)
|
|
||||||
if (strlen(matches[i]) > longestname)
|
|
||||||
longestname = strlen(matches[i]);
|
|
||||||
|
|
||||||
if (longestname > COLS - 1)
|
|
||||||
longestname = COLS - 1;
|
|
||||||
|
|
||||||
foo = charalloc(longestname + 5);
|
|
||||||
|
|
||||||
/* Print the list of matches */
|
|
||||||
for (i = 0, col = 0; i < num_matches; i++) {
|
|
||||||
|
|
||||||
/* make each filename shown be the same length as the
|
|
||||||
longest filename, with two spaces at the end */
|
|
||||||
snprintf(foo, longestname + 1, "%s", matches[i]);
|
|
||||||
while (strlen(foo) < longestname)
|
|
||||||
strcat(foo, " ");
|
|
||||||
|
|
||||||
strcat(foo, " ");
|
|
||||||
|
|
||||||
/* Disable el cursor */
|
|
||||||
curs_set(0);
|
curs_set(0);
|
||||||
/* now, put the match on the screen */
|
|
||||||
waddnstr(edit, foo, strlen(foo));
|
|
||||||
col += strlen(foo);
|
|
||||||
|
|
||||||
/* And if the next match isn't going to fit on the
|
for (match = 0; match < num_matches; match++) {
|
||||||
line, move to the next one */
|
char *disp;
|
||||||
if (col > COLS - longestname && i + 1 < num_matches) {
|
|
||||||
editline++;
|
wmove(edit, editline, (longest_name + 2) *
|
||||||
wmove(edit, editline, 0);
|
(match % columns));
|
||||||
if (editline == editwinrows - 1) {
|
|
||||||
|
if (match % columns == 0 && editline == editwinrows - 1
|
||||||
|
&& num_matches - match > columns) {
|
||||||
waddstr(edit, _("(more)"));
|
waddstr(edit, _("(more)"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
col = 0;
|
|
||||||
|
disp = display_string(matches[match], 0, longest_name,
|
||||||
|
FALSE);
|
||||||
|
waddstr(edit, disp);
|
||||||
|
free(disp);
|
||||||
|
|
||||||
|
if ((match + 1) % columns == 0)
|
||||||
|
editline++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(foo);
|
|
||||||
wrefresh(edit);
|
wrefresh(edit);
|
||||||
*list = TRUE;
|
*list = TRUE;
|
||||||
} else
|
|
||||||
beep();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(mzero);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_charptrarray(matches, num_matches);
|
||||||
|
|
||||||
/* Only refresh the edit window if we don't have a list of filename
|
/* Only refresh the edit window if we don't have a list of filename
|
||||||
matches on it */
|
* matches on it. */
|
||||||
if (*list == FALSE)
|
if (*list == FALSE)
|
||||||
edit_refresh();
|
edit_refresh();
|
||||||
|
|
||||||
|
/* Enable el cursor. */
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
#endif /* !DISABLE_TABCOMP */
|
#endif /* !DISABLE_TABCOMP */
|
||||||
|
|
||||||
/* Only print the last part of a path; isn't there a shell
|
/* Only print the last part of a path. Isn't there a shell command for
|
||||||
* command for this? */
|
* this? */
|
||||||
const char *tail(const char *foo)
|
const char *tail(const char *foo)
|
||||||
{
|
{
|
||||||
const char *tmp = foo + strlen(foo);
|
const char *tmp = strrchr(foo, '/');
|
||||||
|
|
||||||
while (*tmp != '/' && tmp != foo)
|
if (tmp == NULL)
|
||||||
tmp--;
|
tmp = foo;
|
||||||
|
else if (*tmp == '/')
|
||||||
if (*tmp == '/')
|
|
||||||
tmp++;
|
tmp++;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_BROWSER
|
#ifndef DISABLE_BROWSER
|
||||||
/* Our sort routine for file listings -- sort directories before
|
/* Free our malloc()ed memory. */
|
||||||
* files, and then alphabetically. */
|
|
||||||
int diralphasort(const void *va, const void *vb)
|
|
||||||
{
|
|
||||||
struct stat fileinfo;
|
|
||||||
const char *a = *(char *const *)va, *b = *(char *const *)vb;
|
|
||||||
int aisdir = stat(a, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
|
|
||||||
int bisdir = stat(b, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
|
|
||||||
|
|
||||||
if (aisdir != 0 && bisdir == 0)
|
|
||||||
return -1;
|
|
||||||
if (aisdir == 0 && bisdir != 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return strcasecmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free our malloc()ed memory */
|
|
||||||
void free_charptrarray(char **array, size_t len)
|
void free_charptrarray(char **array, size_t len)
|
||||||
{
|
{
|
||||||
for (; len > 0; len--)
|
for (; len > 0; len--)
|
||||||
|
@ -2419,25 +2343,10 @@ void striponedir(char *foo)
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
assert(foo != NULL);
|
assert(foo != NULL);
|
||||||
/* Don't strip the root dir */
|
|
||||||
if (*foo == '\0' || strcmp(foo, "/") == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tmp = foo + strlen(foo) - 1;
|
tmp = strrchr(foo, '/');
|
||||||
assert(tmp >= foo);
|
if (tmp != NULL)
|
||||||
if (*tmp == '/')
|
|
||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
|
|
||||||
while (*tmp != '/' && tmp != foo)
|
|
||||||
tmp--;
|
|
||||||
|
|
||||||
if (tmp != foo)
|
|
||||||
*tmp = '\0';
|
|
||||||
else { /* SPK may need to make a 'default' path here */
|
|
||||||
if (*tmp != '/')
|
|
||||||
*tmp = '.';
|
|
||||||
*(tmp + 1) = '\0';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int readable_dir(const char *path)
|
int readable_dir(const char *path)
|
||||||
|
@ -2528,7 +2437,7 @@ char *do_browser(const char *inpath)
|
||||||
filelist = browser_init(path, &longest, &numents);
|
filelist = browser_init(path, &longest, &numents);
|
||||||
foo = charalloc(longest + 8);
|
foo = charalloc(longest + 8);
|
||||||
|
|
||||||
/* Sort the list by directory first, then alphabetically */
|
/* Sort the list. */
|
||||||
qsort(filelist, numents, sizeof(char *), diralphasort);
|
qsort(filelist, numents, sizeof(char *), diralphasort);
|
||||||
|
|
||||||
titlebar(path);
|
titlebar(path);
|
||||||
|
|
|
@ -183,9 +183,7 @@ bool curses_ended = FALSE; /* Indicates to statusbar() to simply
|
||||||
* write to stderr, since endwin() has
|
* write to stderr, since endwin() has
|
||||||
* ended curses mode. */
|
* ended curses mode. */
|
||||||
|
|
||||||
#ifdef ENABLE_NANORC
|
|
||||||
char *homedir = NULL; /* $HOME or from /etc/passwd. */
|
char *homedir = NULL; /* $HOME or from /etc/passwd. */
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t length_of_list(const shortcut *s)
|
size_t length_of_list(const shortcut *s)
|
||||||
{
|
{
|
||||||
|
|
31
src/proto.h
31
src/proto.h
|
@ -144,25 +144,23 @@ extern historyheadtype replace_history;
|
||||||
|
|
||||||
extern bool curses_ended;
|
extern bool curses_ended;
|
||||||
|
|
||||||
#ifdef ENABLE_NANORC
|
|
||||||
extern char *homedir;
|
extern char *homedir;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Functions we want available. */
|
/* Functions we want available. */
|
||||||
|
|
||||||
/* Public functions in chars.c. */
|
/* Public functions in chars.c. */
|
||||||
bool is_byte(unsigned int c);
|
bool is_byte(int c);
|
||||||
bool is_alnum_char(unsigned int c);
|
bool is_alnum_char(int c);
|
||||||
bool is_alnum_mbchar(const char *c);
|
bool is_alnum_mbchar(const char *c);
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
bool is_alnum_wchar(wchar_t wc);
|
bool is_alnum_wchar(wchar_t wc);
|
||||||
#endif
|
#endif
|
||||||
bool is_blank_char(unsigned int c);
|
bool is_blank_char(int c);
|
||||||
bool is_blank_mbchar(const char *c);
|
bool is_blank_mbchar(const char *c);
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
bool is_blank_wchar(wchar_t wc);
|
bool is_blank_wchar(wchar_t wc);
|
||||||
#endif
|
#endif
|
||||||
bool is_cntrl_char(unsigned int c);
|
bool is_cntrl_char(int c);
|
||||||
bool is_cntrl_mbchar(const char *c);
|
bool is_cntrl_mbchar(const char *c);
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
bool is_cntrl_wchar(wchar_t wc);
|
bool is_cntrl_wchar(wchar_t wc);
|
||||||
|
@ -174,7 +172,7 @@ wchar_t control_wrep(wchar_t c);
|
||||||
#endif
|
#endif
|
||||||
int mbwidth(const char *c);
|
int mbwidth(const char *c);
|
||||||
int mb_cur_max(void);
|
int mb_cur_max(void);
|
||||||
char *make_mbchar(unsigned int chr, char *chr_mb, int *chr_mb_len);
|
char *make_mbchar(int chr, char *chr_mb, int *chr_mb_len);
|
||||||
int parse_mbchar(const char *buf, char *chr
|
int parse_mbchar(const char *buf, char *chr
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
, bool *bad_chr
|
, bool *bad_chr
|
||||||
|
@ -207,6 +205,7 @@ size_t mbstrlen(const char *s);
|
||||||
size_t nstrnlen(const char *s, size_t maxlen);
|
size_t nstrnlen(const char *s, size_t maxlen);
|
||||||
#endif
|
#endif
|
||||||
size_t mbstrnlen(const char *s, size_t maxlen);
|
size_t mbstrnlen(const char *s, size_t maxlen);
|
||||||
|
size_t strrchrn(const char *s, int c, size_t n);
|
||||||
|
|
||||||
/* Public functions in color.c. */
|
/* Public functions in color.c. */
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
|
@ -287,16 +286,18 @@ int write_marked(const char *name, bool tmp, int append);
|
||||||
int do_writeout(bool exiting);
|
int do_writeout(bool exiting);
|
||||||
void do_writeout_void(void);
|
void do_writeout_void(void);
|
||||||
char *real_dir_from_tilde(const char *buf);
|
char *real_dir_from_tilde(const char *buf);
|
||||||
|
#if !defined(DISABLE_TABCOMP) || !defined(DISABLE_BROWSER)
|
||||||
|
int diralphasort(const void *va, const void *vb);
|
||||||
|
#endif
|
||||||
#ifndef DISABLE_TABCOMP
|
#ifndef DISABLE_TABCOMP
|
||||||
int append_slash_if_dir(char *buf, bool *lastwastab, int *place);
|
char **username_tab_completion(const char *buf, size_t *num_matches,
|
||||||
char **username_tab_completion(char *buf, int *num_matches);
|
size_t buflen);
|
||||||
char **cwd_tab_completion(char *buf, int *num_matches);
|
char **cwd_tab_completion(const char *buf, size_t *num_matches, size_t
|
||||||
char *input_tab(char *buf, int place, bool *lastwastab, int *newplace,
|
buflen);
|
||||||
bool *list);
|
char *input_tab(char *buf, size_t *place, bool *lastwastab, bool *list);
|
||||||
#endif
|
#endif
|
||||||
const char *tail(const char *foo);
|
const char *tail(const char *foo);
|
||||||
#ifndef DISABLE_BROWSER
|
#ifndef DISABLE_BROWSER
|
||||||
int diralphasort(const void *va, const void *vb);
|
|
||||||
void free_charptrarray(char **array, size_t len);
|
void free_charptrarray(char **array, size_t len);
|
||||||
void striponedir(char *foo);
|
void striponedir(char *foo);
|
||||||
int readable_dir(const char *path);
|
int readable_dir(const char *path);
|
||||||
|
@ -531,6 +532,7 @@ int regexec_safe(const regex_t *preg, const char *string, size_t nmatch,
|
||||||
int regexp_bol_or_eol(const regex_t *preg, const char *string);
|
int regexp_bol_or_eol(const regex_t *preg, const char *string);
|
||||||
#endif
|
#endif
|
||||||
int num_of_digits(int n);
|
int num_of_digits(int n);
|
||||||
|
void get_homedir(void);
|
||||||
bool parse_num(const char *str, ssize_t *val);
|
bool parse_num(const char *str, ssize_t *val);
|
||||||
void align(char **strp);
|
void align(char **strp);
|
||||||
void null_at(char **data, size_t index);
|
void null_at(char **data, size_t index);
|
||||||
|
@ -560,9 +562,6 @@ void mark_order(const filestruct **top, size_t *top_x, const filestruct
|
||||||
#endif
|
#endif
|
||||||
void get_totals(const filestruct *begin, const filestruct *end, int
|
void get_totals(const filestruct *begin, const filestruct *end, int
|
||||||
*lines, size_t *size);
|
*lines, size_t *size);
|
||||||
#ifndef DISABLE_TABCOMP
|
|
||||||
int check_wildcard_match(const char *text, const char *pattern);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Public functions in winio.c. */
|
/* Public functions in winio.c. */
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
|
|
14
src/rcfile.c
14
src/rcfile.c
|
@ -30,7 +30,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
@ -666,18 +665,7 @@ void do_rcfile(void)
|
||||||
|
|
||||||
lineno = 0;
|
lineno = 0;
|
||||||
|
|
||||||
{
|
get_homedir();
|
||||||
const char *homenv = getenv("HOME");
|
|
||||||
|
|
||||||
/* Rely on $HOME, fall back on getpwuid() */
|
|
||||||
if (homenv == NULL) {
|
|
||||||
const struct passwd *userage = getpwuid(geteuid());
|
|
||||||
|
|
||||||
if (userage != NULL)
|
|
||||||
homenv = userage->pw_dir;
|
|
||||||
}
|
|
||||||
homedir = mallocstrcpy(NULL, homenv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homedir == NULL) {
|
if (homedir == NULL) {
|
||||||
rcfile_error(N_("I can't find my home directory! Wah!"));
|
rcfile_error(N_("I can't find my home directory! Wah!"));
|
||||||
|
|
120
src/utils.c
120
src/utils.c
|
@ -27,6 +27,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -67,6 +68,23 @@ int num_of_digits(int n)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the user's home directory. We use $HOME, and if that fails,
|
||||||
|
* we fall back on getpwuid(). */
|
||||||
|
void get_homedir(void)
|
||||||
|
{
|
||||||
|
if (homedir == NULL) {
|
||||||
|
const char *homenv = getenv("HOME");
|
||||||
|
|
||||||
|
if (homenv == NULL) {
|
||||||
|
const struct passwd *userage = getpwuid(geteuid());
|
||||||
|
|
||||||
|
if (userage != NULL)
|
||||||
|
homenv = userage->pw_dir;
|
||||||
|
}
|
||||||
|
homedir = mallocstrcpy(NULL, homenv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Read a ssize_t from str, and store it in *val (if val is not NULL).
|
/* Read a ssize_t from str, and store it in *val (if val is not NULL).
|
||||||
* On error, we return FALSE and don't change *val. Otherwise, we
|
* On error, we return FALSE and don't change *val. Otherwise, we
|
||||||
* return TRUE. */
|
* return TRUE. */
|
||||||
|
@ -414,105 +432,3 @@ void get_totals(const filestruct *begin, const filestruct *end, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_TABCOMP
|
|
||||||
/*
|
|
||||||
* Routine to see if a text string is matched by a wildcard pattern.
|
|
||||||
* Returns TRUE if the text is matched, or FALSE if it is not matched
|
|
||||||
* or if the pattern is invalid.
|
|
||||||
* * matches zero or more characters
|
|
||||||
* ? matches a single character
|
|
||||||
* [abc] matches 'a', 'b' or 'c'
|
|
||||||
* \c quotes character c
|
|
||||||
* Adapted from code written by Ingo Wilken, and
|
|
||||||
* then taken from sash, Copyright (c) 1999 by David I. Bell
|
|
||||||
* Permission is granted to use, distribute, or modify this source,
|
|
||||||
* provided that this copyright notice remains intact.
|
|
||||||
* Permission to distribute this code under the GPL has been granted.
|
|
||||||
*/
|
|
||||||
int check_wildcard_match(const char *text, const char *pattern)
|
|
||||||
{
|
|
||||||
const char *retrypat;
|
|
||||||
const char *retrytext;
|
|
||||||
int ch;
|
|
||||||
int found;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
retrypat = NULL;
|
|
||||||
retrytext = NULL;
|
|
||||||
|
|
||||||
while (*text != '\0' || *pattern != '\0') {
|
|
||||||
ch = *pattern++;
|
|
||||||
|
|
||||||
switch (ch) {
|
|
||||||
case '*':
|
|
||||||
retrypat = pattern;
|
|
||||||
retrytext = text;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '[':
|
|
||||||
found = FALSE;
|
|
||||||
|
|
||||||
while ((ch = *pattern++) != ']') {
|
|
||||||
if (ch == '\\')
|
|
||||||
ch = *pattern++;
|
|
||||||
|
|
||||||
if (ch == '\0')
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (*text == ch)
|
|
||||||
found = TRUE;
|
|
||||||
}
|
|
||||||
len = strlen(text);
|
|
||||||
if (!found && len != 0) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
if (strlen(pattern) == 0 && len == 1) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
if (len != 0) {
|
|
||||||
text++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fall into next case */
|
|
||||||
|
|
||||||
case '?':
|
|
||||||
if (*text++ == '\0')
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\\':
|
|
||||||
ch = *pattern++;
|
|
||||||
|
|
||||||
if (ch == '\0')
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* fall into next case */
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (*text == ch) {
|
|
||||||
if (*text != '\0')
|
|
||||||
text++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*text != '\0') {
|
|
||||||
pattern = retrypat;
|
|
||||||
text = ++retrytext;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern == NULL)
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
12
src/winio.c
12
src/winio.c
|
@ -2530,17 +2530,11 @@ int nanogetstr(bool allow_tabs, const char *buf, const char *def,
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_TABCOMP
|
#ifndef DISABLE_TABCOMP
|
||||||
if (allow_tabs) {
|
if (allow_tabs) {
|
||||||
int shift = 0;
|
answer = input_tab(answer, &statusbar_x, &tabbed, list);
|
||||||
|
statusbar_xend = statusbar_x;
|
||||||
answer = input_tab(answer, statusbar_x, &tabbed, &shift,
|
|
||||||
list);
|
|
||||||
statusbar_xend = strlen(answer);
|
|
||||||
statusbar_x += shift;
|
|
||||||
if (statusbar_x > statusbar_xend)
|
|
||||||
statusbar_x = statusbar_xend;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case NANO_PREVLINE_KEY:
|
case NANO_PREVLINE_KEY:
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
if (history_list != NULL) {
|
if (history_list != NULL) {
|
||||||
|
|
Loading…
Reference in New Issue