root/src/noitedit/term.c

Revision bafab25395cb398ddf5eae42145f0d0bfc00ec22, 37.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 11 years ago)

import of libedit... prepare to hack

  • Property mode set to 100644
Line 
1 /*      $NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek Exp $       */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "compat.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)term.c      8.2 (Berkeley) 4/30/95";
43 #else
44 __RCSID("$NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47 /*
48  * term.c: Editor/termcap-curses interface
49  *         We have to declare a static variable here, since the
50  *         termcap putchar routine does not take an argument!
51  */
52 #include "sys.h"
53 #include <stdio.h>
54 #include <signal.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #if HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 #if !_MSC_VER
61 #include <curses.h>
62 #ifndef NCURSES_CONST
63 /* ncurses conflicts with termcap on some boxes... and supersets it. */
64 #ifdef HAVE_TERMCAP_H
65 #include <termcap.h>
66 #endif
67 #endif
68 #include <sys/types.h>
69 #include <sys/ioctl.h>
70 #endif
71
72 #include "el.h"
73
74 /*
75  * IMPORTANT NOTE: these routines are allowed to look at the current screen
76  * and the current possition assuming that it is correct.  If this is not
77  * true, then the update will be WRONG!  This is (should be) a valid
78  * assumption...
79  */
80
81 #define TC_BUFSIZE      2048
82
83 #define GoodStr(a)      (el->el_term.t_str[a] != NULL && \
84                             el->el_term.t_str[a][0] != '\0')
85 #define Str(a)          el->el_term.t_str[a]
86 #define Val(a)          el->el_term.t_val[a]
87 extern char *tgoto(const char *, int, int);
88 #ifdef __SUNPRO_C
89 extern char *tgetstr(char *id, char **area);
90 #endif
91
92 #ifdef notdef
93 private const struct {
94         const char *b_name;
95         int b_rate;
96 } baud_rate[] = {
97 #ifdef B0
98         { "0", B0 },
99 #endif
100 #ifdef B50
101         { "50", B50 },
102 #endif
103 #ifdef B75
104         { "75", B75 },
105 #endif
106 #ifdef B110
107         { "110", B110 },
108 #endif
109 #ifdef B134
110         { "134", B134 },
111 #endif
112 #ifdef B150
113         { "150", B150 },
114 #endif
115 #ifdef B200
116         { "200", B200 },
117 #endif
118 #ifdef B300
119         { "300", B300 },
120 #endif
121 #ifdef B600
122         { "600", B600 },
123 #endif
124 #ifdef B900
125         { "900", B900 },
126 #endif
127 #ifdef B1200
128         { "1200", B1200 },
129 #endif
130 #ifdef B1800
131         { "1800", B1800 },
132 #endif
133 #ifdef B2400
134         { "2400", B2400 },
135 #endif
136 #ifdef B3600
137         { "3600", B3600 },
138 #endif
139 #ifdef B4800
140         { "4800", B4800 },
141 #endif
142 #ifdef B7200
143         { "7200", B7200 },
144 #endif
145 #ifdef B9600
146         { "9600", B9600 },
147 #endif
148 #ifdef EXTA
149         { "19200", EXTA },
150 #endif
151 #ifdef B19200
152         { "19200", B19200 },
153 #endif
154 #ifdef EXTB
155         { "38400", EXTB },
156 #endif
157 #ifdef B38400
158         { "38400", B38400 },
159 #endif
160         { NULL, 0 }
161 };
162 #endif
163
164 private const struct termcapstr {
165         const char *name;
166         const char *long_name;
167 } tstr[] = {
168 #define T_al    0
169         { "al", "add new blank line" },
170 #define T_bl    1
171         { "bl", "audible bell" },
172 #define T_cd    2
173         { "cd", "clear to bottom" },
174 #define T_ce    3
175         { "ce", "clear to end of line" },
176 #define T_ch    4
177         { "ch", "cursor to horiz pos" },
178 #define T_cl    5
179         { "cl", "clear screen" },
180 #define T_dc    6
181         { "dc", "delete a character" },
182 #define T_dl    7
183         { "dl", "delete a line" },
184 #define T_dm    8
185         { "dm", "start delete mode" },
186 #define T_ed    9
187         { "ed", "end delete mode" },
188 #define T_ei    10
189         { "ei", "end insert mode" },
190 #define T_fs    11
191         { "fs", "cursor from status line" },
192 #define T_ho    12
193         { "ho", "home cursor" },
194 #define T_ic    13
195         { "ic", "insert character" },
196 #define T_im    14
197         { "im", "start insert mode" },
198 #define T_ip    15
199         { "ip", "insert padding" },
200 #define T_kd    16
201         { "kd", "sends cursor down" },
202 #define T_kl    17
203         { "kl", "sends cursor left" },
204 #define T_kr    18
205         { "kr", "sends cursor right" },
206 #define T_ku    19
207         { "ku", "sends cursor up" },
208 #define T_md    20
209         { "md", "begin bold" },
210 #define T_me    21
211         { "me", "end attributes" },
212 #define T_nd    22
213         { "nd", "non destructive space" },
214 #define T_se    23
215         { "se", "end standout" },
216 #define T_so    24
217         { "so", "begin standout" },
218 #define T_ts    25
219         { "ts", "cursor to status line" },
220 #define T_up    26
221         { "up", "cursor up one" },
222 #define T_us    27
223         { "us", "begin underline" },
224 #define T_ue    28
225         { "ue", "end underline" },
226 #define T_vb    29
227         { "vb", "visible bell" },
228 #define T_DC    30
229         { "DC", "delete multiple chars" },
230 #define T_DO    31
231         { "DO", "cursor down multiple" },
232 #define T_IC    32
233         { "IC", "insert multiple chars" },
234 #define T_LE    33
235         { "LE", "cursor left multiple" },
236 #define T_RI    34
237         { "RI", "cursor right multiple" },
238 #define T_UP    35
239         { "UP", "cursor up multiple" },
240 #define T_kh    36
241         { "kh", "send cursor home" },
242 #define T_at7   37
243         { "@7", "send cursor end" },
244 #define T_str   38
245         { NULL, NULL }
246 };
247
248 private const struct termcapval {
249         const char *name;
250         const char *long_name;
251 } tval[] = {
252 #define T_am    0
253         { "am", "has automatic margins" },
254 #define T_pt    1
255         { "pt", "has physical tabs" },
256 #define T_li    2
257         { "li", "Number of lines" },
258 #define T_co    3
259         { "co", "Number of columns" },
260 #define T_km    4
261         { "km", "Has meta key" },
262 #define T_xt    5
263         { "xt", "Tab chars destructive" },
264 #define T_xn    6
265         { "xn", "newline ignored at right margin" },
266 #define T_MT    7
267         { "MT", "Has meta key" },                       /* XXX? */
268 #define T_val   8
269         { NULL, NULL, }
270 };
271 /* do two or more of the attributes use me */
272
273 private void    term_setflags(EditLine *);
274 private int     term_rebuffer_display(EditLine *);
275 private void    term_free_display(EditLine *);
276 private int     term_alloc_display(EditLine *);
277 private void    term_alloc(EditLine *, const struct termcapstr *, char *);
278 private void    term_init_arrow(EditLine *);
279 private void    term_reset_arrow(EditLine *);
280
281
282 private FILE *term_outfile = NULL;      /* XXX: How do we fix that? */
283
284
285 /* term_setflags():
286  *      Set the terminal capability flags
287  */
288 private void
289 term_setflags(EditLine *el)
290 {
291         EL_FLAGS = 0;
292         if (el->el_tty.t_tabs)
293                 EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0;
294
295         EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0;
296         EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0;
297         EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0;
298         EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ?
299             TERM_CAN_INSERT : 0;
300         EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0;
301         EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0;
302         EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0;
303
304         if (GoodStr(T_me) && GoodStr(T_ue))
305                 EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ?
306                     TERM_CAN_ME : 0;
307         else
308                 EL_FLAGS &= ~TERM_CAN_ME;
309         if (GoodStr(T_me) && GoodStr(T_se))
310                 EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ?
311                     TERM_CAN_ME : 0;
312
313
314 #ifdef DEBUG_SCREEN
315         if (!EL_CAN_UP) {
316                 (void) fprintf(el->el_errfile,
317                     "WARNING: Your terminal cannot move up.\n");
318                 (void) fprintf(el->el_errfile,
319                     "Editing may be odd for long lines.\n");
320         }
321         if (!EL_CAN_CEOL)
322                 (void) fprintf(el->el_errfile, "no clear EOL capability.\n");
323         if (!EL_CAN_DELETE)
324                 (void) fprintf(el->el_errfile, "no delete char capability.\n");
325         if (!EL_CAN_INSERT)
326                 (void) fprintf(el->el_errfile, "no insert char capability.\n");
327 #endif /* DEBUG_SCREEN */
328 }
329
330
331 /* term_init():
332  *      Initialize the terminal stuff
333  */
334 protected int
335 term_init(EditLine *el)
336 {
337
338         el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE);
339         if (el->el_term.t_buf == NULL)
340                 return (-1);
341         el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE);
342         if (el->el_term.t_cap == NULL)
343                 return (-1);
344         el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t));
345         if (el->el_term.t_fkey == NULL)
346                 return (-1);
347         el->el_term.t_loc = 0;
348         el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *));
349         if (el->el_term.t_str == NULL)
350                 return (-1);
351         (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *));
352         el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int));
353         if (el->el_term.t_val == NULL)
354                 return (-1);
355         (void) memset(el->el_term.t_val, 0, T_val * sizeof(int));
356         term_outfile = el->el_outfile;
357         term_init_arrow(el);
358         if (term_set(el, NULL) == -1)
359                 return (-1);
360         return (0);
361 }
362 /* term_end():
363  *      Clean up the terminal stuff
364  */
365 protected void
366 term_end(EditLine *el)
367 {
368
369         el_free((ptr_t) el->el_term.t_buf);
370         el->el_term.t_buf = NULL;
371         el_free((ptr_t) el->el_term.t_cap);
372         el->el_term.t_cap = NULL;
373         el->el_term.t_loc = 0;
374         el_free((ptr_t) el->el_term.t_str);
375         el->el_term.t_str = NULL;
376         el_free((ptr_t) el->el_term.t_val);
377         el->el_term.t_val = NULL;
378         term_free_display(el);
379 }
380
381
382 /* term_alloc():
383  *      Maintain a string pool for termcap strings
384  */
385 private void
386 term_alloc(EditLine *el, const struct termcapstr *t, char *cap)
387 {
388         char termbuf[TC_BUFSIZE];
389         int tlen, clen;
390         char **tlist = el->el_term.t_str;
391         char **tmp, **str = &tlist[t - tstr];
392
393         if (cap == NULL || *cap == '\0') {
394                 *str = NULL;
395                 return;
396         } else
397                 clen = strlen(cap);
398
399         tlen = *str == NULL ? 0 : strlen(*str);
400
401         /*
402          * New string is shorter; no need to allocate space
403          */
404         if (clen <= tlen) {
405                 (void) strcpy(*str, cap);       /* XXX strcpy is safe */
406                 return;
407         }
408         /*
409          * New string is longer; see if we have enough space to append
410          */
411         if (el->el_term.t_loc + 3 < TC_BUFSIZE) {
412                                                 /* XXX strcpy is safe */
413                 (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc],
414                     cap);
415                 el->el_term.t_loc += clen + 1;  /* one for \0 */
416                 return;
417         }
418         /*
419          * Compact our buffer; no need to check compaction, cause we know it
420          * fits...
421          */
422         tlen = 0;
423         for (tmp = tlist; tmp < &tlist[T_str]; tmp++)
424                 if (*tmp != NULL && *tmp != '\0' && *tmp != *str) {
425                         char *ptr;
426
427                         for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++)
428                                 continue;
429                         termbuf[tlen++] = '\0';
430                 }
431         memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE);
432         el->el_term.t_loc = tlen;
433         if (el->el_term.t_loc + 3 >= TC_BUFSIZE) {
434                 (void) fprintf(el->el_errfile,
435                     "Out of termcap string space.\n");
436                 return;
437         }
438                                         /* XXX strcpy is safe */
439         (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap);
440         el->el_term.t_loc += clen + 1;  /* one for \0 */
441         return;
442 }
443
444
445 /* term_rebuffer_display():
446  *      Rebuffer the display after the screen changed size
447  */
448 private int
449 term_rebuffer_display(EditLine *el)
450 {
451         coord_t *c = &el->el_term.t_size;
452
453         term_free_display(el);
454
455         c->h = Val(T_co);
456         c->v = Val(T_li);
457
458         if (term_alloc_display(el) == -1)
459                 return (-1);
460         return (0);
461 }
462
463
464 /* term_alloc_display():
465  *      Allocate a new display.
466  */
467 private int
468 term_alloc_display(EditLine *el)
469 {
470         int i;
471         char **b;
472         coord_t *c = &el->el_term.t_size;
473
474         b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1)));
475         if (b == NULL)
476                 return (-1);
477         for (i = 0; i < c->v; i++) {
478                 b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1)));
479                 if (b[i] == NULL)
480                         return (-1);
481         }
482         b[c->v] = NULL;
483         el->el_display = b;
484
485         b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1)));
486         if (b == NULL)
487                 return (-1);
488         for (i = 0; i < c->v; i++) {
489                 b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1)));
490                 if (b[i] == NULL)
491                         return (-1);
492         }
493         b[c->v] = NULL;
494         el->el_vdisplay = b;
495         return (0);
496 }
497
498
499 /* term_free_display():
500  *      Free the display buffers
501  */
502 private void
503 term_free_display(EditLine *el)
504 {
505         char **b;
506         char **bufp;
507
508         b = el->el_display;
509         el->el_display = NULL;
510         if (b != NULL) {
511                 for (bufp = b; *bufp != NULL; bufp++)
512                         el_free((ptr_t) * bufp);
513                 el_free((ptr_t) b);
514         }
515         b = el->el_vdisplay;
516         el->el_vdisplay = NULL;
517         if (b != NULL) {
518                 for (bufp = b; *bufp != NULL; bufp++)
519                         el_free((ptr_t) * bufp);
520                 el_free((ptr_t) b);
521         }
522 }
523
524
525 /* term_move_to_line():
526  *      move to line <where> (first line == 0)
527  *      as efficiently as possible
528  */
529 protected void
530 term_move_to_line(EditLine *el, int where)
531 {
532         int del;
533 #if _WIN32
534         if (win32_native_console()) {
535                 win32_move_to_line(el, where - el->el_cursor.v);
536                 el->el_cursor.v = where;/* now where is here */
537                 return;
538         }
539 #endif
540
541         if (where == el->el_cursor.v)
542                 return;
543
544         if (where > el->el_term.t_size.v) {
545 #ifdef DEBUG_SCREEN
546                 (void) fprintf(el->el_errfile,
547                     "term_move_to_line: where is ridiculous: %d\r\n", where);
548 #endif /* DEBUG_SCREEN */
549                 return;
550         }
551         if ((del = where - el->el_cursor.v) > 0) {
552                 while (del > 0) {
553                         if (EL_HAS_AUTO_MARGINS &&
554                             el->el_display[el->el_cursor.v][0] != '\0') {
555                                 /* move without newline */
556                                 term_move_to_char(el, el->el_term.t_size.h - 1);
557                                 term_overwrite(el,
558                                     &el->el_display[el->el_cursor.v][el->el_cursor.h],
559                                     1);
560                                 /* updates Cursor */
561                                 del--;
562                         } else {
563                                 if ((del > 1) && GoodStr(T_DO)) {
564                                         (void) tputs(tgoto(Str(T_DO), del, del),
565                                             del, term__putc);
566                                         del = 0;
567                                 } else {
568                                         for (; del > 0; del--)
569                                                 term__putc('\n');
570                                         /* because the \n will become \r\n */
571                                         el->el_cursor.h = 0;
572                                 }
573                         }
574                 }
575         } else {                /* del < 0 */
576                 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
577                         (void) tputs(tgoto(Str(T_UP), -del, -del), -del,
578                             term__putc);
579                 else {
580                         if (GoodStr(T_up))
581                                 for (; del < 0; del++)
582                                         (void) tputs(Str(T_up), 1, term__putc);
583                 }
584         }
585         el->el_cursor.v = where;/* now where is here */
586 }
587
588
589 /* term_move_to_char():
590  *      Move to the character position specified
591  */
592 protected void
593 term_move_to_char(EditLine *el, int where)
594 {
595         int del, i;
596 #if _WIN32
597         if (win32_native_console()) {
598                 win32_move_to_char(el, where);
599                 return;
600         }
601 #endif
602
603 mc_again:
604         if (where == el->el_cursor.h)
605                 return;
606
607         if (where > el->el_term.t_size.h) {
608 #ifdef DEBUG_SCREEN
609                 (void) fprintf(el->el_errfile,
610                     "term_move_to_char: where is riduculous: %d\r\n", where);
611 #endif /* DEBUG_SCREEN */
612                 return;
613         }
614         if (!where) {           /* if where is first column */
615                 term__putc('\r');       /* do a CR */
616                 el->el_cursor.h = 0;
617                 return;
618         }
619         del = where - el->el_cursor.h;
620
621         if ((del < -4 || del > 4) && GoodStr(T_ch))
622                 /* go there directly */
623                 (void) tputs(tgoto(Str(T_ch), where, where), where, term__putc);
624         else {
625                 if (del > 0) {  /* moving forward */
626                         if ((del > 4) && GoodStr(T_RI))
627                                 (void) tputs(tgoto(Str(T_RI), del, del),
628                                     del, term__putc);
629                         else {
630                                         /* if I can do tabs, use them */
631                                 if (EL_CAN_TAB) {
632                                         if ((el->el_cursor.h & 0370) !=
633                                             (where & 0370)) {
634                                                 /* if not within tab stop */
635                                                 for (i =
636                                                     (el->el_cursor.h & 0370);
637                                                     i < (where & 0370);
638                                                     i += 8)
639                                                         term__putc('\t');       
640                                                         /* then tab over */
641                                                 el->el_cursor.h = where & 0370;
642                                         }
643                                 }
644                                 /*
645                                  * it's usually cheaper to just write the
646                                  * chars, so we do.
647                                  */
648                                 /*
649                                  * NOTE THAT term_overwrite() WILL CHANGE
650                                  * el->el_cursor.h!!!
651                                  */
652                                 term_overwrite(el,
653                                     &el->el_display[el->el_cursor.v][el->el_cursor.h],
654                                     where - el->el_cursor.h);
655
656                         }
657                 } else {        /* del < 0 := moving backward */
658                         if ((-del > 4) && GoodStr(T_LE))
659                                 (void) tputs(tgoto(Str(T_LE), -del, -del),
660                                     -del, term__putc);
661                         else {  /* can't go directly there */
662                                 /*
663                                  * if the "cost" is greater than the "cost"
664                                  * from col 0
665                                  */
666                                 if (EL_CAN_TAB ?
667                                     (-del > (((unsigned int) where >> 3) +
668                                      (where & 07)))
669                                     : (-del > where)) {
670                                         term__putc('\r');       /* do a CR */
671                                         el->el_cursor.h = 0;
672                                         goto mc_again;  /* and try again */
673                                 }
674                                 for (i = 0; i < -del; i++)
675                                         term__putc('\b');
676                         }
677                 }
678         }
679         el->el_cursor.h = where;                /* now where is here */
680 }
681
682
683 /* term_overwrite():
684  *      Overstrike num characters
685  */
686 protected void
687 term_overwrite(EditLine *el, char *cp, int n)
688 {
689         if (n <= 0)
690                 return;         /* catch bugs */
691
692         if (n > el->el_term.t_size.h) {
693 #ifdef DEBUG_SCREEN
694                 (void) fprintf(el->el_errfile,
695                     "term_overwrite: n is riduculous: %d\r\n", n);
696 #endif /* DEBUG_SCREEN */
697                 return;
698         }
699         do {
700                 term__putc(*cp++);
701                 el->el_cursor.h++;
702         } while (--n);
703
704         if (el->el_cursor.h >= el->el_term.t_size.h) {  /* wrap? */
705                 if (EL_HAS_AUTO_MARGINS) {      /* yes */
706                         el->el_cursor.h = 0;
707                         el->el_cursor.v++;
708                         if (EL_HAS_MAGIC_MARGINS) {
709                                 /* force the wrap to avoid the "magic"
710                                  * situation */
711                                 char c;
712                                 if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h])
713                                     != '\0')
714                                         term_overwrite(el, &c, 1);
715                                 else
716                                         term__putc(' ');
717                                 el->el_cursor.h = 1;
718                         }
719                 } else          /* no wrap, but cursor stays on screen */
720                         el->el_cursor.h = el->el_term.t_size.h;
721         }
722 }
723
724
725 /* term_deletechars():
726  *      Delete num characters
727  */
728 protected void
729 term_deletechars(EditLine *el, int num)
730 {
731         if (num <= 0)
732                 return;
733
734         if (!EL_CAN_DELETE) {
735 #ifdef DEBUG_EDIT
736                 (void) fprintf(el->el_errfile, "   ERROR: cannot delete   \n");
737 #endif /* DEBUG_EDIT */
738                 return;
739         }
740         if (num > el->el_term.t_size.h) {
741 #ifdef DEBUG_SCREEN
742                 (void) fprintf(el->el_errfile,
743                     "term_deletechars: num is riduculous: %d\r\n", num);
744 #endif /* DEBUG_SCREEN */
745                 return;
746         }
747         if (GoodStr(T_DC))      /* if I have multiple delete */
748                 if ((num > 1) || !GoodStr(T_dc)) {      /* if dc would be more
749                                                          * expen. */
750                         (void) tputs(tgoto(Str(T_DC), num, num),
751                             num, term__putc);
752                         return;
753                 }
754         if (GoodStr(T_dm))      /* if I have delete mode */
755                 (void) tputs(Str(T_dm), 1, term__putc);
756
757         if (GoodStr(T_dc))      /* else do one at a time */
758                 while (num--)
759                         (void) tputs(Str(T_dc), 1, term__putc);
760
761         if (GoodStr(T_ed))      /* if I have delete mode */
762                 (void) tputs(Str(T_ed), 1, term__putc);
763 }
764
765
766 /* term_insertwrite():
767  *      Puts terminal in insert character mode or inserts num
768  *      characters in the line
769  */
770 protected void
771 term_insertwrite(EditLine *el, char *cp, int num)
772 {
773         if (num <= 0)
774                 return;
775         if (!EL_CAN_INSERT) {
776 #ifdef DEBUG_EDIT
777                 (void) fprintf(el->el_errfile, "   ERROR: cannot insert   \n");
778 #endif /* DEBUG_EDIT */
779                 return;
780         }
781         if (num > el->el_term.t_size.h) {
782 #ifdef DEBUG_SCREEN
783                 (void) fprintf(el->el_errfile,
784                     "StartInsert: num is riduculous: %d\r\n", num);
785 #endif /* DEBUG_SCREEN */
786                 return;
787         }
788         if (GoodStr(T_IC))      /* if I have multiple insert */
789                 if ((num > 1) || !GoodStr(T_ic)) {
790                                 /* if ic would be more expensive */
791                         (void) tputs(tgoto(Str(T_IC), num, num),
792                             num, term__putc);
793                         term_overwrite(el, cp, num);
794                                 /* this updates el_cursor.h */
795                         return;
796                 }
797         if (GoodStr(T_im) && GoodStr(T_ei)) {   /* if I have insert mode */
798                 (void) tputs(Str(T_im), 1, term__putc);
799
800                 el->el_cursor.h += num;
801                 do
802                         term__putc(*cp++);
803                 while (--num);
804
805                 if (GoodStr(T_ip))      /* have to make num chars insert */
806                         (void) tputs(Str(T_ip), 1, term__putc);
807
808                 (void) tputs(Str(T_ei), 1, term__putc);
809                 return;
810         }
811         do {
812                 if (GoodStr(T_ic))      /* have to make num chars insert */
813                         (void) tputs(Str(T_ic), 1, term__putc);
814                                         /* insert a char */
815
816                 term__putc(*cp++);
817
818                 el->el_cursor.h++;
819
820                 if (GoodStr(T_ip))      /* have to make num chars insert */
821                         (void) tputs(Str(T_ip), 1, term__putc);
822                                         /* pad the inserted char */
823
824         } while (--num);
825 }
826
827
828 /* term_clear_EOL():
829  *      clear to end of line.  There are num characters to clear
830  */
831 protected void
832 term_clear_EOL(EditLine *el, int num)
833 {
834         int i;
835 #ifdef _WIN32
836         if (win32_native_console()) {
837                 win32_term_clear_EOL();
838                 return;
839         }
840 #endif
841         if (EL_CAN_CEOL && GoodStr(T_ce))
842                 (void) tputs(Str(T_ce), 1, term__putc);
843         else {
844                 for (i = 0; i < num; i++)
845                         term__putc(' ');
846                 el->el_cursor.h += num; /* have written num spaces */
847         }
848 }
849
850
851 /* term_clear_screen():
852  *      Clear the screen
853  */
854 protected void
855 term_clear_screen(EditLine *el)
856 {                               /* clear the whole screen and home */
857 #if _WIN32
858         if (win32_native_console()) {
859                 win32_term_clear_screen();
860                 return;
861         }
862 #endif
863         if (GoodStr(T_cl))
864                 /* send the clear screen code */
865                 (void) tputs(Str(T_cl), Val(T_li), term__putc);
866         else if (GoodStr(T_ho) && GoodStr(T_cd)) {
867                 (void) tputs(Str(T_ho), Val(T_li), term__putc); /* home */
868                 /* clear to bottom of screen */
869                 (void) tputs(Str(T_cd), Val(T_li), term__putc);
870         } else {
871                 term__putc('\r');
872                 term__putc('\n');
873         }
874 }
875
876
877 /* term_beep():
878  *      Beep the way the terminal wants us
879  */
880 protected void
881 term_beep(EditLine *el)
882 {
883         if (GoodStr(T_bl))
884                 /* what termcap says we should use */
885                 (void) tputs(Str(T_bl), 1, term__putc);
886         else
887                 term__putc('\007');     /* an ASCII bell; ^G */
888 }
889
890
891 #ifdef notdef
892 /* term_clear_to_bottom():
893  *      Clear to the bottom of the screen
894  */
895 protected void
896 term_clear_to_bottom(EditLine *el)
897 {
898         if (GoodStr(T_cd))
899                 (void) tputs(Str(T_cd), Val(T_li), term__putc);
900         else if (GoodStr(T_ce))
901                 (void) tputs(Str(T_ce), Val(T_li), term__putc);
902 }
903 #endif
904
905
906 /* term_set():
907  *      Read in the terminal capabilities from the requested terminal
908  */
909 protected int
910 term_set(EditLine *el, char *term)
911 {
912         int i;
913         char buf[TC_BUFSIZE];
914         char *area;
915         const struct termcapstr *t;
916 #if !_WIN32
917         sigset_t oset, nset;
918 #endif
919         int lins, cols;
920
921 #if !_WIN32
922         (void) sigemptyset(&nset);
923         (void) sigaddset(&nset, SIGWINCH);
924         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
925 #endif
926
927         area = buf;
928
929 #if _WIN32
930         term = win32_native_console() ? "pcansi" : "xterm";
931 #else
932         if (term == NULL)
933                 term = getenv("TERM");
934
935         if (!term || !term[0])
936                 term = "dumb";
937
938         if (strcmp(term, "emacs") == 0)
939                 el->el_flags |= EDIT_DISABLED;
940 #endif
941
942         memset(el->el_term.t_cap, 0, TC_BUFSIZE);
943
944         i = tgetent(el->el_term.t_cap, term);
945
946         if (i <= 0) {
947                 if (i == -1)
948                         (void) fprintf(el->el_errfile,
949                             "Cannot read termcap database;\n");
950                 else if (i == 0)
951                         (void) fprintf(el->el_errfile,
952                             "No entry for terminal type \"%s\";\n", term);
953                 (void) fprintf(el->el_errfile,
954                     "using dumb terminal settings.\n");
955                 Val(T_co) = 80; /* do a dumb terminal */
956                 Val(T_pt) = Val(T_km) = Val(T_li) = 0;
957                 Val(T_xt) = Val(T_MT);
958                 for (t = tstr; t->name != NULL; t++)
959                         term_alloc(el, t, NULL);
960         } else {
961                 /* auto/magic margins */
962                 Val(T_am) = tgetflag("am");
963                 Val(T_xn) = tgetflag("xn");
964                 /* Can we tab */
965                 Val(T_pt) = tgetflag("pt");
966                 Val(T_xt) = tgetflag("xt");
967                 /* do we have a meta? */
968                 Val(T_km) = tgetflag("km");
969                 Val(T_MT) = tgetflag("MT");
970                 /* Get the size */
971                 Val(T_co) = tgetnum("co");
972                 Val(T_li) = tgetnum("li");
973                 for (t = tstr; t->name != NULL; t++)
974                         term_alloc(el, t, tgetstr((char *)t->name, &area));
975         }
976
977         if (Val(T_co) < 2)
978                 Val(T_co) = 80; /* just in case */
979         if (Val(T_li) < 1)
980                 Val(T_li) = 24;
981
982         el->el_term.t_size.v = Val(T_co);
983         el->el_term.t_size.h = Val(T_li);
984
985         term_setflags(el);
986
987                                 /* get the correct window size */
988         (void) term_get_size(el, &lins, &cols);
989         if (term_change_size(el, lins, cols) == -1)
990                 return (-1);
991 #if !_WIN32
992         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
993 #endif
994         term_bind_arrow(el);
995         return (i <= 0 ? -1 : 0);
996 }
997
998 int libedit_term_get_size(int fd, int *lins, int *cols)
999 {
1000 #ifdef TIOCGWINSZ
1001         {
1002                 struct winsize ws;
1003                 if (ioctl(fd, TIOCGWINSZ, (ioctl_t) & ws) != -1) {
1004                         if (ws.ws_col)
1005                                 *cols = ws.ws_col;
1006                         if (ws.ws_row)
1007                                 *lins = ws.ws_row;
1008                         return 1;
1009                 }
1010         }
1011 #endif
1012 #ifdef TIOCGSIZE
1013         {
1014                 struct ttysize ts;
1015                 if (ioctl(fd, TIOCGSIZE, (ioctl_t) & ts) != -1) {
1016                         if (ts.ts_cols)
1017                                 *cols = ts.ts_cols;
1018                         if (ts.ts_lines)
1019                                 *lins = ts.ts_lines;
1020                         return 1;
1021                 }
1022         }
1023 #endif
1024 #if _WIN32
1025         return win32_term_get_size(lins, cols);
1026 #endif
1027         return 0;
1028 }
1029
1030 /* term_get_size():
1031  *      Return the new window size in lines and cols, and
1032  *      true if the size was changed.
1033  */
1034 protected int
1035 term_get_size(EditLine *el, int *lins, int *cols)
1036 {
1037         *cols = Val(T_co);
1038         *lins = Val(T_li);
1039
1040         libedit_term_get_size(el->el_infd, lins, cols);
1041
1042         return (Val(T_co) != *cols || Val(T_li) != *lins);
1043 }
1044
1045
1046 /* term_change_size():
1047  *      Change the size of the terminal
1048  */
1049 protected int
1050 term_change_size(EditLine *el, int lins, int cols)
1051 {
1052         /*
1053          * Just in case
1054          */
1055         Val(T_co) = (cols < 2) ? 80 : cols;
1056         Val(T_li) = (lins < 1) ? 24 : lins;
1057
1058         /* re-make display buffers */
1059         if (term_rebuffer_display(el) == -1)
1060                 return (-1);
1061         re_clear_display(el);
1062         return (0);
1063 }
1064
1065
1066 /* term_init_arrow():
1067  *      Initialize the arrow key bindings from termcap
1068  */
1069 private void
1070 term_init_arrow(EditLine *el)
1071 {
1072         fkey_t *arrow = el->el_term.t_fkey;
1073
1074         arrow[A_K_DN].name = "down";
1075         arrow[A_K_DN].key = T_kd;
1076         arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY;
1077         arrow[A_K_DN].type = XK_CMD;
1078
1079         arrow[A_K_UP].name = "up";
1080         arrow[A_K_UP].key = T_ku;
1081         arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY;
1082         arrow[A_K_UP].type = XK_CMD;
1083
1084         arrow[A_K_LT].name = "left";
1085         arrow[A_K_LT].key = T_kl;
1086         arrow[A_K_LT].fun.cmd = ED_PREV_CHAR;
1087         arrow[A_K_LT].type = XK_CMD;
1088
1089         arrow[A_K_RT].name = "right";
1090         arrow[A_K_RT].key = T_kr;
1091         arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR;
1092         arrow[A_K_RT].type = XK_CMD;
1093
1094         arrow[A_K_HO].name = "home";
1095         arrow[A_K_HO].key = T_kh;
1096         arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG;
1097         arrow[A_K_HO].type = XK_CMD;
1098
1099         arrow[A_K_EN].name = "end";
1100         arrow[A_K_EN].key = T_at7;
1101         arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END;
1102         arrow[A_K_EN].type = XK_CMD;
1103 }
1104
1105
1106 /* term_reset_arrow():
1107  *      Reset arrow key bindings
1108  */
1109 private void
1110 term_reset_arrow(EditLine *el)
1111 {
1112         fkey_t *arrow = el->el_term.t_fkey;
1113         static const char strA[] = {033, '[', 'A', '\0'};
1114         static const char strB[] = {033, '[', 'B', '\0'};
1115         static const char strC[] = {033, '[', 'C', '\0'};
1116         static const char strD[] = {033, '[', 'D', '\0'};
1117         static const char strH[] = {033, '[', 'H', '\0'};
1118         static const char strF[] = {033, '[', 'F', '\0'};
1119         static const char stOA[] = {033, 'O', 'A', '\0'};
1120         static const char stOB[] = {033, 'O', 'B', '\0'};
1121         static const char stOC[] = {033, 'O', 'C', '\0'};
1122         static const char stOD[] = {033, 'O', 'D', '\0'};
1123         static const char stOH[] = {033, 'O', 'H', '\0'};
1124         static const char stOF[] = {033, 'O', 'F', '\0'};
1125
1126         key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
1127         key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
1128         key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
1129         key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
1130         key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
1131         key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
1132         key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
1133         key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
1134         key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
1135         key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
1136         key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
1137         key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
1138
1139         if (el->el_map.type == MAP_VI) {
1140                 key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
1141                 key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
1142                 key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
1143                 key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
1144                 key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
1145                 key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
1146                 key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
1147                 key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
1148                 key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
1149                 key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
1150                 key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
1151                 key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
1152         }
1153 }
1154
1155
1156 /* term_set_arrow():
1157  *      Set an arrow key binding
1158  */
1159 protected int
1160 term_set_arrow(EditLine *el, char *name, key_value_t *fun, int type)
1161 {
1162         fkey_t *arrow = el->el_term.t_fkey;
1163         int i;
1164
1165         for (i = 0; i < A_K_NKEYS; i++)
1166                 if (strcmp(name, arrow[i].name) == 0) {
1167                         arrow[i].fun = *fun;
1168                         arrow[i].type = type;
1169                         return (0);
1170                 }
1171         return (-1);
1172 }
1173
1174
1175 /* term_clear_arrow():
1176  *      Clear an arrow key binding
1177  */
1178 protected int
1179 term_clear_arrow(EditLine *el, char *name)
1180 {
1181         fkey_t *arrow = el->el_term.t_fkey;
1182         int i;
1183
1184         for (i = 0; i < A_K_NKEYS; i++)
1185                 if (strcmp(name, arrow[i].name) == 0) {
1186                         arrow[i].type = XK_NOD;
1187                         return (0);
1188                 }
1189         return (-1);
1190 }
1191
1192
1193 /* term_print_arrow():
1194  *      Print the arrow key bindings
1195  */
1196 protected void
1197 term_print_arrow(EditLine *el, char *name)
1198 {
1199         int i;
1200         fkey_t *arrow = el->el_term.t_fkey;
1201
1202         for (i = 0; i < A_K_NKEYS; i++)
1203                 if (*name == '\0' || strcmp(name, arrow[i].name) == 0)
1204                         if (arrow[i].type != XK_NOD)
1205                                 key_kprint(el, arrow[i].name, &arrow[i].fun,
1206                                     arrow[i].type);
1207 }
1208
1209
1210 /* term_bind_arrow():
1211  *      Bind the arrow keys
1212  */
1213 protected void
1214 term_bind_arrow(EditLine *el)
1215 {
1216         el_action_t *map;
1217         const el_action_t *dmap;
1218         int i, j;
1219         char *p;
1220         fkey_t *arrow = el->el_term.t_fkey;
1221
1222         /* Check if the components needed are initialized */
1223         if (el->el_term.t_buf == NULL || el->el_map.key == NULL) {
1224                 return;
1225         }
1226        
1227         map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key;
1228         dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs;
1229
1230         term_reset_arrow(el);
1231
1232         for (i = 0; i < A_K_NKEYS; i++) {
1233                 p = el->el_term.t_str[arrow[i].key];
1234                 if (p && *p) {
1235                         j = (unsigned char) *p;
1236                         /*
1237                          * Assign the arrow keys only if:
1238                          *
1239                          * 1. They are multi-character arrow keys and the user
1240                          *    has not re-assigned the leading character, or
1241                          *    has re-assigned the leading character to be
1242                          *        ED_SEQUENCE_LEAD_IN
1243                          * 2. They are single arrow keys pointing to an
1244                          *    unassigned key.
1245                          */
1246                         if (arrow[i].type == XK_NOD)
1247                                 key_clear(el, map, p);
1248                         else {
1249                                 if (p[1] && (dmap[j] == map[j] ||
1250                                         map[j] == ED_SEQUENCE_LEAD_IN)) {
1251                                         key_add(el, p, &arrow[i].fun,
1252                                             arrow[i].type);
1253                                         map[j] = ED_SEQUENCE_LEAD_IN;
1254                                 } else if (map[j] == ED_UNASSIGNED) {
1255                                         key_clear(el, map, p);
1256                                         if (arrow[i].type == XK_CMD)
1257                                                 map[j] = arrow[i].fun.cmd;
1258                                         else
1259                                                 key_add(el, p, &arrow[i].fun,
1260                                                     arrow[i].type);
1261                                 }
1262                         }
1263                 }
1264         }
1265 }
1266
1267
1268 /* term__putc():
1269  *      Add a character
1270  */
1271 protected int
1272 term__putc(int c)
1273 {
1274
1275         return (fputc(c, term_outfile));
1276 }
1277
1278
1279 /* term__flush():
1280  *      Flush output
1281  */
1282 protected void
1283 term__flush(void)
1284 {
1285
1286         (void) fflush(term_outfile);
1287 }
1288
1289
1290 /* term_telltc():
1291  *      Print the current termcap characteristics
1292  */
1293 protected int
1294 /*ARGSUSED*/
1295 term_telltc(EditLine *el, int argc, char **argv)
1296 {
1297         const struct termcapstr *t;
1298         char **ts;
1299         char upbuf[EL_BUFSIZ];
1300
1301         (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n");
1302         (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n");
1303         (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n",
1304             Val(T_co), Val(T_li));
1305         (void) fprintf(el->el_outfile,
1306             "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no");
1307         (void) fprintf(el->el_outfile,
1308             "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not ");
1309         (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n",
1310             EL_HAS_AUTO_MARGINS ? "has" : "does not have");
1311         if (EL_HAS_AUTO_MARGINS)
1312                 (void) fprintf(el->el_outfile, "\tIt %s magic margins\n",
1313                     EL_HAS_MAGIC_MARGINS ? "has" : "does not have");
1314
1315         for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++)
1316                 (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n",
1317                     t->long_name,
1318                     t->name, *ts && **ts ?
1319                     key__decode_str(*ts, upbuf, "") : "(empty)");
1320         (void) fputc('\n', el->el_outfile);
1321         return (0);
1322 }
1323
1324
1325 /* term_settc():
1326  *      Change the current terminal characteristics
1327  */
1328 protected int
1329 /*ARGSUSED*/
1330 term_settc(EditLine *el, int argc, char **argv)
1331 {
1332         const struct termcapstr *ts;
1333         const struct termcapval *tv;
1334         char *what, *how;
1335
1336         if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
1337                 return (-1);
1338
1339         what = argv[1];
1340         how = argv[2];
1341
1342         /*
1343          * Do the strings first
1344          */
1345         for (ts = tstr; ts->name != NULL; ts++)
1346                 if (strcmp(ts->name, what) == 0)
1347                         break;
1348
1349         if (ts->name != NULL) {
1350                 term_alloc(el, ts, how);
1351                 term_setflags(el);
1352                 return (0);
1353         }
1354         /*
1355          * Do the numeric ones second
1356          */
1357         for (tv = tval; tv->name != NULL; tv++)
1358                 if (strcmp(tv->name, what) == 0)
1359                         break;
1360
1361         if (tv->name != NULL) {
1362                 if (tv == &tval[T_pt] || tv == &tval[T_km] ||
1363                     tv == &tval[T_am] || tv == &tval[T_xn]) {
1364                         if (strcmp(how, "yes") == 0)
1365                                 el->el_term.t_val[tv - tval] = 1;
1366                         else if (strcmp(how, "no") == 0)
1367                                 el->el_term.t_val[tv - tval] = 0;
1368                         else {
1369                                 (void) fprintf(el->el_errfile,
1370                                     "settc: Bad value `%s'.\n", how);
1371                                 return (-1);
1372                         }
1373                         term_setflags(el);
1374                         if (term_change_size(el, Val(T_li), Val(T_co)) == -1)
1375                                 return (-1);
1376                         return (0);
1377                 } else {
1378                         long i;
1379                         char *ep;
1380
1381                         i = strtol(how, &ep, 10);
1382                         if (*ep != '\0') {
1383                                 (void) fprintf(el->el_errfile,
1384                                     "settc: Bad value `%s'.\n", how);
1385                                 return (-1);
1386                         }
1387                         el->el_term.t_val[tv - tval] = (int) i;
1388                         el->el_term.t_size.v = Val(T_co);
1389                         el->el_term.t_size.h = Val(T_li);
1390                         if (tv == &tval[T_co] || tv == &tval[T_li])
1391                                 if (term_change_size(el, Val(T_li), Val(T_co))
1392                                     == -1)
1393                                         return (-1);
1394                         return (0);
1395                 }
1396         }
1397         return (-1);
1398 }
1399
1400
1401 /* term_echotc():
1402  *      Print the termcap string out with variable substitution
1403  */
1404 protected int
1405 /*ARGSUSED*/
1406 term_echotc(EditLine *el, int argc, char **argv)
1407 {
1408         char *cap, *scap, *ep;
1409         int arg_need, arg_cols, arg_rows;
1410         int verbose = 0, silent = 0;
1411         char *area;
1412         static const char fmts[] = "%s\n", fmtd[] = "%d\n";
1413         const struct termcapstr *t;
1414         char buf[TC_BUFSIZE];
1415         long i;
1416
1417         area = buf;
1418
1419         if (argv == NULL || argv[1] == NULL)
1420                 return (-1);
1421         argv++;
1422
1423         if (argv[0][0] == '-') {
1424                 switch (argv[0][1]) {
1425                 case 'v':
1426                         verbose = 1;
1427                         break;
1428                 case 's':
1429                         silent = 1;
1430                         break;
1431                 default:
1432                         /* stderror(ERR_NAME | ERR_TCUSAGE); */
1433                         break;
1434                 }
1435                 argv++;
1436         }
1437         if (!*argv || *argv[0] == '\0')
1438                 return (0);
1439         if (strcmp(*argv, "tabs") == 0) {
1440                 (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no");
1441                 return (0);
1442         } else if (strcmp(*argv, "meta") == 0) {
1443                 (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no");
1444                 return (0);
1445         } else if (strcmp(*argv, "xn") == 0) {
1446                 (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ?
1447                     "yes" : "no");
1448                 return (0);
1449         } else if (strcmp(*argv, "am") == 0) {
1450                 (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ?
1451                     "yes" : "no");
1452                 return (0);
1453         } else if (strcmp(*argv, "baud") == 0) {
1454 #ifdef notdef
1455                 int i;
1456
1457                 for (i = 0; baud_rate[i].b_name != NULL; i++)
1458                         if (el->el_tty.t_speed == baud_rate[i].b_rate) {
1459                                 (void) fprintf(el->el_outfile, fmts,
1460                                     baud_rate[i].b_name);
1461                                 return (0);
1462                         }
1463                 (void) fprintf(el->el_outfile, fmtd, 0);
1464 #else
1465                 (void) fprintf(el->el_outfile, fmtd, el->el_tty.t_speed);
1466 #endif
1467                 return (0);
1468         } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) {
1469                 (void) fprintf(el->el_outfile, fmtd, Val(T_li));
1470                 return (0);
1471         } else if (strcmp(*argv, "cols") == 0) {
1472                 (void) fprintf(el->el_outfile, fmtd, Val(T_co));
1473                 return (0);
1474         }
1475         /*
1476          * Try to use our local definition first
1477          */
1478         scap = NULL;
1479         for (t = tstr; t->name != NULL; t++)
1480                 if (strcmp(t->name, *argv) == 0) {
1481                         scap = el->el_term.t_str[t - tstr];
1482                         break;
1483                 }
1484         if (t->name == NULL)
1485                 scap = tgetstr(*argv, &area);
1486         if (!scap || scap[0] == '\0') {
1487                 if (!silent)
1488                         (void) fprintf(el->el_errfile,
1489                             "echotc: Termcap parameter `%s' not found.\n",
1490                             *argv);
1491                 return (-1);
1492         }
1493         /*
1494          * Count home many values we need for this capability.
1495          */
1496         for (cap = scap, arg_need = 0; *cap; cap++)
1497                 if (*cap == '%')
1498                         switch (*++cap) {
1499                         case 'd':
1500                         case '2':
1501                         case '3':
1502                         case '.':
1503                         case '+':
1504                                 arg_need++;
1505                                 break;
1506                         case '%':
1507                         case '>':
1508                         case 'i':
1509                         case 'r':
1510                         case 'n':
1511                         case 'B':
1512                         case 'D':
1513                                 break;
1514                         default:
1515                                 /*
1516                                  * hpux has lot's of them...
1517                                  */
1518                                 if (verbose)
1519                                         (void) fprintf(el->el_errfile,
1520                                 "echotc: Warning: unknown termcap %% `%c'.\n",
1521                                             *cap);
1522                                 /* This is bad, but I won't complain */
1523                                 break;
1524                         }
1525
1526         switch (arg_need) {
1527         case 0:
1528                 argv++;
1529                 if (*argv && *argv[0]) {
1530                         if (!silent)
1531                                 (void) fprintf(el->el_errfile,
1532                                     "echotc: Warning: Extra argument `%s'.\n",
1533                                     *argv);
1534                         return (-1);
1535                 }
1536                 (void) tputs(scap, 1, term__putc);
1537                 break;
1538         case 1:
1539                 argv++;
1540                 if (!*argv || *argv[0] == '\0') {
1541                         if (!silent)
1542                                 (void) fprintf(el->el_errfile,
1543                                     "echotc: Warning: Missing argument.\n");
1544                         return (-1);
1545                 }
1546                 arg_cols = 0;
1547                 i = strtol(*argv, &ep, 10);
1548                 if (*ep != '\0' || i < 0) {
1549                         if (!silent)
1550                                 (void) fprintf(el->el_errfile,
1551                                     "echotc: Bad value `%s' for rows.\n",
1552                                     *argv);
1553                         return (-1);
1554                 }
1555                 arg_rows = (int) i;
1556                 argv++;
1557                 if (*argv && *argv[0]) {
1558                         if (!silent)
1559                                 (void) fprintf(el->el_errfile,
1560                                     "echotc: Warning: Extra argument `%s'.\n",
1561                                     *argv);
1562                         return (-1);
1563                 }
1564                 (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc);
1565                 break;
1566         default:
1567                 /* This is wrong, but I will ignore it... */
1568                 if (verbose)
1569                         (void) fprintf(el->el_errfile,
1570                          "echotc: Warning: Too many required arguments (%d).\n",
1571                             arg_need);
1572                 /* FALLTHROUGH */
1573         case 2:
1574                 argv++;
1575                 if (!*argv || *argv[0] == '\0') {
1576                         if (!silent)
1577                                 (void) fprintf(el->el_errfile,
1578                                     "echotc: Warning: Missing argument.\n");
1579                         return (-1);
1580                 }
1581                 i = strtol(*argv, &ep, 10);
1582                 if (*ep != '\0' || i < 0) {
1583                         if (!silent)
1584                                 (void) fprintf(el->el_errfile,
1585                                     "echotc: Bad value `%s' for cols.\n",
1586                                     *argv);
1587                         return (-1);
1588                 }
1589                 arg_cols = (int) i;
1590                 argv++;
1591                 if (!*argv || *argv[0] == '\0') {
1592                         if (!silent)
1593                                 (void) fprintf(el->el_errfile,
1594                                     "echotc: Warning: Missing argument.\n");
1595                         return (-1);
1596                 }
1597                 i = strtol(*argv, &ep, 10);
1598                 if (*ep != '\0' || i < 0) {
1599                         if (!silent)
1600                                 (void) fprintf(el->el_errfile,
1601                                     "echotc: Bad value `%s' for rows.\n",
1602                                     *argv);
1603                         return (-1);
1604                 }
1605                 arg_rows = (int) i;
1606                 if (*ep != '\0') {
1607                         if (!silent)
1608                                 (void) fprintf(el->el_errfile,
1609                                     "echotc: Bad value `%s'.\n", *argv);
1610                         return (-1);
1611                 }
1612                 argv++;
1613                 if (*argv && *argv[0]) {
1614                         if (!silent)
1615                                 (void) fprintf(el->el_errfile,
1616                                     "echotc: Warning: Extra argument `%s'.\n",
1617                                     *argv);
1618                         return (-1);
1619                 }
1620                 (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows,
1621                     term__putc);
1622                 break;
1623         }
1624         return (0);
1625 }
Note: See TracBrowser for help on using the browser.