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