1 
2 
3 /* This version of microEmacs is based on the public domain C
4  * version written by Dave G. Conroy.
5  * The D programming language version is written by Walter Bright.
6  * http://www.digitalmars.com/d/
7  * This program is in the public domain.
8  */
9 
10 
11 module tcap;
12 
13 version (none)
14 {
15 import ed;
16 
17 import std.c.stdio;
18 import core.stdc.stdlib;
19 import std.c..string;
20 import std.c.time;
21 import core.sys.posix.termios;
22 
23 extern (C) void cfmakeraw(in termios*);
24 
25 termios  ostate;                 /* saved tty state */
26 termios  nstate;                 /* values for editor mode */
27 
28 
29 /* Termcap library functions
30  * See: http://www.gnu.org/software/termutils/manual/termcap-1.3/html_node/termcap_toc.html
31  */
32 
33 extern (C)
34 {
35     int tgetent(char *buffer, const char *termtype);
36     int tgetnum (const char *name);
37     int tgetflag (const char *name);
38     const(char) *tgetstr (const char *name, const(char) **area);
39     const(char) *tgoto (const(char) *cstring, int hpos, int vpos);
40     const(char) *tparam (const(char) *ctlstring, char *buffer, int size, int parm1,...);
41     char PC;
42     short ospeed;
43     int tputs (const(char) *string, int nlines, int function(int) outfun);
44 }
45 
46 enum
47 {
48     NROW    = 24,
49     NCOL    = 80,
50     BEL     = 0x07,
51     ESC     = 0x1B,
52 }
53 
54 char[2048] tcapbuf;
55 static const(char) *p;	/* roving pointer into tcapbuf[]	*/
56 const(char)*
57 	CM,
58         CL,
59         CE,
60         UP,
61         CD,
62 	KU,	/* up arrow key */
63 	KD,	/* down arrow key */
64 	KL,	/* left arrow key */
65 	KR,	/* right arrow key */
66 	K1,	/* second meta key */
67 	SO,	/* start standout mode */
68 	SE,	/* end standout mode */
69 	VB,	/* visible bell */
70 	CS,	/* scrolling region */
71 	SR,	/* scroll reverse */
72 	SF,	/* scroll forward */
73 	DO,	/* move down (alt for scroll forward) */
74 	AL,	/* add a line */
75 	DL;	/* delete a line */
76 
77 /*
78  * The LONGKEY structures are used to map the keys that produce
79  * escape sequences to single return values.  Each LONGKEY element
80  * is allocated as an array of LONGKEY structures.  lk[0].key is
81  * the number of structure-1, lk[0].ptr is a backpointer.  lk[1] is
82  * the first entry, etc.  These structures are dynamcially allocated
83  * and linked at initialize time.  See tcapgetc() to see how they
84  * are used.
85  */
86 
87 int LONGFINAL(char C) { return C & 0x80; }
88 int LONGCHAR(char C)  { return C & 0x7F; }
89 
90 struct LONGKEY
91 {
92 	char key;
93 	union {
94 	  LONGKEY *ptr;
95 	  int keyv;
96 	}
97 }
98 LONGKEY *lkroot = null;
99 
100 struct TERM
101 {
102     short   t_nrow;              /* Number of rows.              */
103     short   t_ncol;              /* Number of columns.           */
104     bool    t_canscroll = true;
105 
106     void t_open()            /* Open terminal at the start.  */
107     {
108         auto tv_stype = getenv("TERM");
109         if (tv_stype == null)
110         {
111 	    puts("environment variable TERM not defined\n");
112 	    exit(1);
113         }
114 
115         char[2048] tcbuf = void;
116         auto success = tgetent(tcbuf.ptr, tv_stype);
117         if (success < 0)
118         {
119 	    printf("cannot access termcap database\n");
120 	    exit(1);
121         }
122         if (success == 0)
123         {
124 	    printf("unknown terminal type %s\n", tv_stype);
125 	    exit(1);
126         }
127 
128         p = tcapbuf.ptr;
129         auto t = tgetstr("pc", &p);
130         if (t)
131 	    PC = *t;	// set "padding capabilities"
132 
133 	term.t_ncol = cast(short)tgetnum("co");
134 	term.t_nrow = cast(short)tgetnum("li");
135         CD = tgetstr("cd", &p);
136         CM = tgetstr("cm", &p);
137         CE = tgetstr("ce", &p);
138         UP = tgetstr("up", &p);
139 	//printf("UP=%p,%02x,%02x,%02x '%s'\n\n\n\n",UP,*UP,UP[1],UP[2],UP); fflush(stdout); sleep(1);
140 	VB = tgetstr("vb", &p);
141 	KU = tgetstr("ku", &p);
142 	//printf("KU=%p,%02x,%02x,%02x '%s'\n\n\n\n",KU,*KU,KU[1],KU[2],KU); fflush(stdout); sleep(3);
143 	KD = tgetstr("kd", &p);
144 	KL = tgetstr("kl", &p);
145 	KR = tgetstr("kr", &p);
146 	K1 = tgetstr("k1", &p);
147 	SO = tgetstr("so", &p);
148 	SE = tgetstr("se", &p);
149 	CS = tgetstr("cs", &p);
150 	SR = tgetstr("sr", &p);
151 	SF = tgetstr("sf", &p);
152 	DO = tgetstr("do", &p);
153 	AL = tgetstr("al", &p);
154 	DL = tgetstr("dl", &p);
155 	build_long_keys( tv_stype );
156 
157         if (CD == null || CM == null || CE == null || UP == null
158 	 || term.t_ncol < 1 || term.t_nrow < 1 )
159         {
160 	    puts("Incomplete termcap entry\n");
161 	    exit(1);
162         }
163 
164         if (p >= tcapbuf.ptr + tcapbuf.length)
165         {
166 	    puts("Terminal description too big!\n");
167 	    exit(1);
168         }
169 
170 	if (AL && DL)
171 	{
172 	    scroll_type = 0;
173 	}
174 	else if (CS && SR && (SF || DO))
175 	{
176 	    scroll_type = 1;
177 	    if (!SF)
178 		SF = DO;
179 	}
180 	else
181 	{
182 	    t_canscroll = false;
183 	}
184 
185         /* Adjust output channel        */
186         tcgetattr(1, &ostate);                       /* save old state */
187         tcgetattr(1, &nstate);                       /* get base of new state */
188 	cfmakeraw(&nstate);
189         tcsetattr(1, TCSADRAIN, &nstate);      /* set mode */
190 
191 	if( strcmp(tv_stype,"vt100") == 0 )
192 		fputs("\033=",stdout);	/* turn on the keypad	*/
193     }
194 
195     void t_close()            /* Close terminal at end.       */
196     {
197 	if( strcmp(getenv("TERM"),"vt100") == 0 )
198 	    fputs("\033[?7h",stdout);	/* turn on autowrap	*/
199 
200         tcsetattr(1, TCSADRAIN, &ostate);	// return to original mode
201     }
202 
203     int t_getchar()         /* Get character from keyboard. */
204     {
205 	int c,i;
206 	LONGKEY* lkp,tmpp;
207 
208 	__gshared int backlen;
209 	__gshared char[16] backc;
210 
211 	/*
212 	 * If there was a previously almost complete LONGKEY sequence
213 	 * that failed, then we have to send the characters as if they
214 	 * were pressed individually.
215 	 */
216     start:
217 	if( backlen )
218 		return( backc[--backlen] );
219 
220 	/*
221 	 * Continue following the LONGKEY structure sequence until
222 	 * either there is a complete match, or there is a complete
223 	 * failure to match.
224 	 */
225 	lkp = lkroot;
226     loop:
227 	c = fgetc(stdin);
228 	for(i=1; i<=lkp[0].key; i++)
229 	{
230 	    if( LONGCHAR(lkp[i].key) == c )
231 	    {
232 		//static int x;
233 		//printf("\nmatch %d\n",++x); fflush(stdout); sleep(2);
234 		if( LONGFINAL(lkp[i].key) )
235 		    return( lkp[i].keyv );
236 		lkp = lkp[i].ptr;
237 		goto loop;
238 	    }
239 	}
240 
241 	/+
242 	for(i=1; i<=lkp[0].key; i++)
243 	{
244 	  printf("\nLONGCHAR[%d] = x%02x\n",i,lkp[i].key);
245 	}
246 	printf("no match for x%02x of %d entries\n",c,i); fflush(stdout); sleep(10);
247 	+/
248 
249 	/*
250 	 * Upon a complete failure to match, we fill up the backc[]
251 	 * array with the ASCII characters that have been entered
252 	 * so that future calls to tcapgetc() can return these
253 	 * characters is the correct order.
254 	 */
255 	backc[backlen++] = cast(char)c;
256 	while( lkp[0].ptr != null )
257 	{
258 		tmpp = lkp;
259 		lkp = lkp[0].ptr;
260 		for(i=1; i<=lkp[0].key; i++)
261 			if( lkp[i].ptr == tmpp ) break;
262 		backc[backlen++] = lkp[i].key;
263 	}
264 	goto start;
265     }
266 
267     extern (C) static int t_putchar(int c)   /* Put character to display.    */
268     {
269 	return fputc(c, stdout);
270     }
271 
272     void t_flush()           /* Flush output buffers.        */
273     {
274 	fflush(stdout);
275     }
276 
277     void t_move(int row, int col)  /* Move the cursor, origin 0.   */
278     {
279         putpad(tgoto(CM, col, row));
280     }
281 
282     void t_eeol()            /* Erase to end of line.        */
283     {
284         putpad(CE);
285     }
286 
287     void t_eeop()            /* Erase to end of page.        */
288     {
289         putpad(CD);
290     }
291 
292     void t_beep()            /* Beep.                        */
293     {
294 	if (VB)
295 	    putpad(VB);
296 	else
297 	    t_putchar(BEL);
298     }
299 
300     void t_standout()        /* Start standout mode          */
301     {
302 	if (SO)
303 	    putpad( SO );
304     }
305 
306     void t_standend()        /* End standout mode            */
307     {
308 	if (SE)
309 	    putpad( SE );
310     }
311 
312     void setColorBright(bool bright)
313     {
314 	//fprintf(_fp, "\033[%dm", bright);
315     }
316 
317     void setColor(Color color)
318     {
319 	//fprintf(_fp, "\033[%d;%dm", color & Color.bright ? 1 : 0, 30 + (color & ~Color.bright));
320     }
321 
322     void resetColor()
323     {
324 	//fputs("\033[m", _fp);
325     }
326 
327     void t_scrollup(int first, int last)   /* Scroll the screen up         */
328     {
329 	if (scroll_type)
330 	{
331 	    tpstr( CS, first, last );
332 	    t_move( last, 0 );
333 	    putpad( SF );
334 	    tpstr( CS, 0, term.t_nrow - 1 );
335 	    t_move( last, 0 );
336 	}
337 	else
338 	{
339 	    t_move( first, 0 );
340 	    putpad( DL );
341 	    t_move( last, 0 );
342 	    putpad( AL );
343 	}
344     }
345 
346     void t_scrolldn(int first, int last)  /* Scroll the screen down       */
347 					  /* Note: scrolling routines do  */
348 					  /*  not save cursor position.   */
349     {
350 	if (scroll_type)
351 	{
352 	    tpstr( CS, first, last );
353 	    t_move( first, 0 );
354 	    putpad( SR );
355 	    tpstr( CS, 0, term.t_nrow - 1 );
356 	    t_move( first, 0 );
357 	}
358 	else
359 	{
360 	    t_move( last, 0 );
361 	    putpad( DL );
362 	    t_move( first, 0 );
363 	    putpad( AL );
364 	}
365     }
366 
367     void t_setcursor(int insertmode)
368     {
369     }
370 }
371 
372 
373 TERM term;
374 
375 static int scroll_type;	/* type of scrolling region (used in tcapscr{up|dn}) */
376 
377 
378 void putpad(const(char)* str)
379 {
380         tputs(str, 1, &TERM.t_putchar);
381 }
382 
383 void putnpad(const(char)* str, int n)
384 {
385         tputs(str, n, &TERM.t_putchar);
386 }
387 
388 static void build_long_keys(const(char)* term )
389 {
390     lkroot = cast(LONGKEY *)malloc(LONGKEY.sizeof);
391     lkroot.key = 0;
392     lkroot.ptr = null;
393 
394     version (Posix)
395     {
396         build_one_long("\033[A", UPKEY);
397 	build_one_long("\033[B", DNKEY);
398 	build_one_long("\033[C", RTKEY);
399 	build_one_long("\033[D", LTKEY);
400 	build_one_long( "\033\x4F\x50", F1KEY );
401 	build_one_long( "\033\x4F\x51", F2KEY );
402 	build_one_long( "\033\x4F\x52", F3KEY );
403 	build_one_long( "\033\x4F\x53", F4KEY );
404 	build_one_long( "\033\x5B\x31\x31\x7E", F1KEY );
405 	build_one_long( "\033\x5B\x31\x32\x7E", F2KEY );
406 	build_one_long( "\033\x5B\x31\x33\x7E", F3KEY );
407 	build_one_long( "\033\x5B\x31\x34\x7E", F4KEY );
408 	build_one_long( "\033\x5B\x31\x35\x7E", F5KEY );
409 	build_one_long( "\033\x5B\x31\x37\x7E", F6KEY );
410 	build_one_long( "\033\x5B\x31\x38\x7E", F7KEY );
411 	build_one_long( "\033\x5B\x31\x39\x7E", F8KEY );
412 	build_one_long( "\033\x5B\x32\x30\x7E", F9KEY );
413 	build_one_long( "\033\x5B\x32\x31\x7E", F10KEY );
414 
415 
416 	build_one_long("\033\x62", ALTB );
417 	build_one_long("\033\x63", ALTC );
418 	build_one_long("\033\x64", ALTD );
419 	build_one_long("\033\x64", ALTE );
420 	build_one_long("\033\x66", ALTF );
421 	build_one_long("\033\x68", ALTH );
422 	build_one_long("\033\x6D", ALTM );
423 	build_one_long("\033\x78", ALTX );
424 	build_one_long("\033\x7A", ALTZ );
425 
426 	build_one_long("\033\x5B\x32\x7E", InsKEY );
427 	build_one_long("\033\x5B\x33\x7E", DelKEY );
428 	build_one_long("\033\x5B\x31\x7E", HOMEKEY );
429 	build_one_long("\033\x5B\x34\x7E", ENDKEY );
430 	build_one_long("\033\x5B\x35\x7E", PgUpKEY );
431 	build_one_long("\033\x5B\x36\x7E", PgDnKEY );
432     }
433     else
434     {
435 	build_one_long( KU, UPKEY );
436 	build_one_long( KD, DNKEY );
437 	build_one_long( KR, RTKEY );
438 	build_one_long( KL, LTKEY );
439 	build_one_long( K1, GOLDKEY );
440 	build_one_long( tgetstr("kR",&p), SCROLLUPKEY ); /* scroll back */
441 	build_one_long( tgetstr("kF",&p), SCROLLDNKEY ); /* scroll forw */
442 	build_one_long( tgetstr("kP",&p), PAGEUPKEY ); /* prev page */
443 	build_one_long( tgetstr("kN",&p), PAGEDNKEY ); /* next page */
444 	if( strcmp(term,"vt100") == 0 )
445 	{
446 		build_one_long( "\033OQ", PF2KEY );
447 		build_one_long( "\033OR", PF3KEY );
448 		build_one_long( "\033OS", PF4KEY );
449 		build_one_long( "\033Op", F0KEY );
450 		build_one_long( "\033Oq", F1KEY );
451 		build_one_long( "\033Or", F2KEY );
452 		build_one_long( "\033Os", F3KEY );
453 		build_one_long( "\033Ot", F4KEY );
454 		build_one_long( "\033Ou", F5KEY );
455 		build_one_long( "\033Ov", F6KEY );
456 		build_one_long( "\033Ow", F7KEY );
457 		build_one_long( "\033Ox", F8KEY );
458 		build_one_long( "\033Oy", F9KEY );
459 		build_one_long( "\033Om", FMINUSKEY );
460 		build_one_long( "\033Ol", FCOMMAKEY );
461 		build_one_long( "\033On", FDOTKEY );
462 		build_one_long( "\033OM", FENTERKEY );
463 	}
464 	else
465 	{
466 		build_one_long( tgetstr("k2",&p), PF2KEY );
467 		build_one_long( tgetstr("k3",&p), PF3KEY );
468 		build_one_long( tgetstr("k4",&p), PF4KEY );
469 		build_one_long( tgetstr("k5",&p), F5KEY );
470 		build_one_long( tgetstr("k6",&p), F6KEY );
471 		build_one_long( tgetstr("k7",&p), F7KEY );
472 		build_one_long( tgetstr("k8",&p), F8KEY );
473 		build_one_long( tgetstr("k9",&p), F9KEY );
474 		build_one_long( "\033Op", F0KEY );
475 		build_one_long( "\033Oq", F1KEY );
476 		build_one_long( "\033Or", F2KEY );
477 		build_one_long( "\033Os", F3KEY );
478 		build_one_long( "\033Ot", F4KEY );
479 		build_one_long( "\033Om", FMINUSKEY );
480 		build_one_long( "\033[229z", FCOMMAKEY );
481 		build_one_long( "\033Ol", FCOMMAKEY );
482 		build_one_long( "\033OM", FENTERKEY );
483 	}
484     }
485 }
486 
487 static void build_one_long(const(char)* s, int keyval)
488 {
489 	int i;
490 	LONGKEY* lkp,tmpp,tmpq;
491 
492 	if (!s)
493 		return;
494 	lkp = lkroot;
495 	while( *s )
496 	{
497 		for(i=1; i<=lkp[0].key; i++)
498 			if( lkp[i].key == *s ) break;
499 		if( i != lkp[0].key+1 )
500 		{
501 			lkp = lkp[i].ptr;
502 			s++;
503 		}
504 		else
505 		{
506 			tmpp = cast(LONGKEY *)malloc( 
507 				LONGKEY.sizeof * ++i );
508 			while( i-- )
509 			{
510 				tmpp[i].key = lkp[i].key;
511 				tmpp[i].ptr = lkp[i].ptr;
512 			}
513 			if( lkp[0].ptr )
514 			{
515 				tmpq = lkp[0].ptr;
516 				for(i=1; i<=tmpq[0].key; i++)
517 					if( tmpq[i].ptr == lkp )
518 						tmpq[i].ptr = tmpp;
519 			}
520 			else
521 				lkroot = tmpp;
522 			free( lkp );
523 			lkp = tmpp;
524 			for(i=1; i<=lkp[0].key; i++)
525 				if( !LONGFINAL(lkp[i].key) )
526 					lkp[i].ptr.ptr = lkp;
527 			lkp[0].key++;
528 			lkp[lkp[0].key].key = *s++;
529 			if( !*s )
530 			{
531 				lkp[lkp[0].key].keyv = keyval;
532 				lkp[lkp[0].key].key |= 0x80;
533 			}
534 			else
535 			{
536 				tmpp = lkp;
537 				lkp = lkp[lkp[0].key].ptr = cast(LONGKEY *)
538 					malloc( LONGKEY.sizeof );
539 				lkp[0].key = 0;
540 				lkp[0].ptr = tmpp;
541 			}
542 		}
543 	}
544 }
545 
546 void tpstr(const(char)* str, int p1, int p2)
547 {
548 	char[128] buf = '\0';
549 	char* pt = buf.ptr;
550 	int pi;
551 
552 	pi = p1;
553 	while( *str >= '0' && *str <= '9' ) *pt++ = *str++;
554 	if( *str == '*' ) *pt++ = *str++;
555 	while( *str )
556 	{
557 		if( *str == '%' )
558 		{	str++;
559 			switch( *str++ )
560 			{
561 			  case 'd':
562 				sprintf(pt,"%d",pi);
563 				pi = p2; break;
564 			  case '2':
565 				sprintf(pt,"%2d",pi);
566 				pi = p2; break;
567 			  case '3':
568 				sprintf(pt,"%3d",pi);
569 				pi = p2; break;
570 			  case '.':
571 				sprintf(pt,"%c",pi);
572 				pi = p2; break;
573 			  case 'r':
574 				pi = p2;
575 				p2 = p1;
576 				p1 = pi;
577 				break;
578 			  case 'i':
579 				p1++; p2++; pi++; break;
580 			  case '%':
581 				*pt++ = '%'; break;
582 			  default:
583 				strcpy(pt,"\nTERMCAP Error\n");
584 				break;
585 			}
586 			pt = buf.ptr + strlen(buf.ptr);
587 		}
588 		else
589 			*pt++ = *str++;
590 	}
591 	*pt = '\0';
592 	putpad( buf.ptr );
593 }
594 
595 debug
596 {
597     void dump_longs()
598     {
599 	printf("__dump__\n");
600 	dump_one_long( 0, lkroot, null );
601 	printf("________\n");
602     }
603 
604     int backcheck = 0;
605 
606     void dump_one_long( int offset, LONGKEY* lkp, LONGKEY* lkprev )
607     {
608 	int i,j;
609 	if( backcheck )
610 	{
611 		for(j=0; j<offset; j++) printf(" ");
612 		printf( (lkprev == lkp[0].ptr) ? "TRUE\n" : "FALSE\n" );
613 	}
614 	for(i=1; i<=lkp[0].key; i++)
615 	{
616 		for(j=0; j<offset; j++) printf(" ");
617 		printf("%d (%c)      ",
618 			LONGCHAR(lkp[i].key), LONGCHAR(lkp[i].key));
619 		if( LONGFINAL(lkp[i].key) )
620 			printf("return( %d )\n", lkp[i].keyv );
621 		else
622 		{	printf("\n");
623 			dump_one_long( offset+1, lkp[i].ptr, lkp );
624 		}
625 	}
626     }
627 }
628 
629 /**************************
630  * Return true if there are unread chars ready in the input.
631  */
632 
633 bool ttkeysininput()
634 {
635     return false;
636 }
637 
638 /**************************
639  * Return when there are unread chars ready in the input.
640  */
641 
642 void ttwaitkeys()
643 {
644 } 
645 
646 /******************************
647  */
648 
649 void ttyield()
650 {
651 }
652 
653 /******************************
654  */
655 
656 int msm_init()
657 {
658     return FALSE;	// no mouse support
659 }
660 
661 int mouse_command()
662 {
663     return 0;		// no mouse input
664 }
665 }