mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-11 04:30:44 +02:00
commit bash-20080501 snapshot
This commit is contained in:
+201
-25
@@ -1,6 +1,6 @@
|
||||
/* glob.c -- file-name wildcard pattern matching for Bash.
|
||||
|
||||
Copyright (C) 1985-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1985-2008 Free Software Foundation, Inc.
|
||||
|
||||
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
|
||||
@@ -45,7 +45,8 @@
|
||||
|
||||
#include "stdc.h"
|
||||
#include "memalloc.h"
|
||||
#include "quit.h"
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#include "glob.h"
|
||||
#include "strmatch.h"
|
||||
@@ -72,8 +73,15 @@
|
||||
# define ALLOCA_MAX 100000
|
||||
#endif
|
||||
|
||||
struct globval
|
||||
{
|
||||
struct globval *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
extern void throw_to_top_level __P((void));
|
||||
extern int sh_eaccess __P((char *, int));
|
||||
extern char *sh_makepath __P((const char *, const char *, int));
|
||||
|
||||
extern int extended_glob;
|
||||
|
||||
@@ -88,10 +96,12 @@ int glob_ignore_case = 0;
|
||||
/* Global variable to return to signify an error in globbing. */
|
||||
char *glob_error_return;
|
||||
|
||||
static struct globval finddirs_error_return;
|
||||
|
||||
/* Some forward declarations. */
|
||||
static int skipname __P((char *, char *));
|
||||
static int skipname __P((char *, char *, int));
|
||||
#if HANDLE_MULTIBYTE
|
||||
static int mbskipname __P((char *, char *));
|
||||
static int mbskipname __P((char *, char *, int));
|
||||
#endif
|
||||
#if HANDLE_MULTIBYTE
|
||||
static void udequote_pathname __P((char *));
|
||||
@@ -154,9 +164,10 @@ glob_pattern_p (pattern)
|
||||
with matching leading `.'. */
|
||||
|
||||
static int
|
||||
skipname (pat, dname)
|
||||
skipname (pat, dname, flags)
|
||||
char *pat;
|
||||
char *dname;
|
||||
int flags;
|
||||
{
|
||||
/* If a leading dot need not be explicitly matched, and the pattern
|
||||
doesn't start with a `.', don't match `.' or `..' */
|
||||
@@ -179,8 +190,9 @@ skipname (pat, dname)
|
||||
characters in PAT and DNAME. Mostly concerned with matching leading `.'. */
|
||||
|
||||
static int
|
||||
mbskipname (pat, dname)
|
||||
mbskipname (pat, dname, flags)
|
||||
char *pat, *dname;
|
||||
int flags;
|
||||
{
|
||||
int ret;
|
||||
wchar_t *pat_wc, *dn_wc;
|
||||
@@ -315,6 +327,75 @@ glob_testdir (dir)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Recursively scan SDIR for directories matching PAT (PAT is always `**').
|
||||
FLAGS is simply passed down to the recursive call to glob_vector. Returns
|
||||
a list of matching directory names. EP, if non-null, is set to the last
|
||||
element of the returned list. NP, if non-null, is set to the number of
|
||||
directories in the returned list. These two variables exist for the
|
||||
convenience of the caller (always glob_vector). */
|
||||
static struct globval *
|
||||
finddirs (pat, sdir, flags, ep, np)
|
||||
char *pat;
|
||||
char *sdir;
|
||||
int flags;
|
||||
struct globval **ep;
|
||||
int *np;
|
||||
{
|
||||
char **r, *n;
|
||||
int ndirs;
|
||||
struct globval *ret, *e, *g;
|
||||
|
||||
/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/
|
||||
e = ret = 0;
|
||||
r = glob_vector (pat, sdir, flags);
|
||||
if (r == 0 || r[0] == 0)
|
||||
{
|
||||
if (np)
|
||||
*np = 0;
|
||||
if (ep)
|
||||
*ep = 0;
|
||||
if (r)
|
||||
free (r);
|
||||
return (struct globval *)0;
|
||||
}
|
||||
for (ndirs = 0; r[ndirs] != 0; ndirs++)
|
||||
{
|
||||
g = (struct globval *) malloc (sizeof (struct globval));
|
||||
if (g == 0)
|
||||
{
|
||||
while (ret) /* free list built so far */
|
||||
{
|
||||
g = ret->next;
|
||||
free (ret);
|
||||
ret = g;
|
||||
}
|
||||
|
||||
free (r);
|
||||
if (np)
|
||||
*np = 0;
|
||||
if (ep)
|
||||
*ep = 0;
|
||||
return (&finddirs_error_return);
|
||||
}
|
||||
if (e == 0)
|
||||
e = g;
|
||||
|
||||
g->next = ret;
|
||||
ret = g;
|
||||
|
||||
g->name = r[ndirs];
|
||||
}
|
||||
|
||||
free (r);
|
||||
if (ep)
|
||||
*ep = e;
|
||||
if (np)
|
||||
*np = ndirs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Return a vector of names of files in directory DIR
|
||||
whose names match glob pattern PAT.
|
||||
The names are not in any particular order.
|
||||
@@ -337,31 +418,27 @@ glob_vector (pat, dir, flags)
|
||||
char *dir;
|
||||
int flags;
|
||||
{
|
||||
struct globval
|
||||
{
|
||||
struct globval *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
DIR *d;
|
||||
register struct dirent *dp;
|
||||
struct globval *lastlink;
|
||||
struct globval *lastlink, *e, *dirlist;
|
||||
register struct globval *nextlink;
|
||||
register char *nextname, *npat;
|
||||
register char *nextname, *npat, *subdir;
|
||||
unsigned int count;
|
||||
int lose, skip;
|
||||
int lose, skip, ndirs, isdir, sdlen, add_current;
|
||||
register char **name_vector;
|
||||
register unsigned int i;
|
||||
int mflags; /* Flags passed to strmatch (). */
|
||||
int pflags; /* flags passed to sh_makepath () */
|
||||
int nalloca;
|
||||
struct globval *firstmalloc, *tmplink;
|
||||
|
||||
lastlink = 0;
|
||||
count = lose = skip = 0;
|
||||
count = lose = skip = add_current = 0;
|
||||
|
||||
firstmalloc = 0;
|
||||
nalloca = 0;
|
||||
|
||||
/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
|
||||
/* If PAT is empty, skip the loop, but return one (empty) filename. */
|
||||
if (pat == 0 || *pat == '\0')
|
||||
{
|
||||
@@ -463,6 +540,8 @@ glob_vector (pat, dir, flags)
|
||||
if (extended_glob)
|
||||
mflags |= FNM_EXTMATCH;
|
||||
|
||||
add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR));
|
||||
|
||||
/* Scan the directory, finding all names that match.
|
||||
For each name that matches, allocate a struct globval
|
||||
on the stack and store the name in it.
|
||||
@@ -490,13 +569,69 @@ glob_vector (pat, dir, flags)
|
||||
#endif
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name))
|
||||
if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags))
|
||||
continue;
|
||||
else
|
||||
#endif
|
||||
if (skipname (pat, dp->d_name))
|
||||
if (skipname (pat, dp->d_name, flags))
|
||||
continue;
|
||||
|
||||
/* If we're only interested in directories, don't bother with files */
|
||||
if (flags & (GX_MATCHDIRS|GX_ALLDIRS))
|
||||
{
|
||||
pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0;
|
||||
if (flags & GX_NULLDIR)
|
||||
pflags |= MP_IGNDOT;
|
||||
subdir = sh_makepath (dir, dp->d_name, pflags);
|
||||
isdir = glob_testdir (subdir);
|
||||
if (isdir < 0 && (flags & GX_MATCHDIRS))
|
||||
{
|
||||
free (subdir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & GX_ALLDIRS)
|
||||
{
|
||||
if (isdir == 0)
|
||||
{
|
||||
dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs);
|
||||
if (dirlist == &finddirs_error_return)
|
||||
{
|
||||
free (subdir);
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
if (ndirs) /* add recursive directories to list */
|
||||
{
|
||||
if (firstmalloc == 0)
|
||||
firstmalloc = e;
|
||||
e->next = lastlink;
|
||||
lastlink = dirlist;
|
||||
count += ndirs;
|
||||
}
|
||||
}
|
||||
|
||||
nextlink = (struct globval *) malloc (sizeof (struct globval));
|
||||
if (firstmalloc == 0)
|
||||
firstmalloc = nextlink;
|
||||
sdlen = strlen (subdir);
|
||||
nextname = (char *) malloc (sdlen + 1);
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
{
|
||||
free (subdir);
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
nextlink->next = lastlink;
|
||||
lastlink = nextlink;
|
||||
nextlink->name = nextname;
|
||||
bcopy (subdir, nextname, sdlen + 1);
|
||||
free (subdir);
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH)
|
||||
{
|
||||
if (nalloca < ALLOCA_MAX)
|
||||
@@ -510,6 +645,7 @@ glob_vector (pat, dir, flags)
|
||||
if (firstmalloc == 0)
|
||||
firstmalloc = nextlink;
|
||||
}
|
||||
|
||||
nextname = (char *) malloc (D_NAMLEN (dp) + 1);
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
{
|
||||
@@ -527,6 +663,27 @@ glob_vector (pat, dir, flags)
|
||||
(void) closedir (d);
|
||||
}
|
||||
|
||||
/* compat: if GX_ALLDIRS, add the passed directory also */
|
||||
if (add_current)
|
||||
{
|
||||
sdlen = strlen (dir);
|
||||
nextname = (char *)malloc (sdlen + 1);
|
||||
nextlink = (struct globval *) malloc (sizeof (struct globval));
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
lose = 1;
|
||||
else
|
||||
{
|
||||
nextlink->name = nextname;
|
||||
nextlink->next = lastlink;
|
||||
lastlink = nextlink;
|
||||
if (flags & GX_NULLDIR)
|
||||
nextname[0] = '\0';
|
||||
else
|
||||
bcopy (dir, nextname, sdlen + 1);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (lose == 0)
|
||||
{
|
||||
name_vector = (char **) malloc ((count + 1) * sizeof (char *));
|
||||
@@ -585,7 +742,7 @@ glob_vector (pat, dir, flags)
|
||||
free (tmplink);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (name_vector);
|
||||
}
|
||||
|
||||
@@ -678,9 +835,10 @@ glob_filename (pathname, flags)
|
||||
{
|
||||
char **result;
|
||||
unsigned int result_size;
|
||||
char *directory_name, *filename;
|
||||
char *directory_name, *filename, *dname;
|
||||
unsigned int directory_len;
|
||||
int free_dirname; /* flag */
|
||||
int dflags;
|
||||
|
||||
result = (char **) malloc (sizeof (char *));
|
||||
result_size = 1;
|
||||
@@ -721,10 +879,14 @@ glob_filename (pathname, flags)
|
||||
char **directories;
|
||||
register unsigned int i;
|
||||
|
||||
dflags = flags & ~GX_MARKDIRS;
|
||||
if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0'))
|
||||
dflags |= GX_ALLDIRS|GX_ADDCURDIR;
|
||||
|
||||
if (directory_name[directory_len - 1] == '/')
|
||||
directory_name[directory_len - 1] = '\0';
|
||||
|
||||
directories = glob_filename (directory_name, flags & ~GX_MARKDIRS);
|
||||
directories = glob_filename (directory_name, dflags);
|
||||
|
||||
if (free_dirname)
|
||||
{
|
||||
@@ -753,10 +915,19 @@ glob_filename (pathname, flags)
|
||||
{
|
||||
char **temp_results;
|
||||
|
||||
/* Scan directory even on a NULL pathname. That way, `*h/'
|
||||
/* Scan directory even on a NULL filename. That way, `*h/'
|
||||
returns only directories ending in `h', instead of all
|
||||
files ending in `h' with a `/' appended. */
|
||||
temp_results = glob_vector (filename, directories[i], flags & ~GX_MARKDIRS);
|
||||
dname = directories[i];
|
||||
dflags = flags & ~GX_MARKDIRS;
|
||||
if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
|
||||
dflags |= GX_ALLDIRS|GX_ADDCURDIR;
|
||||
if (dname[0] == '\0' && filename[0])
|
||||
{
|
||||
dflags |= GX_NULLDIR;
|
||||
dname = "."; /* treat null directory name and non-null filename as current directory */
|
||||
}
|
||||
temp_results = glob_vector (filename, dname, dflags);
|
||||
|
||||
/* Handle error cases. */
|
||||
if (temp_results == NULL)
|
||||
@@ -830,9 +1001,14 @@ glob_filename (pathname, flags)
|
||||
|
||||
/* Just return what glob_vector () returns appended to the
|
||||
directory name. */
|
||||
dflags = flags & ~GX_MARKDIRS;
|
||||
if (directory_len == 0)
|
||||
dflags |= GX_NULLDIR;
|
||||
if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
|
||||
dflags |= GX_ALLDIRS|GX_ADDCURDIR;
|
||||
temp_results = glob_vector (filename,
|
||||
(directory_len == 0 ? "." : directory_name),
|
||||
flags & ~GX_MARKDIRS);
|
||||
dflags);
|
||||
|
||||
if (temp_results == NULL || temp_results == (char **)&glob_error_return)
|
||||
{
|
||||
@@ -841,7 +1017,7 @@ glob_filename (pathname, flags)
|
||||
return (temp_results);
|
||||
}
|
||||
|
||||
result = glob_dir_to_array (directory_name, temp_results, flags);
|
||||
result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags);
|
||||
if (free_dirname)
|
||||
free (directory_name);
|
||||
return (result);
|
||||
|
||||
+1067
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -23,8 +23,11 @@
|
||||
#define GX_MARKDIRS 0x001 /* mark directory names with trailing `/' */
|
||||
#define GX_NOCASE 0x002 /* ignore case */
|
||||
#define GX_MATCHDOT 0x004 /* match `.' literally */
|
||||
#define GX_ALLDIRS 0x008 /* match all directories */
|
||||
#define GX_MATCHDIRS 0x010 /* return only matching directory names */
|
||||
#define GX_MATCHDIRS 0x008 /* match only directory names */
|
||||
#define GX_ALLDIRS 0x010 /* match all directory names, no others */
|
||||
#define GX_NULLDIR 0x100 /* internal -- no directory preceding pattern */
|
||||
#define GX_ADDCURDIR 0x200 /* internal -- add passed directory name */
|
||||
#define GX_GLOBSTAR 0x400 /* turn on special handling of ** */
|
||||
|
||||
extern int glob_pattern_p __P((const char *));
|
||||
extern char **glob_vector __P((char *, char *, int));
|
||||
|
||||
+24
-24
@@ -317,7 +317,7 @@ rl_macro_bind (keyseq, macro, map)
|
||||
|
||||
if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len))
|
||||
{
|
||||
free (macro_keys);
|
||||
xfree (macro_keys);
|
||||
return -1;
|
||||
}
|
||||
rl_generic_bind (ISMACR, keyseq, macro_keys, map);
|
||||
@@ -347,7 +347,7 @@ rl_generic_bind (type, keyseq, data, map)
|
||||
if (keyseq == 0 || *keyseq == 0)
|
||||
{
|
||||
if (type == ISMACR)
|
||||
free (data);
|
||||
xfree (data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ rl_generic_bind (type, keyseq, data, map)
|
||||
KEYS into KEYS_LEN. */
|
||||
if (rl_translate_keyseq (keyseq, keys, &keys_len))
|
||||
{
|
||||
free (keys);
|
||||
xfree (keys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ rl_generic_bind (type, keyseq, data, map)
|
||||
ic = uc;
|
||||
if (ic < 0 || ic >= KEYMAP_SIZE)
|
||||
{
|
||||
free (keys);
|
||||
xfree (keys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ rl_generic_bind (type, keyseq, data, map)
|
||||
else
|
||||
{
|
||||
if (map[ic].type == ISMACR)
|
||||
free ((char *)map[ic].function);
|
||||
xfree ((char *)map[ic].function);
|
||||
else if (map[ic].type == ISKMAP)
|
||||
{
|
||||
map = FUNCTION_TO_KEYMAP (map, ic);
|
||||
@@ -427,7 +427,7 @@ rl_generic_bind (type, keyseq, data, map)
|
||||
|
||||
rl_binding_keymap = map;
|
||||
}
|
||||
free (keys);
|
||||
xfree (keys);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -793,7 +793,7 @@ _rl_read_file (filename, sizep)
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
free (buffer);
|
||||
xfree (buffer);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
@@ -863,7 +863,7 @@ _rl_read_init_file (filename, include_level)
|
||||
|
||||
openname = tilde_expand (filename);
|
||||
buffer = _rl_read_file (openname, &file_size);
|
||||
free (openname);
|
||||
xfree (openname);
|
||||
|
||||
if (buffer == 0)
|
||||
return (errno);
|
||||
@@ -911,7 +911,7 @@ _rl_read_init_file (filename, include_level)
|
||||
current_readline_init_lineno++;
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
xfree (buffer);
|
||||
currently_reading_init_file = 0;
|
||||
return (0);
|
||||
}
|
||||
@@ -1002,7 +1002,7 @@ parser_if (args)
|
||||
`$if term=sun-cmd' into their .inputrc. */
|
||||
_rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) &&
|
||||
_rl_stricmp (args + 5, rl_terminal_name);
|
||||
free (tname);
|
||||
xfree (tname);
|
||||
}
|
||||
#if defined (VI_MODE)
|
||||
else if (_rl_strnicmp (args, "mode=", 5) == 0)
|
||||
@@ -1352,7 +1352,7 @@ rl_parse_and_bind (string)
|
||||
else
|
||||
rl_bind_keyseq (seq, rl_named_function (funname));
|
||||
|
||||
free (seq);
|
||||
xfree (seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1695,7 +1695,7 @@ sv_isrchterm (value)
|
||||
rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end);
|
||||
_rl_isearch_terminators[end] = '\0';
|
||||
|
||||
free (v);
|
||||
xfree (v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1856,7 +1856,7 @@ rl_list_funmap_names ()
|
||||
for (i = 0; funmap_names[i]; i++)
|
||||
fprintf (rl_outstream, "%s\n", funmap_names[i]);
|
||||
|
||||
free (funmap_names);
|
||||
xfree (funmap_names);
|
||||
}
|
||||
|
||||
static char *
|
||||
@@ -2022,7 +2022,7 @@ rl_invoking_keyseqs_in_map (function, map)
|
||||
}
|
||||
|
||||
strcat (keyname, seqs[i]);
|
||||
free (seqs[i]);
|
||||
xfree (seqs[i]);
|
||||
|
||||
if (result_index + 2 > result_size)
|
||||
{
|
||||
@@ -2034,7 +2034,7 @@ rl_invoking_keyseqs_in_map (function, map)
|
||||
result[result_index] = (char *)NULL;
|
||||
}
|
||||
|
||||
free (seqs);
|
||||
xfree (seqs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2086,10 +2086,10 @@ rl_function_dumper (print_readably)
|
||||
{
|
||||
fprintf (rl_outstream, "\"%s\": %s\n",
|
||||
invokers[j], name);
|
||||
free (invokers[j]);
|
||||
xfree (invokers[j]);
|
||||
}
|
||||
|
||||
free (invokers);
|
||||
xfree (invokers);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2113,9 +2113,9 @@ rl_function_dumper (print_readably)
|
||||
fprintf (rl_outstream, "...\n");
|
||||
|
||||
for (j = 0; invokers[j]; j++)
|
||||
free (invokers[j]);
|
||||
xfree (invokers[j]);
|
||||
|
||||
free (invokers);
|
||||
xfree (invokers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2161,8 +2161,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
|
||||
fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",
|
||||
keyname,
|
||||
out ? out : "");
|
||||
free (keyname);
|
||||
free (out);
|
||||
xfree (keyname);
|
||||
xfree (out);
|
||||
break;
|
||||
case ISFUNC:
|
||||
break;
|
||||
@@ -2185,13 +2185,13 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
|
||||
out = (char *)xmalloc (strlen (keyname) + prefix_len + 1);
|
||||
strcpy (out, prefix);
|
||||
strcpy (out + prefix_len, keyname);
|
||||
free (keyname);
|
||||
xfree (keyname);
|
||||
keyname = out;
|
||||
}
|
||||
}
|
||||
|
||||
_rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname);
|
||||
free (keyname);
|
||||
xfree (keyname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2252,7 +2252,7 @@ _rl_get_string_variable_value (name)
|
||||
if (ret)
|
||||
{
|
||||
strncpy (numbuf, ret, sizeof (numbuf) - 1);
|
||||
free (ret);
|
||||
xfree (ret);
|
||||
numbuf[sizeof(numbuf) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1709,7 +1709,7 @@ sv_histsize (value)
|
||||
{
|
||||
nval = atoi (value);
|
||||
if (nval < 0)
|
||||
nval = 0;
|
||||
return 1;
|
||||
}
|
||||
stifle_history (nval);
|
||||
return 0;
|
||||
|
||||
+173
-6
@@ -1,6 +1,6 @@
|
||||
/* complete.c -- filename completion for readline. */
|
||||
|
||||
/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
@@ -188,6 +188,10 @@ int rl_complete_with_tilde_expansion = 0;
|
||||
completer. */
|
||||
rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL;
|
||||
|
||||
/* Pointer to generator function for rl_menu_complete (). NULL means to use
|
||||
*rl_completion_entry_function (see above). */
|
||||
rl_compentry_func_t *rl_menu_completion_entry_function = (rl_compentry_func_t *)NULL;
|
||||
|
||||
/* Pointer to alternative function to create matches.
|
||||
Function is called with TEXT, START, and END.
|
||||
START and END are indices in RL_LINE_BUFFER saying what the boundaries
|
||||
@@ -336,6 +340,9 @@ int rl_sort_completion_matches = 1;
|
||||
/* Local variable states what happened during the last completion attempt. */
|
||||
static int completion_changed_buffer;
|
||||
|
||||
/* The result of the query to the user about displaying completion matches */
|
||||
static int completion_y_or_n;
|
||||
|
||||
/*************************************/
|
||||
/* */
|
||||
/* Bindable completion functions */
|
||||
@@ -1186,8 +1193,7 @@ compute_lcd_of_matches (match_list, matches, text)
|
||||
}
|
||||
|
||||
/* sort the list to get consistent answers. */
|
||||
if (rl_sort_completion_matches)
|
||||
qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
|
||||
qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
|
||||
|
||||
si = strlen (text);
|
||||
if (si <= low)
|
||||
@@ -1433,7 +1439,7 @@ display_matches (matches)
|
||||
rl_crlf ();
|
||||
fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
|
||||
fflush (rl_outstream);
|
||||
if (get_y_or_n (0) == 0)
|
||||
if ((completion_y_or_n = get_y_or_n (0)) == 0)
|
||||
{
|
||||
rl_crlf ();
|
||||
|
||||
@@ -2140,7 +2146,7 @@ rl_filename_completion_function (text, state)
|
||||
hit the end of the match list, we restore the original unmatched text,
|
||||
ring the bell, and reset the counter to zero. */
|
||||
int
|
||||
rl_menu_complete (count, invoking_key)
|
||||
rl_old_menu_complete (count, invoking_key)
|
||||
int count, invoking_key;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
@@ -2171,7 +2177,9 @@ rl_menu_complete (count, invoking_key)
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_completion_entry_function
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
@@ -2212,6 +2220,10 @@ rl_menu_complete (count, invoking_key)
|
||||
;
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
|
||||
if
|
||||
(match_list_size > 1 && _rl_complete_show_all)
|
||||
display_matches (matches);
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
@@ -2248,3 +2260,158 @@ rl_menu_complete (count, invoking_key)
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rl_menu_complete (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
int matching_filenames, found_quote;
|
||||
|
||||
static char *orig_text;
|
||||
static char **matches = (char **)0;
|
||||
static int match_list_index = 0;
|
||||
static int match_list_size = 0;
|
||||
static int nontrivial_lcd = 0;
|
||||
static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
|
||||
static int orig_start, orig_end;
|
||||
static char quote_char;
|
||||
static int delimiter;
|
||||
|
||||
/* The first time through, we generate the list of matches and set things
|
||||
up to insert them. */
|
||||
if (rl_last_func != rl_menu_complete || full_completion)
|
||||
{
|
||||
/* Clean up from previous call, if any. */
|
||||
FREE (orig_text);
|
||||
if (matches)
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
match_list_index = match_list_size = 0;
|
||||
matches = (char **)NULL;
|
||||
|
||||
full_completion = 0;
|
||||
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
/* We now look backwards for the start of a filename/variable word. */
|
||||
orig_end = rl_point;
|
||||
found_quote = delimiter = 0;
|
||||
quote_char = '\0';
|
||||
|
||||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
orig_start = rl_point;
|
||||
rl_point = orig_end;
|
||||
|
||||
orig_text = rl_copy_text (orig_start, orig_end);
|
||||
matches = gen_completion_matches (orig_text, orig_start, orig_end,
|
||||
our_func, found_quote, quote_char);
|
||||
|
||||
nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
|
||||
|
||||
/* If we are matching filenames, the attempted completion function will
|
||||
have set rl_filename_completion_desired to a non-zero value. The basic
|
||||
rl_filename_completion_function does this. */
|
||||
matching_filenames = rl_filename_completion_desired;
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (match_list_size = 0; matches[match_list_size]; match_list_size++)
|
||||
;
|
||||
|
||||
if (match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
match_list_index = 0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
if (*matches[0])
|
||||
{
|
||||
insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
|
||||
orig_end = orig_start + strlen (matches[0]);
|
||||
completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
|
||||
}
|
||||
|
||||
if (match_list_size > 1 && _rl_complete_show_all)
|
||||
{
|
||||
display_matches (matches);
|
||||
/* If there are so many matches that the user has to be asked
|
||||
whether or not he wants to see the matches, menu completion
|
||||
is unwieldy. */
|
||||
if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if (match_list_size <= 1)
|
||||
{
|
||||
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
|
||||
matches[match_list_index], and add any necessary closing char. */
|
||||
|
||||
if (matches == 0 || match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
match_list_index += count;
|
||||
if (match_list_index < 0)
|
||||
match_list_index += match_list_size;
|
||||
else
|
||||
match_list_index %= match_list_size;
|
||||
|
||||
if (match_list_index == 0 && match_list_size > 1)
|
||||
{
|
||||
rl_ding ();
|
||||
insert_match (matches[0], orig_start, MULT_MATCH, "e_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
||||
append_to_match (matches[match_list_index], delimiter, quote_char,
|
||||
strcmp (orig_text, matches[match_list_index]));
|
||||
}
|
||||
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
+176
-5
@@ -1,6 +1,6 @@
|
||||
/* complete.c -- filename completion for readline. */
|
||||
|
||||
/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
@@ -188,6 +188,10 @@ int rl_complete_with_tilde_expansion = 0;
|
||||
completer. */
|
||||
rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL;
|
||||
|
||||
/* Pointer to generator function for rl_menu_complete (). NULL means to use
|
||||
*rl_completion_entry_function (see above). */
|
||||
rl_compentry_func_t *rl_menu_completion_entry_function = (rl_compentry_func_t *)NULL;
|
||||
|
||||
/* Pointer to alternative function to create matches.
|
||||
Function is called with TEXT, START, and END.
|
||||
START and END are indices in RL_LINE_BUFFER saying what the boundaries
|
||||
@@ -336,6 +340,9 @@ int rl_sort_completion_matches = 1;
|
||||
/* Local variable states what happened during the last completion attempt. */
|
||||
static int completion_changed_buffer;
|
||||
|
||||
/* The result of the query to the user about displaying completion matches */
|
||||
static int completion_y_or_n;
|
||||
|
||||
/*************************************/
|
||||
/* */
|
||||
/* Bindable completion functions */
|
||||
@@ -405,7 +412,7 @@ rl_completion_mode (cfunc)
|
||||
/* */
|
||||
/************************************/
|
||||
|
||||
/* Reset readline state on a signal. */
|
||||
/* Reset readline state on a signal or other event. */
|
||||
void
|
||||
_rl_reset_completion_state ()
|
||||
{
|
||||
@@ -1433,7 +1440,7 @@ display_matches (matches)
|
||||
rl_crlf ();
|
||||
fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
|
||||
fflush (rl_outstream);
|
||||
if (get_y_or_n (0) == 0)
|
||||
if ((completion_y_or_n = get_y_or_n (0)) == 0)
|
||||
{
|
||||
rl_crlf ();
|
||||
|
||||
@@ -1705,6 +1712,7 @@ rl_complete_internal (what_to_do)
|
||||
FREE (saved_line_buffer);
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
_rl_reset_completion_state ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1719,6 +1727,7 @@ rl_complete_internal (what_to_do)
|
||||
FREE (saved_line_buffer);
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
_rl_reset_completion_state ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1773,6 +1782,7 @@ rl_complete_internal (what_to_do)
|
||||
rl_ding ();
|
||||
FREE (saved_line_buffer);
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
_rl_reset_completion_state ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1786,6 +1796,7 @@ rl_complete_internal (what_to_do)
|
||||
}
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
_rl_reset_completion_state ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2136,7 +2147,7 @@ rl_filename_completion_function (text, state)
|
||||
hit the end of the match list, we restore the original unmatched text,
|
||||
ring the bell, and reset the counter to zero. */
|
||||
int
|
||||
rl_menu_complete (count, invoking_key)
|
||||
rl_old_menu_complete (count, invoking_key)
|
||||
int count, invoking_key;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
@@ -2167,7 +2178,9 @@ rl_menu_complete (count, invoking_key)
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_completion_entry_function
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
@@ -2208,6 +2221,9 @@ rl_menu_complete (count, invoking_key)
|
||||
;
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
|
||||
if (match_list_size > 1 && _rl_complete_show_all)
|
||||
display_matches (matches);
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
@@ -2244,3 +2260,158 @@ rl_menu_complete (count, invoking_key)
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rl_menu_complete (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
int matching_filenames, found_quote;
|
||||
|
||||
static char *orig_text;
|
||||
static char **matches = (char **)0;
|
||||
static int match_list_index = 0;
|
||||
static int match_list_size = 0;
|
||||
static int nontrivial_lcd = 0;
|
||||
static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
|
||||
static int orig_start, orig_end;
|
||||
static char quote_char;
|
||||
static int delimiter;
|
||||
|
||||
/* The first time through, we generate the list of matches and set things
|
||||
up to insert them. */
|
||||
if (rl_last_func != rl_menu_complete || full_completion)
|
||||
{
|
||||
/* Clean up from previous call, if any. */
|
||||
FREE (orig_text);
|
||||
if (matches)
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
match_list_index = match_list_size = 0;
|
||||
matches = (char **)NULL;
|
||||
|
||||
full_completion = 0;
|
||||
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
/* We now look backwards for the start of a filename/variable word. */
|
||||
orig_end = rl_point;
|
||||
found_quote = delimiter = 0;
|
||||
quote_char = '\0';
|
||||
|
||||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
orig_start = rl_point;
|
||||
rl_point = orig_end;
|
||||
|
||||
orig_text = rl_copy_text (orig_start, orig_end);
|
||||
matches = gen_completion_matches (orig_text, orig_start, orig_end,
|
||||
our_func, found_quote, quote_char);
|
||||
|
||||
nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
|
||||
|
||||
/* If we are matching filenames, the attempted completion function will
|
||||
have set rl_filename_completion_desired to a non-zero value. The basic
|
||||
rl_filename_completion_function does this. */
|
||||
matching_filenames = rl_filename_completion_desired;
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (match_list_size = 0; matches[match_list_size]; match_list_size++)
|
||||
;
|
||||
|
||||
if (match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
match_list_index = 0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
if (*matches[0])
|
||||
{
|
||||
insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
|
||||
orig_end = orig_start + strlen (matches[0]);
|
||||
completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
|
||||
}
|
||||
|
||||
if (match_list_size > 1 && _rl_complete_show_all)
|
||||
{
|
||||
display_matches (matches);
|
||||
/* If there are so many matches that the user has to be asked
|
||||
whether or not he wants to see the matches, menu completion
|
||||
is unwieldy. */
|
||||
if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if (match_list_size <= 1)
|
||||
{
|
||||
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
|
||||
matches[match_list_index], and add any necessary closing char. */
|
||||
|
||||
if (matches == 0 || match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
match_list_index += count;
|
||||
if (match_list_index < 0)
|
||||
match_list_index += match_list_size;
|
||||
else
|
||||
match_list_index %= match_list_size;
|
||||
|
||||
if (match_list_index == 0 && match_list_size > 1)
|
||||
{
|
||||
rl_ding ();
|
||||
insert_match (matches[0], orig_start, MULT_MATCH, "e_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
||||
append_to_match (matches[match_list_index], delimiter, quote_char,
|
||||
strcmp (orig_text, matches[match_list_index]));
|
||||
}
|
||||
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
/* An initial implementation of a menu completion function a la tcsh. The
|
||||
first time (if the last readline command was not rl_menu_complete), we
|
||||
generate the list of matches. This code is very similar to the code in
|
||||
rl_complete_internal -- there should be a way to combine the two. Then,
|
||||
for each item in the list of matches, we insert the match in an undoable
|
||||
fashion, with the appropriate character appended (this happens on the
|
||||
second and subsequent consecutive calls to rl_menu_complete). When we
|
||||
hit the end of the match list, we restore the original unmatched text,
|
||||
ring the bell, and reset the counter to zero. */
|
||||
int
|
||||
rl_old_menu_complete (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
int matching_filenames, found_quote;
|
||||
|
||||
static char *orig_text;
|
||||
static char **matches = (char **)0;
|
||||
static int match_list_index = 0;
|
||||
static int match_list_size = 0;
|
||||
static int orig_start, orig_end;
|
||||
static char quote_char;
|
||||
static int delimiter;
|
||||
|
||||
/* The first time through, we generate the list of matches and set things
|
||||
up to insert them. */
|
||||
if (rl_last_func != rl_menu_complete)
|
||||
{
|
||||
/* Clean up from previous call, if any. */
|
||||
FREE (orig_text);
|
||||
if (matches)
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
match_list_index = match_list_size = 0;
|
||||
matches = (char **)NULL;
|
||||
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
/* We now look backwards for the start of a filename/variable word. */
|
||||
orig_end = rl_point;
|
||||
found_quote = delimiter = 0;
|
||||
quote_char = '\0';
|
||||
|
||||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
orig_start = rl_point;
|
||||
rl_point = orig_end;
|
||||
|
||||
orig_text = rl_copy_text (orig_start, orig_end);
|
||||
matches = gen_completion_matches (orig_text, orig_start, orig_end,
|
||||
our_func, found_quote, quote_char);
|
||||
|
||||
/* If we are matching filenames, the attempted completion function will
|
||||
have set rl_filename_completion_desired to a non-zero value. The basic
|
||||
rl_filename_completion_function does this. */
|
||||
matching_filenames = rl_filename_completion_desired;
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (match_list_size = 0; matches[match_list_size]; match_list_size++)
|
||||
;
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
|
||||
if (match_list_size > 1 && _rl_complete_show_all)
|
||||
display_matches (matches);
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
|
||||
matches[match_list_index], and add any necessary closing char. */
|
||||
|
||||
if (matches == 0 || match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
match_list_index += count;
|
||||
if (match_list_index < 0)
|
||||
match_list_index += match_list_size;
|
||||
else
|
||||
match_list_index %= match_list_size;
|
||||
|
||||
if (match_list_index == 0 && match_list_size > 1)
|
||||
{
|
||||
rl_ding ();
|
||||
insert_match (orig_text, orig_start, MULT_MATCH, "e_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
||||
append_to_match (matches[match_list_index], delimiter, quote_char,
|
||||
strcmp (orig_text, matches[match_list_index]));
|
||||
}
|
||||
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rl_menu_complete (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
rl_compentry_func_t *our_func;
|
||||
int matching_filenames, found_quote;
|
||||
|
||||
static char *orig_text;
|
||||
static char **matches = (char **)0;
|
||||
static int match_list_index = 0;
|
||||
static int match_list_size = 0;
|
||||
static int nontrivial_lcd = 0;
|
||||
static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
|
||||
static int orig_start, orig_end;
|
||||
static char quote_char;
|
||||
static int delimiter;
|
||||
|
||||
/* The first time through, we generate the list of matches and set things
|
||||
up to insert them. */
|
||||
if (rl_last_func != rl_menu_complete || full_completion)
|
||||
{
|
||||
/* Clean up from previous call, if any. */
|
||||
FREE (orig_text);
|
||||
if (matches)
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
match_list_index = match_list_size = 0;
|
||||
matches = (char **)NULL;
|
||||
|
||||
full_completion = 0;
|
||||
|
||||
/* Only the completion entry function can change these. */
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_menu_completion_entry_function;
|
||||
if (our_func == 0)
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
: rl_filename_completion_function;
|
||||
|
||||
/* We now look backwards for the start of a filename/variable word. */
|
||||
orig_end = rl_point;
|
||||
found_quote = delimiter = 0;
|
||||
quote_char = '\0';
|
||||
|
||||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
orig_start = rl_point;
|
||||
rl_point = orig_end;
|
||||
|
||||
orig_text = rl_copy_text (orig_start, orig_end);
|
||||
matches = gen_completion_matches (orig_text, orig_start, orig_end,
|
||||
our_func, found_quote, quote_char);
|
||||
|
||||
nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
|
||||
|
||||
/* If we are matching filenames, the attempted completion function will
|
||||
have set rl_filename_completion_desired to a non-zero value. The basic
|
||||
rl_filename_completion_function does this. */
|
||||
matching_filenames = rl_filename_completion_desired;
|
||||
|
||||
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
FREE (orig_text);
|
||||
orig_text = (char *)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (match_list_size = 0; matches[match_list_size]; match_list_size++)
|
||||
;
|
||||
|
||||
if (match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
match_list_index = 0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
||||
code below should take care of it. */
|
||||
if (*matches[0])
|
||||
{
|
||||
insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
|
||||
orig_end = orig_start + strlen (matches[0]);
|
||||
completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
|
||||
}
|
||||
|
||||
if (match_list_size > 1 && _rl_complete_show_all)
|
||||
{
|
||||
display_matches (matches);
|
||||
/* If there are so many matches that the user has to be asked
|
||||
whether or not he wants to see the matches, menu completion
|
||||
is unwieldy. */
|
||||
if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if (match_list_size <= 1)
|
||||
{
|
||||
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
|
||||
full_completion = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we have the list of matches. Replace the text between
|
||||
rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
|
||||
matches[match_list_index], and add any necessary closing char. */
|
||||
|
||||
if (matches == 0 || match_list_size == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
FREE (matches);
|
||||
matches = (char **)0;
|
||||
completion_changed_buffer = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
match_list_index += count;
|
||||
if (match_list_index < 0)
|
||||
match_list_index += match_list_size;
|
||||
else
|
||||
match_list_index %= match_list_size;
|
||||
|
||||
if (match_list_index == 0 && match_list_size > 1)
|
||||
{
|
||||
rl_ding ();
|
||||
insert_match (matches[0], orig_start, MULT_MATCH, "e_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
||||
append_to_match (matches[match_list_index], delimiter, quote_char,
|
||||
strcmp (orig_text, matches[match_list_index]));
|
||||
}
|
||||
|
||||
completion_changed_buffer = 1;
|
||||
return (0);
|
||||
}
|
||||
@@ -605,6 +605,10 @@ extern int rl_catch_sigwinch;
|
||||
filename completer. */
|
||||
extern rl_compentry_func_t *rl_completion_entry_function;
|
||||
|
||||
/* Optional generator for menu completion. Default is
|
||||
rl_completion_entry_function (rl_filename_completion_function). */
|
||||
extern rl_compentry_func_t *rl_menu_completion_entry_function;
|
||||
|
||||
/* If rl_ignore_some_completions_function is non-NULL it is the address
|
||||
of a function to call after all of the possible matches have been
|
||||
generated, but before the actual completion is done to the input line.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Readline.h -- the names of functions callable from within readline. */
|
||||
|
||||
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
@@ -233,6 +233,7 @@ extern int rl_vi_append_mode PARAMS((int, int));
|
||||
extern int rl_vi_append_eol PARAMS((int, int));
|
||||
extern int rl_vi_eof_maybe PARAMS((int, int));
|
||||
extern int rl_vi_insertion_mode PARAMS((int, int));
|
||||
extern int rl_vi_insert_mode PARAMS((int, int));
|
||||
extern int rl_vi_movement_mode PARAMS((int, int));
|
||||
extern int rl_vi_arg_digit PARAMS((int, int));
|
||||
extern int rl_vi_change_case PARAMS((int, int));
|
||||
|
||||
Reference in New Issue
Block a user