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 Kern Sibbald.
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);
76 extern "C" int tgetent(char *, char *);
77 extern "C" int tgetnum(char id[2]);
78 extern "C" char *tgetstr(char id[2], char **);
79 extern "C" char *tgoto(char *, int, int);
80 #elif defined (__digital__) && defined (__unix__)
81 extern "C" int tgetent(void *, const char *);
82 extern "C" int tgetnum(const char *);
83 extern "C" char *tgetstr (const char*, char**);
84 extern "C" char *tgoto (const char *, int, int);
92 /* From termios library */
93 #if defined(HAVE_HPUX_OS) || defined(HAVE_AIX_OS)
101 /* Forward referenced functions */
103 static void sigintcatcher(int);
106 static void add_smap(char *str, int func);
109 /* Global variables */
111 static const char *t_up = "\n"; /* scroll up character */
112 static const char *t_honk = "\007"; /* sound beep */
113 static char *t_il; /* insert line */
114 static char *t_dl; /* delete line */
115 static char *t_cs; /* clear screen */
116 static char *t_cl; /* clear line */
117 static int t_width = 79; /* terminal width */
118 static int t_height = 24; /* terminal height */
119 static int linsdel_ok = 0; /* set if term has line insert & delete fncs */
121 static char *t_cm; /* cursor positioning */
122 static char *t_ti; /* init sequence */
123 static char *t_te; /* end sequence */
124 static char *t_do; /* down one line */
125 static char *t_sf; /* scroll screen one line up */
127 /* Keypad and Function Keys */
128 static char *kl; /* left key */
129 static char *kr; /* right */
130 static char *ku; /* up */
131 static char *kd; /* down */
132 static char *kh; /* home */
133 static char *kb; /* backspace */
134 static char *kD; /* delete key */
135 static char *kI; /* insert */
136 static char *kN; /* next page */
137 static char *kP; /* previous page */
138 static char *kH; /* home */
139 static char *kE; /* end */
142 #define EOS '\0' /* end of string terminator */
148 * Stab entry. Input chars (str), the length, and the desired
151 typedef struct s_stab {
160 static stab_t **stab = NULL; /* array of stabs by length */
161 static int num_stab; /* size of stab array */
163 static bool old_term_params_set = false;
164 static struct termios old_term_params;
166 /* Maintain lines in a doubly linked circular pool of lines. Each line is
167 preceded by a header defined by the lstr structure */
170 struct lstr { /* line pool structure */
171 struct lstr *prevl; /* link to previous line */
172 struct lstr *nextl; /* link to next line */
173 long len; /* length of line+header */
174 char used; /* set if line valid */
175 char line; /* line is actually varying length */
179 #define POOLEN 128000 /* bytes in line pool */
181 #define POOLEN 500 /* bytes in line pool */
183 char pool[POOLEN]; /* line pool */
184 #define PHDRL ((int)sizeof(struct lstr)) /* length of line header */
186 static struct lstr *lptr; /* current line pointer */
187 static struct lstr *slptr; /* store line pointer */
189 static char *getnext(), *getprev();
190 static int first = 1;
191 static int mode_insert = 0;
192 static int mode_wspace = 1; /* words separated by spaces */
195 static short char_map[600]= {
196 0, F_SOL, /* ^a Line start */
197 F_PRVWRD, /* ^b Previous word */ F_BREAK, /* ^C break */
198 F_DELCHR, /* ^D Delete character */ F_EOL, /* ^e End of line */
199 F_CSRRGT, /* ^f Right */ F_TABBAK, /* ^G Back tab */
200 F_CSRLFT, /* ^H Left */ F_TAB, /* ^I Tab */
201 F_CSRDWN, /* ^J Down */ F_DELEOL, /* ^K kill to eol */
202 F_CLRSCRN,/* ^L clear screen */ F_RETURN, /* ^M Carriage return */
203 F_RETURN, /* ^N enter line */ F_CONCAT, /* ^O Concatenate lines */
204 F_CSRUP, /* ^P cursor up */ F_TINS, /* ^Q Insert character mode */
205 F_PAGUP, /* ^R Page up */ F_CENTER, /* ^S Center text */
206 F_PAGDWN, /* ^T Page down */ F_DELSOL, /* ^U delete to start of line */
207 F_DELWRD, /* ^V Delete word */ F_PRVWRD, /* ^W Previous word */
208 F_NXTMCH, /* ^X Next match */ F_DELEOL, /* ^Y Delete to end of line */
209 F_BACKGND,/* ^Z Background */ 0x1B, /* ^[=ESC escape */
210 F_TENTRY, /* ^\ Entry mode */ F_PASTECB,/* ^]=paste clipboard */
211 F_HOME, /* ^^ Home */ F_ERSLIN, /* ^_ Erase line */
213 ' ','!','"','#','$','%','&','\047',
214 '(',')','*','+','\054','-','.','/',
215 '0','1','2','3','4','5','6','7',
216 '8','9',':',';','<','=','>','?',
217 '@','A','B','C','D','E','F','G',
218 'H','I','J','K','L','M','N','O',
219 'P','Q','R','S','T','U','V','W',
220 'X','Y','Z','[','\\',']','^','_',
221 '\140','a','b','c','d','e','f','g',
222 'h','i','j','k','l','m','n','o',
223 'p','q','r','s','t','u','v','w',
224 'x','y','z','{','|','}','\176',F_ERSCHR /* erase character */
229 /* Local variables */
231 #define CR '\r' /* carriage return */
234 /* Function Prototypes */
236 static unsigned int input_char(void);
237 static unsigned int t_gnc(void);
238 static void insert_space(char *curline, int line_len);
239 static void insert_hole(char *curline, int line_len);
240 static void forward(char *str, int str_len);
241 static void backup(char *curline);
242 static void delchr(int cnt, char *curline, int line_len);
243 static int iswordc(char c);
244 static int next_word(char *ldb_buf);
245 static int prev_word(char *ldb_buf);
246 static void prtcur(char *str);
247 static void poolinit(void);
248 static char * getnext(void);
249 static char * getprev(void);
250 static void putline(char *newl, int newlen);
251 static void t_honk_horn(void);
252 static void t_insert_line(void);
253 static void t_delete_line(void);
254 static void t_clrline(int pos, int width);
255 void t_sendl(const char *msg, int len);
256 void t_send(const char *msg);
258 static void asclrs();
259 static void ascurs(int y, int x);
261 static void rawmode(FILE *input);
262 static void normode(void);
263 static unsigned t_getch();
264 static void asclrl(int pos, int width);
265 static void asinsl();
266 static void asdell();
268 int input_line(char *string, int length);
276 void con_init(FILE *input)
286 void con_set_zed_keys(void)
288 char_map[1] = F_NXTWRD; /* ^A Next Word */
289 char_map[2] = F_SPLIT; /* ^B Split line */
290 char_map[3] = F_EOI; /* ^C Quit */
291 char_map[4] = F_DELCHR; /* ^D Delete character */
292 char_map[5] = F_EOF; /* ^E End of file */
293 char_map[6] = F_INSCHR; /* ^F Insert character */
294 char_map[7] = F_TABBAK; /* ^G Back tab */
295 char_map[8] = F_CSRLFT; /* ^H Left */
296 char_map[9] = F_TAB; /* ^I Tab */
297 char_map[10] = F_CSRDWN; /* ^J Down */
298 char_map[11] = F_CSRUP; /* ^K Up */
299 char_map[12] = F_CSRRGT; /* ^L Right */
300 char_map[13] = F_RETURN; /* ^M Carriage return */
301 char_map[14] = F_EOL; /* ^N End of line */
302 char_map[15] = F_CONCAT; /* ^O Concatenate lines */
303 char_map[16] = F_MARK; /* ^P Set marker */
304 char_map[17] = F_TINS; /* ^Q Insert character mode */
305 char_map[18] = F_PAGUP; /* ^R Page up */
306 char_map[19] = F_CENTER; /* ^S Center text */
307 char_map[20] = F_PAGDWN; /* ^T Page down */
308 char_map[21] = F_SOL; /* ^U Line start */
309 char_map[22] = F_DELWRD; /* ^V Delete word */
310 char_map[23] = F_PRVWRD; /* ^W Previous word */
311 char_map[24] = F_NXTMCH; /* ^X Next match */
312 char_map[25] = F_DELEOL; /* ^Y Delete to end of line */
313 char_map[26] = F_DELLIN; /* ^Z Delete line */
315 char_map[28] = F_TENTRY; /* ^\ Entry mode */
316 char_map[29] = F_PASTECB;/* ^]=paste clipboard */
317 char_map[30] = F_HOME; /* ^^ Home */
318 char_map[31] = F_ERSLIN; /* ^_ Erase line */
329 * Guarantee that the string is properly terminated */
330 char *bstrncpy(char *dest, const char *src, int maxlen)
332 strncpy(dest, src, maxlen-1);
340 * New style string mapping to function code
342 static unsigned do_smap(unsigned c)
362 for (i=len-1; i<MAX_STAB; i++) {
363 for (tstab=stab[i]; tstab; tstab=tstab->next) {
364 if (strncmp(str, tstab->str, len) == 0) {
365 if (len == tstab->len) {
369 break; /* found possibility continue searching */
376 /* found partial match, so get next character and retry */
377 str[len++] = t_gnc();
383 static void dump_stab()
389 for (i=0; i<MAX_STAB; i++) {
390 for (tstab=stab[i]; tstab; tstab=tstab->next) {
391 for (j=0; j<tstab->len; j++) {
393 if (c < 0x20 || c > 0x7F) {
394 sprintf(buf, " 0x%x ", c);
402 sprintf(buf, " func=%d len=%d\n\r", tstab->func, tstab->len);
410 * New routine. Add string to string->func mapping table.
412 static void add_smap(char *str, int func)
422 /* errmsg("String for func %d is zero length\n", func); */
425 tstab = (stab_t *)malloc(sizeof(stab_t));
426 memset(tstab, 0, sizeof(stab_t));
428 tstab->str = (char *)malloc(tstab->len + 1);
429 bstrncpy(tstab->str, str, tstab->len + 1);
431 if (tstab->len > num_stab) {
432 printf("stab string too long %d. Max is %d\n", tstab->len, num_stab);
435 tstab->next = stab[tstab->len-1];
436 stab[tstab->len-1] = tstab;
437 /* printf("Add_smap tstab=%x len=%d func=%d tstab->next=%x\n\r", tstab, len,
438 func, tstab->next); */
443 /* Get the next character from the terminal - performs table lookup on
444 the character to do the desired translation */
450 if ((c=t_gnc()) <= 599) { /* IBM generates codes up to 260 */
452 } else if (c > 1000) { /* stuffed function */
453 c -= 1000; /* convert back to function code */
458 /* if we got a screen size escape sequence, read height, width */
461 y = t_gnc() - 0x20; /* y */
462 x = t_gnc() - 0x20; /* x */
469 /* Get a complete input line */
472 input_line(char *string, int length)
474 char curline[2000]; /* edit buffer */
481 poolinit(); /* build line pool */
484 noline = 1; /* no line fetched yet */
485 for (cl=cp=0; cl<length && cl<(int)sizeof(curline); ) {
490 switch (c=input_char()) {
491 case F_RETURN: /* CR */
492 t_sendl("\r\n", 2); /* yes, print it and */
493 goto done; /* get out */
494 case F_CLRSCRN: /* clear screen */
496 t_sendl(curline, cl);
500 if (noline) { /* no line fetched yet */
501 getnext(); /* getnext so getprev gets current */
502 noline = 0; /* we now have line */
504 bstrncpy(curline, getprev(), sizeof(curline));
508 noline = 0; /* mark line fetched */
509 bstrncpy(curline, getnext(), sizeof(curline));
513 insert_space(curline, sizeof(curline));
516 delchr(1, curline, sizeof(curline)); /* delete one character */
518 case F_CSRLFT: /* Backspace */
522 forward(curline, sizeof(curline));
524 case F_ERSCHR: /* Rubout */
526 delchr(1, curline, sizeof(curline));
533 t_clrline(0, t_width);
538 i = next_word(curline);
540 forward(curline, sizeof(curline));
544 i = prev_word(curline);
550 delchr(next_word(curline), curline, sizeof(curline)); /* delete word */
552 case F_NXTMCH: /* Ctl-X */
554 *string = EOS; /* terminate string */
555 return(c); /* give it to him */
557 /* Note fall through */
561 backup(curline); /* backup to beginning of line */
563 t_clrline(0, t_width); /* erase line */
565 cl = 0; /* reset cursor counter */
576 forward(curline, sizeof(curline));
582 case F_TINS: /* toggle insert mode */
583 mode_insert = !mode_insert; /* flip bit */
586 if (c > 255) { /* function key hit */
587 if (cl==0) { /* if first character then */
588 *string = EOS; /* terminate string */
589 return c; /* return it */
591 t_honk_horn(); /* complain */
593 if ((c & 0xC0) == 0xC0) {
594 if ((c & 0xFC) == 0xFC) {
596 } else if ((c & 0xF8) == 0xF8) {
598 } else if ((c & 0xF0) == 0xF0) {
600 } else if ((c & 0xE0) == 0xE0) {
609 insert_space(curline, sizeof(curline));
611 curline[cp++] = c; /* store character in line being built */
612 t_char(c); /* echo character to terminal */
615 insert_hole(curline, sizeof(curline));
616 curline[cp++] = c; /* store character in line being built */
617 t_char(c); /* echo character to terminal */
620 cl = cp; /* keep current length */
627 /* If we fall through here rather than goto done, the line is too long
628 simply return what we have now. */
630 curline[cl++] = EOS; /* terminate */
631 bstrncpy(string,curline,length); /* return line to caller */
632 /* Note, put line zaps curline */
633 putline(curline,cl); /* save line for posterity */
634 return 0; /* give it to him/her */
637 /* Insert a space at the current cursor position */
639 insert_space(char *curline, int curline_len)
643 if (cp > cl || cl+1 > curline_len) {
646 /* Note! source and destination overlap */
647 memmove(&curline[cp+1],&curline[cp],i=cl-cp);
652 forward(curline, curline_len);
662 insert_hole(char *curline, int curline_len)
666 if (cp > cl || cl+1 > curline_len) {
669 /* Note! source and destination overlap */
670 memmove(&curline[cp+1], &curline[cp], i=cl-cp);
676 /* Move cursor forward keeping characters under it */
678 forward(char *str, int str_len)
689 if ((str[cp] & 0xC0) == 0xC0) {
691 while ((str[cp] & 0xC0) == 0x80) {
701 /* How many characters under the cursor */
703 char_count(int cptr, char *str)
709 if ((str[cptr] & 0xC0) == 0xC0) {
711 while ((str[cptr] & 0xC0) == 0x80) {
719 /* Backup cursor keeping characters under it */
726 while ((str[cp] & 0xC0) == 0x80) {
733 /* Delete the character under the cursor */
735 delchr(int del, char *curline, int line_len)
739 if (cp > cl || del == 0) {
742 while (del-- && cp > 0) {
743 cnt = char_count(cp, curline);
744 if ((i=cl-cp-cnt) > 0) {
745 memcpy(&curline[cp], &curline[cp+cnt], i);
749 t_clrline(0, t_width);
752 forward(curline, line_len);
761 /* Determine if character is part of a word */
767 if (c >= '0' && c <= '9')
769 if (c == '$' || c == '%')
774 /* Return number of characters to get to next word */
776 next_word(char *ldb_buf)
783 for ( ; ncp<cl && iswordc(*(ldb_buf+ncp)); ncp++) ;
784 for ( ; ncp<cl && !iswordc(*(ldb_buf+ncp)); ncp++) ;
788 /* Return number of characters to get to previous word */
790 prev_word(char *ldb_buf)
794 if (cp == 0) /* if at begin of line stop now */
796 if (cp > cl) /* if past eol start at eol */
800 /* backup to end of previous word - i.e. skip special chars */
801 for (i=ncp-1; i && !iswordc(*(ldb_buf+i)); i--) ;
802 if (i == 0) { /* at beginning of line? */
803 return cp; /* backup to beginning */
805 /* now move back through word to beginning of word */
806 for ( ; i && iswordc(*(ldb_buf+i)); i--) ;
807 ncp = i+1; /* position to first char of word */
808 if (i==0 && iswordc(*ldb_buf)) /* check for beginning of line */
810 return cp-ncp; /* return count */
813 /* Display new current line */
820 t_clrline(0,t_width);
821 cp = cl = strlen(str);
826 /* Initialize line pool. Split pool into two pieces. */
830 slptr = lptr = (struct lstr *)pool;
839 /* Return pointer to next line in the pool and advance current line pointer */
843 do { /* find next used line */
845 } while (!lptr->used);
846 return (char *)&lptr->line;
849 /* Return pointer to previous line in the pool */
853 do { /* find previous used line */
855 } while (!lptr->used);
856 return (char *)&lptr->line;
860 putline(char *newl, int newlen)
862 struct lstr *nptr; /* points to next line */
865 lptr = slptr; /* get ptr to last line stored */
866 lptr = lptr->nextl; /* advance pointer */
867 if ((char *)lptr-pool+newlen+PHDRL > POOLEN) { /* not enough room */
868 lptr->used = 0; /* delete line */
869 lptr = (struct lstr *)pool; /* start at beginning of buffer */
871 while (lptr->len < newlen+PHDRL) { /* concatenate buffers */
872 nptr = lptr->nextl; /* point to next line */
873 lptr->nextl = nptr->nextl; /* unlink it from list */
874 nptr->nextl->prevl = lptr;
875 lptr->len += nptr->len;
877 if (lptr->len > newlen + 2 * PHDRL) { /* split buffer */
878 nptr = (struct lstr *)((char *)lptr + newlen + PHDRL);
879 /* Appropriate byte alignment - normally 2 byte, but on
880 sparc we need 4 byte alignment, so we always do 4 */
881 if (((long unsigned)nptr & 3) != 0) { /* test four byte alignment */
883 nptr = (struct lstr *)((((long unsigned) p) & ~3) + 4);
885 nptr->len = lptr->len - ((char *)nptr - (char *)lptr);
886 lptr->len -= nptr->len;
887 nptr->nextl = lptr->nextl; /* link in new buffer */
888 lptr->nextl->prevl = nptr;
893 memcpy(&lptr->line,newl,newlen);
894 lptr->used = 1; /* mark line used */
895 slptr = lptr; /* save as stored line */
900 dump(struct lstr *ptr, char *msg)
902 printf("%s buf=%x nextl=%x prevl=%x len=%d used=%d\n",
903 msg,ptr,ptr->nextl,ptr->prevl,ptr->len,ptr->used);
905 printf("line=%s\n",&ptr->line);
907 #endif /* DEBUGOUT */
910 /* Honk horn on terminal */
917 /* Insert line on terminal */
924 /* Delete line from terminal */
931 /* clear line from pos to width */
933 t_clrline(int pos, int width)
935 asclrl(pos, width); /* clear to end of line */
938 /* Helper function to add string preceded by
939 * ESC to smap table */
940 static void add_esc_smap(const char *str, int func)
943 buf[0] = 0x1B; /* esc */
944 bstrncpy(buf+1, str, sizeof(buf)-1);
948 /* Set raw mode on terminal file. Basically, get the terminal into a
949 mode in which all characters can be read as they are entered. CBREAK
950 mode is not sufficient.
952 static void rawmode(FILE *input)
955 static char term_buf[2048];
956 static char *term_buffer = term_buf;
957 char *termtype = (char *)getenv("TERM");
959 /* Make sure we are dealing with a terminal */
960 if (!isatty(fileno(input))) {
963 if (tcgetattr(0, &old_term_params) != 0) {
964 printf("conio: Cannot tcgetattr()\n");
967 old_term_params_set = true;
969 t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
971 t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK |
972 ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);
975 t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON |
977 tcflush(0, TCIFLUSH);
978 if (tcsetattr(0, TCSANOW, &t) == -1) {
979 printf("Cannot tcsetattr()\n");
982 /* Defaults, the main program can override these */
983 signal(SIGQUIT, SIG_IGN);
984 signal(SIGHUP, SIG_IGN);
985 signal(SIGINT, sigintcatcher);
986 signal(SIGWINCH, SIG_IGN);
989 printf("Cannot get terminal type.\n");
993 if (tgetent(term_buffer, termtype) < 0) {
994 printf("Cannot get terminal termcap entry.\n");
998 t_width = t_height = -1;
999 /* Note (char *)casting is due to really stupid compiler warnings */
1000 t_width = tgetnum((char *)"co") - 1;
1001 t_height = tgetnum((char *)"li");
1004 t_cm = (char *)tgetstr((char *)"cm", &term_buffer);
1005 t_cs = (char *)tgetstr((char *)"cl", &term_buffer); /* clear screen */
1006 t_cl = (char *)tgetstr((char *)"ce", &term_buffer); /* clear line */
1007 t_dl = (char *)tgetstr((char *)"dl", &term_buffer); /* delete line */
1008 t_il = (char *)tgetstr((char *)"al", &term_buffer); /* insert line */
1009 t_honk = (char *)tgetstr((char *)"bl", &term_buffer); /* beep */
1010 t_ti = (char *)tgetstr((char *)"ti", &term_buffer);
1011 t_te = (char *)tgetstr((char *)"te", &term_buffer);
1012 t_up = (char *)tgetstr((char *)"up", &term_buffer);
1013 t_do = (char *)tgetstr((char *)"do", &term_buffer);
1014 t_sf = (char *)tgetstr((char *)"sf", &term_buffer);
1016 num_stab = MAX_STAB; /* get default stab size */
1017 stab = (stab_t **)malloc(sizeof(stab_t *) * num_stab);
1018 memset(stab, 0, sizeof(stab_t *) * num_stab);
1021 kl = (char *)tgetstr((char *)"kl", &term_buffer);
1022 kr = (char *)tgetstr((char *)"kr", &term_buffer);
1023 ku = (char *)tgetstr((char *)"ku", &term_buffer);
1024 kd = (char *)tgetstr((char *)"kd", &term_buffer);
1025 kh = (char *)tgetstr((char *)"kh", &term_buffer);
1026 kb = (char *)tgetstr((char *)"kb", &term_buffer);
1027 kD = (char *)tgetstr((char *)"kD", &term_buffer);
1028 kI = (char *)tgetstr((char *)"kI", &term_buffer);
1029 kN = (char *)tgetstr((char *)"kN", &term_buffer);
1030 kP = (char *)tgetstr((char *)"kP", &term_buffer);
1031 kH = (char *)tgetstr((char *)"kH", &term_buffer);
1032 kE = (char *)tgetstr((char *)"kE", &term_buffer);
1034 add_smap(kl, F_CSRLFT);
1035 add_smap(kr, F_CSRRGT);
1036 add_smap(ku, F_CSRUP);
1037 add_smap(kd, F_CSRDWN);
1038 add_smap(kI, F_TINS);
1039 add_smap(kN, F_PAGDWN);
1040 add_smap(kP, F_PAGUP);
1041 add_smap(kH, F_HOME);
1042 add_smap(kE, F_EOF);
1045 add_esc_smap("[A", F_CSRUP);
1046 add_esc_smap("[B", F_CSRDWN);
1047 add_esc_smap("[C", F_CSRRGT);
1048 add_esc_smap("[D", F_CSRLFT);
1049 add_esc_smap("[1~", F_HOME);
1050 add_esc_smap("[2~", F_TINS);
1051 add_esc_smap("[3~", F_DELCHR);
1052 add_esc_smap("[4~", F_EOF);
1053 add_esc_smap("f", F_NXTWRD);
1054 add_esc_smap("b", F_PRVWRD);
1058 /* Restore tty mode */
1059 static void normode()
1061 if (old_term_params_set) {
1062 tcsetattr(0, TCSANOW, &old_term_params);
1063 old_term_params_set = false;
1067 /* Get next character from terminal/script file/unget buffer */
1075 /* Get next character from OS */
1076 static unsigned t_getch(void)
1080 if (read(0, &c, 1) != 1) {
1086 /* Send message to terminal - primitive routine */
1088 t_sendl(const char *msg, int len)
1094 t_send(const char *msg)
1099 t_sendl(msg, strlen(msg)); /* faster than one char at time */
1102 /* Send single character to terminal - primitive routine - */
1106 (void)write(1, &c, 1);
1110 static int brkflg = 0; /* set on user break */
1112 /* Routine to return true if user types break */
1118 /* Clear break flag */
1125 /* Interrupt caught here */
1126 static void sigintcatcher(int sig)
1133 signal(SIGINT, sigintcatcher);
1140 signal(SIGINT, sigintcatcher);
1144 /* ASCLRL() -- Clear to end of line from current position */
1145 static void asclrl(int pos, int width)
1150 t_send(t_cl); /* use clear to eol function */
1153 if (pos==1 && linsdel_ok) {
1154 t_delete_line(); /* delete line */
1155 t_insert_line(); /* reinsert it */
1158 for (i=1; i<=width-pos+1; i++)
1159 t_char(' '); /* last resort, blank it out */
1160 for (i=1; i<=width-pos+1; i++) /* backspace to original position */
1167 /* ASCURS -- Set cursor position */
1168 static void ascurs(int y, int x)
1170 t_send((char *)tgoto(t_cm, x, y));
1174 /* ASCLRS -- Clear whole screen */
1175 static void asclrs()
1183 /* ASINSL -- insert new line after cursor */
1184 static void asinsl()
1186 t_clrline(0, t_width);
1187 t_send(t_il); /* insert before */
1190 /* ASDELL -- Delete line at cursor */
1191 static void asdell()