2886 lines
64 KiB
C
2886 lines
64 KiB
C
/*
|
|
* input.c: does the actual input line stuff... keeps the appropriate stuff
|
|
* on the input line, handles insert/delete of characters/words... the whole
|
|
* ball o wax
|
|
*
|
|
* Written By Michael Sandrof
|
|
*
|
|
* Copyright(c) 1990
|
|
*
|
|
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
|
|
*/
|
|
|
|
#include "irc.h"
|
|
static char cvsrevision[] = "$Id$";
|
|
CVS_REVISION(input_c)
|
|
#include <pwd.h>
|
|
#include "struct.h"
|
|
|
|
#include "alias.h"
|
|
#include "commands.h"
|
|
#include "exec.h"
|
|
#include "history.h"
|
|
#include "bsdglob.h"
|
|
#include "hook.h"
|
|
#include "input.h"
|
|
#include "ircaux.h"
|
|
#include "keys.h"
|
|
#include "screen.h"
|
|
#include "server.h"
|
|
#include "ircterm.h"
|
|
#include "list.h"
|
|
#include "vars.h"
|
|
#include "misc.h"
|
|
#include "screen.h"
|
|
#include "output.h"
|
|
#include "chelp.h"
|
|
#include "dcc.h"
|
|
#include "cdcc.h"
|
|
#include "whowas.h"
|
|
#include "tcl_bx.h"
|
|
#include "window.h"
|
|
#include "status.h"
|
|
#include "hash2.h"
|
|
|
|
#ifdef TRANSLATE
|
|
#include "translat.h"
|
|
#endif
|
|
#ifdef WANT_HEBREW
|
|
#include "hebrew.h"
|
|
#endif
|
|
|
|
#define MAIN_SOURCE
|
|
#include "modval.h"
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
void get_history (int);
|
|
|
|
static char new_nick[NICKNAME_LEN+1] = "";
|
|
static char *input_lastmsg = NULL;
|
|
|
|
extern NickTab *BX_getnextnick (int, char *, char *, char *);
|
|
extern int extended_handled;
|
|
extern char *BX_getchannick (char *, char *);
|
|
extern int foreground;
|
|
|
|
NickTab *tabkey_array = NULL, *autoreply_array = NULL;
|
|
|
|
|
|
|
|
const int WIDTH = 10;
|
|
|
|
/* input_prompt: contains the current, unexpanded input prompt */
|
|
static char *input_prompt = NULL;
|
|
|
|
enum I_STATE {
|
|
STATE_NORMAL = 0,
|
|
STATE_COMPLETE,
|
|
STATE_TABKEY,
|
|
STATE_TABKEYNEXT,
|
|
STATE_CNICK,
|
|
STATE_CNICKNEXT
|
|
} in_completion = STATE_NORMAL;
|
|
|
|
/* These are sanity macros. The file was completely unreadable before
|
|
* i put these in here. I make no apologies for them.
|
|
*/
|
|
#define current_screen last_input_screen
|
|
#define INPUT_CURSOR current_screen->input_cursor
|
|
#define INPUT_BUFFER current_screen->input_buffer
|
|
#define MIN_POS current_screen->buffer_min_pos
|
|
#define THIS_POS current_screen->buffer_pos
|
|
#define THIS_CHAR INPUT_BUFFER[THIS_POS]
|
|
#define MIN_CHAR INPUT_BUFFER[MIN_POS]
|
|
#define PREV_CHAR INPUT_BUFFER[THIS_POS-1]
|
|
#define NEXT_CHAR INPUT_BUFFER[THIS_POS+1]
|
|
#define ADD_TO_INPUT(x) strmcat(INPUT_BUFFER, (x), INPUT_BUFFER_SIZE);
|
|
#define INPUT_ONSCREEN current_screen->input_visible
|
|
#define INPUT_VISIBLE INPUT_BUFFER[INPUT_ONSCREEN]
|
|
#define ZONE current_screen->input_zone_len
|
|
#define START_ZONE current_screen->input_start_zone
|
|
#define END_ZONE current_screen->input_end_zone
|
|
#define INPUT_PROMPT current_screen->input_prompt
|
|
#define INPUT_PROMPT_LEN current_screen->input_prompt_len
|
|
#define INPUT_LINE current_screen->input_line
|
|
#define BUILT_IN_KEYBINDING(x) void x (char key, char *string)
|
|
|
|
|
|
#define HOLDLAST current_screen->current_window->screen_hold
|
|
|
|
Display *get_screen_hold(Window *win)
|
|
{
|
|
return win->screen_hold;
|
|
}
|
|
|
|
static int safe_puts (register char *str, int len, int echo)
|
|
{
|
|
int i = 0;
|
|
while (*str && i < len)
|
|
{
|
|
term_putchar(*str);
|
|
str++; i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* cursor_to_input: move the cursor to the input line, if not there already */
|
|
extern void BX_cursor_to_input (void)
|
|
{
|
|
Screen *oldscreen = last_input_screen;
|
|
Screen *screen;
|
|
|
|
if (!foreground)
|
|
return;
|
|
|
|
for (screen = screen_list; screen; screen = screen->next)
|
|
{
|
|
if (screen->alive && is_cursor_in_display(screen))
|
|
{
|
|
output_screen = screen;
|
|
last_input_screen = screen;
|
|
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
|
|
cursor_not_in_display(screen);
|
|
term_flush();
|
|
}
|
|
}
|
|
output_screen = last_input_screen = oldscreen;
|
|
}
|
|
|
|
/*
|
|
* update_input: does varying amount of updating on the input line depending
|
|
* upon the position of the cursor and the update flag. If the cursor has
|
|
* move toward one of the edge boundaries on the screen, update_cursor()
|
|
* flips the input line to the next (previous) line of text. The update flag
|
|
* may be:
|
|
*
|
|
* NO_UPDATE - only do the above bounds checking.
|
|
*
|
|
* UPDATE_JUST_CURSOR - do bounds checking and position cursor where is should
|
|
* be.
|
|
*
|
|
* UPDATE_FROM_CURSOR - does all of the above, and makes sure everything from
|
|
* the cursor to the right edge of the screen is current (by redrawing it).
|
|
*
|
|
* UPDATE_ALL - redraws the entire line
|
|
*/
|
|
extern void BX_update_input (int update)
|
|
{
|
|
int old_zone;
|
|
char *ptr, *ptr_free;
|
|
int len,
|
|
free_it = 0,
|
|
echo = 1,
|
|
max;
|
|
|
|
char *prompt;
|
|
Screen *os = last_input_screen;
|
|
Screen *ns;
|
|
Window *saved_current_window = current_window;
|
|
|
|
|
|
#ifdef WANT_HEBREW
|
|
void BX_set_input_heb (char *str);
|
|
char prehebbuff[2000];
|
|
#endif
|
|
if (dumb_mode || !foreground)
|
|
return;
|
|
for (ns = screen_list; ns; ns = ns->next)
|
|
{
|
|
last_input_screen = ns;
|
|
current_window = ns->current_window;
|
|
|
|
#ifdef WANT_HEBREW
|
|
/*
|
|
* crisk: hebrew thingy
|
|
*/
|
|
if (get_int_var(HEBREW_TOGGLE_VAR))
|
|
{
|
|
update = UPDATE_ALL;
|
|
strcpy(prehebbuff, get_input());
|
|
hebrew_process(get_input());
|
|
}
|
|
#endif
|
|
|
|
cursor_to_input();
|
|
|
|
if (last_input_screen && last_input_screen->promptlist)
|
|
prompt = last_input_screen->promptlist->prompt;
|
|
else
|
|
prompt = input_prompt;
|
|
|
|
if (prompt)
|
|
{
|
|
char *loc;
|
|
int i;
|
|
extern int in_chelp;
|
|
|
|
loc = alloca(strlen(prompt)+200);
|
|
for (i = 0; prompt[i]; i++)
|
|
{
|
|
if (prompt[i] == '$')
|
|
loc[i++] = '$';
|
|
loc[i] = prompt[i];
|
|
}
|
|
loc[i] = 0;
|
|
in_chelp++;
|
|
prompt = convert_output_format(loc, NULL, NULL);
|
|
in_chelp--;
|
|
}
|
|
|
|
if (prompt && update != NO_UPDATE)
|
|
{
|
|
int args_used;
|
|
|
|
if (is_valid_process(get_target_by_refnum(0)) != -1)
|
|
ptr = (char *)get_prompt_by_refnum(0);
|
|
else
|
|
{
|
|
ptr = expand_alias(prompt, empty_string, &args_used, NULL);
|
|
free_it = 1;
|
|
}
|
|
if (last_input_screen->promptlist)
|
|
term_echo(last_input_screen->promptlist->echo);
|
|
|
|
ptr_free = ptr;
|
|
ptr = strip_ansi(ptr);
|
|
strcat(ptr, ALL_OFF_STR); /* Yes, we can do this */
|
|
if (free_it)
|
|
new_free(&ptr_free);
|
|
free_it = 1;
|
|
|
|
if ((ptr && !INPUT_LINE) || (!ptr && INPUT_LINE) ||
|
|
strcmp(ptr, last_input_screen->input_buffer))
|
|
{
|
|
if (last_input_screen->input_prompt_malloc)
|
|
new_free(&INPUT_PROMPT);
|
|
|
|
last_input_screen->input_prompt_malloc = free_it;
|
|
|
|
INPUT_PROMPT = ptr;
|
|
len = strlen(INPUT_PROMPT);
|
|
INPUT_PROMPT_LEN = output_with_count(INPUT_PROMPT, 0, 0);
|
|
update = UPDATE_ALL;
|
|
}
|
|
else
|
|
{
|
|
if (free_it)
|
|
new_free(&ptr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* HAS THE SCREEN CHANGED SIZE SINCE THE LAST TIME?
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* If the screen has resized, then we need to re-compute the
|
|
* side-to-side scrolling effect.
|
|
*/
|
|
if ((last_input_screen->li != last_input_screen->old_li) ||
|
|
(last_input_screen->co != last_input_screen->old_co))
|
|
{
|
|
/*
|
|
* The input line is always the bottom line
|
|
*/
|
|
|
|
INPUT_LINE = last_input_screen->li - 1;
|
|
|
|
/*
|
|
* The "zone" is the range in which when you type, the
|
|
* input line does not scroll. Its WIDTH chars in from
|
|
* either side.
|
|
*/
|
|
ZONE = last_input_screen->co - (WIDTH * 2);
|
|
if (ZONE < 10)
|
|
ZONE = 10; /* Take that! */
|
|
|
|
START_ZONE = WIDTH;
|
|
END_ZONE = last_input_screen->co - WIDTH;
|
|
|
|
last_input_screen->old_co = last_input_screen->co;
|
|
last_input_screen->old_li = last_input_screen->li;
|
|
}
|
|
/*
|
|
* About zones:
|
|
* The input line is divided into "zones". A "zone" is set above,
|
|
* and is the width of the screen minus 20 (by default). The input
|
|
* line, as displayed, is therefore composed of the current "zone",
|
|
* plus 10 characters from the previous zone, plus 10 characters
|
|
* from the next zone. When the cursor moves to an adjacent zone,
|
|
* (by going into column 9 from the right or left of the edge), the
|
|
* input line is redrawn. There is one catch. The first "zone"
|
|
* includes the first ten characters of the input line.
|
|
*/
|
|
old_zone = START_ZONE;
|
|
|
|
/*
|
|
* The BEGINNING of the current "zone" is a calculated value:
|
|
* The number of characters since the origin of the input buffer
|
|
* is the number of printable chars in the input prompt plus the
|
|
* current position in the input buffer. We subtract from that
|
|
* the WIDTH delta to take off the first delta, which doesnt
|
|
* count towards the width of the zone. Then we divide that by
|
|
* the size of the zone, to get an integer, then we multiply it
|
|
* back. This gives us the first character on the screen. We
|
|
* add WIDTH to the result in order to get the start of the zone
|
|
* itself.
|
|
* The END of the current "zone" is just the beginning plus the width.
|
|
* If we have moved to an adjacent "zone" since last time, we want to
|
|
* completely redraw the input line.
|
|
*/
|
|
START_ZONE = ((INPUT_PROMPT_LEN + THIS_POS - WIDTH) / ZONE) * ZONE + WIDTH;
|
|
END_ZONE = START_ZONE + ZONE;
|
|
|
|
if (old_zone != START_ZONE)
|
|
update = UPDATE_ALL;
|
|
|
|
/*
|
|
* Now that we know where the "zone" is in the input buffer, we can
|
|
* easily calculate where where we want to start displaying stuff
|
|
* from the INPUT_BUFFER. If we're in the first "zone", then we will
|
|
* output from the beginning of the buffer. If we're not in the first
|
|
* "zone", then we will begin to output from 10 characters to the
|
|
* left of the zone, after adjusting for the length of the prompt.
|
|
*/
|
|
if (START_ZONE == WIDTH)
|
|
INPUT_ONSCREEN = 0;
|
|
else
|
|
INPUT_ONSCREEN = START_ZONE - WIDTH - INPUT_PROMPT_LEN;
|
|
|
|
/*
|
|
* And the cursor is simply how many characters away THIS_POS is
|
|
* from the first column on the screen.
|
|
*/
|
|
if (INPUT_ONSCREEN == 0)
|
|
INPUT_CURSOR = INPUT_PROMPT_LEN + THIS_POS;
|
|
else
|
|
INPUT_CURSOR = THIS_POS - INPUT_ONSCREEN;
|
|
|
|
/*
|
|
* If the cursor moved, or if we're supposed to do a full update,
|
|
* then redrwa the entire input line.
|
|
*/
|
|
if (update == UPDATE_ALL)
|
|
{
|
|
term_move_cursor(0, INPUT_LINE);
|
|
|
|
/*
|
|
* If the input line is NOT empty, and we're starting the
|
|
* display at the beginning of the input buffer, then we
|
|
* output the prompt first.
|
|
*/
|
|
if (INPUT_ONSCREEN == 0 && INPUT_PROMPT && *INPUT_PROMPT)
|
|
{
|
|
/*
|
|
* Forcibly turn on echo.
|
|
*/
|
|
int echo = term_echo(1);
|
|
|
|
/*
|
|
* Crop back the input prompt so it does not extend
|
|
* past the end of the zone.
|
|
*/
|
|
if (INPUT_PROMPT_LEN > (last_input_screen->co - WIDTH))
|
|
INPUT_PROMPT_LEN = last_input_screen->co - WIDTH - 1;
|
|
|
|
/*
|
|
* Output the prompt.
|
|
*/
|
|
output_with_count(INPUT_PROMPT, 0, 1);
|
|
|
|
/*
|
|
* Turn the echo back to what it was before,
|
|
* and output the rest of the input buffer.
|
|
*/
|
|
term_echo(echo);
|
|
safe_puts(INPUT_BUFFER, last_input_screen->co - INPUT_PROMPT_LEN, echo);
|
|
}
|
|
|
|
/*
|
|
* Otherwise we just output whatever we have.
|
|
*/
|
|
else if (echo)
|
|
safe_puts(&(INPUT_VISIBLE), last_input_screen->co, echo);
|
|
|
|
/*
|
|
* Clear the rest of the input line and reset the cursor
|
|
* to the current input position.
|
|
*/
|
|
term_clear_to_eol();
|
|
}
|
|
else if (update == UPDATE_FROM_CURSOR)
|
|
{
|
|
/*
|
|
* Move the cursor to where its supposed to be,
|
|
* Figure out how much we can output from here,
|
|
* and then output it.
|
|
*/
|
|
#ifdef __EMXPM__
|
|
int echo = term_echo(1);
|
|
#endif
|
|
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
|
|
max = last_input_screen->co - (THIS_POS - INPUT_ONSCREEN);
|
|
if (INPUT_ONSCREEN == 0 && INPUT_PROMPT && *INPUT_PROMPT)
|
|
max -= INPUT_PROMPT_LEN;
|
|
|
|
if ((len = strlen(&(THIS_CHAR))) > max)
|
|
len = max;
|
|
safe_puts(&(THIS_CHAR), len, echo);
|
|
term_clear_to_eol();
|
|
}
|
|
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
|
|
term_echo(1);
|
|
term_flush();
|
|
#ifdef WANT_HEBREW
|
|
/*
|
|
* crisk: hebrew thingy
|
|
*/
|
|
if (get_int_var(HEBREW_TOGGLE_VAR))
|
|
BX_set_input_heb(prehebbuff);
|
|
#endif
|
|
}
|
|
last_input_screen = os;
|
|
current_window = saved_current_window;
|
|
}
|
|
|
|
void change_input_prompt (int direction)
|
|
{
|
|
if (!last_input_screen->promptlist)
|
|
{
|
|
strcpy(INPUT_BUFFER, last_input_screen->saved_input_buffer);
|
|
THIS_POS = last_input_screen->saved_buffer_pos;
|
|
MIN_POS = last_input_screen->saved_min_buffer_pos;
|
|
*last_input_screen->saved_input_buffer = '\0';
|
|
last_input_screen->saved_buffer_pos = 0;
|
|
last_input_screen->saved_min_buffer_pos = 0;
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
else if (direction == -1)
|
|
update_input(UPDATE_ALL);
|
|
|
|
else if (!last_input_screen->promptlist->next)
|
|
{
|
|
strcpy(last_input_screen->saved_input_buffer, INPUT_BUFFER);
|
|
last_input_screen->saved_buffer_pos = THIS_POS;
|
|
last_input_screen->saved_min_buffer_pos = MIN_POS;
|
|
*INPUT_BUFFER = '\0';
|
|
THIS_POS = MIN_POS = 0;
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
}
|
|
|
|
/* input_move_cursor: moves the cursor left or right... got it? */
|
|
extern void input_move_cursor (int dir)
|
|
{
|
|
cursor_to_input();
|
|
if (dir)
|
|
{
|
|
if (THIS_CHAR)
|
|
{
|
|
THIS_POS++;
|
|
term_cursor_right();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (THIS_POS > MIN_POS)
|
|
{
|
|
THIS_POS--;
|
|
term_cursor_left();
|
|
}
|
|
}
|
|
update_input(NO_UPDATE);
|
|
}
|
|
|
|
/*
|
|
* set_input: sets the input buffer to the given string, discarding whatever
|
|
* was in the input buffer before
|
|
*/
|
|
void BX_set_input (char *str)
|
|
{
|
|
strlcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
|
|
THIS_POS = strlen(INPUT_BUFFER);
|
|
}
|
|
|
|
#ifdef WANT_HEBREW
|
|
/*
|
|
* eilon: same as the above just without the cursor reposition.
|
|
* this allows input buffer "traveling" in Hebrew mode
|
|
*/
|
|
void BX_set_input_heb (char *str)
|
|
{
|
|
strlcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* get_input: returns a pointer to the input buffer. Changing this will
|
|
* actually change the input buffer. This is a bad way to change the input
|
|
* buffer tho, cause no bounds checking won't be done
|
|
*/
|
|
char *BX_get_input (void)
|
|
{
|
|
return (&(MIN_CHAR));
|
|
}
|
|
|
|
/* init_input: initialized the input buffer by clearing it out */
|
|
extern void init_input (void)
|
|
{
|
|
*INPUT_BUFFER = (char) 0;
|
|
THIS_POS = MIN_POS;
|
|
}
|
|
|
|
/* get_input_prompt: returns the current input_prompt */
|
|
extern char *BX_get_input_prompt (void)
|
|
{
|
|
return input_prompt;
|
|
}
|
|
|
|
/*
|
|
* set_input_prompt: sets a prompt that will be displayed in the input
|
|
* buffer. This prompt cannot be backspaced over, etc. It's a prompt.
|
|
* Setting the prompt to null uses no prompt
|
|
*/
|
|
void BX_set_input_prompt (Window *win, char *prompt, int unused)
|
|
{
|
|
if (prompt)
|
|
malloc_strcpy(&input_prompt, prompt);
|
|
else if (input_prompt)
|
|
malloc_strcpy(&input_prompt, empty_string);
|
|
else
|
|
return;
|
|
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Why did i put these in this file? I dunno. But i do know that the ones
|
|
* in edit.c didnt have to be here, and i knew the ones that were here DID
|
|
* have to be here, so i just moved them all to here, so that they would all
|
|
* be in the same place. Easy enough. (jfn, june 1995)
|
|
*/
|
|
|
|
/*
|
|
* input_forward_word: move the input cursor forward one word in the input
|
|
* line
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_forward_word)
|
|
{
|
|
cursor_to_input();
|
|
|
|
while ((my_isspace(THIS_CHAR) || ispunct((unsigned char)THIS_CHAR)) && (THIS_CHAR))
|
|
THIS_POS++;
|
|
while (!(ispunct((unsigned char)THIS_CHAR) || my_isspace(THIS_CHAR)) && (THIS_CHAR))
|
|
THIS_POS++;
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
|
|
/* input_backward_word: move the cursor left on word in the input line */
|
|
BUILT_IN_KEYBINDING(input_backward_word)
|
|
{
|
|
cursor_to_input();
|
|
while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct((unsigned char)PREV_CHAR)))
|
|
THIS_POS--;
|
|
while ((THIS_POS > MIN_POS) && !(ispunct((unsigned char)PREV_CHAR) || my_isspace(PREV_CHAR)))
|
|
THIS_POS--;
|
|
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
|
|
/* inPut_delete_character: deletes a character from the input line */
|
|
BUILT_IN_KEYBINDING(input_delete_character)
|
|
{
|
|
int pos;
|
|
cursor_to_input();
|
|
in_completion = STATE_NORMAL;
|
|
if (!THIS_CHAR)
|
|
return;
|
|
ov_strcpy(&THIS_CHAR, &NEXT_CHAR);
|
|
if (!(termfeatures & TERM_CAN_DELETE))
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
else
|
|
{
|
|
term_delete(1);
|
|
pos = INPUT_ONSCREEN + last_input_screen->co - 1;
|
|
if (pos < strlen(INPUT_BUFFER))
|
|
{
|
|
term_move_cursor(last_input_screen->co - 1, INPUT_LINE);
|
|
term_putchar(INPUT_BUFFER[pos]);
|
|
term_move_cursor(INPUT_CURSOR, INPUT_LINE);
|
|
}
|
|
update_input(NO_UPDATE);
|
|
}
|
|
}
|
|
|
|
/* input_backspace: does a backspace in the input buffer */
|
|
BUILT_IN_KEYBINDING(input_backspace)
|
|
{
|
|
cursor_to_input();
|
|
if (THIS_POS > MIN_POS)
|
|
{
|
|
char *ptr = NULL;
|
|
int pos;
|
|
|
|
ptr = LOCAL_COPY(&THIS_CHAR);
|
|
strcpy(&(PREV_CHAR), ptr);
|
|
THIS_POS--;
|
|
term_cursor_left();
|
|
if (THIS_CHAR)
|
|
{
|
|
if (!(termfeatures & TERM_CAN_DELETE))
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
else
|
|
{
|
|
term_delete(1);
|
|
pos = INPUT_ONSCREEN + last_input_screen->co - 1;
|
|
/*
|
|
* If the prompt is visible right now,
|
|
* then we have to cope with that.
|
|
*/
|
|
if (START_ZONE == WIDTH)
|
|
pos -= INPUT_PROMPT_LEN;
|
|
if (pos < strlen(INPUT_BUFFER))
|
|
{
|
|
term_move_cursor(last_input_screen->co - 1, INPUT_LINE);
|
|
term_putchar(INPUT_BUFFER[pos]);
|
|
}
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
term_putchar(' ');
|
|
#ifndef __EMX__
|
|
term_cursor_left();
|
|
update_input(NO_UPDATE);
|
|
#else
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
#endif
|
|
}
|
|
}
|
|
if (THIS_POS == MIN_POS)
|
|
HOLDLAST = NULL;
|
|
in_completion = STATE_NORMAL;
|
|
*new_nick = 0;
|
|
}
|
|
|
|
/*
|
|
* input_beginning_of_line: moves the input cursor to the first character in
|
|
* the input buffer
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_beginning_of_line)
|
|
{
|
|
cursor_to_input();
|
|
THIS_POS = MIN_POS;
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
|
|
/*
|
|
* input_beginning_of_line: moves the input cursor to the first character in
|
|
* the input buffer
|
|
*/
|
|
BUILT_IN_KEYBINDING(new_input_beginning_of_line)
|
|
{
|
|
cursor_to_input();
|
|
THIS_POS = MIN_POS;
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
/*
|
|
* input_end_of_line: moves the input cursor to the last character in the
|
|
* input buffer
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_end_of_line)
|
|
{
|
|
cursor_to_input();
|
|
THIS_POS = strlen(INPUT_BUFFER);
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(input_delete_to_previous_space)
|
|
{
|
|
int old_pos;
|
|
|
|
cursor_to_input();
|
|
old_pos = THIS_POS;
|
|
|
|
while (!my_isspace(THIS_CHAR) && THIS_POS >= MIN_POS)
|
|
THIS_POS--;
|
|
|
|
if (THIS_POS < old_pos)
|
|
{
|
|
strcpy(&(NEXT_CHAR), &(INPUT_BUFFER[old_pos]));
|
|
THIS_POS++;
|
|
}
|
|
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
}
|
|
|
|
|
|
/*
|
|
* input_delete_previous_word: deletes from the cursor backwards to the next
|
|
* space character.
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_delete_previous_word)
|
|
{
|
|
int old_pos;
|
|
char c;
|
|
|
|
cursor_to_input();
|
|
old_pos = THIS_POS;
|
|
while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct((unsigned char)PREV_CHAR)))
|
|
THIS_POS--;
|
|
while ((THIS_POS > MIN_POS) && !(ispunct((unsigned char)PREV_CHAR) || my_isspace(PREV_CHAR)))
|
|
THIS_POS--;
|
|
c = INPUT_BUFFER[old_pos];
|
|
INPUT_BUFFER[old_pos] = (char) 0;
|
|
malloc_strcpy(&cut_buffer, &THIS_CHAR);
|
|
INPUT_BUFFER[old_pos] = c;
|
|
strcpy(&(THIS_CHAR), &(INPUT_BUFFER[old_pos]));
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
}
|
|
|
|
/*
|
|
* input_delete_next_word: deletes from the cursor to the end of the next
|
|
* word
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_delete_next_word)
|
|
{
|
|
int pos;
|
|
char *ptr = NULL,
|
|
c;
|
|
|
|
cursor_to_input();
|
|
pos = THIS_POS;
|
|
while ((my_isspace(INPUT_BUFFER[pos]) || ispunct((unsigned char)INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
|
|
pos++;
|
|
while (!(ispunct((unsigned char)INPUT_BUFFER[pos]) || my_isspace(INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
|
|
pos++;
|
|
c = INPUT_BUFFER[pos];
|
|
INPUT_BUFFER[pos] = (char) 0;
|
|
malloc_strcpy(&cut_buffer, &(THIS_CHAR));
|
|
INPUT_BUFFER[pos] = c;
|
|
malloc_strcpy(&ptr, &(INPUT_BUFFER[pos]));
|
|
strcpy(&(THIS_CHAR), ptr);
|
|
new_free(&ptr);
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
}
|
|
|
|
/*
|
|
* input_add_character: adds the character c to the input buffer, repecting
|
|
* the current overwrite/insert mode status, etc
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_add_character)
|
|
{
|
|
int display_flag = NO_UPDATE;
|
|
|
|
if (last_input_screen->promptlist)
|
|
term_echo(last_input_screen->promptlist->echo);
|
|
|
|
cursor_to_input();
|
|
if (THIS_POS >= INPUT_BUFFER_SIZE)
|
|
{
|
|
term_echo(1);
|
|
return;
|
|
}
|
|
|
|
if (get_int_var(INSERT_MODE_VAR))
|
|
{
|
|
if (THIS_CHAR)
|
|
{
|
|
char *ptr = NULL;
|
|
|
|
ptr = LOCAL_COPY(&(THIS_CHAR));
|
|
THIS_CHAR = key;
|
|
NEXT_CHAR = 0;
|
|
ADD_TO_INPUT(ptr);
|
|
if (termfeatures & TERM_CAN_INSERT)
|
|
term_insert(key);
|
|
else
|
|
{
|
|
term_putchar(key);
|
|
if (NEXT_CHAR)
|
|
display_flag = UPDATE_FROM_CURSOR;
|
|
else
|
|
display_flag = NO_UPDATE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
THIS_CHAR = key;
|
|
NEXT_CHAR = 0;
|
|
term_putchar(key);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (THIS_CHAR == 0)
|
|
NEXT_CHAR = 0;
|
|
THIS_CHAR = key;
|
|
term_putchar(key);
|
|
}
|
|
|
|
if (!THIS_POS)
|
|
HOLDLAST = current_window->display_ip;
|
|
THIS_POS++;
|
|
#ifdef GUI
|
|
gui_flush();
|
|
#endif
|
|
update_input(display_flag);
|
|
if (in_completion == STATE_COMPLETE && key == ' ' && input_lastmsg)
|
|
{
|
|
new_free(&input_lastmsg);
|
|
*new_nick = 0;
|
|
in_completion = STATE_NORMAL;
|
|
}
|
|
term_echo(1);
|
|
}
|
|
|
|
/* input_clear_to_eol: erases from the cursor to the end of the input buffer */
|
|
BUILT_IN_KEYBINDING(input_clear_to_eol)
|
|
{
|
|
cursor_to_input();
|
|
malloc_strcpy(&cut_buffer, &(THIS_CHAR));
|
|
THIS_CHAR = 0;
|
|
term_clear_to_eol();
|
|
update_input(NO_UPDATE);
|
|
}
|
|
|
|
/*
|
|
* input_clear_to_bol: clears from the cursor to the beginning of the input
|
|
* buffer
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_clear_to_bol)
|
|
{
|
|
char *ptr = NULL;
|
|
cursor_to_input();
|
|
malloc_strcpy(&cut_buffer, &(MIN_CHAR));
|
|
cut_buffer[THIS_POS - MIN_POS] = (char) 0;
|
|
malloc_strcpy(&ptr, &(THIS_CHAR));
|
|
MIN_CHAR = (char) 0;
|
|
ADD_TO_INPUT(ptr);
|
|
new_free(&ptr);
|
|
THIS_POS = MIN_POS;
|
|
term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
|
|
term_clear_to_eol();
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
}
|
|
|
|
/*
|
|
* input_clear_line: clears entire input line
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_clear_line)
|
|
{
|
|
cursor_to_input();
|
|
malloc_strcpy(&cut_buffer, INPUT_BUFFER + MIN_POS);
|
|
MIN_CHAR = (char) 0;
|
|
THIS_POS = MIN_POS;
|
|
term_move_cursor(INPUT_PROMPT_LEN, INPUT_LINE);
|
|
term_clear_to_eol();
|
|
update_input(NO_UPDATE);
|
|
}
|
|
|
|
/*
|
|
* input_transpose_characters: swaps the positions of the two characters
|
|
* before the cursor position
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_transpose_characters)
|
|
{
|
|
cursor_to_input();
|
|
if (last_input_screen->buffer_pos > MIN_POS)
|
|
{
|
|
u_char c1[3] = { 0 };
|
|
int pos, end_of_line = 0;
|
|
|
|
if (THIS_CHAR)
|
|
pos = THIS_POS;
|
|
else if (strlen(get_input()) > MIN_POS + 2)
|
|
{
|
|
pos = THIS_POS - 1;
|
|
end_of_line = 1;
|
|
}
|
|
else
|
|
return;
|
|
|
|
c1[0] = INPUT_BUFFER[pos];
|
|
c1[1] = INPUT_BUFFER[pos] = INPUT_BUFFER[pos - 1];
|
|
INPUT_BUFFER[pos - 1] = c1[0];
|
|
term_cursor_left();
|
|
if (end_of_line)
|
|
term_cursor_left();
|
|
|
|
term_putchar(c1[0]);
|
|
term_putchar(c1[1]);
|
|
if (!end_of_line)
|
|
term_cursor_left();
|
|
update_input(NO_UPDATE);
|
|
}
|
|
}
|
|
|
|
|
|
BUILT_IN_KEYBINDING(refresh_inputline)
|
|
{
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
/*
|
|
* input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
|
|
* into the input line
|
|
*/
|
|
BUILT_IN_KEYBINDING(input_yank_cut_buffer)
|
|
{
|
|
char *ptr = NULL;
|
|
|
|
if (cut_buffer)
|
|
{
|
|
malloc_strcpy(&ptr, &(THIS_CHAR));
|
|
/* Ooops... */
|
|
THIS_CHAR = 0;
|
|
ADD_TO_INPUT(cut_buffer);
|
|
ADD_TO_INPUT(ptr);
|
|
new_free(&ptr);
|
|
update_input(UPDATE_FROM_CURSOR);
|
|
THIS_POS += strlen(cut_buffer);
|
|
if (THIS_POS > INPUT_BUFFER_SIZE)
|
|
THIS_POS = INPUT_BUFFER_SIZE;
|
|
update_input(UPDATE_JUST_CURSOR);
|
|
}
|
|
}
|
|
|
|
|
|
/* used with input_move_cursor */
|
|
#define RIGHT 1
|
|
#define LEFT 0
|
|
|
|
/* BIND functions: */
|
|
BUILT_IN_KEYBINDING(forward_character)
|
|
{
|
|
input_move_cursor(RIGHT);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(backward_character)
|
|
{
|
|
input_move_cursor(LEFT);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(backward_history)
|
|
{
|
|
get_history(PREV);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(forward_history)
|
|
{
|
|
get_history(NEXT);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(toggle_insert_mode)
|
|
{
|
|
int tog = get_int_var(INSERT_MODE_VAR);
|
|
tog ^= 1;
|
|
set_int_var(INSERT_MODE_VAR, tog);
|
|
}
|
|
|
|
|
|
BUILT_IN_KEYBINDING(input_msgreply)
|
|
{
|
|
char *cmdchar;
|
|
char *line, *cmd, *t;
|
|
char *snick;
|
|
NickTab *nick = NULL;
|
|
int got_space = 0;
|
|
|
|
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
|
|
cmdchar = DEFAULT_CMDCHARS;
|
|
|
|
t = line = m_strdup(get_input());
|
|
if (t)
|
|
got_space = strchr(t, ' ') ? 1 : 0;
|
|
cmd = next_arg(line, &line);
|
|
snick = next_arg(line, &line);
|
|
if ((cmd && *cmd == *cmdchar && got_space) || !cmd)
|
|
{
|
|
|
|
if (cmd && *cmd == *cmdchar)
|
|
cmd++;
|
|
if (in_completion == STATE_NORMAL && snick)
|
|
strncpy(new_nick, snick, sizeof(new_nick)-1);
|
|
|
|
if ((nick = getnextnick(0, new_nick, input_lastmsg, snick)))
|
|
{
|
|
if (nick->nick && *(nick->nick))
|
|
{
|
|
snick = nick->nick;
|
|
malloc_strcpy(&input_lastmsg, nick->nick);
|
|
}
|
|
}
|
|
if (nick)
|
|
{
|
|
char *tmp = NULL;
|
|
input_clear_line('\0', NULL);
|
|
if (fget_string_var(FORMAT_NICK_MSG_FSET))
|
|
malloc_strcpy(&tmp, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_MSG_FSET), "%s%s %s %s", cmdchar, nick->type ? nick->type:cmd?cmd:"msg", nick->nick, line?line:empty_string)));
|
|
else
|
|
malloc_sprintf(&tmp, "%s%s %s %s", cmdchar, nick->type?nick->type:cmd?cmd:"msg", nick->nick, line?line:empty_string);
|
|
set_input(tmp);
|
|
new_free(&tmp);
|
|
} else
|
|
command_completion(0, NULL);
|
|
}
|
|
else
|
|
command_completion(0, NULL);
|
|
update_input(UPDATE_ALL);
|
|
new_free(&t);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(input_msgreplyback)
|
|
{
|
|
#if 0
|
|
char *tmp = NULL;
|
|
char *cmdchar;
|
|
tmp = gettabkey(-1, 0, NULL);
|
|
if (tmp && *tmp)
|
|
{
|
|
char *tmp1 = NULL;
|
|
input_clear_line('\0', NULL);
|
|
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
|
|
cmdchar = DEFAULT_CMDCHARS;
|
|
if (fget_string_var(FORMAT_NICK_MSG_FSET))
|
|
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_MSG_FSET), "%cmsg %s", *cmdchar, tmp)));
|
|
else
|
|
malloc_sprintf(&tmp1, "%cmsg %s ", *cmdchar, tmp);
|
|
set_input(tmp1);
|
|
new_free(&tmp1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void add_autonick_input(char *nick, char *line)
|
|
{
|
|
char *tmp1 = NULL;
|
|
input_clear_line('\0', NULL);
|
|
if ((do_hook(REPLY_AR_LIST, "%s", nick)))
|
|
{
|
|
if (fget_string_var(FORMAT_NICK_AUTO_FSET))
|
|
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_AUTO_FSET), "%s %s", nick, line?line:empty_string)));
|
|
else
|
|
malloc_sprintf(&tmp1, "%s\002:\002 %s" , nick, line);
|
|
set_input(tmp1);
|
|
new_free(&tmp1);
|
|
}
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(input_autoreply)
|
|
{
|
|
char *tmp = NULL, *q;
|
|
char *nick = NULL;
|
|
char *line = NULL;
|
|
|
|
q = line = m_strdup(&last_input_screen->input_buffer[MIN_POS]);
|
|
if ((nick = next_arg(line, &line)))
|
|
{
|
|
if ((tmp = strrchr(nick, ':')))
|
|
*tmp = 0;
|
|
if ((tmp = strrchr(nick, '\002')))
|
|
*tmp = 0;
|
|
}
|
|
if (!input_lastmsg)
|
|
{
|
|
NickTab *t;
|
|
t = gettabkey(1, 1, nick);
|
|
if (*new_nick && !tmp)
|
|
t = gettabkey(1,1,new_nick);
|
|
if (t)
|
|
tmp = t->nick;
|
|
}
|
|
if (tmp && *tmp)
|
|
{
|
|
add_autonick_input(tmp, line);
|
|
strcpy(new_nick, tmp);
|
|
}
|
|
else
|
|
{
|
|
tmp = getchannick(input_lastmsg, nick);
|
|
if (*new_nick && !tmp)
|
|
tmp = getchannick(input_lastmsg, new_nick);
|
|
if (tmp)
|
|
{
|
|
add_autonick_input(tmp, line);
|
|
strcpy(new_nick, tmp);
|
|
}
|
|
}
|
|
malloc_strcpy(&input_lastmsg, nick);
|
|
in_completion = STATE_COMPLETE;
|
|
new_free(&q);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(input_autoreplyback)
|
|
{
|
|
#if 0
|
|
char *tmp = NULL;
|
|
tmp = gettabkey(-1, 1, NULL);
|
|
if (tmp && *tmp)
|
|
{
|
|
char *tmp1 = NULL;
|
|
input_clear_line('\0', NULL);
|
|
if ((do_hook(AR_REPLY_LIST, "%s", tmp)))
|
|
{
|
|
if (fget_int_var(FORMAT_NICK_AUTO_FSET))
|
|
malloc_strcpy(&tmp1, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_AUTO_FSET), "%s", tmp)));
|
|
else
|
|
malloc_sprintf(&tmp1, "%s\002:\002", tmp);
|
|
set_input(tmp1);
|
|
new_free(&tmp1);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
NickList *BX_lookup_nickcompletion(ChannelList *chan, char *possible)
|
|
{
|
|
NickList *nick, *ntmp = NULL, *bestmatch = NULL;
|
|
for (nick = next_nicklist(chan, NULL); nick; nick = next_nicklist(chan, nick))
|
|
{
|
|
if (!my_stricmp(possible, nick->nick))
|
|
bestmatch = ntmp = nick;
|
|
else if (!my_strnicmp(possible, nick->nick, strlen(possible)))
|
|
ntmp = nick;
|
|
else if (!ntmp && my_strnstr(nick->nick, possible, strlen(possible)))
|
|
ntmp = nick;
|
|
}
|
|
return bestmatch ? bestmatch : ntmp;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(send_line)
|
|
{
|
|
int server;
|
|
WaitPrompt *OldPrompt;
|
|
|
|
server = from_server;
|
|
from_server = get_window_server(0);
|
|
unhold_a_window(last_input_screen->current_window);
|
|
if (last_input_screen->promptlist && last_input_screen->promptlist->type == WAIT_PROMPT_LINE)
|
|
{
|
|
OldPrompt = last_input_screen->promptlist;
|
|
(*OldPrompt->func)(OldPrompt->data, get_input());
|
|
set_input(empty_string);
|
|
last_input_screen->promptlist = OldPrompt->next;
|
|
new_free(&OldPrompt->data);
|
|
new_free(&OldPrompt->prompt);
|
|
new_free((char **)&OldPrompt);
|
|
change_input_prompt(-1);
|
|
}
|
|
else
|
|
{
|
|
char *line,
|
|
*cmdchar,
|
|
*tmp = NULL;
|
|
|
|
line = get_input();
|
|
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
|
|
cmdchar = "/";
|
|
malloc_strcpy(&tmp, line);
|
|
if (line && (*line != *cmdchar) && get_int_var(NICK_COMPLETION_VAR) && !current_window->query_nick)
|
|
{
|
|
char auto_comp_char;
|
|
char *p;
|
|
|
|
/* this is for people with old BitchX.sav files that set it to '\0' */
|
|
if (!(auto_comp_char = (char)get_int_var(NICK_COMPLETION_CHAR_VAR)))
|
|
auto_comp_char = DEFAULT_NICK_COMPLETION_CHAR;
|
|
|
|
/* possible nick completion */
|
|
if ((p = strchr(tmp, auto_comp_char)) && do_hook(NICK_COMP_LIST, "%s", line))
|
|
{
|
|
ChannelList *chan;
|
|
NickList *nick;
|
|
char *channel;
|
|
*p++ = 0;
|
|
if (*tmp && *p && (strlen(tmp) >= get_int_var(NICK_COMPLETION_LEN_VAR) && (channel = get_current_channel_by_refnum(0))))
|
|
{
|
|
chan = lookup_channel(channel, from_server, 0);
|
|
nick = lookup_nickcompletion(chan, tmp);
|
|
if (nick)
|
|
{
|
|
if (fget_string_var(FORMAT_NICK_COMP_FSET))
|
|
malloc_strcpy(&tmp, stripansicodes(convert_output_format(fget_string_var(FORMAT_NICK_COMP_FSET), "%s %s", nick->nick, p)));
|
|
else
|
|
malloc_sprintf(&tmp, "%s\002%c\002%s", nick->nick, auto_comp_char, p);
|
|
} else
|
|
malloc_strcpy(&tmp, line);
|
|
} else
|
|
malloc_strcpy(&tmp, line);
|
|
}
|
|
}
|
|
set_input(empty_string);
|
|
update_input(UPDATE_ALL);
|
|
reset_display_target();
|
|
#ifdef WANT_TCL
|
|
|
|
if (!check_tcl_input(tmp) && do_hook(INPUT_LIST, "%s", tmp))
|
|
#else
|
|
if (do_hook(INPUT_LIST, "%s", tmp))
|
|
#endif
|
|
{
|
|
if (get_int_var(INPUT_ALIASES_VAR))
|
|
parse_line(NULL, tmp, empty_string, 1, 0, 1);
|
|
else
|
|
parse_line(NULL, tmp, NULL, 1, 0, 1);
|
|
}
|
|
new_free(&tmp);
|
|
}
|
|
new_free(&input_lastmsg);
|
|
*new_nick = 0;
|
|
in_completion = STATE_NORMAL;
|
|
HOLDLAST = NULL;
|
|
from_server = server;
|
|
}
|
|
|
|
#define METAX(x) \
|
|
BUILT_IN_KEYBINDING( meta ## x ## _char ) \
|
|
{ last_input_screen->meta_hit = (x); }
|
|
METAX(39) METAX(38) METAX(37) METAX(36) METAX(35)
|
|
METAX(34) METAX(33) METAX(32) METAX(31) METAX(30)
|
|
METAX(29) METAX(28) METAX(27) METAX(26) METAX(25)
|
|
METAX(24) METAX(23) METAX(22) METAX(21) METAX(20)
|
|
METAX(19) METAX(18) METAX(17) METAX(16) METAX(15)
|
|
METAX(14) METAX(13) METAX(12) METAX(11) METAX(10)
|
|
METAX(9) METAX(8) METAX(7) METAX(6) METAX(5)
|
|
METAX(3) METAX(2) METAX(1)
|
|
|
|
|
|
BUILT_IN_KEYBINDING(meta4_char)
|
|
{
|
|
if (last_input_screen->meta_hit == 4)
|
|
last_input_screen->meta_hit = 0;
|
|
else
|
|
last_input_screen->meta_hit = 4;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(quote_char)
|
|
{
|
|
last_input_screen->quote_hit = 1;
|
|
}
|
|
|
|
/* These four functions are boomerang functions, which allow the highlight
|
|
* characters to be bound by simply having these functions put in the
|
|
* appropriate characters when you press any key to which you have bound
|
|
* that highlight character. >;-)
|
|
*/
|
|
BUILT_IN_KEYBINDING(insert_bold)
|
|
{
|
|
input_add_character (BOLD_TOG, string);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(insert_reverse)
|
|
{
|
|
input_add_character (REV_TOG, string);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(insert_underline)
|
|
{
|
|
input_add_character (UND_TOG, string);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(highlight_off)
|
|
{
|
|
input_add_character (ALL_OFF, string);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(insert_blink)
|
|
{
|
|
input_add_character (BLINK_TOG, string);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(insert_altcharset)
|
|
{
|
|
input_add_character (ALT_TOG, string);
|
|
}
|
|
|
|
/* type_text: the BIND function TYPE_TEXT */
|
|
BUILT_IN_KEYBINDING(type_text)
|
|
{
|
|
if (!string)
|
|
return;
|
|
for (; *string; string++)
|
|
input_add_character(*string, empty_string);
|
|
}
|
|
|
|
/*
|
|
* clear_screen: the CLEAR_SCREEN function for BIND. Clears the screen and
|
|
* starts it if it is held
|
|
*/
|
|
BUILT_IN_KEYBINDING(clear_screen)
|
|
{
|
|
set_hold_mode(NULL, OFF, 1);
|
|
clear_window_by_refnum(0);
|
|
}
|
|
|
|
/* parse_text: the bindable function that executes its string */
|
|
BUILT_IN_KEYBINDING(parse_text)
|
|
{
|
|
parse_line(NULL, string, empty_string, 0, 0, 1);
|
|
}
|
|
|
|
/*
|
|
* edit_char: handles each character for an input stream. Not too difficult
|
|
* to work out.
|
|
*/
|
|
void edit_char(char key)
|
|
{
|
|
void (*func) (char, char *) = NULL;
|
|
char *ptr = NULL;
|
|
u_char extended_key;
|
|
WaitPrompt *oldprompt;
|
|
int xxx_return = 0;
|
|
|
|
if (dumb_mode)
|
|
{
|
|
#ifdef TIOCSTI
|
|
ioctl(0, TIOCSTI, &key);
|
|
#else
|
|
say("Sorry, your system doesnt support 'faking' user input...");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* were we waiting for a keypress? */
|
|
if (last_input_screen->promptlist && last_input_screen->promptlist->type == WAIT_PROMPT_KEY)
|
|
{
|
|
char key_[2] = { key, 0 };
|
|
oldprompt = last_input_screen->promptlist;
|
|
last_input_screen->promptlist = oldprompt->next;
|
|
(*oldprompt->func)(oldprompt->data, key_);
|
|
new_free(&oldprompt->data);
|
|
new_free(&oldprompt->prompt);
|
|
new_free((char **)&oldprompt);
|
|
set_input(empty_string);
|
|
change_input_prompt(-1);
|
|
xxx_return = 1;
|
|
}
|
|
if (last_input_screen->promptlist &&
|
|
last_input_screen->promptlist->type == WAIT_PROMPT_DUMMY)
|
|
{
|
|
oldprompt = last_input_screen->promptlist;
|
|
(*oldprompt->func)(oldprompt->data, NULL);
|
|
last_input_screen->promptlist = oldprompt->next;
|
|
new_free(&oldprompt->data);
|
|
new_free(&oldprompt->prompt);
|
|
new_free((char **)&oldprompt);
|
|
}
|
|
|
|
if (xxx_return)
|
|
return;
|
|
|
|
#if __bsdi__
|
|
if (key & 0x80)
|
|
{
|
|
if (meta_mode)
|
|
{
|
|
edit_char('\033');
|
|
key &= ~0x80;
|
|
}
|
|
else if (!term_eight_bit())
|
|
key &= ~0x80;
|
|
}
|
|
#endif
|
|
|
|
#ifdef TRANSLATE
|
|
if (translation)
|
|
extended_key = transFromClient[(unsigned char)key];
|
|
else
|
|
#endif
|
|
extended_key = key;
|
|
|
|
|
|
#ifdef __EMX__
|
|
if (key == 0)
|
|
key = 27;
|
|
#endif
|
|
|
|
/* did we just hit the quote character? */
|
|
if (last_input_screen->quote_hit)
|
|
{
|
|
last_input_screen->quote_hit = 0;
|
|
input_add_character(extended_key, empty_string);
|
|
}
|
|
else
|
|
{
|
|
int m = last_input_screen->meta_hit;
|
|
int i;
|
|
|
|
if ((i = get_binding(m, key, &func, &ptr)))
|
|
last_input_screen->meta_hit = i;
|
|
else if (last_input_screen->meta_hit != 4)
|
|
last_input_screen->meta_hit = 0;
|
|
if (func)
|
|
func(extended_key, SAFE(ptr));
|
|
}
|
|
}
|
|
|
|
#ifdef GUI
|
|
BUILT_IN_KEYBINDING(paste_to_input)
|
|
{
|
|
/* Try calling this directly ... */
|
|
parse_line(NULL, "//pmpaste -input", NULL, 0, 0, 1);
|
|
}
|
|
#endif
|
|
|
|
BUILT_IN_KEYBINDING(my_scrollback)
|
|
{
|
|
scrollback_backwards(key, string);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(my_scrollforward)
|
|
{
|
|
scrollback_forwards(key, string);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(my_scrollend)
|
|
{
|
|
scrollback_end(key, string);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
#ifdef WANT_CHELP
|
|
BUILT_IN_KEYBINDING(do_chelp)
|
|
{
|
|
chelp(NULL, "INDEX", NULL, NULL);
|
|
extended_handled = 1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WANT_CDCC
|
|
BUILT_IN_KEYBINDING(cdcc_plist)
|
|
{
|
|
l_plist(NULL, NULL);
|
|
extended_handled = 1;
|
|
}
|
|
#endif
|
|
|
|
BUILT_IN_KEYBINDING(dcc_plist)
|
|
{
|
|
dcc_glist(NULL, NULL);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(toggle_cloak)
|
|
{
|
|
if (get_int_var(CLOAK_VAR) == 1 || get_int_var(CLOAK_VAR) == 2)
|
|
set_int_var(CLOAK_VAR, 0);
|
|
else
|
|
set_int_var(CLOAK_VAR, 1);
|
|
put_it("CTCP Cloaking is now [\002%s\002]", on_off(get_int_var(CLOAK_VAR)));
|
|
extended_handled = 1;
|
|
}
|
|
|
|
|
|
extern int in_window_command;
|
|
|
|
static void handle_swap(int windownum)
|
|
{
|
|
char *p = NULL;
|
|
malloc_sprintf(&p, "SWAP %d", windownum);
|
|
windowcmd(NULL, p, NULL, NULL);
|
|
set_channel_window(current_window, get_current_channel_by_refnum(current_window->refnum), current_window->server);
|
|
new_free(&p);
|
|
set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
|
|
target_window = NULL;
|
|
update_input(UPDATE_ALL);
|
|
update_all_windows();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap1)
|
|
{
|
|
handle_swap(1);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap2)
|
|
{
|
|
handle_swap(2);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap3)
|
|
{
|
|
handle_swap(3);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap4)
|
|
{
|
|
handle_swap(4);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap5)
|
|
{
|
|
handle_swap(5);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap6)
|
|
{
|
|
handle_swap(6);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_swap7)
|
|
{
|
|
handle_swap(7);
|
|
extended_handled = 1;
|
|
}
|
|
BUILT_IN_KEYBINDING(window_swap8)
|
|
{
|
|
handle_swap(8);
|
|
extended_handled = 1;
|
|
}
|
|
BUILT_IN_KEYBINDING(window_swap9)
|
|
{
|
|
handle_swap(9);
|
|
extended_handled = 1;
|
|
}
|
|
BUILT_IN_KEYBINDING(window_swap10)
|
|
{
|
|
handle_swap(10);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(channel_chops)
|
|
{
|
|
users("chops", "-ops", NULL, NULL);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(channel_nonops)
|
|
{
|
|
users("nops", "-nonops", NULL, NULL);
|
|
extended_handled = 1;
|
|
}
|
|
|
|
#ifdef WANT_CHELP
|
|
BUILT_IN_KEYBINDING(w_help)
|
|
{
|
|
chelp(NULL, "WINDOW", NULL, NULL);
|
|
}
|
|
#endif
|
|
|
|
BUILT_IN_KEYBINDING(change_to_split)
|
|
{
|
|
extern char *last_split_server;
|
|
if (!last_split_server)
|
|
return;
|
|
servercmd(NULL, last_split_server, NULL, NULL);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(join_last_invite)
|
|
{
|
|
if (invite_channel)
|
|
{
|
|
if (!in_join_list(invite_channel, from_server))
|
|
{
|
|
win_create(JOIN_NEW_WINDOW_VAR, 0);
|
|
send_to_server("JOIN %s", invite_channel);
|
|
new_free(&invite_channel);
|
|
}
|
|
else
|
|
bitchsay("Already joining %s", invite_channel);
|
|
}
|
|
else
|
|
bitchsay("You haven't been invited to a channel yet");
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(wholeft)
|
|
{
|
|
show_wholeft(NULL);
|
|
}
|
|
|
|
static int oiwc;
|
|
static int osu;
|
|
|
|
BUILT_IN_KEYBINDING(window_key_balance)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
rebalance_windows(current_window->screen);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_grow_one)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
resize_window(1, current_window, 1);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_key_hide)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
hide_window(current_window);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_key_kill)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
delete_window(current_window);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_key_list)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
window_list(current_window, NULL, NULL);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_key_move)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
move_window(current_window, 1);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(window_shrink_one)
|
|
{
|
|
oiwc = in_window_command;
|
|
osu = status_update_flag;
|
|
in_window_command = 1;
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
resize_window(1, current_window, -1);
|
|
in_window_command = oiwc;
|
|
status_update_flag = osu;
|
|
update_all_windows();
|
|
update_all_status(current_window, NULL, 0);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(dcc_ostats)
|
|
{
|
|
set_display_target(NULL, LOG_CURRENT);
|
|
extended_handled = 1;
|
|
dcc_stats(NULL, NULL);
|
|
reset_display_target();
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(cpu_saver_on)
|
|
{
|
|
cpu_saver = 1;
|
|
update_all_status(current_window, NULL, 0);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(input_unclear_screen)
|
|
{
|
|
set_hold_mode(NULL, OFF, 1);
|
|
unclear_window_by_refnum(0);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(ignore_last_nick)
|
|
{
|
|
NickTab *nick;
|
|
char *tmp1;
|
|
if ((nick = gettabkey(1, 0, NULL)))
|
|
{
|
|
set_input(empty_string);
|
|
tmp1 = m_sprintf("%sig %s", get_string_var(CMDCHARS_VAR), nick->nick);
|
|
set_input(tmp1);
|
|
new_free(&tmp1);
|
|
}
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(nick_completion)
|
|
{
|
|
char *q, *line;
|
|
int i = -1;
|
|
char *nick = NULL, *tmp;
|
|
|
|
q = line = m_strdup(&last_input_screen->input_buffer[MIN_POS]);
|
|
if (in_completion == STATE_NORMAL)
|
|
{
|
|
i = word_count(line);
|
|
nick = extract(line, i-1, i);
|
|
}
|
|
if (nick)
|
|
line[strlen(line)-strlen(nick)] = 0;
|
|
else
|
|
*line = 0;
|
|
if ((tmp = getchannick(input_lastmsg, nick && *nick ? nick : NULL)))
|
|
{
|
|
malloc_strcat(&q, tmp);
|
|
set_input(q);
|
|
update_input(UPDATE_ALL);
|
|
malloc_strcpy(&input_lastmsg, tmp);
|
|
in_completion = STATE_COMPLETE;
|
|
}
|
|
new_free(&q);
|
|
new_free(&nick);
|
|
}
|
|
|
|
char *BX_getchannick (char *oldnick, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
char *channel, *tnick = NULL;
|
|
NickList *cnick;
|
|
channel = get_current_channel_by_refnum(0);
|
|
if (channel)
|
|
{
|
|
if (!(chan = lookup_channel(channel, from_server, 0)) || !(cnick = next_nicklist(chan, NULL)))
|
|
{
|
|
in_completion = STATE_NORMAL;
|
|
return NULL;
|
|
}
|
|
/*
|
|
* we've never been here before so return first nick
|
|
* user hasn't entered anything on the line.
|
|
*/
|
|
if (!oldnick && !nick && cnick)
|
|
{
|
|
in_completion = STATE_CNICK;
|
|
return cnick->nick;
|
|
}
|
|
/*
|
|
* user has been here before so we attempt to find the correct
|
|
* first nick to start from.
|
|
*/
|
|
if (oldnick)
|
|
{
|
|
/* find the old nick so we have a frame of reference */
|
|
for(cnick = next_nicklist(chan, NULL); cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (!my_strnicmp(cnick->nick, oldnick, strlen(oldnick)))
|
|
{
|
|
tnick = cnick->nick;
|
|
if ((cnick = next_nicklist(chan, cnick)))
|
|
tnick = cnick->nick;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
/*
|
|
* if the user has put something on the line
|
|
* we attempt to pattern match here.
|
|
*/
|
|
if (nick && in_completion == STATE_NORMAL)
|
|
{
|
|
/*
|
|
* if oldnick was the last one in the channel
|
|
* cnick will be NULL;
|
|
*/
|
|
if (!cnick)
|
|
{
|
|
cnick = next_nicklist(chan, NULL);
|
|
tnick = cnick->nick;
|
|
}
|
|
/* we have a new nick */
|
|
else if (next_nicklist(chan, cnick))
|
|
{
|
|
/*
|
|
* if there's more than one nick, start
|
|
* scanning.
|
|
*/
|
|
for (; cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
#if 1
|
|
if (!my_strnicmp(cnick->nick, nick, strlen(nick)) || my_strnstr(cnick->nick, nick, strlen(nick)))
|
|
#else
|
|
if (!my_strnicmp(cnick->nick, nick, strlen(nick)))
|
|
#endif
|
|
{
|
|
tnick = cnick->nick;
|
|
break;
|
|
}
|
|
}
|
|
#if 1
|
|
/* Same as before, make sure bx gets its try w/o ours interfering... */
|
|
|
|
if (!tnick)
|
|
{
|
|
for (; cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (my_strnstr(cnick->nick, nick, strlen(nick)))
|
|
{
|
|
tnick = cnick->nick;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
tnick = cnick->nick;
|
|
}
|
|
else if (in_completion == STATE_CNICK)
|
|
{
|
|
/*
|
|
* else we've been here before so
|
|
* attempt to continue through the nicks
|
|
*/
|
|
if (!cnick)
|
|
cnick = next_nicklist(chan, NULL);
|
|
tnick = cnick->nick;
|
|
}
|
|
}
|
|
if (tnick)
|
|
in_completion = STATE_CNICK;
|
|
|
|
return tnick;
|
|
}
|
|
|
|
/*
|
|
* set which to 1 to access autoreply array.
|
|
* 0 for msglist array
|
|
*/
|
|
|
|
void BX_addtabkey(char *nick, char *type, int which)
|
|
{
|
|
NickTab *tmp, *new;
|
|
|
|
tmp = (which == 1) ? autoreply_array : tabkey_array;
|
|
|
|
if (!tmp || !(new = (NickTab *)remove_from_list((List **)&tmp, nick)))
|
|
{
|
|
new = (NickTab *)new_malloc(sizeof(NickTab));
|
|
malloc_strcpy(&new->nick, nick);
|
|
if (type)
|
|
malloc_strcpy(&new->type, type);
|
|
}
|
|
/*
|
|
* most recent nick is at the top of the list
|
|
*/
|
|
new->next = tmp;
|
|
tmp = new;
|
|
if (which == 1)
|
|
autoreply_array = tmp;
|
|
else
|
|
tabkey_array = tmp;
|
|
}
|
|
|
|
|
|
NickTab *BX_gettabkey(int direction, int which, char *nick)
|
|
{
|
|
NickTab *tmp, *new;
|
|
|
|
|
|
new = tmp = (which == 1) ? autoreply_array : tabkey_array;
|
|
|
|
if (nick)
|
|
{
|
|
for (; tmp; tmp = tmp->next)
|
|
if (!my_strnicmp(nick, tmp->nick, strlen(nick)))
|
|
return tmp;
|
|
return NULL;
|
|
}
|
|
tmp = new;
|
|
if (!tmp)
|
|
return NULL;
|
|
|
|
switch(direction)
|
|
{
|
|
case 1:
|
|
default:
|
|
{
|
|
/*
|
|
* need at least two nicks in the list
|
|
*/
|
|
if (new->next)
|
|
{
|
|
/*
|
|
* reset top of array
|
|
*/
|
|
if (which == 1)
|
|
autoreply_array = new->next;
|
|
else
|
|
tabkey_array = new->next;
|
|
|
|
/*
|
|
* set the current nick next pointer to NULL
|
|
* and then reset top of list.
|
|
*/
|
|
|
|
new->next = NULL;
|
|
if (which == 1)
|
|
tmp = autoreply_array;
|
|
else
|
|
tmp = tabkey_array;
|
|
|
|
/*
|
|
* find the last nick in the list
|
|
* so we can make the old top pointer
|
|
* point to the item
|
|
*/
|
|
while (tmp)
|
|
if (tmp->next)
|
|
tmp = tmp->next;
|
|
else
|
|
break;
|
|
/* set the pointer and then return. */
|
|
tmp->next = new;
|
|
}
|
|
break;
|
|
}
|
|
case -1:
|
|
{
|
|
if (new && new->next)
|
|
{
|
|
tmp = new;
|
|
while(tmp)
|
|
if (tmp->next && tmp->next->next)
|
|
tmp = tmp->next;
|
|
else
|
|
break;
|
|
/*
|
|
* tmp now points at last two items in list
|
|
* now just swap some pointers.
|
|
*/
|
|
new = tmp->next;
|
|
tmp->next = NULL;
|
|
if (which == 1)
|
|
{
|
|
new->next = autoreply_array;
|
|
autoreply_array = new;
|
|
} else {
|
|
new->next = tabkey_array;
|
|
tabkey_array = new;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (new && new->nick)
|
|
return new;
|
|
return NULL;
|
|
}
|
|
|
|
NickTab *BX_getnextnick(int which, char *input_nick, char *oldnick, char *nick)
|
|
{
|
|
ChannelList *chan;
|
|
NickList *cnick = NULL;
|
|
NickTab *tmp = (which == 1) ? autoreply_array : tabkey_array;
|
|
int server = from_server;
|
|
static NickTab sucks = { NULL };
|
|
|
|
if (tmp && (in_completion == STATE_NORMAL || in_completion == STATE_TABKEY))
|
|
{
|
|
if (!oldnick && !nick)
|
|
{
|
|
in_completion = STATE_TABKEY;
|
|
return tmp;
|
|
}
|
|
if (oldnick)
|
|
{
|
|
for (; tmp; tmp = tmp->next)
|
|
{
|
|
if (!my_strnicmp(oldnick, tmp->nick, strlen(oldnick)))
|
|
break;
|
|
}
|
|
/* nick was not in the list. oops didn't come from here */
|
|
if (!tmp && in_completion == STATE_TABKEY)
|
|
tmp = (which == 1) ? autoreply_array : tabkey_array;
|
|
else if (tmp)
|
|
tmp = tmp->next;
|
|
}
|
|
if (nick && in_completion != STATE_TABKEY)
|
|
{
|
|
if (tmp && tmp->next)
|
|
{
|
|
for (; tmp; tmp = tmp->next)
|
|
if (!my_strnicmp(nick, tmp->nick, strlen(nick)))
|
|
break;
|
|
}
|
|
}
|
|
if (tmp)
|
|
{
|
|
in_completion = STATE_TABKEY;
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
if ((chan = prepare_command(&server, NULL, PC_SILENT)))
|
|
{
|
|
cnick = next_nicklist(chan, NULL);
|
|
/*
|
|
* we've never been here before so return first nick
|
|
* user hasn't entered anything on the line.
|
|
*/
|
|
if (!oldnick && !nick && cnick)
|
|
{
|
|
in_completion = STATE_CNICK;
|
|
sucks.nick = cnick->nick;
|
|
return &sucks;
|
|
}
|
|
/*
|
|
* user has been here before so we attempt to find the correct
|
|
* first nick to start from.
|
|
*/
|
|
if (oldnick)
|
|
{
|
|
/* find the old nick so we have a frame of reference */
|
|
for (; cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (!my_strnicmp(cnick->nick, oldnick, strlen(oldnick)))
|
|
{
|
|
cnick = next_nicklist(chan, cnick);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* if the user has put something on the line
|
|
* we attempt to pattern match here.
|
|
*/
|
|
if (input_nick)
|
|
{
|
|
/*
|
|
* if oldnick was the last one in the channel
|
|
* cnick will be NULL;
|
|
*/
|
|
if (!cnick && oldnick)
|
|
cnick = next_nicklist(chan, NULL);
|
|
/* we have a new nick */
|
|
else if (cnick)
|
|
{
|
|
/*
|
|
* if there's more than one nick, start
|
|
* scanning.
|
|
*/
|
|
for (;cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (!my_strnicmp(cnick->nick, input_nick, strlen(input_nick)) || !strcasecmp(cnick->nick, input_nick))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (in_completion == STATE_CNICK)
|
|
{
|
|
/*
|
|
* else we've been here before so
|
|
* attempt to continue through the nicks
|
|
*/
|
|
/*
|
|
if (!cnick)
|
|
cnick = chan->nicks;
|
|
*/
|
|
}
|
|
}
|
|
if (!cnick)
|
|
in_completion = STATE_NORMAL;
|
|
else
|
|
in_completion = STATE_CNICK;
|
|
if (cnick)
|
|
sucks.nick = cnick->nick;
|
|
return sucks.nick ? &sucks : NULL;
|
|
}
|
|
|
|
|
|
#ifdef WANT_TABKEY
|
|
|
|
#define TABDEBUG
|
|
|
|
struct _name_type {
|
|
char name[10];
|
|
int len;
|
|
};
|
|
|
|
struct _name_type
|
|
name_type[] = {
|
|
{"MP3", 3},
|
|
{"DCC", 3},
|
|
{"EXEC",4},
|
|
{"LS", 2},
|
|
{"LOAD",4},
|
|
{"SERVER",6},
|
|
{"CDCC",4},
|
|
{"MSG", 1},
|
|
{"KB", 2},
|
|
{"CD", 2},
|
|
{ "", 0}};
|
|
|
|
enum tab_types { MP3 = 0, DCC, EXEC, LS, LOAD, SERVER, CDCC, IMSG, KB, CHDIR};
|
|
|
|
typedef struct _ext_name_type {
|
|
struct _ext_name_type *next;
|
|
char *name;
|
|
int len;
|
|
enum completion type;
|
|
} Ext_Name_Type;
|
|
|
|
Ext_Name_Type *ext_completion = NULL;
|
|
|
|
char *get_home_dir(char *possible, int *count)
|
|
{
|
|
#ifdef HAVE_GETPWENT
|
|
struct passwd *pw;
|
|
char *booya = NULL;
|
|
int len = 0;
|
|
char *q;
|
|
char str[BIG_BUFFER_SIZE+1];
|
|
(*count) = 0;
|
|
if (possible)
|
|
{
|
|
possible++;
|
|
len = strlen(possible);
|
|
}
|
|
while ((pw = getpwent()))
|
|
{
|
|
*str = 0;
|
|
if ((q = strrchr(pw->pw_dir, '/')))
|
|
q++;
|
|
if (possible && *possible && q && strncmp(possible, q, len))
|
|
continue;
|
|
if (q && *q)
|
|
{
|
|
strmopencat(str, BIG_BUFFER_SIZE, "~", q, NULL);
|
|
m_s3cat(&booya, space, str);
|
|
}
|
|
else
|
|
m_s3cat(&booya, space, pw->pw_dir);
|
|
(*count)++;
|
|
}
|
|
endpwent();
|
|
if (*count)
|
|
return booya;
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
char *get_completions(enum completion type, char *possible, int *count, char **suggested)
|
|
{
|
|
char *booya = NULL;
|
|
char *path = NULL;
|
|
char *path2, *freeme;
|
|
glob_t globbers;
|
|
int globtype = GLOB_MARK, i;
|
|
|
|
#if defined(__EMX__) || defined(WINNT)
|
|
if (possible && *possible)
|
|
convert_unix(possible);
|
|
#endif
|
|
|
|
switch(type)
|
|
{
|
|
case SERVER_COMPLETION:
|
|
{
|
|
for (i = 0; i < server_list_size(); i++)
|
|
{
|
|
if (possible && my_strnicmp(possible, get_server_name(i), strlen(possible)))
|
|
continue;
|
|
m_s3cat(&booya, space, get_server_name(i));
|
|
(*count)++;
|
|
}
|
|
return booya;
|
|
}
|
|
case TABKEY_COMPLETION:
|
|
{
|
|
NickTab *n = tabkey_array;
|
|
*count = 0;
|
|
if (possible)
|
|
{
|
|
if (*possible == '#' || *possible == '&')
|
|
{
|
|
ChannelList *chan;
|
|
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
|
|
{
|
|
if (my_strnicmp(possible, chan->channel, strlen(possible)))
|
|
continue;
|
|
m_s3cat(&booya, space, chan->channel);
|
|
(*count)++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( ; n; n = n->next)
|
|
{
|
|
if (possible && my_strnicmp(possible, n->nick, strlen(possible)))
|
|
continue;
|
|
m_s3cat(&booya, space, n->nick);
|
|
(*count)++;
|
|
}
|
|
if (*count == 1 && !strcmp(possible, booya))
|
|
{
|
|
new_free(&booya);
|
|
(*count) = 0;
|
|
possible = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (((*count) == 0) || ((*count) == 1))
|
|
{
|
|
/*
|
|
* nothing specified for a match.
|
|
* so grab the first one, if available.
|
|
* or, only one match was available.
|
|
*/
|
|
if (possible && count == 0)
|
|
possible = NULL;
|
|
if ((n = gettabkey(1, 0, possible)) && !booya)
|
|
{
|
|
(*count) = 1;
|
|
booya = m_strdup(n->nick);
|
|
if (suggested)
|
|
*suggested = n->type;
|
|
}
|
|
}
|
|
return booya;
|
|
}
|
|
case COM_COMPLETION:
|
|
command_completion(0, NULL);
|
|
return NULL;
|
|
case CHAN_COMPLETION:
|
|
{
|
|
NickList *cnick = NULL;
|
|
ChannelList *chan = NULL;
|
|
int server = from_server;
|
|
chan = prepare_command(&server, NULL, PC_SILENT);
|
|
if (possible && (*possible == '#' || *possible == '&'))
|
|
{
|
|
int len = strlen(possible);
|
|
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
|
|
{
|
|
if ((len == 1) || (len >= 2 && !my_strnicmp(possible, chan->channel, len)))
|
|
{
|
|
(*count)++;
|
|
m_s3cat(&booya, space, chan->channel);
|
|
}
|
|
}
|
|
}
|
|
else if (chan)
|
|
{
|
|
cnick = next_nicklist(chan, NULL);
|
|
for (; cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (possible && my_strnicmp(cnick->nick, possible, strlen(possible)))
|
|
continue;
|
|
(*count)++;
|
|
m_s3cat(&booya, space, cnick->nick);
|
|
}
|
|
}
|
|
if (!booya)
|
|
{
|
|
for (chan = get_server_channels(current_window->server); chan; chan = chan->next)
|
|
{
|
|
cnick = next_nicklist(chan, NULL);
|
|
for (; cnick; cnick = next_nicklist(chan, cnick))
|
|
{
|
|
if (possible && my_strnicmp(cnick->nick, possible, strlen(possible)))
|
|
continue;
|
|
(*count)++;
|
|
m_s3cat(&booya, space, cnick->nick);
|
|
}
|
|
}
|
|
}
|
|
return booya;
|
|
}
|
|
case LOAD_COMPLETION:
|
|
{
|
|
if (!possible)
|
|
path = m_sprintf("~/.BitchX/");
|
|
else
|
|
{
|
|
if (*possible == '/' || *possible == '~' || *possible == '.')
|
|
path = m_sprintf("%s*", possible);
|
|
else
|
|
path = m_sprintf("~/%s*", possible);
|
|
}
|
|
break;
|
|
}
|
|
case EXEC_COMPLETION:
|
|
{
|
|
if (!possible)
|
|
#if !defined(__EMX__) && !defined(WINNT)
|
|
path = m_sprintf("/usr/bin/*");
|
|
#elif defined(__EMX__)
|
|
path = m_sprintf("C:/OS2/*.EXE");
|
|
#elif defined(WINNT) /* Might need something for WinNT itself C:/WINNT/SYSTEM32/ *.EXE */
|
|
path = m_sprintf("C:/WINDOWS/COMMAND/*.EXE");
|
|
#endif
|
|
else
|
|
{
|
|
if (*possible == '~' && (*(possible+1) != '/'))
|
|
{
|
|
if ((booya = get_home_dir(possible, count)))
|
|
return booya;
|
|
}
|
|
#if defined(__EMX__) || defined(WINNT)
|
|
if (*possible == '/' || *possible == '~' || *possible == '.' || (strlen(possible) > 3 && *(possible+1) == ':' && *(possible+2) == '/'))
|
|
path = m_sprintf("%s*.EXE", possible);
|
|
else
|
|
path = m_sprintf("~/%s*.EXE", possible);
|
|
#else
|
|
if (*possible == '/' || *possible == '~' || *possible == '.')
|
|
path = m_sprintf("%s*", possible);
|
|
else
|
|
path = m_sprintf("~/%s*", possible);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
case CDCC_COMPLETION:
|
|
case DCC_COMPLETION:
|
|
{
|
|
char *dl = get_string_var(DCC_DLDIR_VAR);
|
|
if (!possible)
|
|
path = m_sprintf("%s%s%s", dl, strrchr(dl, '/')?empty_string:"/", "*");
|
|
else
|
|
{
|
|
if (*possible == '~' && (*(possible+1) != '/'))
|
|
{
|
|
if ((booya = get_home_dir(possible, count)))
|
|
return booya;
|
|
}
|
|
#if defined(__EMX__) || defined(WINNT)
|
|
if (*possible == '/' || *possible == '~' || *possible == '.' || (strlen(possible) > 3 && *(possible+1) == ':' && *(possible+2) == '/'))
|
|
#else
|
|
if (*possible == '/' || *possible == '~' || *possible == '.')
|
|
#endif
|
|
path = m_sprintf("%s*", possible);
|
|
else
|
|
path = m_sprintf("~/%s*", possible);
|
|
}
|
|
break;
|
|
}
|
|
case FILE_COMPLETION:
|
|
{
|
|
globtype |= GLOB_TILDE;
|
|
if (!possible)
|
|
path = m_sprintf("~/*");
|
|
else if (*possible == '~' && (*(possible+1) != '/'))
|
|
{
|
|
if ((booya = get_home_dir(possible, count)))
|
|
return booya;
|
|
path = m_strdup(possible);
|
|
}
|
|
else if (*possible == '/' || *possible == '~' || *possible == '.')
|
|
path = m_sprintf("%s*", possible);
|
|
else
|
|
path = m_sprintf("~/%s*", possible);
|
|
#if 0
|
|
path = m_sprintf("%s%s%s", possible, strrchr(possible, '/') ? empty_string: "/", strchr(possible, '*')?empty_string:"*");
|
|
#endif
|
|
break;
|
|
}
|
|
default:
|
|
return NULL;
|
|
}
|
|
#ifdef NEED_GLOB
|
|
#define glob bsd_glob
|
|
#define globfree bsd_globfree
|
|
#endif
|
|
freeme = path2 = expand_twiddle(path);
|
|
if (!path2)
|
|
path2 = path;
|
|
memset(&globbers, 0, sizeof(glob_t));
|
|
glob(path2, globtype, NULL, &globbers);
|
|
for (i = 0; i < globbers.gl_pathc; i++)
|
|
{
|
|
if (strchr(globbers.gl_pathv[i], ' '))
|
|
{
|
|
int len = strlen(globbers.gl_pathv[i])+4;
|
|
char *b = alloca(len+1);
|
|
*b = 0;
|
|
strmopencat(b, len, "\"", globbers.gl_pathv[i], "\"", NULL);
|
|
m_s3cat(&booya, space, b);
|
|
}
|
|
else
|
|
m_s3cat(&booya, space, globbers.gl_pathv[i]);
|
|
(*count)++;
|
|
}
|
|
globfree(&globbers);
|
|
new_free(&freeme);
|
|
new_free(&path);
|
|
return booya;
|
|
}
|
|
|
|
/*
|
|
* this is an oddball routine that attempts to figure out where
|
|
* the last char is in the completes array, that is equal in all
|
|
* the array conditions. when found it sets the input prompt to the
|
|
* command [inp] and the greatest amount of chars found common in all
|
|
* array elements.
|
|
*/
|
|
void set_input_best(enum completion type, char *inp, char *old, int count, char **completes)
|
|
{
|
|
int i,
|
|
c,
|
|
j = 0,
|
|
match = 0;
|
|
char buffer[BIG_BUFFER_SIZE+1];
|
|
|
|
match = strlen(old);
|
|
if (count == 2)
|
|
{
|
|
#if !defined(__EMX__) && !defined(WINNT)
|
|
if (type == CHAN_COMPLETION || type == NICK_COMPLETION || type == TABKEY_COMPLETION)
|
|
i = strieq(completes[0], completes[1]);
|
|
else
|
|
#endif
|
|
i = streq(completes[0], completes[1]);
|
|
completes[0][i] = 0;
|
|
}
|
|
else
|
|
{
|
|
int getout;
|
|
i = match - 1;
|
|
while (1)
|
|
{
|
|
getout = 0;
|
|
c = 1;
|
|
for (j = 1; j < count; j++)
|
|
{
|
|
if (!completes[0][i] || !completes[j][i])
|
|
break;
|
|
#if defined(__EMX__) || defined(WINNT)
|
|
if (toupper(completes[0][i]) == toupper(completes[j][i]))
|
|
c++;
|
|
#else
|
|
if (type == CHAN_COMPLETION || type == NICK_COMPLETION || type == TABKEY_COMPLETION)
|
|
{
|
|
if (toupper(completes[0][i]) == toupper(completes[j][i]))
|
|
c++;
|
|
else
|
|
{
|
|
getout = 1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (completes[0][i] == completes[j][i])
|
|
c++;
|
|
else
|
|
{
|
|
getout = 1;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if ((c != count) || getout)
|
|
break;
|
|
i++;
|
|
}
|
|
if (i)
|
|
completes[0][i] = 0;
|
|
}
|
|
if (old && *old)
|
|
{
|
|
if (strchr(completes[0], ' '))
|
|
snprintf(buffer, sizeof buffer, "%s%s\"%s\"", inp, space, i ? completes[0] : old);
|
|
else
|
|
snprintf(buffer, sizeof buffer, "%s%s%s", inp, space, i ? completes[0] : old);
|
|
}
|
|
else
|
|
strcpy(buffer, completes[0]);
|
|
if (strcmp(buffer, get_input()))
|
|
set_input(buffer);
|
|
if (strchr(completes[0], ' '))
|
|
THIS_POS = strlen(INPUT_BUFFER) - 1;
|
|
}
|
|
|
|
BUILT_IN_KEYBINDING(tab_completion)
|
|
{
|
|
int count = 0,
|
|
wcount = 0;
|
|
enum completion type = NO_COMPLETION;
|
|
char *inp = NULL;
|
|
char *possible = NULL, *old_pos = NULL;
|
|
char *cmdchar;
|
|
char *suggested = NULL;
|
|
int got_space = 0;
|
|
char *get = NULL;
|
|
Ext_Name_Type *extcomp = ext_completion;
|
|
|
|
/*
|
|
* is this the != second word, then just complete from the
|
|
* channel nicks. if it is the second word, grab the first word, and
|
|
* this is used to determine what type of nick completion will be
|
|
* done.
|
|
*/
|
|
inp = alloca(strlen(get_input())+2);
|
|
strcpy(inp, get_input() ? get_input() : empty_string);
|
|
|
|
if (*inp && inp[strlen(inp)-1] == ' ')
|
|
got_space = 1;
|
|
wcount = word_count(inp);
|
|
if (!(cmdchar = get_string_var(CMDCHARS_VAR)))
|
|
cmdchar = "/";
|
|
switch(wcount)
|
|
{
|
|
case 0:
|
|
{
|
|
type = TABKEY_COMPLETION;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
if (*inp != *cmdchar)
|
|
{
|
|
type = CHAN_COMPLETION;
|
|
possible = m_strdup(get_input());
|
|
break;
|
|
}
|
|
else if (!got_space)
|
|
{
|
|
type = COM_COMPLETION;
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
char *p, *old_p;
|
|
int i, got_comp = 0;
|
|
|
|
old_p = p = extract(inp, 0, 0);
|
|
if (wcount > 1)
|
|
old_pos = possible = extract(inp, wcount-1, EOS);
|
|
if ((*p == *cmdchar))
|
|
p++;
|
|
if (possible && (*possible == '"'))
|
|
{
|
|
possible++;
|
|
if (*possible)
|
|
chop(possible, 1);
|
|
else
|
|
possible = NULL;
|
|
}
|
|
if (type == NO_COMPLETION)
|
|
type = CHAN_COMPLETION;
|
|
for (i = 0; *p && name_type[i].len; i++)
|
|
{
|
|
if (!my_strnicmp(p, name_type[i].name, name_type[i].len/*strlen(p)*/))
|
|
{
|
|
got_comp = 1;
|
|
switch(i)
|
|
{
|
|
case IMSG:
|
|
case KB:
|
|
type = TABKEY_COMPLETION;
|
|
break;
|
|
case DCC:
|
|
if (wcount <= 3 && !got_space)
|
|
type = TABKEY_COMPLETION;
|
|
else
|
|
type = DCC_COMPLETION;
|
|
if (wcount == 3 && got_space)
|
|
{
|
|
new_free(&old_pos);
|
|
possible = NULL;
|
|
}
|
|
break;
|
|
case EXEC:
|
|
type = EXEC_COMPLETION;
|
|
break;
|
|
case CHDIR:
|
|
case MP3:
|
|
case LS:
|
|
type = FILE_COMPLETION;
|
|
break;
|
|
case LOAD:
|
|
type = LOAD_COMPLETION;
|
|
break;
|
|
case SERVER:
|
|
type = SERVER_COMPLETION;
|
|
break;
|
|
case CDCC:
|
|
if (wcount == 2 || wcount == 3)
|
|
type = CDCC_COMPLETION;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!got_comp)
|
|
{
|
|
for (extcomp = ext_completion; extcomp; extcomp = extcomp->next)
|
|
{
|
|
if (!my_strnicmp(p, extcomp->name, extcomp->len))
|
|
{
|
|
type = extcomp->type;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
new_free(&old_p);
|
|
break;
|
|
}
|
|
}
|
|
#ifdef TABDEBUG1
|
|
put_it("type = %s", type == TABKEY_COMPLETION ? "TABKEY":
|
|
type == CHAN_COMPLETION? "CHAN" :
|
|
type == COM_COMPLETION? "COMMAND":
|
|
type == EXEC_COMPLETION? "EXEC":
|
|
type == FILE_COMPLETION? "FILE":
|
|
type == DCC_COMPLETION? "DCC":
|
|
"NO_COMPLETION");
|
|
#endif
|
|
do_more_tab:
|
|
count = 0;
|
|
if ((get = get_completions(type, possible, &count, &suggested)))
|
|
{
|
|
char buffer[BIG_BUFFER_SIZE+1];
|
|
char *p = NULL;
|
|
char *old = NULL;
|
|
*buffer = 0;
|
|
if (count == 1)
|
|
{
|
|
if (wcount > 1)
|
|
p = extract(get_input(), 0, wcount - 2);
|
|
else if (suggested && *suggested)
|
|
p = m_3dup("/", suggested, "");
|
|
if (type == TABKEY_COMPLETION)
|
|
snprintf(buffer, sizeof buffer, "%s %s%s%s ", (p && *p == '/') ? p : "/m", get, (p && (*p != '/'))?space:empty_string, (p && (*p != '/'))?p:empty_string);
|
|
else
|
|
{
|
|
if (wcount == 1 && got_space)
|
|
snprintf(buffer, sizeof buffer, "%s %s ", get_input(), get);
|
|
else
|
|
snprintf(buffer, sizeof buffer, "%s%s%s ", p ? p : get, p ? space : empty_string, p ? get : empty_string);
|
|
}
|
|
if ((type == CDCC_COMPLETION || type == LOAD_COMPLETION || type == FILE_COMPLETION || type == DCC_COMPLETION) || ((type == EXEC_COMPLETION) && (get[strlen(get)-1] == '/')))
|
|
chop(buffer, 1);
|
|
set_input(buffer);
|
|
if (strchr(get, ' '))
|
|
THIS_POS = strlen(INPUT_BUFFER) - 1;
|
|
new_free(&p);
|
|
}
|
|
else
|
|
{
|
|
char **completes = NULL;
|
|
int c = 0, matches = count;
|
|
RESIZE(completes, char *, count+1);
|
|
if (wcount > 1)
|
|
{
|
|
if (!got_space)
|
|
{
|
|
old = last_arg(&inp);
|
|
if ((*old == '"'))
|
|
{
|
|
old++;
|
|
chop(old, 1);
|
|
}
|
|
}
|
|
}
|
|
switch(type)
|
|
{
|
|
case LOAD_COMPLETION:
|
|
case DCC_COMPLETION:
|
|
case FILE_COMPLETION:
|
|
case CDCC_COMPLETION:
|
|
{
|
|
char *n, *use = get;
|
|
bitchsay("Found %d files/dirs", count);
|
|
n = new_next_arg(use, &use);
|
|
while (n && *n)
|
|
{
|
|
put_it("%s", n);
|
|
completes[c++] = n;
|
|
n = new_next_arg(use, &use);
|
|
}
|
|
break;
|
|
}
|
|
case EXEC_COMPLETION:
|
|
{
|
|
char *n, *q, *use = get;
|
|
char path[BIG_BUFFER_SIZE+1];
|
|
*path = 0;
|
|
memset(path, 0, sizeof(path));
|
|
n = new_next_arg(use, &use);
|
|
if ((q = strrchr(n, '/')) && *(q+1))
|
|
{
|
|
strncpy(path, n, q - n + 1);
|
|
bitchsay("path = %s", path);
|
|
}
|
|
count = 0;
|
|
while (n && *n)
|
|
{
|
|
if ((q = strrchr(n, '/')) && *(q+1))
|
|
q++;
|
|
else
|
|
q = n;
|
|
strlcat(buffer, q, sizeof buffer);
|
|
strlcat(buffer, space, sizeof buffer);
|
|
if (++count == 4)
|
|
{
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
|
|
count = 0;
|
|
*buffer = 0;
|
|
}
|
|
completes[c++] = n;
|
|
n = new_next_arg(use, &use);
|
|
}
|
|
if (count)
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
|
|
break;
|
|
}
|
|
case SERVER_COMPLETION:
|
|
case TABKEY_COMPLETION:
|
|
case CHAN_COMPLETION:
|
|
{
|
|
char *n, *use = get;
|
|
n = new_next_arg(use, &use);
|
|
count = 0;
|
|
while (n && *n)
|
|
{
|
|
strlcat(buffer, n, sizeof buffer);
|
|
strlcat(buffer, space, sizeof buffer);
|
|
if (++count == 4)
|
|
{
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
|
|
count = 0;
|
|
*buffer = 0;
|
|
}
|
|
completes[c++] = n;
|
|
n = new_next_arg(use, &use);
|
|
}
|
|
if (count)
|
|
put_it("%s", convert_output_format(fget_string_var(FORMAT_COMPLETE_FSET),"%s", buffer));
|
|
break;
|
|
}
|
|
case NO_COMPLETION:
|
|
break;
|
|
default:
|
|
put_it("get = %s[%d]", get, count);
|
|
|
|
}
|
|
if (old && c)
|
|
set_input_best(type, inp, old, matches, completes);
|
|
new_free((char **)&completes);
|
|
}
|
|
update_input(UPDATE_ALL);
|
|
}
|
|
else if (type == TABKEY_COMPLETION)
|
|
{
|
|
if (get_current_channel_by_refnum(0))
|
|
{
|
|
type = CHAN_COMPLETION;
|
|
goto do_more_tab;
|
|
}
|
|
}
|
|
new_free(&get);
|
|
new_free(&old_pos);
|
|
return;
|
|
}
|
|
|
|
int BX_add_completion_type(char *name, int len, enum completion type)
|
|
{
|
|
Ext_Name_Type *new;
|
|
if (!find_in_list((List **)&ext_completion, name, 0))
|
|
{
|
|
new = (Ext_Name_Type *)new_malloc(sizeof(Ext_Name_Type));
|
|
new->name = m_strdup(name);
|
|
new->len = len;
|
|
new->type = type;
|
|
add_to_list((List **)&ext_completion, (List *)new);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* type: The TYPE command. This parses the given string and treats each
|
|
* character as though it were typed in by the user. Thus key bindings
|
|
* are used for each character parsed. Special case characters are control
|
|
* character sequences, specified by a ^ follow by a legal control key.
|
|
* Thus doing "/TYPE ^B" will be as tho ^B were hit at the keyboard,
|
|
* probably moving the cursor backward one character.
|
|
*
|
|
* This was moved from keys.c, because it certainly does not belong there,
|
|
* and this seemed a reasonable place for it to go for now.
|
|
*/
|
|
BUILT_IN_COMMAND(type)
|
|
{
|
|
int c;
|
|
char key;
|
|
|
|
while (*args)
|
|
{
|
|
if (*args == '^')
|
|
{
|
|
switch (*(++args))
|
|
{
|
|
case '?':
|
|
{
|
|
key = '\177';
|
|
args++;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
c = (unsigned char)*(args++);
|
|
if (islower(c))
|
|
c = toupper(c);
|
|
if (c < 64 || c > 95)
|
|
{
|
|
say("Invalid key sequence: ^%c", c);
|
|
return;
|
|
}
|
|
key = c - 64;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (*args == '\\')
|
|
{
|
|
key = *++args;
|
|
args++;
|
|
}
|
|
else
|
|
key = *(args++);
|
|
|
|
edit_char(key);
|
|
}
|
|
}
|
|
|