Browse Source
that the file readline.c has been split into multiple files. * bind.c, complete.c, dispay.c, isearch.c, parens.c, rldefs.h, rltty.c, search.c signals.c, tilde.c, tilde.h, xmalloc.c: New files.gdb-4_18-branch
16 changed files with 5600 additions and 4061 deletions
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,801 @@ |
|||
/* display.c -- readline redisplay facility. */ |
|||
|
|||
/* 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> |
|||
|
|||
/* System-specific feature definitions and include files. */ |
|||
#include "rldefs.h" |
|||
|
|||
/* Some standard library routines. */ |
|||
#include "readline.h" |
|||
#include "history.h" |
|||
|
|||
#if !defined (strrchr) |
|||
extern char *strrchr (); |
|||
#endif /* !strchr */ |
|||
|
|||
/* Global and pseudo-global variables and functions
|
|||
imported from readline.c. */ |
|||
extern char *rl_prompt; |
|||
extern int readline_echoing_p; |
|||
extern char *term_clreol, *term_im, *term_ic, *term_ei, *term_DC; |
|||
/* Termcap variables. */ |
|||
extern char *term_up, *term_dc, *term_cr, *term_IC; |
|||
extern int screenheight, screenwidth, terminal_can_insert; |
|||
|
|||
extern void _rl_output_some_chars (); |
|||
extern void _rl_output_character_function (); |
|||
|
|||
extern int _rl_convert_meta_chars_to_ascii; |
|||
extern int _rl_horizontal_scroll_mode; |
|||
extern int _rl_mark_modified_lines; |
|||
extern int _rl_prefer_visible_bell; |
|||
|
|||
/* Pseudo-global functions (local to the readline library) exported
|
|||
by this file. */ |
|||
void _rl_move_cursor_relative (), _rl_output_some_chars (); |
|||
void _rl_move_vert (); |
|||
|
|||
static void update_line (), clear_to_eol (); |
|||
static void delete_chars (), insert_some_chars (); |
|||
|
|||
extern char *xmalloc (), *xrealloc (); |
|||
|
|||
/* **************************************************************** */ |
|||
/* */ |
|||
/* Display stuff */ |
|||
/* */ |
|||
/* **************************************************************** */ |
|||
|
|||
/* 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 |
|||
screenwidth by one. */ |
|||
|
|||
/* 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. */ |
|||
|
|||
/* What YOU turn on when you have handled all redisplay yourself. */ |
|||
int rl_display_fixed = 0; |
|||
|
|||
/* 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; |
|||
|
|||
/* Pseudo-global variables declared here. */ |
|||
/* The visible cursor position. If you print some text, adjust this. */ |
|||
int _rl_last_c_pos = 0; |
|||
int _rl_last_v_pos = 0; |
|||
|
|||
/* Number of lines currently on screen minus 1. */ |
|||
int _rl_vis_botlin = 0; |
|||
|
|||
/* Variables used only in this file. */ |
|||
/* 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; |
|||
|
|||
/* A buffer for `modeline' messages. */ |
|||
static char msg_buf[128]; |
|||
|
|||
/* Non-zero forces the redisplay even if we thought it was unnecessary. */ |
|||
static int forced_display = 0; |
|||
|
|||
/* Default and initial buffer size. Can grow. */ |
|||
static int line_size = 1024; |
|||
|
|||
/* Basic redisplay algorithm. */ |
|||
rl_redisplay () |
|||
{ |
|||
register int in, out, c, linenum; |
|||
register char *line = invisible_line; |
|||
char *prompt_this_line; |
|||
int c_pos = 0; |
|||
int inv_botlin = 0; /* Number of lines in newly drawn buffer. */ |
|||
|
|||
if (!readline_echoing_p) |
|||
return; |
|||
|
|||
if (!rl_display_prompt) |
|||
rl_display_prompt = ""; |
|||
|
|||
if (!invisible_line) |
|||
{ |
|||
visible_line = (char *)xmalloc (line_size); |
|||
invisible_line = (char *)xmalloc (line_size); |
|||
line = invisible_line; |
|||
for (in = 0; in < line_size; in++) |
|||
{ |
|||
visible_line[in] = 0; |
|||
invisible_line[in] = 1; |
|||
} |
|||
rl_on_new_line (); |
|||
} |
|||
|
|||
/* Draw the line into the buffer. */ |
|||
c_pos = -1; |
|||
|
|||
/* Mark the line as modified or not. We only do this for history
|
|||
lines. */ |
|||
out = 0; |
|||
if (_rl_mark_modified_lines && current_history () && rl_undo_list) |
|||
{ |
|||
line[out++] = '*'; |
|||
line[out] = '\0'; |
|||
} |
|||
|
|||
/* 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 caller's misconception. */ |
|||
if (visible_line[0] != invisible_line[0]) |
|||
rl_display_fixed = 0; |
|||
|
|||
prompt_this_line = strrchr (rl_display_prompt, '\n'); |
|||
if (!prompt_this_line) |
|||
prompt_this_line = rl_display_prompt; |
|||
else |
|||
{ |
|||
prompt_this_line++; |
|||
if (forced_display) |
|||
_rl_output_some_chars |
|||
(rl_display_prompt, prompt_this_line - rl_display_prompt); |
|||
} |
|||
|
|||
strncpy (line + out, prompt_this_line, strlen (prompt_this_line)); |
|||
out += strlen (prompt_this_line); |
|||
line[out] = '\0'; |
|||
|
|||
for (in = 0; in < rl_end; in++) |
|||
{ |
|||
c = (unsigned char)rl_line_buffer[in]; |
|||
|
|||
if (out + 8 >= line_size) /* XXX - 8 for \t */ |
|||
{ |
|||
line_size *= 2; |
|||
visible_line = (char *)xrealloc (visible_line, line_size); |
|||
invisible_line = (char *)xrealloc (invisible_line, line_size); |
|||
line = invisible_line; |
|||
} |
|||
|
|||
if (in == rl_point) |
|||
c_pos = out; |
|||
|
|||
if (META_CHAR (c)) |
|||
{ |
|||
if (_rl_convert_meta_chars_to_ascii) |
|||
{ |
|||
sprintf (line + out, "\\%o", c); |
|||
out += 4; |
|||
} |
|||
else |
|||
line[out++] = c; |
|||
} |
|||
#define DISPLAY_TABS |
|||
#if defined (DISPLAY_TABS) |
|||
else if (c == '\t') |
|||
{ |
|||
register int newout = (out | (int)7) + 1; |
|||
while (out < newout) |
|||
line[out++] = ' '; |
|||
} |
|||
#endif |
|||
else if (c < ' ') |
|||
{ |
|||
line[out++] = '^'; |
|||
line[out++] = UNCTRL (c); /* XXX was c ^ 0x40 */ |
|||
} |
|||
else if (c == 127) |
|||
{ |
|||
line[out++] = '^'; |
|||
line[out++] = '?'; |
|||
} |
|||
else |
|||
line[out++] = c; |
|||
} |
|||
line[out] = '\0'; |
|||
if (c_pos < 0) |
|||
c_pos = out; |
|||
|
|||
/* 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 (!_rl_horizontal_scroll_mode && term_up && *term_up) |
|||
{ |
|||
int total_screen_chars = (screenwidth * screenheight); |
|||
|
|||
if (!rl_display_fixed || forced_display) |
|||
{ |
|||
forced_display = 0; |
|||
|
|||
/* 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 > _rl_vis_botlin ? "" |
|||
: &visible_line[linenum * screenwidth], |
|||
&invisible_line[linenum * screenwidth], |
|||
linenum); |
|||
|
|||
/* We may have deleted some lines. If so, clear the left over
|
|||
blank ones at the bottom out. */ |
|||
if (_rl_vis_botlin > inv_botlin) |
|||
{ |
|||
char *tt; |
|||
for (; linenum <= _rl_vis_botlin; linenum++) |
|||
{ |
|||
tt = &visible_line[linenum * screenwidth]; |
|||
_rl_move_vert (linenum); |
|||
_rl_move_cursor_relative (0, tt); |
|||
clear_to_eol |
|||
((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth); |
|||
} |
|||
} |
|||
_rl_vis_botlin = inv_botlin; |
|||
|
|||
/* Move the cursor where it should be. */ |
|||
_rl_move_vert (c_pos / screenwidth); |
|||
_rl_move_cursor_relative (c_pos % screenwidth, |
|||
&invisible_line[(c_pos / screenwidth) * screenwidth]); |
|||
} |
|||
} |
|||
else /* Do horizontal scrolling. */ |
|||
{ |
|||
int lmargin; |
|||
|
|||
/* Always at top line. */ |
|||
_rl_last_v_pos = 0; |
|||
|
|||
/* 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); |
|||
else |
|||
lmargin = last_lmargin; |
|||
|
|||
/* If the first character on the screen isn't the first character
|
|||
in the display line, indicate this with a special character. */ |
|||
if (lmargin > 0) |
|||
line[lmargin] = '<'; |
|||
|
|||
if (lmargin + screenwidth < out) |
|||
line[lmargin + screenwidth - 1] = '>'; |
|||
|
|||
if (!rl_display_fixed || forced_display || lmargin != last_lmargin) |
|||
{ |
|||
forced_display = 0; |
|||
update_line (&visible_line[last_lmargin], |
|||
&invisible_line[lmargin], 0); |
|||
|
|||
_rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); |
|||
last_lmargin = lmargin; |
|||
} |
|||
} |
|||
fflush (rl_outstream); |
|||
|
|||
/* Swap visible and non-visible lines. */ |
|||
{ |
|||
char *temp = visible_line; |
|||
visible_line = invisible_line; |
|||
invisible_line = temp; |
|||
rl_display_fixed = 0; |
|||
} |
|||
} |
|||
|
|||
/* PWP: update_line() is based on finding the middle difference of each
|
|||
line on the screen; vis: |
|||
|
|||
/old first difference |
|||
/beginning of line | /old last same /old EOL |
|||
v v v v |
|||
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 |
|||
\new first difference |
|||
|
|||
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 */ |
|||
static void |
|||
update_line (old, new, current_line) |
|||
register char *old, *new; |
|||
int current_line; |
|||
{ |
|||
register char *ofd, *ols, *oe, *nfd, *nls, *ne; |
|||
int lendiff, wsatend; |
|||
|
|||
/* Find first difference. */ |
|||
for (ofd = old, nfd = new; |
|||
(ofd - old < screenwidth) && *ofd && (*ofd == *nfd); |
|||
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) |
|||
return; |
|||
|
|||
wsatend = 1; /* flag for trailing whitespace */ |
|||
ols = oe - 1; /* find last same */ |
|||
nls = ne - 1; |
|||
while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) |
|||
{ |
|||
if (*ols != ' ') |
|||
wsatend = 0; |
|||
ols--; |
|||
nls--; |
|||
} |
|||
|
|||
if (wsatend) |
|||
{ |
|||
ols = oe; |
|||
nls = ne; |
|||
} |
|||
else if (*ols != *nls) |
|||
{ |
|||
if (*ols) /* don't step past the NUL */ |
|||
ols++; |
|||
if (*nls) |
|||
nls++; |
|||
} |
|||
|
|||
_rl_move_vert (current_line); |
|||
_rl_move_cursor_relative (ofd - old, old); |
|||
|
|||
/* if (len (new) > len (old)) */ |
|||
lendiff = (nls - nfd) - (ols - ofd); |
|||
|
|||
/* Insert (diff (len (old), len (new)) ch. */ |
|||
if (lendiff > 0) |
|||
{ |
|||
if (terminal_can_insert) |
|||
{ |
|||
/* Sometimes it is cheaper to print the characters rather than
|
|||
use the terminal's capabilities. */ |
|||
if ((2 * (ne - nfd)) < lendiff && !term_IC) |
|||
{ |
|||
_rl_output_some_chars (nfd, (ne - nfd)); |
|||
_rl_last_c_pos += (ne - nfd); |
|||
} |
|||
else |
|||
{ |
|||
if (*ols) |
|||
{ |
|||
insert_some_chars (nfd, lendiff); |
|||
_rl_last_c_pos += lendiff; |
|||
} |
|||
else |
|||
{ |
|||
/* At the end of a line the characters do not have to
|
|||
be "inserted". They can just be placed on the screen. */ |
|||
_rl_output_some_chars (nfd, lendiff); |
|||
_rl_last_c_pos += lendiff; |
|||
} |
|||
/* Copy (new) chars to screen from first diff to last match. */ |
|||
if (((nls - nfd) - lendiff) > 0) |
|||
{ |
|||
_rl_output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff)); |
|||
_rl_last_c_pos += ((nls - nfd) - lendiff); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ /* cannot insert chars, write to EOL */ |
|||
_rl_output_some_chars (nfd, (ne - nfd)); |
|||
_rl_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)) |
|||
{ |
|||
if (lendiff) |
|||
delete_chars (-lendiff); /* delete (diff) characters */ |
|||
|
|||
/* Copy (new) chars to screen from first diff to last match */ |
|||
if ((nls - nfd) > 0) |
|||
{ |
|||
_rl_output_some_chars (nfd, (nls - nfd)); |
|||
_rl_last_c_pos += (nls - nfd); |
|||
} |
|||
} |
|||
/* Otherwise, print over the existing material. */ |
|||
else |
|||
{ |
|||
_rl_output_some_chars (nfd, (ne - nfd)); |
|||
_rl_last_c_pos += (ne - nfd); |
|||
clear_to_eol ((oe - old) - (ne - new)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* Tell the update routines that we have moved onto a new (empty) line. */ |
|||
rl_on_new_line () |
|||
{ |
|||
if (visible_line) |
|||
visible_line[0] = '\0'; |
|||
|
|||
_rl_last_c_pos = _rl_last_v_pos = 0; |
|||
_rl_vis_botlin = last_lmargin = 0; |
|||
} |
|||
|
|||
/* Actually update the display, period. */ |
|||
rl_forced_update_display () |
|||
{ |
|||
if (visible_line) |
|||
{ |
|||
register char *temp = visible_line; |
|||
|
|||
while (*temp) *temp++ = '\0'; |
|||
} |
|||
rl_on_new_line (); |
|||
forced_display++; |
|||
rl_redisplay (); |
|||
} |
|||
|
|||
/* Move the cursor from _rl_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. */ |
|||
void |
|||
_rl_move_cursor_relative (new, data) |
|||
int new; |
|||
char *data; |
|||
{ |
|||
register int i; |
|||
|
|||
/* It may be faster to output a CR, and then move forwards instead
|
|||
of moving backwards. */ |
|||
if (new + 1 < _rl_last_c_pos - new) |
|||
{ |
|||
#ifdef __MSDOS__ |
|||
putc('\r', rl_outstream); |
|||
#else |
|||
tputs (term_cr, 1, _rl_output_character_function); |
|||
#endif |
|||
_rl_last_c_pos = 0; |
|||
} |
|||
|
|||
if (_rl_last_c_pos == new) return; |
|||
|
|||
if (_rl_last_c_pos < new) |
|||
{ |
|||
/* 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. */ |
|||
#if defined (HACK_TERMCAP_MOTION) |
|||
extern char *term_forward_char; |
|||
|
|||
if (term_forward_char) |
|||
for (i = _rl_last_c_pos; i < new; i++) |
|||
tputs (term_forward_char, 1, _rl_output_character_function); |
|||
else |
|||
for (i = _rl_last_c_pos; i < new; i++) |
|||
putc (data[i], rl_outstream); |
|||
#else |
|||
for (i = _rl_last_c_pos; i < new; i++) |
|||
putc (data[i], rl_outstream); |
|||
#endif /* HACK_TERMCAP_MOTION */ |
|||
} |
|||
else |
|||
backspace (_rl_last_c_pos - new); |
|||
_rl_last_c_pos = new; |
|||
} |
|||
|
|||
/* PWP: move the cursor up or down. */ |
|||
void |
|||
_rl_move_vert (to) |
|||
int to; |
|||
{ |
|||
register int delta, i; |
|||
|
|||
if (_rl_last_v_pos == to || to > screenheight) |
|||
return; |
|||
|
|||
#ifdef __GO32__ |
|||
{ |
|||
int row, col; |
|||
ScreenGetCursor (&row, &col); |
|||
ScreenSetCursor ((row + to - _rl_last_v_pos), col); |
|||
} |
|||
#else /* __GO32__ */ |
|||
if ((delta = to - _rl_last_v_pos) > 0) |
|||
{ |
|||
for (i = 0; i < delta; i++) |
|||
putc ('\n', rl_outstream); |
|||
tputs (term_cr, 1, _rl_output_character_function); |
|||
_rl_last_c_pos = 0; |
|||
} |
|||
else |
|||
{ /* delta < 0 */ |
|||
if (term_up && *term_up) |
|||
for (i = 0; i < -delta; i++) |
|||
tputs (term_up, 1, _rl_output_character_function); |
|||
} |
|||
#endif /* !__GO32__ */ |
|||
_rl_last_v_pos = to; /* Now TO is here */ |
|||
} |
|||
|
|||
/* Physically print C on rl_outstream. This is for functions which know
|
|||
how to optimize the display. */ |
|||
rl_show_char (c) |
|||
int c; |
|||
{ |
|||
if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii) |
|||
{ |
|||
fprintf (rl_outstream, "M-"); |
|||
c = UNMETA (c); |
|||
} |
|||
|
|||
#if defined (DISPLAY_TABS) |
|||
if (c < 32 && c != '\t') |
|||
#else |
|||
if (c < 32) |
|||
#endif /* !DISPLAY_TABS */ |
|||
{ |
|||
|
|||
c += 64; |
|||
} |
|||
|
|||
putc (c, rl_outstream); |
|||
fflush (rl_outstream); |
|||
} |
|||
|
|||
int |
|||
rl_character_len (c, pos) |
|||
register int c, pos; |
|||
{ |
|||
if (META_CHAR (c)) |
|||
return (_rl_convert_meta_chars_to_ascii ? 4 : 1); |
|||
|
|||
if (c == '\t') |
|||
{ |
|||
#if defined (DISPLAY_TABS) |
|||
return (((pos | (int)7) + 1) - pos); |
|||
#else |
|||
return (2); |
|||
#endif /* !DISPLAY_TABS */ |
|||
} |
|||
|
|||
if (isprint (c)) |
|||
return (1); |
|||
else |
|||
return (2); |
|||
} |
|||
|
|||
/* How to print things in the "echo-area". The prompt is treated as a
|
|||
mini-modeline. */ |
|||
|
|||
#if defined (HAVE_VARARGS_H) |
|||
rl_message (va_alist) |
|||
va_dcl |
|||
{ |
|||
char *format; |
|||
va_list args; |
|||
|
|||
va_start (args); |
|||
format = va_arg (args, char *); |
|||
vsprintf (msg_buf, format, args); |
|||
va_end (args); |
|||
|
|||
rl_display_prompt = msg_buf; |
|||
rl_redisplay (); |
|||
} |
|||
#else /* !HAVE_VARARGS_H */ |
|||
rl_message (format, arg1, arg2) |
|||
char *format; |
|||
{ |
|||
sprintf (msg_buf, format, arg1, arg2); |
|||
rl_display_prompt = msg_buf; |
|||
rl_redisplay (); |
|||
} |
|||
#endif /* !HAVE_VARARGS_H */ |
|||
|
|||
/* How to clear things from the "echo-area". */ |
|||
rl_clear_message () |
|||
{ |
|||
rl_display_prompt = rl_prompt; |
|||
rl_redisplay (); |
|||
} |
|||
|
|||
rl_reset_line_state () |
|||
{ |
|||
rl_on_new_line (); |
|||
|
|||
rl_display_prompt = rl_prompt ? rl_prompt : ""; |
|||
forced_display = 1; |
|||
} |
|||
|
|||
/* Quick redisplay hack when erasing characters at the end of the line. */ |
|||
void |
|||
_rl_erase_at_end_of_line (l) |
|||
int l; |
|||
{ |
|||
register int i; |
|||
|
|||
backspace (l); |
|||
for (i = 0; i < l; i++) |
|||
putc (' ', rl_outstream); |
|||
backspace (l); |
|||
for (i = 0; i < l; i++) |
|||
visible_line[--_rl_last_c_pos] = '\0'; |
|||
rl_display_fixed++; |
|||
} |
|||
|
|||
/* Clear to the end of the line. COUNT is the minimum
|
|||
number of character spaces to clear, */ |
|||
static void |
|||
clear_to_eol (count) |
|||
int count; |
|||
{ |
|||
#ifndef __GO32__ |
|||
if (term_clreol) |
|||
{ |
|||
tputs (term_clreol, 1, _rl_output_character_function); |
|||
} |
|||
else |
|||
#endif /* !__GO32__ */ |
|||
{ |
|||
register int i; |
|||
|
|||
/* Do one more character space. */ |
|||
count++; |
|||
|
|||
for (i = 0; i < count; i++) |
|||
putc (' ', rl_outstream); |
|||
|
|||
backspace (count); |
|||
} |
|||
} |
|||
/* Insert COUNT characters from STRING to the output stream. */ |
|||
static void |
|||
insert_some_chars (string, count) |
|||
char *string; |
|||
int count; |
|||
{ |
|||
#ifdef __GO32__ |
|||
int row, col, width; |
|||
char *row_start; |
|||
|
|||
ScreenGetCursor (&row, &col); |
|||
width = ScreenCols (); |
|||
row_start = ScreenPrimary + (row * width); |
|||
memcpy (row_start + col + count, row_start + col, width - col - count); |
|||
/* Place the text on the screen. */ |
|||
_rl_output_some_chars (string, count); |
|||
#else /* __GO32__ */ |
|||
/* If IC is defined, then we do not have to "enter" insert mode. */ |
|||
if (term_IC) |
|||
{ |
|||
char *tgoto (), *buffer; |
|||
buffer = tgoto (term_IC, 0, count); |
|||
tputs (buffer, 1, _rl_output_character_function); |
|||
_rl_output_some_chars (string, count); |
|||
} |
|||
else |
|||
{ |
|||
register int i; |
|||
|
|||
/* If we have to turn on insert-mode, then do so. */ |
|||
if (term_im && *term_im) |
|||
tputs (term_im, 1, _rl_output_character_function); |
|||
|
|||
/* If there is a special command for inserting characters, then
|
|||
use that first to open up the space. */ |
|||
if (term_ic && *term_ic) |
|||
{ |
|||
for (i = count; i--; ) |
|||
tputs (term_ic, 1, _rl_output_character_function); |
|||
} |
|||
|
|||
/* Print the text. */ |
|||
_rl_output_some_chars (string, count); |
|||
|
|||
/* If there is a string to turn off insert mode, we had best use
|
|||
it now. */ |
|||
if (term_ei && *term_ei) |
|||
tputs (term_ei, 1, _rl_output_character_function); |
|||
} |
|||
#endif /* __GO32__ */ |
|||
} |
|||
|
|||
/* Delete COUNT characters from the display line. */ |
|||
static void |
|||
delete_chars (count) |
|||
int count; |
|||
{ |
|||
#if defined (__GO32__) |
|||
int row, col, width; |
|||
char *row_start; |
|||
|
|||
ScreenGetCursor (&row, &col); |
|||
width = ScreenCols (); |
|||
row_start = ScreenPrimary + (row * width); |
|||
memcpy (row_start + col, row_start + col + count, width - col - count); |
|||
memset (row_start + width - count, 0, count * 2); |
|||
#else /* !__GO32__ */ |
|||
if (count > screenwidth) |
|||
return; |
|||
|
|||
if (term_DC && *term_DC) |
|||
{ |
|||
char *tgoto (), *buffer; |
|||
buffer = tgoto (term_DC, 0, count); |
|||
tputs (buffer, 1, _rl_output_character_function); |
|||
} |
|||
else |
|||
{ |
|||
if (term_dc && *term_dc) |
|||
while (count--) |
|||
tputs (term_dc, 1, _rl_output_character_function); |
|||
} |
|||
#endif /* !__GO32__ */ |
|||
} |
|||
@ -0,0 +1,378 @@ |
|||
/* **************************************************************** */ |
|||
/* */ |
|||
/* I-Search and Searching */ |
|||
/* */ |
|||
/* **************************************************************** */ |
|||
|
|||
/* 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 |
|||
for it. |
|||
|
|||
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) |
|||
any later version. |
|||
|
|||
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. */ |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#if defined (__GNUC__) |
|||
# define alloca __builtin_alloca |
|||
#else |
|||
# if defined (sparc) || defined (HAVE_ALLOCA_H) |
|||
# include <alloca.h> |
|||
# endif |
|||
#endif |
|||
|
|||
#include "readline.h" |
|||
#include "history.h" |
|||
|
|||
extern Keymap _rl_keymap; |
|||
extern HIST_ENTRY *saved_line_for_history; |
|||
extern int rl_line_buffer_len; |
|||
extern int rl_point, rl_end; |
|||
extern char *rl_prompt, *rl_line_buffer; |
|||
|
|||
/* Remove these declarations when we have a complete libgnu.a. */ |
|||
extern char *xmalloc (), *xrealloc (); |
|||
|
|||
static void rl_search_history (); |
|||
|
|||
/* Search backwards through the history looking for a string which is typed
|
|||
interactively. Start with the current line. */ |
|||
rl_reverse_search_history (sign, key) |
|||
int sign; |
|||
int 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) |
|||
int sign; |
|||
int 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. */ |
|||
static void |
|||
rl_display_search (search_string, reverse_p, where) |
|||
char *search_string; |
|||
int reverse_p, where; |
|||
{ |
|||
char *message = (char *)NULL; |
|||
|
|||
message = |
|||
(char *)xmalloc (1 + (search_string ? strlen (search_string) : 0) + 30); |
|||
|
|||
*message = '\0'; |
|||
|
|||
#if defined (NOTDEF) |
|||
if (where != -1) |
|||
sprintf (message, "[%d]", where + history_base); |
|||
#endif /* NOTDEF */ |
|||
|
|||
strcat (message, "("); |
|||
|
|||
if (reverse_p) |
|||
strcat (message, "reverse-"); |
|||
|
|||
strcat (message, "i-search)`"); |
|||
|
|||
if (search_string) |
|||
strcat (message, search_string); |
|||
|
|||
strcat (message, "': "); |
|||
rl_message ("%s", message, 0); |
|||
free (message); |
|||
rl_redisplay (); |
|||
} |
|||
|
|||
/* 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 |
|||
backwards. */ |
|||
static void |
|||
rl_search_history (direction, invoking_key) |
|||
int direction; |
|||
int invoking_key; |
|||
{ |
|||
/* The string that the user types in to search for. */ |
|||
char *search_string; |
|||
|
|||
/* The current length of SEARCH_STRING. */ |
|||
int search_string_index; |
|||
|
|||
/* The amount of space that SEARCH_STRING has allocated to it. */ |
|||
int search_string_size; |
|||
|
|||
/* The list of lines to search through. */ |
|||
char **lines; |
|||
|
|||
/* The length of LINES. */ |
|||
int hlen; |
|||
|
|||
/* Where we get LINES from. */ |
|||
HIST_ENTRY **hlist = history_list (); |
|||
|
|||
register int i = 0; |
|||
int orig_point = rl_point; |
|||
int orig_line = where_history (); |
|||
int last_found_line = orig_line; |
|||
int c, done = 0; |
|||
|
|||
/* The line currently being searched. */ |
|||
char *sline; |
|||
|
|||
/* Offset in that line. */ |
|||
int index; |
|||
|
|||
/* 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. */ |
|||
maybe_replace_line (); |
|||
if (hlist) |
|||
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; |
|||
else |
|||
/* So I have to type it in this way instead. */ |
|||
{ |
|||
char *alloced_line; |
|||
|
|||
/* Keep that MIPS alloca () happy. */ |
|||
alloced_line = (char *)alloca (1 + strlen (rl_line_buffer)); |
|||
lines[i] = alloced_line; |
|||
strcpy (lines[i], &rl_line_buffer[0]); |
|||
} |
|||
|
|||
hlen++; |
|||
|
|||
/* The line where we start the search. */ |
|||
i = orig_line; |
|||
|
|||
/* Initialize search parameters. */ |
|||
search_string = (char *)xmalloc (search_string_size = 128); |
|||
*search_string = '\0'; |
|||
search_string_index = 0; |
|||
|
|||
/* Normalize DIRECTION into 1 or -1. */ |
|||
if (direction >= 0) |
|||
direction = 1; |
|||
else |
|||
direction = -1; |
|||
|
|||
rl_display_search (search_string, reverse, -1); |
|||
|
|||
sline = rl_line_buffer; |
|||
index = rl_point; |
|||
|
|||
while (!done) |
|||
{ |
|||
c = rl_read_key (); |
|||
|
|||
/* Hack C to Do What I Mean. */ |
|||
{ |
|||
Function *f = (Function *)NULL; |
|||
|
|||
if (_rl_keymap[c].type == ISFUNC) |
|||
{ |
|||
f = _rl_keymap[c].function; |
|||
|
|||
if (f == rl_reverse_search_history) |
|||
c = reverse ? -1 : -2; |
|||
else if (f == rl_forward_search_history) |
|||
c = !reverse ? -1 : -2; |
|||
} |
|||
} |
|||
|
|||
switch (c) |
|||
{ |
|||
case ESC: |
|||
done = 1; |
|||
continue; |
|||
|
|||
/* case invoking_key: */ |
|||
case -1: |
|||
goto search_again; |
|||
|
|||
/* switch directions */ |
|||
case -2: |
|||
direction = -direction; |
|||
reverse = (direction < 0); |
|||
|
|||
goto do_search; |
|||
|
|||
case CTRL ('G'): |
|||
strcpy (rl_line_buffer, lines[orig_line]); |
|||
rl_point = orig_point; |
|||
rl_end = strlen (rl_line_buffer); |
|||
rl_clear_message (); |
|||
return; |
|||
|
|||
default: |
|||
if (c < 32 || c > 126) |
|||
{ |
|||
rl_execute_next (c); |
|||
done = 1; |
|||
continue; |
|||
} |
|||
else |
|||
{ |
|||
if (search_string_index + 2 >= search_string_size) |
|||
search_string = (char *)xrealloc |
|||
(search_string, (search_string_size += 128)); |
|||
search_string[search_string_index++] = c; |
|||
search_string[search_string_index] = '\0'; |
|||
goto do_search; |
|||
|
|||
search_again: |
|||
|
|||
if (!search_string_index) |
|||
continue; |
|||
else |
|||
{ |
|||
if (reverse) |
|||
--index; |
|||
else |
|||
if (index != strlen (sline)) |
|||
++index; |
|||
else |
|||
ding (); |
|||
} |
|||
do_search: |
|||
|
|||
while (1) |
|||
{ |
|||
if (reverse) |
|||
{ |
|||
while (index >= 0) |
|||
if (strncmp |
|||
(search_string, sline + index, search_string_index) |
|||
== 0) |
|||
goto string_found; |
|||
else |
|||
index--; |
|||
} |
|||
else |
|||
{ |
|||
register int limit = |
|||
(strlen (sline) - search_string_index) + 1; |
|||
|
|||
while (index < limit) |
|||
{ |
|||
if (strncmp (search_string, |
|||
sline + index, |
|||
search_string_index) == 0) |
|||
goto string_found; |
|||
index++; |
|||
} |
|||
} |
|||
|
|||
next_line: |
|||
i += direction; |
|||
|
|||
/* At limit for direction? */ |
|||
if ((reverse && i < 0) || |
|||
(!reverse && i == hlen)) |
|||
goto search_failed; |
|||
|
|||
sline = lines[i]; |
|||
if (reverse) |
|||
index = strlen (sline); |
|||
else |
|||
index = 0; |
|||
|
|||
/* If the search string is longer than the current
|
|||
line, no match. */ |
|||
if (search_string_index > (int)strlen (sline)) |
|||
goto next_line; |
|||
|
|||
/* Start actually searching. */ |
|||
if (reverse) |
|||
index -= search_string_index; |
|||
} |
|||
|
|||
search_failed: |
|||
/* We cannot find the search string. Ding the bell. */ |
|||
ding (); |
|||
i = last_found_line; |
|||
break; |
|||
|
|||
string_found: |
|||
/* We have found the search string. Just display it. But don't
|
|||
actually move there in the history list until the user accepts |
|||
the location. */ |
|||
{ |
|||
int line_len; |
|||
|
|||
line_len = strlen (lines[i]); |
|||
|
|||
if (line_len >= rl_line_buffer_len) |
|||
rl_extend_line_buffer (line_len); |
|||
|
|||
strcpy (rl_line_buffer, lines[i]); |
|||
rl_point = index; |
|||
rl_end = line_len; |
|||
last_found_line = i; |
|||
rl_display_search |
|||
(search_string, reverse, (i == orig_line) ? -1 : i); |
|||
} |
|||
} |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
/* The searching is over. The user may have found the string that she
|
|||
was looking for, or else she may have exited a failing search. If |
|||
INDEX is -1, then that shows that the string searched for was not |
|||
found. We use this to determine where to place rl_point. */ |
|||
{ |
|||
int now = last_found_line; |
|||
|
|||
/* First put back the original state. */ |
|||
strcpy (rl_line_buffer, lines[orig_line]); |
|||
|
|||
/* Free the search string. */ |
|||
free (search_string); |
|||
|
|||
if (now < orig_line) |
|||
rl_get_previous_history (orig_line - now); |
|||
else |
|||
rl_get_next_history (now - orig_line); |
|||
|
|||
/* If the index of the "matched" string is less than zero, then the
|
|||
final search string was never matched, so put point somewhere |
|||
reasonable. */ |
|||
if (index < 0) |
|||
index = strlen (rl_line_buffer); |
|||
|
|||
rl_point = index; |
|||
rl_clear_message (); |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
/* parens.c -- Implemenation of matching parenthesis feature. */ |
|||
|
|||
/* 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 <sys/time.h> |
|||
#include "readline.h" |
|||
|
|||
/* Non-zero means try to blink the matching open parenthesis when the
|
|||
close parenthesis is inserted. */ |
|||
#if defined (FD_SET) |
|||
int rl_blink_matching_paren = 1; |
|||
#else /* !FD_SET */ |
|||
int rl_blink_matching_paren = 0; |
|||
#endif /* !FD_SET */ |
|||
|
|||
static int find_matching_open (); |
|||
|
|||
rl_insert_close (count, invoking_key) |
|||
int count, invoking_key; |
|||
{ |
|||
extern int rl_explicit_arg; |
|||
|
|||
if (rl_explicit_arg || !rl_blink_matching_paren) |
|||
rl_insert (count, invoking_key); |
|||
else |
|||
{ |
|||
#if defined (FD_SET) |
|||
int orig_point, match_point, ready; |
|||
struct timeval timer; |
|||
fd_set readfds; |
|||
|
|||
rl_insert (1, invoking_key); |
|||
rl_redisplay (); |
|||
match_point = |
|||
find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); |
|||
|
|||
/* Emacs might message or ring the bell here, but I don't. */ |
|||
if (match_point < 0) |
|||
return; |
|||
|
|||
FD_ZERO (&readfds); |
|||
FD_SET (fileno (rl_instream), &readfds); |
|||
timer.tv_sec = 1; |
|||
timer.tv_usec = 500; |
|||
|
|||
orig_point = rl_point; |
|||
rl_point = match_point; |
|||
rl_redisplay (); |
|||
ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); |
|||
rl_point = orig_point; |
|||
#else /* !FD_SET */ |
|||
rl_insert (count, invoking_key); |
|||
#endif /* !FD_SET */ |
|||
} |
|||
} |
|||
|
|||
static int |
|||
find_matching_open (string, from, closer) |
|||
char *string; |
|||
int from, closer; |
|||
{ |
|||
register int i; |
|||
int opener, level, delimiter; |
|||
|
|||
switch (closer) |
|||
{ |
|||
case ']': opener = '['; break; |
|||
case '}': opener = '{'; break; |
|||
case ')': opener = '('; break; |
|||
default: |
|||
return (-1); |
|||
} |
|||
|
|||
level = 1; /* The closer passed in counts as 1. */ |
|||
delimiter = 0; /* Delimited state unknown. */ |
|||
|
|||
for (i = from; i > -1; i--) |
|||
{ |
|||
if (delimiter && (string[i] == delimiter)) |
|||
delimiter = 0; |
|||
else if ((string[i] == '\'') || (string[i] == '"')) |
|||
delimiter = rl_line_buffer[i]; |
|||
else if (!delimiter && (string[i] == closer)) |
|||
level++; |
|||
else if (!delimiter && (string[i] == opener)) |
|||
level--; |
|||
|
|||
if (!level) |
|||
break; |
|||
} |
|||
return (i); |
|||
} |
|||
|
|||
|
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,250 @@ |
|||
/* rldefs.h -- an attempt to isolate some of the system-specific defines
|
|||
for readline. This should be included after any files that define |
|||
system-specific constants like _POSIX_VERSION or USG. */ |
|||
|
|||
/* 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 |
|||
for it. |
|||
|
|||
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) |
|||
any later version. |
|||
|
|||
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. */ |
|||
|
|||
#if !defined (_RLDEFS_H) |
|||
#define _RLDEFS_H |
|||
|
|||
#if defined (__GNUC__) |
|||
# undef alloca |
|||
# define alloca __builtin_alloca |
|||
#else |
|||
# if defined (sparc) || defined (HAVE_ALLOCA_H) |
|||
# include <alloca.h> |
|||
# endif |
|||
#endif |
|||
|
|||
#define NEW_TTY_DRIVER |
|||
#define HAVE_BSD_SIGNALS |
|||
/* #define USE_XON_XOFF */ |
|||
|
|||
#ifdef __MSDOS__ |
|||
#undef NEW_TTY_DRIVER |
|||
#undef HAVE_BSD_SIGNALS |
|||
#endif |
|||
|
|||
#if defined (__linux__) |
|||
# include <termcap.h> |
|||
#endif /* __linux__ */ |
|||
|
|||
/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */ |
|||
#if defined (USG) && !defined (hpux) |
|||
# undef HAVE_BSD_SIGNALS |
|||
#endif |
|||
|
|||
/* System V machines use termio. */ |
|||
#if !defined (_POSIX_VERSION) |
|||
# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) |
|||
# undef NEW_TTY_DRIVER |
|||
# define TERMIO_TTY_DRIVER |
|||
# include <termio.h> |
|||
# if !defined (TCOON) |
|||
# define TCOON 1 |
|||
# endif |
|||
# endif /* USG || hpux || Xenix || sgi || DUGX */ |
|||
#endif /* !_POSIX_VERSION */ |
|||
|
|||
/* Posix systems use termios and the Posix signal functions. */ |
|||
#if defined (_POSIX_VERSION) |
|||
# if !defined (TERMIOS_MISSING) |
|||
# undef NEW_TTY_DRIVER |
|||
# define TERMIOS_TTY_DRIVER |
|||
# include <termios.h> |
|||
# endif /* !TERMIOS_MISSING */ |
|||
# define HAVE_POSIX_SIGNALS |
|||
# if !defined (O_NDELAY) |
|||
# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ |
|||
# endif /* O_NDELAY */ |
|||
#endif /* _POSIX_VERSION */ |
|||
|
|||
/* System V.3 machines have the old 4.1 BSD `reliable' signal interface. */ |
|||
#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) |
|||
# if defined (USGr3) |
|||
# if !defined (HAVE_USG_SIGHOLD) |
|||
# define HAVE_USG_SIGHOLD |
|||
# endif /* !HAVE_USG_SIGHOLD */ |
|||
# endif /* USGr3 */ |
|||
#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ |
|||
|
|||
/* Other (BSD) machines use sgtty. */ |
|||
#if defined (NEW_TTY_DRIVER) |
|||
# include <sgtty.h> |
|||
#endif |
|||
|
|||
/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
|
|||
it is not already defined. It is used both to determine if a |
|||
special character is disabled and to disable certain special |
|||
characters. Posix systems should set to 0, USG systems to -1. */ |
|||
#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) |
|||
# if defined (_POSIX_VERSION) |
|||
# define _POSIX_VDISABLE 0 |
|||
# else /* !_POSIX_VERSION */ |
|||
# define _POSIX_VDISABLE -1 |
|||
# endif /* !_POSIX_VERSION */ |
|||
#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ |
|||
|
|||
#if 1 |
|||
# define D_NAMLEN(d) strlen ((d)->d_name) |
|||
#else /* !1 */ |
|||
|
|||
#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) |
|||
# if !defined (HAVE_DIRENT_H) |
|||
# define HAVE_DIRENT_H |
|||
# endif /* !HAVE_DIRENT_H */ |
|||
#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ |
|||
|
|||
#if defined (HAVE_DIRENT_H) |
|||
# include <dirent.h> |
|||
# if !defined (direct) |
|||
# define direct dirent |
|||
# endif /* !direct */ |
|||
# define D_NAMLEN(d) strlen ((d)->d_name) |
|||
#else /* !HAVE_DIRENT_H */ |
|||
# define D_NAMLEN(d) ((d)->d_namlen) |
|||
# if defined (USG) |
|||
# if defined (Xenix) |
|||
# include <sys/ndir.h> |
|||
# else /* !Xenix (but USG...) */ |
|||
# include "ndir.h" |
|||
# endif /* !Xenix */ |
|||
# else /* !USG */ |
|||
# include <sys/dir.h> |
|||
# endif /* !USG */ |
|||
#endif /* !HAVE_DIRENT_H */ |
|||
#endif /* !1 */ |
|||
|
|||
#if defined (USG) && defined (TIOCGWINSZ) && !defined (Linux) |
|||
# include <sys/stream.h> |
|||
# if defined (HAVE_SYS_PTEM_H) |
|||
# include <sys/ptem.h> |
|||
# endif /* HAVE_SYS_PTEM_H */ |
|||
# if defined (HAVE_SYS_PTE_H) |
|||
# include <sys/pte.h> |
|||
# endif /* HAVE_SYS_PTE_H */ |
|||
#endif /* USG && TIOCGWINSZ && !Linux */ |
|||
|
|||
/* Posix macro to check file in statbuf for directory-ness.
|
|||
This requires that <sys/stat.h> be included before this test. */ |
|||
#if defined (S_IFDIR) && !defined (S_ISDIR) |
|||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) |
|||
#endif |
|||
|
|||
/* Decide which flavor of the header file describing the C library
|
|||
string functions to include and include it. */ |
|||
|
|||
#if defined (USG) || defined (NeXT) |
|||
# if !defined (HAVE_STRING_H) |
|||
# define HAVE_STRING_H |
|||
# endif /* !HAVE_STRING_H */ |
|||
#endif /* USG || NeXT */ |
|||
|
|||
#if defined (HAVE_STRING_H) |
|||
# include <string.h> |
|||
#else /* !HAVE_STRING_H */ |
|||
# include <strings.h> |
|||
#endif /* !HAVE_STRING_H */ |
|||
|
|||
#if !defined (strchr) && !defined (__STDC__) |
|||
extern char *strchr (), *strrchr (); |
|||
#endif /* !strchr && !__STDC__ */ |
|||
|
|||
#if defined (HAVE_VARARGS_H) |
|||
# include <varargs.h> |
|||
#endif /* HAVE_VARARGS_H */ |
|||
|
|||
/* This definition is needed by readline.c, rltty.c, and signals.c. */ |
|||
/* If on, then readline handles signals in a way that doesn't screw. */ |
|||
#define HANDLE_SIGNALS |
|||
|
|||
#if !defined (emacs_mode) |
|||
# define no_mode -1 |
|||
# define vi_mode 0 |
|||
# define emacs_mode 1 |
|||
#endif |
|||
|
|||
/* Define some macros for dealing with assorted signalling disciplines.
|
|||
|
|||
These macros provide a way to use signal blocking and disabling |
|||
without smothering your code in a pile of #ifdef's. |
|||
|
|||
SIGNALS_UNBLOCK; Stop blocking all signals. |
|||
|
|||
{ |
|||
SIGNALS_DECLARE_SAVED (name); Declare a variable to save the |
|||
signal blocking state. |
|||
... |
|||
SIGNALS_BLOCK (SIGSTOP, name); Block a signal, and save the previous |
|||
state for restoration later. |
|||
... |
|||
SIGNALS_RESTORE (name); Restore previous signals. |
|||
} |
|||
|
|||
*/ |
|||
|
|||
#ifdef HAVE_POSIX_SIGNALS |
|||
/* POSIX signals */ |
|||
|
|||
#define SIGNALS_UNBLOCK \ |
|||
do { sigset_t set; \ |
|||
sigemptyset (&set); \ |
|||
sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); \ |
|||
} while (0) |
|||
|
|||
#define SIGNALS_DECLARE_SAVED(name) sigset_t name |
|||
|
|||
#define SIGNALS_BLOCK(SIG, saved) \ |
|||
do { sigset_t set; \ |
|||
sigemptyset (&set); \ |
|||
sigaddset (&set, SIG); \ |
|||
sigprocmask (SIG_BLOCK, &set, &saved); \ |
|||
} while (0) |
|||
|
|||
#define SIGNALS_RESTORE(saved) \ |
|||
sigprocmask (SIG_SETMASK, &saved, (sigset_t *)NULL) |
|||
|
|||
|
|||
#else /* HAVE_POSIX_SIGNALS */ |
|||
#ifdef HAVE_BSD_SIGNALS |
|||
/* BSD signals */ |
|||
|
|||
#define SIGNALS_UNBLOCK sigsetmask (0) |
|||
#define SIGNALS_DECLARE_SAVED(name) int name |
|||
#define SIGNALS_BLOCK(SIG, saved) saved = sigblock (sigmask (SIG)) |
|||
#define SIGNALS_RESTORE(saved) sigsetmask (saved) |
|||
|
|||
|
|||
#else /* HAVE_BSD_SIGNALS */ |
|||
/* None of the Above */ |
|||
|
|||
#define SIGNALS_UNBLOCK /* nothing */ |
|||
#define SIGNALS_DECLARE_SAVED(name) /* nothing */ |
|||
#define SIGNALS_BLOCK(SIG, saved) /* nothing */ |
|||
#define SIGNALS_RESTORE(saved) /* nothing */ |
|||
|
|||
|
|||
#endif /* HAVE_BSD_SIGNALS */ |
|||
#endif /* HAVE_POSIX_SIGNALS */ |
|||
|
|||
/* End of signal handling definitions. */ |
|||
#endif /* !_RLDEFS_H */ |
|||
@ -0,0 +1,271 @@ |
|||
/* search.c - code for non-incremental searching in emacs and vi modes. */ |
|||
|
|||
/* Copyright (C) 1992 Free Software Foundation, Inc.
|
|||
|
|||
This file is part of the Readline Library (the Library), a set of |
|||
routines for providing Emacs style line input to programs that ask |
|||
for it. |
|||
|
|||
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) |
|||
any later version. |
|||
|
|||
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. */ |
|||
|
|||
#include <stdio.h> |
|||
|
|||
#if defined (__GNUC__) |
|||
# define alloca __builtin_alloca |
|||
#else |
|||
# if defined (sparc) || defined (HAVE_ALLOCA_H) |
|||
# include <alloca.h> |
|||
# endif |
|||
#endif |
|||
|
|||
#include "readline.h" |
|||
#include "history.h" |
|||
|
|||
extern char *xmalloc (), *xrealloc (); |
|||
|
|||
/* Variables imported from readline.c */ |
|||
extern int rl_point, rl_end, rl_line_buffer_len; |
|||
extern Keymap _rl_keymap; |
|||
extern char *rl_prompt; |
|||
extern char *rl_line_buffer; |
|||
extern HIST_ENTRY *saved_line_for_history; |
|||
|
|||
static char *noninc_search_string = (char *) NULL; |
|||
static int noninc_history_pos = 0; |
|||
|
|||
/* Search the history list for STRING starting at absolute history position
|
|||
POS. If STRING begins with `^', the search must match STRING at the |
|||
beginning of a history line, otherwise a full substring match is performed |
|||
for STRING. DIR < 0 means to search backwards through the history list, |
|||
DIR >= 0 means to search forward. */ |
|||
static int |
|||
noninc_search_from_pos (string, pos, dir) |
|||
char *string; |
|||
int pos, dir; |
|||
{ |
|||
int ret, old; |
|||
|
|||
old = where_history (); |
|||
history_set_pos (pos); |
|||
|
|||
if (*string == '^') |
|||
ret = history_search_prefix (string + 1, dir); |
|||
else |
|||
ret = history_search (string, dir); |
|||
|
|||
if (ret != -1) |
|||
ret = where_history (); |
|||
|
|||
history_set_pos (old); |
|||
return (ret); |
|||
} |
|||
|
|||
/* Search for a line in the history containing STRING. If DIR is < 0, the
|
|||
search is backwards through previous entries, else through subsequent |
|||
entries. */ |
|||
static void |
|||
noninc_dosearch (string, dir) |
|||
char *string; |
|||
int dir; |
|||
{ |
|||
int oldpos, pos; |
|||
HIST_ENTRY *entry; |
|||
|
|||
if (string == 0 || *string == 0 || noninc_history_pos < 0) |
|||
{ |
|||
ding (); |
|||
return; |
|||
} |
|||
|
|||
pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); |
|||
if (pos == -1) |
|||
{ |
|||
/* Search failed, current history position unchanged. */ |
|||
maybe_unsave_line (); |
|||
rl_clear_message (); |
|||
rl_point = 0; |
|||
ding (); |
|||
return; |
|||
} |
|||
|
|||
noninc_history_pos = pos; |
|||
|
|||
oldpos = where_history (); |
|||
history_set_pos (noninc_history_pos); |
|||
entry = current_history (); |
|||
history_set_pos (oldpos); |
|||
|
|||
{ |
|||
int line_len; |
|||
|
|||
line_len = strlen (entry->line); |
|||
if (line_len >= rl_line_buffer_len) |
|||
rl_extend_line_buffer (line_len); |
|||
strcpy (rl_line_buffer, entry->line); |
|||
} |
|||
|
|||
rl_undo_list = (UNDO_LIST *)entry->data; |
|||
rl_end = strlen (rl_line_buffer); |
|||
rl_point = 0; |
|||
rl_clear_message (); |
|||
|
|||
if (saved_line_for_history) |
|||
free_history_entry (saved_line_for_history); |
|||
saved_line_for_history = (HIST_ENTRY *)NULL; |
|||
} |
|||
|
|||
/* Search non-interactively through the history list. DIR < 0 means to
|
|||
search backwards through the history of previous commands; otherwise |
|||
the search is for commands subsequent to the current position in the |
|||
history list. PCHAR is the character to use for prompting when reading |
|||
the search string; if not specified (0), it defaults to `:'. */ |
|||
static void |
|||
noninc_search (dir, pchar) |
|||
int dir; |
|||
int pchar; |
|||
{ |
|||
int saved_point, c, pmtlen; |
|||
char *p; |
|||
|
|||
maybe_save_line (); |
|||
saved_point = rl_point; |
|||
|
|||
/* Use the line buffer to read the search string. */ |
|||
rl_line_buffer[0] = 0; |
|||
rl_end = rl_point = 0; |
|||
|
|||
pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; |
|||
p = (char *)alloca (2 + pmtlen); |
|||
if (pmtlen) |
|||
strcpy (p, rl_prompt); |
|||
p[pmtlen] = pchar ? pchar : ':'; |
|||
p[pmtlen + 1] = '\0'; |
|||
|
|||
rl_message (p, 0, 0); |
|||
|
|||
/* Read the search string. */ |
|||
while (c = rl_read_key ()) |
|||
{ |
|||
switch (c) |
|||
{ |
|||
case CTRL('H'): |
|||
case RUBOUT: |
|||
if (rl_point == 0) |
|||
{ |
|||
maybe_unsave_line (); |
|||
rl_clear_message (); |
|||
rl_point = saved_point; |
|||
return; |
|||
} |
|||
/* FALLTHROUGH */ |
|||
|
|||
case CTRL('W'): |
|||
case CTRL('U'): |
|||
rl_dispatch (c, _rl_keymap); |
|||
break; |
|||
|
|||
case RETURN: |
|||
case NEWLINE: |
|||
goto dosearch; |
|||
/* NOTREACHED */ |
|||
break; |
|||
|
|||
case CTRL('C'): |
|||
case CTRL('G'): |
|||
maybe_unsave_line (); |
|||
rl_clear_message (); |
|||
rl_point = saved_point; |
|||
ding (); |
|||
return; |
|||
|
|||
default: |
|||
rl_insert (1, c); |
|||
break; |
|||
} |
|||
rl_redisplay (); |
|||
} |
|||
|
|||
dosearch: |
|||
/* If rl_point == 0, we want to re-use the previous search string and
|
|||
start from the saved history position. If there's no previous search |
|||
string, punt. */ |
|||
if (rl_point == 0) |
|||
{ |
|||
if (!noninc_search_string) |
|||
{ |
|||
ding (); |
|||
return; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
/* We want to start the search from the current history position. */ |
|||
noninc_history_pos = where_history (); |
|||
if (noninc_search_string) |
|||
free (noninc_search_string); |
|||
noninc_search_string = savestring (rl_line_buffer); |
|||
} |
|||
|
|||
noninc_dosearch (noninc_search_string, dir); |
|||
} |
|||
|
|||
/* Search forward through the history list for a string. If the vi-mode
|
|||
code calls this, KEY will be `?'. */ |
|||
rl_noninc_forward_search (count, key) |
|||
int count, key; |
|||
{ |
|||
if (key == '?') |
|||
noninc_search (1, '?'); |
|||
else |
|||
noninc_search (1, 0); |
|||
} |
|||
|
|||
/* Reverse search the history list for a string. If the vi-mode code
|
|||
calls this, KEY will be `/'. */ |
|||
rl_noninc_reverse_search (count, key) |
|||
int count, key; |
|||
{ |
|||
if (key == '/') |
|||
noninc_search (-1, '/'); |
|||
else |
|||
noninc_search (-1, 0); |
|||
} |
|||
|
|||
/* Search forward through the history list for the last string searched
|
|||
for. If there is no saved search string, abort. */ |
|||
rl_noninc_forward_search_again (count, key) |
|||
int count, key; |
|||
{ |
|||
if (!noninc_search_string) |
|||
{ |
|||
ding (); |
|||
return (-1); |
|||
} |
|||
noninc_dosearch (noninc_search_string, 1); |
|||
} |
|||
|
|||
/* Reverse search in the history list for the last string searched
|
|||
for. If there is no saved search string, abort. */ |
|||
rl_noninc_reverse_search_again (count, key) |
|||
int count, key; |
|||
{ |
|||
if (!noninc_search_string) |
|||
{ |
|||
ding (); |
|||
return (-1); |
|||
} |
|||
noninc_dosearch (noninc_search_string, -1); |
|||
} |
|||
@ -0,0 +1,396 @@ |
|||
/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */ |
|||
|
|||
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
|
|||
|
|||
This file is part of GNU Readline, a library for reading lines |
|||
of text with interactive input and history editing. |
|||
|
|||
Readline 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. |
|||
|
|||
Readline is distributed in the hope that it will be useful, but |
|||
WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with Readline; see the file COPYING. If not, write to the Free |
|||
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|||
|
|||
#if defined (__GNUC__) |
|||
# undef alloca |
|||
# define alloca __builtin_alloca |
|||
#else /* !__GNUC__ */ |
|||
# if defined (_AIX) |
|||
#pragma alloca |
|||
# else /* !_AIX */ |
|||
# if defined (HAVE_ALLOCA_H) |
|||
# include <alloca.h> |
|||
# endif /* HAVE_ALLOCA_H */ |
|||
# endif /* !AIX */ |
|||
#endif /* !__GNUC__ */ |
|||
|
|||
#if defined (HAVE_STRING_H) |
|||
# include <string.h> |
|||
#else /* !HAVE_STRING_H */ |
|||
# include <strings.h> |
|||
#endif /* !HAVE_STRING_H */ |
|||
|
|||
#if defined (HAVE_STDLIB_H) |
|||
# include <stdlib.h> |
|||
#else |
|||
# include "ansi_stdlib.h" |
|||
#endif /* HAVE_STDLIB_H */ |
|||
|
|||
#include <tilde/tilde.h> |
|||
#include <pwd.h> |
|||
|
|||
#if !defined (sgi) && !defined (isc386) |
|||
extern struct passwd *getpwnam (), *getpwuid (); |
|||
#endif /* !sgi */ |
|||
|
|||
#if !defined (savestring) |
|||
extern char *xmalloc (); |
|||
# ifndef strcpy |
|||
extern char *strcpy (); |
|||
# endif |
|||
#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) |
|||
#endif /* !savestring */ |
|||
|
|||
#if !defined (NULL) |
|||
# if defined (__STDC__) |
|||
# define NULL ((void *) 0) |
|||
# else |
|||
# define NULL 0x0 |
|||
# endif /* !__STDC__ */ |
|||
#endif /* !NULL */ |
|||
|
|||
#if defined (TEST) || defined (STATIC_MALLOC) |
|||
static char *xmalloc (), *xrealloc (); |
|||
#else |
|||
extern char *xmalloc (), *xrealloc (); |
|||
#endif /* TEST || STATIC_MALLOC */ |
|||
|
|||
/* The default value of tilde_additional_prefixes. This is set to
|
|||
whitespace preceding a tilde so that simple programs which do not |
|||
perform any word separation get desired behaviour. */ |
|||
static char *default_prefixes[] = |
|||
{ " ~", "\t~", (char *)NULL }; |
|||
|
|||
/* The default value of tilde_additional_suffixes. This is set to
|
|||
whitespace or newline so that simple programs which do not |
|||
perform any word separation get desired behaviour. */ |
|||
static char *default_suffixes[] = |
|||
{ " ", "\n", (char *)NULL }; |
|||
|
|||
/* 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 *tilde_expansion_failure_hook = (Function *)NULL; |
|||
|
|||
/* When non-null, this is a NULL terminated array of strings which
|
|||
are duplicates for a tilde prefix. Bash uses this to expand |
|||
`=~' and `:~'. */ |
|||
char **tilde_additional_prefixes = default_prefixes; |
|||
|
|||
/* When non-null, this is a NULL terminated array of strings which match
|
|||
the end of a username, instead of just "/". Bash sets this to |
|||
`:' and `=~'. */ |
|||
char **tilde_additional_suffixes = default_suffixes; |
|||
|
|||
/* Find the start of a tilde expansion in STRING, and return the index of
|
|||
the tilde which starts the expansion. Place the length of the text |
|||
which identified this tilde starter in LEN, excluding the tilde itself. */ |
|||
static int |
|||
tilde_find_prefix (string, len) |
|||
char *string; |
|||
int *len; |
|||
{ |
|||
register int i, j, string_len; |
|||
register char **prefixes = tilde_additional_prefixes; |
|||
|
|||
string_len = strlen (string); |
|||
*len = 0; |
|||
|
|||
if (!*string || *string == '~') |
|||
return (0); |
|||
|
|||
if (prefixes) |
|||
{ |
|||
for (i = 0; i < string_len; i++) |
|||
{ |
|||
for (j = 0; prefixes[j]; j++) |
|||
{ |
|||
if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0) |
|||
{ |
|||
*len = strlen (prefixes[j]) - 1; |
|||
return (i + *len); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return (string_len); |
|||
} |
|||
|
|||
/* Find the end of a tilde expansion in STRING, and return the index of
|
|||
the character which ends the tilde definition. */ |
|||
static int |
|||
tilde_find_suffix (string) |
|||
char *string; |
|||
{ |
|||
register int i, j, string_len; |
|||
register char **suffixes = tilde_additional_suffixes; |
|||
|
|||
string_len = strlen (string); |
|||
|
|||
for (i = 0; i < string_len; i++) |
|||
{ |
|||
if (string[i] == '/' || !string[i]) |
|||
break; |
|||
|
|||
for (j = 0; suffixes && suffixes[j]; j++) |
|||
{ |
|||
if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0) |
|||
return (i); |
|||
} |
|||
} |
|||
return (i); |
|||
} |
|||
|
|||
/* Return a new string which is the result of tilde expanding STRING. */ |
|||
char * |
|||
tilde_expand (string) |
|||
char *string; |
|||
{ |
|||
char *result, *tilde_expand_word (); |
|||
int result_size, result_index; |
|||
|
|||
result_size = result_index = 0; |
|||
result = (char *)NULL; |
|||
|
|||
/* Scan through STRING expanding tildes as we come to them. */ |
|||
while (1) |
|||
{ |
|||
register int start, end; |
|||
char *tilde_word, *expansion; |
|||
int len; |
|||
|
|||
/* Make START point to the tilde which starts the expansion. */ |
|||
start = tilde_find_prefix (string, &len); |
|||
|
|||
/* Copy the skipped text into the result. */ |
|||
if ((result_index + start + 1) > result_size) |
|||
result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); |
|||
|
|||
strncpy (result + result_index, string, start); |
|||
result_index += start; |
|||
|
|||
/* Advance STRING to the starting tilde. */ |
|||
string += start; |
|||
|
|||
/* Make END be the index of one after the last character of the
|
|||
username. */ |
|||
end = tilde_find_suffix (string); |
|||
|
|||
/* If both START and END are zero, we are all done. */ |
|||
if (!start && !end) |
|||
break; |
|||
|
|||
/* Expand the entire tilde word, and copy it into RESULT. */ |
|||
tilde_word = (char *)xmalloc (1 + end); |
|||
strncpy (tilde_word, string, end); |
|||
tilde_word[end] = '\0'; |
|||
string += end; |
|||
|
|||
expansion = tilde_expand_word (tilde_word); |
|||
free (tilde_word); |
|||
|
|||
len = strlen (expansion); |
|||
if ((result_index + len + 1) > result_size) |
|||
result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); |
|||
|
|||
strcpy (result + result_index, expansion); |
|||
result_index += len; |
|||
free (expansion); |
|||
} |
|||
|
|||
result[result_index] = '\0'; |
|||
|
|||
return (result); |
|||
} |
|||
|
|||
/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
|
|||
tilde. If there is no expansion, call tilde_expansion_failure_hook. */ |
|||
char * |
|||
tilde_expand_word (filename) |
|||
char *filename; |
|||
{ |
|||
char *dirname; |
|||
|
|||
dirname = filename ? savestring (filename) : (char *)NULL; |
|||
|
|||
if (dirname && *dirname == '~') |
|||
{ |
|||
char *temp_name; |
|||
if (!dirname[1] || dirname[1] == '/') |
|||
{ |
|||
/* Prepend $HOME to the rest of the string. */ |
|||
char *temp_home = (char *)getenv ("HOME"); |
|||
|
|||
/* If there is no HOME variable, look up the directory in
|
|||
the password database. */ |
|||
if (!temp_home) |
|||
{ |
|||
struct passwd *entry; |
|||
|
|||
entry = getpwuid (getuid ()); |
|||
if (entry) |
|||
temp_home = entry->pw_dir; |
|||
} |
|||
|
|||
temp_name = (char *)alloca (1 + strlen (&dirname[1]) |
|||
+ (temp_home ? strlen (temp_home) : 0)); |
|||
temp_name[0] = '\0'; |
|||
if (temp_home) |
|||
strcpy (temp_name, temp_home); |
|||
strcat (temp_name, &dirname[1]); |
|||
free (dirname); |
|||
dirname = savestring (temp_name); |
|||
} |
|||
else |
|||
{ |
|||
struct passwd *user_entry; |
|||
char *username = (char *)alloca (257); |
|||
int i, c; |
|||
|
|||
for (i = 1; c = dirname[i]; i++) |
|||
{ |
|||
if (c == '/') |
|||
break; |
|||
else |
|||
username[i - 1] = c; |
|||
} |
|||
username[i - 1] = '\0'; |
|||
|
|||
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. */ |
|||
if (tilde_expansion_failure_hook) |
|||
{ |
|||
char *expansion; |
|||
|
|||
expansion = |
|||
(char *)(*tilde_expansion_failure_hook) (username); |
|||
|
|||
if (expansion) |
|||
{ |
|||
temp_name = (char *)alloca (1 + strlen (expansion) |
|||
+ strlen (&dirname[i])); |
|||
strcpy (temp_name, expansion); |
|||
strcat (temp_name, &dirname[i]); |
|||
free (expansion); |
|||
goto return_name; |
|||
} |
|||
} |
|||
/* We shouldn't report errors. */ |
|||
} |
|||
else |
|||
{ |
|||
temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir) |
|||
+ strlen (&dirname[i])); |
|||
strcpy (temp_name, user_entry->pw_dir); |
|||
strcat (temp_name, &dirname[i]); |
|||
return_name: |
|||
free (dirname); |
|||
dirname = savestring (temp_name); |
|||
} |
|||
endpwent (); |
|||
} |
|||
} |
|||
return (dirname); |
|||
} |
|||
|
|||
|
|||
#if defined (TEST) |
|||
#undef NULL |
|||
#include <stdio.h> |
|||
|
|||
main (argc, argv) |
|||
int argc; |
|||
char **argv; |
|||
{ |
|||
char *result, line[512]; |
|||
int done = 0; |
|||
|
|||
while (!done) |
|||
{ |
|||
printf ("~expand: "); |
|||
fflush (stdout); |
|||
|
|||
if (!gets (line)) |
|||
strcpy (line, "done"); |
|||
|
|||
if ((strcmp (line, "done") == 0) || |
|||
(strcmp (line, "quit") == 0) || |
|||
(strcmp (line, "exit") == 0)) |
|||
{ |
|||
done = 1; |
|||
break; |
|||
} |
|||
|
|||
result = tilde_expand (line); |
|||
printf (" --> %s\n", result); |
|||
free (result); |
|||
} |
|||
exit (0); |
|||
} |
|||
|
|||
static void memory_error_and_abort (); |
|||
|
|||
static char * |
|||
xmalloc (bytes) |
|||
int bytes; |
|||
{ |
|||
char *temp = (char *)malloc (bytes); |
|||
|
|||
if (!temp) |
|||
memory_error_and_abort (); |
|||
return (temp); |
|||
} |
|||
|
|||
static char * |
|||
xrealloc (pointer, bytes) |
|||
char *pointer; |
|||
int bytes; |
|||
{ |
|||
char *temp; |
|||
|
|||
if (!pointer) |
|||
temp = (char *)malloc (bytes); |
|||
else |
|||
temp = (char *)realloc (pointer, bytes); |
|||
|
|||
if (!temp) |
|||
memory_error_and_abort (); |
|||
|
|||
return (temp); |
|||
} |
|||
|
|||
static void |
|||
memory_error_and_abort () |
|||
{ |
|||
fprintf (stderr, "readline: Out of virtual memory!\n"); |
|||
abort (); |
|||
} |
|||
|
|||
/*
|
|||
* Local variables: |
|||
* compile-command: "gcc -g -DTEST -o tilde tilde.c" |
|||
* end: |
|||
*/ |
|||
#endif /* TEST */ |
|||
@ -0,0 +1,33 @@ |
|||
/* tilde.h: Externally available variables and function in libtilde.a. */ |
|||
|
|||
/* Function pointers can be declared as (Function *)foo. */ |
|||
#if !defined (__FUNCTION_DEF) |
|||
# define __FUNCTION_DEF |
|||
typedef int Function (); |
|||
typedef void VFunction (); |
|||
typedef char *CPFunction (); |
|||
typedef char **CPPFunction (); |
|||
#endif /* _FUNCTION_DEF */ |
|||
|
|||
/* 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. */ |
|||
extern Function *tilde_expansion_failure_hook; |
|||
|
|||
/* When non-null, this is a NULL terminated array of strings which
|
|||
are duplicates for a tilde prefix. Bash uses this to expand |
|||
`=~' and `:~'. */ |
|||
extern char **tilde_additional_prefixes; |
|||
|
|||
/* When non-null, this is a NULL terminated array of strings which match
|
|||
the end of a username, instead of just "/". Bash sets this to |
|||
`:' and `=~'. */ |
|||
extern char **tilde_additional_suffixes; |
|||
|
|||
/* Return a new string which is the result of tilde expanding STRING. */ |
|||
extern char *tilde_expand (); |
|||
|
|||
/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
|
|||
tilde. If there is no expansion, call tilde_expansion_failure_hook. */ |
|||
extern char *tilde_expand_word (); |
|||
@ -0,0 +1,76 @@ |
|||
/* xmalloc.c -- safe versions of malloc and realloc */ |
|||
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
|||
|
|||
This file is part of GNU Readline, a library for reading lines |
|||
of text with interactive input and history editing. |
|||
|
|||
Readline 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. |
|||
|
|||
Readline is distributed in the hope that it will be useful, but |
|||
WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with Readline; see the file COPYING. If not, write to the Free |
|||
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|||
|
|||
#if defined (ALREADY_HAVE_XMALLOC) |
|||
#else |
|||
#include <stdio.h> |
|||
|
|||
#if defined (HAVE_STDLIB_H) |
|||
# include <stdlib.h> |
|||
#endif /* HAVE_STDLIB_H */ |
|||
|
|||
static void memory_error_and_abort (); |
|||
|
|||
/* **************************************************************** */ |
|||
/* */ |
|||
/* Memory Allocation and Deallocation. */ |
|||
/* */ |
|||
/* **************************************************************** */ |
|||
|
|||
/* Return a pointer to free()able block of memory large enough
|
|||
to hold BYTES number of bytes. If the memory cannot be allocated, |
|||
print an error message and abort. */ |
|||
char * |
|||
xmalloc (bytes) |
|||
int bytes; |
|||
{ |
|||
char *temp = (char *)malloc (bytes); |
|||
|
|||
if (!temp) |
|||
memory_error_and_abort ("xmalloc"); |
|||
return (temp); |
|||
} |
|||
|
|||
char * |
|||
xrealloc (pointer, bytes) |
|||
char *pointer; |
|||
int bytes; |
|||
{ |
|||
char *temp; |
|||
|
|||
if (!pointer) |
|||
temp = (char *)malloc (bytes); |
|||
else |
|||
temp = (char *)realloc (pointer, bytes); |
|||
|
|||
if (!temp) |
|||
memory_error_and_abort ("xrealloc"); |
|||
return (temp); |
|||
} |
|||
|
|||
static void |
|||
memory_error_and_abort (fname) |
|||
char *fname; |
|||
{ |
|||
fprintf (stderr, "%s: Out of virtual memory!\n", fname); |
|||
abort (); |
|||
} |
|||
#endif /* !ALREADY_HAVE_XMALLOC */ |
|||
Loading…
Reference in new issue