2 Bacula® - The Network Backup Solution
4 Copyright (C) 1981-2010 Free Software Foundation Europe e.V.
5 Yes, that is 1981 no error.
7 The main author of Bacula is Kern Sibbald, with contributions from
8 many others, a complete list can be found in the file AUTHORS.
9 This program is Free Software; you can redistribute it and/or
10 modify it under the terms of version three of the GNU Affero General Public
11 License as published by the Free Software Foundation and included
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Affero General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 Bacula® is a registered trademark of Kern Sibbald.
25 The licensor of Bacula is the Free Software Foundation Europe
26 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
27 Switzerland, email:ftf@fsfeurope.org.
30 Generalized console input/output handler
31 A maintanable replacement for readline()
33 Updated for Bacula, Kern Sibbald, December MMIII
35 This code is in part derived from code that I wrote in
36 1981, so some of it is a bit old and could use a cleanup.
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 */
67 #if defined(HAVE_SUN_OS)
69 extern "C" int tgetent(void *, const char *);
70 extern "C" int tgetnum(const char *);
71 extern "C" char *tgetstr (const char*, char**);
73 extern "C" char *tgoto (const char *, int, int);
75 extern "C" int tgetent(char *, char *);
76 extern "C" int tgetnum(char id[2]);
77 extern "C" char *tgetstr(char id[2], char **);
78 extern "C" char *tgoto(char *, int, int);
79 #elif defined (__digital__) && defined (__unix__)
80 extern "C" int tgetent(void *, const char *);
81 extern "C" int tgetnum(const char *);
82 extern "C" char *tgetstr (const char*, char**);
83 extern "C" char *tgoto (const char *, int, int);
88 /* From termios library */
89 #if defined(HAVE_HPUX_OS) || defined(HAVE_AIX_OS)
97 /* Forward referenced functions */
99 static void sigintcatcher(int);
102 static void add_smap(char *str, int func);
105 /* Global variables */
107 static const char *t_up = "\n"; /* scroll up character */
108 static const char *t_honk = "\007"; /* sound beep */
109 static char *t_il; /* insert line */
110 static char *t_dl; /* delete line */
111 static char *t_cs; /* clear screen */
112 static char *t_cl; /* clear line */
113 static int t_width = 79; /* terminal width */
114 static int t_height = 24; /* terminal height */
115 static int linsdel_ok = 0; /* set if term has line insert & delete fncs */
117 static char *t_cm; /* cursor positioning */
118 static char *t_ti; /* init sequence */
119 static char *t_te; /* end sequence */
120 static char *t_do; /* down one line */
121 static char *t_sf; /* scroll screen one line up */
123 /* Keypad and Function Keys */
124 static char *kl; /* left key */
125 static char *kr; /* right */
126 static char *ku; /* up */
127 static char *kd; /* down */
128 static char *kh; /* home */
129 static char *kb; /* backspace */
130 static char *kD; /* delete key */
131 static char *kI; /* insert */
132 static char *kN; /* next page */
133 static char *kP; /* previous page */
134 static char *kH; /* home */
135 static char *kE; /* end */
138 #define EOS '\0' /* end of string terminator */
144 * Stab entry. Input chars (str), the length, and the desired
147 typedef struct s_stab {
156 static stab_t **stab = NULL; /* array of stabs by length */
157 static int num_stab; /* size of stab array */
159 static bool old_term_params_set = false;
160 static struct termios old_term_params;
162 /* Maintain lines in a doubly linked circular pool of lines. Each line is
163 preceded by a header defined by the lstr structure */
166 struct lstr { /* line pool structure */
167 struct lstr *prevl; /* link to previous line */
168 struct lstr *nextl; /* link to next line */
169 long len; /* length of line+header */
170 char used; /* set if line valid */
171 char line; /* line is actually varying length */
175 #define POOLEN 128000 /* bytes in line pool */
177 #define POOLEN 500 /* bytes in line pool */
179 char pool[POOLEN]; /* line pool */
180 #define PHDRL ((int)sizeof(struct lstr)) /* length of line header */
182 static struct lstr *lptr; /* current line pointer */
183 static struct lstr *slptr; /* store line pointer */
185 static char *getnext(), *getprev();
186 static int first = 1;
187 static int mode_insert = 1;
188 static int mode_wspace = 1; /* words separated by spaces */
191 static short char_map[600]= {
192 0, F_SOL, /* ^a Line start */
193 F_PRVWRD, /* ^b Previous word */ F_BREAK, /* ^C break */
194 F_DELCHR, /* ^D Delete character */ F_EOL, /* ^e End of line */
195 F_CSRRGT, /* ^f Right */ F_TABBAK, /* ^G Back tab */
196 F_CSRLFT, /* ^H Left */ F_TAB, /* ^I Tab */
197 F_CSRDWN, /* ^J Down */ F_DELEOL, /* ^K kill to eol */
198 F_CLRSCRN,/* ^L clear screen */ F_RETURN, /* ^M Carriage return */
199 F_RETURN, /* ^N enter line */ F_CONCAT, /* ^O Concatenate lines */
200 F_CSRUP, /* ^P cursor up */ F_TINS, /* ^Q Insert character mode */
201 F_PAGUP, /* ^R Page up */ F_CENTER, /* ^S Center text */
202 F_PAGDWN, /* ^T Page down */ F_DELSOL, /* ^U delete to start of line */
203 F_DELWRD, /* ^V Delete word */ F_PRVWRD, /* ^W Previous word */
204 F_NXTMCH, /* ^X Next match */ F_DELEOL, /* ^Y Delete to end of line */
205 F_BACKGND,/* ^Z Background */ 0x1B, /* ^[=ESC escape */
206 F_TENTRY, /* ^\ Entry mode */ F_PASTECB,/* ^]=paste clipboard */
207 F_HOME, /* ^^ Home */ F_ERSLIN, /* ^_ Erase line */
209 ' ','!','"','#','$','%','&','\047',
210 '(',')','*','+','\054','-','.','/',
211 '0','1','2','3','4','5','6','7',
212 '8','9',':',';','<','=','>','?',
213 '@','A','B','C','D','E','F','G',
214 'H','I','J','K','L','M','N','O',
215 'P','Q','R','S','T','U','V','W',
216 'X','Y','Z','[','\\',']','^','_',
217 '\140','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','{','|','}','\176',F_ERSCHR /* erase character */
225 /* Local variables */
227 #define CR '\r' /* carriage return */
230 /* Function Prototypes */
232 static unsigned int input_char(void);
233 static unsigned int t_gnc(void);
234 static void insert_space(char *curline, int line_len);
235 static void insert_hole(char *curline, int line_len);
236 static void forward(char *str, int str_len);
237 static void backup(char *curline);
238 static void delchr(int cnt, char *curline, int line_len);
239 static int iswordc(char c);
240 static int next_word(char *ldb_buf);
241 static int prev_word(char *ldb_buf);
242 static void prtcur(char *str);
243 static void poolinit(void);
244 static char * getnext(void);
245 static char * getprev(void);
246 static void putline(char *newl, int newlen);
247 static void t_honk_horn(void);
248 static void t_insert_line(void);
249 static void t_delete_line(void);
250 static void t_clrline(int pos, int width);
251 void t_sendl(const char *msg, int len);
252 void t_send(const char *msg);
254 static void asclrs();
255 static void ascurs(int y, int x);
257 static void rawmode(FILE *input);
258 static void normode(void);
259 static unsigned t_getch();
260 static void asclrl(int pos, int width);
261 static void asinsl();
262 static void asdell();
264 int input_line(char *string, int length);
272 void con_init(FILE *input)
282 void con_set_zed_keys(void)
284 char_map[1] = F_NXTWRD; /* ^A Next Word */
285 char_map[2] = F_SPLIT; /* ^B Split line */
286 char_map[3] = F_EOI; /* ^C Quit */
287 char_map[4] = F_DELCHR; /* ^D Delete character */
288 char_map[5] = F_EOF; /* ^E End of file */
289 char_map[6] = F_INSCHR; /* ^F Insert character */
290 char_map[7] = F_TABBAK; /* ^G Back tab */
291 char_map[8] = F_CSRLFT; /* ^H Left */
292 char_map[9] = F_TAB; /* ^I Tab */
293 char_map[10] = F_CSRDWN; /* ^J Down */
294 char_map[11] = F_CSRUP; /* ^K Up */
295 char_map[12] = F_CSRRGT; /* ^L Right */
296 char_map[13] = F_RETURN; /* ^M Carriage return */
297 char_map[14] = F_EOL; /* ^N End of line */
298 char_map[15] = F_CONCAT; /* ^O Concatenate lines */
299 char_map[16] = F_MARK; /* ^P Set marker */
300 char_map[17] = F_TINS; /* ^Q Insert character mode */
301 char_map[18] = F_PAGUP; /* ^R Page up */
302 char_map[19] = F_CENTER; /* ^S Center text */
303 char_map[20] = F_PAGDWN; /* ^T Page down */
304 char_map[21] = F_SOL; /* ^U Line start */
305 char_map[22] = F_DELWRD; /* ^V Delete word */
306 char_map[23] = F_PRVWRD; /* ^W Previous word */
307 char_map[24] = F_NXTMCH; /* ^X Next match */
308 char_map[25] = F_DELEOL; /* ^Y Delete to end of line */
309 char_map[26] = F_DELLIN; /* ^Z Delete line */
311 char_map[28] = F_TENTRY; /* ^\ Entry mode */
312 char_map[29] = F_PASTECB;/* ^]=paste clipboard */
313 char_map[30] = F_HOME; /* ^^ Home */
314 char_map[31] = F_ERSLIN; /* ^_ Erase line */
325 * Guarantee that the string is properly terminated */
326 char *bstrncpy(char *dest, const char *src, int maxlen)
328 strncpy(dest, src, maxlen-1);
336 * New style string mapping to function code
338 static unsigned do_smap(unsigned c)
358 for (i=len-1; i<MAX_STAB; i++) {
359 for (tstab=stab[i]; tstab; tstab=tstab->next) {
360 if (strncmp(str, tstab->str, len) == 0) {
361 if (len == tstab->len) {
365 break; /* found possibility continue searching */
372 /* found partial match, so get next character and retry */
373 str[len++] = t_gnc();
379 static void dump_stab()
385 for (i=0; i<MAX_STAB; i++) {
386 for (tstab=stab[i]; tstab; tstab=tstab->next) {
387 for (j=0; j<tstab->len; j++) {
389 if (c < 0x20 || c > 0x7F) {
390 sprintf(buf, " 0x%x ", c);
398 sprintf(buf, " func=%d len=%d\n\r", tstab->func, tstab->len);
406 * New routine. Add string to string->func mapping table.
408 static void add_smap(char *str, int func)
418 /* errmsg("String for func %d is zero length\n", func); */
421 tstab = (stab_t *)malloc(sizeof(stab_t));
422 memset(tstab, 0, sizeof(stab_t));
424 tstab->str = (char *)malloc(tstab->len + 1);
425 bstrncpy(tstab->str, str, tstab->len + 1);
427 if (tstab->len > num_stab) {
428 printf("stab string too long %d. Max is %d\n", tstab->len, num_stab);
431 tstab->next = stab[tstab->len-1];
432 stab[tstab->len-1] = tstab;
433 /* printf("Add_smap tstab=%x len=%d func=%d tstab->next=%x\n\r", tstab, len,
434 func, tstab->next); */
439 /* Get the next character from the terminal - performs table lookup on
440 the character to do the desired translation */
446 if ((c=t_gnc()) <= 599) { /* IBM generates codes up to 260 */
448 } else if (c > 1000) { /* stuffed function */
449 c -= 1000; /* convert back to function code */
454 /* if we got a screen size escape sequence, read height, width */
456 t_gnc(); /* - 0x20 = y */
457 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 /* Save non-blank lines. Note, put line zaps curline */
628 if (curline[0] != EOS) {
629 putline(curline,cl); /* save line for posterity */
631 return 0; /* give it to him/her */
634 /* Insert a space at the current cursor position */
636 insert_space(char *curline, int curline_len)
640 if (cp >= cl || cl+1 > curline_len) {
643 /* Note! source and destination overlap */
644 memmove(&curline[cp+1],&curline[cp],i=cl-cp);
649 forward(curline, curline_len);
659 insert_hole(char *curline, int curline_len)
663 if (cp > cl || cl+1 > curline_len) {
666 /* Note! source and destination overlap */
667 memmove(&curline[cp+1], &curline[cp], i=cl-cp);
673 /* Move cursor forward keeping characters under it */
675 forward(char *str, int str_len)
686 if ((str[cp] & 0xC0) == 0xC0) {
688 while ((str[cp] & 0xC0) == 0x80) {
698 /* How many characters under the cursor */
700 char_count(int cptr, char *str)
706 if ((str[cptr] & 0xC0) == 0xC0) {
708 while ((str[cptr] & 0xC0) == 0x80) {
716 /* Backup cursor keeping characters under it */
723 while ((str[cp] & 0xC0) == 0x80) {
730 /* Delete the character under the cursor */
732 delchr(int del, char *curline, int line_len)
736 if (cp > cl || del == 0) {
739 while (del-- && cl > 0) {
740 cnt = char_count(cp, curline);
741 if ((i=cl-cp-cnt) > 0) {
742 memcpy(&curline[cp], &curline[cp+cnt], i);
746 t_clrline(0, t_width);
749 forward(curline, line_len);
758 /* Determine if character is part of a word */
764 if (c >= '0' && c <= '9')
766 if (c == '$' || c == '%')
771 /* Return number of characters to get to next word */
773 next_word(char *ldb_buf)
780 for ( ; ncp<cl && iswordc(*(ldb_buf+ncp)); ncp++) ;
781 for ( ; ncp<cl && !iswordc(*(ldb_buf+ncp)); ncp++) ;
785 /* Return number of characters to get to previous word */
787 prev_word(char *ldb_buf)
791 if (cp == 0) /* if at begin of line stop now */
793 if (cp > cl) /* if past eol start at eol */
797 /* backup to end of previous word - i.e. skip special chars */
798 for (i=ncp-1; i && !iswordc(*(ldb_buf+i)); i--) ;
799 if (i == 0) { /* at beginning of line? */
800 return cp; /* backup to beginning */
802 /* now move back through word to beginning of word */
803 for ( ; i && iswordc(*(ldb_buf+i)); i--) ;
804 ncp = i+1; /* position to first char of word */
805 if (i==0 && iswordc(*ldb_buf)) /* check for beginning of line */
807 return cp-ncp; /* return count */
810 /* Display new current line */
817 t_clrline(0,t_width);
818 cp = cl = strlen(str);
823 /* Initialize line pool. Split pool into two pieces. */
827 slptr = lptr = (struct lstr *)pool;
836 /* Return pointer to next line in the pool and advance current line pointer */
840 do { /* find next used line */
842 } while (!lptr->used);
843 return (char *)&lptr->line;
846 /* Return pointer to previous line in the pool */
850 do { /* find previous used line */
852 } while (!lptr->used);
853 return (char *)&lptr->line;
857 putline(char *newl, int newlen)
859 struct lstr *nptr; /* points to next line */
862 lptr = slptr; /* get ptr to last line stored */
863 lptr = lptr->nextl; /* advance pointer */
864 if ((char *)lptr-pool+newlen+PHDRL > POOLEN) { /* not enough room */
865 lptr->used = 0; /* delete line */
866 lptr = (struct lstr *)pool; /* start at beginning of buffer */
868 while (lptr->len < newlen+PHDRL) { /* concatenate buffers */
869 nptr = lptr->nextl; /* point to next line */
870 lptr->nextl = nptr->nextl; /* unlink it from list */
871 nptr->nextl->prevl = lptr;
872 lptr->len += nptr->len;
874 if (lptr->len > newlen + 2 * PHDRL) { /* split buffer */
875 nptr = (struct lstr *)((char *)lptr + newlen + PHDRL);
876 /* Appropriate byte alignment - normally 2 byte, but on
877 sparc we need 4 byte alignment, so we always do 4 */
878 if (((long unsigned)nptr & 3) != 0) { /* test four byte alignment */
880 nptr = (struct lstr *)((((long unsigned) p) & ~3) + 4);
882 nptr->len = lptr->len - ((char *)nptr - (char *)lptr);
883 lptr->len -= nptr->len;
884 nptr->nextl = lptr->nextl; /* link in new buffer */
885 lptr->nextl->prevl = nptr;
890 memcpy(&lptr->line,newl,newlen);
891 lptr->used = 1; /* mark line used */
892 slptr = lptr; /* save as stored line */
897 dump(struct lstr *ptr, char *msg)
899 printf("%s buf=%x nextl=%x prevl=%x len=%d used=%d\n",
900 msg,ptr,ptr->nextl,ptr->prevl,ptr->len,ptr->used);
902 printf("line=%s\n",&ptr->line);
904 #endif /* DEBUGOUT */
907 /* Honk horn on terminal */
914 /* Insert line on terminal */
921 /* Delete line from terminal */
928 /* clear line from pos to width */
930 t_clrline(int pos, int width)
932 asclrl(pos, width); /* clear to end of line */
935 /* Helper function to add string preceded by
936 * ESC to smap table */
937 static void add_esc_smap(const char *str, int func)
940 buf[0] = 0x1B; /* esc */
941 bstrncpy(buf+1, str, sizeof(buf)-1);
945 /* Set raw mode on terminal file. Basically, get the terminal into a
946 mode in which all characters can be read as they are entered. CBREAK
947 mode is not sufficient.
949 static void rawmode(FILE *input)
952 static char term_buf[2048];
953 static char *term_buffer = term_buf;
954 char *termtype = (char *)getenv("TERM");
956 /* Make sure we are dealing with a terminal */
957 if (!isatty(fileno(input))) {
960 if (tcgetattr(0, &old_term_params) != 0) {
961 printf("conio: Cannot tcgetattr()\n");
964 old_term_params_set = true;
966 t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
968 t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK |
969 ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);
972 t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON |
974 tcflush(0, TCIFLUSH);
975 if (tcsetattr(0, TCSANOW, &t) == -1) {
976 printf("Cannot tcsetattr()\n");
979 /* Defaults, the main program can override these */
980 signal(SIGQUIT, SIG_IGN);
981 signal(SIGHUP, SIG_IGN);
982 signal(SIGINT, sigintcatcher);
983 signal(SIGWINCH, SIG_IGN);
986 printf("Cannot get terminal type.\n");
990 if (tgetent(term_buffer, termtype) < 0) {
991 printf("Cannot get terminal termcap entry.\n");
995 t_width = t_height = -1;
996 /* Note (char *)casting is due to really stupid compiler warnings */
997 t_width = tgetnum((char *)"co") - 1;
998 t_height = tgetnum((char *)"li");
1001 t_cm = (char *)tgetstr((char *)"cm", &term_buffer);
1002 t_cs = (char *)tgetstr((char *)"cl", &term_buffer); /* clear screen */
1003 t_cl = (char *)tgetstr((char *)"ce", &term_buffer); /* clear line */
1004 t_dl = (char *)tgetstr((char *)"dl", &term_buffer); /* delete line */
1005 t_il = (char *)tgetstr((char *)"al", &term_buffer); /* insert line */
1006 t_honk = (char *)tgetstr((char *)"bl", &term_buffer); /* beep */
1007 t_ti = (char *)tgetstr((char *)"ti", &term_buffer);
1008 t_te = (char *)tgetstr((char *)"te", &term_buffer);
1009 t_up = (char *)tgetstr((char *)"up", &term_buffer);
1010 t_do = (char *)tgetstr((char *)"do", &term_buffer);
1011 t_sf = (char *)tgetstr((char *)"sf", &term_buffer);
1013 num_stab = MAX_STAB; /* get default stab size */
1014 stab = (stab_t **)malloc(sizeof(stab_t *) * num_stab);
1015 memset(stab, 0, sizeof(stab_t *) * num_stab);
1018 kl = (char *)tgetstr((char *)"kl", &term_buffer);
1019 kr = (char *)tgetstr((char *)"kr", &term_buffer);
1020 ku = (char *)tgetstr((char *)"ku", &term_buffer);
1021 kd = (char *)tgetstr((char *)"kd", &term_buffer);
1022 kh = (char *)tgetstr((char *)"kh", &term_buffer);
1023 kb = (char *)tgetstr((char *)"kb", &term_buffer);
1024 kD = (char *)tgetstr((char *)"kD", &term_buffer);
1025 kI = (char *)tgetstr((char *)"kI", &term_buffer);
1026 kN = (char *)tgetstr((char *)"kN", &term_buffer);
1027 kP = (char *)tgetstr((char *)"kP", &term_buffer);
1028 kH = (char *)tgetstr((char *)"kH", &term_buffer);
1029 kE = (char *)tgetstr((char *)"kE", &term_buffer);
1031 add_smap(kl, F_CSRLFT);
1032 add_smap(kr, F_CSRRGT);
1033 add_smap(ku, F_CSRUP);
1034 add_smap(kd, F_CSRDWN);
1035 add_smap(kI, F_TINS);
1036 add_smap(kN, F_PAGDWN);
1037 add_smap(kP, F_PAGUP);
1038 add_smap(kH, F_HOME);
1039 add_smap(kE, F_EOF);
1042 add_esc_smap("[A", F_CSRUP);
1043 add_esc_smap("[B", F_CSRDWN);
1044 add_esc_smap("[C", F_CSRRGT);
1045 add_esc_smap("[D", F_CSRLFT);
1046 add_esc_smap("[1~", F_HOME);
1047 add_esc_smap("[2~", F_TINS);
1048 add_esc_smap("[3~", F_DELCHR);
1049 add_esc_smap("[4~", F_EOF);
1050 add_esc_smap("f", F_NXTWRD);
1051 add_esc_smap("b", F_PRVWRD);
1055 /* Restore tty mode */
1056 static void normode()
1058 if (old_term_params_set) {
1059 tcsetattr(0, TCSANOW, &old_term_params);
1060 old_term_params_set = false;
1064 /* Get next character from terminal/script file/unget buffer */
1072 /* Get next character from OS */
1073 static unsigned t_getch(void)
1077 if (read(0, &c, 1) != 1) {
1083 /* Send message to terminal - primitive routine */
1085 t_sendl(const char *msg, int len)
1091 t_send(const char *msg)
1096 t_sendl(msg, strlen(msg)); /* faster than one char at time */
1099 /* Send single character to terminal - primitive routine - */
1103 (void)write(1, &c, 1);
1107 static int brkflg = 0; /* set on user break */
1109 /* Routine to return true if user types break */
1115 /* Clear break flag */
1122 /* Interrupt caught here */
1123 static void sigintcatcher(int sig)
1130 signal(SIGINT, sigintcatcher);
1137 signal(SIGINT, sigintcatcher);
1141 /* ASCLRL() -- Clear to end of line from current position */
1142 static void asclrl(int pos, int width)
1147 t_send(t_cl); /* use clear to eol function */
1150 if (pos==1 && linsdel_ok) {
1151 t_delete_line(); /* delete line */
1152 t_insert_line(); /* reinsert it */
1155 for (i=1; i<=width-pos+1; i++)
1156 t_char(' '); /* last resort, blank it out */
1157 for (i=1; i<=width-pos+1; i++) /* backspace to original position */
1164 /* ASCURS -- Set cursor position */
1165 static void ascurs(int y, int x)
1167 t_send((char *)tgoto(t_cm, x, y));
1171 /* ASCLRS -- Clear whole screen */
1172 static void asclrs()
1180 /* ASINSL -- insert new line after cursor */
1181 static void asinsl()
1183 t_clrline(0, t_width);
1184 t_send(t_il); /* insert before */
1187 /* ASDELL -- Delete line at cursor */
1188 static void asdell()