/****************************************************************************** * 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 #include /*** 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); }