|
|
1.1 root 1: /* getstr.cpp */
2:
3: /* Synchronet string input routines */
4:
5: /* $Id: getstr.cpp,v 1.3 2000/11/14 02:16:57 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 2000 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];
53: uchar ch;
54: uchar ins=0,atr;
55:
56: console&=~CON_UPARROW;
57: sys_status&=~SS_ABORT;
58: if(mode&K_LINE && useron.misc&ANSI && !(mode&K_NOECHO)) {
59: attr(cfg.color[clr_inputline]);
60: for(i=0;i<maxlen;i++)
61: outchar(SP);
62: bprintf("\x1b[%dD",maxlen); }
63: if(wordwrap[0]) {
64: strcpy(str1,wordwrap);
65: wordwrap[0]=0; }
66: else str1[0]=0;
67: if(mode&K_EDIT)
68: strcat(str1,strout);
69: else
70: strout[0]=0;
71: if(strlen(str1)>maxlen)
72: str1[maxlen]=0;
73: atr=curatr;
74: if(!(mode&K_NOECHO)) {
75: if(mode&K_AUTODEL && str1[0]) {
76: i=(cfg.color[clr_inputline]&0x77)<<4;
77: i|=(cfg.color[clr_inputline]&0x77)>>4;
78: attr(i); }
79: rputs(str1);
80: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && useron.misc&ANSI)
81: bputs("\x1b[K"); /* destroy to eol */ }
82:
83: i=l=strlen(str1);
84: if(mode&K_AUTODEL && str1[0] && !(mode&K_NOECHO)) {
85: ch=getkey(mode|K_GETSTR);
86: attr(atr);
87: if(isprint(ch) || ch==DEL) {
88: for(i=0;i<l;i++)
89: bputs("\b \b");
90: i=l=0; }
91: else {
92: for(i=0;i<l;i++)
93: outchar(BS);
94: rputs(str1);
95: i=l; }
96: if(ch!=SP && ch!=TAB)
97: ungetkey(ch); }
98:
99: while(!(sys_status&SS_ABORT) && (ch=getkey(mode|K_GETSTR))!=CR && online) {
100: if(sys_status&SS_ABORT)
101: break;
102: if(ch==LF && mode&K_MSG) /* Down-arrow same as CR */
103: break;
104: if(ch==TAB && (mode&K_TAB || !(mode&K_WRAP))) /* TAB same as CR */
105: break;
106: if(!i && mode&K_UPRLWR && (ch==SP || ch==TAB))
107: continue; /* ignore beginning white space if upper/lower */
108: if(mode&K_E71DETECT && (uchar)ch==(CR|0x80) && l>1) {
109: if(strstr(str1,"��")) {
110: bputs("\r\n\r\nYou must set your terminal to NO PARITY, "
111: "8 DATA BITS, and 1 STOP BIT (N-8-1).\7\r\n");
112: return(0); } }
113: switch(ch) {
114: case 1: /* Ctrl-A for ANSI */
115: if(!(mode&K_MSG) || useron.rest&FLAG('A') || i>maxlen-3)
116: break;
117: if(ins) {
118: if(l<maxlen)
119: l++;
120: for(x=l;x>i;x--)
121: str1[x]=str1[x-1];
122: rprintf("%.*s",l-i,str1+i);
123: rprintf("\x1b[%dD",l-i);
124: if(i==maxlen-1)
125: ins=0; }
126: outchar(str1[i++]=1);
127: break;
128: case 2: /* Ctrl-B Beginning of Line */
129: if(useron.misc&ANSI && i && !(mode&K_NOECHO)) {
130: bprintf("\x1b[%dD",i);
131: i=0; }
132: break;
133: case 4: /* Ctrl-D Delete word right */
134: if(i<l) {
135: x=i;
136: while(x<l && str1[x]!=SP) {
137: outchar(SP);
138: x++; }
139: while(x<l && str1[x]==SP) {
140: outchar(SP);
141: x++; }
142: bprintf("\x1b[%dD",x-i); /* move cursor back */
143: z=i;
144: while(z<l-(x-i)) { /* move chars in string */
145: outchar(str1[z]=str1[z+(x-i)]);
146: z++; }
147: while(z<l) { /* write over extra chars */
148: outchar(SP);
149: z++; }
150: bprintf("\x1b[%dD",z-i);
151: l-=x-i; } /* l=new length */
152: break;
153: case 5: /* Ctrl-E End of line */
154: if(useron.misc&ANSI && i<l) {
155: bprintf("\x1b[%dC",l-i); /* move cursor to eol */
156: i=l; }
157: break;
158: case 6: /* Ctrl-F move cursor forewards */
159: if(i<l && (useron.misc&ANSI)) {
160: bputs("\x1b[C"); /* move cursor right one */
161: i++; }
162: break;
163: case 7: /* Ctrl-G */
164: if(!(mode&K_MSG))
165: break;
166: if(useron.rest&FLAG('B')) {
167: if (i+6<maxlen) {
168: if(ins) {
169: for(x=l+6;x>i;x--)
170: str1[x]=str1[x-6];
171: if(l+5<maxlen)
172: l+=6;
173: if(i==maxlen-1)
174: ins=0; }
175: str1[i++]='(';
176: str1[i++]='b';
177: str1[i++]='e';
178: str1[i++]='e';
179: str1[i++]='p';
180: str1[i++]=')';
181: if(!(mode&K_NOECHO))
182: bputs("(beep)"); }
183: if(ins)
184: redrwstr(str1,i,l,0);
185: break; }
186: if(ins) {
187: if(l<maxlen)
188: l++;
189: for(x=l;x>i;x--)
190: str1[x]=str1[x-1];
191: if(i==maxlen-1)
192: ins=0; }
193: if(i<maxlen) {
194: str1[i++]=BEL;
195: if(!(mode&K_NOECHO))
196: outchar(BEL); }
197: break;
198: case 8: /* Ctrl-H/Backspace */
199: if(!i)
200: break;
201: i--;
202: l--;
203: if(i!=l) { /* Deleting char in middle of line */
204: outchar(BS);
205: z=i;
206: while(z<l) { /* move the characters in the line */
207: outchar(str1[z]=str1[z+1]);
208: z++; }
209: outchar(SP); /* write over the last char */
210: bprintf("\x1b[%dD",(l-i)+1); }
211: else if(!(mode&K_NOECHO))
212: bputs("\b \b");
213: break;
214: case 9: /* Ctrl-I/TAB */
215: if(!(i%TABSIZE)) {
216: if(ins) {
217: if(l<maxlen)
218: l++;
219: for(x=l;x>i;x--)
220: str1[x]=str1[x-1];
221: if(i==maxlen-1)
222: ins=0; }
223: str1[i++]=SP;
224: if(!(mode&K_NOECHO))
225: outchar(SP); }
226: while(i<maxlen && i%TABSIZE) {
227: if(ins) {
228: if(l<maxlen)
229: l++;
230: for(x=l;x>i;x--)
231: str1[x]=str1[x-1];
232: if(i==maxlen-1)
233: ins=0; }
234: str1[i++]=SP;
235: if(!(mode&K_NOECHO))
236: outchar(SP); }
237: if(ins && !(mode&K_NOECHO))
238: redrwstr(str1,i,l,0);
239: break;
240:
241: case 12: /* Ctrl-L Center line (used to be Ctrl-V) */
242: str1[l]=0;
243: l=bstrlen(str1);
244: if(!l) break;
245: for(x=0;x<(maxlen-l)/2;x++)
246: str2[x]=SP;
247: str2[x]=0;
248: strcat(str2,str1);
249: strcpy(strout,str2);
250: l=strlen(strout);
251: if(mode&K_NOECHO)
252: return(l);
253: if(mode&K_MSG)
254: redrwstr(strout,i,l,K_MSG);
255: else {
256: while(i--)
257: bputs("\b");
258: bputs(strout);
259: if(mode&K_LINE)
260: attr(LIGHTGRAY); }
261: CRLF;
262: return(l);
263:
264: case 14: /* Ctrl-N Next word */
265: if(i<l && (useron.misc&ANSI)) {
266: x=i;
267: while(str1[i]!=SP && i<l)
268: i++;
269: while(str1[i]==SP && i<l)
270: i++;
271: bprintf("\x1b[%dC",i-x); }
272: break;
273: case 18: /* Ctrl-R Redraw Line */
274: if(!(mode&K_NOECHO))
275: redrwstr(str1,i,l,0);
276: break;
277: case 22: /* Ctrl-V Toggles Insert/Overwrite */
278: if(!(useron.misc&ANSI) || mode&K_NOECHO)
279: break;
280: if(ins) {
281: ins=0;
282: redrwstr(str1,i,l,0); }
283: else if(i<l) {
284: ins=1;
285: bprintf("\x1b[s\x1b[79C"); /* save pos */
286: z=curatr; /* and go to EOL */
287: attr(z|BLINK|HIGH);
288: outchar('�');
289: attr(z);
290: bputs("\x1b[u"); } /* restore pos */
291: break;
292: case 23: /* Ctrl-W Delete word left */
293: if(i<l) {
294: x=i; /* x=original offset */
295: while(i && str1[i-1]==SP) {
296: outchar(BS);
297: i--; }
298: while(i && str1[i-1]!=SP) {
299: outchar(BS);
300: i--; }
301: z=i; /* i=z=new offset */
302: while(z<l-(x-i)) { /* move chars in string */
303: outchar(str1[z]=str1[z+(x-i)]);
304: z++; }
305: while(z<l) { /* write over extra chars */
306: outchar(SP);
307: z++; }
308: bprintf("\x1b[%dD",z-i); /* back to new x corridnant */
309: l-=x-i; } /* l=new length */
310: else {
311: while(i && str1[i-1]==SP) {
312: i--;
313: l--;
314: if(!(mode&K_NOECHO))
315: bputs("\b \b"); }
316: while(i && str1[i-1]!=SP) {
317: i--;
318: l--;
319: if(!(mode&K_NOECHO))
320: bputs("\b \b"); } }
321: break;
322: case 24: /* Ctrl-X Delete entire line */
323: if(mode&K_NOECHO)
324: l=0;
325: else {
326: while(i<l) {
327: outchar(SP);
328: i++; }
329: while(l) {
330: l--;
331: bputs("\b \b"); } }
332: i=0;
333: break;
334: case 25: /* Ctrl-Y Delete to end of line */
335: if(useron.misc&ANSI && !(mode&K_NOECHO)) {
336: bputs("\x1b[K");
337: l=i; }
338: break;
339: case 28: /* Ctrl-\ Previous word */
340: if(i && (useron.misc&ANSI) && !(mode&K_NOECHO)) {
341: x=i;
342: while(str1[i-1]==SP && i)
343: i--;
344: while(str1[i-1]!=SP && i)
345: i--;
346: bprintf("\x1b[%dD",x-i); }
347: break;
348: case 29: /* Ctrl-]/Left Arrow Reverse Cursor Movement */
349: if(i && (useron.misc&ANSI) && !(mode&K_NOECHO)) {
350: bputs("\x1b[D"); /* move cursor left one */
351: i--; }
352: break;
353: case 30: /* Ctrl-^/Up Arrow */
354: if(!(mode&K_EDIT))
355: break;
356: if(i>l)
357: l=i;
358: str1[l]=0;
359: strcpy(strout,str1);
360: if((stripattr(strout) || ins) && !(mode&K_NOECHO))
361: redrwstr(strout,i,l,K_MSG);
362: if(mode&K_LINE && !(mode&K_NOECHO))
363: attr(LIGHTGRAY);
364: console|=CON_UPARROW;
365: return(l);
366: case DEL: /* Ctrl-BkSpc (DEL) Delete current char */
367: if(i==l) { /* Backspace if end of line */
368: if(i) {
369: i--;
370: l--;
371: if(!(mode&K_NOECHO))
372: bputs("\b \b");
373: }
374: break;
375: }
376: l--;
377: z=i;
378: while(z<l) { /* move the characters in the line */
379: outchar(str1[z]=str1[z+1]);
380: z++; }
381: outchar(SP); /* write over the last char */
382: bprintf("\x1b[%dD",(l-i)+1);
383: break;
384: default:
385: if(mode&K_WRAP && i==maxlen && ch>=SP && !ins) {
386: str1[i]=0;
387: if(ch==SP && !(mode&K_CHAT)) { /* don't wrap a space */
388: strcpy(strout,str1); /* as last char */
389: if(stripattr(strout) && !(mode&K_NOECHO))
390: redrwstr(strout,i,l,K_MSG);
391: if(!(mode&K_NOECHO))
392: CRLF;
393: return(i); }
394: x=i-1;
395: z=1;
396: wordwrap[0]=ch;
397: while(str1[x]!=SP && x)
398: wordwrap[z++]=str1[x--];
399: if(x<(maxlen/2)) {
400: wordwrap[1]=0; /* only wrap one character */
401: strcpy(strout,str1);
402: if(stripattr(strout) && !(mode&K_NOECHO))
403: redrwstr(strout,i,l,K_MSG);
404: if(!(mode&K_NOECHO))
405: CRLF;
406: return(i); }
407: wordwrap[z]=0;
408: if(!(mode&K_NOECHO))
409: while(z--) {
410: bputs("\b \b");
411: i--; }
412: strrev(wordwrap);
413: str1[x]=0;
414: strcpy(strout,str1);
415: if(stripattr(strout) && !(mode&K_NOECHO))
416: redrwstr(strout,i,x,(char)mode);
417: if(!(mode&K_NOECHO))
418: CRLF;
419: return(x); }
420: if(i<maxlen && ch>=SP) {
421: if(mode&K_UPRLWR)
422: if(!i || (i && (str1[i-1]==SP || str1[i-1]=='-'
423: || str1[i-1]=='.' || str1[i-1]=='_')))
424: ch=toupper(ch);
425: else
426: ch=tolower(ch);
427: if(ins) {
428: if(l<maxlen) /* l<maxlen */
429: l++;
430: for(x=l;x>i;x--)
431: str1[x]=str1[x-1];
432: rprintf("%.*s",l-i,str1+i);
433: rprintf("\x1b[%dD",l-i);
434: if(i==maxlen-1) {
435: bputs(" \b\b");
436: ins=0; } }
437: str1[i++]=ch;
438: if(!(mode&K_NOECHO))
439: outchar(ch); } }
440: if(i>l)
441: l=i;
442: if(mode&K_CHAT && !l)
443: return(0); }
444: if(!online)
445: return(0);
446: if(i>l)
447: l=i;
448: str1[l]=0;
449: if(!(sys_status&SS_ABORT)) {
450: strcpy(strout,str1);
451: if((stripattr(strout) || ins) && !(mode&K_NOECHO))
452: redrwstr(strout,i,l,K_MSG); }
453: else
454: l=0;
455: if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY);
456: if(!(mode&(K_NOCRLF|K_NOECHO))) {
457: outchar(CR);
458: if(!(mode&K_MSG && sys_status&SS_ABORT))
459: outchar(LF);
460: lncntr=0; }
461: return(l);
462: }
463:
464: /****************************************************************************/
465: /* Hot keyed number input routine. */
466: /* Returns a valid number between 1 and max, 0 if no number entered, or -1 */
467: /* if the user hit 'Q' or ctrl-c */
468: /****************************************************************************/
469: long sbbs_t::getnum(ulong max)
470: {
471: uchar ch,n=0;
472: long i=0;
473:
474: while(online) {
475: ch=getkey(K_UPPER);
476: if(ch>0x7f)
477: continue;
478: if(ch=='Q') {
479: outchar('Q');
480: if(useron.misc&COLDKEYS)
481: ch=getkey(K_UPPER);
482: if(ch==BS) {
483: bputs("\b \b");
484: continue; }
485: CRLF;
486: lncntr=0;
487: return(-1); }
488: else if(sys_status&SS_ABORT) {
489: CRLF;
490: lncntr=0;
491: return(-1); }
492: else if(ch==CR) {
493: CRLF;
494: lncntr=0;
495: return(i); }
496: else if(ch==BS && n) {
497: bputs("\b \b");
498: i/=10;
499: n--; }
500: else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (ch!='0' || n)) {
501: i*=10L;
502: n++;
503: i+=ch&0xf;
504: outchar(ch);
505: if(i*10UL>max && !(useron.misc&COLDKEYS)) {
506: CRLF;
507: lncntr=0;
508: return(i); } } }
509: return(0);
510: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.