~ubuntu-branches/ubuntu/lucid/mysql-dfsg-5.1/lucid-security

« back to all changes in this revision

Viewing changes to cmd-line-utils/libedit/terminal.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 22:33:55 UTC
  • mto: (1.2.1) (37.1.1 lucid-security)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: package-import@ubuntu.com-20120222223355-ku1tb4r70osci6v2
Tags: upstream-5.1.61
ImportĀ upstreamĀ versionĀ 5.1.61

Show diffs side-by-side

added added

removed removed

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