|
|
1.1 root 1: /* getstr.cpp */
2:
3: /* Synchronet string input routines */
4:
5: /* $Id: getstr.cpp,v 1.22 2006/08/23 01:45:05 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39:
40: /****************************************************************************/
41: /* Waits for remote or local user to input a CR terminated string. 'length' */
42: /* is the maximum number of characters that getstr will allow the user to */
43: /* input into the string. 'mode' specifies upper case characters are echoed */
44: /* or wordwrap or if in message input (^A sequences allowed). ^W backspaces */
45: /* a word, ^X backspaces a line, ^Gs, BSs, TABs are processed, LFs ignored. */
46: /* ^N non-destructive BS, ^V center line. Valid keys are echoed. */
47: /****************************************************************************/
48: size_t sbbs_t::getstr(char *strout, size_t maxlen, long mode)
49: {
50: size_t i,l,x,z; /* i=current position, l=length, j=printed chars */
51: /* x&z=misc */
52: char str1[256],str2[256],undo[256];
53: uchar ch;
54: uchar atr;
55:
56: console&=~(CON_UPARROW|CON_DOWNARROW|CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE);
57: if(!(mode&K_WRAP))
58: console&=~CON_INSERT;
59: sys_status&=~SS_ABORT;
60: if(mode&K_LINE && term_supports(ANSI) && !(mode&K_NOECHO)) {
61: attr(cfg.color[clr_inputline]);
62: for(i=0;i<maxlen;i++)
63: outchar(' ');
64: cursor_left(maxlen);
65: }
66: if(wordwrap[0]) {
67: strcpy(str1,wordwrap);
68: wordwrap[0]=0;
69: }
70: else str1[0]=0;
71: if(mode&K_EDIT)
72: strcat(str1,strout);
73: else
74: strout[0]=0;
75: if(strlen(str1)>maxlen)
76: str1[maxlen]=0;
77: atr=curatr;
78: if(!(mode&K_NOECHO)) {
79: if(mode&K_AUTODEL && str1[0]) {
80: i=(cfg.color[clr_inputline]&0x77)<<4;
81: i|=(cfg.color[clr_inputline]&0x77)>>4;
82: attr(i);
83: }
84: rputs(str1);
85: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && term_supports(ANSI))
86: cleartoeol(); /* destroy to eol */
87: }
88:
89: SAFECOPY(undo,str1);
90: i=l=strlen(str1);
91: if(mode&K_AUTODEL && str1[0] && !(mode&K_NOECHO)) {
92: ch=getkey(mode|K_GETSTR);
93: attr(atr);
94: if(isprint(ch) || ch==DEL) {
95: for(i=0;i<l;i++)
96: backspace();
97: i=l=0;
98: }
99: else {
100: for(i=0;i<l;i++)
101: outchar(BS);
102: rputs(str1);
103: i=l;
104: }
105: if(ch!=' ' && ch!=TAB)
106: ungetkey(ch);
107: }
108:
109: if(mode&K_USEOFFSET) {
110: i=getstr_offset;
111: if(i>l)
112: i=l;
113: if(l-i) {
114: cursor_left(l-i);
115: }
116: }
117:
118: if(console&CON_INSERT && term_supports(ANSI) && !(mode&K_NOECHO))
119: insert_indicator();
120:
121: while(!(sys_status&SS_ABORT) && online && input_thread_running) {
122: if(mode&K_LEFTEXIT
123: && console&(CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE))
124: break;
125: if(console&CON_UPARROW)
126: break;
127: if((ch=getkey(mode|K_GETSTR))==CR)
128: break;
129: if(sys_status&SS_ABORT || !online)
130: break;
131: if(ch==LF && mode&K_MSG) { /* Down-arrow same as CR */
132: console|=CON_DOWNARROW;
133: break;
134: }
135: if(ch==TAB && (mode&K_TAB || !(mode&K_WRAP))) /* TAB same as CR */
136: break;
137: if(!i && mode&K_UPRLWR && (ch==' ' || ch==TAB))
138: continue; /* ignore beginning white space if upper/lower */
139: if(mode&K_E71DETECT && (uchar)ch==(CR|0x80) && l>1) {
140: if(strstr(str1,"��")) {
141: bputs("\r\n\r\nYou must set your terminal to NO PARITY, "
142: "8 DATA BITS, and 1 STOP BIT (N-8-1).\7\r\n");
143: return(0);
144: }
145: }
146: getstr_offset=i;
147: switch(ch) {
148: case CTRL_A: /* Ctrl-A for ANSI */
149: if(!(mode&K_MSG) || useron.rest&FLAG('A') || i>maxlen-3)
150: break;
151: if(console&CON_INSERT) {
152: if(l<maxlen)
153: l++;
154: for(x=l;x>i;x--)
155: str1[x]=str1[x-1];
156: rprintf("%.*s",l-i,str1+i);
157: cursor_left(l-i);
158: #if 0
159: if(i==maxlen-1)
160: console&=~CON_INSERT;
161: #endif
162: }
163: outchar(str1[i++]=1);
164: break;
165: case CTRL_B: /* Ctrl-B Beginning of Line */
166: if(term_supports(ANSI) && i && !(mode&K_NOECHO)) {
167: cursor_left(i);
168: i=0;
169: }
170: break;
171: case CTRL_D: /* Ctrl-D Delete word right */
172: if(i<l) {
173: x=i;
174: while(x<l && str1[x]!=' ') {
175: outchar(' ');
176: x++;
177: }
178: while(x<l && str1[x]==' ') {
179: outchar(' ');
180: x++;
181: }
182: cursor_left(x-i); /* move cursor back */
183: z=i;
184: while(z<l-(x-i)) { /* move chars in string */
185: outchar(str1[z]=str1[z+(x-i)]);
186: z++;
187: }
188: while(z<l) { /* write over extra chars */
189: outchar(' ');
190: z++;
191: }
192: cursor_left(z-i);
193: l-=x-i; /* l=new length */
194: }
195: break;
196: case CTRL_E: /* Ctrl-E End of line */
197: if(term_supports(ANSI) && i<l) {
198: cursor_right(l-i); /* move cursor to eol */
199: i=l;
200: }
201: break;
202: case CTRL_F: /* Ctrl-F move cursor forewards */
203: if(i<l && term_supports(ANSI)) {
204: cursor_right(); /* move cursor right one */
205: i++;
206: }
207: break;
208: case CTRL_G: /* Bell */
209: if(!(mode&K_MSG))
210: break;
211: if(useron.rest&FLAG('B')) {
212: if (i+6<maxlen) {
213: if(console&CON_INSERT) {
214: for(x=l+6;x>i;x--)
215: str1[x]=str1[x-6];
216: if(l+5<maxlen)
217: l+=6;
218: #if 0
219: if(i==maxlen-1)
220: console&=~CON_INSERT;
221: #endif
222: }
223: str1[i++]='(';
224: str1[i++]='b';
225: str1[i++]='e';
226: str1[i++]='e';
227: str1[i++]='p';
228: str1[i++]=')';
229: if(!(mode&K_NOECHO))
230: bputs("(beep)");
231: }
232: if(console&CON_INSERT)
233: redrwstr(str1,i,l,0);
234: break;
235: }
236: if(console&CON_INSERT) {
237: if(l<maxlen)
238: l++;
239: for(x=l;x>i;x--)
240: str1[x]=str1[x-1];
241: #if 0
242: if(i==maxlen-1)
243: console&=~CON_INSERT;
244: #endif
245: }
246: if(i<maxlen) {
247: str1[i++]=BEL;
248: if(!(mode&K_NOECHO))
249: outchar(BEL);
250: }
251: break;
252: case CTRL_H: /* Ctrl-H/Backspace */
253: if(i==0) {
254: console|=CON_BACKSPACE;
255: break;
256: }
257: i--;
258: l--;
259: if(i!=l) { /* Deleting char in middle of line */
260: outchar(BS);
261: z=i;
262: while(z<l) { /* move the characters in the line */
263: outchar(str1[z]=str1[z+1]);
264: z++;
265: }
266: outchar(' '); /* write over the last char */
267: cursor_left((l-i)+1);
268: }
269: else if(!(mode&K_NOECHO))
270: backspace();
271: break;
272: case CTRL_I: /* Ctrl-I/TAB */
273: if(!(i%EDIT_TABSIZE)) {
274: if(console&CON_INSERT) {
275: if(l<maxlen)
276: l++;
277: for(x=l;x>i;x--)
278: str1[x]=str1[x-1];
279: #if 0
280: if(i==maxlen-1)
281: console&=~CON_INSERT;
282: #endif
283: }
284: str1[i++]=' ';
285: if(!(mode&K_NOECHO))
286: outchar(' ');
287: }
288: while(i<maxlen && i%EDIT_TABSIZE) {
289: if(console&CON_INSERT) {
290: if(l<maxlen)
291: l++;
292: for(x=l;x>i;x--)
293: str1[x]=str1[x-1];
294: #if 0
295: if(i==maxlen-1)
296: console&=~CON_INSERT;
297: #endif
298: }
299: str1[i++]=' ';
300: if(!(mode&K_NOECHO))
301: outchar(' ');
302: }
303: if(console&CON_INSERT && !(mode&K_NOECHO))
304: redrwstr(str1,i,l,0);
305: break;
306:
307: case CTRL_L: /* Ctrl-L Center line (used to be Ctrl-V) */
308: str1[l]=0;
309: l=bstrlen(str1);
310: if(!l) break;
311: for(x=0;x<(maxlen-l)/2;x++)
312: str2[x]=' ';
313: str2[x]=0;
314: strcat(str2,str1);
315: strcpy(strout,str2);
316: l=strlen(strout);
317: if(mode&K_NOECHO)
318: return(l);
319: if(mode&K_MSG)
320: redrwstr(strout,i,l,K_MSG);
321: else {
322: while(i--)
323: bputs("\b");
324: bputs(strout);
325: if(mode&K_LINE)
326: attr(LIGHTGRAY);
327: }
328: if(!(mode&K_NOCRLF))
329: CRLF;
330: return(l);
331:
332: case CTRL_N: /* Ctrl-N Next word */
333: if(i<l && term_supports(ANSI)) {
334: x=i;
335: while(str1[i]!=' ' && i<l)
336: i++;
337: while(str1[i]==' ' && i<l)
338: i++;
339: cursor_right(i-x);
340: }
341: break;
342: case CTRL_R: /* Ctrl-R Redraw Line */
343: if(!(mode&K_NOECHO))
344: redrwstr(str1,i,l,0);
345: break;
346: case CTRL_V: /* Ctrl-V Toggles Insert/Overwrite */
347: if(!term_supports(ANSI) || mode&K_NOECHO)
348: break;
349: console^=CON_INSERT;
350: insert_indicator();
351: break;
352: case CTRL_W: /* Ctrl-W Delete word left */
353: if(i<l) {
354: x=i; /* x=original offset */
355: while(i && str1[i-1]==' ') {
356: outchar(BS);
357: i--;
358: }
359: while(i && str1[i-1]!=' ') {
360: outchar(BS);
361: i--;
362: }
363: z=i; /* i=z=new offset */
364: while(z<l-(x-i)) { /* move chars in string */
365: outchar(str1[z]=str1[z+(x-i)]);
366: z++;
367: }
368: while(z<l) { /* write over extra chars */
369: outchar(' ');
370: z++;
371: }
372: cursor_left(z-i); /* back to new x corridnant */
373: l-=x-i; /* l=new length */
374: } else {
375: while(i && str1[i-1]==' ') {
376: i--;
377: l--;
378: if(!(mode&K_NOECHO))
379: backspace();
380: }
381: while(i && str1[i-1]!=' ') {
382: i--;
383: l--;
384: if(!(mode&K_NOECHO))
385: backspace();
386: }
387: }
388: break;
389: case CTRL_Y: /* Ctrl-Y Delete to end of line */
390: if(i!=l) { /* if not at EOL */
391: if(term_supports(ANSI) && !(mode&K_NOECHO))
392: cleartoeol();
393: l=i;
394: break;
395: }
396: /* fall-through */
397: case CTRL_X: /* Ctrl-X Delete entire line */
398: if(mode&K_NOECHO)
399: l=0;
400: else {
401: if(term_supports(ANSI)) {
402: cursor_left(i);
403: cleartoeol();
404: l=0;
405: } else {
406: while(i<l) {
407: outchar(' ');
408: i++;
409: }
410: while(l) {
411: l--;
412: backspace();
413: }
414: }
415: }
416: i=0;
417: console|=CON_DELETELINE;
418: break;
419: case CTRL_Z: /* Undo */
420: SAFECOPY(str1,undo);
421: i=l=strlen(str1);
422: rprintf("\r%s",str1);
423: if(term_supports(ANSI))
424: cleartoeol(); /* destroy to eol */
425: break;
426: case 28: /* Ctrl-\ Previous word */
427: if(i && term_supports(ANSI) && !(mode&K_NOECHO)) {
428: x=i;
429: while(str1[i-1]==' ' && i)
430: i--;
431: while(str1[i-1]!=' ' && i)
432: i--;
433: cursor_left(x-i);
434: }
435: break;
436: case 29: /* Ctrl-]/Left Arrow Reverse Cursor Movement */
437: if(i==0) {
438: if(mode&K_LEFTEXIT)
439: console|=CON_LEFTARROW;
440: break;
441: }
442: if(term_supports(ANSI) && !(mode&K_NOECHO)) {
443: cursor_left(); /* move cursor left one */
444: i--;
445: }
446: break;
447: case 30: /* Ctrl-^/Up Arrow */
448: if(!(mode&K_EDIT))
449: break;
450: #if 1
451: if(i>l)
452: l=i;
453: str1[l]=0;
454: strcpy(strout,str1);
455: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
456: redrwstr(strout,i,l,K_MSG);
457: if(mode&K_LINE && !(mode&K_NOECHO))
458: attr(LIGHTGRAY);
459: console|=CON_UPARROW;
460: return(l);
461: #else
462: console|=CON_UPARROW;
463: break;
464: #endif
465: case DEL: /* Ctrl-BkSpc (DEL) Delete current char */
466: if(i==l) { /* Backspace if end of line */
467: if(i) {
468: i--;
469: l--;
470: if(!(mode&K_NOECHO))
471: backspace();
472: }
473: break;
474: }
475: l--;
476: z=i;
477: while(z<l) { /* move the characters in the line */
478: outchar(str1[z]=str1[z+1]);
479: z++;
480: }
481: outchar(' '); /* write over the last char */
482: cursor_left((l-i)+1);
483: break;
484: default:
485: if(mode&K_WRAP && i==maxlen && ch>=' ' && !(console&CON_INSERT)) {
486: str1[i]=0;
487: if(ch==' ' && !(mode&K_CHAT)) { /* don't wrap a space */
488: 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: return(i);
494: }
495: x=i-1;
496: z=1;
497: wordwrap[0]=ch;
498: while(str1[x]!=' ' && x)
499: wordwrap[z++]=str1[x--];
500: if(x<(maxlen/2)) {
501: wordwrap[1]=0; /* only wrap one character */
502: 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: return(i);
508: }
509: wordwrap[z]=0;
510: if(!(mode&K_NOECHO))
511: while(z--) {
512: backspace();
513: i--;
514: }
515: strrev(wordwrap);
516: str1[x]=0;
517: strcpy(strout,str1);
518: if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
519: redrwstr(strout,i,x,mode);
520: if(!(mode&(K_NOECHO|K_NOCRLF)))
521: CRLF;
522: return(x);
523: }
524: if(i<maxlen && ch>=' ') {
525: if(mode&K_UPRLWR)
526: if(!i || (i && (str1[i-1]==' ' || str1[i-1]=='-'
527: || str1[i-1]=='.' || str1[i-1]=='_')))
528: ch=toupper(ch);
529: else
530: ch=tolower(ch);
531: if(console&CON_INSERT && i!=l) {
532: if(l<maxlen) /* l<maxlen */
533: l++;
534: for(x=l;x>i;x--)
535: str1[x]=str1[x-1];
536: rprintf("%.*s",l-i,str1+i);
537: cursor_left(l-i);
538: #if 0
539: if(i==maxlen-1) {
540: bputs(" \b\b");
541: console&=~CON_INSERT;
542: }
543: #endif
544: }
545: str1[i++]=ch;
546: if(!(mode&K_NOECHO))
547: outchar(ch);
548: } else
549: outchar(BEL); /* Added at Angus McLeod's request */
550: }
551: if(i>l)
552: l=i;
553: if(mode&K_CHAT && !l)
554: return(0);
555: }
556: getstr_offset=i;
557: if(!online)
558: return(0);
559: if(i>l)
560: l=i;
561: str1[l]=0;
562: if(!(sys_status&SS_ABORT)) {
563: strcpy(strout,str1);
564: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
565: redrwstr(strout,i,l,K_MSG);
566: }
567: else
568: l=0;
569: if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY);
570: if(!(mode&(K_NOCRLF|K_NOECHO))) {
571: outchar(CR);
572: if(!(mode&K_MSG && sys_status&SS_ABORT))
573: outchar(LF);
574: lncntr=0;
575: }
576: return(l);
577: }
578:
579: /****************************************************************************/
580: /* Hot keyed number input routine. */
581: /* Returns a valid number between 1 and max, 0 if no number entered, or -1 */
582: /* if the user hit 'Q' or ctrl-c */
583: /****************************************************************************/
584: long sbbs_t::getnum(ulong max)
585: {
586: uchar ch,n=0;
587: long i=0;
588:
589: while(online) {
590: ch=getkey(K_UPPER);
591: if(ch>0x7f)
592: continue;
593: if(ch=='Q') {
594: outchar('Q');
595: if(useron.misc&COLDKEYS)
596: ch=getkey(K_UPPER);
597: if(ch==BS || ch==DEL) {
598: backspace();
599: continue;
600: }
601: CRLF;
602: lncntr=0;
603: return(-1);
604: }
605: else if(sys_status&SS_ABORT) {
606: CRLF;
607: lncntr=0;
608: return(-1);
609: }
610: else if(ch==CR) {
611: CRLF;
612: lncntr=0;
613: return(i);
614: }
615: else if((ch==BS || ch==DEL) && n) {
616: backspace();
617: i/=10;
618: n--;
619: }
620: else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (ch!='0' || n)) {
621: i*=10L;
622: n++;
623: i+=ch&0xf;
624: outchar(ch);
625: if(i*10UL>max && !(useron.misc&COLDKEYS)) {
626: CRLF;
627: lncntr=0;
628: return(i);
629: }
630: }
631: }
632: return(0);
633: }
634:
635: void sbbs_t::insert_indicator(void)
636: {
637: ANSI_SAVE();
638: GOTOXY(cols,1);
639: uchar z=curatr; /* and go to EOL */
640: if(console&CON_INSERT) {
641: attr(BLINK|BLACK|(LIGHTGRAY<<4));
642: outchar('I');
643: } else {
644: attr(LIGHTGRAY);
645: outchar(' ');
646: }
647: attr(z);
648: ANSI_RESTORE();
649: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.