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