📄 complete.c
字号:
/* Input line filename/username/hostname/variable/command completion.
(Let mc type for you...)
Copyright (C) 1995 The Free Software Foundation
Written by: 1995 Jakub Jelinek
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
#include "tty.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
# ifdef __os2__
# include "dirent.h"
# else
# include <dirent.h>
# endif
# define NLENGTH(dirent) (strlen ((dirent)->d_name))
#else
# define dirent direct
# define NLENGTH(dirent) ((dirent)->d_namlen)
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYS_DIR_H */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif /* HAVE_NDIR_H */
#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
#include <sys/types.h>
#include <sys/stat.h>
#ifndef OS2_NT
# include <pwd.h>
#endif
#include "global.h"
#include "mad.h"
#include "util.h"
#include "win.h"
#include "color.h"
#include "dlg.h"
#include "widget.h"
#include "dialog.h"
#include "wtools.h"
#include "complete.h"
#include "main.h"
#include "key.h" /* XCTRL and ALT macros */
/* This flag is used in filename_completion_function */
int ignore_filenames = 0;
/* This flag is used by command_completion_function */
/* to hint the filename_completion_function */
int look_for_executables = 0;
char *filename_completion_function (char *text, int state)
{
static DIR *directory;
static char *filename = NULL;
static char *dirname = NULL;
static char *users_dirname = NULL;
static int filename_len;
int isdir = 1, isexec = 0;
struct dirent *entry = NULL;
/* If we're starting the match process, initialize us a bit. */
if (!state){
char *temp;
if (dirname)
free (dirname);
if (filename)
free (filename);
if (users_dirname)
free (users_dirname);
filename = strdup (text);
if (!*text)
text = ".";
dirname = strdup (text);
temp = strrchr (dirname, PATH_SEP);
if (temp){
strcpy (filename, ++temp);
*temp = 0;
}
else
strcpy (dirname, ".");
/* We aren't done yet. We also support the "~user" syntax. */
/* Save the version of the directory that the user typed. */
users_dirname = strdup (dirname);
{
char *temp_dirname;
temp_dirname = tilde_expand (dirname);
if (!temp_dirname){
free (dirname);
free (users_dirname);
free (filename);
dirname = users_dirname = filename = NULL;
return NULL;
}
free (dirname);
dirname = temp_dirname;
canonicalize_pathname (dirname);
/* Here we should do something with variable expansion
and `command`.
Maybe a dream - UNIMPLEMENTED yet. */
}
directory = opendir (dirname);
filename_len = strlen (filename);
}
/* Now that we have some state, we can read the directory. */
while (directory && (entry = readdir (directory))){
/* Special case for no filename.
All entries except "." and ".." match. */
if (!filename_len){
if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
continue;
} else {
/* Otherwise, if these match up to the length of filename, then
it may be a match. */
if ((entry->d_name[0] != filename[0]) ||
((NLENGTH (entry)) < filename_len) ||
strncmp (filename, entry->d_name, filename_len))
continue;
}
isdir = 1; isexec = 0;
{
char *tmp = xmalloc (3 + strlen (dirname) + NLENGTH (entry), "Filename completion");
struct stat tempstat;
strcpy (tmp, dirname);
strcat (tmp, PATH_SEP_STR);
strcat (tmp, entry->d_name);
canonicalize_pathname (tmp);
/* Unix version */
if (!stat (tmp, &tempstat)){
uid_t my_uid = getuid ();
gid_t my_gid = getgid ();
if (!S_ISDIR (tempstat.st_mode)){
isdir = 0;
if ((!my_uid && (tempstat.st_mode & 0111)) ||
(my_uid == tempstat.st_uid && (tempstat.st_mode & 0100)) ||
(my_gid == tempstat.st_gid && (tempstat.st_mode & 0010)) ||
(tempstat.st_mode & 0001))
isexec = 1;
}
}
free (tmp);
}
switch (look_for_executables)
{
case 2: if (!isexec)
continue;
break;
case 1: if (!isexec && !isdir)
continue;
break;
}
if (ignore_filenames && !isdir)
continue;
break;
}
if (!entry){
if (directory){
closedir (directory);
directory = NULL;
}
if (dirname){
free (dirname);
dirname = NULL;
}
if (filename){
free (filename);
filename = NULL;
}
if (users_dirname){
free (users_dirname);
users_dirname = NULL;
}
return NULL;
} else {
char *temp;
if (users_dirname && (users_dirname[0] != '.' || users_dirname[1])){
int dirlen = strlen (users_dirname);
temp = xmalloc (3 + dirlen + NLENGTH (entry), "Filename completion");
strcpy (temp, users_dirname);
/* We need a `/' at the end. */
if (users_dirname[dirlen - 1] != PATH_SEP){
temp[dirlen] = PATH_SEP;
temp[dirlen + 1] = 0;
}
strcat (temp, entry->d_name);
} else {
temp = xmalloc (2 + NLENGTH (entry), "Filename completion");
strcpy (temp, entry->d_name);
}
if (isdir)
strcat (temp, PATH_SEP_STR);
return temp;
}
}
/* We assume here that text[0] == '~' , if you want to call it in another way,
you have to change the code */
#ifdef OS2_NT
char *username_completion_function (char *text, int state)
{
return NULL;
}
#else
char *username_completion_function (char *text, int state)
{
static struct passwd *entry;
static int userlen;
if (!state){ /* Initialization stuff */
setpwent ();
userlen = strlen (text + 1);
}
while ((entry = getpwent ()) != NULL){
/* Null usernames should result in all users as possible completions. */
if (!userlen)
break;
else if (text[1] == entry->pw_name[0] &&
!strncmp (text + 1, entry->pw_name, userlen))
break;
}
if (!entry){
endpwent ();
return NULL;
} else {
char *temp = xmalloc (3 + strlen (entry->pw_name), "Username completion");
*temp = '~';
strcpy (temp + 1, entry->pw_name);
strcat (temp, PATH_SEP_STR);
return temp;
}
}
extern char **environ;
#endif /* OS2_NT */
/* We assume text [0] == '$' and want to have a look at text [1], if it is
equal to '{', so that we should append '}' at the end */
char *variable_completion_function (char *text, int state)
{
static char **env_p;
static int varlen, isbrace;
char *p = 0;
if (!state){ /* Initialization stuff */
isbrace = (text [1] == '{');
varlen = strlen (text + 1 + isbrace);
env_p = environ;
}
while (*env_p){
p = strchr (*env_p, '=');
if (p && p - *env_p >= varlen && !strncmp (text + 1 + isbrace, *env_p, varlen))
break;
env_p++;
}
if (!*env_p)
return NULL;
else {
char *temp = xmalloc (2 + 2 * isbrace + p - *env_p, "Variable completion");
*temp = '$';
if (isbrace)
temp [1] = '{';
strncpy (temp + 1 + isbrace, *env_p, p - *env_p);
if (isbrace)
strcpy (temp + 2 + (p - *env_p), "}");
else
temp [1 + p - *env_p] = 0;
env_p++;
return temp;
}
}
#define whitespace(c) ((c) == ' ' || (c) == '\t')
#define cr_whitespace(c) (whitespace (c) || (c) == '\n' || (c) == '\r')
static char **hosts = NULL;
static char **hosts_p = NULL;
static int hosts_alloclen = 0;
static void fetch_hosts (char *filename)
{
FILE *file = fopen (filename, "r");
char *temp, buffer[256], *name;
register int i, start;
if (!file)
return;
while ((temp = fgets (buffer, 255, file)) != NULL){
/* Skip to first character. */
for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++);
/* Ignore comments... */
if (buffer[i] == '#')
continue;
/* Handle $include. */
if (!strncmp (buffer + i, "$include ", 9)){
char *includefile = buffer + i + 9;
char *t;
/* Find start of filename. */
while (*includefile && whitespace (*includefile))
includefile++;
t = includefile;
/* Find end of filename. */
while (*t && !cr_whitespace (*t))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -