/*
* 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 Michael Sandrof.
* Copyright (c) 1991, 1992 Troy Rollo.
* Copyright (c) 1992-2003 Matthew R. Green.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: input.c,v 1.22 2006/04/30 14:15:43 f Exp $
*/
#include "irc.h"
#ifdef HAVE_ICONV_H
# include <iconv.h>
#endif /* HAVE ICONV_H */
#include "input.h"
#include "ircterm.h"
#include "alias.h"
#include "vars.h"
#include "ircaux.h"
#include "window.h"
#include "screen.h"
#include "exec.h"
#include "output.h"
#include "translat.h"
#include "debug.h"
/**************************** PATCHED by Flier ******************************/
#include "myvars.h"
#ifdef WANTANSI
extern int CountAnsiInput _((char *, int));
#endif
extern void StripAnsi _((char *, char *, int));
extern NickList *tabnickcompl;
/****************************************************************************/
#define WIDTH 10
/* input_prompt: contains the current, unexpanded input prompt */
static char *input_prompt = (char *) 0;
static struct mb_data mbdata;
static int mbdata_ok = 0;
/**************************** PATCHED by Flier ******************************/
static void ResetNickCompletion() {
tabnickcompl = NULL;
}
/****************************************************************************/
/* cursor_to_input: move the cursor to the input line, if not there already */
void
cursor_to_input(void)
{
Screen *old_current_screen, *screen;
old_current_screen = current_screen;
for (screen = screen_list; screen; screen = screen->next)
{
set_current_screen(screen);
if (screen->alive && is_cursor_in_display())
{
term_move_cursor(screen->inputdata.cursor_x, screen->inputdata.cursor_y);
Debug((3, "cursor_to_input: moving cursor to input for screen %d", screen->screennum));
cursor_not_in_display();
term_flush();
}
}
set_current_screen(old_current_screen);
}
static unsigned
input_do_calculate_width(unsigned unival, iconv_t conv)
{
if (!displayable_unival(unival, conv))
{
/* undisplayable values are printed raw */
if (unival < 0x80)
return 1;
if (unival < 0x800)
return 2;
if (unival < 0x10000)
return 3;
return 4;
}
return calc_unival_width(unival);
}
static void
input_do_set_cursor_pos(unsigned pos)
{
cursor_to_input();
current_screen->inputdata.buffer.pos = pos;
update_input(UPDATE_JUST_CURSOR);
}
static void
input_do_insert_raw(char* source)
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
unsigned max = sizeof(current_screen->inputdata.buffer.buf);
unsigned inslen = strlen(source);
/* This function inserts the given substring of bytes
* to the input line at the current editing position.
* Cursor is moved to point to the end of the substring.
*/
if (pos + inslen > max)
{
inslen = max-pos;
}
/* Move the tail out of way */
memmove(buf + pos + inslen,
buf + pos,
max - pos - inslen);
/* Then put the substring in */
memcpy(buf + pos,
source,
inslen);
/* Ensure the buffer is terminated */
buf[max-1] = '\0';
pos += inslen;
if (pos > max)
pos = max;
/* Update the screen from the old cursor position */
cursor_to_input();
update_input(UPDATE_FROM_CURSOR);
/* Then place the cursor correctly */
input_do_set_cursor_pos(pos);
}
static void
input_do_delete_raw(int n, int do_save_cut)
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
unsigned max = sizeof(current_screen->inputdata.buffer.buf);
cursor_to_input();
/*
fprintf(stderr, "pos(%u)max(%u)buf(%s)do_delete_raw(%d, %d)\n",
pos,max,buf, n, do_save_cut);
*/
/* If n>0, deletes from front
* if n<0, deletes from back & moves cursor
*/
if (n < 0)
{
unsigned limit = current_screen->inputdata.buffer.minpos;
/* Number of bytes LEFT from the cursor (prompt excluding) */
unsigned oldbytes = pos-limit;
unsigned erasebytes = -n;
/* Don't delete more than we can */
if (erasebytes > oldbytes)
erasebytes = oldbytes;
/* Move cursor backward */
pos -= erasebytes;
input_do_set_cursor_pos(pos);
/* Then delete from forward */
n = erasebytes;
}
if (n > 0)
{
unsigned oldbytes = max-pos;
unsigned erasebytes = n > oldbytes ? oldbytes : n;
unsigned newbytes = oldbytes - erasebytes;
if (do_save_cut)
{
if (cut_buffer) new_free(&cut_buffer);
cut_buffer = new_malloc(erasebytes+1);
memcpy(cut_buffer, buf+pos, erasebytes);
cut_buffer[erasebytes] = '\0';
}
memmove(buf+pos,
buf+pos+erasebytes,
newbytes);
buf[pos+newbytes] = '\0';
}
/*
fprintf(stderr, "-> pos(%u)max(%u)buf(%s)\n",
pos,max,buf);
*/
/* Now update the right side from cursor */
update_input(UPDATE_FROM_CURSOR);
}
static void
input_do_delete_chars(int n, int do_save_cut)
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
/* The usage of this function is identical to input_do_delete_raw(),
* but instead of bytes, n means the number of characters.
* Since characters may consist of 1-4 bytes, this
* function converts the number to bytes and then
* calls input_do_delete_raw().
*/
if (n > 0)
{
int bytes;
for (bytes = 0; buf[pos] != '\0' && n > 0; --n)
{
unsigned length = calc_unival_length(buf+pos);
bytes += length;
pos += length;
}
input_do_delete_raw(bytes, do_save_cut);
}
else if (n < 0)
{
unsigned limit = current_screen->inputdata.buffer.minpos;
int bytes;
for(bytes=0; n<0 && pos > limit; ++n)
{
/* Go back until we reach a beginning of a character */
for(;;)
{
unsigned length = calc_unival_length(buf + --pos);
if (length) { bytes += length; break; }
/* But don't go more than we're allowed to */
if (pos == limit) break;
}
}
input_do_delete_raw(-bytes, do_save_cut);
}
}
static void
input_do_replace_prompt(u_char *newprompt)
{
ScreenInputBufferData* bufdata = ¤t_screen->inputdata.buffer;
char* buf = bufdata->buf;
unsigned oldlen = bufdata->minpos;
unsigned newlen = strlen(newprompt);
unsigned max = sizeof(bufdata->buf);
unsigned saved_len = max - (oldlen > newlen ? oldlen : newlen);
/*
fprintf(stderr, "oldlen=%u, newlen=%u, max=%u, saved_len=%u\n",
oldlen,newlen, max, saved_len);
*/
memmove(buf+newlen,
buf+oldlen,
saved_len);
memcpy(buf,
newprompt,
newlen);
buf[max-1] = '\0'; /* prevent dragons */
bufdata->minpos = newlen;
bufdata->pos = bufdata->pos - oldlen + newlen;
if (bufdata->pos < newlen)
bufdata->pos = newlen;
}
static int
input_is_password_prompt(void)
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned limit = current_screen->inputdata.buffer.minpos;
if (limit < 9)
return 0;
/* If the prompt ends with "Password:", it is a password prompt. */
/* This includes the following known prompts:
* "Password:"
* "Operator Password:"
* "Server Password:"
* PATCHED by Flier
* "Master Password:"
* "Old Master Password:"
*/
return my_strnicmp(buf+limit-9, "Password:", 9) == 0;
}
static char
input_do_check_prompt(int update)
{
char *prompt;
char changed = 0;
if (current_screen->promptlist)
prompt = current_screen->promptlist->prompt;
else
/**************************** PATCHED by Flier ******************************/
{
/****************************************************************************/
prompt = input_prompt;
/**************************** PATCHED by Flier ******************************/
/*
* fix bug where old prompt was not replaced in case of
* an empty input_prompt
*/
if (prompt == NULL) prompt = empty_string;
}
/****************************************************************************/
if (prompt)
{
if (update != NO_UPDATE)
{
int free_it = 1;
unsigned len;
char *ptr;
int args_used; /* this isn't used here but is
* passed to expand_alias()
*/
#ifndef _Windows
if (is_process(get_target_by_refnum(0)))
{
ptr = get_prompt_by_refnum(0);
free_it = 0;
}
else
#endif /* _Windows */
ptr = expand_alias((u_char *) 0, prompt, empty_string, &args_used, NULL);
len = strlen(ptr);
if (strncmp(ptr, current_screen->inputdata.buffer.buf, len) || !len)
{
input_do_replace_prompt(ptr);
changed = 1;
}
if (free_it)
new_free(&ptr);
}
}
return changed;
}
static char
input_check_resized(void)
{
ScreenInputData* inputdata = ¤t_screen->inputdata;
if (inputdata->old_li == current_screen->li
&& inputdata->old_co == current_screen->co)
return 0;
/* resized? Keep it simple and reset everything */
inputdata->cursor_x = 0;
inputdata->cursor_y = current_screen->li - 1;
inputdata->old_li = current_screen->li;
inputdata->old_co = current_screen->co;
inputdata->zone = current_screen->co;
if (inputdata->zone > WIDTH)
inputdata->zone -= WIDTH;
if (inputdata->zone > WIDTH)
inputdata->zone -= WIDTH;
return 1;
}
/*
* 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
*/
void
update_input(update)
int update;
{
ScreenInputData* inputdata = ¤t_screen->inputdata;
iconv_t display_conv = NULL;
int term_echo = 1;
if (dumb)
return;
cursor_to_input();
if (input_do_check_prompt(update))
update = UPDATE_ALL;
term_echo = !input_is_password_prompt();
if (input_check_resized())
update = UPDATE_ALL;
if (update != NO_UPDATE)
{
#ifdef HAVE_ICONV_OPEN
const char *enc = display_encoding;
if (!enc)
enc = "ISO-8859-1";
display_conv = iconv_open(enc, "UTF-8");
#endif /* HAVE_ICONV_OPEN */
}
/*
{
unsigned a;
u_char* buf = inputdata->buffer.buf;
fputc('"', stderr);
for (a = 0; buf[a]; ++a)
fputc(buf[a], stderr);
fprintf(stderr, "\"\n");
fputc('>', stderr);
for (a = 0; buf[a]; ++a)
if (a == inputdata->buffer.pos)
fputc('^', stderr);
else if (a == inputdata->buffer.minpos)
fputc('|', stderr);
else
fputc(' ', stderr);
fprintf(stderr, "\n");
}
*/
if (update == UPDATE_JUST_CURSOR || update == UPDATE_ALL)
{
char* buf = inputdata->buffer.buf;
unsigned pos = inputdata->buffer.pos;
unsigned limit = inputdata->buffer.minpos;
unsigned column, ptr;
unsigned window;
/* Recalculate pos_column */
for (column = ptr = 0; ptr < pos; )
{
unsigned unival = calc_unival(buf+ptr);
if (!term_echo && ptr >= limit)
unival = ' ';
column += input_do_calculate_width(unival, display_conv);
ptr += calc_unival_length(buf+ptr);
}
inputdata->pos_column = column;
window = column - (column % inputdata->zone);
/* Recalculate left_ptr */
for (column = ptr = 0; column < window; )
{
unsigned unival = calc_unival(buf+ptr);
if (!term_echo && ptr >= limit)
unival = ' ';
column += input_do_calculate_width(unival, display_conv);
ptr += calc_unival_length(buf+ptr);
}
/* If the left edge has been moved, redraw the input line */
if (ptr != inputdata->left_ptr)
update = UPDATE_ALL;
inputdata->left_ptr = ptr;
/* Recalculate cursor_x */
inputdata->cursor_x = inputdata->pos_column - column;
}
if (update == UPDATE_FROM_CURSOR || update == UPDATE_ALL)
{
unsigned limit = inputdata->buffer.minpos;
char *buf = inputdata->buffer.buf;
char VisBuf[BIG_BUFFER_SIZE];
unsigned column, iptr, optr;
int written;
for (column = 0, optr = 0, iptr = inputdata->left_ptr;
buf[iptr] != '\0' && column < current_screen->co; )
{
unsigned unival = calc_unival(buf+iptr);
unsigned len = calc_unival_length(buf+iptr);
if (!term_echo && iptr >= limit)
unival = ' ';
if (displayable_unival(unival, display_conv))
{
column += calc_unival_width(unival);
/**************************** PATCHED by Flier ******************************/
/*
* hide password prompts
*/
if (!term_echo && (unival == ' ')) {
char *space = " ";
memcpy(VisBuf+optr, space, 1);
}
else
/****************************************************************************/
memcpy(VisBuf+optr, buf+iptr, len);
optr += len;
iptr += len;
}
else
{
unsigned n;
VisBuf[optr++] = REV_TOG;
for (n = 0; n < len; ++n)
VisBuf[optr++] = (buf[iptr++] & 127) | 64;
VisBuf[optr++] = REV_TOG;
column += len;
}
}
VisBuf[optr] = '\0';
term_move_cursor(0, inputdata->cursor_y);
written = output_line(VisBuf, 0);
if (term_clear_to_eol() && written < current_screen->co)
{
/* EOL wasn't implemented, so do it with spaces */
term_space_erase(current_screen->co - written);
}
}
if (update != NO_UPDATE)
{
/* Always update cursor */
term_move_cursor(inputdata->cursor_x, inputdata->cursor_y);
}
if (update != NO_UPDATE)
{
#ifdef HAVE_ICONV_OPEN
iconv_close(display_conv);
#endif /* HAVE_ICONV_OPEN */
}
term_flush();
}
void
refresh_inputline(key, ptr)
u_int key;
char * ptr;
{
update_input(UPDATE_ALL);
}
void
change_input_prompt(direction)
int direction;
{
if (!current_screen->promptlist)
{
/* Restore stuff */
memcpy(¤t_screen->inputdata.saved_buffer,
¤t_screen->inputdata.buffer,
sizeof(current_screen->inputdata.buffer));
}
else if (direction == -1)
{
/* Just update whatever should be on screen */
}
else if (!current_screen->promptlist->next)
{
/* Save stuff */
memcpy(¤t_screen->inputdata.buffer,
¤t_screen->inputdata.saved_buffer,
sizeof(current_screen->inputdata.buffer));
/* Erase input line */
*current_screen->inputdata.buffer.buf = '\0';
current_screen->inputdata.buffer.pos =
current_screen->inputdata.buffer.minpos = 0;
}
update_input(UPDATE_ALL);
}
/* input_move_cursor: moves the cursor left or right... got it? */
/* zero=left, nonzero=right */
void
input_move_cursor(dir)
int dir;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
if (dir)
{
/* if there are still chars remaining */
if (buf[pos] != '\0')
{
/* Skip over 1 character */
pos += calc_unival_length(buf+pos);
input_do_set_cursor_pos(pos);
}
}
else
{
unsigned limit = current_screen->inputdata.buffer.minpos;
if (pos > limit)
{
/* Go back until we reach a beginning of a character */
while(!calc_unival_length(buf + --pos))
{
/* But don't go more than we're allowed to */
if (pos == limit) break;
}
input_do_set_cursor_pos(pos);
}
}
}
/*
* input_forward_word: move the input cursor forward one word in the input
* line
*/
void
input_forward_word(key, ptr)
u_int key;
char * ptr;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
/* Skip while definitely space, then skip while definitely nonspace */
/* For nontypical characters, does nothing */
while (buf[pos] != '\0')
{
unsigned unival = calc_unival(buf+pos);
if (!isspace(unival) && !ispunct(unival))
break;
pos += calc_unival_length(buf+pos);
}
while (buf[pos] != '\0')
{
unsigned unival = calc_unival(buf+pos);
if (isspace(unival) || ispunct(unival) || unival >= 0x300)
break;
pos += calc_unival_length(buf+pos);
}
input_do_set_cursor_pos(pos);
}
/* input_backward_word: move the cursor left on word in the input line */
void
input_backward_word(key, ptr)
u_int key;
char * ptr;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
unsigned limit = current_screen->inputdata.buffer.minpos;
/* Skip while previous is definitely space, */
/* then skip while previous is definitely nonspace. */
/* For nontypical characters, does nothing */
while (pos > limit)
{
unsigned prevpos = pos, unival;
while (!calc_unival_length(buf + --prevpos))
if (prevpos <= limit)
break;
unival = calc_unival(buf + prevpos);
if (!isspace(unival) && !ispunct(unival))
break;
pos = prevpos;
}
while (pos > limit)
{
unsigned prevpos = pos, unival;
while (!calc_unival_length(buf + --prevpos))
if (prevpos <= limit)
break;
unival = calc_unival(buf + prevpos);
if (isspace(unival) || ispunct(unival) || unival >= 0x300)
break;
pos = prevpos;
}
input_do_set_cursor_pos(pos);
}
/* input_delete_character: deletes a character from the input line */
void
input_delete_character(key, ptr)
u_int key;
char * ptr;
{
input_do_delete_chars(1, 0);
/**************************** PATCHED by Flier ******************************/
ResetNickCompletion();
/****************************************************************************/
}
/* input_backspace: does a backspace in the input buffer */
/*ARGSUSED*/
void
input_backspace(key, ptr)
u_int key;
char * ptr;
{
input_do_delete_chars(-1, 0);
/**************************** PATCHED by Flier ******************************/
ResetNickCompletion();
/****************************************************************************/
}
/*
* input_beginning_of_line: moves the input cursor to the first character in
* the input buffer
*/
void
input_beginning_of_line(key, ptr)
u_int key;
char *ptr;
{
input_do_set_cursor_pos(current_screen->inputdata.buffer.minpos);
}
/*
* input_end_of_line: moves the input cursor to the last character in the
* input buffer
*/
void
input_end_of_line(key, ptr)
u_int key;
char *ptr;
{
input_do_set_cursor_pos(strlen(current_screen->inputdata.buffer.buf));
}
/*
* input_delete_previous_word: deletes from the cursor backwards to the next
* space character.
*/
void
input_delete_previous_word(key, ptr)
u_int key;
char * ptr;
{
unsigned pos = current_screen->inputdata.buffer.pos;
int bytes;
/* moves cursor backwards */
input_backward_word(key,ptr);
bytes = pos - current_screen->inputdata.buffer.pos;
/* now that we're back, delete next n bytes */
input_do_delete_raw(bytes, 1);
/**************************** PATCHED by Flier ******************************/
tabnickcompl = NULL;
/****************************************************************************/
}
/*
* input_delete_next_word: deletes from the cursor to the end of the next
* word
*/
void
input_delete_next_word(key, ptr)
u_int key;
char * ptr;
{
unsigned pos = current_screen->inputdata.buffer.pos;
int bytes;
/* moves cursor forward */
input_forward_word(key,ptr);
bytes = current_screen->inputdata.buffer.pos - pos;
/* now that we're after the word, delete past n bytes */
input_do_delete_raw(-bytes, 1);
}
/*
* input_add_character: adds the byte c to the input buffer, repecting
* the current overwrite/insert mode status, etc
*/
/*ARGSUSED*/
void
input_add_character(key, ptr)
u_int key;
char * ptr;
{
u_char output_buffer[8];
#ifdef HAVE_ICONV_OPEN
static u_char input_buffer[32]="";
static unsigned input_pos=0;
size_t retval;
u_char *iptr, *optr;
size_t isize, osize;
input_buffer[input_pos++] = key;
if (!mbdata_ok)
{
mbdata_init(&mbdata, input_encoding);
mbdata_ok = 1;
}
re_encode:
if (!input_pos)
{
return;
}
iptr = input_buffer;
isize = input_pos;
optr = output_buffer;
osize = sizeof output_buffer;
retval = iconv(mbdata.conv_in,
(iconv_const char **)&iptr, &isize,
(char **)&optr, &osize);
if (retval == (size_t)-1)
{
switch(errno)
{
case EINVAL:
{
/* User didn't give enough bytes. Must give more later. */
return;
}
case EILSEQ:
{
/* User gave a bad byte. Ignore bad bytes! */
memmove(input_buffer+1,
input_buffer,
--input_pos);
goto re_encode;
}
}
}
*optr = '\0';
input_pos = 0;
#else
/* no iconv, assume in=iso-8859-1 */
utf8_sequence(key, output_buffer);
#endif /* HAVE_ICONV_OPEN */
if (!get_int_var(INSERT_MODE_VAR))
{
/* Delete the next character */
input_do_delete_chars(1, 0);
}
input_do_insert_raw(output_buffer);
/**************************** PATCHED by Flier ******************************/
if (key == ' ') ResetNickCompletion();
/****************************************************************************/
}
#ifndef _Windows
/*
* set_input: sets the input buffer to the given string, discarding whatever
* was in the input buffer before
*/
void
set_input(str)
char *str;
{
u_char converted_input[INPUT_BUFFER_SIZE];
struct mb_data mbdata1;
unsigned dest;
#ifdef HAVE_ICONV_OPEN
mbdata_init(&mbdata1, irc_encoding);
#else
mbdata_init(&mbdata1, NULL);
#endif /* HAVE_ICONV_OPEN */
for (dest = 0; *str != '\0'; )
{
if (dest + 8 >= sizeof(converted_input))
break;
/**************************** PATCHED by Flier ******************************/
/*
* copy attribute characters/beeps directly so we can
* properly recall previous commands
*/
if (*str == REV_TOG || *str == UND_TOG || *str == BOLD_TOG ||
*str == ALL_OFF || *str == '\007') {
converted_input[dest++] = *str++;
continue;
}
/****************************************************************************/
decode_mb(str, converted_input+dest, &mbdata1);
dest += mbdata1.output_bytes;
str += mbdata1.input_bytes;
}
converted_input[dest] = '\0';
set_input_raw(converted_input);
}
void
set_input_raw(str)
char* str;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
unsigned limit = current_screen->inputdata.buffer.minpos;
strmcpy(buf + limit,
str,
(size_t)sizeof(current_screen->inputdata.buffer.buf) - limit);
pos = strlen(buf);
current_screen->inputdata.buffer.pos = pos;
if (mbdata_ok)
{
mbdata_done(&mbdata);
mbdata_ok = 0;
}
}
#endif /* _Windows */
/*
* 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 *
get_input()
{
char* source = get_input_raw();
/* The input buffer is UTF-8 encoded. Clients will want irc_encoding instead. */
static char converted_buffer[INPUT_BUFFER_SIZE];
#ifdef HAVE_ICONV_OPEN
iconv_t conv = iconv_open(irc_encoding, "UTF-8");
char* dest = converted_buffer;
size_t left, space;
left = strlen(source);
space = sizeof(converted_buffer);
while (*source != '\0')
{
size_t retval;
retval = iconv(conv,
(iconv_const char**) &source, &left,
(char **)&dest, &space);
if (retval == (size_t)-1)
{
if (errno == E2BIG)
break;
if (errno == EILSEQ)
{
/* Ignore silently 1 illegal byte */
if (left > 0)
{
++source;
--left;
}
}
if (errno == EINVAL)
{
/* Input terminated with a partial byte. */
/* Ignore the error silently. */
break;
}
}
}
/* Reset the converter, create a reset-sequence */
iconv(conv, NULL, &left, (char **)&dest, &space);
/* Ensure null-terminators are where they should be */
converted_buffer[sizeof(converted_buffer)-1] = '\0';
*dest = '\0';
iconv_close(conv);
#else
/* Must convert manually - assume output is ISO-8859-1 */
unsigned dest = 0;
while (*source != '\0')
{
unsigned len = calc_unival_length(source);
unsigned unival;
if (!len)
{
/* ignore illegal byte (shouldn't happen) */
++source;
continue;
}
unival = calc_unival(source);
if (displayable_unival(unival, NULL))
{
converted_buffer[dest++] = unival;
if (dest+1 >= sizeof(converted_buffer))
break;
}
source += len;
}
converted_buffer[dest] = '\0';
#endif /* HAVE_ICONV_OPEN */
return converted_buffer;
}
char *
get_input_raw()
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned limit = current_screen->inputdata.buffer.minpos;
return buf+limit;
}
/* input_clear_to_eol: erases from the cursor to the end of the input buffer */
void
input_clear_to_eol(key, ptr)
u_int key;
char * ptr;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
int bytes;
for (bytes = 0; buf[pos] != '\0';)
{
unsigned length = calc_unival_length(buf+pos);
bytes += length;
pos += length;
}
input_do_delete_raw(bytes, 1);
}
/*
* input_clear_to_bol: clears from the cursor to the beginning of the input
* buffer
*/
void
input_clear_to_bol(key, ptr)
u_int key;
char *ptr;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
int bytes;
unsigned limit = current_screen->inputdata.buffer.minpos;
for (bytes = 0; limit < pos; )
{
unsigned length = calc_unival_length(buf+limit);
bytes += length;
limit += length;
}
input_do_delete_raw(-bytes, 1);
}
/*
* input_clear_line: clears entire input line
*/
void
input_clear_line(key, ptr)
u_int key;
char *ptr;
{
input_beginning_of_line(key, ptr);
input_clear_to_eol(key, ptr);
/**************************** PATCHED by Flier ******************************/
tabnickcompl = NULL;
/****************************************************************************/
}
/*
* input_transpose_characters: swaps the positions of the two characters
* before the cursor position
* and moves cursor 1 forward
*/
void
input_transpose_characters(key, ptr)
u_int key;
char * ptr;
{
char* buf = current_screen->inputdata.buffer.buf;
unsigned pos = current_screen->inputdata.buffer.pos;
/*
delete previous char,
then move 1 right,
then insert the deleted char
example (^ denotes cursor position):
before:
defg
^
after:
dfeg
^
this is how bash transposes at least /Bisqwit
FIXME: cut-buffer shouldn't be affected when transposing
*/
if (!buf[pos])
{
/* back off 1 char */
input_move_cursor(0);
pos = current_screen->inputdata.buffer.pos;
/* If we're still at the end of the string,
* the string consists of only 1 char.
* In which case there's nothing to transpose.
*/
if (!buf[pos])
{
return;
}
}
input_do_delete_chars(-1, 1);
input_move_cursor(1);
input_yank_cut_buffer(key, ptr);
}
/* init_input: initialized the input buffer by clearing it out */
void
init_input()
{
*current_screen->inputdata.buffer.buf = (char) 0;
current_screen->inputdata.buffer.pos = current_screen->inputdata.buffer.minpos;
}
/*
* input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
* into the input line
*/
void
input_yank_cut_buffer(key, ptr)
u_int key;
char * ptr;
{
if (cut_buffer)
input_do_insert_raw(cut_buffer);
}
/* get_input_prompt: returns the current input_prompt */
char *
get_input_prompt()
{
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
set_input_prompt(prompt)
char *prompt;
{
if (!prompt)
{
if (!input_prompt)
return;
malloc_strcpy(&input_prompt, empty_string);
}
else
{
char converted_prompt[INPUT_BUFFER_SIZE];
struct mb_data mbdata1;
unsigned dest;
#ifdef HAVE_ICONV_OPEN
mbdata_init(&mbdata1, irc_encoding);
#else
mbdata_init(&mbdata1, NULL);
#endif /* HAVE_ICONV_OPEN */
for (dest = 0; *prompt != '\0'; )
{
decode_mb(prompt, converted_prompt+dest, &mbdata1);
dest += mbdata1.output_bytes;
prompt += mbdata1.input_bytes;
}
converted_prompt[dest] = '\0';
if (input_prompt && !strcmp(converted_prompt, input_prompt))
return;
malloc_strcpy(&input_prompt, converted_prompt);
}
update_input(UPDATE_ALL);
}
/*
* input_pause: prompt the user with a message then waits for a single
* keystroke before continuing. The key hit is returned.
*
* This function is NEVER to be called, once the inital irc_io()
* loop has been called from main(). Perhaps it would be better
* to just put this code at the only place it is called, and not
* have the function. If you want an input_pause, use add_wait_prompt()
* with WAIT_PROMPT_KEY.
*/
char
input_pause(msg)
char *msg;
{
char *ptr = (char *) 0;
char c;
if (dumb)
{
puts(msg);
fflush(stdout);
if (use_input)
irc_io(&c, NULL, -1, 1);
}
else
{
malloc_strcpy(&ptr, get_input());
set_input(msg);
update_input(UPDATE_ALL);
irc_io(&c, NULL, -1, 1);
set_input(ptr);
update_input(UPDATE_ALL);
new_free(&ptr);
}
return (c);
}
void
input_reset_screen(Screen* new)
{
new->inputdata.old_li = -1;
new->inputdata.old_co = -1;
new->inputdata.cursor_x = 0;
new->inputdata.cursor_y = 0;
new->inputdata.left_ptr = 0;
new->inputdata.pos_column = 0;
new->inputdata.buffer.pos = 0;
new->inputdata.buffer.minpos = 0;
new->inputdata.buffer.buf[0] = '\0';
}
/* moved from alias.c */
u_char *
function_curpos(input)
u_char *input;
{
char *new = (char *) 0,
pos[8];
snprintf(pos, sizeof pos, "%d", current_screen->inputdata.buffer.pos);
malloc_strcpy(&new, pos);
return new;
}
syntax highlighted by Code2HTML, v. 0.9.1