Newer
Older
/* Synchronet string input routines */
// vi: tabstop=4
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
/****************************************************************************/
/* Waits for remote or local user to input a CR terminated string. 'length' */
/* is the maximum number of characters that getstr will allow the user to */
/* input into the string. 'mode' specifies upper case characters are echoed */
/* or wordwrap or if in message input (^A sequences allowed). ^W backspaces */
/* a word, ^X backspaces a line, ^Gs, BSs, TABs are processed, LFs ignored. */
/* ^N non-destructive BS, ^V center line. Valid keys are echoed. */
/****************************************************************************/
size_t sbbs_t::getstr(char *strout, size_t maxlen, long mode, const str_list_t history)
{
size_t i,l,x,z; /* i=current position, l=length, j=printed chars */
/* x&z=misc */
char str1[256],str2[256],undo[256];
int hidx = -1;
console&=~(CON_UPARROW|CON_DOWNARROW|CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE);
if(!(mode&K_WRAP))
console&=~CON_INSERT;
if(cols >= TERM_COLS_MIN
&& column + (long)maxlen >= cols) /* Don't allow the terminal to auto line-wrap */
maxlen = cols-column-1;
if(mode&K_LINE && (term&(ANSI|PETSCII)) && !(mode&K_NOECHO)) {
attr(cfg.color[clr_inputline]);
for(i=0;i<maxlen;i++)
cursor_left(maxlen);
SAFECOPY(str1,wordwrap);
wordwrap[0]=0;
}
else str1[0]=0;
if(mode&K_EDIT)
strcat(str1,strout);
else
strout[0]=0;
if(strlen(str1)>maxlen)
str1[maxlen]=0;
atr=curatr;
if(!(mode&K_NOECHO)) {
if(mode&K_AUTODEL && str1[0]) {
i=(cfg.color[clr_inputline]&0x77)<<4;
i|=(cfg.color[clr_inputline]&0x77)>>4;
attr(i);
}
if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)))
cleartoeol(); /* destroy to eol */
SAFECOPY(undo,str1);
i=l=strlen(str1);
if(mode&K_AUTODEL && str1[0] && !(mode&K_NOECHO)) {
ch=getkey(mode|K_GETSTR);
attr(atr);
i=l=0;
}
else {
for(i=0;i<l;i++)
outchar(BS);
i=l;
}
ungetkey(ch);
}
if(mode&K_USEOFFSET) {
i=getstr_offset;
if(i>l)
i=l;
if(l-i) {
cursor_left(l-i);
}
}
insert_indicator();
while(!(sys_status&SS_ABORT) && online && input_thread_running) {
if(mode&K_LEFTEXIT
&& console&(CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE))
break;
if(console&CON_UPARROW)
break;
if((ch=getkey(mode|K_GETSTR))==CR)
if(sys_status&SS_ABORT || !online)
if(ch==LF && mode&K_MSG) { /* Down-arrow same as CR */
console|=CON_DOWNARROW;
}
if(ch==TAB && (mode&K_TAB || (!(mode&K_WRAP) && history == NULL))) /* TAB same as CR */
if(!i && (mode&(K_UPRLWR|K_TRIM)) && (ch==' ' || ch==TAB))
continue; /* ignore beginning white space if upper/lower */
if(mode&K_E71DETECT && (uchar)ch==(CR|0x80) && l>1) {
if(strstr(str1,"")) {
bputs("\r\n\r\nYou must set your terminal to NO PARITY, "
"8 DATA BITS, and 1 STOP BIT (N-8-1).\7\r\n");
return(0);
}
getstr_offset=i;
if(!(mode&K_MSG) || useron.rest&FLAG('A') || i>maxlen-3)
break;
if(console&CON_INSERT) {
if(l<maxlen)
l++;
for(x=l;x>i;x--)
str1[x]=str1[x-1];
column+=rprintf("%.*s",(int)(l-i),str1+i);
cursor_left(l-i);
console&=~CON_INSERT;
#endif
}
outchar(str1[i++]=1);
break;
case TERM_KEY_HOME: /* Ctrl-B Beginning of Line */
if(i && !(mode&K_NOECHO)) {
cursor_left(i);
i=0;
}
case CTRL_D: /* Ctrl-D Delete word right */
while(x<l && str1[x]!=' ') {
outchar(' ');
x++;
}
while(x<l && str1[x]==' ') {
outchar(' ');
x++;
}
cursor_left(x-i); /* move cursor back */
z=i;
while(z<l-(x-i)) { /* move chars in string */
outchar(str1[z]=str1[z+(x-i)]);
z++;
}
while(z<l) { /* write over extra chars */
z++;
}
cursor_left(z-i);
l-=x-i; /* l=new length */
}
case TERM_KEY_END: /* Ctrl-E End of line */
cursor_right(l-i); /* move cursor to eol */
i=l;
}
case TERM_KEY_RIGHT: /* Ctrl-F move cursor forward */
cursor_right(); /* move cursor right one */
i++;
}
if(!(mode&K_MSG))
break;
if(useron.rest&FLAG('B')) {
if (i+6<maxlen) {
if(console&CON_INSERT) {
for(x=l+6;x>i;x--)
str1[x]=str1[x-6];
if(l+5<maxlen)
l+=6;
console&=~CON_INSERT;
#endif
}
str1[i++]='(';
str1[i++]='b';
str1[i++]='e';
str1[i++]='e';
str1[i++]='p';
str1[i++]=')';
if(!(mode&K_NOECHO))
bputs("(beep)");
}
if(console&CON_INSERT)
break;
}
if(console&CON_INSERT) {
if(l<maxlen)
l++;
for(x=l;x>i;x--)
str1[x]=str1[x-1];
console&=~CON_INSERT;
#endif
}
if(i<maxlen) {
str1[i++]=BEL;
outchar(BEL);
}
break;
if(i==0) {
console|=CON_BACKSPACE;
}
i--;
l--;
if(i!=l) { /* Deleting char in middle of line */
outchar(BS);
z=i;
while(z<l) { /* move the characters in the line */
outchar(str1[z]=str1[z+1]);
z++;
}
outchar(' '); /* write over the last char */
cursor_left((l-i)+1);
}
if(history != NULL) {
if(l < 1)
break;
int hi;
for(hi=0; history[hi] != NULL; hi++)
if(strnicmp(history[hi], str1, l) == 0) {
hidx = hi;
SAFECOPY(str1, history[hi]);
while(i--)
backspace();
i=l=strlen(str1);
rputs(str1);
cleartoeol();
break;
}
break;
}
if(!(i%EDIT_TABSIZE)) {
if(console&CON_INSERT) {
if(l<maxlen)
l++;
for(x=l;x>i;x--)
str1[x]=str1[x-1];
console&=~CON_INSERT;
#endif
}
}
while(i<maxlen && i%EDIT_TABSIZE) {
if(console&CON_INSERT) {
if(l<maxlen)
l++;
for(x=l;x>i;x--)
str1[x]=str1[x-1];
console&=~CON_INSERT;
#endif
}
}
if(console&CON_INSERT && !(mode&K_NOECHO))
redrwstr(str1,i,l,0);
break;
case CTRL_L: /* Ctrl-L Center line (used to be Ctrl-V) */
str1[l]=0;
l=bstrlen(str1);
if(!l) break;
for(x=0;x<(maxlen-l)/2;x++)
str2[x]=0;
strcat(str2,str1);
strcpy(strout,str2);
l=strlen(strout);
if(mode&K_NOECHO)
return(l);
if(mode&K_MSG)
redrwstr(strout,i,l,K_MSG);
else {
while(i--)
bputs("\b");
bputs(strout);
if(mode&K_LINE)
attr(LIGHTGRAY);
}
if(!(mode&K_NOCRLF))
CRLF;
while(str1[i]!=' ' && i<l)
while(str1[i]==' ' && i<l)
cursor_right(i-x);
}
if(!(mode&K_NOECHO))
redrwstr(str1,i,l,0);
break;
case TERM_KEY_INSERT: /* Ctrl-V Toggles Insert/Overwrite */
if(mode&K_NOECHO)
console^=CON_INSERT;
insert_indicator();
case CTRL_W: /* Ctrl-W Delete word left */
if(i<l) {
x=i; /* x=original offset */
while(i && str1[i-1]==' ') {
i--;
}
while(i && str1[i-1]!=' ') {
i--;
}
z=i; /* i=z=new offset */
while(z<l-(x-i)) { /* move chars in string */
outchar(str1[z]=str1[z+(x-i)]);
z++;
}
while(z<l) { /* write over extra chars */
z++;
}
cursor_left(z-i); /* back to new x corridnant */
l-=x-i; /* l=new length */
} else {
while(i && str1[i-1]==' ') {
i--;
l--;
if(!(mode&K_NOECHO))
}
while(i && str1[i-1]!=' ') {
i--;
l--;
if(!(mode&K_NOECHO))
}
}
case CTRL_Y: /* Ctrl-Y Delete to end of line */
if(i!=l) { /* if not at EOL */
if(!(mode&K_NOECHO))
cleartoeol();
l=i;
break;
}
/* fall-through */
case CTRL_X: /* Ctrl-X Delete entire line */
if(mode&K_NOECHO)
l=0;
else {
cursor_left(i);
cleartoeol();
l=0;
}
console|=CON_DELETELINE;
case CTRL_Z: /* Undo */
if(!(mode&K_NOECHO)) {
while(i--)
backspace();
}
SAFECOPY(str1,undo);
i=l=strlen(str1);
rputs(str1);
cleartoeol();
case CTRL_BACKSLASH: /* Ctrl-\ Previous word */
if(i && !(mode&K_NOECHO)) {
while(str1[i-1]==' ' && i)
while(str1[i-1]!=' ' && i)
cursor_left(x-i);
}
case TERM_KEY_LEFT: /* Ctrl-]/Left Arrow Reverse Cursor Movement */
if(i==0) {
if(mode&K_LEFTEXIT)
console|=CON_LEFTARROW;
break;
}
if(!(mode&K_NOECHO)) {
cursor_left(); /* move cursor left one */
i--;
}
case TERM_KEY_DOWN:
if(history != NULL) {
if(hidx < 0) {
outchar(BEL);
break;
}
hidx--;
if(hidx < 0)
SAFECOPY(str1, undo);
else
SAFECOPY(str1, history[hidx]);
while(i--)
backspace();
i=l=strlen(str1);
rputs(str1);
cleartoeol();
break;
}
break;
case TERM_KEY_UP: /* Ctrl-^/Up Arrow */
if(history != NULL) {
if(history[hidx + 1] == NULL) {
outchar(BEL);
break;
}
hidx++;
while(i--)
backspace();
SAFECOPY(str1, history[hidx]);
i=l=strlen(str1);
rputs(str1);
cleartoeol();
break;
}
#if 1
if(i>l)
l=i;
str1[l]=0;
strcpy(strout,str1);
if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
redrwstr(strout,i,l,K_MSG);
if(mode&K_LINE && !(mode&K_NOECHO))
attr(LIGHTGRAY);
console|=CON_UPARROW;
return(l);
#else
console|=CON_UPARROW;
break;
#endif
case TERM_KEY_DELETE: /* Ctrl-BkSpc (DEL) Delete current char */
if(i==l) { /* Backspace if end of line */
if(i) {
i--;
l--;
if(!(mode&K_NOECHO))
}
break;
}
l--;
z=i;
while(z<l) { /* move the characters in the line */
outchar(str1[z]=str1[z+1]);
z++;
}
outchar(' '); /* write over the last char */
cursor_left((l-i)+1);
if(mode&K_WRAP && i==maxlen && ch>=' ' && !(console&CON_INSERT)) {
if(ch==' ' && !(mode&K_CHAT)) { /* don't wrap a space */
strcpy(strout,str1); /* as last char */
if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
if(!(mode&(K_NOECHO|K_NOCRLF)))
return(i);
}
x=i-1;
z=1;
wordwrap[0]=ch;
while(str1[x]!=' ' && x)
wordwrap[z++]=str1[x--];
if(x<(maxlen/2)) {
wordwrap[1]=0; /* only wrap one character */
strcpy(strout,str1);
if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
if(!(mode&(K_NOECHO|K_NOCRLF)))
return(i);
}
wordwrap[z]=0;
if(!(mode&K_NOECHO))
while(z--) {
i--;
}
strrev(wordwrap);
str1[x]=0;
strcpy(strout,str1);
if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
redrwstr(strout,i,x,mode);
if(!(mode&(K_NOECHO|K_NOCRLF)))
return(x);
}
if(i<maxlen && ch>=' ') {
if(ch==' ' && (mode&K_TRIM) && i && str1[i-1] == ' ')
continue;
if(!i || (i && (str1[i-1]==' ' || str1[i-1]=='-'
|| str1[i-1]=='.' || str1[i-1]=='_')))
ch=toupper(ch);
else
ch=tolower(ch);
if(console&CON_INSERT && i!=l) {
if(l<maxlen) /* l<maxlen */
l++;
for(x=l;x>i;x--)
str1[x]=str1[x-1];
column+=rprintf("%.*s",(int)(l-i),str1+i);
cursor_left(l-i);
if(i==maxlen-1) {
bputs(" \b\b");
console&=~CON_INSERT;
}
}
str1[i++]=ch;
if(!(mode&K_NOECHO))
outchar(ch);
} else
outchar(BEL); /* Added at Angus McLeod's request */
}
if(i>l)
l=i;
if(mode&K_CHAT && !l)
return(0);
}
getstr_offset=i;
if(!online)
return(0);
if(i>l)
l=i;
str1[l]=0;
if(!(sys_status&SS_ABORT)) {
strcpy(strout,str1);
if(mode&K_TRIM)
truncsp(strout);
if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
redrwstr(strout,i,l,K_MSG);
}
else
l=0;
if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY);
if(!(mode&(K_NOCRLF|K_NOECHO))) {
if(!(mode&K_MSG && sys_status&SS_ABORT)) {
CRLF;
} else
carriage_return();
lncntr=0;
}
return(l);
}
/****************************************************************************/
/* Hot keyed number input routine. */
/* Returns a valid number between 1 and max, 0 if no number entered, or -1 */
/* if the user hit the quit key (e.g. 'Q') or ctrl-c */
/****************************************************************************/
long sbbs_t::getnum(ulong max, ulong dflt)
{
uchar ch,n=0;
long i=0;
while(online) {
ch=getkey(K_UPPER);
if(ch>0x7f)
continue;
if(ch==text[YNQP][2]) {
outchar(text[YNQP][2]);
if(useron.misc&COLDKEYS)
ch=getkey(K_UPPER);
continue;
}
return(-1);
}
else if(sys_status&SS_ABORT) {
CRLF;
lncntr=0;
return(-1);
}
else if(ch==CR) {
CRLF;
lncntr=0;
if(!n)
return(dflt);
return(i);
}
else if((ch==BS || ch==DEL) && n) {
n--;
}
else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (dflt || ch!='0' || n)) {
i*=10L;
n++;
i+=ch&0xf;
outchar(ch);
if(i*10UL>max && !(useron.misc&COLDKEYS)) {
CRLF;
lncntr=0;
return(i);
}
}
}
void sbbs_t::insert_indicator(void)
{
if(term_supports(ANSI)) {
ansi_save();
ansi_gotoxy(cols,1);
if(console&CON_INSERT) {
attr(BLINK|BLACK|(LIGHTGRAY<<4));
outchar('I');
} else {
attr(LIGHTGRAY);
outchar(' ');
}
attr(z);
ansi_restore();