]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/conio.c
ifdef off conio.c if not configured -- should not be necessary
[bacula/bacula] / bacula / src / console / conio.c
1 /*        
2       Generalized console input/output handler
3       Kern Sibbald, December MMIII
4 */
5
6 #define BACULA
7 #ifdef  BACULA
8 #include "bacula.h"
9 #else
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <ctype.h> 
15 #endif
16
17 #ifdef HAVE_CONIO
18
19 /*
20 #include <curses.h>
21 #include <term.h>
22 */
23 #include <termcap.h>
24 #include "func.h"
25
26 /* Global functions imported */
27
28
29 extern char *getenv(char *);
30
31 static void add_smap(char *str, int func);
32
33 /* From termios library */
34 extern char *BC;
35 extern char *UP;
36
37 /* Global variables */
38
39 static char *t_up = "\n";                    /* scroll up character */
40 static char *t_honk = "\007";                /* sound beep */
41 static char *t_il;                           /* insert line */
42 static char *t_dl;                           /* delete line */
43 static char *t_cs;                           /* clear screen */
44 static char *t_cl;                           /* clear line */
45 static int t_width = 79;                     /* terminal width */
46 static int t_height = 24;                    /* terminal height */
47 static int linsdel_ok = 0;              /* set if term has line insert & delete fncs */
48
49 static char *t_cm;                           /* cursor positioning */
50 static char *t_ti;                           /* init sequence */
51 static char *t_te;                           /* end sequence */
52 static char *t_do;                           /* down one line */
53 static char *t_sf;                           /* scroll screen one line up */
54
55 /* Keypad and Function Keys */
56 static char *kl;                             /* left key */
57 static char *kr;                             /* right */
58 static char *ku;                             /* up */
59 static char *kd;                             /* down */
60 static char *kh;                             /* home */
61 static char *kb;                             /* backspace */
62 static char *kD;                             /* delete key */
63 static char *kI;                             /* insert */
64 static char *kN;                             /* next page */
65 static char *kP;                             /* previous page */
66 static char *kH;                             /* home */
67 static char *kE;                             /* end */
68
69 #ifndef EOS
70 #define EOS  '\0'                     /* end of string terminator */
71 #endif
72
73 #define TRUE  1
74 #define FALSE 0
75 /*
76  * Stab entry. Input chars (str), the length, and the desired
77  *  func code.
78  */
79 typedef struct s_stab {
80    struct s_stab *next;
81    int len;
82    int func;
83    char *str;
84 } stab_t;
85
86 #define MAX_STAB 30
87
88 static stab_t **stab = NULL;                 /* array of stabs by length */
89 static int num_stab;                         /* size of stab array */
90
91 /* Local variables */
92
93 static bool old_term_params_set = false;
94 static struct termios old_term_params;
95
96 /* Maintain lines in a doubly linked circular pool of lines. Each line is
97    preceded by a header defined by the lstr structure */
98
99
100 struct lstr {                         /* line pool structure */
101    struct lstr *prevl;                /* link to previous line */
102    struct lstr *nextl;                /* link to next line */
103    long len;                          /* length of line+header */
104    char used;                         /* set if line valid */
105    char line;                         /* line is actually varying length */
106 };
107
108 #ifdef unix
109 #define POOLEN 128000                 /* bytes in line pool */
110 #else
111 #define POOLEN 500                    /* bytes in line pool */
112 #endif
113 char pool[POOLEN];                    /* line pool */
114 #define PHDRL ((int)sizeof(struct lstr))  /* length of line header */
115
116 static struct lstr *lptr;             /* current line pointer */
117 static struct lstr *slptr;            /* store line pointer */
118 static int cl, cp;
119 static char *getnext(), *getprev();
120 static int first = 1;
121 static int mode_insert = 0;
122 static int mode_wspace = 1;           /* words separated by spaces */
123
124 /* Forward referenced functions */
125 static void sigintcatcher(int);
126
127 /* Global variables Exported */
128
129 static short char_map[600]= {
130    0,                                  F_SOL,    /* ^a Line start */
131    F_PRVWRD, /* ^b Previous word */    F_BREAK,  /* ^C break */
132    F_DELCHR, /* ^D Delete character */ F_EOL,    /* ^e End of line */
133    F_CSRRGT, /* ^f Right */            F_TABBAK, /* ^G Back tab */
134    F_CSRLFT, /* ^H Left */             F_TAB,    /* ^I Tab */
135    F_CSRDWN, /* ^J Down */             F_DELEOL, /* ^K kill to eol */
136    F_CLRSCRN,/* ^L clear screen */     F_RETURN, /* ^M Carriage return */
137    F_RETURN, /* ^N enter line  */      F_CONCAT, /* ^O Concatenate lines */
138    F_CSRUP,  /* ^P cursor up */        F_TINS,   /* ^Q Insert character mode */
139    F_PAGUP,  /* ^R Page up */          F_CENTER, /* ^S Center text */
140    F_PAGDWN, /* ^T Page down */        F_DELSOL, /* ^U delete to start of line */
141    F_DELWRD, /* ^V Delete word */      F_PRVWRD, /* ^W Previous word */
142    F_NXTMCH, /* ^X Next match */       F_DELEOL, /* ^Y Delete to end of line */
143    F_BACKGND,/* ^Z Background */       0x1B,     /* ^[=ESC escape */
144    F_TENTRY, /* ^\ Entry mode */       F_PASTECB,/* ^]=paste clipboard */
145    F_HOME,   /* ^^ Home */             F_ERSLIN, /* ^_ Erase line */
146
147    ' ','!','"','#','$','%','&','\047',
148    '(',')','*','+','\054','-','.','/',
149    '0','1','2','3','4','5','6','7',
150    '8','9',':',';','<','=','>','?',
151    '@','A','B','C','D','E','F','G',
152    'H','I','J','K','L','M','N','O',
153    'P','Q','R','S','T','U','V','W',
154    'X','Y','Z','[','\\',']','^','_',
155    '\140','a','b','c','d','e','f','g',
156    'h','i','j','k','l','m','n','o',
157    'p','q','r','s','t','u','v','w',
158    'x','y','z','{','|','}','\176',F_ERSCHR  /* erase character */
159
160   };
161
162
163 #define NVID  0x1E                    /* normal video -- blue */
164 #define RVID  0x4F                    /* reverse video -- red */
165 #define MNVID 0x07                    /* normal video (monochrome tube) */
166 #define MRVID 0x70                    /* reverse video (monochrome tube) */
167
168
169 /* Local variables */
170
171 #define CR '\r'                       /* carriage return */
172
173
174 /* Function Prototypes */
175
176 static int input_char(void);
177 static int t_gnc(void);
178 static void insert_space(char *curline, int line_len);
179 static void forward(int i, char *str, int str_len);
180 static void backup(int i);
181 static void delchr(int cnt, char *curline, int line_len);
182 static int iswordc(char c);
183 static int  next_word(char *ldb_buf);
184 static int  prev_word(char *ldb_buf);
185 static void prtcur(char *str);
186 static void poolinit(void);
187 static char * getnext(void);
188 static char * getprev(void);
189 static void putline(char *newl, int newlen);
190 static void t_honk_horn(void);
191 static void t_insert_line(void);
192 static void t_delete_line(void);
193 static void t_clrline(int pos, int width);
194 void t_sendl(char *msg, int len);
195 void t_send(char *msg);
196 void t_char(char c);
197 static void asclrs();
198 static void ascurs(int y, int x);
199
200 static void rawmode(FILE *input);
201 static void normode(void);
202 static int t_getch();
203 static void trapctlc();
204 static void asclrl(int pos, int width);
205 static void asinsl();
206 static void asdell();
207
208 int input_line(char *string, int length);
209
210 void con_init(FILE *input)
211 {
212    rawmode(input);
213    trapctlc();
214 }
215
216 /*
217  * Zed control keys
218  */
219 void con_set_zed_keys(void)
220 {
221    char_map[1]  = F_NXTWRD; /* ^A Next Word */
222    char_map[2]  = F_SPLIT;  /* ^B Split line */
223    char_map[3]  = F_EOI;    /* ^C Quit */
224    char_map[4]  = F_DELCHR; /* ^D Delete character */
225    char_map[5]  = F_EOF;    /* ^E End of file */
226    char_map[6]  = F_INSCHR; /* ^F Insert character */
227    char_map[7]  = F_TABBAK; /* ^G Back tab */
228    char_map[8]  = F_CSRLFT; /* ^H Left */
229    char_map[9]  = F_TAB;    /* ^I Tab */
230    char_map[10] = F_CSRDWN; /* ^J Down */
231    char_map[11] = F_CSRUP;  /* ^K Up */
232    char_map[12] = F_CSRRGT; /* ^L Right */
233    char_map[13] = F_RETURN; /* ^M Carriage return */
234    char_map[14] = F_EOL;    /* ^N End of line */
235    char_map[15] = F_CONCAT; /* ^O Concatenate lines */
236    char_map[16] = F_MARK;   /* ^P Set marker */
237    char_map[17] = F_TINS;   /* ^Q Insert character mode */
238    char_map[18] = F_PAGUP;  /* ^R Page up */
239    char_map[19] = F_CENTER; /* ^S Center text */
240    char_map[20] = F_PAGDWN; /* ^T Page down */
241    char_map[21] = F_SOL;    /* ^U Line start */
242    char_map[22] = F_DELWRD; /* ^V Delete word */
243    char_map[23] = F_PRVWRD; /* ^W Previous word */
244    char_map[24] = F_NXTMCH; /* ^X Next match */
245    char_map[25] = F_DELEOL; /* ^Y Delete to end of line */
246    char_map[26] = F_DELLIN; /* ^Z Delete line */
247    /* 27 = ESC */
248    char_map[28] = F_TENTRY; /* ^\ Entry mode */
249    char_map[29] = F_PASTECB;/* ^]=paste clipboard */
250    char_map[30] = F_HOME;   /* ^^ Home */
251    char_map[31] = F_ERSLIN; /* ^_ Erase line */
252
253 }
254
255 void con_term()
256 {
257    normode();
258 }
259
260 #ifndef BACULA
261 /*
262  * Guarantee that the string is properly terminated */
263 static char *bstrncpy(char *dest, const char *src, int maxlen)
264 {
265    strncpy(dest, src, maxlen-1);
266    dest[maxlen-1] = 0;
267    return dest;
268 }
269 #endif
270
271
272 /*
273  * New style string mapping to function code
274  */
275 static int do_smap(int c)
276 {
277     char str[MAX_STAB];
278     int len = 0; 
279     stab_t *tstab;
280     int i, found;
281
282     len = 1;
283     str[0] = c;
284     str[1] = 0;
285
286     if (c != 27) {
287        c = char_map[c];
288     }
289     if (c <= 0) {
290        return c;
291     }
292     for ( ;; ) {
293        found = 0;
294        for (i=len-1; i<MAX_STAB; i++) {
295           for (tstab=stab[i]; tstab; tstab=tstab->next) {
296              if (strncmp(str, tstab->str, len) == 0) {
297                 if (len == tstab->len) {
298                    return tstab->func;
299                 }
300                 found = 1;
301                 break;                /* found possibility continue searching */
302              }
303           }
304        }
305        if (!found) {
306           return len==1?c:0;
307        }
308        /* found partial match, so get next character and retry */
309        str[len++] = t_gnc();
310        str[len] = 0;
311     }
312 }
313
314 #ifdef DEBUG_x
315 static void dump_stab()
316 {
317     int i, j, c;
318     stab_t *tstab;
319     char buf[100];
320
321     for (i=0; i<MAX_STAB; i++) {
322        for (tstab=stab[i]; tstab; tstab=tstab->next) {
323           for (j=0; j<tstab->len; j++) {
324              c = tstab->str[j];
325              if (c < 0x20 || c > 0x7F) {
326                 sprintf(buf, " 0x%x ", c);
327                 t_send(buf);
328              } else {
329                 buf[0] = c;
330                 buf[1] = 0;
331                 t_sendl(buf, 1);
332              }
333           }
334           sprintf(buf, " func=%d len=%d\n\r", tstab->func, tstab->len);
335           t_send(buf);
336        }
337     }
338 }
339 #endif
340
341 /*
342  * New routine. Add string to string->func mapping table.
343  */
344 static void add_smap(char *str, int func)
345 {
346    stab_t *tstab;
347    int len;
348   
349    if (!str) {
350       return;
351    }
352    len = strlen(str);
353    if (len == 0) {
354 /*    errmsg("String for func %d is zero length\n", func); */
355       return;
356    }
357    tstab = (stab_t *)malloc(sizeof(stab_t));
358    memset(tstab, 0, sizeof(stab_t));
359    tstab->len = len;
360    tstab->str = (char *)malloc(tstab->len + 1);
361    bstrncpy(tstab->str, str, tstab->len + 1);
362    tstab->func = func;
363    if (tstab->len > num_stab) {
364       printf("stab string too long %d. Max is %d\n", tstab->len, num_stab);
365       exit(1);
366    }
367    tstab->next = stab[tstab->len-1];
368    stab[tstab->len-1] = tstab;
369 /* printf("Add_smap tstab=%x len=%d func=%d tstab->next=%x\n\r", tstab, len, 
370           func, tstab->next); */
371
372 }
373
374
375 /* Get the next character from the terminal - performs table lookup on
376    the character to do the desired translation */
377 static int
378 /*FCN*/input_char()
379 {
380     int c;
381
382     if ((c=t_gnc()) <= 599) {         /* IBM generates codes up to 260 */
383           c = do_smap(c);
384     } else if (c > 1000) {            /* stuffed function */
385        c -= 1000;                     /* convert back to function code */
386     }
387     if (c <= 0) {
388         t_honk_horn();
389     }
390     /* if we got a screen size escape sequence, read height, width */
391     if (c == F_SCRSIZ) {
392        int y, x;
393        y = t_gnc() - 0x20;        /* y */
394        x = t_gnc() - 0x20;        /* x */
395        c = input_char();
396     }
397     return c;
398 }
399
400
401 /* Get a complete input line */
402
403 int
404 /*FCN*/input_line(char *string, int length)
405 {
406    char curline[200];                 /* edit buffer */
407    int noline;
408    int c;
409
410     if (first) {
411         poolinit();                   /* build line pool */
412         first = 0;
413     }
414     noline = 1;                       /* no line fetched yet */
415     for (cl=cp=0; cl<length && cl<(int)sizeof(curline); ) {
416         switch (c=(int)input_char()) {
417         case F_RETURN:                /* CR */
418             t_sendl("\r\n", 2);       /* yes, print it and */
419             goto done;                /* get out */
420         case F_CLRSCRN:               /* clear screen */
421            asclrs();
422            t_sendl(curline, cl);
423            ascurs(0, cp);
424            break;
425         case F_CSRUP:
426             if (noline) {             /* no line fetched yet */
427                 getnext();            /* getnext so getprev gets current */
428                 noline = 0;           /* we now have line */
429             }
430             bstrncpy(curline, getprev(), sizeof(curline));
431             prtcur(curline);
432             break;
433         case F_CSRDWN:
434             noline = 0;               /* mark line fetched */
435             bstrncpy(curline, getnext(), sizeof(curline));
436             prtcur(curline);
437             break;
438         case F_INSCHR:
439             insert_space(curline, sizeof(curline));
440             break;
441         case F_DELCHR:
442             delchr(1, curline, sizeof(curline));       /* delete one character */
443             break;
444         case F_CSRLFT:                /* Backspace */
445             backup(1);
446             break;
447         case F_CSRRGT:
448             forward(1,curline, sizeof(curline));
449             break;
450         case F_ERSCHR:                /* Rubout */
451             backup(1);
452             delchr(1, curline, sizeof(curline));
453             break;
454         case F_DELEOL:
455             t_clrline(0, t_width);
456             if (cl > cp)
457                 cl = cp;
458             break;
459         case F_NXTWRD:
460             forward(next_word(curline),curline, sizeof(curline));
461             break;
462         case F_PRVWRD:
463             backup(prev_word(curline));
464             break;
465         case F_DELWRD:
466             delchr(next_word(curline), curline, sizeof(curline)); /* delete word */
467             break;
468         case F_NXTMCH:                /* Ctl-X */
469             if (cl==0) {
470                 *string = EOS;        /* terminate string */
471                 return(c);            /* give it to him */
472             }
473             /* Note fall through */
474         case F_DELLIN:
475         case F_ERSLIN:
476             backup(cp);               /* backup to beginning of line */
477             t_clrline(0,t_width);     /* erase line */
478             cp = 0;
479             cl = 0;                   /* reset cursor counter */
480             break;
481         case F_SOL:
482             backup(cp);
483             break;
484         case F_EOL:
485             while (cp < cl) {
486                 forward(1,curline, sizeof(curline));
487             }
488             while (cp > cl) {
489                 backup(1);
490             }
491             break;
492         case F_TINS:                  /* toggle insert mode */
493             mode_insert = !mode_insert;  /* flip bit */
494             break;
495         default:
496             if (c > 255) {            /* function key hit */
497                 if (cl==0) {          /* if first character then */
498                     *string = EOS;         /* terminate string */
499                     return c;              /* return it */
500                 }
501                 t_honk_horn();        /* complain */
502             } else {
503                 if (mode_insert) {
504                     insert_space(curline, sizeof(curline));
505                 }
506                 curline[cp++] = c;    /* store character in line being built */
507                 t_char((char)c);      /* echo character to terminal */
508                 if (cp > cl) {
509                     cl = cp;          /* keep current length */
510                 }
511             }
512             break;
513         }                             /* end switch */
514     }
515 /* If we fall through here rather than goto done, the line is too long
516    simply return what we have now. */
517 done:
518     curline[cl++] = EOS;              /* terminate */
519     bstrncpy(string,curline,length);           /* return line to caller */
520     /* Note, put line zaps curline */
521     putline(curline,cl);              /* save line for posterity */
522     return 0;                         /* give it to him/her */
523 }
524
525 /* Insert a space at the current cursor position */
526 static void
527 /*FCN*/insert_space(char *curline, int curline_len)
528 {
529     int i;
530
531     if (cp > cl || cl+1 > curline_len) return;
532     /* Note! source and destination overlap */
533     memmove(&curline[cp+1],&curline[cp],i=cl-cp);
534     cl++;
535     i++;
536     curline[cp] = ' ';
537     forward(i,curline, curline_len);
538     backup(i);
539 }
540
541
542 /* Move cursor forward keeping characters under it */
543 static void
544 /*FCN*/forward(int i,char *str, int str_len)
545 {
546     while (i--) {
547         if (cp > str_len) {
548            return;
549         }
550         if (cp>=cl) {
551             t_char(' ');
552             str[cp+1] = ' ';
553         } else {
554             t_char(str[cp]);
555         }
556         cp++;
557     }
558 }
559
560 /* Backup cursor keeping characters under it */
561 static void
562 /*FCN*/backup(int i)
563 {
564     for ( ;i && cp; i--,cp--)
565         t_char('\010');
566 }
567
568 /* Delete the character under the cursor */
569 static void
570 /*FCN*/delchr(int cnt, char *curline, int line_len) 
571 {
572     register int i;
573
574     if (cp > cl)
575         return;
576     if ((i=cl-cp-cnt+1) > 0) {
577         memcpy(&curline[cp],&curline[cp+cnt],i);
578     }
579     curline[cl -= cnt] = EOS;
580     t_clrline(0,t_width);
581     if (cl > cp) {
582         forward(i=cl-cp,curline, line_len);
583         backup(i);
584     }
585 }
586
587 /* Determine if character is part of a word */
588 static int
589 /*FCN*/iswordc(char c)
590 {
591    if (mode_wspace)
592       return !isspace(c);
593    if (c >= '0' && c <= '9')
594       return TRUE;
595    if (c == '$' || c == '%')
596       return TRUE;
597    return isalpha(c);
598 }
599
600 /* Return number of characters to get to next word */
601 static int
602 /*FCN*/next_word(char *ldb_buf)
603 {
604     int ncp;
605
606     if (cp > cl)
607         return 0;
608     ncp = cp;
609     for ( ; ncp<cl && iswordc(*(ldb_buf+ncp)); ncp++) ;
610     for ( ; ncp<cl && !iswordc(*(ldb_buf+ncp)); ncp++) ;
611     return ncp-cp;
612 }
613
614 /* Return number of characters to get to previous word */
615 static int
616 /*FCN*/prev_word(char *ldb_buf)
617 {
618     int ncp, i;
619
620     if (cp == 0)                      /* if at begin of line stop now */
621         return 0;
622     if (cp > cl)                      /* if past eol start at eol */
623         ncp=cl+1;
624     else
625         ncp = cp;
626     /* backup to end of previous word - i.e. skip special chars */
627     for (i=ncp-1; i && !iswordc(*(ldb_buf+i)); i--) ;
628     if (i == 0) {                     /* at beginning of line? */
629         return cp;                    /* backup to beginning */
630     }
631     /* now move back through word to beginning of word */
632     for ( ; i && iswordc(*(ldb_buf+i)); i--) ;
633     ncp = i+1;                        /* position to first char of word */
634     if (i==0 && iswordc(*ldb_buf))    /* check for beginning of line */
635         ncp = 0;
636     return cp-ncp;                    /* return count */
637 }
638
639 /* Display new current line */
640 static void
641 /*FCN*/prtcur(char *str)
642 {
643     backup(cp);
644     t_clrline(0,t_width);
645     cp = cl = strlen(str);
646     t_sendl(str,cl);
647 }
648
649
650 /* Initialize line pool. Split pool into two pieces. */
651 static void
652 /*FCN*/poolinit()
653 {
654     slptr = lptr = (struct lstr *)pool;
655     lptr->nextl = lptr;
656     lptr->prevl = lptr;
657     lptr->used = 1;
658     lptr->line = 0;
659     lptr->len = POOLEN;
660 }
661
662
663 /* Return pointer to next line in the pool and advance current line pointer */
664 static char *
665 /*FCN*/getnext()
666 {
667     do {                              /* find next used line */
668         lptr = lptr->nextl;
669     } while (!lptr->used);
670     return (char *)&lptr->line;
671 }
672
673 /* Return pointer to previous line in the pool */
674 static char *
675 /*FCN*/getprev()
676 {
677     do {                              /* find previous used line */
678         lptr = lptr->prevl;
679     } while (!lptr->used);
680     return (char *)&lptr->line;
681 }
682
683 static void
684 /*FCN*/putline(char *newl, int newlen)
685 {
686     struct lstr *nptr;                /* points to next line */
687     char *p;
688
689     lptr = slptr;                     /* get ptr to last line stored */
690     lptr = lptr->nextl;               /* advance pointer */
691     if ((char *)lptr-pool+newlen+PHDRL > POOLEN) { /* not enough room */
692         lptr->used = 0;               /* delete line */
693         lptr = (struct lstr *)pool;   /* start at beginning of buffer */
694     }
695     while (lptr->len < newlen+PHDRL) { /* concatenate buffers */
696         nptr = lptr->nextl;           /* point to next line */
697         lptr->nextl = nptr->nextl;    /* unlink it from list */
698         nptr->nextl->prevl = lptr;
699         lptr->len += nptr->len;
700     }
701     if (lptr->len > newlen + 2 * PHDRL) { /* split buffer */
702         nptr = (struct lstr *)((char *)lptr + newlen + PHDRL);
703         /* Appropriate byte alignment - normally 2 byte, but on
704            sparc we need 4 byte alignment, so we always do 4 */
705         if (((unsigned)nptr & 3) != 0) { /* test four byte alignment */
706             p = (char *)nptr;
707             nptr = (struct lstr *)((((unsigned) p) & ~3) + 4);
708         }
709         nptr->len = lptr->len - ((char *)nptr - (char *)lptr);
710         lptr->len -= nptr->len;
711         nptr->nextl = lptr->nextl;    /* link in new buffer */
712         lptr->nextl->prevl = nptr;
713         lptr->nextl = nptr;
714         nptr->prevl = lptr;
715         nptr->used = 0;
716     }
717     memcpy(&lptr->line,newl,newlen);
718     lptr->used = 1;                   /* mark line used */
719     slptr = lptr;                     /* save as stored line */
720 }
721
722 #ifdef  DEBUGOUT
723 static void
724 /*FCN*/dump(struct lstr *ptr, char *msg)
725 {
726     printf("%s buf=%x nextl=%x prevl=%x len=%d used=%d\n",
727         msg,ptr,ptr->nextl,ptr->prevl,ptr->len,ptr->used);
728     if (ptr->used)
729         printf("line=%s\n",&ptr->line);
730 }
731 #endif  /* DEBUGOUT */
732
733
734 /* Honk horn on terminal */
735 static void
736 /*FCN*/t_honk_horn()
737 {
738     t_send(t_honk);
739 }
740
741 /* Insert line on terminal */
742 static void
743 /*FCN*/t_insert_line()
744 {
745     asinsl();
746 }
747
748 /* Delete line from terminal */
749 static void
750 /*FCN*/t_delete_line()
751 {
752     asdell();
753 }
754
755 /* clear line from pos to width */
756 static void
757 /*FCN*/t_clrline(int pos, int width)
758 {
759     asclrl(pos, width);           /* clear to end of line */
760 }
761
762 /* Helper function to add string preceded by 
763  *  ESC to smap table */
764 static void add_esc_smap(char *str, int func)
765 {
766    char buf[100];
767    buf[0] = 0x1B;                     /* esc */
768    bstrncpy(buf+1, str, sizeof(buf)-1);
769    add_smap(buf, func);
770 }
771
772 /* Set raw mode on terminal file.  Basically, get the terminal into a
773    mode in which all characters can be read as they are entered.  CBREAK
774    mode is not sufficient.
775  */
776 /*FCN*/static void rawmode(FILE *input)
777 {
778    struct termios t;
779    static char term_buf[2048];
780    static char *term_buffer = term_buf;
781    char *termtype = (char *)getenv("TERM");
782
783    /* Make sure we are dealing with a terminal */
784    if (!isatty(fileno(input))) {
785       return;
786    }
787    if (tcgetattr(0, &old_term_params) != 0) {
788       printf(_("conio: Cannot tcgetattr()\n"));
789       exit(1);
790    }
791    old_term_params_set = true;
792    t = old_term_params;                         
793    t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
794    t.c_cc[VTIME] = 0;
795    t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | 
796                   ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);     
797    t.c_iflag |= IGNBRK | ISIG;
798 // t.c_oflag &= ~(OPOST);    /* no output processing */       
799    t.c_oflag |= ONLCR;
800    t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON |
801                   NOFLSH | TOSTOP);
802    tcflush(0, TCIFLUSH);
803    if (tcsetattr(0, TCSANOW, &t) == -1) {
804       printf("Cannot tcsetattr()\n");
805    }
806
807 // signal(SIGQUIT, SIG_IGN);
808 // signal(SIGHUP, SIG_IGN);
809 // signal(SIGSTOP, SIG_IGN);
810    signal(SIGINT, sigintcatcher);
811 // signal(SIGWINCH, SIG_IGN);   
812 // signal(SIGQUIT, SIG_IGN);
813 // signal(SIGCHLD, SIG_IGN);
814 // signal(SIGTSTP, SIG_IGN);
815
816    if (!termtype) {
817       printf("Cannot get terminal type.\n");
818       exit(1);
819    }
820    if (tgetent(term_buffer, termtype) < 0) {
821       printf("Cannot get terminal termcap entry.\n");
822       exit(1);
823    }
824    t_width = t_height = -1;
825    t_width = tgetnum("co") - 1;
826    t_height = tgetnum("li");
827    BC = NULL;
828    UP = NULL;
829    t_cm = (char *)tgetstr("cm", &term_buffer);
830    t_cs = (char *)tgetstr("cl", &term_buffer); /* clear screen */
831    t_cl = (char *)tgetstr("ce", &term_buffer); /* clear line */
832    t_dl = (char *)tgetstr("dl", &term_buffer); /* delete line */
833    t_il = (char *)tgetstr("al", &term_buffer); /* insert line */
834    t_honk = (char *)tgetstr("bl", &term_buffer); /* beep */
835    t_ti = (char *)tgetstr("ti", &term_buffer);
836    t_te = (char *)tgetstr("te", &term_buffer);
837    t_up = (char *)tgetstr("up", &term_buffer);
838    t_do = (char *)tgetstr("do", &term_buffer);
839    t_sf = (char *)tgetstr("sf", &term_buffer);
840
841    num_stab = MAX_STAB;                  /* get default stab size */
842    stab = (stab_t **)malloc(sizeof(stab_t *) * num_stab);
843    memset(stab, 0, sizeof(stab_t *) * num_stab);
844
845    /* Key bindings */
846    kl = (char *)tgetstr("kl", &term_buffer);
847    kr = (char *)tgetstr("kr", &term_buffer);
848    ku = (char *)tgetstr("ku", &term_buffer);
849    kd = (char *)tgetstr("kd", &term_buffer);
850    kh = (char *)tgetstr("kh", &term_buffer);
851    kb = (char *)tgetstr("kb", &term_buffer);
852    kD = (char *)tgetstr("kD", &term_buffer);
853    kI = (char *)tgetstr("kI", &term_buffer);
854    kN = (char *)tgetstr("kN", &term_buffer);
855    kP = (char *)tgetstr("kP", &term_buffer);
856    kH = (char *)tgetstr("kH", &term_buffer);
857    kE = (char *)tgetstr("kE", &term_buffer);
858
859    add_smap(kl, F_CSRLFT);
860    add_smap(kr, F_CSRRGT);
861    add_smap(ku, F_CSRUP);
862    add_smap(kd, F_CSRDWN);
863    add_smap(kI, F_TINS);
864    add_smap(kN, F_PAGDWN);
865    add_smap(kP, F_PAGUP);
866    add_smap(kH, F_HOME);
867    add_smap(kE, F_EOF);
868
869
870    add_esc_smap("[A",   F_CSRUP);
871    add_esc_smap("[B",   F_CSRDWN);
872    add_esc_smap("[C",   F_CSRRGT);
873    add_esc_smap("[D",   F_CSRLFT);
874    add_esc_smap("[1~",  F_HOME);
875    add_esc_smap("[2~",  F_TINS);
876    add_esc_smap("[3~",  F_DELCHR);
877    add_esc_smap("[4~",  F_EOF);
878    add_esc_smap("f",    F_NXTWRD);
879    add_esc_smap("b",    F_PRVWRD);
880
881
882 #ifdef needed
883    for (i=301; i<600; i++) {
884       char_map[i] = i;                /* setup IBM function codes */
885    }
886 #endif
887 }
888
889
890 /* Restore tty mode */
891 /*FCN*/static void normode()
892 {
893    if (old_term_params_set) {
894       tcsetattr(0, TCSANOW, &old_term_params);
895    }
896 }
897
898 /* Get next character from terminal/script file/unget buffer */
899 static int
900 /*FCN*/t_gnc()
901 {
902     int ch;
903
904     while ((ch=t_getch()) == 0) ;     /* get next input character */
905     return(ch);
906 }
907
908
909 /* Get next character from OS */
910 static int t_getch(void)
911 {
912    char c;
913
914    if (read(0, &c, 1) != 1) {
915       c = 0;
916    }
917    return (int)c;   
918 }
919     
920 #ifdef xxx
921
922 /* window_size -- Return window height and width to caller. */
923 static int window_size(int *height, int *width)         /* /window_size/ */
924 {
925    *width = tgetnum("co") - 1;
926    *height = tgetnum("li");
927    return 1;
928 }
929 #endif
930
931 /* Send message to terminal - primitive routine */
932 void
933 /*FCN*/t_sendl(char *msg,int len)
934 {
935     write(1, msg, len);
936 }
937
938 void
939 /*FCN*/t_send(char *msg)
940 {
941     if (msg == NULL) {
942        return;
943     }
944     t_sendl(msg, strlen(msg));    /* faster than one char at time */
945 }
946
947 /* Send single character to terminal - primitive routine - */
948 void
949 /*FCN*/t_char(char c)
950 {
951    write(1, &c, 1);
952 }
953
954
955 static int brkflg = 0;              /* set on user break */
956
957 /* Routine to return true if user types break */
958 /*FCN*/int usrbrk()
959 {
960    return brkflg;
961 }
962
963 /* Clear break flag */
964 void clrbrk()
965 {
966    brkflg = 0;
967
968 }
969
970 /* Interrupt caught here */
971 static void sigintcatcher(int sig)
972 {
973    brkflg = 1;
974    signal(SIGINT, sigintcatcher);
975 }
976
977
978 /* Trap Ctl-C */
979 /*FCN*/void trapctlc()
980 {
981    signal(SIGINT, sigintcatcher);
982 }
983
984
985 /* ASCLRL() -- Clear to end of line from current position */
986 static void asclrl(int pos, int width) 
987 {
988     int i;
989
990     if (t_cl) {
991         t_send(t_cl);                 /* use clear to eol function */
992         return;
993     }
994     if (pos==1 && linsdel_ok) {
995         t_delete_line();              /* delete line */
996         t_insert_line();              /* reinsert it */
997         return;
998     }
999     for (i=1; i<=width-pos+1; i++)
1000         t_char(' ');                  /* last resort, blank it out */
1001     for (i=1; i<=width-pos+1; i++)    /* backspace to original position */
1002         t_char(0x8);
1003     return;
1004   
1005 }
1006
1007
1008 /* ASCURS -- Set cursor position */
1009 static void ascurs(int y, int x)
1010 {
1011    t_send((char *)tgoto(t_cm, x, y));
1012 }
1013                                                                                         
1014
1015 /* ASCLRS -- Clear whole screen */
1016 static void asclrs() 
1017 {
1018    ascurs(0,0);
1019    t_send(t_cs);
1020 }
1021
1022
1023
1024 /* ASINSL -- insert new line after cursor */
1025 static void asinsl()
1026 {
1027    t_clrline(0, t_width);
1028    t_send(t_il);                      /* insert before */
1029 }
1030
1031 /* ASDELL -- Delete line at cursor */
1032 static void asdell()
1033 {
1034    t_send(t_dl);
1035 }
1036
1037 #endif