|
|
1.1 root 1: /* getstr.cpp */
2:
3: /* Synchronet string input routines */
4:
1.1.1.2 ! root 5: /* $Id: getstr.cpp,v 1.26 2009/02/19 10:51:09 rswindell Exp $ */
1.1 root 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: * *
1.1.1.2 ! root 11: * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 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: }
1.1.1.2 ! root 84: column+=rputs(str1);
! 85: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)))
1.1 root 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);
1.1.1.2 ! root 102: column+=rputs(str1);
1.1 root 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];
1.1.1.2 ! root 156: column+=rprintf("%.*s",l-i,str1+i);
1.1 root 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 */
1.1.1.2 ! root 166: if(i && !(mode&K_NOECHO)) {
1.1 root 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 */
1.1.1.2 ! root 347: if(mode&K_NOECHO)
1.1 root 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 */
1.1.1.2 ! root 391: if(!(mode&K_NOECHO))
1.1 root 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 {
1.1.1.2 ! root 401: cursor_left(i);
! 402: cleartoeol();
! 403: l=0;
1.1 root 404: }
405: i=0;
406: console|=CON_DELETELINE;
407: break;
408: case CTRL_Z: /* Undo */
409: SAFECOPY(str1,undo);
410: i=l=strlen(str1);
411: rprintf("\r%s",str1);
1.1.1.2 ! root 412: cleartoeol();
1.1 root 413: break;
414: case 28: /* Ctrl-\ Previous word */
1.1.1.2 ! root 415: if(i && !(mode&K_NOECHO)) {
1.1 root 416: x=i;
417: while(str1[i-1]==' ' && i)
418: i--;
419: while(str1[i-1]!=' ' && i)
420: i--;
421: cursor_left(x-i);
422: }
423: break;
424: case 29: /* Ctrl-]/Left Arrow Reverse Cursor Movement */
425: if(i==0) {
426: if(mode&K_LEFTEXIT)
427: console|=CON_LEFTARROW;
428: break;
429: }
1.1.1.2 ! root 430: if(!(mode&K_NOECHO)) {
1.1 root 431: cursor_left(); /* move cursor left one */
432: i--;
433: }
434: break;
435: case 30: /* Ctrl-^/Up Arrow */
436: if(!(mode&K_EDIT))
437: break;
438: #if 1
439: if(i>l)
440: l=i;
441: str1[l]=0;
442: strcpy(strout,str1);
443: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
444: redrwstr(strout,i,l,K_MSG);
445: if(mode&K_LINE && !(mode&K_NOECHO))
446: attr(LIGHTGRAY);
447: console|=CON_UPARROW;
448: return(l);
449: #else
450: console|=CON_UPARROW;
451: break;
452: #endif
453: case DEL: /* Ctrl-BkSpc (DEL) Delete current char */
454: if(i==l) { /* Backspace if end of line */
455: if(i) {
456: i--;
457: l--;
458: if(!(mode&K_NOECHO))
459: backspace();
460: }
461: break;
462: }
463: l--;
464: z=i;
465: while(z<l) { /* move the characters in the line */
466: outchar(str1[z]=str1[z+1]);
467: z++;
468: }
469: outchar(' '); /* write over the last char */
470: cursor_left((l-i)+1);
471: break;
472: default:
473: if(mode&K_WRAP && i==maxlen && ch>=' ' && !(console&CON_INSERT)) {
474: str1[i]=0;
475: if(ch==' ' && !(mode&K_CHAT)) { /* don't wrap a space */
476: strcpy(strout,str1); /* as last char */
477: if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
478: redrwstr(strout,i,l,K_MSG);
479: if(!(mode&(K_NOECHO|K_NOCRLF)))
480: CRLF;
481: return(i);
482: }
483: x=i-1;
484: z=1;
485: wordwrap[0]=ch;
486: while(str1[x]!=' ' && x)
487: wordwrap[z++]=str1[x--];
488: if(x<(maxlen/2)) {
489: wordwrap[1]=0; /* only wrap one character */
490: strcpy(strout,str1);
491: if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
492: redrwstr(strout,i,l,K_MSG);
493: if(!(mode&(K_NOECHO|K_NOCRLF)))
494: CRLF;
495: return(i);
496: }
497: wordwrap[z]=0;
498: if(!(mode&K_NOECHO))
499: while(z--) {
500: backspace();
501: i--;
502: }
503: strrev(wordwrap);
504: str1[x]=0;
505: strcpy(strout,str1);
506: if(strip_invalid_attr(strout) && !(mode&K_NOECHO))
507: redrwstr(strout,i,x,mode);
508: if(!(mode&(K_NOECHO|K_NOCRLF)))
509: CRLF;
510: return(x);
511: }
512: if(i<maxlen && ch>=' ') {
513: if(mode&K_UPRLWR)
514: if(!i || (i && (str1[i-1]==' ' || str1[i-1]=='-'
515: || str1[i-1]=='.' || str1[i-1]=='_')))
516: ch=toupper(ch);
517: else
518: ch=tolower(ch);
519: if(console&CON_INSERT && i!=l) {
520: if(l<maxlen) /* l<maxlen */
521: l++;
522: for(x=l;x>i;x--)
523: str1[x]=str1[x-1];
1.1.1.2 ! root 524: column+=rprintf("%.*s",l-i,str1+i);
1.1 root 525: cursor_left(l-i);
526: #if 0
527: if(i==maxlen-1) {
528: bputs(" \b\b");
529: console&=~CON_INSERT;
530: }
531: #endif
532: }
533: str1[i++]=ch;
534: if(!(mode&K_NOECHO))
535: outchar(ch);
536: } else
537: outchar(BEL); /* Added at Angus McLeod's request */
538: }
539: if(i>l)
540: l=i;
541: if(mode&K_CHAT && !l)
542: return(0);
543: }
544: getstr_offset=i;
545: if(!online)
546: return(0);
547: if(i>l)
548: l=i;
549: str1[l]=0;
550: if(!(sys_status&SS_ABORT)) {
551: strcpy(strout,str1);
552: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO))
553: redrwstr(strout,i,l,K_MSG);
554: }
555: else
556: l=0;
557: if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY);
558: if(!(mode&(K_NOCRLF|K_NOECHO))) {
559: outchar(CR);
560: if(!(mode&K_MSG && sys_status&SS_ABORT))
561: outchar(LF);
562: lncntr=0;
563: }
564: return(l);
565: }
566:
567: /****************************************************************************/
568: /* Hot keyed number input routine. */
569: /* Returns a valid number between 1 and max, 0 if no number entered, or -1 */
570: /* if the user hit 'Q' or ctrl-c */
571: /****************************************************************************/
1.1.1.2 ! root 572: long sbbs_t::getnum(ulong max, ulong dflt)
1.1 root 573: {
574: uchar ch,n=0;
575: long i=0;
576:
577: while(online) {
578: ch=getkey(K_UPPER);
579: if(ch>0x7f)
580: continue;
581: if(ch=='Q') {
582: outchar('Q');
583: if(useron.misc&COLDKEYS)
584: ch=getkey(K_UPPER);
585: if(ch==BS || ch==DEL) {
586: backspace();
587: continue;
588: }
589: CRLF;
590: lncntr=0;
591: return(-1);
592: }
593: else if(sys_status&SS_ABORT) {
594: CRLF;
595: lncntr=0;
596: return(-1);
597: }
598: else if(ch==CR) {
599: CRLF;
600: lncntr=0;
1.1.1.2 ! root 601: if(!n)
! 602: return(dflt);
1.1 root 603: return(i);
604: }
605: else if((ch==BS || ch==DEL) && n) {
606: backspace();
607: i/=10;
608: n--;
609: }
1.1.1.2 ! root 610: else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (dflt || ch!='0' || n)) {
1.1 root 611: i*=10L;
612: n++;
613: i+=ch&0xf;
614: outchar(ch);
615: if(i*10UL>max && !(useron.misc&COLDKEYS)) {
616: CRLF;
617: lncntr=0;
618: return(i);
619: }
620: }
621: }
622: return(0);
623: }
624:
625: void sbbs_t::insert_indicator(void)
626: {
1.1.1.2 ! root 627: if(term_supports(ANSI)) {
! 628: ansi_save();
! 629: ansi_gotoxy(cols,1);
! 630: uchar z=curatr; /* and go to EOL */
! 631: if(console&CON_INSERT) {
! 632: attr(BLINK|BLACK|(LIGHTGRAY<<4));
! 633: outchar('I');
! 634: } else {
! 635: attr(LIGHTGRAY);
! 636: outchar(' ');
! 637: }
! 638: attr(z);
! 639: ansi_restore();
1.1 root 640: }
641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.