* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
static char sccsid
[] = "@(#)readline.c 6.4 (Berkeley) 5/8/91";
/* readline.c -- a general facility for reading lines of input
with emacs style editing and completion. */
/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
This file contains the Readline Library (the Library), a set of
routines for providing Emacs style line input to programs that ask
The 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)
The 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. */
/* Remove these declarations when we have a complete libgnu.a. */
extern char *xmalloc (), *xrealloc ();
static char *xmalloc (), *xrealloc ();
#define alloca __builtin_alloca
#if defined (sparc) && defined (sun)
#if defined (SYSV) || defined (hpux)
/* These next are for filename completion. Perhaps this belongs
struct passwd
*getpwuid (), *getpwent ();
#define HACK_TERMCAP_MOTION
#define d_namlen d_reclen
/* Some standard library routines. */
#define digit(c) ((c) >= '0' && (c) <= '9')
#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
#define digit_value(c) ((c) - '0')
#define member(c, s) ((c) ? index ((s), (c)) : 0)
#define isident(c) ((isletter(c) || digit(c) || c == '_'))
#define exchange(x, y) {int temp = x; x = y; y = temp;}
static void output_character_function ();
/* This typedef is equivalant to the one for Function; it allows us
to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
typedef void SigHandler ();
static void rl_handle_sigwinch ();
static SigHandler
*old_sigwinch
= (SigHandler
*)NULL
;
/* If on, then readline handles signals in a way that doesn't screw. */
/* #define HANDLE_SIGNALS */
/* Stupid comparison routine for qsort () ing strings. */
return (strcmp (*s1
, *s2
));
/* **************************************************************** */
/* Line editing input utility */
/* **************************************************************** */
/* A pointer to the keymap that is currently in use.
By default, it is the standard emacs keymap. */
Keymap keymap
= emacs_standard_keymap
;
/* The current style of editing. */
int rl_editing_mode
= emacs_mode
;
/* Non-zero if the previous command was a kill command. */
static int last_command_was_kill
= 0;
/* The current value of the numeric argument specified by the user. */
/* Non-zero if an argument was typed. */
/* Temporary value used while generating the argument. */
/* Non-zero means we have been called at least once before. */
static int rl_initialized
= 0;
/* If non-zero, this program is running in an EMACS buffer. */
static char *running_in_emacs
= (char *)NULL
;
/* The current offset in the current input line. */
/* Mark in the current input line. */
/* Length of the current input line. */
/* Make this non-zero to return the current input_line. */
/* The last function executed by readline. */
Function
*rl_last_func
= (Function
*)NULL
;
/* Top level environment for readline_internal (). */
static jmp_buf readline_top_level
;
/* The streams we interact with. */
static FILE *in_stream
, *out_stream
;
/* The names of the streams that we do input and output to. */
FILE *rl_instream
= stdin
, *rl_outstream
= stdout
;
/* Non-zero means echo characters as they are read. */
int readline_echoing_p
= 1;
/* The number of characters read in order to type this complete command. */
int rl_key_sequence_length
= 0;
/* If non-zero, then this is the address of a function to call just
before readline_internal () prints the first prompt. */
Function
*rl_startup_hook
= (Function
*)NULL
;
/* What we use internally. You should always refer to RL_LINE_BUFFER. */
/* The character that can generate an EOF. Really read from
the terminal driver... just defaulted here. */
static int eof_char
= CTRL ('D');
/* Non-zero makes this the next keystroke to read. */
int rl_pending_input
= 0;
/* Pointer to a useful terminal name. */
char *rl_terminal_name
= (char *)NULL
;
/* Line buffer and maintenence. */
char *rl_line_buffer
= (char *)NULL
;
static int rl_line_buffer_len
= 0;
#define DEFAULT_BUFFER_SIZE 256
/* **************************************************************** */
/* Top Level Functions */
/* **************************************************************** */
/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means
none. A return value of NULL means that EOF was encountered. */
static rl_prep_terminal (), rl_deprep_terminal ();
char *readline_internal ();
/* If we are at EOF return a NULL string. */
if (rl_pending_input
== EOF
)
old_sigwinch
= (SigHandler
*)signal (SIGWINCH
, rl_handle_sigwinch
);
value
= readline_internal ();
signal (SIGWINCH
, old_sigwinch
);
/* Read a line of input from the global rl_instream, doing output on
If rl_prompt is non-null, then that is our prompt. */
in_stream
= rl_instream
; out_stream
= rl_outstream
;
fprintf (out_stream
, "%s", rl_prompt
);
if (rl_editing_mode
== vi_mode
)
int lk
= last_command_was_kill
;
int code
= setjmp (readline_top_level
);
/* Then initialize the argument and number of keys read. */
rl_key_sequence_length
= 0;
/* EOF typed to a non-blank line is a <NL>. */
/* The character eof_char typed to blank line, and not as the
previous character is interpreted as EOF. */
if (((c
== eof_char
&& lastc
!= c
) || c
== EOF
) && !rl_end
)
/* If there was no change in last_command_was_kill, then no kill
has taken place. Note that if input is pending we are reading
a prefix command, so nothing has changed yet. */
if (lk
== last_command_was_kill
)
last_command_was_kill
= 0;
/* In vi mode, when you exit insert mode, the cursor moves back
over the previous character. We explicitly check for that here. */
if (rl_editing_mode
== vi_mode
&& keymap
== vi_movement_keymap
)
/* Restore the original of this history line, iff the line that we
are editing was originally in the history, AND the line has changed. */
HIST_ENTRY
*entry
= current_history ();
if (entry
&& rl_undo_list
)
char *temp
= savestring (the_line
);
entry
= replace_history_entry (where_history (), the_line
,
free_history_entry (entry
);
/* At any rate, it is highly likely that this line has an undo list. Get
return (savestring (the_line
));
/* Variables for keyboard macros. */
/* The currently executing macro string. If this is non-zero,
then it is a malloc ()'ed string where input is coming from. */
static char *executing_macro
= (char *)NULL
;
/* The offset in the above string to the next character to be read. */
static int executing_macro_index
= 0;
/* Non-zero means to save keys that we dispatch on in a kbd macro. */
static int defining_kbd_macro
= 0;
/* The current macro string being built. Characters get stuffed
in here by add_macro_char (). */
static char *current_macro
= (char *)NULL
;
/* The size of the buffer allocated to current_macro. */
static int current_macro_size
= 0;
/* The index at which characters are being added to current_macro. */
static int current_macro_index
= 0;
/* A structure used to save nested macro strings.
It is a linked list of string/index for each saved macro. */
struct saved_macro
*next
;
/* The list of saved macros. */
struct saved_macro
*macro_list
= (struct saved_macro
*)NULL
;
/* **************************************************************** */
/* **************************************************************** */
rl_handle_sigwinch (sig
, code
, scp
)
char *term
= rl_terminal_name
, *getenv ();
rl_reset_terminal (term
);
rl_forced_update_display ();
old_sigwinch
!= (SigHandler
*)SIG_IGN
&&
old_sigwinch
!= (SigHandler
*)SIG_DFL
)
(*old_sigwinch
)(sig
, code
, scp
);
/* Interrupt handling. */
static SigHandler
*old_int
= (SigHandler
*)NULL
,
*old_tstp
= (SigHandler
*)NULL
,
*old_ttou
= (SigHandler
*)NULL
,
*old_ttin
= (SigHandler
*)NULL
,
*old_cont
= (SigHandler
*)NULL
;
/* Handle an interrupt character. */
rl_signal_handler (sig
, code
, scp
)
static rl_prep_terminal (), rl_deprep_terminal ();
signal (SIGWINCH
, old_sigwinch
);
old_int
= (SigHandler
*)signal (SIGINT
, rl_signal_handler
);
if (old_int
== (SigHandler
*)SIG_IGN
)
signal (SIGINT
, SIG_IGN
);
old_tstp
= (SigHandler
*)signal (SIGTSTP
, rl_signal_handler
);
if (old_tstp
== (SigHandler
*)SIG_IGN
)
signal (SIGTSTP
, SIG_IGN
);
old_ttou
= (SigHandler
*)signal (SIGTTOU
, rl_signal_handler
);
old_ttin
= (SigHandler
*)signal (SIGTTIN
, rl_signal_handler
);
signal (SIGINT
, old_int
);
signal (SIGTSTP
, old_tstp
);
signal (SIGTTOU
, old_ttou
);
signal (SIGTTIN
, old_ttin
);
#endif /* HANDLE_SIGNALS */
/* **************************************************************** */
/* Character Input Buffering */
/* **************************************************************** */
/* If the terminal was in xoff state when we got to it, then xon_char
contains the character that is supposed to start it again. */
static int xon_char
, xoff_state
;
static int pop_index
= 0, push_index
= 0, ibuffer_len
= 511;
static unsigned char ibuffer
[512];
/* Non-null means it is a pointer to a function to run while waiting for
Function
*rl_event_hook
= (Function
*)NULL
;
#define any_typein (push_index != pop_index)
/* Add KEY to the buffer of characters to be read. */
ibuffer
[push_index
++] = key
;
if (push_index
>= ibuffer_len
)
/* Return the amount of space available in the
buffer for stuffing characters. */
if (pop_index
> push_index
)
return (pop_index
- push_index
);
return (ibuffer_len
- (push_index
- pop_index
));
/* Get a key from the buffer of characters to be read.
Result is KEY if there was a key, or -2 if there wasn't. */
if (push_index
== pop_index
)
key
= ibuffer
[pop_index
++];
if (pop_index
>= ibuffer_len
)
/* Stuff KEY into the *front* of the input buffer.
Returns non-zero if successful, zero if there is
no space left in the buffer. */
pop_index
= ibuffer_len
- 1;
ibuffer
[pop_index
] = key
;
int tty
= fileno(stream
);
char buf
[512]; /* XXX - must be at least as large as ibuffer */
if (ioctl(tty
, FIONREAD
, &nchar
) == -1)
result
= ibuffer_space();
result
= read(tty
, buf
, nchar
);
/* Read a key, including pending input. */
rl_key_sequence_length
++;
static int next_macro_key ();
/* If input is coming from a macro, then use that. */
if (c
= next_macro_key ())
while ((c
= rl_get_char()) == -2)
if ((c
= rl_get_char()) != -2)
/* Ugh. But I can't think of a better way. */
if (xoff_state
&& c
== xon_char
)
ioctl (fileno (in_stream
), TIOCSTART
, 0);
/* Do the command associated with KEY in MAP.
If the associated command is really a keymap, then read
another key, and dispatch into that map. */
static add_macro_char ();
if (key
> 127 && key
< 256)
if (map
[ESC
].type
== ISKMAP
)
map
= (Keymap
)map
[ESC
].function
;
Function
*func
= map
[key
].function
;
if (func
!= (Function
*)NULL
)
/* Special case rl_do_lowercase_version (). */
if (func
== rl_do_lowercase_version
)
rl_dispatch (to_lower (key
), map
);
(*map
[key
].function
)(rl_numeric_arg
* arg_sign
, key
);
if (map
[key
].function
!= (Function
*)NULL
)
rl_key_sequence_length
++;
rl_dispatch (newkey
, (Keymap
)map
[key
].function
);
if (map
[key
].function
!= (Function
*)NULL
)
static with_macro_input ();
char *macro
= savestring ((char *)map
[key
].function
);
with_macro_input (macro
);
/* If we have input pending, then the last command was a prefix
command. Don't change the state of rl_last_func. */
rl_last_func
= map
[key
].function
;
/* **************************************************************** */
/* Hacking Keyboard Macros */
/* **************************************************************** */
/* Set up to read subsequent input from STRING.
STRING is free ()'ed when we are done with it. */
with_macro_input (string
)
static push_executing_macro ();
executing_macro
= string
;
executing_macro_index
= 0;
/* Return the next character available from a macro, or 0 if
there are no macro characters. */
if (!executing_macro
[executing_macro_index
])
static pop_executing_macro ();
return (next_macro_key ());
return (executing_macro
[executing_macro_index
++]);
/* Save the currently executing macro on a stack of saved macros. */
struct saved_macro
*saver
;
saver
= (struct saved_macro
*)xmalloc (sizeof (struct saved_macro
));
saver
->next
= macro_list
;
saver
->index
= executing_macro_index
;
saver
->string
= executing_macro
;
/* Discard the current macro, replacing it with the one
on the top of the stack of saved macros. */
executing_macro
= (char *)NULL
;
executing_macro_index
= 0;
struct saved_macro
*disposer
= macro_list
;
executing_macro
= macro_list
->string
;
executing_macro_index
= macro_list
->index
;
macro_list
= macro_list
->next
;
/* Add a character to the macro being built. */
if (current_macro_index
+ 1 >= current_macro_size
)
current_macro
= (char *)xmalloc (current_macro_size
= 25);
(char *)xrealloc (current_macro
, current_macro_size
+= 25);
current_macro
[current_macro_index
++] = c
;
current_macro
[current_macro_index
] = '\0';
/* Begin defining a keyboard macro.
Keystrokes are recorded as they are executed.
End the definition with rl_end_kbd_macro ().
If a numeric argument was explicitly typed, then append this
definition to the end of the existing macro, and start by
re-executing the existing macro. */
rl_start_kbd_macro (ignore1
, ignore2
)
with_macro_input (savestring (current_macro
));
/* Stop defining a keyboard macro.
A numeric argument says to execute the macro right now,
that many times, counting the definition as the first time. */
rl_end_kbd_macro (count
, ignore
)
current_macro_index
-= (rl_key_sequence_length
- 1);
current_macro
[current_macro_index
] = '\0';
rl_call_last_kbd_macro (--count
, 0);
/* Execute the most recently defined keyboard macro.
COUNT says how many times to execute it. */
rl_call_last_kbd_macro (count
, ignore
)
with_macro_input (savestring (current_macro
));
/* Non-zero means do not parse any lines other than comments and
static unsigned char parsing_conditionalized_out
= 0;
/* **************************************************************** */
/* **************************************************************** */
/* Initliaze readline (and terminal if not already). */
extern char *rl_display_prompt
;
/* If we have never been called before, initialize the
terminal and data structures. */
readline_initialize_everything ();
/* Initalize the current line information. */
the_line
= rl_line_buffer
;
/* We aren't done yet. We haven't even gotten started yet! */
/* Tell the history routines what is going on. */
/* Make the display buffer match the state of the line. */
extern char *rl_display_prompt
;
extern int forced_display
;
rl_display_prompt
= rl_prompt
? rl_prompt
: "";
/* No such function typed yet. */
rl_last_func
= (Function
*)NULL
;
/* Parsing of key-bindings begins in an enabled state. */
parsing_conditionalized_out
= 0;
/* Initialize the entire state of the world. */
readline_initialize_everything ()
/* Find out if we are running in Emacs. */
running_in_emacs
= (char *)getenv ("EMACS");
/* Allocate data structures. */
(char *)xmalloc (rl_line_buffer_len
= DEFAULT_BUFFER_SIZE
);
/* Initialize the terminal interface. */
init_terminal_io ((char *)NULL
);
/* Bind tty characters to readline functions. */
readline_default_bindings ();
/* Initialize the function names. */
/* Read in the init file. */
rl_read_init_file ((char *)NULL
);
/* If the completion parser's default word break characters haven't
been set yet, then do so now. */
extern char *rl_completer_word_break_characters
;
extern char *rl_basic_word_break_characters
;
if (rl_completer_word_break_characters
== (char *)NULL
)
rl_completer_word_break_characters
= rl_basic_word_break_characters
;
/* If this system allows us to look at the values of the regular
input editing characters, then bind them to their readline
readline_default_bindings ()
int tty
= fileno (rl_instream
);
if (ioctl (tty
, TIOCGETP
, &ttybuff
) != -1)
int erase
= ttybuff
.sg_erase
, kill
= ttybuff
.sg_kill
;
if (erase
!= -1 && keymap
[erase
].type
== ISFUNC
)
keymap
[erase
].function
= rl_rubout
;
if (kill
!= -1 && keymap
[kill
].type
== ISFUNC
)
keymap
[kill
].function
= rl_unix_line_discard
;
if (ioctl (tty
, TIOCGLTC
, <
) != -1)
int erase
= lt
.t_werasc
, nextc
= lt
.t_lnextc
;
if (erase
!= -1 && keymap
[erase
].type
== ISFUNC
)
keymap
[erase
].function
= rl_unix_word_rubout
;
if (nextc
!= -1 && keymap
[nextc
].type
== ISFUNC
)
keymap
[nextc
].function
= rl_quoted_insert
;
/* **************************************************************** */
/* **************************************************************** */
/* Handle C-u style numeric args, as well as M--, and M-digits. */
/* Add the current digit to the argument in progress. */
rl_digit_argument (ignore
, key
)
/* What to do when you abort reading an argument. */
/* Create a default argument. */
rl_numeric_arg
= arg_sign
= 1;
/* C-u, universal argument. Multiply the current argument by 4.
Read a key. If the key has nothing to do with arguments, then
dispatch on it. If the key is the abort character then abort. */
rl_message ("(arg: %d) ", arg_sign
* rl_numeric_arg
);
key
= c
= rl_read_key ();
if (keymap
[c
].type
== ISFUNC
&&
keymap
[c
].function
== rl_universal_argument
)
rl_numeric_arg
= (rl_numeric_arg
* 10) + (c
- '0');
rl_numeric_arg
= (c
- '0');
if (c
== '-' && !rl_explicit_arg
)
rl_dispatch (key
, keymap
);
/* **************************************************************** */
/* **************************************************************** */
/* This is the stuff that is hard for me. I never seem to write good
display routines in C. Let's see how I do this time. */
/* (PWP) Well... Good for a simple line updater, but totally ignores
the problems of input lines longer than the screen width.
update_line and the code that calls it makes a multiple line,
automatically wrapping line update. Carefull attention needs
to be paid to the vertical position variables.
handling of terminals with autowrap on (incl. DEC braindamage)
could be improved a bit. Right now I just cheat and decrement
/* Keep two buffers; one which reflects the current contents of the
screen, and the other to draw what we think the new contents should
be. Then compare the buffers, and make whatever changes to the
screen itself that we should. Finally, make the buffer that we
just drew into be the one which reflects the current contents of the
screen, and place the cursor where it belongs.
Commands that want to can fix the display themselves, and then let
this function know that the display has been fixed by setting the
RL_DISPLAY_FIXED variable. This is good for efficiency. */
extern char *term_up
, *term_dc
, *term_cr
;
extern int screenheight
, screenwidth
, terminal_can_insert
;
/* What YOU turn on when you have handled all redisplay yourself. */
int rl_display_fixed
= 0;
/* The visible cursor position. If you print some text, adjust this. */
/* The last left edge of text that was displayed. This is used when
doing horizontal scrolling. It shifts in thirds of a screenwidth. */
static int last_lmargin
= 0;
/* The line display buffers. One is the line currently displayed on
the screen. The other is the line about to be displayed. */
static char *visible_line
= (char *)NULL
;
static char *invisible_line
= (char *)NULL
;
/* Number of lines currently on screen minus 1. */
/* A buffer for `modeline' messages. */
/* Non-zero forces the redisplay even if we thought it was unnecessary. */
/* The stuff that gets printed out before the actual text of the line.
This is usually pointing to rl_prompt. */
char *rl_display_prompt
= (char *)NULL
;
/* Default and initial buffer size. Can grow. */
static int line_size
= 1024;
/* Non-zero means to always use horizontal scrolling in line display. */
int horizontal_scroll_mode
= 0;
/* I really disagree with this, but my boss (among others) insists that we
support compilers that don't work. I don't think we are gaining by doing
so; what is the advantage in producing better code if we can't use it? */
/* The following two declarations belong inside the
function block, not here. */
static void move_cursor_relative ();
static void output_some_chars ();
/* Basic redisplay algorithm. */
register int in
, out
, c
, linenum
;
register char *line
= invisible_line
;
int inv_botlin
= 0; /* Number of lines in newly drawn buffer. */
extern int readline_echoing_p
;
visible_line
= (char *)xmalloc (line_size
);
invisible_line
= (char *)xmalloc (line_size
);
for (in
= 0; in
< line_size
; in
++)
/* Draw the line into the buffer. */
/* Mark the line as modified or not. We only do this for history
if (current_history () && rl_undo_list
)
/* If someone thought that the redisplay was handled, but the currently
visible line has a different modification state than the one about
to become visible, then correct the callers misconception. */
if (visible_line
[0] != invisible_line
[0])
strncpy (line
+ out
, rl_display_prompt
, strlen (rl_display_prompt
));
out
+= strlen (rl_display_prompt
);
for (in
= 0; in
< rl_end
; in
++)
if (out
+ 1 >= line_size
)
visible_line
= (char *)xrealloc (visible_line
, line_size
);
invisible_line
= (char *)xrealloc (invisible_line
, line_size
);
register int newout
= (out
| (int)7) + 1;
/* PWP: now is when things get a bit hairy. The visible and invisible
line buffers are really multiple lines, which would wrap every
(screenwidth - 1) characters. Go through each in turn, finding
the changed region and updating it. The line order is top to bottom. */
/* If we can move the cursor up and down, then use multiple lines,
otherwise, let long lines display in a single terminal line, and
horizontally scroll it. */
if (!horizontal_scroll_mode
&& term_up
&& *term_up
)
int total_screen_chars
= (screenwidth
* screenheight
);
if (!rl_display_fixed
|| forced_display
)
/* If we have more than a screenful of material to display, then
only display a screenful. We should display the last screen,
not the first. I'll fix this in a minute. */
if (out
>= total_screen_chars
)
out
= total_screen_chars
- 1;
/* Number of screen lines to display. */
inv_botlin
= out
/ screenwidth
;
/* For each line in the buffer, do the updating display. */
for (linenum
= 0; linenum
<= inv_botlin
; linenum
++)
update_line (linenum
> vis_botlin
? ""
: &visible_line
[linenum
* screenwidth
],
&invisible_line
[linenum
* screenwidth
],
/* We may have deleted some lines. If so, clear the left over
blank ones at the bottom out. */
if (vis_botlin
> inv_botlin
)
for (; linenum
<= vis_botlin
; linenum
++)
tt
= &visible_line
[linenum
* screenwidth
];
move_cursor_relative (0, tt
);
clear_to_eol ((linenum
== vis_botlin
)?
strlen (tt
) : screenwidth
);
/* Move the cursor where it should be. */
move_vert (c_pos
/ screenwidth
);
move_cursor_relative (c_pos
% screenwidth
,
&invisible_line
[(c_pos
/ screenwidth
) * screenwidth
]);
else /* Do horizontal scrolling. */
/* Always at top line. */
/* If the display position of the cursor would be off the edge
of the screen, start the display of this line at an offset that
leaves the cursor on the screen. */
if (c_pos
- last_lmargin
> screenwidth
- 2)
lmargin
= (c_pos
/ (screenwidth
/ 3) - 2) * (screenwidth
/ 3);
else if (c_pos
- last_lmargin
< 1)
lmargin
= ((c_pos
- 1) / (screenwidth
/ 3)) * (screenwidth
/ 3);
/* If the first character on the screen isn't the first character
in the display line, indicate this with a special character. */
if (lmargin
+ screenwidth
< out
)
line
[lmargin
+ screenwidth
- 1] = '>';
if (!rl_display_fixed
|| forced_display
|| lmargin
!= last_lmargin
)
update_line (&visible_line
[last_lmargin
],
&invisible_line
[lmargin
], 0);
move_cursor_relative (c_pos
- lmargin
, &invisible_line
[lmargin
]);
/* Swap visible and non-visible lines. */
char *temp
= visible_line
;
visible_line
= invisible_line
;
/* PWP: update_line() is based on finding the middle difference of each
/beginning of line | /old last same /old EOL
old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
new: eddie> Oh, my little buggy says to me, as lurgid as
\beginning of line | \new last same \new end of line
All are character pointers for the sake of speed. Special cases for
no differences, as well as for end of line additions must be handeled.
Could be made even smarter, but this works well enough */
update_line (old
, new, current_line
)
register char *old
, *new;
register char *ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
/* Find first difference. */
for (ofd
= old
, nfd
= new;
(ofd
- old
< screenwidth
) && *ofd
&& (*ofd
== *nfd
);
/* Move to the end of the screen line. */
for (oe
= ofd
; ((oe
- old
) < screenwidth
) && *oe
; oe
++);
for (ne
= nfd
; ((ne
- new) < screenwidth
) && *ne
; ne
++);
/* If no difference, continue to next line. */
if (ofd
== oe
&& nfd
== ne
)
wsatend
= 1; /* flag for trailing whitespace */
ols
= oe
- 1; /* find last same */
while ((*ols
== *nls
) && (ols
> ofd
) && (nls
> nfd
))
if (*ols
) /* don't step past the NUL */
move_vert (current_line
);
move_cursor_relative (ofd
- old
, old
);
/* if (len (new) > len (old)) */
lendiff
= (nls
- nfd
) - (ols
- ofd
);
/* Insert (diff(len(old),len(new)) ch */
/* Sometimes it is cheaper to print the characters rather than
use the terminal's capabilities. */
if ((2 * (ne
- nfd
)) < lendiff
&& (!term_IC
|| !*term_IC
))
output_some_chars (nfd
, (ne
- nfd
));
last_c_pos
+= (ne
- nfd
);
output_some_chars (nfd
, lendiff
);
/* At the end of a line the characters do not have to
be "inserted". They can just be placed on the screen. */
output_some_chars (nfd
, lendiff
);
/* Copy (new) chars to screen from first diff to last match. */
if (((nls
- nfd
) - lendiff
) > 0)
output_some_chars (&nfd
[lendiff
], ((nls
- nfd
) - lendiff
));
last_c_pos
+= ((nls
- nfd
) - lendiff
);
{ /* cannot insert chars, write to EOL */
output_some_chars (nfd
, (ne
- nfd
));
last_c_pos
+= (ne
- nfd
);
else /* Delete characters from line. */
/* If possible and inexpensive to use terminal deletion, then do so. */
if (term_dc
&& (2 * (ne
- nfd
)) >= (-lendiff
))
delete_chars (-lendiff
); /* delete (diff) characters */
/* Copy (new) chars to screen from first diff to last match */
output_some_chars (nfd
, (nls
- nfd
));
last_c_pos
+= (nls
- nfd
);
/* Otherwise, print over the existing material. */
output_some_chars (nfd
, (ne
- nfd
));
last_c_pos
+= (ne
- nfd
);
clear_to_eol ((oe
- old
) - (ne
- new));
/* (PWP) tell the update routines that we have moved onto a
last_c_pos
= last_v_pos
= 0;
vis_botlin
= last_lmargin
= 0;
/* Actually update the display, period. */
rl_forced_update_display ()
register char *temp
= visible_line
;
while (*temp
) *temp
++ = '\0';
/* Move the cursor from last_c_pos to NEW, which are buffer indices.
DATA is the contents of the screen line of interest; i.e., where
the movement is being done. */
move_cursor_relative (new, data
)
static void output_character_function ();
/* It may be faster to output a CR, and then move forwards instead
if (new + 1 < last_c_pos
- new)
tputs (term_cr
, 1, output_character_function
);
if (last_c_pos
== new) return;
/* Move the cursor forward. We do it by printing the command
to move the cursor forward if there is one, else print that
portion of the output buffer again. Which is cheaper? */
/* The above comment is left here for posterity. It is faster
to print one character (non-control) than to print a control
sequence telling the terminal to move forward one character.
That kind of control is for people who don't know what the
data is underneath the cursor. */
#ifdef HACK_TERMCAP_MOTION
extern char *term_forward_char
;
for (i
= last_c_pos
; i
< new; i
++)
tputs (term_forward_char
, 1, output_character_function
);
for (i
= last_c_pos
; i
< new; i
++)
putc (data
[i
], out_stream
);
for (i
= last_c_pos
; i
< new; i
++)
putc (data
[i
], out_stream
);
#endif /* HACK_TERMCAP_MOTION */
backspace (last_c_pos
- new);
/* PWP: move the cursor up or down. */
void output_character_function ();
if (last_v_pos
== to
) return;
if ((delta
= to
- last_v_pos
) > 0)
for (i
= 0; i
< delta
; i
++)
tputs (term_cr
, 1, output_character_function
);
last_c_pos
= 0; /* because crlf() will do \r\n */
for (i
= 0; i
< -delta
; i
++)
tputs (term_up
, 1, output_character_function
);
last_v_pos
= to
; /* now to is here */
/* Physically print C on out_stream. This is for functions which know
how to optimize the display. */
fprintf (out_stream
, "M-");
rl_character_len (c
, pos
)
return (((pos
| (int)7) + 1) - pos
);
/* How to print things in the "echo-area". The prompt is treated as a
rl_message (string
, arg1
, arg2
)
sprintf (msg_buf
, string
, arg1
, arg2
);
rl_display_prompt
= msg_buf
;
/* How to clear things from the "echo-area". */
rl_display_prompt
= rl_prompt
;
/* **************************************************************** */
/* Terminal and Termcap */
/* **************************************************************** */
static char *term_buffer
= (char *)NULL
;
static char *term_string_buffer
= (char *)NULL
;
/* Non-zero means this terminal can't really do anything. */
/* Some strings to control terminal actions. These are output by tputs (). */
char *term_goto
, *term_clreol
, *term_cr
, *term_clrpag
, *term_backspace
;
int screenwidth
, screenheight
;
/* Non-zero if we determine that the terminal can do character insertion. */
int terminal_can_insert
= 0;
/* How to insert characters. */
char *term_im
, *term_ei
, *term_ic
, *term_ip
, *term_IC
;
/* How to delete characters. */
#ifdef HACK_TERMCAP_MOTION
#endif /* HACK_TERMCAP_MOTION */
/* How to go up a line. */
/* Re-initialize the terminal considering that the TERM/TERMCAP variable
rl_reset_terminal (terminal_name
)
init_terminal_io (terminal_name
);
init_terminal_io (terminal_name
)
char *term
= (terminal_name
? terminal_name
: (char *)getenv ("TERM"));
char *tgetstr (), *buffer
;
term_string_buffer
= (char *)xmalloc (2048);
term_buffer
= (char *)xmalloc (2048);
buffer
= term_string_buffer
;
term_clrpag
= term_cr
= term_clreol
= (char *)NULL
;
if (tgetent (term_buffer
, term
) < 0)
BC
= tgetstr ("pc", &buffer
);
PC
= buffer
? *buffer
: 0;
term_backspace
= tgetstr ("le", &buffer
);
term_cr
= tgetstr ("cr", &buffer
);
term_clreol
= tgetstr ("ce", &buffer
);
term_clrpag
= tgetstr ("cl", &buffer
);
#ifdef HACK_TERMCAP_MOTION
term_forward_char
= tgetstr ("nd", &buffer
);
#endif /* HACK_TERMCAP_MOTION */
screenwidth
= tgetnum ("co");
screenwidth
--; /* PWP: avoid autowrap bugs */
screenheight
= tgetnum ("li");
term_im
= tgetstr ("im", &buffer
);
term_ei
= tgetstr ("ei", &buffer
);
term_IC
= tgetstr ("IC", &buffer
);
term_ic
= tgetstr ("ic", &buffer
);
term_ip
= tgetstr ("ip", &buffer
);
term_IC
= tgetstr ("IC", &buffer
);
/* "An application program can assume that the terminal can do
character insertion if *any one of* the capabilities `IC',
`im', `ic' or `ip' is provided." */
/* XXX Circumvent broken code. */
terminal_can_insert
= (term_IC
|| term_im
|| term_ic
|| term_ip
);
term_up
= tgetstr ("up", &buffer
);
term_dc
= tgetstr ("dc", &buffer
);
term_DC
= tgetstr ("DC", &buffer
);
/* A function for the use of tputs () */
output_character_function (c
)
/* Write COUNT characters from STRING to the output stream. */
output_some_chars (string
, count
)
fwrite (string
, 1, count
, out_stream
);
/* Delete COUNT characters from the display line. */
buffer
= tgoto (term_DC
, 0, count
);
tputs (buffer
, 1, output_character_function
);
tputs (term_dc
, 1, output_character_function
);
/* Prepare to insert by inserting COUNT blank spaces. */
tputs (term_im
, 1, output_character_function
);
if (term_IC
&& *term_IC
&&
(count
> 1 || !term_ic
|| !*term_ic
))
buffer
= tgoto (term_IC
, 0, count
);
tputs (buffer
, 1, output_character_function
);
tputs (term_ic
, 1, output_character_function
);
/* We are finished doing our insertion. Send ending string. */
tputs (term_ei
, 1, output_character_function
);
/* Move the cursor back. */
for (i
= 0; i
< count
; i
++)
tputs (term_backspace
, 1, output_character_function
);
for (i
= 0; i
< count
; i
++)
/* Move to the start of the next line. */
tputs (term_cr
, 1, output_character_function
);
/* Clear to the end of the line. COUNT is the minimum
number of character spaces to clear, */
tputs (term_clreol
, 1, output_character_function
);
/* Do one more character space. */
for (i
= 0; i
< count
; i
++)
/* **************************************************************** */
/* Saving and Restoring the TTY */
/* **************************************************************** */
/* Standard flags, including ECHO. */
static int original_tty_flags
= 0;
/* Local mode flags, like LPASS8. */
static int local_mode_flags
= 0;
/* Terminal characters. This has C-s and C-q in it. */
static struct tchars original_tchars
;
/* Local special characters. This has the interrupt characters in it. */
static struct ltchars original_ltchars
;
/* We use this to get and set the tty_flags. */
static struct sgttyb the_ttybuff
;
/* Put the terminal in CBREAK mode so that we can detect key presses. */
int tty
= fileno (rl_instream
);
/* We always get the latest tty values. Maybe stty changed them. */
ioctl (tty
, TIOCGETP
, &the_ttybuff
);
original_tty_flags
= the_ttybuff
.sg_flags
;
readline_echoing_p
= (original_tty_flags
& ECHO
);
/* If this terminal doesn't care how the 8th bit is used,
then we can use it for the meta-key.
We check by seeing if BOTH odd and even parity are allowed. */
if ((the_ttybuff
.sg_flags
& (ODDP
| EVENP
)) == (ODDP
| EVENP
))
the_ttybuff
.sg_flags
|= PASS8
;
#if defined (TIOCLGET) && defined (LPASS8)
ioctl (tty
, TIOCLGET
, &flags
);
local_mode_flags
= flags
;
ioctl (tty
, TIOCLSET
, &flags
);
ioctl (tty
, TIOCGETC
, &original_tchars
);
bcopy (&original_tchars
, &temp
, sizeof (struct tchars
));
/* Get rid of C-s and C-q.
We remember the value of startc (C-q) so that if the terminal is in
xoff state, the user can xon it by pressing that character. */
xon_char
= temp
.t_startc
;
/* If there is an XON character, bind it to restart the output. */
rl_bind_key (xon_char
, rl_restart_output
);
/* If there is an EOF char, bind eof_char to it. */
/* Get rid of C-\ and C-c. */
temp
.t_intrc
= temp
.t_quitc
= -1;
ioctl (tty
, TIOCSETC
, &temp
);
ioctl (tty
, TIOCGLTC
, &original_ltchars
);
bcopy (&original_ltchars
, &temp
, sizeof (struct ltchars
));
/* Make the interrupt keys go away. Just enough to make people happy. */
temp
.t_dsuspc
= -1; /* C-y */
temp
.t_lnextc
= -1; /* C-v */
ioctl (tty
, TIOCSLTC
, &temp
);
the_ttybuff
.sg_flags
&= ~ECHO
;
the_ttybuff
.sg_flags
|= CBREAK
;
ioctl (tty
, TIOCSETN
, &the_ttybuff
);
/* Restore the terminal to its original state. */
int tty
= fileno (rl_instream
);
#if defined (TIOCLGET) && defined (LPASS8)
if ((the_ttybuff
.sg_flags
& (ODDP
| EVENP
)) == (ODDP
| EVENP
))
ioctl (tty
, TIOCLSET
, &local_mode_flags
);
ioctl (tty
, TIOCSLTC
, &original_ltchars
);
ioctl (tty
, TIOCSETC
, &original_tchars
);
the_ttybuff
.sg_flags
= original_tty_flags
;
ioctl (tty
, TIOCSETN
, &the_ttybuff
);
#else /* !defined (NEW_TTY_DRIVER) */
static struct termio otio
;
int tty
= fileno (rl_instream
);
ioctl (tty
, TCGETA
, &tio
);
ioctl (tty
, TCGETA
, &otio
);
readline_echoing_p
= (tio
.c_lflag
& ECHO
);
tio
.c_lflag
&= ~(ICANON
|ECHO
);
tio
.c_iflag
&= ~(IXON
|ISTRIP
|INPCK
);
tio
.c_cc
[VEOF
] = 1; /* really: MIN */
tio
.c_cc
[VEOL
] = 0; /* really: TIME */
ioctl (tty
, TCSETAW
,&tio
);
int tty
= fileno (rl_instream
);
ioctl (tty
, TCSETAW
, &otio
);
#endif /* NEW_TTY_DRIVER */
/* **************************************************************** */
/* **************************************************************** */
/* Return 0 if C is not a member of the class of characters that belong
in words, or 1 if it is. */
int allow_pathname_alphabetic_chars
= 0;
char *pathname_alphabetic_chars
= "/-_=~.#$";
if (pure_alphabetic (c
) || (numeric (c
)))
if (allow_pathname_alphabetic_chars
)
return ((int)rindex (pathname_alphabetic_chars
, c
));
/* Return non-zero if C is a numeric character. */
return (c
>= '0' && c
<= '9');
/* Ring the terminal bell. */
fprintf (stderr
, "\007");
/* How to abort things. */
longjmp (readline_top_level
, 1);
/* Return a copy of the string between FROM and TO.
FROM is inclusive, TO is not. */
/* Fix it if the caller is confused. */
copy
= (char *)xmalloc (1 + length
);
strncpy (copy
, the_line
+ from
, length
);
/* **************************************************************** */
/* **************************************************************** */
/* Insert a string of text into the line at point. This is the only
way that you should do insertion. rl_insert () calls this
extern int doing_an_undo
;
register int i
, l
= strlen (string
);
while (rl_end
+ l
>= rl_line_buffer_len
)
(char *)xrealloc (rl_line_buffer
,
rl_line_buffer_len
+= DEFAULT_BUFFER_SIZE
);
the_line
= rl_line_buffer
;
for (i
= rl_end
; i
>= rl_point
; i
--)
the_line
[i
+ l
] = the_line
[i
];
strncpy (the_line
+ rl_point
, string
, l
);
/* Remember how to undo this if we aren't undoing something. */
/* If possible and desirable, concatenate the undos. */
if ((strlen (string
) == 1) &&
(rl_undo_list
->what
== UNDO_INSERT
) &&
(rl_undo_list
->end
== rl_point
) &&
(rl_undo_list
->end
- rl_undo_list
->start
< 20))
rl_add_undo (UNDO_INSERT
, rl_point
, rl_point
+ l
, (char *)NULL
);
/* Delete the string between FROM and TO. FROM is
rl_delete_text (from
, to
)
extern int doing_an_undo
;
/* Fix it if the caller is confused. */
text
= rl_copy (from
, to
);
strncpy (the_line
+ from
, the_line
+ to
, rl_end
- to
);
/* Remember how to undo this delete. */
rl_add_undo (UNDO_DELETE
, from
, to
, text
);
/* **************************************************************** */
/* Readline character functions */
/* **************************************************************** */
/* This is not a gap editor, just a stupid line input routine. No hair
is involved in writing any of the functions, and none should be. */
rl_end is the place in the string that we would place '\0';
i.e., it is always safe to place '\0' there.
rl_point is the place in the string where the cursor is. Sometimes
this is the same as rl_end.
Any command that is called interactively receives two arguments.
The first is a count: the numeric arg pased to this command.
The second is the key which invoked this command.
/* **************************************************************** */
/* **************************************************************** */
/* Note that if you `optimize' the display for these functions, you cannot
use said functions in other functions which do not do optimizing display.
I.e., you will have to update the data base for rl_redisplay, and you
might as well let rl_redisplay do that job. */
/* Move forward COUNT characters. */
if (rl_point
== (rl_end
- (rl_editing_mode
== vi_mode
)))
/* Move backward COUNT characters. */
/* Move to the beginning of the line. */
/* Move to the end of the line. */
/* Move forward a word. We do what Emacs does. */
rl_backward_word (-count
);
/* If we are not in a word, move forward until we are in one.
Then, move forward until we hit a non-alphabetic character. */
while (++rl_point
< rl_end
)
if (alphabetic (c
)) break;
if (rl_point
== rl_end
) return;
while (++rl_point
< rl_end
)
if (!alphabetic (c
)) break;
/* Move backward a word. We do what Emacs does. */
rl_forward_word (-count
);
/* Like rl_forward_word (), except that we look at the characters
c
= the_line
[rl_point
- 1];
c
= the_line
[rl_point
- 1];
if (alphabetic (c
)) break;
c
= the_line
[rl_point
- 1];
/* Clear the current line. Numeric argument to C-l does this. */
int curr_line
= last_c_pos
/ screenwidth
;
move_cursor_relative (0, the_line
); /* XXX is this right */
rl_forced_update_display ();
/* C-l typed to a line without quoting clears the screen, and then reprints
the prompt and the current input line. Given a numeric arg, redraw only
extern char *term_clrpag
;
static void output_character_function ();
tputs (term_clrpag
, 1, output_character_function
);
rl_forced_update_display ();
/* **************************************************************** */
/* **************************************************************** */
/* Insert the character C at the current location, moving point forward. */
/* If we can optimize, then do it. But don't let people crash
readline because of extra large arguments. */
if (count
> 1 && count
< 1024)
string
= (char *)alloca (1 + count
);
for (i
= 0; i
< count
; i
++)
string
= (char *)alloca (1024 + 1);
for (i
= 0; i
< 1024; i
++)
descreaser
= (count
> 1024 ? 1024 : count
);
string
[descreaser
] = '\0';
/* We are inserting a single character.
If there is pending input, then make a string of all of the
pending characters that are bound to rl_insert, and insert
string
= (char *)alloca (ibuffer_len
+ 1);
while ((key
= rl_get_char()) != -2 &&
(keymap
[key
].type
== ISFUNC
&&
keymap
[key
].function
== rl_insert
))
/* Inserting a single character. */
string
= (char *)alloca (2);
/* Insert the next typed character verbatim. */
int c
= rl_read_key (in_stream
);
/* Insert a tab character. */
/* Non-zero means enter insertion mode. */
static vi_doing_insert
= 0;
/* What to do when a NEWLINE is pressed. We accept the whole line.
KEY is the key that invoked this command. I guess it could have
meaning in the future. */
/* What to do for some uppercase characters, like meta characters,
and some characters appearing in emacs_ctlx_keymap. This function
is just a stub, you bind keys to it and the code in rl_dispatch ()
rl_do_lowercase_version (ignore1
, ignore2
)
/* Rubout the character behind point. */
int orig_point
= rl_point
;
rl_kill_text (orig_point
, rl_point
);
int c
= the_line
[--rl_point
];
rl_delete_text (rl_point
, rl_point
+ 1);
if (rl_point
== rl_end
&& alphabetic (c
) && last_c_pos
)
/* Delete the character under the cursor. Given a numeric argument,
kill that many characters instead. */
rl_delete (count
, invoking_key
)
if ((count
> 1) || ((count
== 1) && (rl_editing_mode
== vi_mode
)))
int orig_point
= rl_point
;
while (count
&& (rl_point
< rl_end
))
rl_kill_text (orig_point
, rl_point
);
rl_delete_text (rl_point
, rl_point
+ 1);
/* **************************************************************** */
/* **************************************************************** */
/* The next two functions mimic unix line editing behaviour, except they
save the deleted text on the kill ring. This is safer than not saving
it, and since we have a ring, nobody should get screwed. */
/* This does what C-w does in Unix. We can't prevent people from
using behaviour that they expect. */
int orig_point
= rl_point
;
while (rl_point
&& whitespace (the_line
[rl_point
- 1]))
while (rl_point
&& !whitespace (the_line
[rl_point
- 1]))
rl_kill_text (rl_point
, orig_point
);
/* Here is C-u doing what Unix does. You don't *have* to use these
key-bindings. We have a choice of killing the entire line, or
killing from where we are to the start of the line. We choose the
latter, because if you are a Unix weenie, then you haven't backspaced
into the line at all, and if you aren't, then you know what you are
rl_kill_text (rl_point
, 0);
/* **************************************************************** */
/* **************************************************************** */
/* Random and interesting things in here. */
/* **************************************************************** */
/* **************************************************************** */
/* The three kinds of things that we know how to do. */
/* Uppercase the word at point. */
rl_change_case (count
, UpCase
);
/* Lowercase the word at point. */
rl_change_case (count
, DownCase
);
/* Upcase the first letter, downcase the rest. */
rl_capitalize_word (count
)
rl_change_case (count
, CapCase
);
Change the case of COUNT words, performing OP on them.
OP is one of UpCase, DownCase, or CapCase.
If a negative argument is given, leave point where it started,
otherwise, leave it where it moves to. */
rl_change_case (count
, op
)
register int start
= rl_point
, end
;
/* We are going to modify some text, so let's prepare to undo it. */
rl_modifying (start
, end
);
for (; start
< end
; start
++)
the_line
[start
] = to_upper (the_line
[start
]);
the_line
[start
] = to_lower (the_line
[start
]);
the_line
[start
] = to_upper (the_line
[start
]);
the_line
[start
] = to_lower (the_line
[start
]);
if (!pure_alphabetic (the_line
[start
]))
/* **************************************************************** */
/* **************************************************************** */
/* Transpose the words at point. */
rl_transpose_words (count
)
int w1_beg
, w1_end
, w2_beg
, w2_end
;
int orig_point
= rl_point
;
/* Find the two words. */
rl_backward_word (count
);
/* Do some check to make sure that there really are two words. */
if ((w1_beg
== w2_beg
) || (w2_beg
< w1_end
))
/* Get the text of the words. */
word1
= rl_copy (w1_beg
, w1_end
);
word2
= rl_copy (w2_beg
, w2_end
);
/* We are about to do many insertions and deletions. Remember them
/* Do the stuff at word2 first, so that we don't have to worry
rl_delete_text (w2_beg
, w2_end
);
rl_delete_text (w1_beg
, w1_end
);
/* This is exactly correct since the text before this point has not
/* I think that does it. */
free (word1
); free (word2
);
/* Transpose the characters at point. If point is at the end of the line,
then transpose the characters before point. */
rl_transpose_chars (count
)
if (!rl_point
|| rl_end
< 2) {
if (rl_point
== rl_end
) {
int t
= the_line
[rl_point
- 1];
the_line
[rl_point
- 1] = the_line
[rl_point
- 2];
the_line
[rl_point
- 2] = t
;
int t
= the_line
[rl_point
];
the_line
[rl_point
] = the_line
[rl_point
- 1];
the_line
[rl_point
- 1] = t
;
if (count
< 0 && rl_point
)
/* **************************************************************** */
/* **************************************************************** */
rl_restart_output (count
, key
)
int fildes
= fileno (stdin
);
ioctl (fildes
, TIOCSTART
, 0);
/* **************************************************************** */
/* Completion matching, from readline's point of view. */
/* **************************************************************** */
/* Pointer to the generator function for completion_matches ().
NULL means to use filename_entry_function (), the default filename
Function
*rl_completion_entry_function
= (Function
*)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
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
;
/* Complete the word at or before point. You have supplied the function
that does the initial simple matching selection algorithm (see
completion_matches ()). The default is to do filename completion. */
rl_complete (ignore
, invoking_key
)
int ignore
, invoking_key
;
rl_complete_internal (TAB
);
/* List the possible completions. See description of rl_complete (). */
rl_possible_completions ()
rl_complete_internal ('?');
/* The user must press "y" or "n". Non-zero return means "y" pressed. */
c
= rl_read_key (in_stream
);
if (c
== 'y' || c
== 'Y') return (1);
if (c
== 'n' || c
== 'N') return (0);
if (c
== ABORT_CHAR
) rl_abort ();
/* Up to this many items will be displayed in response to a
possible-completions call. After that, we ask the user if
she is sure she wants to see them all. */
int rl_completion_query_items
= 100;
/* The basic list of characters that signal a break between words for the
completer routine. The contents of this variable is what breaks words
in the shell, i.e. " \t\n\"\\'`@$><=" */
char *rl_basic_word_break_characters
= " \t\n\"\\'`@$><=";
/* The list of characters that signal a break between words for
rl_complete_internal. The default list is the contents of
rl_basic_word_break_characters. */
char *rl_completer_word_break_characters
= (char *)NULL
;
/* List of characters that are word break characters, but should be left
in TEXT when it is passed to the completion function. The shell uses
this to help determine what kind of completing to do. */
char *rl_special_prefixes
= (char *)NULL
;
/* If non-zero, then disallow duplicates in the matches. */
int rl_ignore_completion_duplicates
= 1;
/* Non-zero means that the results of the matches are to be treated
as filenames. This is ALWAYS zero on entry, and can only be changed
within a completion entry finder function. */
int rl_filename_completion_desired
= 0;
/* Complete the word at or before point.
WHAT_TO_DO says what to do with the completion.
`?' means list the possible completions.
TAB means do standard completion.
`*' means insert all of the possible completions. */
rl_complete_internal (what_to_do
)
char *filename_completion_function ();
char **completion_matches (), **matches
;
int start
, end
, delimiter
= 0;
if (rl_completion_entry_function
)
our_func
= rl_completion_entry_function
;
our_func
= (int (*)())filename_completion_function
;
/* Only the completion entry function can change this. */
rl_filename_completion_desired
= 0;
/* We now look backwards for the start of a filename/variable word. */
!rindex (rl_completer_word_break_characters
, the_line
[rl_point
]));
/* If we are at a word break, then advance past it. */
if (rindex (rl_completer_word_break_characters
, (the_line
[rl_point
])))
/* If the character that caused the word break was a quoting
character, then remember it as the delimiter. */
if (rindex ("\"'", the_line
[rl_point
]) && (end
- rl_point
) > 1)
delimiter
= the_line
[rl_point
];
/* 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
||
!rindex (rl_special_prefixes
, the_line
[rl_point
]))
text
= rl_copy (start
, end
);
/* If the user wants to TRY to complete, but then wants to give
up and use the default completion function, they set the
variable rl_attempted_completion_function. */
if (rl_attempted_completion_function
)
(char **)(*rl_attempted_completion_function
) (text
, start
, end
);
goto after_usual_completion
;
matches
= completion_matches (text
, our_func
, start
, end
);
/* It seems to me that in all the cases we handle we would like
to ignore duplicate possiblilities. Scan for the text to
insert being identical to the other completions. */
if (rl_ignore_completion_duplicates
)
/* It is safe to sort this array, because the lowest common
denominator found in matches[0] will remain in place. */
for (i
= 0; matches
[i
]; i
++);
qsort (matches
, i
, sizeof (char *), compare_strings
);
/* Remember the lowest common denimator for it may be unique. */
lowest_common
= savestring (matches
[0]);
for (i
= 0; matches
[i
+ 1]; i
++)
if (strcmp (matches
[i
], matches
[i
+ 1]) == 0)
/* We have marked all the dead slots with (char *)-1.
Copy all the non-dead entries into a new array. */
(char **)malloc ((3 + newlen
) * sizeof (char *));
for (i
= 1, j
= 1; matches
[i
]; i
++)
if (matches
[i
] != (char *)-1)
temp_array
[j
++] = matches
[i
];
temp_array
[j
] = (char *)NULL
;
if (matches
[0] != (char *)-1)
/* Place the lowest common denominator back in [0]. */
matches
[0] = lowest_common
;
/* If there is one string left, and it is identical to the
lowest common denominator, then the LCD is the string to
if (j
== 2 && strcmp (matches
[0], matches
[1]) == 0)
matches
[1] = (char *)NULL
;
rl_delete_text (start
, rl_point
);
rl_insert_text (matches
[0]);
/* If there are more matches, ring the bell to indicate.
If this was the only match, and we are hacking files,
check the file to see if it was a directory. If so,
add a '/' to the name. If not, and we are at the end
of the line, then add a space. */
ding (); /* There are other matches remaining. */
temp_string
[0] = delimiter
? delimiter
: ' ';
if (rl_filename_completion_desired
)
char *filename
= tilde_expand (matches
[0]);
if ((stat (filename
, &finfo
) == 0) &&
((finfo
.st_mode
& S_IFMT
) == S_IFDIR
))
if (the_line
[rl_point
] != '/')
rl_insert_text (temp_string
);
rl_insert_text (temp_string
);
rl_delete_text (start
, rl_point
);
rl_insert_text (matches
[i
++]);
rl_insert_text (matches
[0]);
int len
, count
, limit
, max
= 0;
/* Handle simple case first. What if there is only one answer? */
if (rl_filename_completion_desired
)
temp
= rindex (matches
[0], '/');
fprintf (out_stream
, "%s", temp
);
/* There is more than one answer. Find out how many there are,
and find out what the maximum printed length of a single entry
for (i
= 1; matches
[i
]; i
++)
char *temp
= (char *)NULL
;
/* If we are hacking filenames, then only count the characters
after the last slash in the pathname. */
if (rl_filename_completion_desired
)
temp
= rindex (matches
[i
], '/');
/* If there are many items, then ask the user if she
really wants to see them all. */
if (len
>= rl_completion_query_items
)
"There are %d possibilities. Do you really", len
);
fprintf (out_stream
, "wish to see them all? (y or n)");
/* How many items of MAX length can we fit in the screen window? */
limit
= screenwidth
/ max
;
if (limit
!= 1 && (limit
* max
== screenwidth
))
/* How many iterations of the printing loop? */
count
= (len
+ (limit
- 1)) / limit
;
/* Watch out for special case. If LEN is less than LIMIT, then
just do the inner printing loop. */
if (len
< limit
) count
= 1;
/* Sort the items if they are not already sorted. */
if (!rl_ignore_completion_duplicates
)
qsort (matches
, len
, sizeof (char *), compare_strings
);
/* Print the sorted items, up-and-down alphabetically, like
for (i
= 1; i
< count
+ 1; i
++)
for (j
= 0, l
= i
; j
< limit
; j
++)
if (l
> len
|| !matches
[l
])
char *temp
= (char *)NULL
;
if (rl_filename_completion_desired
)
temp
= rindex (matches
[l
], '/');
fprintf (out_stream
, "%s", temp
);
for (k
= 0; k
< max
- strlen (temp
); k
++)
for (i
= 0; matches
[i
]; i
++)
/* A completion function for usernames.
TEXT contains a partial username preceded by a random
character (usually `~'). */
username_completion_function (text
, state
)
static char *username
= (char *)NULL
;
static struct passwd
*entry
;
username
= savestring (&text
[1]);
namelen
= strlen (username
);
while (entry
= getpwent ())
if (strncmp (username
, entry
->pw_name
, namelen
) == 0)
char *value
= (char *)xmalloc (2 + strlen (entry
->pw_name
));
strcpy (value
+ 1, entry
->pw_name
);
rl_filename_completion_desired
= 1;
/* If non-null, this contains the address of a function to call if the
standard meaning for expanding a tilde fails. The function is called
with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
which is the expansion, or a NULL pointer if there is no expansion. */
Function
*rl_tilde_expander
= (Function
*)NULL
;
/* Expand FILENAME if it begins with a tilde. This always returns
char *dirname
= filename
? savestring (filename
) : (char *)NULL
;
if (dirname
&& *dirname
== '~')
if (!dirname
[1] || dirname
[1] == '/')
/* Prepend $HOME to the rest of the string. */
char *temp_home
= (char *)getenv ("HOME");
temp_name
= (char *)alloca (1 + strlen (&dirname
[1])
+ (temp_home
? strlen (temp_home
) : 0));
strcpy (temp_name
, temp_home
);
strcat (temp_name
, &dirname
[1]);
dirname
= savestring (temp_name
);
struct passwd
*getpwnam (), *user_entry
;
char *username
= (char *)alloca (257);
for (i
= 1; c
= dirname
[i
]; i
++)
else username
[i
- 1] = c
;
if (!(user_entry
= getpwnam (username
)))
/* If the calling program has a special syntax for
expanding tildes, and we couldn't find a standard
expansion, then let them try. */
expansion
= (char *)(*rl_tilde_expander
) (username
);
temp_name
= (char *)alloca (1 + strlen (expansion
)
strcpy (temp_name
, expansion
);
strcat (temp_name
, &dirname
[i
]);
* We shouldn't report errors.
temp_name
= (char *)alloca (1 + strlen (user_entry
->pw_dir
)
strcpy (temp_name
, user_entry
->pw_dir
);
strcat (temp_name
, &dirname
[i
]);
dirname
= savestring (temp_name
);
/* **************************************************************** */
/* **************************************************************** */
/* Non-zero tells rl_delete_text and rl_insert_text to not add to
/* The current undo list for THE_LINE. */
UNDO_LIST
*rl_undo_list
= (UNDO_LIST
*)NULL
;
/* Remember how to undo something. Concatenate some undos if that
rl_add_undo (what
, start
, end
, text
)
UNDO_LIST
*temp
= (UNDO_LIST
*)xmalloc (sizeof (UNDO_LIST
));
temp
->next
= rl_undo_list
;
/* Free the existing undo list. */
UNDO_LIST
*release
= rl_undo_list
;
rl_undo_list
= rl_undo_list
->next
;
if (release
->what
== UNDO_DELETE
)
/* Undo the next thing in the list. Return 0 if there
is nothing to undo, or non-zero if there was. */
int waiting_for_begin
= 0;
switch (rl_undo_list
->what
) {
/* Undoing deletes means inserting some text. */
rl_point
= rl_undo_list
->start
;
rl_insert_text (rl_undo_list
->text
);
free (rl_undo_list
->text
);
/* Undoing inserts means deleting some text. */
rl_delete_text (rl_undo_list
->start
, rl_undo_list
->end
);
rl_point
= rl_undo_list
->start
;
/* Undoing an END means undoing everything 'til we get to
/* Undoing a BEGIN means that we are done with this group. */
rl_undo_list
= rl_undo_list
->next
;
/* Begin a group. Subsequent undos are undone as an atomic operation. */
rl_add_undo (UNDO_BEGIN
, 0, 0, 0);
/* End an undo group started with rl_begin_undo_group (). */
rl_add_undo (UNDO_END
, 0, 0, 0);
/* Save an undo entry for the text from START to END. */
rl_modifying (start
, end
)
char *temp
= rl_copy (start
, end
);
rl_add_undo (UNDO_DELETE
, start
, end
, temp
);
rl_add_undo (UNDO_INSERT
, start
, end
, (char *)NULL
);
/* Revert the current line to its previous state. */
if (!rl_undo_list
) ding ();
/* Do some undoing of things that were done. */
if (count
< 0) return; /* Nothing to do. */
/* **************************************************************** */
/* **************************************************************** */
/* We already have a history library, and that is what we use to control
the history features of readline. However, this is our local interface
to the history mechanism. */
/* While we are editing the history, this is the saved
version of the original line. */
HIST_ENTRY
*saved_line_for_history
= (HIST_ENTRY
*)NULL
;
/* Set the history pointer back to the last entry in the history. */
if (saved_line_for_history
)
free_history_entry (saved_line_for_history
);
saved_line_for_history
= (HIST_ENTRY
*)NULL
;
/* Free the contents (and containing structure) of a HIST_ENTRY. */
free_history_entry (entry
)
/* Perhaps put back the current line if it has changed. */
HIST_ENTRY
*temp
= current_history ();
/* If the current line has changed, save the changes. */
if (temp
&& ((UNDO_LIST
*)(temp
->data
) != rl_undo_list
)) {
temp
= replace_history_entry (where_history (), the_line
, rl_undo_list
);
/* Put back the saved_line_for_history if there is one. */
if (saved_line_for_history
) {
strcpy (the_line
, saved_line_for_history
->line
);
rl_undo_list
= (UNDO_LIST
*)saved_line_for_history
->data
;
free_history_entry (saved_line_for_history
);
saved_line_for_history
= (HIST_ENTRY
*)NULL
;
rl_end
= rl_point
= strlen (the_line
);
/* Save the current line in saved_line_for_history. */
if (!saved_line_for_history
) {
saved_line_for_history
= (HIST_ENTRY
*)xmalloc (sizeof (HIST_ENTRY
));
saved_line_for_history
->line
= savestring (the_line
);
saved_line_for_history
->data
= (char *)rl_undo_list
;
/* **************************************************************** */
/* **************************************************************** */
/* Meta-< goes to the start of the history. */
rl_beginning_of_history ()
rl_get_previous_history (1 + where_history ());
/* Meta-> goes to the end of the history. (The current line). */
/* Move down to the next history line. */
rl_get_next_history (count
)
HIST_ENTRY
*temp
= (HIST_ENTRY
*)NULL
;
rl_get_previous_history (-count
);
strcpy (the_line
, temp
->line
);
rl_undo_list
= (UNDO_LIST
*)temp
->data
;
rl_end
= rl_point
= strlen (the_line
);
/* Get the previous item out of our interactive history, making it the current
line. If there is no previous history, just ding. */
rl_get_previous_history (count
)
HIST_ENTRY
*old_temp
= (HIST_ENTRY
*)NULL
;
HIST_ENTRY
*temp
= (HIST_ENTRY
*)NULL
;
rl_get_next_history (-count
);
/* If we don't have a line saved, then save this one. */
/* If the current line has changed, save the changes. */
temp
= previous_history ();
/* If there was a large argument, and we moved back to the start of the
history, that is not an error. So use the last value found. */
strcpy (the_line
, temp
->line
);
rl_undo_list
= (UNDO_LIST
*)temp
->data
;
rl_end
= rl_point
= strlen (the_line
);
if (rl_editing_mode
== vi_mode
)
/* There is a command in ksh which yanks into this line, the last word
of the previous line. Here it is. We left it on M-. */
rl_yank_previous_last_arg (ignore
)
/* **************************************************************** */
/* I-Search and Searching */
/* **************************************************************** */
/* Search backwards through the history looking for a string which is typed
interactively. Start with the current line. */
rl_reverse_search_history (sign
, key
)
rl_search_history (-sign
, key
);
/* Search forwards through the history looking for a string which is typed
interactively. Start with the current line. */
rl_forward_search_history (sign
, key
)
rl_search_history (sign
, key
);
/* Display the current state of the search in the echo-area.
SEARCH_STRING contains the string that is being searched for,
DIRECTION is zero for forward, or 1 for reverse,
WHERE is the history list number of the current line. If it is
-1, then this line is the starting one. */
rl_display_search (search_string
, reverse_p
, where
)
char *message
= (char *)NULL
;
(char *)alloca (1 + (search_string
? strlen (search_string
) : 0) + 30);
sprintf (message
, "[%d]", where
+ history_base
);
strcat (message
, "reverse-");
strcat (message
, "i-search)`");
strcat (message
, search_string
);
rl_message (message
, 0, 0);
/* Search through the history looking for an interactively typed string.
This is analogous to i-search. We start the search in the current line.
DIRECTION is which direction to search; > 0 means forward, < 0 means
rl_search_history (direction
, invoking_key
)
/* The string that the user types in to search for. */
char *search_string
= (char *)alloca (128);
/* The current length of SEARCH_STRING. */
/* The list of lines to search through. */
/* The length of LINES. */
/* Where we get LINES from. */
HIST_ENTRY
**hlist
= history_list ();
int orig_point
= rl_point
;
int orig_line
= where_history ();
int last_found_line
= orig_line
;
/* The line currently being searched. */
/* Offset in that line. */
/* Non-zero if we are doing a reverse search. */
int reverse
= (direction
< 0);
/* Create an arrary of pointers to the lines that we want to search. */
for (i
= 0; hlist
[i
]; i
++);
/* Allocate space for this many lines, +1 for the current input line,
and remember those lines. */
lines
= (char **)alloca ((1 + (hlen
= i
)) * sizeof (char *));
for (i
= 0; i
< hlen
; i
++)
lines
[i
] = hlist
[i
]->line
;
if (saved_line_for_history
)
lines
[i
] = saved_line_for_history
->line
;
/* So I have to type it in this way instead. */
lines
[i
] = (char *)alloca (1 + strlen (the_line
));
strcpy (lines
[i
], &the_line
[0]);
/* The line where we start the search. */
/* Initialize search parameters. */
rl_display_search (search_string
, reverse
, -1);
c
= rl_read_key (in_stream
);
/* Hack C to Do What I Mean. */
Function
*f
= (Function
*)NULL
;
if (keymap
[c
].type
== ISFUNC
)
if (f
== rl_reverse_search_history
)
else if (f
== rl_forward_search_history
)
reverse
= (direction
< 0);
strcpy (the_line
, lines
[orig_line
]);
rl_end
= strlen (the_line
);
search_string
[search_string_index
++] = c
;
search_string
[search_string_index
] = '\0';
if (!search_string_index
)
if (index
!= strlen (sline
))
search_string_index
) == 0)
(strlen (sline
) - search_string_index
) + 1;
if (strncmp (search_string
,
search_string_index
) == 0)
/* At limit for direction? */
if ((reverse
&& i
< 0) ||
/* If the search string is longer than the current
if (search_string_index
> strlen (sline
))
/* Start actually searching. */
index
-= search_string_index
;
/* We cannot find the search string. Ding the bell. */
/* We have found the search string. Just display it. But don't
actually move there in the history list until the user accepts
strcpy (the_line
, lines
[i
]);
rl_end
= strlen (the_line
);
rl_display_search (search_string
, reverse
,
(i
== orig_line
) ? -1 : i
);
/* The user has won. They found the string that they wanted. Now all
we have to do is place them there. */
int now
= last_found_line
;
/* First put back the original state. */
strcpy (the_line
, lines
[orig_line
]);
rl_get_previous_history (orig_line
- now
);
rl_get_next_history (now
- orig_line
);
/* Make C be the next command to be executed. */
/* **************************************************************** */
/* **************************************************************** */
/* What we assume for a max number of kills. */
#define DEFAULT_MAX_KILLS 10
/* The real variable to look at to find out when to flush kills. */
int rl_max_kills
= DEFAULT_MAX_KILLS
;
/* Where to store killed text. */
char **rl_kill_ring
= (char **)NULL
;
/* Where we are in the kill ring. */
/* How many slots we have in the kill ring. */
int rl_kill_ring_length
= 0;
/* How to say that you only want to save a certain amount
rl_set_retained_kills (num
)
/* The way to kill something. This appends or prepends to the last
kill, if the last command was a kill command. if FROM is less
than TO, then the text is appended, otherwise prepended. If the
last command was not a kill command, then a new slot is made for
char *text
= rl_copy (from
, to
);
/* Is there anything to kill? */
/* Delete the copied text from the line. */
rl_delete_text (from
, to
);
/* First, find the slot to work with. */
if (!last_command_was_kill
) {
/* If we don't have any defined, then make one. */
(char **)xmalloc (((rl_kill_ring_length
= 1) + 1) * sizeof (char *));
/* We have to add a new slot on the end, unless we have exceeded
the max limit for remembering kills. */
slot
= rl_kill_ring_length
;
if (slot
== rl_max_kills
) {
for (i
= 0; i
< slot
; i
++)
rl_kill_ring
[i
] = rl_kill_ring
[i
+ 1];
(char **)xrealloc (rl_kill_ring
,
((slot
= (rl_kill_ring_length
+= 1)) + 1)
slot
= rl_kill_ring_length
- 1;
/* If the last command was a kill, prepend or append. */
if (last_command_was_kill
) {
char *old
= rl_kill_ring
[slot
];
char *new = (char *)xmalloc (1 + strlen (old
) + strlen (text
));
rl_kill_ring
[slot
] = new;
rl_kill_ring
[slot
] = text
;
/* Now REMEMBER! In order to do prepending or appending correctly, kill
commands always make rl_point's original position be the FROM argument,
and rl_point's extent be the TO argument. */
/* **************************************************************** */
/* **************************************************************** */
/* Delete the word at point, saving the text in the kill ring. */
int orig_point
= rl_point
;
rl_backward_kill_word (-count
);
if (rl_point
!= orig_point
)
rl_kill_text (orig_point
, rl_point
);
/* Rubout the word before point, placing it on the kill ring. */
rl_backward_kill_word (count
)
int orig_point
= rl_point
;
rl_backward_word (count
);
if (rl_point
!= orig_point
)
rl_kill_text (orig_point
, rl_point
);
/* Kill from here to the end of the line. If DIRECTION is negative, kill
back to the line start instead. */
int orig_point
= rl_point
;
rl_backward_kill_line (1);
if (orig_point
!= rl_point
)
rl_kill_text (orig_point
, rl_point
);
/* Kill backwards to the start of the line. If DIRECTION is negative, kill
forwards to the line end instead. */
rl_backward_kill_line (direction
)
int orig_point
= rl_point
;
rl_kill_text (orig_point
, rl_point
);
/* Yank back the last killed text. This ignores arguments. */
if (!rl_kill_ring
) rl_abort ();
rl_insert_text (rl_kill_ring
[rl_kill_index
]);
/* If the last command was yank, or yank_pop, and the text just
before point is identical to the current kill item, then
delete that text from the line, rotate the index down, and
yank back some other text. */
if (((rl_last_func
!= rl_yank_pop
) && (rl_last_func
!= rl_yank
)) ||
l
= strlen (rl_kill_ring
[rl_kill_index
]);
if (((rl_point
- l
) >= 0) &&
(strncmp (the_line
+ (rl_point
- l
),
rl_kill_ring
[rl_kill_index
], l
) == 0))
rl_delete_text ((rl_point
- l
), rl_point
);
rl_kill_index
= rl_kill_ring_length
- 1;
/* Yank the COUNTth argument from the previous history line. */
rl_yank_nth_arg (count
, ignore
)
register HIST_ENTRY
*entry
= previous_history ();
arg
= history_arg_extract (count
, count
, entry
->line
);
if (rl_point
&& the_line
[rl_point
- 1] != ' ')
/* How to toggle back and forth between editing modes. */
rl_editing_mode
= vi_mode
;
rl_editing_mode
= emacs_mode
;
keymap
= emacs_standard_keymap
;
/* **************************************************************** */
/* **************************************************************** */
/* Non-zero means that case is not significant in completion. */
int completion_case_fold
= 0;
/* Return an array of (char *) which is a list of completions for TEXT.
If there are no completions, return a NULL pointer.
The first entry in the returned array is the substitution for TEXT.
The remaining entries are the possible completions.
The array is terminated with a NULL pointer.
ENTRY_FUNCTION is a function of two args, and returns a (char *).
The first argument is TEXT.
The second is a state argument; it should be zero on the first call, and
non-zero on subsequent calls. It returns a NULL pointer to the caller
when there are no more matches.
completion_matches (text
, entry_function
)
char *(*entry_function
) ();
/* Number of slots in match_list. */
/* The list of matches. */
(char **)xmalloc (((match_list_size
= 10) + 1) * sizeof (char *));
/* Number of matches actually found. */
/* Temporary string binder. */
match_list
[1] = (char *)NULL
;
while (string
= (*entry_function
) (text
, matches
))
if (matches
+ 1 == match_list_size
)
(char **)xrealloc (match_list
,
((match_list_size
+= 10) + 1) * sizeof (char *));
match_list
[++matches
] = string
;
match_list
[matches
+ 1] = (char *)NULL
;
/* If there were any matches, then look through them finding out the
lowest common denominator. That then becomes match_list[0]. */
int low
= 100000; /* Count of max-matched characters. */
/* If only one match, just use that. */
match_list
[0] = match_list
[1];
match_list
[1] = (char *)NULL
;
/* Otherwise, compare each member of the list with
the next, finding out where they stop matching. */
if (completion_case_fold
)
(c1
= to_lower(match_list
[i
][si
])) &&
(c2
= to_lower(match_list
[i
+ 1][si
]));
(c1
= match_list
[i
][si
]) &&
(c2
= match_list
[i
+ 1][si
]);
match_list
[0] = (char *)xmalloc (low
+ 1);
strncpy (match_list
[0], match_list
[1], low
);
match_list
[0][low
] = '\0';
else /* There were no matches. */
match_list
= (char **)NULL
;
/* Okay, now we write the entry_function for filename completion. In the
general case. Note that completion in the shell is a little different
because of all the pathnames that must be followed when looking up the
completion for a command. */
filename_completion_function (text
, state
)
static char *filename
= (char *)NULL
;
static char *dirname
= (char *)NULL
;
static char *users_dirname
= (char *)NULL
;
struct direct
*entry
= (struct direct
*)NULL
;
/* If we don't have any state, then do some initialization. */
if (dirname
) free (dirname
);
if (filename
) free (filename
);
if (users_dirname
) free (users_dirname
);
filename
= savestring (text
);
dirname
= savestring (text
);
temp
= rindex (dirname
, '/');
strcpy (filename
, ++temp
);
/* We aren't done yet. We also support the "~user" syntax. */
/* Save the version of the directory that the user typed. */
users_dirname
= savestring (dirname
);
char *tilde_expand (), *temp_dirname
= tilde_expand (dirname
);
extern int follow_symbolic_links
;
if (follow_symbolic_links
&& (strcmp (dirname
, ".") != 0))
temp_dirname
= make_absolute (dirname
, get_working_directory (""));
directory
= opendir (dirname
);
filename_len
= strlen (filename
);
rl_filename_completion_desired
= 1;
/* At this point we should entertain the possibility of hacking wildcarded
filenames, like /usr/man*\/te<TAB>. If the directory name contains
globbing characters, then build an array of directories to glob on, and
glob on the first one. */
/* 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 ((strcmp (entry
->d_name
, ".") != 0) &&
(strcmp (entry
->d_name
, "..") != 0))
/* Otherwise, if these match upto the length of filename, then
if ((strlen (entry
->d_name
) >= filename_len
) &&
(strncmp (filename
, entry
->d_name
, filename_len
) == 0))
if ((entry
->d_namlen
>= filename_len
) &&
(strncmp (filename
, entry
->d_name
, filename_len
) == 0))
if (dirname
&& (strcmp (dirname
, ".") != 0))
temp
= (char *)xmalloc (1 + strlen (users_dirname
)
+ strlen (entry
->d_name
));
temp
= (char *)xmalloc (1 + strlen (users_dirname
)
strcpy (temp
, users_dirname
);
strcat (temp
, entry
->d_name
);
temp
= (savestring (entry
->d_name
));
/* **************************************************************** */
/* **************************************************************** */
/* rl_add_defun (char *name, Function *function, int key)
Add NAME to the list of named functions. Make FUNCTION
be the function that gets called.
If KEY is not -1, then bind it. */
rl_add_defun (name
, function
, key
)
rl_bind_key (key
, function
);
rl_add_funmap_entry (name
, function
);
/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
rl_bind_key (key
, function
)
if (key
> 127 && key
< 256)
if (keymap
[ESC
].type
== ISKMAP
)
Keymap escmap
= (Keymap
)keymap
[ESC
].function
;
escmap
[key
].type
= ISFUNC
;
escmap
[key
].function
= function
;
keymap
[key
].type
= ISFUNC
;
keymap
[key
].function
= function
;
/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid
rl_bind_key_in_map (key
, function
, map
)
result
= rl_bind_key (key
, function
);
/* Make KEY do nothing in the currently selected keymap.
Returns non-zero in case of error. */
return (rl_bind_key (key
, (Function
*)NULL
));
/* Make KEY do nothing in MAP.
Returns non-zero in case of error. */
rl_unbind_key_in_map (key
, map
)
return (rl_bind_key_in_map (key
, (Function
*)NULL
, map
));
/* Bind the key sequence represented by the string KEYSEQ to
FUNCTION. This makes new keymaps as necessary. The initial
place to do bindings is in MAP. */
rl_set_key (keyseq
, function
, map
)
rl_generic_bind (ISFUNC
, keyseq
, function
, map
);
/* Bind the key sequence represented by the string KEYSEQ to
the string of characters MACRO. This makes new keymaps as
necessary. The initial place to do bindings is in MAP. */
rl_macro_bind (keyseq
, macro
, map
)
char *macro_keys
= (char *)xmalloc (2 * (strlen (macro
)));
if (rl_translate_keyseq (macro
, macro_keys
, ¯o_keys_len
))
rl_generic_bind (ISMACR
, keyseq
, macro_keys
, map
);
/* Bind the key sequence represented by the string KEYSEQ to
the arbitrary pointer DATA. TYPE says what kind of data is
pointed to by DATA, right now this can be a function (ISFUNC),
a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps
as necessary. The initial place to do bindings is in MAP. */
rl_generic_bind (type
, keyseq
, data
, map
)
/* If no keys to bind to, exit right away. */
keys
= (char *)alloca (1 + (2 * strlen (keyseq
)));
/* Translate the ASCII representation of KEYSEQ into an array
of characters. Stuff the characters into ARRAY, and the
length of ARRAY into LENGTH. */
if (rl_translate_keyseq (keyseq
, keys
, &keys_len
))
/* Handle mapping of the ESC Key in vi mode */
if ((rl_editing_mode
== vi_mode
) && (keys
[0] == ESC
))
map
= vi_movement_keymap
;
extern KEYMAP_ENTRY_ARRAY vi_escape_keymap
;
/* Bind keys, making new keymaps as necessary. */
for (i
= start
; i
< keys_len
; i
++)
if (map
[keys
[i
]].type
!= ISKMAP
)
if (map
[i
].type
== ISMACR
)
free ((char *)map
[i
].function
);
map
[keys
[i
]].type
= ISKMAP
;
map
[keys
[i
]].function
= (Function
*)rl_make_bare_keymap ();
map
= (Keymap
)map
[keys
[i
]].function
;
if (map
[keys
[i
]].type
== ISMACR
)
free ((char *)map
[keys
[i
]].function
);
map
[keys
[i
]].function
= (Function
*)data
;
map
[keys
[i
]].type
= type
;
/* Translate the ASCII representation of SEQ, stuffing the
values into ARRAY, an array of characters. LEN gets the
final length of ARRAY. Return non-zero if there was an
rl_translate_keyseq (seq
, array
, len
)
register int i
, c
, l
= 0;
for (i
= 0; c
= seq
[i
]; i
++)
if (((c
== 'C' || c
== 'M') && seq
[i
+ 1] == '-') ||
/* Handle special case of backwards define. */
if (strncmp (&seq
[i
], "C-\\M-", 5) == 0)
array
[l
++] = CTRL (to_upper (seq
[i
]));
array
[l
++] = CTRL (to_upper (seq
[i
]));
/* Return a pointer to the function that STRING represents.
If STRING doesn't have a matching function, then a NULL pointer
rl_named_function (string
)
for (i
= 0; funmap
[i
]; i
++)
if (stricmp (funmap
[i
]->name
, string
) == 0)
return (funmap
[i
]->function
);
return ((Function
*)NULL
);
/* The last key bindings file read. */
static char *last_readline_init_file
= "~/.inputrc";
/* Re-read the current keybindings file. */
rl_re_read_init_file (count
, ignore
)
rl_read_init_file (last_readline_init_file
);
/* Do key bindings from a file. If FILENAME is NULL it defaults
to `~/.inputrc'. If the file existed and could be opened and
read, 0 is returned, otherwise errno is returned. */
rl_read_init_file (filename
)
int line_size
, line_index
;
char *line
= (char *)xmalloc (line_size
= 100);
/* Default the filename. */
openname
= tilde_expand (filename
);
file
= fopen (openname
, "r");
last_readline_init_file
= filename
;
/* Loop reading lines from the file. Lines that start with `#' are
comments, all other lines are commands for readline initialization. */
while ((c
= getc(file
)) != EOF
)
/* If comment, flush to EOL. */
while ((c
= getc(file
)) != EOF
&& c
!= '\n');
/* Otherwise, this is the start of a line. Read the
while (c
!= EOF
&& c
!= '\n')
if (line_index
== line_size
)
line
= (char *)xrealloc (line
, line_size
+= 100);
rl_parse_and_bind (line
);
/* Close up the file and exit. */
/* **************************************************************** */
/* **************************************************************** */
/* Calling programs set this to have their argv[0]. */
char *rl_readline_name
= "other";
/* Stack of previous values of parsing_conditionalized_out. */
static unsigned char *if_stack
= (unsigned char *)NULL
;
static int if_stack_depth
= 0;
static int if_stack_size
= 0;
/* Push parsing_conditionalized_out, and set parser state based on ARGS. */
if (if_stack_depth
+ 1 >= if_stack_size
)
if_stack
= (unsigned char *)xmalloc (if_stack_size
= 20);
if_stack
= (unsigned char *)xrealloc (if_stack
, if_stack_size
+= 20);
if_stack
[if_stack_depth
++] = parsing_conditionalized_out
;
/* We only check to see if the first word in ARGS is the same as the
value stored in rl_readline_name. */
/* Isolate first argument. */
for (i
= 0; args
[i
] && !whitespace (args
[i
]); i
++);
if (stricmp (args
, rl_readline_name
) == 0)
parsing_conditionalized_out
= 0;
parsing_conditionalized_out
= 1;
/* Invert the current parser state if there is anything on the stack. */
parsing_conditionalized_out
= !parsing_conditionalized_out
;
/* *** What, no error message? *** */
/* Terminate a conditional, popping the value of
parsing_conditionalized_out from the stack. */
parsing_conditionalized_out
= if_stack
[--if_stack_depth
];
/* *** What, no error message? *** */
/* Associate textual names with actual functions. */
} parser_directives
[] = {
{ "endif", parser_endif
},
{ (char *)0x0, (Function
*)0x0 }
/* Handle a parser directive. STATEMENT is the line of the directive
without any leading `$'. */
handle_parser_directive (statement
)
/* Isolate the actual directive. */
for (i
= 0; whitespace (statement
[i
]); i
++);
directive
= &statement
[i
];
for (; statement
[i
] && !whitespace (statement
[i
]); i
++);
for (; statement
[i
] && whitespace (statement
[i
]); i
++);
/* Lookup the command, and act on it. */
for (i
= 0; parser_directives
[i
].name
; i
++)
if (stricmp (directive
, parser_directives
[i
].name
) == 0)
(*parser_directives
[i
].function
) (args
);
/* *** Should an error message be output? */
/* Read the binding command from STRING and perform it.
A key binding command looks like: Keyname: function-name\0,
a variable binding command looks like: set variable value.
A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
rl_parse_and_bind (string
)
extern char *possible_control_prefixes
[], *possible_meta_prefixes
[];
static int substring_member_of_array (), stricmp ();
if (!string
|| !*string
|| *string
== '#')
/* If this is a parser directive, act on it. */
handle_parser_directive (&string
[1]);
/* If we are supposed to be skipping parsing right now, then do it. */
if (parsing_conditionalized_out
)
/* If this keyname is a complex key expression surrounded by quotes,
advance to after the matching close quote. */
for (i
= 1; c
= string
[i
]; i
++)
if (c
== '"' && string
[i
- 1] != '\\')
/* Advance to the colon (:) or whitespace which separates the two objects. */
for (; (c
= string
[i
]) && c
!= ':' && c
!= ' ' && c
!= '\t'; i
++ );
/* Mark the end of the command (or keyname). */
/* If this is a command to set a variable, then do that. */
if (stricmp (string
, "set") == 0)
/* Make VAR point to start of variable name. */
while (*var
&& whitespace (*var
)) var
++;
/* Make value point to start of value string. */
while (*value
&& !whitespace (*value
)) value
++;
while (*value
&& whitespace (*value
)) value
++;
rl_variable_bind (var
, value
);
/* Skip any whitespace between keyname and funname. */
for (; string
[i
] && whitespace (string
[i
]); i
++);
For straight function names just look for whitespace, since
that will signify the end of the string. But this could be a
macro definition. In that case, the string is quoted, so skip
to the matching delimiter. */
if (*funname
== '\'' || *funname
== '"')
int delimiter
= string
[i
++];
for (; c
= string
[i
]; i
++)
if (c
== delimiter
&& string
[i
- 1] != '\\')
/* Advance to the end of the string. */
for (; string
[i
] && !whitespace (string
[i
]); i
++);
/* No extra whitespace at the end of the string. */
/* If this is a new-style key-binding, then do the binding with
rl_set_key (). Otherwise, let the older code deal with it. */
char *seq
= (char *)alloca (1 + strlen (string
));
for (j
= 1; string
[j
]; j
++)
if (string
[j
] == '"' && string
[j
- 1] != '\\')
if (*funname
== '\'' || *funname
== '"')
if (j
&& funname
[j
- 1] == *funname
)
rl_macro_bind (seq
, &funname
[1], keymap
);
rl_set_key (seq
, rl_named_function (funname
), keymap
);
/* Get the actual character we want to deal with. */
kname
= rindex (string
, '-');
key
= glean_key_from_name (kname
);
/* Add in control and meta bits. */
if (substring_member_of_array (string
, possible_control_prefixes
))
key
= CTRL (to_upper (key
));
if (substring_member_of_array (string
, possible_meta_prefixes
))
/* Temporary. Handle old-style keyname with macro-binding. */
if (*funname
== '\'' || *funname
== '"')
int fl
= strlen (funname
);
seq
[0] = key
; seq
[1] = '\0';
if (fl
&& funname
[fl
- 1] == *funname
)
rl_macro_bind (seq
, &funname
[1], keymap
);
rl_bind_key (key
, rl_named_function (funname
));
rl_variable_bind (name
, value
)
static int strnicmp (), stricmp ();
if (stricmp (name
, "editing-mode") == 0)
if (strnicmp (value
, "vi", 2) == 0)
keymap
= vi_insertion_keymap
;
rl_editing_mode
= vi_mode
;
else if (strnicmp (value
, "emacs", 5) == 0)
keymap
= emacs_standard_keymap
;
rl_editing_mode
= emacs_mode
;
else if (stricmp (name
, "horizontal-scroll-mode") == 0)
if (!*value
|| stricmp (value
, "On") == 0)
horizontal_scroll_mode
= 1;
horizontal_scroll_mode
= 0;
/* Return the character which matches NAME.
For example, `Space' returns ' '. */
assoc_list name_key_alist
[] = {
glean_key_from_name (name
)
for (i
= 0; name_key_alist
[i
].name
; i
++)
if (stricmp (name
, name_key_alist
[i
].name
) == 0)
return (name_key_alist
[i
].value
);
/* **************************************************************** */
/* String Utility Functions */
/* **************************************************************** */
/* Return non-zero if any members of ARRAY are a substring in STRING. */
substring_member_of_array (string
, array
)
static char *strindex ();
if (strindex (string
, *array
))
/* Whoops, Unix doesn't have strnicmp. */
/* Compare at most COUNT characters from string1 to string2. Case
strnicmp (string1
, string2
, count
)
if (to_upper(ch1
) == to_upper(ch2
))
/* strcmp (), but caseless. */
stricmp (string1
, string2
)
while (*string1
&& *string2
) {
if (to_upper(ch1
) != to_upper(ch2
))
return (*string1
| *string2
);
/* Determine if s2 occurs in s1. If so, return a pointer to the
match in s1. The compare is case insensitive. */
register int i
, l
= strlen (s2
);
register int len
= strlen (s1
);
for (i
= 0; (len
- i
) >= l
; i
++)
if (strnicmp (&s1
[i
], s2
, l
) == 0)
/* **************************************************************** */
/* xmalloc and xrealloc () */
/* **************************************************************** */
static memory_error_and_abort ();
char *temp
= (char *)malloc (bytes
);
memory_error_and_abort ();
xrealloc (pointer
, bytes
)
static memory_error_and_abort ();
char *temp
= (char *)realloc (pointer
, bytes
);
memory_error_and_abort ();
memory_error_and_abort ()
fprintf (stderr
, "readline: Out of virtual memory!\n");
#endif /* STATIC_MALLOC */
/* **************************************************************** */
/* **************************************************************** */
HIST_ENTRY
**history_list ();
char *temp
= (char *)NULL
;
char *prompt
= "readline% ";
temp
= readline (prompt
);
/* If there is anything on the line, print it and remember it. */
fprintf (stderr
, "%s\r\n", temp
);
/* Check for `command' that we handle. */
if (strcmp (temp
, "quit") == 0)
if (strcmp (temp
, "list") == 0) {
HIST_ENTRY
**list
= history_list ();
for (i
= 0; list
[i
]; i
++) {
fprintf (stderr
, "%d: %s\r\n", i
, list
[i
]->line
);
* compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap"