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

« back to all changes in this revision

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