getstr.cpp 15.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* getstr.cpp */

/* Synchronet string input routines */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
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 47 48 49 50 51
 *																			*
 * 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)
{
    size_t	i,l,x,z;    /* i=current position, l=length, j=printed chars */
                    /* x&z=misc */
52
	char	str1[256],str2[256],undo[256];
53
    uchar	ch;
54
	uchar	atr;
55

56 57 58
	console&=~(CON_UPARROW|CON_DOWNARROW|CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE);
	if(!(mode&K_WRAP))
		console&=~CON_INSERT;
59 60 61 62 63
	sys_status&=~SS_ABORT;
	if(mode&K_LINE && useron.misc&ANSI && !(mode&K_NOECHO)) {
		attr(cfg.color[clr_inputline]);
		for(i=0;i<maxlen;i++)
			outchar(SP);
64
		cursor_left(maxlen); 
65
	}
66 67
	if(wordwrap[0]) {
		strcpy(str1,wordwrap);
68 69
		wordwrap[0]=0; 
	}
70 71 72 73 74 75 76 77 78 79 80 81
	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;
82 83
			attr(i); 
		}
84 85
		rputs(str1);
		if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && useron.misc&ANSI)
86
			cleartoeol();  /* destroy to eol */ 
87
	}
88

89
	SAFECOPY(undo,str1);
90 91 92 93
	i=l=strlen(str1);
	if(mode&K_AUTODEL && str1[0] && !(mode&K_NOECHO)) {
		ch=getkey(mode|K_GETSTR);
		attr(atr);
94
		if(isprint(ch) || ch==DEL) {
95 96
			for(i=0;i<l;i++)
				bputs("\b \b");
97 98
			i=l=0; 
		}
99 100 101 102
		else {
			for(i=0;i<l;i++)
				outchar(BS);
			rputs(str1);
103 104
			i=l; 
		}
105
		if(ch!=SP && ch!=TAB)
106 107
			ungetkey(ch); 
	}
108

109 110 111 112 113
	if(mode&K_USEOFFSET) {
		i=getstr_offset;
		if(i>l)
			i=l;
		if(l-i) {
114
			cursor_left(l-i);
115 116 117
		}
	}

118 119 120
	if(console&CON_INSERT && useron.misc&ANSI && !(mode&K_NOECHO))
		insert_indicator();

121
	while(!(sys_status&SS_ABORT) && online && input_thread_running) {
122
		if(mode&K_LEFTEXIT
123 124 125
			&& console&(CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE))
			break;
		if(console&CON_UPARROW)
126 127
			break;
		if((ch=getkey(mode|K_GETSTR))==CR)
128
			break;
129
		if(sys_status&SS_ABORT || !online)
130
			break;
131 132
		if(ch==LF && mode&K_MSG) { /* Down-arrow same as CR */
			console|=CON_DOWNARROW;
133
			break;
134
		}
135 136 137 138 139 140 141 142
		if(ch==TAB && (mode&K_TAB || !(mode&K_WRAP)))	/* TAB same as CR */
			break;
		if(!i && mode&K_UPRLWR && (ch==SP || 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");
143 144 145 146
				return(0); 
			} 
		}
		getstr_offset=i;
147
		switch(ch) {
148
			case CTRL_A: /* Ctrl-A for ANSI */
149 150
				if(!(mode&K_MSG) || useron.rest&FLAG('A') || i>maxlen-3)
					break;
151
				if(console&CON_INSERT) {
152 153 154 155 156
					if(l<maxlen)
						l++;
					for(x=l;x>i;x--)
						str1[x]=str1[x-1];
					rprintf("%.*s",l-i,str1+i);
157
					cursor_left(l-i);
158
#if 0
159
					if(i==maxlen-1)
160 161
						console&=~CON_INSERT; 
#endif
162
				}
163 164
				outchar(str1[i++]=1);
				break;
165
			case CTRL_B: /* Ctrl-B Beginning of Line */
166
				if(useron.misc&ANSI && i && !(mode&K_NOECHO)) {
167
					cursor_left(i);
168 169
					i=0; 
				}
170
				break;
171
			case CTRL_D: /* Ctrl-D Delete word right */
172 173 174 175
				if(i<l) {
					x=i;
					while(x<l && str1[x]!=SP) {
						outchar(SP);
176 177
						x++; 
					}
178 179
					while(x<l && str1[x]==SP) {
						outchar(SP);
180 181
						x++; 
					}
182
					cursor_left(x-i);   /* move cursor back */
183 184 185
					z=i;
					while(z<l-(x-i))  {             /* move chars in string */
						outchar(str1[z]=str1[z+(x-i)]);
186 187
						z++; 
					}
188 189
					while(z<l) {                    /* write over extra chars */
						outchar(SP);
190 191
						z++; 
					}
192
					cursor_left(z-i);
193 194
					l-=x-i;							/* l=new length */
				}
195
				break;
196
			case CTRL_E: /* Ctrl-E End of line */
197
				if(useron.misc&ANSI && i<l) {
198
					cursor_right(l-i);  /* move cursor to eol */
199 200
					i=l; 
				}
201
				break;
202
			case CTRL_F: /* Ctrl-F move cursor forewards */
203
				if(i<l && (useron.misc&ANSI)) {
204
					cursor_right();   /* move cursor right one */
205 206
					i++; 
				}
207
				break;
208
			case CTRL_G: /* Bell */
209 210 211 212
				if(!(mode&K_MSG))
					break;
				if(useron.rest&FLAG('B')) {
					if (i+6<maxlen) {
213
						if(console&CON_INSERT) {
214 215 216 217
							for(x=l+6;x>i;x--)
								str1[x]=str1[x-6];
							if(l+5<maxlen)
								l+=6;
218
#if 0
219
							if(i==maxlen-1)
220 221
								console&=~CON_INSERT; 
#endif
222
						}
223 224 225 226 227 228 229
						str1[i++]='(';
						str1[i++]='b';
						str1[i++]='e';
						str1[i++]='e';
						str1[i++]='p';
						str1[i++]=')';
						if(!(mode&K_NOECHO))
230 231
							bputs("(beep)"); 
					}
232
					if(console&CON_INSERT)
233
						redrwstr(str1,i,l,0);
234 235
					break; 
				}
236
				if(console&CON_INSERT) {
237 238 239 240
					if(l<maxlen)
						l++;
					for(x=l;x>i;x--)
						str1[x]=str1[x-1];
241
#if 0
242
					if(i==maxlen-1)
243 244
						console&=~CON_INSERT; 
#endif
245 246
				}
				if(i<maxlen) {
247
					str1[i++]=BEL;
248
					if(!(mode&K_NOECHO))
249 250 251
						outchar(BEL); 
				}
				break;
252
			case CTRL_H:	/* Ctrl-H/Backspace */
253
				if(i==0) {
254
					console|=CON_BACKSPACE;
255
					break;
256
				}
257 258 259 260 261 262 263
				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]);
264 265
						z++; 
					}
266
					outchar(SP);        /* write over the last char */
267
					cursor_left((l-i)+1); 
268
				}
269 270 271
				else if(!(mode&K_NOECHO))
					bputs("\b \b");
				break;
272
			case CTRL_I:	/* Ctrl-I/TAB */
273
				if(!(i%EDIT_TABSIZE)) {
274
					if(console&CON_INSERT) {
275 276 277 278
						if(l<maxlen)
							l++;
						for(x=l;x>i;x--)
							str1[x]=str1[x-1];
279
#if 0
280
						if(i==maxlen-1)
281 282
							console&=~CON_INSERT; 
#endif
283
					}
284 285
					str1[i++]=SP;
					if(!(mode&K_NOECHO))
286 287
						outchar(SP); 
				}
288
				while(i<maxlen && i%EDIT_TABSIZE) {
289
					if(console&CON_INSERT) {
290 291 292 293
						if(l<maxlen)
							l++;
						for(x=l;x>i;x--)
							str1[x]=str1[x-1];
294
#if 0
295
						if(i==maxlen-1)
296 297
							console&=~CON_INSERT; 
#endif
298
					}
299 300
					str1[i++]=SP;
					if(!(mode&K_NOECHO))
301 302
						outchar(SP); 
				}
303
				if(console&CON_INSERT && !(mode&K_NOECHO))
304 305 306
					redrwstr(str1,i,l,0);
				break;

307
			case CTRL_L:    /* Ctrl-L   Center line (used to be Ctrl-V) */
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
				str1[l]=0;
				l=bstrlen(str1);
				if(!l) break;
				for(x=0;x<(maxlen-l)/2;x++)
					str2[x]=SP;
				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)
326 327
						attr(LIGHTGRAY); 
				}
328 329
				if(!(mode&K_NOCRLF))
					CRLF;
330 331
				return(l);

332
			case CTRL_N:    /* Ctrl-N Next word */
333 334 335 336 337 338
				if(i<l && (useron.misc&ANSI)) {
					x=i;
					while(str1[i]!=SP && i<l)
						i++;
					while(str1[i]==SP && i<l)
						i++;
339
					cursor_right(i-x); 
340
				}
341
				break;
342
			case CTRL_R:    /* Ctrl-R Redraw Line */
343 344 345
				if(!(mode&K_NOECHO))
					redrwstr(str1,i,l,0);
				break;
346
			case CTRL_V:	/* Ctrl-V			Toggles Insert/Overwrite */
347 348
				if(!(useron.misc&ANSI) || mode&K_NOECHO)
					break;
349
				console^=CON_INSERT;
350
				insert_indicator();
351
				break;
352
			case CTRL_W:    /* Ctrl-W   Delete word left */
353 354 355 356
				if(i<l) {
					x=i;                            /* x=original offset */
					while(i && str1[i-1]==SP) {
						outchar(BS);
357 358
						i--; 
					}
359 360
					while(i && str1[i-1]!=SP) {
						outchar(BS);
361 362
						i--; 
					}
363 364 365
					z=i;                            /* i=z=new offset */
					while(z<l-(x-i))  {             /* move chars in string */
						outchar(str1[z]=str1[z+(x-i)]);
366 367
						z++; 
					}
368 369
					while(z<l) {                    /* write over extra chars */
						outchar(SP);
370 371
						z++; 
					}
372
					cursor_left(z-i);				/* back to new x corridnant */
373 374
					l-=x-i;                         /* l=new length */
				} else {
375 376 377 378
					while(i && str1[i-1]==SP) {
						i--;
						l--;
						if(!(mode&K_NOECHO))
379 380
							bputs("\b \b"); 
					}
381 382 383 384
					while(i && str1[i-1]!=SP) {
						i--;
						l--;
						if(!(mode&K_NOECHO))
385 386 387
							bputs("\b \b"); 
					} 
				}
388
				break;
389 390 391
			case CTRL_Y:    /* Ctrl-Y   Delete to end of line */
				if(i!=l) {	/* if not at EOL */
					if(useron.misc&ANSI && !(mode&K_NOECHO))
392
						cleartoeol();
393 394 395 396
					l=i; 
					break;
				}
				/* fall-through */
397
			case CTRL_X:    /* Ctrl-X   Delete entire line */
398 399 400
				if(mode&K_NOECHO)
					l=0;
				else {
401
					if(useron.misc&ANSI) {
402 403
						cursor_left(i);
						cleartoeol();
404 405 406 407 408 409 410 411 412 413
						l=0;
					} else {
						while(i<l) {
							outchar(SP);
							i++; 
						}
						while(l) {
							l--;
							bputs("\b \b"); 
						} 
414 415
					}
				}
416
				i=0;
417
				console|=CON_DELETELINE;
418
				break;
419 420 421 422 423
			case CTRL_Z:	/* Undo */
				SAFECOPY(str1,undo);
				i=l=strlen(str1);
				rprintf("\r%s",str1);
				if(useron.misc&ANSI)
424
					cleartoeol();  /* destroy to eol */ 
425 426 427 428 429 430 431 432
				break;
			case 28:    /* Ctrl-\ Previous word */
				if(i && (useron.misc&ANSI) && !(mode&K_NOECHO)) {
					x=i;
					while(str1[i-1]==SP && i)
						i--;
					while(str1[i-1]!=SP && i)
						i--;
433
					cursor_left(x-i); 
434
				}
435 436
				break;
			case 29:  /* Ctrl-]/Left Arrow  Reverse Cursor Movement */
437 438 439 440 441 442
				if(i==0) {
					if(mode&K_LEFTEXIT)
						console|=CON_LEFTARROW;
					break;
				}
				if((useron.misc&ANSI) && !(mode&K_NOECHO)) {
443
					cursor_left();   /* move cursor left one */
444 445
					i--; 
				}
446 447 448 449
				break;
			case 30:  /* Ctrl-^/Up Arrow */
				if(!(mode&K_EDIT))
					break;
450
#if 1
451 452 453 454
				if(i>l)
					l=i;
				str1[l]=0;
				strcpy(strout,str1);
455
				if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
456 457 458 459 460
					redrwstr(strout,i,l,K_MSG);
				if(mode&K_LINE && !(mode&K_NOECHO))
					attr(LIGHTGRAY);
				console|=CON_UPARROW;
				return(l);
461 462 463 464
#else
				console|=CON_UPARROW;
				break;
#endif
465
			case DEL:  /* Ctrl-BkSpc (DEL) Delete current char */
466 467 468 469 470 471 472 473 474 475 476 477 478
				if(i==l) {	/* Backspace if end of line */
					if(i) {
						i--;
						l--;
						if(!(mode&K_NOECHO))
							bputs("\b \b");
					}
					break;
				}
				l--;
				z=i;
				while(z<l)  {       /* move the characters in the line */
					outchar(str1[z]=str1[z+1]);
479 480
					z++; 
				}
481
				outchar(SP);        /* write over the last char */
482
				cursor_left((l-i)+1);
483 484
				break;
			default:
485
				if(mode&K_WRAP && i==maxlen && ch>=SP && !(console&CON_INSERT)) {
486 487 488
					str1[i]=0;
					if(ch==SP && !(mode&K_CHAT)) { /* don't wrap a space */ 
						strcpy(strout,str1);	   /* as last char */
489
						if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
490
							redrwstr(strout,i,l,K_MSG);
491
						if(!(mode&(K_NOECHO|K_NOCRLF)))
492
							CRLF;
493 494
						return(i); 
					}
495 496 497 498 499 500 501 502
					x=i-1;
					z=1;
					wordwrap[0]=ch;
					while(str1[x]!=SP && x)
						wordwrap[z++]=str1[x--];
					if(x<(maxlen/2)) {
						wordwrap[1]=0;  /* only wrap one character */
						strcpy(strout,str1);
503
						if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
504
							redrwstr(strout,i,l,K_MSG);
505
						if(!(mode&(K_NOECHO|K_NOCRLF)))
506
							CRLF;
507 508
						return(i); 
					}
509 510 511
					wordwrap[z]=0;
					if(!(mode&K_NOECHO))
						while(z--) {
512
							rputs("\b \b");
513 514
							i--; 
						}
515 516 517
					strrev(wordwrap);
					str1[x]=0;
					strcpy(strout,str1);
518
					if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
519 520
						redrwstr(strout,i,x,mode);
					if(!(mode&(K_NOECHO|K_NOCRLF)))
521
						CRLF;
522 523
					return(x); 
				}
524 525 526 527 528 529 530
				if(i<maxlen && ch>=SP) {
					if(mode&K_UPRLWR)
						if(!i || (i && (str1[i-1]==SP || str1[i-1]=='-'
							|| str1[i-1]=='.' || str1[i-1]=='_')))
							ch=toupper(ch);
						else
							ch=tolower(ch);
531
					if(console&CON_INSERT && i!=l) {
532 533 534 535 536
						if(l<maxlen)    /* l<maxlen */
							l++;
						for(x=l;x>i;x--)
							str1[x]=str1[x-1];
						rprintf("%.*s",l-i,str1+i);
537
						cursor_left(l-i);
538
#if 0
539 540
						if(i==maxlen-1) {
							bputs("  \b\b");
541
							console&=~CON_INSERT; 
542
						} 
543
#endif
544
					}
545 546
					str1[i++]=ch;
					if(!(mode&K_NOECHO))
547 548 549
						outchar(ch); 
				} 
		}
550 551 552
		if(i>l)
			l=i;
		if(mode&K_CHAT && !l)
553 554 555
			return(0); 
	}
	getstr_offset=i;
556 557 558 559 560 561 562
	if(!online)
		return(0);
	if(i>l)
		l=i;
	str1[l]=0;
	if(!(sys_status&SS_ABORT)) {
		strcpy(strout,str1);
563
		if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
564 565
			redrwstr(strout,i,l,K_MSG); 
	}
566 567 568 569 570 571 572
	else
		l=0;
	if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY);
	if(!(mode&(K_NOCRLF|K_NOECHO))) {
		outchar(CR);
		if(!(mode&K_MSG && sys_status&SS_ABORT))
			outchar(LF);
573 574
		lncntr=0; 
	}
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
	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 'Q' or ctrl-c                                            */
/****************************************************************************/
long sbbs_t::getnum(ulong max)
{
    uchar ch,n=0;
	long i=0;

	while(online) {
		ch=getkey(K_UPPER);
		if(ch>0x7f)
			continue;
		if(ch=='Q') {
			outchar('Q');
			if(useron.misc&COLDKEYS)
				ch=getkey(K_UPPER);
596
			if(ch==BS || ch==DEL) {
597
				bputs("\b \b");
598 599
				continue; 
			}
600 601
			CRLF;
			lncntr=0;
602 603
			return(-1); 
		}
604 605 606
		else if(sys_status&SS_ABORT) {
			CRLF;
			lncntr=0;
607 608
			return(-1); 
		}
609 610 611
		else if(ch==CR) {
			CRLF;
			lncntr=0;
612 613
			return(i); 
		}
614
		else if((ch==BS || ch==DEL) && n) {
615 616
			bputs("\b \b");
			i/=10;
617 618
			n--; 
		}
619 620 621 622 623 624 625 626
		else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (ch!='0' || n)) {
			i*=10L;
			n++;
			i+=ch&0xf;
			outchar(ch);
			if(i*10UL>max && !(useron.misc&COLDKEYS)) {
				CRLF;
				lncntr=0;
627 628 629 630
				return(i); 
			} 
		} 
	}
631 632
	return(0);
}
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647

void sbbs_t::insert_indicator(void)
{
	ANSI_SAVE();
	GOTOXY(80,1);
	uchar z=curatr;                       /* and go to EOL */
	if(console&CON_INSERT) {
		attr(BLINK|BLACK|(LIGHTGRAY<<4));
		outchar('I');
	} else {
		attr(LIGHTGRAY);
		outchar(' ');
	}
	attr(z);
	ANSI_RESTORE();
648
}