2 Generalized console input/output handler
3 A maintanable replacement for readline()
5 Updated for Bacula, Kern Sibbald, December MMIII
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.
12 Bacula® - The Network Backup Solution
14 Copyright (C) 1981-2006 Free Software Foundation Europe e.V.
15 Yes, that is 1981 no error.
17 The main author of Bacula is Kern Sibbald, with contributions from
18 many others, a complete list can be found in the file AUTHORS.
19 This program is Free Software; you can redistribute it and/or
20 modify it under the terms of version two of the GNU General Public
21 License as published by the Free Software Foundation and included
24 This program is distributed in the hope that it will be useful, but
25 WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
34 Bacula® is a registered trademark of John Walker.
35 The licensor of Bacula is the Free Software Foundation Europe
36 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
37 Switzerland, email:ftf@fsfeurope.org.
42 * If the top bit of a UTF-8 string is 0 (8 bits), then it
43 * is a normal ASCII character.
44 * If the top two bits are 11 (i.e. (c & 0xC0) == 0xC0 then
45 * it is the start of a series of chars (up to 5)
46 * Each subsequent character starts with 10 (i.e. (c & 0xC0) == 0x80)
59 /* We are in Bacula */
66 extern "C" int tgetent(void *, const char *);
67 extern "C" int tgetnum(const char *);
68 extern "C" char *tgetstr (const char*, char**);
69 extern "C" char *tgoto (const char *, int, int);
75 #elif defined (__digital__) && defined (__unix__)
76 extern "C" int tgetent(void *, const char *);
77 extern "C" int tgetnum(const char *);
78 extern "C" char *tgetstr (const char*, char**);
79 extern "C" char *tgoto (const char *, int, int);
87 /* From termios library */
88 #if defined(HAVE_HPUX_OS) || defined(HAVE_AIX_OS)
96 /* Forward referenced functions */
98 static void sigintcatcher(int);
101 static void add_smap(char *str, int func);
104 /* Global variables */
106 static const char *t_up = "\n"; /* scroll up character */
107 static const char *t_honk = "\007"; /* sound beep */
108 static char *t_il; /* insert line */
109 static char *t_dl; /* delete line */
110 static char *t_cs; /* clear screen */
111 static char *t_cl; /* clear line */
112 static int t_width = 79; /* terminal width */
113 static int t_height = 24; /* terminal height */
114 static int linsdel_ok = 0; /* set if term has line insert & delete fncs */
116 static char *t_cm; /* cursor positioning */
117 static char *t_ti; /* init sequence */
118 static char *t_te; /* end sequence */
119 static char *t_do; /* down one line */
120 static char *t_sf; /* scroll screen one line up */
122 /* Keypad and Function Keys */
123 static char *kl; /* left key */
124 static char *kr; /* right */
125 static char *ku; /* up */
126 static char *kd; /* down */
127 static char *kh; /* home */
128 static char *kb; /* backspace */
129 static char *kD; /* delete key */
130 static char *kI; /* insert */
131 static char *kN; /* next page */
132 static char *kP; /* previous page */
133 static char *kH; /* home */
134 static char *kE; /* end */
137 #define EOS '\0' /* end of string terminator */
143 * Stab entry. Input chars (str), the length, and the desired
146 typedef struct s_stab {
155 static stab_t **stab = NULL; /* array of stabs by length */
156 static int num_stab; /* size of stab array */
158 static bool old_term_params_set = false;
159 static struct termios old_term_params;
161 /* Maintain lines in a doubly linked circular pool of lines. Each line is
162 preceded by a header defined by the lstr structure */
165 struct lstr { /* line pool structure */
166 struct lstr *prevl; /* link to previous line */
167 struct lstr *nextl; /* link to next line */
168 long len; /* length of line+header */
169 char used; /* set if line valid */
170 char line; /* line is actually varying length */
174 #define POOLEN 128000 /* bytes in line pool */
176 #define POOLEN 500 /* bytes in line pool */
178 char pool[POOLEN]; /* line pool */
179 #define PHDRL ((int)sizeof(struct lstr)) /* length of line header */
181 static struct lstr *lptr; /* current line pointer */
182 static struct lstr *slptr; /* store line pointer */
184 static char *getnext(), *getprev();
185 static int first = 1;
186 static int mode_insert = 0;
187 static int mode_wspace = 1; /* words separated by spaces */
190 static short char_map[600]= {
191 0, F_SOL, /* ^a Line start */
192 F_PRVWRD, /* ^b Previous word */ F_BREAK, /* ^C break */
193 F_DELCHR, /* ^D Delete character */ F_EOL, /* ^e End of line */
194 F_CSRRGT, /* ^f Right */ F_TABBAK, /* ^G Back tab */
195 F_CSRLFT, /* ^H Left */ F_TAB, /* ^I Tab */
196 F_CSRDWN, /* ^J Down */ F_DELEOL, /* ^K kill to eol */
197 F_CLRSCRN,/* ^L clear screen */ F_RETURN, /* ^M Carriage return */
198 F_RETURN, /* ^N enter line */ F_CONCAT, /* ^O Concatenate lines */
199 F_CSRUP, /* ^P cursor up */ F_TINS, /* ^Q Insert character mode */
200 F_PAGUP, /* ^R Page up */ F_CENTER, /* ^S Center text */
201 F_PAGDWN, /* ^T Page down */ F_DELSOL, /* ^U delete to start of line */
202 F_DELWRD, /* ^V Delete word */ F_PRVWRD, /* ^W Previous word */
203 F_NXTMCH, /* ^X Next match */ F_DELEOL, /* ^Y Delete to end of line */
204 F_BACKGND,/* ^Z Background */ 0x1B, /* ^[=ESC escape */
205 F_TENTRY, /* ^\ Entry mode */ F_PASTECB,/* ^]=paste clipboard */
206 F_HOME, /* ^^ Home */ F_ERSLIN, /* ^_ Erase line */
208 ' ','!','"','#','$','%','&','\047',
209 '(',')','*','+','\054','-','.','/',
210 '0','1','2','3','4','5','6','7',
211 '8','9',':',';','<','=','>','?',
212 '@','A','B','C','D','E','F','G',
213 'H','I','J','K','L','M','N','O',
214 'P','Q','R','S','T','U','V','W',
215 'X','Y','Z','[','\\',']','^','_',
216 '\140','a','b','c','d','e','f','g',
217 'h','i','j','k','l','m','n','o',
218 'p','q','r','s','t','u','v','w',
219 'x','y','z','{','|','}','\176',F_ERSCHR /* erase character */
224 /* Local variables */
226 #define CR '\r' /* carriage return */
229 /* Function Prototypes */
231 static unsigned int input_char(void);
232 static unsigned int t_gnc(void);
233 static void insert_space(char *curline, int line_len);
234 static void insert_hole(char *curline, int line_len);
235 static void forward(char *str, int str_len);
236 static void backup(char *curline);
237 static void delchr(int cnt, char *curline, int line_len);
238 static int iswordc(char c);
239 static int next_word(char *ldb_buf);
240 static int prev_word(char *ldb_buf);
241 static void prtcur(char *str);
242 static void poolinit(void);
243 static char * getnext(void);
244 static char * getprev(void);
245 static void putline(char *newl, int newlen);
246 static void t_honk_horn(void);
247 static void t_insert_line(void);
248 static void t_delete_line(void);
249 static void t_clrline(int pos, int width);
250 void t_sendl(const char *msg, int len);
251 void t_send(const char *msg);
253 static void asclrs();
254 static void ascurs(int y, int x);
256 static void rawmode(FILE *input);
257 static void normode(void);
258 static unsigned t_getch();
259 static void asclrl(int pos, int width);
260 static void asinsl();
261 static void asdell();
263 int input_line(char *string, int length);
271 void con_init(FILE *input)
281 void con_set_zed_keys(void)
283 char_map[1] = F_NXTWRD; /* ^A Next Word */
284 char_map[2] = F_SPLIT; /* ^B Split line */
285 char_map[3] = F_EOI; /* ^C Quit */
286 char_map[4] = F_DELCHR; /* ^D Delete character */
287 char_map[5] = F_EOF; /* ^E End of file */
288 char_map[6] = F_INSCHR; /* ^F Insert character */
289 char_map[7] = F_TABBAK; /* ^G Back tab */
290 char_map[8] = F_CSRLFT; /* ^H Left */
291 char_map[9] = F_TAB; /* ^I Tab */
292 char_map[10] = F_CSRDWN; /* ^J Down */
293 char_map[11] = F_CSRUP; /* ^K Up */
294 char_map[12] = F_CSRRGT; /* ^L Right */
295 char_map[13] = F_RETURN; /* ^M Carriage return */
296 char_map[14] = F_EOL; /* ^N End of line */
297 char_map[15] = F_CONCAT; /* ^O Concatenate lines */
298 char_map[16] = F_MARK; /* ^P Set marker */
299 char_map[17] = F_TINS; /* ^Q Insert character mode */
300 char_map[18] = F_PAGUP; /* ^R Page up */
301 char_map[19] = F_CENTER; /* ^S Center text */
302 char_map[20] = F_PAGDWN; /* ^T Page down */
303 char_map[21] = F_SOL; /* ^U Line start */
304 char_map[22] = F_DELWRD; /* ^V Delete word */
305 char_map[23] = F_PRVWRD; /* ^W Previous word */
306 char_map[24] = F_NXTMCH; /* ^X Next match */
307 char_map[25] = F_DELEOL; /* ^Y Delete to end of line */
308 char_map[26] = F_DELLIN; /* ^Z Delete line */
310 char_map[28] = F_TENTRY; /* ^\ Entry mode */
311 char_map[29] = F_PASTECB;/* ^]=paste clipboard */
312 char_map[30] = F_HOME; /* ^^ Home */
313 char_map[31] = F_ERSLIN; /* ^_ Erase line */
324 * Guarantee that the string is properly terminated */
325 char *bstrncpy(char *dest, const char *src, int maxlen)
327 strncpy(dest, src, maxlen-1);
335 * New style string mapping to function code
337 static unsigned do_smap(unsigned c)
357 for (i=len-1; i<MAX_STAB; i++) {
358 for (tstab=stab[i]; tstab; tstab=tstab->next) {
359 if (strncmp(str, tstab->str, len) == 0) {
360 if (len == tstab->len) {
364 break; /* found possibility continue searching */
371 /* found partial match, so get next character and retry */
372 str[len++] = t_gnc();
378 static void dump_stab()
384 for (i=0; i<MAX_STAB; i++) {
385 for (tstab=stab[i]; tstab; tstab=tstab->next) {
386 for (j=0; j<tstab->len; j++) {
388 if (c < 0x20 || c > 0x7F) {
389 sprintf(buf, " 0x%x ", c);
397 sprintf(buf, " func=%d len=%d\n\r", tstab->func, tstab->len);
405 * New routine. Add string to string->func mapping table.
407 static void add_smap(char *str, int func)
417 /* errmsg("String for func %d is zero length\n", func); */
420 tstab = (stab_t *)malloc(sizeof(stab_t));
421 memset(tstab, 0, sizeof(stab_t));
423 tstab->str = (char *)malloc(tstab->len + 1);
424 bstrncpy(tstab->str, str, tstab->len + 1);
426 if (tstab->len > num_stab) {
427 printf("stab string too long %d. Max is %d\n", tstab->len, num_stab);
430 tstab->next = stab[tstab->len-1];
431 stab[tstab->len-1] = tstab;
432 /* printf("Add_smap tstab=%x len=%d func=%d tstab->next=%x\n\r", tstab, len,
433 func, tstab->next); */
438 /* Get the next character from the terminal - performs table lookup on
439 the character to do the desired translation */
445 if ((c=t_gnc()) <= 599) { /* IBM generates codes up to 260 */
447 } else if (c > 1000) { /* stuffed function */
448 c -= 1000; /* convert back to function code */
453 /* if we got a screen size escape sequence, read height, width */
456 y = t_gnc() - 0x20; /* y */
457 x = t_gnc() - 0x20; /* x */
464 /* Get a complete input line */
467 input_line(char *string, int length)
469 char curline[2000]; /* edit buffer */
476 poolinit(); /* build line pool */
479 noline = 1; /* no line fetched yet */
480 for (cl=cp=0; cl<length && cl<(int)sizeof(curline); ) {
485 switch (c=input_char()) {
486 case F_RETURN: /* CR */
487 t_sendl("\r\n", 2); /* yes, print it and */
488 goto done; /* get out */
489 case F_CLRSCRN: /* clear screen */
491 t_sendl(curline, cl);
495 if (noline) { /* no line fetched yet */
496 getnext(); /* getnext so getprev gets current */
497 noline = 0; /* we now have line */
499 bstrncpy(curline, getprev(), sizeof(curline));
503 noline = 0; /* mark line fetched */
504 bstrncpy(curline, getnext(), sizeof(curline));
508 insert_space(curline, sizeof(curline));
511 delchr(1, curline, sizeof(curline)); /* delete one character */
513 case F_CSRLFT: /* Backspace */
517 forward(curline, sizeof(curline));
519 case F_ERSCHR: /* Rubout */
521 delchr(1, curline, sizeof(curline));
528 t_clrline(0, t_width);
533 i = next_word(curline);
535 forward(curline, sizeof(curline));
539 i = prev_word(curline);
545 delchr(next_word(curline), curline, sizeof(curline)); /* delete word */
547 case F_NXTMCH: /* Ctl-X */
549 *string = EOS; /* terminate string */
550 return(c); /* give it to him */
552 /* Note fall through */
556 backup(curline); /* backup to beginning of line */
558 t_clrline(0, t_width); /* erase line */
560 cl = 0; /* reset cursor counter */
571 forward(curline, sizeof(curline));
577 case F_TINS: /* toggle insert mode */
578 mode_insert = !mode_insert; /* flip bit */
581 if (c > 255) { /* function key hit */
582 if (cl==0) { /* if first character then */
583 *string = EOS; /* terminate string */
584 return c; /* return it */
586 t_honk_horn(); /* complain */
588 if ((c & 0xC0) == 0xC0) {
589 if ((c & 0xFC) == 0xFC) {
591 } else if ((c & 0xF8) == 0xF8) {
593 } else if ((c & 0xF0) == 0xF0) {
595 } else if ((c & 0xE0) == 0xE0) {
604 insert_space(curline, sizeof(curline));
606 curline[cp++] = c; /* store character in line being built */
607 t_char(c); /* echo character to terminal */
610 insert_hole(curline, sizeof(curline));
611 curline[cp++] = c; /* store character in line being built */
612 t_char(c); /* echo character to terminal */
615 cl = cp; /* keep current length */
622 /* If we fall through here rather than goto done, the line is too long
623 simply return what we have now. */
625 curline[cl++] = EOS; /* terminate */
626 bstrncpy(string,curline,length); /* return line to caller */
627 /* Note, put line zaps curline */
628 putline(curline,cl); /* save line for posterity */
629 return 0; /* give it to him/her */
632 /* Insert a space at the current cursor position */
634 insert_space(char *curline, int curline_len)
638 if (cp > cl || cl+1 > curline_len) {
641 /* Note! source and destination overlap */
642 memmove(&curline[cp+1],&curline[cp],i=cl-cp);
647 forward(curline, curline_len);
657 insert_hole(char *curline, int curline_len)
661 if (cp > cl || cl+1 > curline_len) {
664 /* Note! source and destination overlap */
665 memmove(&curline[cp+1], &curline[cp], i=cl-cp);
671 /* Move cursor forward keeping characters under it */
673 forward(char *str, int str_len)
684 if ((str[cp] & 0xC0) == 0xC0) {
686 while ((str[cp] & 0xC0) == 0x80) {
696 /* How many characters under the cursor */
698 char_count(int cptr, char *str)
704 if ((str[cptr] & 0xC0) == 0xC0) {
706 while ((str[cptr] & 0xC0) == 0x80) {
714 /* Backup cursor keeping characters under it */
721 while ((str[cp] & 0xC0) == 0x80) {
728 /* Delete the character under the cursor */
730 delchr(int del, char *curline, int line_len)
734 if (cp > cl || del == 0) {
737 while (del-- && cp > 0) {
738 cnt = char_count(cp, curline);
739 if ((i=cl-cp-cnt) > 0) {
740 memcpy(&curline[cp], &curline[cp+cnt], i);
744 t_clrline(0, t_width);
747 forward(curline, line_len);
756 /* Determine if character is part of a word */
762 if (c >= '0' && c <= '9')
764 if (c == '$' || c == '%')
769 /* Return number of characters to get to next word */
771 next_word(char *ldb_buf)
778 for ( ; ncp<cl && iswordc(*(ldb_buf+ncp)); ncp++) ;
779 for ( ; ncp<cl && !iswordc(*(ldb_buf+ncp)); ncp++) ;
783 /* Return number of characters to get to previous word */
785 prev_word(char *ldb_buf)
789 if (cp == 0) /* if at begin of line stop now */
791 if (cp > cl) /* if past eol start at eol */
795 /* backup to end of previous word - i.e. skip special chars */
796 for (i=ncp-1; i && !iswordc(*(ldb_buf+i)); i--) ;
797 if (i == 0) { /* at beginning of line? */
798 return cp; /* backup to beginning */
800 /* now move back through word to beginning of word */
801 for ( ; i && iswordc(*(ldb_buf+i)); i--) ;
802 ncp = i+1; /* position to first char of word */
803 if (i==0 && iswordc(*ldb_buf)) /* check for beginning of line */
805 return cp-ncp; /* return count */
808 /* Display new current line */
815 t_clrline(0,t_width);
816 cp = cl = strlen(str);
821 /* Initialize line pool. Split pool into two pieces. */
825 slptr = lptr = (struct lstr *)pool;
834 /* Return pointer to next line in the pool and advance current line pointer */
838 do { /* find next used line */
840 } while (!lptr->used);
841 return (char *)&lptr->line;
844 /* Return pointer to previous line in the pool */
848 do { /* find previous used line */
850 } while (!lptr->used);
851 return (char *)&lptr->line;
855 putline(char *newl, int newlen)
857 struct lstr *nptr; /* points to next line */
860 lptr = slptr; /* get ptr to last line stored */
861 lptr = lptr->nextl; /* advance pointer */
862 if ((char *)lptr-pool+newlen+PHDRL > POOLEN) { /* not enough room */
863 lptr->used = 0; /* delete line */
864 lptr = (struct lstr *)pool; /* start at beginning of buffer */
866 while (lptr->len < newlen+PHDRL) { /* concatenate buffers */
867 nptr = lptr->nextl; /* point to next line */
868 lptr->nextl = nptr->nextl; /* unlink it from list */
869 nptr->nextl->prevl = lptr;
870 lptr->len += nptr->len;
872 if (lptr->len > newlen + 2 * PHDRL) { /* split buffer */
873 nptr = (struct lstr *)((char *)lptr + newlen + PHDRL);
874 /* Appropriate byte alignment - normally 2 byte, but on
875 sparc we need 4 byte alignment, so we always do 4 */
876 if (((long unsigned)nptr & 3) != 0) { /* test four byte alignment */
878 nptr = (struct lstr *)((((long unsigned) p) & ~3) + 4);
880 nptr->len = lptr->len - ((char *)nptr - (char *)lptr);
881 lptr->len -= nptr->len;
882 nptr->nextl = lptr->nextl; /* link in new buffer */
883 lptr->nextl->prevl = nptr;
888 memcpy(&lptr->line,newl,newlen);
889 lptr->used = 1; /* mark line used */
890 slptr = lptr; /* save as stored line */
895 dump(struct lstr *ptr, char *msg)
897 printf("%s buf=%x nextl=%x prevl=%x len=%d used=%d\n",
898 msg,ptr,ptr->nextl,ptr->prevl,ptr->len,ptr->used);
900 printf("line=%s\n",&ptr->line);
902 #endif /* DEBUGOUT */
905 /* Honk horn on terminal */
912 /* Insert line on terminal */
919 /* Delete line from terminal */
926 /* clear line from pos to width */
928 t_clrline(int pos, int width)
930 asclrl(pos, width); /* clear to end of line */
933 /* Helper function to add string preceded by
934 * ESC to smap table */
935 static void add_esc_smap(const char *str, int func)
938 buf[0] = 0x1B; /* esc */
939 bstrncpy(buf+1, str, sizeof(buf)-1);
943 /* Set raw mode on terminal file. Basically, get the terminal into a
944 mode in which all characters can be read as they are entered. CBREAK
945 mode is not sufficient.
947 static void rawmode(FILE *input)
950 static char term_buf[2048];
951 static char *term_buffer = term_buf;
952 char *termtype = (char *)getenv("TERM");
954 /* Make sure we are dealing with a terminal */
955 if (!isatty(fileno(input))) {
958 if (tcgetattr(0, &old_term_params) != 0) {
959 printf("conio: Cannot tcgetattr()\n");
962 old_term_params_set = true;
964 t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
966 t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK |
967 ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);
970 t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON |
972 tcflush(0, TCIFLUSH);
973 if (tcsetattr(0, TCSANOW, &t) == -1) {
974 printf("Cannot tcsetattr()\n");
977 /* Defaults, the main program can override these */
978 signal(SIGQUIT, SIG_IGN);
979 signal(SIGHUP, SIG_IGN);
980 signal(SIGINT, sigintcatcher);
981 signal(SIGWINCH, SIG_IGN);
984 printf("Cannot get terminal type.\n");
988 if (tgetent(term_buffer, termtype) < 0) {
989 printf("Cannot get terminal termcap entry.\n");
993 t_width = t_height = -1;
994 t_width = tgetnum("co") - 1;
995 t_height = tgetnum("li");
998 t_cm = (char *)tgetstr("cm", &term_buffer);
999 t_cs = (char *)tgetstr("cl", &term_buffer); /* clear screen */
1000 t_cl = (char *)tgetstr("ce", &term_buffer); /* clear line */
1001 t_dl = (char *)tgetstr("dl", &term_buffer); /* delete line */
1002 t_il = (char *)tgetstr("al", &term_buffer); /* insert line */
1003 t_honk = (char *)tgetstr("bl", &term_buffer); /* beep */
1004 t_ti = (char *)tgetstr("ti", &term_buffer);
1005 t_te = (char *)tgetstr("te", &term_buffer);
1006 t_up = (char *)tgetstr("up", &term_buffer);
1007 t_do = (char *)tgetstr("do", &term_buffer);
1008 t_sf = (char *)tgetstr("sf", &term_buffer);
1010 num_stab = MAX_STAB; /* get default stab size */
1011 stab = (stab_t **)malloc(sizeof(stab_t *) * num_stab);
1012 memset(stab, 0, sizeof(stab_t *) * num_stab);
1015 kl = (char *)tgetstr("kl", &term_buffer);
1016 kr = (char *)tgetstr("kr", &term_buffer);
1017 ku = (char *)tgetstr("ku", &term_buffer);
1018 kd = (char *)tgetstr("kd", &term_buffer);
1019 kh = (char *)tgetstr("kh", &term_buffer);
1020 kb = (char *)tgetstr("kb", &term_buffer);
1021 kD = (char *)tgetstr("kD", &term_buffer);
1022 kI = (char *)tgetstr("kI", &term_buffer);
1023 kN = (char *)tgetstr("kN", &term_buffer);
1024 kP = (char *)tgetstr("kP", &term_buffer);
1025 kH = (char *)tgetstr("kH", &term_buffer);
1026 kE = (char *)tgetstr("kE", &term_buffer);
1028 add_smap(kl, F_CSRLFT);
1029 add_smap(kr, F_CSRRGT);
1030 add_smap(ku, F_CSRUP);
1031 add_smap(kd, F_CSRDWN);
1032 add_smap(kI, F_TINS);
1033 add_smap(kN, F_PAGDWN);
1034 add_smap(kP, F_PAGUP);
1035 add_smap(kH, F_HOME);
1036 add_smap(kE, F_EOF);
1039 add_esc_smap("[A", F_CSRUP);
1040 add_esc_smap("[B", F_CSRDWN);
1041 add_esc_smap("[C", F_CSRRGT);
1042 add_esc_smap("[D", F_CSRLFT);
1043 add_esc_smap("[1~", F_HOME);
1044 add_esc_smap("[2~", F_TINS);
1045 add_esc_smap("[3~", F_DELCHR);
1046 add_esc_smap("[4~", F_EOF);
1047 add_esc_smap("f", F_NXTWRD);
1048 add_esc_smap("b", F_PRVWRD);
1052 /* Restore tty mode */
1053 static void normode()
1055 if (old_term_params_set) {
1056 tcsetattr(0, TCSANOW, &old_term_params);
1057 old_term_params_set = false;
1061 /* Get next character from terminal/script file/unget buffer */
1069 /* Get next character from OS */
1070 static unsigned t_getch(void)
1074 if (read(0, &c, 1) != 1) {
1080 /* Send message to terminal - primitive routine */
1082 t_sendl(const char *msg, int len)
1088 t_send(const char *msg)
1093 t_sendl(msg, strlen(msg)); /* faster than one char at time */
1096 /* Send single character to terminal - primitive routine - */
1100 (void)write(1, &c, 1);
1104 static int brkflg = 0; /* set on user break */
1106 /* Routine to return true if user types break */
1112 /* Clear break flag */
1119 /* Interrupt caught here */
1120 static void sigintcatcher(int sig)
1127 signal(SIGINT, sigintcatcher);
1134 signal(SIGINT, sigintcatcher);
1138 /* ASCLRL() -- Clear to end of line from current position */
1139 static void asclrl(int pos, int width)
1144 t_send(t_cl); /* use clear to eol function */
1147 if (pos==1 && linsdel_ok) {
1148 t_delete_line(); /* delete line */
1149 t_insert_line(); /* reinsert it */
1152 for (i=1; i<=width-pos+1; i++)
1153 t_char(' '); /* last resort, blank it out */
1154 for (i=1; i<=width-pos+1; i++) /* backspace to original position */
1161 /* ASCURS -- Set cursor position */
1162 static void ascurs(int y, int x)
1164 t_send((char *)tgoto(t_cm, x, y));
1168 /* ASCLRS -- Clear whole screen */
1169 static void asclrs()
1177 /* ASINSL -- insert new line after cursor */
1178 static void asinsl()
1180 t_clrline(0, t_width);
1181 t_send(t_il); /* insert before */
1184 /* ASDELL -- Delete line at cursor */
1185 static void asdell()