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