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 Copyright (C) 1981-2006 Kern Sibbald
13 Yes, that is 1981 no error.
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License
17 version 2 as amended with additional clauses defined in the
18 file LICENSE in the main source directory.
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
23 the file LICENSE for additional details.
29 * If the top bit of a UTF-8 string is 0 (8 bits), then it
30 * is a normal ASCII character.
31 * If the top two bits are 11 (i.e. (c & 0xC0) == 0xC0 then
32 * it is the start of a series of chars (up to 5)
33 * Each subsequent character starts with 10 (i.e. (c & 0xC0) == 0x80)
46 /* We are in Bacula */
53 extern "C" int tgetent(void *, const char *);
54 extern "C" int tgetnum(const char *);
55 extern "C" char *tgetstr (const char*, char**);
56 extern "C" char *tgoto (const char *, int, int);
59 #elif defined (__digital__) && defined (__unix__)
60 extern "C" int tgetent(void *, const char *);
61 extern "C" int tgetnum(const char *);
62 extern "C" char *tgetstr (const char*, char**);
63 extern "C" char *tgoto (const char *, int, int);
71 /* From termios library */
80 /* Forward referenced functions */
82 static void sigintcatcher(int);
85 static void add_smap(char *str, int func);
88 /* Global variables */
90 static const char *t_up = "\n"; /* scroll up character */
91 static const char *t_honk = "\007"; /* sound beep */
92 static char *t_il; /* insert line */
93 static char *t_dl; /* delete line */
94 static char *t_cs; /* clear screen */
95 static char *t_cl; /* clear line */
96 static int t_width = 79; /* terminal width */
97 static int t_height = 24; /* terminal height */
98 static int linsdel_ok = 0; /* set if term has line insert & delete fncs */
100 static char *t_cm; /* cursor positioning */
101 static char *t_ti; /* init sequence */
102 static char *t_te; /* end sequence */
103 static char *t_do; /* down one line */
104 static char *t_sf; /* scroll screen one line up */
106 /* Keypad and Function Keys */
107 static char *kl; /* left key */
108 static char *kr; /* right */
109 static char *ku; /* up */
110 static char *kd; /* down */
111 static char *kh; /* home */
112 static char *kb; /* backspace */
113 static char *kD; /* delete key */
114 static char *kI; /* insert */
115 static char *kN; /* next page */
116 static char *kP; /* previous page */
117 static char *kH; /* home */
118 static char *kE; /* end */
121 #define EOS '\0' /* end of string terminator */
127 * Stab entry. Input chars (str), the length, and the desired
130 typedef struct s_stab {
139 static stab_t **stab = NULL; /* array of stabs by length */
140 static int num_stab; /* size of stab array */
142 static bool old_term_params_set = false;
143 static struct termios old_term_params;
145 /* Maintain lines in a doubly linked circular pool of lines. Each line is
146 preceded by a header defined by the lstr structure */
149 struct lstr { /* line pool structure */
150 struct lstr *prevl; /* link to previous line */
151 struct lstr *nextl; /* link to next line */
152 long len; /* length of line+header */
153 char used; /* set if line valid */
154 char line; /* line is actually varying length */
158 #define POOLEN 128000 /* bytes in line pool */
160 #define POOLEN 500 /* bytes in line pool */
162 char pool[POOLEN]; /* line pool */
163 #define PHDRL ((int)sizeof(struct lstr)) /* length of line header */
165 static struct lstr *lptr; /* current line pointer */
166 static struct lstr *slptr; /* store line pointer */
168 static char *getnext(), *getprev();
169 static int first = 1;
170 static int mode_insert = 0;
171 static int mode_wspace = 1; /* words separated by spaces */
174 static short char_map[600]= {
175 0, F_SOL, /* ^a Line start */
176 F_PRVWRD, /* ^b Previous word */ F_BREAK, /* ^C break */
177 F_DELCHR, /* ^D Delete character */ F_EOL, /* ^e End of line */
178 F_CSRRGT, /* ^f Right */ F_TABBAK, /* ^G Back tab */
179 F_CSRLFT, /* ^H Left */ F_TAB, /* ^I Tab */
180 F_CSRDWN, /* ^J Down */ F_DELEOL, /* ^K kill to eol */
181 F_CLRSCRN,/* ^L clear screen */ F_RETURN, /* ^M Carriage return */
182 F_RETURN, /* ^N enter line */ F_CONCAT, /* ^O Concatenate lines */
183 F_CSRUP, /* ^P cursor up */ F_TINS, /* ^Q Insert character mode */
184 F_PAGUP, /* ^R Page up */ F_CENTER, /* ^S Center text */
185 F_PAGDWN, /* ^T Page down */ F_DELSOL, /* ^U delete to start of line */
186 F_DELWRD, /* ^V Delete word */ F_PRVWRD, /* ^W Previous word */
187 F_NXTMCH, /* ^X Next match */ F_DELEOL, /* ^Y Delete to end of line */
188 F_BACKGND,/* ^Z Background */ 0x1B, /* ^[=ESC escape */
189 F_TENTRY, /* ^\ Entry mode */ F_PASTECB,/* ^]=paste clipboard */
190 F_HOME, /* ^^ Home */ F_ERSLIN, /* ^_ Erase line */
192 ' ','!','"','#','$','%','&','\047',
193 '(',')','*','+','\054','-','.','/',
194 '0','1','2','3','4','5','6','7',
195 '8','9',':',';','<','=','>','?',
196 '@','A','B','C','D','E','F','G',
197 'H','I','J','K','L','M','N','O',
198 'P','Q','R','S','T','U','V','W',
199 'X','Y','Z','[','\\',']','^','_',
200 '\140','a','b','c','d','e','f','g',
201 'h','i','j','k','l','m','n','o',
202 'p','q','r','s','t','u','v','w',
203 'x','y','z','{','|','}','\176',F_ERSCHR /* erase character */
208 /* Local variables */
210 #define CR '\r' /* carriage return */
213 /* Function Prototypes */
215 static unsigned int input_char(void);
216 static unsigned int t_gnc(void);
217 static void insert_space(char *curline, int line_len);
218 static void insert_hole(char *curline, int line_len);
219 static void forward(char *str, int str_len);
220 static void backup(char *curline);
221 static void delchr(int cnt, char *curline, int line_len);
222 static int iswordc(char c);
223 static int next_word(char *ldb_buf);
224 static int prev_word(char *ldb_buf);
225 static void prtcur(char *str);
226 static void poolinit(void);
227 static char * getnext(void);
228 static char * getprev(void);
229 static void putline(char *newl, int newlen);
230 static void t_honk_horn(void);
231 static void t_insert_line(void);
232 static void t_delete_line(void);
233 static void t_clrline(int pos, int width);
234 void t_sendl(const char *msg, int len);
235 void t_send(const char *msg);
237 static void asclrs();
238 static void ascurs(int y, int x);
240 static void rawmode(FILE *input);
241 static void normode(void);
242 static unsigned t_getch();
243 static void asclrl(int pos, int width);
244 static void asinsl();
245 static void asdell();
247 int input_line(char *string, int length);
255 void con_init(FILE *input)
265 void con_set_zed_keys(void)
267 char_map[1] = F_NXTWRD; /* ^A Next Word */
268 char_map[2] = F_SPLIT; /* ^B Split line */
269 char_map[3] = F_EOI; /* ^C Quit */
270 char_map[4] = F_DELCHR; /* ^D Delete character */
271 char_map[5] = F_EOF; /* ^E End of file */
272 char_map[6] = F_INSCHR; /* ^F Insert character */
273 char_map[7] = F_TABBAK; /* ^G Back tab */
274 char_map[8] = F_CSRLFT; /* ^H Left */
275 char_map[9] = F_TAB; /* ^I Tab */
276 char_map[10] = F_CSRDWN; /* ^J Down */
277 char_map[11] = F_CSRUP; /* ^K Up */
278 char_map[12] = F_CSRRGT; /* ^L Right */
279 char_map[13] = F_RETURN; /* ^M Carriage return */
280 char_map[14] = F_EOL; /* ^N End of line */
281 char_map[15] = F_CONCAT; /* ^O Concatenate lines */
282 char_map[16] = F_MARK; /* ^P Set marker */
283 char_map[17] = F_TINS; /* ^Q Insert character mode */
284 char_map[18] = F_PAGUP; /* ^R Page up */
285 char_map[19] = F_CENTER; /* ^S Center text */
286 char_map[20] = F_PAGDWN; /* ^T Page down */
287 char_map[21] = F_SOL; /* ^U Line start */
288 char_map[22] = F_DELWRD; /* ^V Delete word */
289 char_map[23] = F_PRVWRD; /* ^W Previous word */
290 char_map[24] = F_NXTMCH; /* ^X Next match */
291 char_map[25] = F_DELEOL; /* ^Y Delete to end of line */
292 char_map[26] = F_DELLIN; /* ^Z Delete line */
294 char_map[28] = F_TENTRY; /* ^\ Entry mode */
295 char_map[29] = F_PASTECB;/* ^]=paste clipboard */
296 char_map[30] = F_HOME; /* ^^ Home */
297 char_map[31] = F_ERSLIN; /* ^_ Erase line */
308 * Guarantee that the string is properly terminated */
309 char *bstrncpy(char *dest, const char *src, int maxlen)
311 strncpy(dest, src, maxlen-1);
319 * New style string mapping to function code
321 static unsigned do_smap(unsigned c)
341 for (i=len-1; i<MAX_STAB; i++) {
342 for (tstab=stab[i]; tstab; tstab=tstab->next) {
343 if (strncmp(str, tstab->str, len) == 0) {
344 if (len == tstab->len) {
348 break; /* found possibility continue searching */
355 /* found partial match, so get next character and retry */
356 str[len++] = t_gnc();
362 static void dump_stab()
368 for (i=0; i<MAX_STAB; i++) {
369 for (tstab=stab[i]; tstab; tstab=tstab->next) {
370 for (j=0; j<tstab->len; j++) {
372 if (c < 0x20 || c > 0x7F) {
373 sprintf(buf, " 0x%x ", c);
381 sprintf(buf, " func=%d len=%d\n\r", tstab->func, tstab->len);
389 * New routine. Add string to string->func mapping table.
391 static void add_smap(char *str, int func)
401 /* errmsg("String for func %d is zero length\n", func); */
404 tstab = (stab_t *)malloc(sizeof(stab_t));
405 memset(tstab, 0, sizeof(stab_t));
407 tstab->str = (char *)malloc(tstab->len + 1);
408 bstrncpy(tstab->str, str, tstab->len + 1);
410 if (tstab->len > num_stab) {
411 printf("stab string too long %d. Max is %d\n", tstab->len, num_stab);
414 tstab->next = stab[tstab->len-1];
415 stab[tstab->len-1] = tstab;
416 /* printf("Add_smap tstab=%x len=%d func=%d tstab->next=%x\n\r", tstab, len,
417 func, tstab->next); */
422 /* Get the next character from the terminal - performs table lookup on
423 the character to do the desired translation */
429 if ((c=t_gnc()) <= 599) { /* IBM generates codes up to 260 */
431 } else if (c > 1000) { /* stuffed function */
432 c -= 1000; /* convert back to function code */
437 /* if we got a screen size escape sequence, read height, width */
440 y = t_gnc() - 0x20; /* y */
441 x = t_gnc() - 0x20; /* x */
448 /* Get a complete input line */
451 input_line(char *string, int length)
453 char curline[2000]; /* edit buffer */
460 poolinit(); /* build line pool */
463 noline = 1; /* no line fetched yet */
464 for (cl=cp=0; cl<length && cl<(int)sizeof(curline); ) {
469 switch (c=input_char()) {
470 case F_RETURN: /* CR */
471 t_sendl("\r\n", 2); /* yes, print it and */
472 goto done; /* get out */
473 case F_CLRSCRN: /* clear screen */
475 t_sendl(curline, cl);
479 if (noline) { /* no line fetched yet */
480 getnext(); /* getnext so getprev gets current */
481 noline = 0; /* we now have line */
483 bstrncpy(curline, getprev(), sizeof(curline));
487 noline = 0; /* mark line fetched */
488 bstrncpy(curline, getnext(), sizeof(curline));
492 insert_space(curline, sizeof(curline));
495 delchr(1, curline, sizeof(curline)); /* delete one character */
497 case F_CSRLFT: /* Backspace */
501 forward(curline, sizeof(curline));
503 case F_ERSCHR: /* Rubout */
505 delchr(1, curline, sizeof(curline));
512 t_clrline(0, t_width);
517 i = next_word(curline);
519 forward(curline, sizeof(curline));
523 i = prev_word(curline);
529 delchr(next_word(curline), curline, sizeof(curline)); /* delete word */
531 case F_NXTMCH: /* Ctl-X */
533 *string = EOS; /* terminate string */
534 return(c); /* give it to him */
536 /* Note fall through */
540 backup(curline); /* backup to beginning of line */
542 t_clrline(0, t_width); /* erase line */
544 cl = 0; /* reset cursor counter */
555 forward(curline, sizeof(curline));
561 case F_TINS: /* toggle insert mode */
562 mode_insert = !mode_insert; /* flip bit */
565 if (c > 255) { /* function key hit */
566 if (cl==0) { /* if first character then */
567 *string = EOS; /* terminate string */
568 return c; /* return it */
570 t_honk_horn(); /* complain */
572 if ((c & 0xC0) == 0xC0) {
573 if ((c & 0xFC) == 0xFC) {
575 } else if ((c & 0xF8) == 0xF8) {
577 } else if ((c & 0xF0) == 0xF0) {
579 } else if ((c & 0xE0) == 0xE0) {
588 insert_space(curline, sizeof(curline));
590 curline[cp++] = c; /* store character in line being built */
591 t_char(c); /* echo character to terminal */
594 insert_hole(curline, sizeof(curline));
595 curline[cp++] = c; /* store character in line being built */
596 t_char(c); /* echo character to terminal */
599 cl = cp; /* keep current length */
606 /* If we fall through here rather than goto done, the line is too long
607 simply return what we have now. */
609 curline[cl++] = EOS; /* terminate */
610 bstrncpy(string,curline,length); /* return line to caller */
611 /* Note, put line zaps curline */
612 putline(curline,cl); /* save line for posterity */
613 return 0; /* give it to him/her */
616 /* Insert a space at the current cursor position */
618 insert_space(char *curline, int curline_len)
622 if (cp > cl || cl+1 > curline_len) {
625 /* Note! source and destination overlap */
626 memmove(&curline[cp+1],&curline[cp],i=cl-cp);
631 forward(curline, curline_len);
641 insert_hole(char *curline, int curline_len)
645 if (cp > cl || cl+1 > curline_len) {
648 /* Note! source and destination overlap */
649 memmove(&curline[cp+1], &curline[cp], i=cl-cp);
655 /* Move cursor forward keeping characters under it */
657 forward(char *str, int str_len)
668 if ((str[cp] & 0xC0) == 0xC0) {
670 while ((str[cp] & 0xC0) == 0x80) {
680 /* How many characters under the cursor */
682 char_count(int cptr, char *str)
688 if ((str[cptr] & 0xC0) == 0xC0) {
690 while ((str[cptr] & 0xC0) == 0x80) {
698 /* Backup cursor keeping characters under it */
705 while ((str[cp] & 0xC0) == 0x80) {
712 /* Delete the character under the cursor */
714 delchr(int del, char *curline, int line_len)
718 if (cp > cl || del == 0) {
721 while (del-- && cp > 0) {
722 cnt = char_count(cp, curline);
723 if ((i=cl-cp-cnt) > 0) {
724 memcpy(&curline[cp], &curline[cp+cnt], i);
728 t_clrline(0, t_width);
731 forward(curline, line_len);
740 /* Determine if character is part of a word */
746 if (c >= '0' && c <= '9')
748 if (c == '$' || c == '%')
753 /* Return number of characters to get to next word */
755 next_word(char *ldb_buf)
762 for ( ; ncp<cl && iswordc(*(ldb_buf+ncp)); ncp++) ;
763 for ( ; ncp<cl && !iswordc(*(ldb_buf+ncp)); ncp++) ;
767 /* Return number of characters to get to previous word */
769 prev_word(char *ldb_buf)
773 if (cp == 0) /* if at begin of line stop now */
775 if (cp > cl) /* if past eol start at eol */
779 /* backup to end of previous word - i.e. skip special chars */
780 for (i=ncp-1; i && !iswordc(*(ldb_buf+i)); i--) ;
781 if (i == 0) { /* at beginning of line? */
782 return cp; /* backup to beginning */
784 /* now move back through word to beginning of word */
785 for ( ; i && iswordc(*(ldb_buf+i)); i--) ;
786 ncp = i+1; /* position to first char of word */
787 if (i==0 && iswordc(*ldb_buf)) /* check for beginning of line */
789 return cp-ncp; /* return count */
792 /* Display new current line */
799 t_clrline(0,t_width);
800 cp = cl = strlen(str);
805 /* Initialize line pool. Split pool into two pieces. */
809 slptr = lptr = (struct lstr *)pool;
818 /* Return pointer to next line in the pool and advance current line pointer */
822 do { /* find next used line */
824 } while (!lptr->used);
825 return (char *)&lptr->line;
828 /* Return pointer to previous line in the pool */
832 do { /* find previous used line */
834 } while (!lptr->used);
835 return (char *)&lptr->line;
839 putline(char *newl, int newlen)
841 struct lstr *nptr; /* points to next line */
844 lptr = slptr; /* get ptr to last line stored */
845 lptr = lptr->nextl; /* advance pointer */
846 if ((char *)lptr-pool+newlen+PHDRL > POOLEN) { /* not enough room */
847 lptr->used = 0; /* delete line */
848 lptr = (struct lstr *)pool; /* start at beginning of buffer */
850 while (lptr->len < newlen+PHDRL) { /* concatenate buffers */
851 nptr = lptr->nextl; /* point to next line */
852 lptr->nextl = nptr->nextl; /* unlink it from list */
853 nptr->nextl->prevl = lptr;
854 lptr->len += nptr->len;
856 if (lptr->len > newlen + 2 * PHDRL) { /* split buffer */
857 nptr = (struct lstr *)((char *)lptr + newlen + PHDRL);
858 /* Appropriate byte alignment - normally 2 byte, but on
859 sparc we need 4 byte alignment, so we always do 4 */
860 if (((long unsigned)nptr & 3) != 0) { /* test four byte alignment */
862 nptr = (struct lstr *)((((long unsigned) p) & ~3) + 4);
864 nptr->len = lptr->len - ((char *)nptr - (char *)lptr);
865 lptr->len -= nptr->len;
866 nptr->nextl = lptr->nextl; /* link in new buffer */
867 lptr->nextl->prevl = nptr;
872 memcpy(&lptr->line,newl,newlen);
873 lptr->used = 1; /* mark line used */
874 slptr = lptr; /* save as stored line */
879 dump(struct lstr *ptr, char *msg)
881 printf("%s buf=%x nextl=%x prevl=%x len=%d used=%d\n",
882 msg,ptr,ptr->nextl,ptr->prevl,ptr->len,ptr->used);
884 printf("line=%s\n",&ptr->line);
886 #endif /* DEBUGOUT */
889 /* Honk horn on terminal */
896 /* Insert line on terminal */
903 /* Delete line from terminal */
910 /* clear line from pos to width */
912 t_clrline(int pos, int width)
914 asclrl(pos, width); /* clear to end of line */
917 /* Helper function to add string preceded by
918 * ESC to smap table */
919 static void add_esc_smap(const char *str, int func)
922 buf[0] = 0x1B; /* esc */
923 bstrncpy(buf+1, str, sizeof(buf)-1);
927 /* Set raw mode on terminal file. Basically, get the terminal into a
928 mode in which all characters can be read as they are entered. CBREAK
929 mode is not sufficient.
931 static void rawmode(FILE *input)
934 static char term_buf[2048];
935 static char *term_buffer = term_buf;
936 char *termtype = (char *)getenv("TERM");
938 /* Make sure we are dealing with a terminal */
939 if (!isatty(fileno(input))) {
942 if (tcgetattr(0, &old_term_params) != 0) {
943 printf("conio: Cannot tcgetattr()\n");
946 old_term_params_set = true;
948 t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
950 t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK |
951 ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);
954 t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON |
956 tcflush(0, TCIFLUSH);
957 if (tcsetattr(0, TCSANOW, &t) == -1) {
958 printf("Cannot tcsetattr()\n");
961 /* Defaults, the main program can override these */
962 signal(SIGQUIT, SIG_IGN);
963 signal(SIGHUP, SIG_IGN);
964 signal(SIGINT, sigintcatcher);
965 signal(SIGWINCH, SIG_IGN);
968 printf("Cannot get terminal type.\n");
972 if (tgetent(term_buffer, termtype) < 0) {
973 printf("Cannot get terminal termcap entry.\n");
977 t_width = t_height = -1;
978 t_width = tgetnum("co") - 1;
979 t_height = tgetnum("li");
982 t_cm = (char *)tgetstr("cm", &term_buffer);
983 t_cs = (char *)tgetstr("cl", &term_buffer); /* clear screen */
984 t_cl = (char *)tgetstr("ce", &term_buffer); /* clear line */
985 t_dl = (char *)tgetstr("dl", &term_buffer); /* delete line */
986 t_il = (char *)tgetstr("al", &term_buffer); /* insert line */
987 t_honk = (char *)tgetstr("bl", &term_buffer); /* beep */
988 t_ti = (char *)tgetstr("ti", &term_buffer);
989 t_te = (char *)tgetstr("te", &term_buffer);
990 t_up = (char *)tgetstr("up", &term_buffer);
991 t_do = (char *)tgetstr("do", &term_buffer);
992 t_sf = (char *)tgetstr("sf", &term_buffer);
994 num_stab = MAX_STAB; /* get default stab size */
995 stab = (stab_t **)malloc(sizeof(stab_t *) * num_stab);
996 memset(stab, 0, sizeof(stab_t *) * num_stab);
999 kl = (char *)tgetstr("kl", &term_buffer);
1000 kr = (char *)tgetstr("kr", &term_buffer);
1001 ku = (char *)tgetstr("ku", &term_buffer);
1002 kd = (char *)tgetstr("kd", &term_buffer);
1003 kh = (char *)tgetstr("kh", &term_buffer);
1004 kb = (char *)tgetstr("kb", &term_buffer);
1005 kD = (char *)tgetstr("kD", &term_buffer);
1006 kI = (char *)tgetstr("kI", &term_buffer);
1007 kN = (char *)tgetstr("kN", &term_buffer);
1008 kP = (char *)tgetstr("kP", &term_buffer);
1009 kH = (char *)tgetstr("kH", &term_buffer);
1010 kE = (char *)tgetstr("kE", &term_buffer);
1012 add_smap(kl, F_CSRLFT);
1013 add_smap(kr, F_CSRRGT);
1014 add_smap(ku, F_CSRUP);
1015 add_smap(kd, F_CSRDWN);
1016 add_smap(kI, F_TINS);
1017 add_smap(kN, F_PAGDWN);
1018 add_smap(kP, F_PAGUP);
1019 add_smap(kH, F_HOME);
1020 add_smap(kE, F_EOF);
1023 add_esc_smap("[A", F_CSRUP);
1024 add_esc_smap("[B", F_CSRDWN);
1025 add_esc_smap("[C", F_CSRRGT);
1026 add_esc_smap("[D", F_CSRLFT);
1027 add_esc_smap("[1~", F_HOME);
1028 add_esc_smap("[2~", F_TINS);
1029 add_esc_smap("[3~", F_DELCHR);
1030 add_esc_smap("[4~", F_EOF);
1031 add_esc_smap("f", F_NXTWRD);
1032 add_esc_smap("b", F_PRVWRD);
1036 /* Restore tty mode */
1037 static void normode()
1039 if (old_term_params_set) {
1040 tcsetattr(0, TCSANOW, &old_term_params);
1041 old_term_params_set = false;
1045 /* Get next character from terminal/script file/unget buffer */
1053 /* Get next character from OS */
1054 static unsigned t_getch(void)
1058 if (read(0, &c, 1) != 1) {
1064 /* Send message to terminal - primitive routine */
1066 t_sendl(const char *msg, int len)
1072 t_send(const char *msg)
1077 t_sendl(msg, strlen(msg)); /* faster than one char at time */
1080 /* Send single character to terminal - primitive routine - */
1084 (void)write(1, &c, 1);
1088 static int brkflg = 0; /* set on user break */
1090 /* Routine to return true if user types break */
1096 /* Clear break flag */
1103 /* Interrupt caught here */
1104 static void sigintcatcher(int sig)
1111 signal(SIGINT, sigintcatcher);
1118 signal(SIGINT, sigintcatcher);
1122 /* ASCLRL() -- Clear to end of line from current position */
1123 static void asclrl(int pos, int width)
1128 t_send(t_cl); /* use clear to eol function */
1131 if (pos==1 && linsdel_ok) {
1132 t_delete_line(); /* delete line */
1133 t_insert_line(); /* reinsert it */
1136 for (i=1; i<=width-pos+1; i++)
1137 t_char(' '); /* last resort, blank it out */
1138 for (i=1; i<=width-pos+1; i++) /* backspace to original position */
1145 /* ASCURS -- Set cursor position */
1146 static void ascurs(int y, int x)
1148 t_send((char *)tgoto(t_cm, x, y));
1152 /* ASCLRS -- Clear whole screen */
1153 static void asclrs()
1161 /* ASINSL -- insert new line after cursor */
1162 static void asinsl()
1164 t_clrline(0, t_width);
1165 t_send(t_il); /* insert before */
1168 /* ASDELL -- Delete line at cursor */
1169 static void asdell()