/******************************************************************************
* This file is part of a software distribution, which is furnished under the *
* terms of a license. Use of this software by any means is subject to this *
* license and signifies the acceptance of the licensing terms stated *
* therein. Please see the file LICENSE in the top-level directory of this *
* software distribution for detailed copyright disclaimers and licensing *
* terms. *
******************************************************************************
* Copryight (c) by Andreas S. Wetzel - All rights reserved. *
******************************************************************************/
/* $Id: ed_funcs.c,v 1.3 2001/03/19 23:17:28 mickey Exp $ */
#include <vchat.h>
#include <proto_common.h>
/*** Globals ***/
extern int in_chat_window;
extern ED *ed;
extern VP vp;
extern VTCAP vtcap;
extern ULIST_ITEM *ulist_base;
extern int ulist_cnt;
/*** Code ***/
void curs_left(void)
{
u_int treshold;
/*
* Nothing happens if already at buffer start.
*/
if(ed->curpos <= ed->buffer)
return;
/*
* Decrement buffer position.
*/
ed->curpos--;
if(ed->curpos < ed->margin && !(ed->flags & ED_NO_ECHO))
{
/*
* Scrolling _IS_ necessary - determine scrolling mode.
*/
if(vp.sc_mode == 0)
{
/*
* Character scrolling.
*/
ed->margin--;
if(HAS_IC)
{
if(in_chat_window)
mv(ED_SCRPOS, vtcap.rows);
tputs(vtcap.insertchar, 1, (void *)outc);
putchar(*ed->curpos);
mv(ED_SCRPOS, vtcap.rows);
}
else if(HAS_IM)
{
if(in_chat_window)
mv(ED_SCRPOS, vtcap.rows);
tputs(vtcap.insert_on, 1, (void *)outc);
putchar(*ed->curpos);
tputs(vtcap.insert_off, 1, (void *)outc);
mv(ED_SCRPOS, vtcap.rows);
}
else
{
line_update();
}
}
else if(vp.sc_mode == 1)
{
/*
* Block scrolling.
*/
treshold = (u_int)((vtcap.cols - ed->offset) / 3);
ed->margin = (ed->curpos > (ed->buffer + treshold)) ? (ed->margin - treshold) : ed->buffer;
line_update();
}
}
else if(!(ed->flags & ED_NO_ECHO))
{
/*
* Scrolling is _NOT_ necessary - Just move the cursor.
*/
mv(ED_SCRPOS, vtcap.rows);
}
else if(in_chat_window)
{
/*
* NO_ECHO mode - just set the cursor back into the input line.
*/
mv((1 + ed->offset), vtcap.rows);
}
/*
* Cursor should now reside in the input line not the chat window.
*/
in_chat_window = 0;
}
void curs_right(void)
{
u_int treshold;
/*
* When already at end of buffer, nothing happens.
*/
if(ed->curpos >= ed->endpos)
return;
/*
* Increment the buffer position.
*/
ed->curpos++;
if(ED_SCRPOS > vtcap.cols && !(ed->flags & ED_NO_ECHO))
{
/*
* Scrolling _IS_ necessary. Determine selected scroll mode.
*/
if(vp.sc_mode == 0)
{
/*
* Character scrolling.
*/
ed->margin++;
if(HAS_DC)
{
mv((1 + ed->offset), vtcap.rows);
tputs(vtcap.deletechar, 1, (void *)outc);
mv(vtcap.cols, vtcap.rows);
putchar(*ed->curpos);
}
else if(HAS_DM)
{
/* Huh ? */
line_update();
}
else
{
line_update();
}
}
else if(vp.sc_mode == 1)
{
/*
* Block scrolling.
*/
treshold = (u_int)((vtcap.cols - ed->offset) / 3);
ed->margin = ((ed->margin + treshold) > ED_MARGINMAX) ? ED_MARGINMAX : (ed->margin + treshold);
line_update();
}
}
else if(!(ed->flags & ED_NO_ECHO))
{
/*
* Scrolling not necessary, just move the cursor.
*/
mv(ED_SCRPOS, vtcap.rows);
}
else if(in_chat_window)
{
/*
* NO_ECHO mode, just move the cursor back to input line.
*/
mv((1 + ed->offset), vtcap.rows);
}
/*
* Cursor should now be in the input line, not in the chat window.
*/
in_chat_window = 0;
}
void backspace(void)
{
u_int bs_treshold;
/*
* We don't do anything if we
* are already at buffer-start.
*/
if(ed->curpos <= ed->buffer)
return;
if(ed->curpos != ed->endpos)
{
/*
* Cursor stands in-line
*/
memmove((char *)(ed->curpos - 1), ed->curpos, ED_REMAIN);
*(--ed->endpos) = '\0';
--ed->curpos;
if(ed->flags & ED_NO_ECHO)
{
if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
return;
}
switch(vp.bs_mode)
{
case 0: /*
* Jump & Move
*/
bs_treshold = (u_int)((vtcap.cols - ed->offset) / 3);
if(ed->curpos < (ed->margin + bs_treshold))
{
ed->margin = (ed->margin > (ed->buffer + bs_treshold)) ? (char *)(ed->margin - bs_treshold) : ed->buffer;
line_update();
}
else
{
inline_backspace();
}
break;
case 1: /*
default: * Reverse delete
*/
if(ed->margin > ed->buffer)
{
slide_backspace();
}
else
{
inline_backspace();
}
break;
}
}
else
{
/*
* Cursor at end of input
*/
*(--ed->curpos) = '\0';
--ed->endpos;
if(ed->flags & ED_NO_ECHO)
{
if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
return;
}
switch(vp.bs_mode)
{
case 0: /*
* Jump & Move
*/
bs_treshold = (u_int)((vtcap.cols - ed->offset) / 3);
if(ed->curpos < (ed->margin + bs_treshold))
{
ed->margin = (ed->margin > (ed->buffer + bs_treshold)) ? (char *)(ed->margin - bs_treshold) : ed->buffer;
line_update();
}
else
{
normal_backspace();
}
break;
case 1: /*
default: * Reverse delete
*/
if(ed->margin > ed->buffer)
{
slide_backspace();
}
else
{
normal_backspace();
}
break;
}
}
}
void normal_backspace(void)
{
/*
* Ordinary backspace
*/
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
if(vtcap.clear2eol)
tputs(vtcap.clear2eol, 1, (void *)outc);
else if(vtcap.clear2eod)
tputs(vtcap.clear2eod, 1, (void *)outc);
in_chat_window = 0;
}
else
{
putchar(BS);
putchar(' ');
putchar(BS);
}
}
void slide_backspace(void)
{
/*
* Slide window margin
*/
--ed->margin;
if(HAS_DC && HAS_IC)
{
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
else
{
putchar(BS);
}
tputs(vtcap.deletechar, 1, (void *)outc);
mv(1 + ed->offset, vtcap.rows);
tputs(vtcap.insertchar, 1, (void *)outc);
putchar(*ed->margin);
mv(ED_SCRPOS, vtcap.rows);
}
else
{
line_update();
}
}
void inline_backspace(void)
{
/*
* Inline backspace
*/
if(HAS_DC)
{
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
else
{
putchar(BS);
}
tputs(vtcap.deletechar, 1, (void *)outc);
/*
* Anything left to pull over ?
*/
if(ed->endpos >= (ed->margin + vtcap.cols))
{
mv(vtcap.cols, vtcap.rows);
putchar(*(ed->margin + vtcap.cols - 1));
mv(ED_SCRPOS, vtcap.rows);
}
}
else
{
/*
* We are doing line_update(); here so far :-(
*/
line_update();
}
}
void jump_start(void)
{
if(ed->margin == ed->buffer)
{
/*
* Current display area is already at start of buffer.
*/
ed->curpos = ed->buffer;
if(!(ed->flags & ED_NO_ECHO))
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
else
{
ed->curpos = ed->margin = ed->buffer;
if(!(ed->flags & ED_NO_ECHO))
{
line_update();
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
}
void jump_end(void)
{
ed->curpos = ed->endpos;
if(ed->curpos >= (ed->margin + vtcap.cols))
{
ed->margin = (char *)(ed->endpos - (vtcap.cols + ed->offset) + 1);
if(!(ed->flags & ED_NO_ECHO))
{
line_update();
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
else
{
if(!(ed->flags & ED_NO_ECHO))
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
}
void erase_eol(void)
{
while(ed->endpos > ed->curpos)
*ed->endpos-- = '\0';
*ed->endpos = '\0';
if(!(ed->flags & ED_NO_ECHO))
{
if(vtcap.clear2eol)
{
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
tputs(vtcap.clear2eol, 1, (void *)outc);
}
else if(vtcap.clear2eod)
{
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
tputs(vtcap.clear2eod, 1, (void *)outc);
}
else
{
line_update();
}
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
void erase_line(void)
{
BZERO(&ed->buffer, EDBUFSIZE+1);
ed->endpos = ed->curpos = ed->margin = (char *) &ed->buffer;
if(!(ed->flags & ED_NO_ECHO))
{
if(vtcap.clear2eol)
{
mv((1 + ed->offset), vtcap.rows);
tputs(vtcap.clear2eol, 1, (void *)outc);
in_chat_window = 0;
}
else if(vtcap.clear2eod)
{
mv((1 + ed->offset), vtcap.rows);
tputs(vtcap.clear2eod, 1, (void *)outc);
in_chat_window = 0;
}
else
{
line_update();
}
}
else if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
void insert_char(char c)
{
/*
* Check if there is enough bufferspace available.
*/
if(ed->endpos >= (char *) &ed->buffer[ed->maxlen])
return;
/*
* Move the rest of the buffer one position right.
*/
memmove((char *)(ed->curpos + 1), ed->curpos, ED_REMAIN);
*ed->curpos++ = (u_char) c;
ed->endpos++;
if(ED_SCRPOS > vtcap.cols && !(ed->flags & ED_NO_ECHO))
{
/*
* Cursor has left the screen, scrolling _IS_ necessary.
*/
ed->margin++;
if(HAS_DC && (HAS_IC || HAS_IM))
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
tputs(vtcap.deletechar, 1, (void *)outc);
mv((vtcap.cols - 1), vtcap.rows);
if(HAS_IC)
{
tputs(vtcap.insertchar, 1, (void *)outc);
putchar(c);
}
else
{
tputs(vtcap.insert_on, 1, (void *)outc);
putchar(c);
tputs(vtcap.insert_off, 1, (void *)outc);
}
}
else
{
line_update();
}
}
else if(!(ed->flags & ED_NO_ECHO))
{
/*
* Cursor is still on the screen.
*/
if(HAS_IC)
{
if(in_chat_window)
{
mv((ED_SCRPOS - 1), vtcap.rows);
in_chat_window = 0;
}
tputs(vtcap.insertchar, 1, (void *)outc);
putchar(c);
}
else if(HAS_IM)
{
if(in_chat_window)
{
mv((ED_SCRPOS - 1), vtcap.rows);
in_chat_window = 0;
}
tputs(vtcap.insert_on, 1, (void *)outc);
putchar(c);
tputs(vtcap.insert_off, 1, (void *)outc);
}
else
{
line_update();
}
}
else if(in_chat_window)
{
/*
* NO_ECHO mode - just set the cursor back into the input line.
*/
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
void append_char(char c)
{
/*
* Check if there is enough bufferspace available.
*/
if(ed->endpos >= (char *) &ed->buffer[ed->maxlen])
return;
*ed->curpos++ = (u_char) c;
ed->endpos++;
if(ED_SCRPOS > vtcap.cols && !(ed->flags & ED_NO_ECHO))
{
/*
* Cursor has left the screen, scrolling _IS_ necessary.
*/
ed->margin++;
if(HAS_DC)
{
mv((1 + ed->offset), vtcap.rows);
tputs(vtcap.deletechar, 1, (void *)outc);
mv((vtcap.cols - 1), vtcap.rows);
in_chat_window = 0;
putchar(c);
}
else
{
line_update();
}
}
else if(!(ed->flags & ED_NO_ECHO))
{
/*
* Cursor still on the screen, scrolling is _NOT_ necessary.
*/
if(in_chat_window)
{
mv((ED_SCRPOS - 1), vtcap.rows);
in_chat_window = 0;
}
putchar(c);
}
else if(in_chat_window)
{
/*
* NO_ECHO mode - just set the cursor back into the input line.
*/
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
}
void delete(void)
{
/*
* Nothing to do here, we're already at end-of-line
*/
if(ed->curpos == ed->endpos)
return;
if(ed->curpos == (char *)(ed->endpos - 1))
{
/*
* Delete the last character in line.
*/
*(--ed->endpos) = '\0';
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
if(ed->flags & ED_NO_ECHO)
return;
if(HAS_DC)
{
tputs(vtcap.deletechar, 1, (void *)outc);
}
else if(vtcap.clear2eol)
{
tputs(vtcap.clear2eol, 1, (void *)outc);
}
else if(vtcap.clear2eod)
{
tputs(vtcap.clear2eod, 1, (void *)outc);
}
else
{
putchar(' ');
putchar(BS);
}
}
else
{
/*
* Delete ANY character in line.
*/
memmove(ed->curpos, (char *)(ed->curpos + 1), (ED_REMAIN-1));
*(--ed->endpos) = '\0';
if(ed->flags & ED_NO_ECHO)
{
if(in_chat_window)
{
mv((1 + ed->offset), vtcap.rows);
in_chat_window = 0;
}
return;
}
if(HAS_DC)
{
if(in_chat_window)
{
mv(ED_SCRPOS, vtcap.rows);
in_chat_window = 0;
}
tputs(vtcap.deletechar, 1, (void *)outc);
mv(vtcap.cols, vtcap.rows);
putchar(*(ed->margin + vtcap.cols - 1));
mv(ED_SCRPOS, vtcap.rows);
}
else
{
line_update();
}
}
}
void word_forward(void)
{
char *next;
long int offset;
next = scan_forward();
offset = (next - ed->curpos);
ed->margin += ((ed->margin + offset) <= ED_MARGINMAX) ? offset : (ED_MARGINMAX - ed->margin);
ed->curpos += offset;
line_update();
}
char *scan_forward(void)
{
char *i;
int flag = 0x00;
for(i = ed->curpos; i < ed->endpos; i++)
{
if(*i == ' ' || *i == '\t')
{
flag = 0xff;
}
else
{
if(flag)
return(i);
}
}
return(i);
}
void word_reverse(void)
{
char *prev;
long int offset;
prev = scan_reverse();
offset = ed->curpos - prev;
if((ed->margin - offset) >= ed->buffer)
ed->margin -= offset;
else
ed->margin = ed->buffer;
ed->curpos = (ed->curpos - offset) < ed->buffer ? ed->buffer : (ed->curpos - offset);
line_update();
}
char *scan_reverse(void)
{
char *i;
int flag = 0x00;
for(i = ed->curpos; i > ed->buffer; i--)
{
if(*i == ' ' || *i == '\t')
{
flag = 0xff;
}
else
{
if(flag)
{
for(; i > ed->buffer; i--)
if(*i == ' ' || *i == '\t')
return(i + 1);
}
}
}
return(i);
}
int is_key_sequence(char *key, u_char c)
{
static int index = 0;
u_char x;
if(key && c == *(key + index))
{
if(++index >= strlen(key))
{
index = 0;
return(1);
}
x = getchar();
if(is_key_sequence(key, x))
{
return(1);
}
else
{
ungetc(x, stdin);
return(0);
}
}
index = 0;
return(0);
}
void clear_ed(ED *ced)
{
BZERO(&ced->buffer, EDBUFSIZE + 1);
ced->curpos = ced->endpos = ced->margin = (char *)&ced->buffer;
ced->prompt = NULL;
ced->offset = 0;
ced->flags = 0;
ced->maxlen = EDBUFSIZE;
}
void tabcomplete()
{
register int i;
char *ls;
char *le;
char lookup[VPNICKSIZE + 1];
char complete[VPNICKSIZE + 3]; /* Leave room for ": " */
int flags = 0x00;
#define TCPL_BOB 0x00000001
#define TCPL_AMBIGIOUS 0x00000002
int matches = 0;
int matchchars = 0;
int mchars = 0;
int ichars = 0;
ULIST_ITEM *u;
/*
* Find the beginning of the current word
*/
for(ls = ed->curpos; *ls != ' ' && *ls != '\t'
&& ls > ed->buffer; --ls);
if(*ls == ' ' || *ls == '\t')
++ls;
/*
* When hit start of buffer, set flag
*/
if(ls == ed->buffer)
flags |= TCPL_BOB;
/*
* If the current word is empty or
* it's size exceeds the maximum size
* of a nickname, then do nothing.
*/
le = ed->curpos;
if(le <= ls || (le - ls) > VPNICKSIZE) /* NOP */
return;
/*
* Copy out the lookup word
*/
BZERO(lookup, sizeof(lookup));
BCOPY(ls, lookup, (le - ls));
/*
* Step through nickname list and find possible matches.
*/
BZERO(complete, sizeof(complete));
for(i = 0; i < ulist_cnt; i++)
{
u = ulist_base + i;
/*
* Calculate the longest possible match
*/
mchars = matching_chars(u->nick, lookup);
/*
* Ignore multiple occurances of the same nickname
* and matches smaller than the lookup string.
*/
if(!strcmp(u->nick, complete) || mchars < strlen(lookup))
continue;
/*
* Update the completion string and
* the number of matched characters.
*/
if(matches > 0)
{
matchchars = matching_chars(complete, u->nick);
strncpy(complete, u->nick, matchchars);
complete[matchchars] = '\0';
flags |= TCPL_AMBIGIOUS;
++matches;
}
else
{
strcpy(complete, u->nick);
matchchars = strlen(complete);
matches = 1;
}
}
/*
* When there was no match at all, then it is ambigous, too.
*/
if(matches == 0)
flags |= TCPL_AMBIGIOUS;
/*
* When there is no closer match, then there is nothing left to do.
*/
if(matchchars <= strlen(lookup))
{
if((flags & TCPL_AMBIGIOUS) && vp.matchbeep)
putchar(BEL);
return;
}
/*
* If there is an exact match, append ": " to the completion
* string if the current word is at the beginning of the buffer
* or " " if the current word is inline.
*/
if((flags & TCPL_AMBIGIOUS) == 0)
{
if((flags & TCPL_BOB) != 0)
{
strcat(complete, ": ");
matchchars += 2;
}
else
{
strcat(complete, " ");
matchchars += 1;
}
}
/*
* See if there is enough space in the input
* buffer to insert the completion string.
*/
ichars = (matchchars - strlen(lookup));
if(ED_FREE < ichars)
{
if(vp.matchbeep)
putchar(BEL);
return;
}
/*
* Move the rest of the input buffer to make space for completion.
*/
BCOPY(ed->curpos, (ed->curpos + ichars), ED_REMAIN);
ed->endpos += ichars;
/*
* Insert the complete string.
*/
BCOPY(complete, ls, matchchars);
ed->curpos += ichars;
/*
* Scroll if necessary.
*/
if(ed->curpos >= ED_ENDMARGIN)
{
if((ed->margin + ichars) <= ED_MARGINMAX)
{
ed->margin += ichars;
}
}
/*
* Update screen
*/
line_update();
/*
* Bell user if ambigious and matchbeep enabled.
*/
if((flags & TCPL_AMBIGIOUS) && vp.matchbeep)
putchar(BEL);
}
int matching_chars(char *c1, char *c2)
{
int ret = 0;
for(; *c1++ == *c2++; ++ret);
return(ret);
}
syntax highlighted by Code2HTML, v. 0.9.1