Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / sources / new-s5r4 / inkeyux.c
1 #include <stdio.h>
2 #include <signal.h>
3 #include <assert.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include <termio.h>
8
9
10 #include "graf/graf.h"
11
12 #define KB_BACKSPACE    (int)'\b'       /* kb */
13 #define KB_ENTER        (int)'\r'       /* RT */
14 #define KB_TAB          (int)'\t'       /* TB */
15 #define KB_ESC          0x1b            /* EC */
16
17 #define KB_HOME         -71     /* kh or HM */
18 #define KB_END          -79     /* EN */
19 #define KB_UP           -72     /* ku or UP */
20 #define KB_DOWN         -80     /* kd */
21 #define KB_LEFT         -75     /* kl */
22 #define KB_RIGHT        -77     /* kr */
23 #define KB_PGUP         -73     /* PU */
24 #define KB_PGDN         -81     /* PD */
25 #define KB_BACK_TAB     -15     /* BT */
26 #define KB_INS          -82     /* al */
27 #define KB_DEL          -83     /* DL */
28
29 #define KB_F1           -59     /* k1 */
30 #define KB_F2           -60     /* k2 */
31 #define KB_F3           -61     /* k3 */
32 #define KB_F4           -62     /* k4 */
33 #define KB_F5           -63     /* k5 */
34 #define KB_F6           -64     /* k6 */
35 #define KB_F7           -65     /* k7 */
36 #define KB_F8           -66     /* k8 */
37 #define KB_F9           -67     /* k9 */
38 #define KB_F10          -68     /* k0 */
39
40 #define KB_STR_EXISTS       1   /* string exists in tree or his prefix  */
41 #define KB_TOO_MANY_STRINGS 2   
42 #define KB_NULL_STRING      3
43 #define KB_OUT_OF_MEMORY    4
44 #define KB_OK               0
45
46
47
48 #include "depend.h"
49 #include "genint.h"
50 #include "int.h"
51 #include "process.h"
52 #include "intproto.h"
53
54
55 #define TERMINAL 0
56 #define KEYBOARD 1
57
58 static char *capability,*capability_value;
59
60 typedef struct _tree_node *tree;    /* drzewo zawierajace ciagi znakow     */
61 struct _tree_node {                 /* odpowiadajace klawiszowi klawiatury */
62    int key;
63    tree way;
64    int outkey;
65 };    
66
67 #ifndef NO_PROTOTYPES
68 static int tfirst(int);
69 static int tnext(void);
70 static void *___allocate_object(unsigned);
71 static void ___free_object(void *);
72 static char *object_str(char *);        /* allocate space and copy string */
73 static int __testkey(int*,int*);
74 static int getkey(void);
75 static int __inkey(void);
76 static void kbinit(void);
77 static tree new_tree_node(void);
78 static int _create_new_leaf(tree,int,unsigned char *,int);
79 static int inskey(int,char *);
80 #else
81 static int tfirst();
82 static int tnext();
83 static void *___allocate_object();
84 static void ___free_object();
85 static char *object_str();
86 static int __testkey();
87 static int getkey();
88 static int __inkey();
89 static void kbinit();
90 static tree new_tree_node();
91 static int _create_new_leaf();
92 static int inskey();
93 #endif
94
95
96
97
98
99 #define object_kill(i) (___free_object(i),(i)=NULL)
100 #define object_new(type) ((type *)___allocate_object(sizeof(type)))
101 #define object_dim(i,type) ((type *)___allocate_object((i)*sizeof(type)))
102
103
104
105
106 #define KB_NDEF 0xff /* KN - key suppressed by inkey() */
107
108 #define NODE_SIZE 100
109
110
111 #define QSIZE 256
112 static int cqueue[QSIZE];               /* implementacja kolejki */
113 static int qh=0,qt=0,qs=0;
114 static int bget(){
115    int c;
116    if( qs == 0 )  return -1;
117    c = cqueue[ qh++ ];
118    qh &= QSIZE - 1 ;
119    qs--;
120    return c;
121 }
122 static void bput( c )  int c; {
123    if( qs == QSIZE )  return;
124    cqueue[ qt++ ] = c;
125    qt &= QSIZE - 1 ;
126    qs++;
127 }
128 static int qq;
129 static int bfirst(){
130    if( qs == 0 )  return -1;
131    qq = qh + 1 ;
132    qq &= QSIZE - 1 ;
133    return  cqueue[ qh ];
134 }
135 static int bnext(){
136    int c;
137    if( qq == qt )  return -1;
138    c = cqueue[ qq++ ];
139    qq &= QSIZE - 1 ;
140    return c;
141 }
142
143
144 static tree troot=NULL;
145
146 #ifndef NDEBUG
147 static FILE *f=NULL;
148 static void _show_tree(root,r) tree root;int r;{
149    int i,j;
150    for(i=0;(i<NODE_SIZE) && (root[i].key!=-1);i++){
151       for(j=0;j<r;j++) fprintf(f,"i");
152       fflush(f);
153       fprintf(f,"%d ",root[i].key);fflush(f);
154       if(root[i].way==NULL){
155          fprintf(f,"%d\n",root[i].outkey);fflush(f);
156       }else _show_tree(root[i].way,r+1);
157    }
158 }
159 static void show_tree(){
160    f=fopen("show_tree","a");
161    if(f==NULL){printf("cant open");exit(7);}
162    fprintf(f,"%lx\n",troot);fflush(f);
163    _show_tree(troot,0);
164    fprintf(f,"********************\n");
165    fclose(f);
166 }
167 #endif
168
169
170 #define NO_CHARS        0
171 #define PART_SUBSTRING  1
172 #define SUBSTRING       2
173 #define STRING          3
174 #define NO_MATCH        4
175
176 static int __testkey(outkey,to_take) int *outkey,*to_take;
177 {
178    int c,i;
179    tree tact;
180
181    tact=troot;
182    c=bfirst();
183
184    if(c==-1) return NO_CHARS; /* buffer empty - wait for char */
185
186    *to_take=1;
187
188    for(;;){
189       for(i=0;i<NODE_SIZE;i++){
190          if(tact[i].key==-1){ i=NODE_SIZE; break; }
191          if(tact[i].key==c)
192             if(tact[i].way!=NULL){
193                c=bnext();
194                (*to_take)++;
195                if(c==-1){
196                   *outkey=tact[i].outkey;
197                   if(*outkey != -1)  return SUBSTRING;
198                   else               return PART_SUBSTRING;
199                }
200                tact=tact[i].way;
201                break;
202             }
203             else{
204                *outkey = tact[i].outkey;
205                return STRING;
206             }
207       }
208       if( i==NODE_SIZE )   return NO_MATCH;
209    } 
210 }
211
212
213 static void (*prev_fun)()=NULL;
214 static void alarm_fun(){}
215
216
217 static int getkey(){
218    int c;
219    prev_fun = signal( SIGALRM, alarm_fun );
220    alarm(1);
221    c = getchar();
222    alarm(0);
223    signal( SIGALRM, prev_fun );
224    return c;
225 }
226
227
228
229 static int __inkey()
230 {
231    int c,i,outkey,chars;
232    if(troot==NULL){printf("Not initialized\n\r");exit(7);}
233
234    alarm(0);
235
236    for(;;){
237
238       i=__testkey(&outkey,&chars);
239
240       switch( i ){
241
242          case NO_CHARS :
243             c = getkey();
244             if( c != -1 )   bput( c );
245             else  return 0;
246             break;
247
248          case PART_SUBSTRING :
249             c = getkey();
250             if( c==-1 ) return bget();
251             bput( c );
252             break;
253
254          case SUBSTRING :
255             c = getkey();
256             if( c==-1 ){
257                while( chars-- )  bget();
258                return outkey;
259             }
260             bput( c );
261             break;
262
263          case STRING :
264             while( chars-- )  bget();
265             return outkey;
266             break;
267
268          case NO_MATCH :
269             return bget();
270             break;
271       }
272    }
273 }
274
275
276 static struct termio term_state,term_new;
277
278 int inkey( dummy )
279    void *dummy;
280 {  /* podaj znak z klawiatury - zapominanie KB_NDEF */
281    static int first_time=1;
282    int k;
283
284    if( first_time ){  kbinit(); first_time=0; }
285
286    ioctl(fileno(stdin),TCGETA,&term_state);  /* RAW MODE */
287    term_new = term_state;
288    term_new.c_lflag&=~(ISIG|ICANON|ECHO);   /* echo,canonical line processing */
289                                             /* signal processing = OFF */
290    term_new.c_iflag&=~(ICRNL|INLCR);        /* conversions OFF */
291    term_new.c_oflag=0;
292    term_new.c_cc[VEOF]='\1';                /* every char flushed immedietly */
293    ioctl(fileno(stdin),TCSETA,&term_new);
294
295    do k=__inkey(); while(k==KB_NDEF);
296
297    ioctl(fileno(stdin),TCSETA,&term_state);  /* PREVIOUS MODE */
298
299    return k;
300 }
301
302
303 static tree new_tree_node(){
304    tree p;
305    int i;
306    p=(tree)object_dim(NODE_SIZE+1,struct _tree_node);
307    p++;
308    for(i=0;i<NODE_SIZE;i++){
309       p[i].key=p[i].outkey=-1;
310       p[i].way=NULL;
311    }
312    return p;
313 }
314
315
316 static int inskey(ch,str)
317    int ch;
318    char *str;
319 {
320    tree tact=troot;
321    int i;
322
323    if(troot==NULL) return KB_OUT_OF_MEMORY;
324    if(str==NULL || (!(*str))) return KB_NULL_STRING;
325
326    for(;;){
327       for(i=0;i<NODE_SIZE;i++){
328          if(tact[i].key==-1){
329             tact[i].key=(int)(*(str++));
330             return _create_new_leaf(tact,i,str,ch);
331          }
332          if(tact[i].key==(int)(*str)){
333             str++;
334             if(tact[i].way==NULL)
335                if( *str!='\0' )  return _create_new_leaf(tact,i,str,ch);
336                else              return KB_STR_EXISTS;
337             if( *str=='\0' ){
338                tact[i].outkey=ch;
339                return KB_OK;
340             }
341             tact=tact[i].way;
342             break;
343          }
344       }
345       if(i==NODE_SIZE) return KB_TOO_MANY_STRINGS;
346    }
347 }
348
349
350 static int _create_new_leaf(tact,i,str,ch)
351    tree tact;
352    int i,ch;
353    unsigned char *str;
354 {
355    while(*str!='\0'){
356       tact[i].way=new_tree_node();
357       tact[i].way[-1].way=tact;
358       tact=tact[i].way;
359       i=0;
360       tact[0].key=(int)(*(str++));
361    } 
362    tact[i].outkey=ch;
363    return KB_OK;
364 }
365
366
367 static struct { int key; char capability[3]; } tab[]={
368
369         { KB_NDEF       , "KN" },
370         { KB_BACKSPACE  , "kb" },
371         { KB_ENTER      , "RT" },
372         { KB_HOME       , "kh" },
373         { KB_HOME       , "HM" },
374         { KB_END        , "EN" },
375         { KB_UP         , "ku" },
376         { KB_UP         , "UP" },
377         { KB_DOWN       , "kd" },
378         { KB_LEFT       , "kl" },
379         { KB_RIGHT      , "kr" },
380         { KB_PGUP       , "PU" },
381         { KB_PGDN       , "PD" },
382         { KB_BACK_TAB   , "BT" },
383         { KB_TAB        , "TB" },
384         { KB_ESC        , "EC" },
385         { KB_INS        , "al" },
386         { KB_DEL        , "DL" },
387         { KB_F1         , "k1" },
388         { KB_F2         , "k2" },
389         { KB_F3         , "k3" },
390         { KB_F4         , "k4" },
391         { KB_F5         , "k5" },
392         { KB_F6         , "k6" },
393         { KB_F7         , "k7" },
394         { KB_F8         , "k8" },
395         { KB_F9         , "k9" },
396         { KB_F10        , "k0" }
397    };
398
399
400 static void kb_install(){
401    int i;
402    for(i=0;i<sizeof(tab)/sizeof(*tab);i++){
403       if(tab[i].capability[0]!=capability[0]) continue;
404       if(tab[i].capability[1]!=capability[1]) continue;
405       if(capability_value==NULL) return;
406       if(capability[2]!='='){
407          if( capability_value!=NULL) object_kill(capability_value);
408          return;
409       }
410       {
411          int err = inskey(tab[i].key,capability_value);
412          if(err==KB_OK) return;
413          if(err==KB_STR_EXISTS || err==KB_NULL_STRING){
414             object_kill(capability_value);
415             return;
416          }
417          printf("Capability %2.2s cannot be inserted:",capability);
418          if(err==KB_TOO_MANY_STRINGS) printf("too many strings\n\r");
419          if(err==KB_OUT_OF_MEMORY   ) printf("out of memory\n\r");
420          exit(7);
421       }
422       return;
423    }
424    if(capability_value!=NULL) object_kill(capability_value);
425 }
426
427
428 static void kbinit()                   /* inicjalizacja klawiatury  */
429 {                                      /* RAW MODE                  */
430    char *s,*s1;
431    int i,err;
432
433    troot=new_tree_node();
434    troot[-1].way=NULL;
435
436    capability="DL=";
437    capability_value=object_str("\177");
438    kb_install();
439
440    if(tfirst(KEYBOARD)==0){
441       kb_install();
442       while(tnext()==0){
443          kb_install();
444       }
445    }
446
447    if(tfirst(TERMINAL)==0){
448       kb_install();
449       while(tnext()==0){
450          kb_install();
451       }
452    }
453
454 }
455
456
457
458
459 /*   FUNCTIONS for search through one TERMCAP entry   */
460
461
462 static char *termcap=NULL;
463 static char *keybcap=NULL;
464
465 #ifndef NO_PROTOTYPES
466 static char *envset(char *,char*);
467 static char *findchar(char *,char);
468 static int convert(char *,char *,int);
469 static int next_char(FILE *);
470 static int find_name(FILE *,char *);
471 #else
472 static char *envset();
473 static char *findchar();
474 static int convert();
475 static int next_char();
476 static int find_name();
477 #endif
478
479
480 static char *findchar(str,ch) char *str,ch;{
481    if(str==NULL) return NULL;
482    while( *str!='\0'  &&  *str!=ch )  str++;
483    if(*str=='\0') return NULL;
484    return str;
485 }
486
487 static char *tgetent(dev)
488                             /* gets info from variable TERMCAP  */ 
489                             /* or var INKEY  or file /etc/inkey */
490 int dev;{
491
492  if(dev==TERMINAL){
493    if(termcap==NULL)   termcap=envset("TERMCAP","termcap");
494    if(termcap==NULL){
495       fprintf(stderr,"\n\rfile [/etc/]termcap not found\n\r");
496       fflush(stderr);exit(7);
497    }
498    return termcap;
499  }else
500  if(dev==KEYBOARD){
501     if(keybcap==NULL)  keybcap=envset("INKEY","inkey");
502     return keybcap;
503  }else{ printf("bad device for tgetent \n\r"); exit(7); }
504 }
505
506
507
508
509 static char stat_value[100];
510
511 static int tfirst(dev)
512    int dev;
513 {
514    char *value;
515    capability=tgetent(dev);
516    if(capability==NULL) return 1;
517    return tnext();
518 }
519 static int tnext(){
520    char *value,*colon;
521    do{
522       capability=findchar(capability,':');
523       if(capability==NULL) return 1;
524       capability++;
525       if(*capability=='\0') return 1;
526    } while( capability[0]==' ' || capability[0]=='\t' );
527    value=findchar(capability,'=');
528    colon=findchar(capability,':');
529    if( value==NULL || ( colon!=NULL && value!=NULL && colon<value ) ){
530       capability_value=object_str("");
531       return 0;
532    }
533    value++;
534    if(*value=='\0') return 1;
535    convert(stat_value,value,sizeof(stat_value));
536    capability_value=object_str(stat_value);
537    return 0;
538 }
539
540
541 static int convert(ptr,tptr,ptr_size) char *ptr,*tptr; int ptr_size; {
542    int i;
543    char c;
544    while( (tptr!=NULL) && (*tptr!=':') && (*tptr!='\0') )
545       switch(*tptr){
546          case '\\':tptr++;
547                    switch(*tptr){
548                       case 'E' :tptr++;ptr_size--;*(ptr++)='\x1b';break;
549                       case 'n' :tptr++;ptr_size--;*(ptr++)='\n';break;
550                       case 'r' :tptr++;ptr_size--;*(ptr++)='\r';break;
551                       case 't' :tptr++;ptr_size--;*(ptr++)='\t';break;
552                       case 'b' :tptr++;ptr_size--;*(ptr++)='\b';break;
553                       case 'f' :tptr++;ptr_size--;*(ptr++)='\f';break;
554                       case '\\':tptr++;ptr_size--;*(ptr++)='\\';break;
555                       case '^' :tptr++;ptr_size--;*(ptr++)='^';break;
556                       default  :*ptr='\0';
557                                 for(i=0;i<3;i++){
558                                    if(*tptr<'0' || *tptr>'7') return 1;
559                                    *ptr*=8;
560                                    *ptr+=*(tptr++)-'0';
561                                 }
562                                 ptr++; ptr_size--;
563                    }
564                    break;
565          case '^': tptr++;
566                    c=*(tptr++);
567                    *(ptr++)=(char)((toupper(c))-'A'+1); ptr_size--;
568                    break;
569          default: *(ptr++)=*(tptr++); ptr_size--; 
570       } 
571    *ptr='\0';
572    if( ptr_size<=0 ){
573       fprintf(stderr,"buffer exceeded in convert(%s)",__FILE__);
574       fflush(stderr);
575       exit(7);
576    }
577    return 0;
578 }
579
580
581 /*     FUNCTIONS looking for entries in /ETC/TERMCAP      */
582
583
584
585 static char etcname[80];
586 static char termname[80];
587 static char *fname;
588
589
590 static char *envset(envname,envfile) char *envname,*envfile;{
591    extern char *getenv();
592    char *TERM=getenv("TERM");
593    char *env=getenv(envname);
594    char *str,*ptr;
595    FILE *f;
596    int c,continued=1;
597
598    ptr=str=object_dim(32000,char);
599    if(str==NULL){
600       fprintf(stderr,"Out of memory.\n");
601       fflush(stderr);
602       exit(7);
603    }
604
605    if(TERM==NULL){
606       fprintf(stderr,"\n\renvironment variable TERM not found\n\r");
607       fflush(stderr);
608       exit(7);
609    }
610
611    strcpy(termname,TERM);
612
613    f=fopen(env,"r");
614    if( f==NULL )  f=fopen(envfile,"r");  else  fname=env;
615    if( f==NULL )  f=fopen(strcat(strcpy(etcname,"/etc/"),envfile),"r");
616    else           fname=envfile;
617    if( f==NULL )  return NULL;
618    else           fname=etcname;
619
620    while( continued ){
621
622       char *rev,*tnm;
623
624       if( find_name(f,termname)==0 )   return object_str(":");
625
626       *(ptr++)=':';
627       c=' ';
628       do{
629          c=next_char(f);
630          if( c!='\0' ) *(ptr++)=(char)c;
631       }while( c!='\0' );
632
633       *(ptr)='\0';
634       rev=ptr-1;
635       while( rev>str && rev[-1]!=':' )  rev--;
636       if( rev[0]=='t' && rev[1]=='c' ){
637          ptr=rev-1;
638          rev+=3;
639          tnm=termname;
640          while( *rev!=':' ) *(tnm++)=*(rev++);
641          *tnm='\0';
642          continued=1;
643       }else  continued=0;
644
645    }
646
647    ptr=object_str(str);
648    object_kill(str);
649    return ptr;
650
651 }
652
653 static int find_name(f,termname) FILE *f; char *termname;{
654    int i,c,lastc,found=0;
655    fseek(f,0L,0);
656
657    do{
658
659       do{
660          c=fgetc(f);
661          if(c==EOF)  return 0;
662          if(c=='#' || c=='\t' || c==':' || c=='\n')
663             while(c!='\n'){
664                lastc=c;
665                c=fgetc(f);
666                if(c==EOF)  return 0;
667                if( lastc=='\\' ) c=' ';
668             }
669       }while(c=='\n');
670
671       while( !found ){
672          for(i=0;termname[i]!='\0';i++){
673             if((char)c!=termname[i]) break;
674             c=fgetc(f);
675          }
676          if( termname[i]=='\0' ){ found=1; break; }
677          while( isalpha((char)c) )  c=fgetc(f);
678          if( c=='|' )  c=fgetc(f);
679          else{ ungetc('#',f); break; }
680       }
681
682    } while( !found );
683
684    while(c!=':'){
685       c=fgetc(f);
686       if(c==EOF)  return 0;
687    }
688
689    return 1;
690 }
691
692
693 static int next_char(f) FILE *f;{
694    int c;
695    static int lastc='\0';
696    if( lastc!='\0' ){
697       c=lastc;
698       lastc='\0';
699       return c;
700    }
701    c=fgetc(f);
702    if( c==EOF || c=='\n' )  return '\0';
703    if( c=='\\' ){
704       c=fgetc(f);
705       if( c=='\n' ){
706          while( c=='\n' || c=='\t' || c==':' || c==' ' )  c=fgetc(f);
707          return c;
708       }
709       lastc=c;
710       return '\\';
711    }
712    return c;
713 }
714
715
716
717
718 static void *___allocate_object(size) unsigned size;{
719    char *p;
720    extern void *calloc();
721    if(size==0) return NULL;
722    p=calloc(size,1);
723    if( p==NULL ){
724       printf("\r\n");
725       printf("=======================================\r\n");
726       printf("Memory overflow ... \r\n");
727       printf("=======================================\r\n");
728       fflush(stdout);
729       system("stty sane");
730       exit(7);
731    }
732    return (void *)p;
733 }
734
735 static void ___free_object(ff) void *ff;{
736    assert(ff!=NULL);
737    free((char *)ff);
738 }
739
740 static char *object_str(str) char *str;{
741    char *buf=object_dim(strlen(str)+1,char);
742    strcpy(buf,str);
743    return buf;
744 }