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