#include "sysdep.h"
#include <stdio.h>
-#include <sys/types.h>
#include <fcntl.h>
#if !defined (NO_SYS_FILE)
# include <sys/file.h>
/* These next are for filename completion. Perhaps this belongs
in a different place. */
-#ifndef __MSDOS__
+#if !defined(__MSDOS__) && !defined(_MSC_VER)
#include <pwd.h>
#endif /* __MSDOS__ */
#if defined (USG) && !defined (isc386) && !defined (sgi)
extern struct passwd *getpwent ();
#endif
+/* Included by <fcntl.h> on some systems, but not SCO, so include it here. */
+#include <sys/stat.h>
+
/* System-specific feature definitions and include files. */
#include "rldefs.h"
/* Some standard library routines. */
#include "readline.h"
-#if !defined (strchr)
-extern char *strchr ();
-#endif /* !strchr */
-#if !defined (strrchr)
-extern char *strrchr ();
-#endif /* !strrchr*/
+/* Possible values for do_replace in rl_complete_internal. */
+#define NO_MATCH 0
+#define SINGLE_MATCH 1
+#define MULT_MATCH 2
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
extern char *tilde_expand ();
extern char *rl_copy_text ();
extern int rl_editing_mode;
extern int screenwidth;
+/* Forward declarations for functions defined and used in this file. */
+char *filename_completion_function ();
+char **completion_matches ();
+
static int compare_strings ();
static char *rl_strpbrk ();
#define VISIBLE_STATS
#if defined (VISIBLE_STATS)
+# if !defined (X_OK)
+# define X_OK 1
+# endif
+
static int stat_char ();
/* Non-zero means add an additional character to each filename displayed
If this function exists and returns NULL then call the value of
rl_completion_entry_function to try to match, otherwise use the
array of strings returned. */
-Function *rl_attempted_completion_function = (Function *)NULL;
+CPPFunction *rl_attempted_completion_function = (CPPFunction *)NULL;
/* Local variable states what happened during the last completion attempt. */
static int completion_changed_buffer = 0;
/* List the possible completions. See description of rl_complete (). */
rl_possible_completions (ignore, invoking_key)
+ int ignore, invoking_key;
{
rl_complete_internal ('?');
}
to implement FIGNORE a la SunOS csh. */
Function *rl_ignore_some_completions_function = (Function *)NULL;
+#if defined (SHELL)
+/* A function to strip quotes that are not protected by backquotes. It
+ allows single quotes to appear within double quotes, and vice versa.
+ It should be smarter. It's fairly shell-specific, hence the SHELL
+ definition wrapper. */
+static char *
+_delete_quotes (text)
+ char *text;
+{
+ char *ret, *p, *r;
+ int l, quoted;
+
+ l = strlen (text);
+ ret = xmalloc (l + 1);
+ for (quoted = 0, p = text, r = ret; p && *p; p++)
+ {
+ /* Allow backslash-quoted characters to pass through unscathed. */
+ if (*p == '\\')
+ continue;
+ /* Close quote. */
+ if (quoted && *p == quoted)
+ {
+ quoted = 0;
+ continue;
+ }
+ /* Open quote. */
+ if (quoted == 0 && (*p == '\'' || *p == '"'))
+ {
+ quoted = *p;
+ continue;
+ }
+ *r++ = *p;
+ }
+ *r = '\0';
+ return ret;
+}
+#endif /* SHELL */
+
/* Complete the word at or before point.
WHAT_TO_DO says what to do with the completion.
`?' means list the possible completions.
rl_complete_internal (what_to_do)
int what_to_do;
{
- char *filename_completion_function ();
- char **completion_matches (), **matches;
+ char **matches;
Function *our_func;
- int start, scan, end, delimiter = 0;
+ int start, scan, end, delimiter = 0, pass_next;
char *text, *saved_line_buffer;
- char quote_char = '\0';
char *replacement;
+ char quote_char = '\0';
+#if defined (SHELL)
+ int found_quote = 0;
+#endif
if (rl_line_buffer)
saved_line_buffer = savestring (rl_line_buffer);
if (rl_completion_entry_function)
our_func = rl_completion_entry_function;
else
- our_func = (int (*)())filename_completion_function;
+ our_func = (Function *)filename_completion_function;
/* Only the completion entry function can change this. */
rl_filename_completion_desired = 0;
{
/* We have a list of characters which can be used in pairs to
quote substrings for the completer. Try to find the start
- of an unclosed quoted substring.
- [FIXME: Doesn't yet handle '\' escapes to quote quotes. */
- for (scan = 0; scan < end; scan++)
+ of an unclosed quoted substring. */
+ /* FOUND_QUOTE is set so we know what kind of quotes we found. */
+ for (scan = pass_next = 0; scan < end; scan++)
{
+ if (pass_next)
+ {
+ pass_next = 0;
+ continue;
+ }
+
+ if (rl_line_buffer[scan] == '\\')
+ {
+ pass_next = 1;
+ continue;
+ }
+
if (quote_char != '\0')
{
/* Ignore everything until the matching close quote char. */
if (rl_line_buffer[scan] == quote_char)
{
- /* Found matching close quote. Abandon this substring. */
+ /* Found matching close. Abandon this substring. */
quote_char = '\0';
rl_point = end;
}
/* Found start of a quoted substring. */
quote_char = rl_line_buffer[scan];
rl_point = scan + 1;
+#if defined (SHELL)
+ if (quote_char == '\'')
+ found_quote |= 1;
+ else if (quote_char == '"')
+ found_quote |= 2;
+#endif
}
}
}
+
if (rl_point == end)
{
- /* We didn't find an unclosed quoted substring upon which to do
+ int quoted = 0;
+ /* We didn't find an unclosed quoted substring up which to do
completion, so use the word break characters to find the
- substring on which to do completion. */
- while (--rl_point &&
- !strchr (rl_completer_word_break_characters,
- rl_line_buffer[rl_point])) {;}
+ substring on which to complete. */
+ while (--rl_point)
+ {
+#if defined (SHELL)
+ /* Don't let word break characters in quoted substrings break
+ words for the completer. */
+ if (found_quote)
+ {
+ if (strchr (rl_completer_quote_characters, rl_line_buffer[rl_point]))
+ {
+ quoted = !quoted;
+ continue;
+ }
+ if (quoted)
+ continue;
+ }
+#endif /* SHELL */
+ if (strchr (rl_completer_word_break_characters, rl_line_buffer[rl_point]))
+ break;
+ }
}
/* If we are at a word break, then advance past it. */
/* If the character isn't needed to determine something special
about what kind of completion to perform, then advance past it. */
-
if (!rl_special_prefixes ||
!strchr (rl_special_prefixes, rl_line_buffer[rl_point]))
rl_point++;
}
}
+ /* At this point, we know we have an open quote if quote_char != '\0'. */
start = rl_point;
rl_point = end;
text = rl_copy_text (start, end);
variable rl_attempted_completion_function. */
if (rl_attempted_completion_function)
{
- matches =
- (char **)(*rl_attempted_completion_function) (text, start, end);
+ matches = (*rl_attempted_completion_function) (text, start, end);
if (matches)
{
+ /* XXX - This is questionable code. - XXX */
if (matches == (char **)-1)
matches = (char **)NULL;
our_func = (Function *)NULL;
}
}
+#if defined (SHELL)
+ /* Beware -- we're stripping the quotes here. Do this only if we know
+ we are doing filename completion. */
+ if (found_quote && our_func == (Function *)filename_completion_function)
+ {
+ /* delete single and double quotes */
+ replacement = _delete_quotes (text);
+ free (text);
+ text = replacement;
+ replacement = (char *)0;
+ }
+#endif /* SHELL */
+
matches = completion_matches (text, our_func);
after_usual_completion:
{
register int i;
- some_matches:
-
/* It seems to me that in all the cases we handle we would like
- to ignore duplicate possibilities. Scan for the text to
+ to ignore duplicate possiblilities. Scan for the text to
insert being identical to the other completions. */
if (rl_ignore_completion_duplicates)
{
char *lowest_common;
int j, newlen = 0;
+ char dead_slot;
/* Sort the items. */
/* It is safe to sort this array, because the lowest common
if (strcmp (matches[i], matches[i + 1]) == 0)
{
free (matches[i]);
- matches[i] = (char *)-1;
+ matches[i] = (char *)&dead_slot;
}
else
newlen++;
}
- /* We have marked all the dead slots with (char *)-1.
+ /* We have marked all the dead slots with (char *)&dead_slot.
Copy all the non-dead entries into a new array. */
{
char **temp_array =
for (i = 1, j = 1; matches[i]; i++)
{
- if (matches[i] != (char *)-1)
+ if (matches[i] != (char *)&dead_slot)
temp_array[j++] = matches[i];
}
temp_array[j] = (char *)NULL;
- if (matches[0] != (char *)-1)
+ if (matches[0] != (char *)&dead_slot)
free (matches[0]);
free (matches);
ignore function with the array as a parameter. It can
munge the array, deleting matches as it desires. */
if (rl_ignore_some_completions_function &&
- our_func == (int (*)())filename_completion_function)
+ our_func == (Function *)filename_completion_function)
(void)(*rl_ignore_some_completions_function)(matches);
/* If we are doing completion on quoted substrings, and any matches
{
int do_replace;
- do_replace = 0;
+ do_replace = NO_MATCH;
- /* If there is only a single match, see if we need to
- quote it. */
- if (!matches[1] &&
- rl_strpbrk (matches[0], rl_completer_word_break_characters))
- do_replace = 1;
+ /* If there is a single match, see if we need to quote it.
+ This also checks whether the common prefix of several
+ matches needs to be quoted. If the common prefix should
+ not be checked, add !matches[1] to the if clause. */
+ if (rl_strpbrk (matches[0], rl_completer_word_break_characters))
+ do_replace = matches[1] ? MULT_MATCH : SINGLE_MATCH;
- /* If there are multiple matches, check to see if any of them
- require that the substring be quoted. */
- for (i = 1; matches[i] != NULL; i++)
- if (rl_strpbrk (matches[i], rl_completer_word_break_characters))
- {
- do_replace = 1;
- break;
- }
- if (do_replace)
+ if (do_replace != NO_MATCH)
{
#if defined (SHELL)
/* XXX - experimental */
- /* Single-quote the replacement, since we found an
- embedded word break character in a potential match. */
- char *rtext;
- extern char *single_quote (); /* in builtins/common.c */
-
- rtext = single_quote (matches[0]);
- replacement = (char *)alloca (strlen (rtext) + 1);
+ /* Quote the replacement, since we found an
+ embedded word break character in a potential
+ match. */
+ char *rtext, *mtext;
+ int rlen;
+ extern char *double_quote (); /* in builtins/common.c */
+
+ /* If DO_REPLACE == MULT_MATCH, it means that there is
+ more than one match. In this case, we do not add
+ the closing quote or attempt to perform tilde
+ expansion. If DO_REPLACE == SINGLE_MATCH, we try
+ to perform tilde expansion, because double quotes
+ inhibit tilde expansion by the shell. */
+
+ mtext = matches[0];
+ if (mtext[0] == '~' && do_replace == SINGLE_MATCH)
+ mtext = tilde_expand (matches[0]);
+ rtext = double_quote (mtext);
+ if (mtext != matches[0])
+ free (mtext);
+
+ rlen = strlen (rtext);
+ replacement = (char *)alloca (rlen + 1);
strcpy (replacement, rtext);
+ if (do_replace == MULT_MATCH)
+ replacement[rlen - 1] = '\0';
free (rtext);
#else /* !SHELL */
/* Found an embedded word break character in a potential
#endif /* SHELL */
}
}
+
if (replacement)
{
rl_delete_text (start, rl_point);
/* Handle simple case first. What if there is only one answer? */
if (!matches[1])
{
- char *temp;
+ char *temp = (char *)NULL;
if (rl_filename_completion_desired)
temp = strrchr (matches[0], '/');
- else
- temp = (char *)NULL;
if (!temp)
temp = matches[0];
goto restart;
}
}
+
/* How many items of MAX length can we fit in the screen window? */
max += 2;
limit = screenwidth / max;
break;
default:
+ fprintf (stderr, "\r\nreadline: bad value for what_to_do in rl_complete\n");
abort ();
}
int state;
char *text;
{
-#ifdef __GO32__
+#if defined (MINIMAL)
return (char *)NULL;
-#else /* !__GO32__ */
+#else /* !MINIMAL */
static char *username = (char *)NULL;
static struct passwd *entry;
static int namelen, first_char, first_char_loc;
return (value);
}
-#endif /* !__GO32__ */
+#endif /* !MINIMAL */
}
-
\f
/* **************************************************************** */
/* */
char **
completion_matches (text, entry_function)
char *text;
- char *(*entry_function) ();
+ CPFunction *entry_function;
{
/* Number of slots in match_list. */
int match_list_size;
int state;
char *text;
{
+#ifndef WIN32
static DIR *directory;
static char *filename = (char *)NULL;
static char *dirname = (char *)NULL;
}
return (temp);
}
+#endif
}
/* A function for simple tilde expansion. */
--- /dev/null
+/* signals.c -- signal handling support for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 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.
+
+ The GNU Readline Library 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 1, or
+ (at your option) any later version.
+
+ The GNU Readline Library 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+# include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+#include <signal.h>
+
+/* This is needed to include support for TIOCGWINSZ and window resizing. */
+#if defined (OSF1) || defined (BSD386) || defined (_386BSD) || defined (__BSD_4_4__) || defined (AIX)
+# include <sys/ioctl.h>
+#endif /* OSF1 || BSD386 || _386BSD || __BSD_4_4__ || AIX */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+static void cr ();
+
+extern int readline_echoing_p;
+extern int rl_pending_input;
+
+extern int _rl_meta_flag;
+
+#ifdef __STDC__
+extern void _rl_output_character_function (int);
+#else
+extern void _rl_output_character_function ();
+#endif
+
+extern void free_undo_list ();
+
+#if defined (VOID_SIGHANDLER)
+# define sighandler void
+#else
+# define sighandler int
+#endif /* VOID_SIGHANDLER */
+
+/* This typedef is equivalant to the one for Function; it allows us
+ to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef sighandler SigHandler ();
+
+/* **************************************************************** */
+/* */
+/* Signal Handling */
+/* */
+/* **************************************************************** */
+
+#if defined (HANDLE_SIGNALS)
+
+#if defined (SIGWINCH)
+static SigHandler *old_sigwinch = (SigHandler *)NULL;
+
+static sighandler
+rl_handle_sigwinch (sig)
+ int sig;
+{
+ if (readline_echoing_p)
+ {
+ _rl_set_screen_size (fileno (rl_instream), 1);
+
+ cr (); /* was crlf () */
+ rl_forced_update_display ();
+ }
+
+ if (old_sigwinch &&
+ old_sigwinch != (SigHandler *)SIG_IGN &&
+ old_sigwinch != (SigHandler *)SIG_DFL)
+ (*old_sigwinch) (sig);
+#if !defined (VOID_SIGHANDLER)
+ return (0);
+#endif /* VOID_SIGHANDLER */
+}
+#endif /* SIGWINCH */
+
+/* Interrupt handling. */
+static SigHandler
+ *old_int = (SigHandler *)NULL,
+ *old_tstp = (SigHandler *)NULL,
+ *old_ttou = (SigHandler *)NULL,
+ *old_ttin = (SigHandler *)NULL,
+ *old_cont = (SigHandler *)NULL,
+ *old_alrm = (SigHandler *)NULL;
+
+/* Handle an interrupt character. */
+static sighandler
+rl_signal_handler (sig)
+ int sig;
+{
+#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
+ /* Since the signal will not be blocked while we are in the signal
+ handler, ignore it until rl_clear_signals resets the catcher. */
+ if (sig == SIGINT)
+ signal (sig, SIG_IGN);
+#endif /* !HAVE_BSD_SIGNALS */
+
+ switch (sig)
+ {
+ case SIGINT:
+ {
+ register HIST_ENTRY *entry;
+
+ free_undo_list ();
+
+ entry = current_history ();
+ if (entry)
+ entry->data = (char *)NULL;
+ }
+ _rl_kill_kbd_macro ();
+ rl_clear_message ();
+ rl_init_argument ();
+
+#if defined (SIGTSTP)
+ case SIGTSTP:
+ case SIGTTOU:
+ case SIGTTIN:
+#endif /* SIGTSTP */
+ case SIGALRM:
+ rl_clean_up_for_exit ();
+ rl_deprep_terminal ();
+ rl_clear_signals ();
+ rl_pending_input = 0;
+
+ kill (getpid (), sig);
+
+ SIGNALS_UNBLOCK;
+
+ rl_prep_terminal (_rl_meta_flag);
+ rl_set_signals ();
+ }
+
+#if !defined (VOID_SIGHANDLER)
+ return (0);
+#endif /* !VOID_SIGHANDLER */
+}
+
+#if defined (HAVE_POSIX_SIGNALS)
+static SigHandler *
+rl_set_sighandler (sig, handler)
+ int sig;
+ SigHandler *handler;
+{
+ struct sigaction act, oact;
+
+ act.sa_handler = handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigemptyset (&oact.sa_mask);
+ sigaction (sig, &act, &oact);
+ return (oact.sa_handler);
+}
+
+#else /* !HAVE_POSIX_SIGNALS */
+# define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler)
+#endif /* !HAVE_POSIX_SIGNALS */
+
+rl_set_signals ()
+{
+ old_int = (SigHandler *)rl_set_sighandler (SIGINT, rl_signal_handler);
+ if (old_int == (SigHandler *)SIG_IGN)
+ signal (SIGINT, SIG_IGN);
+
+ old_alrm = (SigHandler *)rl_set_sighandler (SIGALRM, rl_signal_handler);
+ if (old_alrm == (SigHandler *)SIG_IGN)
+ signal (SIGALRM, SIG_IGN);
+
+#if defined (SIGTSTP)
+ old_tstp = (SigHandler *)rl_set_sighandler (SIGTSTP, rl_signal_handler);
+ if (old_tstp == (SigHandler *)SIG_IGN)
+ signal (SIGTSTP, SIG_IGN);
+#endif
+#if defined (SIGTTOU)
+ old_ttou = (SigHandler *)rl_set_sighandler (SIGTTOU, rl_signal_handler);
+ old_ttin = (SigHandler *)rl_set_sighandler (SIGTTIN, rl_signal_handler);
+
+ if (old_tstp == (SigHandler *)SIG_IGN)
+ {
+ signal (SIGTTOU, SIG_IGN);
+ signal (SIGTTIN, SIG_IGN);
+ }
+#endif
+
+#if defined (SIGWINCH)
+ old_sigwinch =
+ (SigHandler *) rl_set_sighandler (SIGWINCH, rl_handle_sigwinch);
+#endif
+}
+
+rl_clear_signals ()
+{
+ rl_set_sighandler (SIGINT, old_int);
+ rl_set_sighandler (SIGALRM, old_alrm);
+
+#if defined (SIGTSTP)
+ signal (SIGTSTP, old_tstp);
+#endif
+
+#if defined (SIGTTOU)
+ signal (SIGTTOU, old_ttou);
+ signal (SIGTTIN, old_ttin);
+#endif
+
+#if defined (SIGWINCH)
+ signal (SIGWINCH, old_sigwinch);
+#endif
+}
+
+/* Move to the start of the current line. */
+static void
+cr ()
+{
+ extern char *term_cr;
+
+ if (term_cr)
+ tputs (term_cr, 1, _rl_output_character_function);
+}
+#endif /* HANDLE_SIGNALS */