|
|
1.1 root 1: /* $Id: */
2:
3: /****************************************************************************
4: * @format.tab-size 4 (Plain Text/Source Code File Header) *
5: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
6: * *
7: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
8: * *
9: * This library is free software; you can redistribute it and/or *
10: * modify it under the terms of the GNU Lesser General Public License *
11: * as published by the Free Software Foundation; either version 2 *
12: * of the License, or (at your option) any later version. *
13: * See the GNU Lesser General Public License for more details: lgpl.txt or *
14: * http://www.fsf.org/copyleft/lesser.html *
15: * *
16: * Anonymous FTP access to the most recent released source is available at *
17: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
18: * *
19: * Anonymous CVS access to the development source and modification history *
20: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
21: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
22: * (just hit return, no password is necessary) *
23: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
24: * *
25: * For Synchronet coding style and modification guidelines, see *
26: * http://www.synchro.net/source.html *
27: * *
28: * You are encouraged to submit any modifications (preferably in Unix diff *
29: * format) via e-mail to [email protected] *
30: * *
31: * Note: If this box doesn't appear square, then you need to fix your tabs. *
32: ****************************************************************************/
33:
34: #include <stdlib.h>
35: #include <string.h>
36:
37: #include <genwrap.h>
38: #include <ciolib.h>
39: #include <keys.h>
40:
41: #include "cterm.h"
42:
43: #define BUFSIZE 2048
44:
45: struct cterminal cterm;
46:
47: /* const int tabs[11]={1,8,16,24,32,40,48,56,64,72,80}; */
48: const int cterm_tabs[11]={9,17,25,33,41,49,57,65,73,80,80.1};
49:
50: void play_music(void)
51: {
52: /* ToDo Music code parsing stuff */
53: cterm.music=0;
54: }
55:
56: void scrolldown(void)
57: {
58: char *buf;
59: int i,j;
60:
61: buf=(char *)malloc(cterm.width*(cterm.height-1)*2);
62: gettext(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y+cterm.height-2,buf);
63: puttext(cterm.x,cterm.y+1,cterm.x+cterm.width-1,cterm.y+cterm.height-1,buf);
64: j=0;
65: for(i=0;i<cterm.width;i++) {
66: buf[j++]=' ';
67: buf[j++]=cterm.attr;
68: }
69: puttext(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y,buf);
70: free(buf);
71: }
72:
73: void scrollup(void)
74: {
75: char *buf;
76: int i,j;
77:
78: cterm.backpos++;
79: if(cterm.scrollback!=NULL) {
80: if(cterm.backpos>cterm.backlines) {
81: memmove(cterm.scrollback,cterm.scrollback+cterm.width*2,cterm.width*2*(cterm.backlines-1));
82: cterm.backpos--;
83: }
84: gettext(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y,cterm.scrollback+(cterm.backpos-1)*cterm.width*2);
85: }
86: buf=(char *)malloc(cterm.width*(cterm.height-1)*2);
87: gettext(cterm.x,cterm.y+1,cterm.x+cterm.width-1,cterm.y+cterm.height-1,buf);
88: puttext(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y+cterm.height-2,buf);
89: j=0;
90: for(i=0;i<cterm.width;i++) {
91: buf[j++]=' ';
92: buf[j++]=cterm.attr;
93: }
94: puttext(cterm.x,cterm.y+cterm.height-1,cterm.x+cterm.width-1,cterm.y+cterm.height-1,buf);
95: free(buf);
96: }
97:
98: void clear2bol(void)
99: {
100: char *buf;
101: int i,j;
102:
103: buf=(char *)malloc((wherex()+1)*2);
104: j=0;
105: for(i=1;i<=wherex();i++) {
106: buf[j++]=' ';
107: buf[j++]=cterm.attr;
108: }
109: puttext(cterm.x+1,cterm.y+wherey(),cterm.x+wherex(),cterm.y+wherey(),buf);
110: free(buf);
111: }
112:
113: void clear2eol(void)
114: {
115: char *buf;
116: int i,j;
117:
118: clreol();
119: }
120:
121: void clearscreen(char attr)
122: {
123: char *buf;
124: int x,y,j;
125:
126: if(cterm.scrollback!=NULL) {
127: cterm.backpos+=cterm.height;
128: if(cterm.backpos>cterm.backlines) {
129: memmove(cterm.scrollback,cterm.scrollback+cterm.width*2*(cterm.backpos-cterm.backlines),cterm.width*2*(cterm.backlines-(cterm.backpos-cterm.backlines)));
130: cterm.backpos=cterm.backlines;
131: }
132: gettext(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y+cterm.height-1,cterm.scrollback+(cterm.backpos-cterm.height)*cterm.width*2);
133: }
134: clrscr();
135: }
136:
137: void do_ansi(char *retbuf, int retsize)
138: {
139: char *p;
140: char *p2;
141: char tmp[1024];
142: int i,j,k;
143: int row,col;
144:
145: switch(cterm.escbuf[0]) {
146: case '[':
147: /* ANSI stuff */
148: p=cterm.escbuf+strlen(cterm.escbuf)-1;
149: switch(*p) {
150: case '@': /* Insert Char */
151: i=wherex();
152: j=wherey();
153: gettext(cterm.x+wherex(),cterm.y+wherey(),cterm.x+cterm.width-1,cterm.y+wherey(),tmp);
154: putch(' ');
155: puttext(cterm.x+wherex()+1,cterm.y+wherey(),cterm.x+cterm.width,cterm.y+wherey(),tmp);
156: gotoxy(i,j);
157: break;
158: case 'A': /* Cursor Up */
159: i=atoi(cterm.escbuf+1);
160: if(i==0)
161: i=1;
162: i=wherey()-i;
163: if(i<1)
164: i=1;
165: gotoxy(wherex(),i);
166: break;
167: case 'B': /* Cursor Down */
168: i=atoi(cterm.escbuf+1);
169: if(i==0)
170: i=1;
171: i=wherey()+i;
172: if(i>cterm.height)
173: i=cterm.height;
174: gotoxy(wherex(),i);
175: break;
176: case 'C': /* Cursor Right */
177: i=atoi(cterm.escbuf+1);
178: if(i==0)
179: i=1;
180: i=wherex()+i;
181: if(i>cterm.width)
182: i=cterm.width;
183: gotoxy(i,wherey());
184: break;
185: case 'D': /* Cursor Left */
186: i=atoi(cterm.escbuf+1);
187: if(i==0)
188: i=1;
189: i=wherex()-i;
190: if(i<1)
191: i=1;
192: gotoxy(i,wherey());
193: break;
194: case 'E':
195: i=atoi(cterm.escbuf+1);
196: if(i==0)
197: i=1;
198: i=wherey()+i;
199: for(j=0;j<i;j++)
200: putch('\n');
201: break;
202: case 'f':
203: case 'H':
204: row=1;
205: col=1;
206: *(p--)=0;
207: if(strlen(cterm.escbuf)>1) {
208: if((p=strtok(cterm.escbuf+1,";"))!=NULL) {
209: row=atoi(p);
210: if((p=strtok(NULL,";"))!=NULL) {
211: col=atoi(p);
212: }
213: }
214: }
215: if(row<1)
216: row=1;
217: if(col<1)
218: col=1;
219: if(row>cterm.height)
220: row=cterm.height;
221: if(col>cterm.width)
222: col=cterm.width;
223: gotoxy(col,row);
224: break;
225: case 'J':
226: i=atoi(cterm.escbuf+1);
227: switch(i) {
228: case 0:
229: clear2eol();
230: p2=(char *)malloc(cterm.width*2);
231: j=0;
232: for(i=0;i<cterm.width;i++) {
233: p2[j++]=' ';
234: p2[j++]=cterm.attr;
235: }
236: for(i=wherey()+1;i<=cterm.height;i++) {
237: puttext(cterm.x+1,cterm.y+i,cterm.x+cterm.width,cterm.y+i,p2);
238: }
239: free(p2);
240: break;
241: case 1:
242: clear2bol();
243: p2=(char *)malloc(cterm.width*2);
244: j=0;
245: for(i=0;i<cterm.width;i++) {
246: p2[j++]=' ';
247: p2[j++]=cterm.attr;
248: }
249: for(i=wherey()-1;i>=1;i--) {
250: puttext(cterm.x+1,cterm.y+i,cterm.x+cterm.width,cterm.y+i,p2);
251: }
252: free(p2);
253: break;
254: case 2:
255: clearscreen(cterm.attr);
256: gotoxy(1,1);
257: break;
258: }
259: break;
260: case 'K':
261: i=atoi(cterm.escbuf+1);
262: switch(i) {
263: case 0:
264: clear2eol();
265: break;
266: case 1:
267: clear2bol();
268: break;
269: case 2:
270: p2=(char *)malloc(cterm.width*2);
271: j=0;
272: for(i=0;i<cterm.width;i++) {
273: p2[j++]=' ';
274: p2[j++]=cterm.attr;
275: }
276: puttext(cterm.x+1,cterm.y+wherey(),cterm.x+cterm.width,cterm.y+wherey(),p2);
277: free(p2);
278: break;
279: }
280: break;
281: case 'L':
282: i=atoi(cterm.escbuf+1);
283: if(i==0)
284: i=1;
285: if(i>cterm.height-wherey())
286: i=cterm.height-wherey();
287: if(i<cterm.height-wherey()) {
288: p2=(char *)malloc((cterm.height-wherey()-i)*cterm.width*2);
289: gettext(cterm.x+1,cterm.y+wherey(),cterm.x+cterm.width,wherey()+(cterm.height-wherey()-i),p2);
290: puttext(cterm.x+1,cterm.y+wherey()+i,cterm.x+cterm.width,wherey()+(cterm.height-wherey()),p2);
291: j=0;
292: free(p2);
293: }
294: p2=(char *)malloc(cterm.width*2);
295: j=0;
296: for(k=0;k<cterm.width;k++) {
297: p2[j++]=' ';
298: p2[j++]=cterm.attr;
299: }
300: for(i=0;j<i;i++) {
301: puttext(cterm.x+1,cterm.y+i,cterm.x+cterm.width,cterm.y+i,p2);
302: }
303: free(p2);
304: break;
305: case 'M':
306: case 'N':
307: cterm.music=1;
308: break;
309: case 'P': /* Delete char */
310: i=atoi(cterm.escbuf+1);
311: if(i==0)
312: i=1;
313: if(i>cterm.width-wherex())
314: i=cterm.width-wherex();
315: p2=(char *)malloc((cterm.width-wherex())*2);
316: gettext(cterm.x+wherex(),cterm.y+wherey(),cterm.x+cterm.width,cterm.y+wherey(),p2);
317: memmove(p2,p2+(i*2),(cterm.width-wherex()-i)*2);
318: for(i=(cterm.width-wherex())*2-2;i>=wherex();i-=2)
319: p2[i]=' ';
320: puttext(cterm.x+wherex(),cterm.y+wherey(),cterm.x+cterm.width,cterm.y+wherey(),p2);
321: break;
322: case 'S':
323: scrollup();
324: break;
325: case 'T':
326: scrolldown();
327: break;
328: case 'U':
329: clearscreen(7);
330: gotoxy(1,1);
331: break;
332: case 'Y': /* ToDo? BananaCom Clear Line */
333: break;
334: case 'Z':
335: for(j=10;j>=0;j--) {
336: if(cterm_tabs[j]<wherex()) {
337: gotoxy(cterm_tabs[j],wherey());
338: break;
339: }
340: }
341: break;
342: case 'b': /* ToDo? Banana ANSI */
343: break;
344: case 'g': /* ToDo? VT100 Tabs */
345: break;
346: case 'h': /* ToDo? Scrolling regeion, word-wrap, doorway mode */
347: break;
348: case 'i': /* ToDo? Printing */
349: break;
350: case 'l': /* ToDo? Scrolling regeion, word-wrap, doorway mode */
351: break;
352: case 'm':
353: *(p--)=0;
354: p2=cterm.escbuf+1;
355: if(p2>p) {
356: cterm.attr=7;
357: break;
358: }
359: while((p=strtok(p2,";"))!=NULL) {
360: p2=NULL;
361: switch(atoi(p)) {
362: case 0:
363: cterm.attr=7;
364: break;
365: case 1:
366: cterm.attr|=8;
367: break;
368: case 2:
369: cterm.attr&=247;
370: break;
371: case 4: /* Underscore */
372: break;
373: case 5:
374: case 6:
375: cterm.attr|=128;
376: break;
377: case 7:
378: i=cterm.attr&7;
379: j=cterm.attr&112;
380: cterm.attr &= 136;
381: cterm.attr |= j>>4;
382: cterm.attr |= i<<4;
383: break;
384: case 8:
385: j=cterm.attr&112;
386: cterm.attr&=112;
387: cterm.attr |= j>>4;
388: break;
389: case 30:
390: cterm.attr&=248;
391: break;
392: case 31:
393: cterm.attr&=248;
394: cterm.attr|=4;
395: break;
396: case 32:
397: cterm.attr&=248;
398: cterm.attr|=2;
399: break;
400: case 33:
401: cterm.attr&=248;
402: cterm.attr|=6;
403: break;
404: case 34:
405: cterm.attr&=248;
406: cterm.attr|=1;
407: break;
408: case 35:
409: cterm.attr&=248;
410: cterm.attr|=5;
411: break;
412: case 36:
413: cterm.attr&=248;
414: cterm.attr|=3;
415: break;
416: case 37:
417: cterm.attr&=248;
418: cterm.attr|=7;
419: break;
420: case 40:
421: cterm.attr&=143;
422: break;
423: case 41:
424: cterm.attr&=143;
425: cterm.attr|=4<<4;
426: break;
427: case 42:
428: cterm.attr&=143;
429: cterm.attr|=2<<4;
430: break;
431: case 43:
432: cterm.attr&=143;
433: cterm.attr|=6<<4;
434: break;
435: case 44:
436: cterm.attr&=143;
437: cterm.attr|=1<<4;
438: break;
439: case 45:
440: cterm.attr&=143;
441: cterm.attr|=5<<4;
442: break;
443: case 46:
444: cterm.attr&=143;
445: cterm.attr|=3<<4;
446: break;
447: case 47:
448: cterm.attr&=143;
449: cterm.attr|=7<<4;
450: break;
451: }
452: }
453: textattr(cterm.attr);
454: break;
455: case 'n':
456: i=atoi(cterm.escbuf+1);
457: switch(i) {
458: case 6:
459: if(retbuf!=NULL) {
460: sprintf(tmp,"%c[%d;%dR",27,wherey(),wherex());
461: if(strlen(retbuf)+strlen(tmp) < retsize)
462: strcat(retbuf,tmp);
463: }
464: break;
465: case 255:
466: if(retbuf!=NULL) {
467: sprintf(tmp,"%c[%d;%dR",27,cterm.height,cterm.width);
468: if(strlen(retbuf)+strlen(tmp) < retsize)
469: strcat(retbuf,tmp);
470: }
471: break;
472: }
473: break;
474: case 'p': /* ToDo? ANSI keyboard reassignment */
475: break;
476: case 'q': /* ToDo? VT100 keyboard lights */
477: break;
478: case 'r': /* ToDo? Scrolling reigon */
479: break;
480: case 's':
481: cterm.save_xpos=wherex();
482: cterm.save_ypos=wherey();
483: break;
484: case 'u':
485: if(cterm.save_ypos>0 && cterm.save_ypos<=cterm.height
486: && cterm.save_xpos>0 && cterm.save_xpos<=cterm.width) {
487: gotoxy(cterm.save_xpos,cterm.save_ypos);
488: }
489: break;
490: case 'y': /* ToDo? VT100 Tests */
491: break;
492: case 'z': /* ToDo? Reset */
493: break;
494: }
495: break;
496: case 'D':
497: scrollup();
498: break;
499: case 'M':
500: scrolldown();
501: break;
502: case 'c':
503: /* ToDo: Reset Terminal */
504: break;
505: }
506: cterm.escbuf[0]=0;
507: cterm.sequence=0;
508: }
509:
510: void cterm_init(int height, int width, int xpos, int ypos, int backlines, unsigned char *scrollback)
511: {
512: cterm.x=xpos;
513: cterm.y=ypos;
514: cterm.height=height;
515: cterm.width=width;
516: cterm.attr=7;
517: cterm.save_xpos=0;
518: cterm.save_ypos=0;
519: cterm.escbuf[0]=0;
520: cterm.sequence=0;
521: cterm.music=0;
522: cterm.backpos=0;
523: cterm.backlines=backlines;
524: cterm.scrollback=scrollback;
525: if(cterm.scrollback!=NULL)
526: memset(cterm.scrollback,0,cterm.width*2*cterm.backlines);
527: textattr(cterm.attr);
528: _setcursortype(_NORMALCURSOR);
529: window(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y+cterm.height-1);
530: clrscr();
531: gotoxy(1,1);
532: }
533:
534: void ctputs(char *buf)
535: {
536: char *outp;
537: char *p;
538: char outline[80];
539: int oldscroll;
540: int cx;
541: int cy;
542: int i;
543:
544: p=buf;
545: outp=buf;
546: oldscroll=_wscroll;
547: _wscroll=0;
548: cx=wherex();
549: cy=wherey();
550: for(p=buf;*p;p++) {
551: switch(*p) {
552: case '\r':
553: cx=1;
554: break;
555: case '\n':
556: if(cy==cterm.height) {
557: *p=0;
558: cputs(outp);
559: outp=p+1;
560: scrollup();
561: }
562: else
563: cy++;
564: break;
565: case '\b':
566: if(cx>0)
567: cx--;
568: break;
569: case 7: /* Bell */
570: break;
571: case '\t':
572: for(i=0;i<10;i++) {
573: if(cterm_tabs[i]>cx) {
574: while(cx<cterm_tabs[i]) {
575: cx++;
576: }
577: break;
578: }
579: }
580: if(i==10) {
581: cx=1;
582: if(cy==cterm.height) {
583: *p=0;
584: cputs(outp);
585: outp=p+1;
586: scrollup();
587: }
588: else
589: cy++;
590: }
591: break;
592: default:
593: if(cy==cterm.height
594: && cx==cterm.width) {
595: *p=0;
596: cputs(outp);
597: outp=p+1;
598: scrollup();
599: cx=1;
600: }
601: else {
602: if(cx==cterm.width) {
603: cx=1;
604: cy++;
605: }
606: else {
607: cx++;
608: }
609: }
610: break;
611: }
612: }
613: cputs(outp);
614: _wscroll=oldscroll;
615: }
616:
617: char *cterm_write(unsigned char *buf, int buflen, char *retbuf, int retsize)
618: {
619: unsigned char ch[2];
620: unsigned char prn[BUFSIZE];
621: int key;
622: int i,j,k;
623: char *ret;
624: struct text_info ti;
625: int olddmc;
626:
627: olddmc=dont_move_cursor;
628: dont_move_cursor=1;
629: if(retbuf!=NULL)
630: retbuf[0]=0;
631: gettextinfo(&ti);
632: window(cterm.x,cterm.y,cterm.x+cterm.width-1,cterm.y+cterm.height-1);
633: gotoxy(cterm.xpos,cterm.ypos);
634: textattr(cterm.attr);
635: ch[1]=0;
636: switch(buflen) {
637: case 0:
638: break;
639: default:
640: prn[0]=0;
641: for(j=0;j<buflen;j++) {
642: ch[0]=buf[j];
643: if(cterm.sequence) {
644: strcat(cterm.escbuf,ch);
645: if((ch[0]>='@' && ch[0]<='Z')
646: || (ch[0]>='a' && ch[0]<='z')) {
647: do_ansi(retbuf, retsize);
648: }
649: }
650: else if (cterm.music) {
651: strcat(cterm.musicbuf,ch);
652: if(ch[0]==14)
653: play_music();
654: }
655: else {
656: switch(buf[j]) {
657: case 0:
658: break;
659: case 7: /* Beep */
660: ctputs(prn);
661: prn[0]=0;
662: #ifdef __unix__
663: putch(7);
664: #else
665: MessageBeep(MB_OK);
666: #endif
667: break;
668: case 12: /* ^L - Clear screen */
669: ctputs(prn);
670: prn[0]=0;
671: clearscreen(cterm.attr);
672: gotoxy(1,1);
673: break;
674: case 27: /* ESC */
675: ctputs(prn);
676: prn[0]=0;
677: cterm.sequence=1;
678: break;
679: case '\t':
680: ctputs(prn);
681: prn[0]=0;
682: for(k=0;k<11;k++) {
683: if(cterm_tabs[k]>wherex()) {
684: gotoxy(cterm_tabs[k],wherey());
685: break;
686: }
687: }
688: break;
689: default:
690: strcat(prn,ch);
691: }
692: }
693: }
694: ctputs(prn);
695: prn[0]=0;
696: break;
697: }
698: cterm.xpos=wherex();
699: cterm.ypos=wherey();
700: #if 0
701: window(ti.winleft,ti.wintop,ti.winright,ti.wintop);
702: gotoxy(ti.curx,ti.cury);
703: textattr(ti.attribute);
704: #endif
705:
706: dont_move_cursor=olddmc;
707: gotoxy(wherex(),wherey());
708: return(retbuf);
709: }
710:
711: void cterm_end(void)
712: {
713: /* Nothing to be done here at the moment */
714: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.