~ubuntu-branches/ubuntu/quantal/less/quantal

« back to all changes in this revision

Viewing changes to screen.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1984-2000  Mark Nudelman
 
3
 *
 
4
 * You may distribute under the terms of either the GNU General Public
 
5
 * License or the Less License, as specified in the README file.
 
6
 *
 
7
 * For more information about less, or for information on how to 
 
8
 * contact the author, see the README file.
 
9
 */
 
10
 
 
11
 
 
12
/*
 
13
 * Routines which deal with the characteristics of the terminal.
 
14
 * Uses termcap to be as terminal-independent as possible.
 
15
 */
 
16
 
 
17
#include "less.h"
 
18
#include "cmd.h"
 
19
 
 
20
#if MSDOS_COMPILER
 
21
#include "pckeys.h"
 
22
#if MSDOS_COMPILER==MSOFTC
 
23
#include <graph.h>
 
24
#else
 
25
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
26
#include <conio.h>
 
27
#if MSDOS_COMPILER==DJGPPC
 
28
#include <pc.h>
 
29
extern int fd0;
 
30
#endif
 
31
#else
 
32
#if MSDOS_COMPILER==WIN32C
 
33
#include <windows.h>
 
34
#endif
 
35
#endif
 
36
#endif
 
37
#include <time.h>
 
38
 
 
39
#else
 
40
 
 
41
#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
 
42
#include <termios.h>
 
43
#if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
 
44
#include <sys/ioctl.h>
 
45
#endif
 
46
#else
 
47
#if HAVE_TERMIO_H
 
48
#include <termio.h>
 
49
#else
 
50
#if HAVE_SGSTAT_H
 
51
#include <sgstat.h>
 
52
#else
 
53
#include <sgtty.h>
 
54
#endif
 
55
#if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
 
56
#include <sys/ioctl.h>
 
57
#endif
 
58
#endif
 
59
#endif
 
60
 
 
61
#if HAVE_TERMCAP_H
 
62
#include <termcap.h>
 
63
#endif
 
64
#ifdef _OSK
 
65
#include <signal.h>
 
66
#endif
 
67
#if OS2
 
68
#include <sys/signal.h>
 
69
#include "pckeys.h"
 
70
#endif
 
71
#if HAVE_SYS_STREAM_H
 
72
#include <sys/stream.h>
 
73
#endif
 
74
#if HAVE_SYS_PTEM_H
 
75
#include <sys/ptem.h>
 
76
#endif
 
77
 
 
78
#endif /* MSDOS_COMPILER */
 
79
 
 
80
/*
 
81
 * Check for broken termios package that forces you to manually
 
82
 * set the line discipline.
 
83
 */
 
84
#ifdef __ultrix__
 
85
#define MUST_SET_LINE_DISCIPLINE 1
 
86
#else
 
87
#define MUST_SET_LINE_DISCIPLINE 0
 
88
#endif
 
89
 
 
90
#if OS2
 
91
#define DEFAULT_TERM            "ansi"
 
92
static char *windowid;
 
93
#else
 
94
#define DEFAULT_TERM            "unknown"
 
95
#endif
 
96
 
 
97
#if MSDOS_COMPILER==MSOFTC
 
98
static int videopages;
 
99
static long msec_loops;
 
100
static int flash_created = 0;
 
101
#define SETCOLORS(fg,bg)        { _settextcolor(fg); _setbkcolor(bg); }
 
102
#endif
 
103
 
 
104
#if MSDOS_COMPILER==BORLANDC
 
105
static unsigned short *whitescreen;
 
106
static int flash_created = 0;
 
107
#endif
 
108
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
109
#define _settextposition(y,x)   gotoxy(x,y)
 
110
#define _clearscreen(m)         clrscr()
 
111
#define _outtext(s)             cputs(s)
 
112
#define SETCOLORS(fg,bg)        { textcolor(fg); textbackground(bg); }
 
113
extern int sc_height;
 
114
#endif
 
115
 
 
116
#if MSDOS_COMPILER==WIN32C
 
117
struct keyRecord
 
118
{
 
119
        int ascii;
 
120
        int scan;
 
121
} currentKey;
 
122
 
 
123
static int keyCount = 0;
 
124
static WORD curr_attr;
 
125
static int pending_scancode = 0;
 
126
static WORD *whitescreen;
 
127
 
 
128
static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */
 
129
static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */
 
130
HANDLE con_out = INVALID_HANDLE_VALUE;             /* current console */
 
131
 
 
132
extern int quitting;
 
133
static void win32_init_term();
 
134
static void win32_deinit_term();
 
135
 
 
136
#define FG_COLORS       (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
 
137
#define BG_COLORS       (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY)
 
138
#define MAKEATTR(fg,bg)         ((WORD)((fg)|((bg)<<4)))
 
139
#define SETCOLORS(fg,bg)        { curr_attr = MAKEATTR(fg,bg); \
 
140
                                if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \
 
141
                                error("SETCOLORS failed"); }
 
142
#endif
 
143
 
 
144
#if MSDOS_COMPILER
 
145
public int nm_fg_color;         /* Color of normal text */
 
146
public int nm_bg_color;
 
147
public int bo_fg_color;         /* Color of bold text */
 
148
public int bo_bg_color;
 
149
public int ul_fg_color;         /* Color of underlined text */
 
150
public int ul_bg_color;
 
151
public int so_fg_color;         /* Color of standout text */
 
152
public int so_bg_color;
 
153
public int bl_fg_color;         /* Color of blinking text */
 
154
public int bl_bg_color;
 
155
static int sy_fg_color;         /* Color of system text (before less) */
 
156
static int sy_bg_color;
 
157
 
 
158
#else
 
159
 
 
160
/*
 
161
 * Strings passed to tputs() to do various terminal functions.
 
162
 */
 
163
static char
 
164
        *sc_pad,                /* Pad string */
 
165
        *sc_home,               /* Cursor home */
 
166
        *sc_addline,            /* Add line, scroll down following lines */
 
167
        *sc_lower_left,         /* Cursor to last line, first column */
 
168
        *sc_move,               /* General cursor positioning */
 
169
        *sc_clear,              /* Clear screen */
 
170
        *sc_eol_clear,          /* Clear to end of line */
 
171
        *sc_eos_clear,          /* Clear to end of screen */
 
172
        *sc_s_in,               /* Enter standout (highlighted) mode */
 
173
        *sc_s_out,              /* Exit standout mode */
 
174
        *sc_u_in,               /* Enter underline mode */
 
175
        *sc_u_out,              /* Exit underline mode */
 
176
        *sc_b_in,               /* Enter bold mode */
 
177
        *sc_b_out,              /* Exit bold mode */
 
178
        *sc_bl_in,              /* Enter blink mode */
 
179
        *sc_bl_out,             /* Exit blink mode */
 
180
        *sc_visual_bell,        /* Visual bell (flash screen) sequence */
 
181
        *sc_backspace,          /* Backspace cursor */
 
182
        *sc_s_keypad,           /* Start keypad mode */
 
183
        *sc_e_keypad,           /* End keypad mode */
 
184
        *sc_init,               /* Startup terminal initialization */
 
185
        *sc_deinit;             /* Exit terminal de-initialization */
 
186
#endif
 
187
 
 
188
static int init_done = 0;
 
189
 
 
190
public int auto_wrap;           /* Terminal does \r\n when write past margin */
 
191
public int ignaw;               /* Terminal ignores \n immediately after wrap */
 
192
public int erase_char, kill_char; /* The user's erase and line-kill chars */
 
193
public int werase_char;         /* The user's word-erase char */
 
194
public int sc_width, sc_height; /* Height & width of screen */
 
195
public int bo_s_width, bo_e_width;      /* Printing width of boldface seq */
 
196
public int ul_s_width, ul_e_width;      /* Printing width of underline seq */
 
197
public int so_s_width, so_e_width;      /* Printing width of standout seq */
 
198
public int bl_s_width, bl_e_width;      /* Printing width of blink seq */
 
199
public int above_mem, below_mem;        /* Memory retained above/below screen */
 
200
public int can_goto_line;               /* Can move cursor to any line */
 
201
public int clear_bg;            /* Clear fills with background color */
 
202
public int missing_cap = 0;     /* Some capability is missing */
 
203
 
 
204
static int attrmode = AT_NORMAL;
 
205
 
 
206
#if !MSDOS_COMPILER
 
207
static char *cheaper();
 
208
static void tmodes();
 
209
#endif
 
210
 
 
211
/*
 
212
 * These two variables are sometimes defined in,
 
213
 * and needed by, the termcap library.
 
214
 */
 
215
#if MUST_DEFINE_OSPEED
 
216
extern short ospeed;    /* Terminal output baud rate */
 
217
extern char PC;         /* Pad character */
 
218
#endif
 
219
#ifdef _OSK
 
220
short ospeed;
 
221
char PC_, *UP, *BC;
 
222
#endif
 
223
 
 
224
extern int quiet;               /* If VERY_QUIET, use visual bell for bell */
 
225
extern int no_back_scroll;
 
226
extern int swindow;
 
227
extern int no_init;
 
228
extern int no_keypad;
 
229
extern int sigs;
 
230
extern int wscroll;
 
231
extern int screen_trashed;
 
232
#if HILITE_SEARCH
 
233
extern int hilite_search;
 
234
#endif
 
235
 
 
236
extern char *tgetstr();
 
237
extern char *tgoto();
 
238
 
 
239
 
 
240
/*
 
241
 * Change terminal to "raw mode", or restore to "normal" mode.
 
242
 * "Raw mode" means 
 
243
 *      1. An outstanding read will complete on receipt of a single keystroke.
 
244
 *      2. Input is not echoed.  
 
245
 *      3. On output, \n is mapped to \r\n.
 
246
 *      4. \t is NOT expanded into spaces.
 
247
 *      5. Signal-causing characters such as ctrl-C (interrupt),
 
248
 *         etc. are NOT disabled.
 
249
 * It doesn't matter whether an input \n is mapped to \r, or vice versa.
 
250
 */
 
251
        public void
 
252
raw_mode(on)
 
253
        int on;
 
254
{
 
255
        static int curr_on = 0;
 
256
 
 
257
        if (on == curr_on)
 
258
                return;
 
259
#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
 
260
    {
 
261
        struct termios s;
 
262
        static struct termios save_term;
 
263
        static int saved_term = 0;
 
264
 
 
265
        if (on) 
 
266
        {
 
267
                /*
 
268
                 * Get terminal modes.
 
269
                 */
 
270
                tcgetattr(2, &s);
 
271
 
 
272
                /*
 
273
                 * Save modes and set certain variables dependent on modes.
 
274
                 */
 
275
                if (!saved_term)
 
276
                {
 
277
                        save_term = s;
 
278
                        saved_term = 1;
 
279
                }
 
280
#if HAVE_OSPEED
 
281
                switch (cfgetospeed(&s))
 
282
                {
 
283
#ifdef B0
 
284
                case B0: ospeed = 0; break;
 
285
#endif
 
286
#ifdef B50
 
287
                case B50: ospeed = 1; break;
 
288
#endif
 
289
#ifdef B75
 
290
                case B75: ospeed = 2; break;
 
291
#endif
 
292
#ifdef B110
 
293
                case B110: ospeed = 3; break;
 
294
#endif
 
295
#ifdef B134
 
296
                case B134: ospeed = 4; break;
 
297
#endif
 
298
#ifdef B150
 
299
                case B150: ospeed = 5; break;
 
300
#endif
 
301
#ifdef B200
 
302
                case B200: ospeed = 6; break;
 
303
#endif
 
304
#ifdef B300
 
305
                case B300: ospeed = 7; break;
 
306
#endif
 
307
#ifdef B600
 
308
                case B600: ospeed = 8; break;
 
309
#endif
 
310
#ifdef B1200
 
311
                case B1200: ospeed = 9; break;
 
312
#endif
 
313
#ifdef B1800
 
314
                case B1800: ospeed = 10; break;
 
315
#endif
 
316
#ifdef B2400
 
317
                case B2400: ospeed = 11; break;
 
318
#endif
 
319
#ifdef B4800
 
320
                case B4800: ospeed = 12; break;
 
321
#endif
 
322
#ifdef B9600
 
323
                case B9600: ospeed = 13; break;
 
324
#endif
 
325
#ifdef EXTA
 
326
                case EXTA: ospeed = 14; break;
 
327
#endif
 
328
#ifdef EXTB
 
329
                case EXTB: ospeed = 15; break;
 
330
#endif
 
331
#ifdef B57600
 
332
                case B57600: ospeed = 16; break;
 
333
#endif
 
334
#ifdef B115200
 
335
                case B115200: ospeed = 17; break;
 
336
#endif
 
337
                default: ;
 
338
                }
 
339
#endif
 
340
                erase_char = s.c_cc[VERASE];
 
341
                kill_char = s.c_cc[VKILL];
 
342
#ifdef VWERASE
 
343
                werase_char = s.c_cc[VWERASE];
 
344
#else
 
345
                werase_char = CONTROL('W');
 
346
#endif
 
347
 
 
348
                /*
 
349
                 * Set the modes to the way we want them.
 
350
                 */
 
351
                s.c_lflag &= ~(0
 
352
#ifdef ICANON
 
353
                        | ICANON
 
354
#endif
 
355
#ifdef ECHO
 
356
                        | ECHO
 
357
#endif
 
358
#ifdef ECHOE
 
359
                        | ECHOE
 
360
#endif
 
361
#ifdef ECHOK
 
362
                        | ECHOK
 
363
#endif
 
364
#if ECHONL
 
365
                        | ECHONL
 
366
#endif
 
367
                );
 
368
 
 
369
                s.c_oflag |= (0
 
370
#ifdef OXTABS
 
371
                        | OXTABS
 
372
#else
 
373
#ifdef TAB3
 
374
                        | TAB3
 
375
#else
 
376
#ifdef XTABS
 
377
                        | XTABS
 
378
#endif
 
379
#endif
 
380
#endif
 
381
#ifdef OPOST
 
382
                        | OPOST
 
383
#endif
 
384
#ifdef ONLCR
 
385
                        | ONLCR
 
386
#endif
 
387
                );
 
388
 
 
389
                s.c_oflag &= ~(0
 
390
#ifdef ONOEOT
 
391
                        | ONOEOT
 
392
#endif
 
393
#ifdef OCRNL
 
394
                        | OCRNL
 
395
#endif
 
396
#ifdef ONOCR
 
397
                        | ONOCR
 
398
#endif
 
399
#ifdef ONLRET
 
400
                        | ONLRET
 
401
#endif
 
402
                );
 
403
                s.c_cc[VMIN] = 1;
 
404
                s.c_cc[VTIME] = 0;
 
405
#ifdef VLNEXT
 
406
                s.c_cc[VLNEXT] = 0;
 
407
#endif
 
408
#ifdef VDSUSP
 
409
                s.c_cc[VDSUSP] = 0;
 
410
#endif
 
411
#if MUST_SET_LINE_DISCIPLINE
 
412
                /*
 
413
                 * System's termios is broken; need to explicitly 
 
414
                 * request TERMIODISC line discipline.
 
415
                 */
 
416
                s.c_line = TERMIODISC;
 
417
#endif
 
418
        } else
 
419
        {
 
420
                /*
 
421
                 * Restore saved modes.
 
422
                 */
 
423
                s = save_term;
 
424
        }
 
425
#if HAVE_FSYNC
 
426
        fsync(2);
 
427
#endif
 
428
        tcsetattr(2, TCSADRAIN, &s);
 
429
#if MUST_SET_LINE_DISCIPLINE
 
430
        if (!on)
 
431
        {
 
432
                /*
 
433
                 * Broken termios *ignores* any line discipline
 
434
                 * except TERMIODISC.  A different old line discipline
 
435
                 * is therefore not restored, yet.  Restore the old
 
436
                 * line discipline by hand.
 
437
                 */
 
438
                ioctl(2, TIOCSETD, &save_term.c_line);
 
439
        }
 
440
#endif
 
441
    }
 
442
#else
 
443
#ifdef TCGETA
 
444
    {
 
445
        struct termio s;
 
446
        static struct termio save_term;
 
447
        static int saved_term = 0;
 
448
 
 
449
        if (on)
 
450
        {
 
451
                /*
 
452
                 * Get terminal modes.
 
453
                 */
 
454
                ioctl(2, TCGETA, &s);
 
455
 
 
456
                /*
 
457
                 * Save modes and set certain variables dependent on modes.
 
458
                 */
 
459
                if (!saved_term)
 
460
                {
 
461
                        save_term = s;
 
462
                        saved_term = 1;
 
463
                }
 
464
#if HAVE_OSPEED
 
465
                ospeed = s.c_cflag & CBAUD;
 
466
#endif
 
467
                erase_char = s.c_cc[VERASE];
 
468
                kill_char = s.c_cc[VKILL];
 
469
#ifdef VWERASE
 
470
                werase_char = s.c_cc[VWERASE];
 
471
#else
 
472
                werase_char = CONTROL('W');
 
473
#endif
 
474
 
 
475
                /*
 
476
                 * Set the modes to the way we want them.
 
477
                 */
 
478
                s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
 
479
                s.c_oflag |=  (OPOST|ONLCR|TAB3);
 
480
                s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
 
481
                s.c_cc[VMIN] = 1;
 
482
                s.c_cc[VTIME] = 0;
 
483
        } else
 
484
        {
 
485
                /*
 
486
                 * Restore saved modes.
 
487
                 */
 
488
                s = save_term;
 
489
        }
 
490
        ioctl(2, TCSETAW, &s);
 
491
    }
 
492
#else
 
493
#ifdef TIOCGETP
 
494
    {
 
495
        struct sgttyb s;
 
496
        static struct sgttyb save_term;
 
497
        static int saved_term = 0;
 
498
 
 
499
        if (on)
 
500
        {
 
501
                /*
 
502
                 * Get terminal modes.
 
503
                 */
 
504
                ioctl(2, TIOCGETP, &s);
 
505
 
 
506
                /*
 
507
                 * Save modes and set certain variables dependent on modes.
 
508
                 */
 
509
                if (!saved_term)
 
510
                {
 
511
                        save_term = s;
 
512
                        saved_term = 1;
 
513
                }
 
514
#if HAVE_OSPEED
 
515
                ospeed = s.sg_ospeed;
 
516
#endif
 
517
                erase_char = s.sg_erase;
 
518
                kill_char = s.sg_kill;
 
519
                werase_char = CONTROL('W');
 
520
 
 
521
                /*
 
522
                 * Set the modes to the way we want them.
 
523
                 */
 
524
                s.sg_flags |= CBREAK;
 
525
                s.sg_flags &= ~(ECHO|XTABS);
 
526
        } else
 
527
        {
 
528
                /*
 
529
                 * Restore saved modes.
 
530
                 */
 
531
                s = save_term;
 
532
        }
 
533
        ioctl(2, TIOCSETN, &s);
 
534
    }
 
535
#else
 
536
#ifdef _OSK
 
537
    {
 
538
        struct sgbuf s;
 
539
        static struct sgbuf save_term;
 
540
        static int saved_term = 0;
 
541
 
 
542
        if (on)
 
543
        {
 
544
                /*
 
545
                 * Get terminal modes.
 
546
                 */
 
547
                _gs_opt(2, &s);
 
548
 
 
549
                /*
 
550
                 * Save modes and set certain variables dependent on modes.
 
551
                 */
 
552
                if (!saved_term)
 
553
                {
 
554
                        save_term = s;
 
555
                        saved_term = 1;
 
556
                }
 
557
                erase_char = s.sg_bspch;
 
558
                kill_char = s.sg_dlnch;
 
559
                werase_char = CONTROL('W');
 
560
 
 
561
                /*
 
562
                 * Set the modes to the way we want them.
 
563
                 */
 
564
                s.sg_echo = 0;
 
565
                s.sg_eofch = 0;
 
566
                s.sg_pause = 0;
 
567
                s.sg_psch = 0;
 
568
        } else
 
569
        {
 
570
                /*
 
571
                 * Restore saved modes.
 
572
                 */
 
573
                s = save_term;
 
574
        }
 
575
        _ss_opt(2, &s);
 
576
    }
 
577
#else
 
578
        /* MS-DOS, Windows, or OS2 */
 
579
#if OS2
 
580
        /* OS2 */
 
581
        LSIGNAL(SIGINT, SIG_IGN);
 
582
#endif
 
583
        erase_char = '\b';
 
584
#if MSDOS_COMPILER==DJGPPC
 
585
        kill_char = CONTROL('U');
 
586
        /*
 
587
         * So that when we shell out or run another program, its
 
588
         * stdin is in cooked mode.  We do not switch stdin to binary 
 
589
         * mode if fd0 is zero, since that means we were called before
 
590
         * tty was reopened in open_getchr, in which case we would be
 
591
         * changing the original stdin device outside less.
 
592
         */
 
593
        if (fd0 != 0)
 
594
                setmode(0, on ? O_BINARY : O_TEXT);
 
595
#else
 
596
        kill_char = ESC;
 
597
#endif
 
598
        werase_char = CONTROL('W');
 
599
#endif
 
600
#endif
 
601
#endif
 
602
#endif
 
603
        curr_on = on;
 
604
}
 
605
 
 
606
#if !MSDOS_COMPILER
 
607
/*
 
608
 * Some glue to prevent calling termcap functions if tgetent() failed.
 
609
 */
 
610
static int hardcopy;
 
611
 
 
612
        static char *
 
613
ltget_env(capname)
 
614
        char *capname;
 
615
{
 
616
        char name[16];
 
617
 
 
618
        strcpy(name, "LESS_TERMCAP_");
 
619
        strcat(name, capname);
 
620
        return (lgetenv(name));
 
621
}
 
622
 
 
623
        static int
 
624
ltgetflag(capname)
 
625
        char *capname;
 
626
{
 
627
        char *s;
 
628
 
 
629
        if ((s = ltget_env(capname)) != NULL)
 
630
                return (*s != '\0' && *s != '0');
 
631
        if (hardcopy)
 
632
                return (0);
 
633
        return (tgetflag(capname));
 
634
}
 
635
 
 
636
        static int
 
637
ltgetnum(capname)
 
638
        char *capname;
 
639
{
 
640
        char *s;
 
641
 
 
642
        if ((s = ltget_env(capname)) != NULL)
 
643
                return (atoi(s));
 
644
        if (hardcopy)
 
645
                return (-1);
 
646
        return (tgetnum(capname));
 
647
}
 
648
 
 
649
        static char *
 
650
ltgetstr(capname, pp)
 
651
        char *capname;
 
652
        char **pp;
 
653
{
 
654
        char *s;
 
655
 
 
656
        if ((s = ltget_env(capname)) != NULL)
 
657
                return (s);
 
658
        if (hardcopy)
 
659
                return (NULL);
 
660
        return (tgetstr(capname, pp));
 
661
}
 
662
#endif /* MSDOS_COMPILER */
 
663
 
 
664
/*
 
665
 * Get size of the output screen.
 
666
 */
 
667
        public void
 
668
scrsize()
 
669
{
 
670
        register char *s;
 
671
        int sys_height;
 
672
        int sys_width;
 
673
#if !MSDOS_COMPILER
 
674
        int n;
 
675
#endif
 
676
 
 
677
#define DEF_SC_WIDTH    80
 
678
#if MSDOS_COMPILER
 
679
#define DEF_SC_HEIGHT   25
 
680
#else
 
681
#define DEF_SC_HEIGHT   24
 
682
#endif
 
683
 
 
684
 
 
685
        sys_width = sys_height = 0;
 
686
 
 
687
#if MSDOS_COMPILER==MSOFTC
 
688
        {
 
689
                struct videoconfig w;
 
690
                _getvideoconfig(&w);
 
691
                sys_height = w.numtextrows;
 
692
                sys_width = w.numtextcols;
 
693
        }
 
694
#else
 
695
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
696
        {
 
697
                struct text_info w;
 
698
                gettextinfo(&w);
 
699
                sys_height = w.screenheight;
 
700
                sys_width = w.screenwidth;
 
701
        }
 
702
#else
 
703
#if MSDOS_COMPILER==WIN32C
 
704
        {
 
705
                CONSOLE_SCREEN_BUFFER_INFO scr;
 
706
                GetConsoleScreenBufferInfo(con_out, &scr);
 
707
                sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1;
 
708
                sys_width = scr.srWindow.Right - scr.srWindow.Left + 1;
 
709
        }
 
710
#else
 
711
#if OS2
 
712
        {
 
713
                int s[2];
 
714
                _scrsize(s);
 
715
                sys_width = s[0];
 
716
                sys_height = s[1];
 
717
                /*
 
718
                 * When using terminal emulators for XFree86/OS2, the
 
719
                 * _scrsize function does not work well.
 
720
                 * Call the scrsize.exe program to get the window size.
 
721
                 */
 
722
                windowid = getenv("WINDOWID");
 
723
                if (windowid != NULL)
 
724
                {
 
725
                        FILE *fd = popen("scrsize", "rt");
 
726
                        if (fd != NULL)
 
727
                        {
 
728
                                int w, h;
 
729
                                fscanf(fd, "%i %i", &w, &h);
 
730
                                if (w > 0 && h > 0)
 
731
                                {
 
732
                                        sys_width = w;
 
733
                                        sys_height = h;
 
734
                                }
 
735
                                pclose(fd);
 
736
                        }
 
737
                }
 
738
        }
 
739
#else
 
740
#ifdef TIOCGWINSZ
 
741
        {
 
742
                struct winsize w;
 
743
                if (ioctl(2, TIOCGWINSZ, &w) == 0)
 
744
                {
 
745
                        if (w.ws_row > 0)
 
746
                                sys_height = w.ws_row;
 
747
                        if (w.ws_col > 0)
 
748
                                sys_width = w.ws_col;
 
749
                }
 
750
        }
 
751
#else
 
752
#ifdef WIOCGETD
 
753
        {
 
754
                struct uwdata w;
 
755
                if (ioctl(2, WIOCGETD, &w) == 0)
 
756
                {
 
757
                        if (w.uw_height > 0)
 
758
                                sys_height = w.uw_height / w.uw_vs;
 
759
                        if (w.uw_width > 0)
 
760
                                sys_width = w.uw_width / w.uw_hs;
 
761
                }
 
762
        }
 
763
#endif
 
764
#endif
 
765
#endif
 
766
#endif
 
767
#endif
 
768
#endif
 
769
 
 
770
        if (sys_height > 0)
 
771
                sc_height = sys_height;
 
772
        else if ((s = lgetenv("LINES")) != NULL)
 
773
                sc_height = atoi(s);
 
774
#if !MSDOS_COMPILER
 
775
        else if ((n = ltgetnum("li")) > 0)
 
776
                sc_height = n;
 
777
#endif
 
778
        else
 
779
                sc_height = DEF_SC_HEIGHT;
 
780
 
 
781
        if (sys_width > 0)
 
782
                sc_width = sys_width;
 
783
        else if ((s = lgetenv("COLUMNS")) != NULL)
 
784
                sc_width = atoi(s);
 
785
#if !MSDOS_COMPILER
 
786
        else if ((n = ltgetnum("co")) > 0)
 
787
                sc_width = n;
 
788
#endif
 
789
        else
 
790
                sc_width = DEF_SC_WIDTH;
 
791
}
 
792
 
 
793
#if MSDOS_COMPILER==MSOFTC
 
794
/*
 
795
 * Figure out how many empty loops it takes to delay a millisecond.
 
796
 */
 
797
        static void
 
798
get_clock()
 
799
{
 
800
        clock_t start;
 
801
        
 
802
        /*
 
803
         * Get synchronized at the start of a tick.
 
804
         */
 
805
        start = clock();
 
806
        while (clock() == start)
 
807
                ;
 
808
        /*
 
809
         * Now count loops till the next tick.
 
810
         */
 
811
        start = clock();
 
812
        msec_loops = 0;
 
813
        while (clock() == start)
 
814
                msec_loops++;
 
815
        /*
 
816
         * Convert from (loops per clock) to (loops per millisecond).
 
817
         */
 
818
        msec_loops *= CLOCKS_PER_SEC;
 
819
        msec_loops /= 1000;
 
820
}
 
821
 
 
822
/*
 
823
 * Delay for a specified number of milliseconds.
 
824
 */
 
825
        static void
 
826
dummy_func()
 
827
{
 
828
        static long delay_dummy = 0;
 
829
        delay_dummy++;
 
830
}
 
831
 
 
832
        static void
 
833
delay(msec)
 
834
        int msec;
 
835
{
 
836
        long i;
 
837
        
 
838
        while (msec-- > 0)
 
839
        {
 
840
                for (i = 0;  i < msec_loops;  i++)
 
841
                {
 
842
                        /*
 
843
                         * Make it look like we're doing something here,
 
844
                         * so the optimizer doesn't remove the whole loop.
 
845
                         */
 
846
                        dummy_func();
 
847
                }
 
848
        }
 
849
}
 
850
#endif
 
851
 
 
852
/*
 
853
 * Return the characters actually input by a "special" key.
 
854
 */
 
855
        public char *
 
856
special_key_str(key)
 
857
        int key;
 
858
{
 
859
        static char tbuf[40];
 
860
        char *s;
 
861
#if MSDOS_COMPILER || OS2
 
862
        static char k_right[]           = { '\340', PCK_RIGHT, 0 };
 
863
        static char k_left[]            = { '\340', PCK_LEFT, 0  };
 
864
        static char k_ctl_right[]       = { '\340', PCK_CTL_RIGHT, 0  };
 
865
        static char k_ctl_left[]        = { '\340', PCK_CTL_LEFT, 0  };
 
866
        static char k_insert[]          = { '\340', PCK_INSERT, 0  };
 
867
        static char k_delete[]          = { '\340', PCK_DELETE, 0  };
 
868
        static char k_ctl_delete[]      = { '\340', PCK_CTL_DELETE, 0  };
 
869
        static char k_ctl_backspace[]   = { '\177', 0 };
 
870
        static char k_home[]            = { '\340', PCK_HOME, 0 };
 
871
        static char k_end[]             = { '\340', PCK_END, 0 };
 
872
        static char k_up[]              = { '\340', PCK_UP, 0 };
 
873
        static char k_down[]            = { '\340', PCK_DOWN, 0 };
 
874
        static char k_backtab[]         = { '\340', PCK_SHIFT_TAB, 0 };
 
875
        static char k_pagedown[]        = { '\340', PCK_PAGEDOWN, 0 };
 
876
        static char k_pageup[]          = { '\340', PCK_PAGEUP, 0 };
 
877
        static char k_f1[]              = { '\340', PCK_F1, 0 };
 
878
#endif
 
879
#if !MSDOS_COMPILER
 
880
        char *sp = tbuf;
 
881
#endif
 
882
 
 
883
        switch (key)
 
884
        {
 
885
#if OS2
 
886
        /*
 
887
         * If windowid is not NULL, assume less is executed in 
 
888
         * the XFree86 environment.
 
889
         */
 
890
        case SK_RIGHT_ARROW:
 
891
                s = windowid ? ltgetstr("kr", &sp) : k_right;
 
892
                break;
 
893
        case SK_LEFT_ARROW:
 
894
                s = windowid ? ltgetstr("kl", &sp) : k_left;
 
895
                break;
 
896
        case SK_UP_ARROW:
 
897
                s = windowid ? ltgetstr("ku", &sp) : k_up;
 
898
                break;
 
899
        case SK_DOWN_ARROW:
 
900
                s = windowid ? ltgetstr("kd", &sp) : k_down;
 
901
                break;
 
902
        case SK_PAGE_UP:
 
903
                s = windowid ? ltgetstr("kP", &sp) : k_pageup;
 
904
                break;
 
905
        case SK_PAGE_DOWN:
 
906
                s = windowid ? ltgetstr("kN", &sp) : k_pagedown;
 
907
                break;
 
908
        case SK_HOME:
 
909
                s = windowid ? ltgetstr("kh", &sp) : k_home;
 
910
                break;
 
911
        case SK_END:
 
912
                s = windowid ? ltgetstr("@7", &sp) : k_end;
 
913
                break;
 
914
        case SK_DELETE:
 
915
                if (windowid)
 
916
                {
 
917
                        s = ltgetstr("kD", &sp);
 
918
                        if (s == NULL)
 
919
                        {
 
920
                                tbuf[0] = '\177';
 
921
                                tbuf[1] = '\0';
 
922
                                s = tbuf;
 
923
                        }
 
924
                } else
 
925
                        s = k_delete;
 
926
                break;
 
927
#endif
 
928
#if MSDOS_COMPILER
 
929
        case SK_RIGHT_ARROW:
 
930
                s = k_right;
 
931
                break;
 
932
        case SK_LEFT_ARROW:
 
933
                s = k_left;
 
934
                break;
 
935
        case SK_UP_ARROW:
 
936
                s = k_up;
 
937
                break;
 
938
        case SK_DOWN_ARROW:
 
939
                s = k_down;
 
940
                break;
 
941
        case SK_PAGE_UP:
 
942
                s = k_pageup;
 
943
                break;
 
944
        case SK_PAGE_DOWN:
 
945
                s = k_pagedown;
 
946
                break;
 
947
        case SK_HOME:
 
948
                s = k_home;
 
949
                break;
 
950
        case SK_END:
 
951
                s = k_end;
 
952
                break;
 
953
        case SK_DELETE:
 
954
                s = k_delete;
 
955
                break;
 
956
#endif
 
957
#if MSDOS_COMPILER || OS2
 
958
        case SK_INSERT:
 
959
                s = k_insert;
 
960
                break;
 
961
        case SK_CTL_LEFT_ARROW:
 
962
                s = k_ctl_left;
 
963
                break;
 
964
        case SK_CTL_RIGHT_ARROW:
 
965
                s = k_ctl_right;
 
966
                break;
 
967
        case SK_CTL_BACKSPACE:
 
968
                s = k_ctl_backspace;
 
969
                break;
 
970
        case SK_CTL_DELETE:
 
971
                s = k_ctl_delete;
 
972
                break;
 
973
        case SK_F1:
 
974
                s = k_f1;
 
975
                break;
 
976
        case SK_BACKTAB:
 
977
                s = k_backtab;
 
978
                break;
 
979
#else
 
980
        case SK_RIGHT_ARROW:
 
981
                s = ltgetstr("kr", &sp);
 
982
                break;
 
983
        case SK_LEFT_ARROW:
 
984
                s = ltgetstr("kl", &sp);
 
985
                break;
 
986
        case SK_UP_ARROW:
 
987
                s = ltgetstr("ku", &sp);
 
988
                break;
 
989
        case SK_DOWN_ARROW:
 
990
                s = ltgetstr("kd", &sp);
 
991
                break;
 
992
        case SK_PAGE_UP:
 
993
                s = ltgetstr("kP", &sp);
 
994
                break;
 
995
        case SK_PAGE_DOWN:
 
996
                s = ltgetstr("kN", &sp);
 
997
                break;
 
998
        case SK_HOME:
 
999
                s = ltgetstr("kh", &sp);
 
1000
                break;
 
1001
        case SK_END:
 
1002
                s = ltgetstr("@7", &sp);
 
1003
                break;
 
1004
        case SK_DELETE:
 
1005
                s = ltgetstr("kD", &sp);
 
1006
                if (s == NULL)
 
1007
                {
 
1008
                        tbuf[0] = '\177';
 
1009
                        tbuf[1] = '\0';
 
1010
                        s = tbuf;
 
1011
                }
 
1012
                break;
 
1013
#endif
 
1014
        case SK_CONTROL_K:
 
1015
                tbuf[0] = CONTROL('K');
 
1016
                tbuf[1] = '\0';
 
1017
                s = tbuf;
 
1018
                break;
 
1019
        default:
 
1020
                return (NULL);
 
1021
        }
 
1022
        return (s);
 
1023
}
 
1024
 
 
1025
/*
 
1026
 * Get terminal capabilities via termcap.
 
1027
 */
 
1028
        public void
 
1029
get_term()
 
1030
{
 
1031
#if MSDOS_COMPILER
 
1032
        auto_wrap = 1;
 
1033
        ignaw = 0;
 
1034
        can_goto_line = 1;
 
1035
        clear_bg = 1;
 
1036
        /*
 
1037
         * Set up default colors.
 
1038
         * The xx_s_width and xx_e_width vars are already initialized to 0.
 
1039
         */
 
1040
#if MSDOS_COMPILER==MSOFTC
 
1041
        sy_bg_color = _getbkcolor();
 
1042
        sy_fg_color = _gettextcolor();
 
1043
        get_clock();
 
1044
#else
 
1045
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
1046
    {
 
1047
        struct text_info w;
 
1048
        gettextinfo(&w);
 
1049
        sy_bg_color = (w.attribute >> 4) & 0x0F;
 
1050
        sy_fg_color = (w.attribute >> 0) & 0x0F;
 
1051
    }
 
1052
#else
 
1053
#if MSDOS_COMPILER==WIN32C
 
1054
    {
 
1055
        DWORD nread;
 
1056
        CONSOLE_SCREEN_BUFFER_INFO scr;
 
1057
 
 
1058
        con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE);
 
1059
        /*
 
1060
         * Always open stdin in binary. Note this *must* be done
 
1061
         * before any file operations have been done on fd0.
 
1062
         */
 
1063
        SET_BINARY(0);
 
1064
        GetConsoleScreenBufferInfo(con_out, &scr);
 
1065
        ReadConsoleOutputAttribute(con_out, &curr_attr, 
 
1066
                                        1, scr.dwCursorPosition, &nread);
 
1067
        sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */
 
1068
        sy_fg_color = curr_attr & FG_COLORS;
 
1069
    }
 
1070
#endif
 
1071
#endif
 
1072
#endif
 
1073
        nm_fg_color = sy_fg_color;
 
1074
        nm_bg_color = sy_bg_color;
 
1075
        bo_fg_color = 11;
 
1076
        bo_bg_color = 0;
 
1077
        ul_fg_color = 9;
 
1078
        ul_bg_color = 0;
 
1079
        so_fg_color = 15;
 
1080
        so_bg_color = 9;
 
1081
        bl_fg_color = 15;
 
1082
        bl_bg_color = 0;
 
1083
 
 
1084
        /*
 
1085
         * Get size of the screen.
 
1086
         */
 
1087
        scrsize();
 
1088
        pos_init();
 
1089
 
 
1090
 
 
1091
#else /* !MSDOS_COMPILER */
 
1092
 
 
1093
        char *sp;
 
1094
        register char *t1, *t2;
 
1095
        char *term;
 
1096
        char termbuf[TERMBUF_SIZE];
 
1097
 
 
1098
        static char sbuf[TERMSBUF_SIZE];
 
1099
 
 
1100
#if OS2
 
1101
        /*
 
1102
         * Make sure the termcap database is available.
 
1103
         */
 
1104
        sp = lgetenv("TERMCAP");
 
1105
        if (sp == NULL || *sp == '\0')
 
1106
        {
 
1107
                char *termcap;
 
1108
                if ((sp = homefile("termcap.dat")) != NULL)
 
1109
                {
 
1110
                        termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char));
 
1111
                        sprintf(termcap, "TERMCAP=%s", sp);
 
1112
                        free(sp);
 
1113
                        putenv(termcap);
 
1114
                }
 
1115
        }
 
1116
#endif
 
1117
        /*
 
1118
         * Find out what kind of terminal this is.
 
1119
         */
 
1120
        if ((term = lgetenv("TERM")) == NULL)
 
1121
                term = DEFAULT_TERM;
 
1122
        hardcopy = 0;
 
1123
        if (tgetent(termbuf, term) <= 0)
 
1124
                hardcopy = 1;
 
1125
        if (ltgetflag("hc"))
 
1126
                hardcopy = 1;
 
1127
 
 
1128
        /*
 
1129
         * Get size of the screen.
 
1130
         */
 
1131
        scrsize();
 
1132
        pos_init();
 
1133
 
 
1134
        auto_wrap = ltgetflag("am");
 
1135
        ignaw = ltgetflag("xn");
 
1136
        above_mem = ltgetflag("da");
 
1137
        below_mem = ltgetflag("db");
 
1138
        clear_bg = ltgetflag("ut");
 
1139
 
 
1140
        /*
 
1141
         * Assumes termcap variable "sg" is the printing width of:
 
1142
         * the standout sequence, the end standout sequence,
 
1143
         * the underline sequence, the end underline sequence,
 
1144
         * the boldface sequence, and the end boldface sequence.
 
1145
         */
 
1146
        if ((so_s_width = ltgetnum("sg")) < 0)
 
1147
                so_s_width = 0;
 
1148
        so_e_width = so_s_width;
 
1149
 
 
1150
        bo_s_width = bo_e_width = so_s_width;
 
1151
        ul_s_width = ul_e_width = so_s_width;
 
1152
        bl_s_width = bl_e_width = so_s_width;
 
1153
 
 
1154
#if HILITE_SEARCH
 
1155
        if (so_s_width > 0 || so_e_width > 0)
 
1156
                /*
 
1157
                 * Disable highlighting by default on magic cookie terminals.
 
1158
                 * Turning on highlighting might change the displayed width
 
1159
                 * of a line, causing the display to get messed up.
 
1160
                 * The user can turn it back on with -g, 
 
1161
                 * but she won't like the results.
 
1162
                 */
 
1163
                hilite_search = 0;
 
1164
#endif
 
1165
 
 
1166
        /*
 
1167
         * Get various string-valued capabilities.
 
1168
         */
 
1169
        sp = sbuf;
 
1170
 
 
1171
#if HAVE_OSPEED
 
1172
        sc_pad = ltgetstr("pc", &sp);
 
1173
        if (sc_pad != NULL)
 
1174
                PC = *sc_pad;
 
1175
#endif
 
1176
 
 
1177
        sc_s_keypad = ltgetstr("ks", &sp);
 
1178
        if (sc_s_keypad == NULL)
 
1179
                sc_s_keypad = "";
 
1180
        sc_e_keypad = ltgetstr("ke", &sp);
 
1181
        if (sc_e_keypad == NULL)
 
1182
                sc_e_keypad = "";
 
1183
                
 
1184
        sc_init = ltgetstr("ti", &sp);
 
1185
        if (sc_init == NULL)
 
1186
                sc_init = "";
 
1187
 
 
1188
        sc_deinit= ltgetstr("te", &sp);
 
1189
        if (sc_deinit == NULL)
 
1190
                sc_deinit = "";
 
1191
 
 
1192
        sc_eol_clear = ltgetstr("ce", &sp);
 
1193
        if (sc_eol_clear == NULL || *sc_eol_clear == '\0')
 
1194
        {
 
1195
                missing_cap = 1;
 
1196
                sc_eol_clear = "";
 
1197
        }
 
1198
 
 
1199
        sc_eos_clear = ltgetstr("cd", &sp);
 
1200
        if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0'))
 
1201
        {
 
1202
                missing_cap = 1;
 
1203
                sc_eol_clear = "";
 
1204
        }
 
1205
 
 
1206
        sc_clear = ltgetstr("cl", &sp);
 
1207
        if (sc_clear == NULL || *sc_clear == '\0')
 
1208
        {
 
1209
                missing_cap = 1;
 
1210
                sc_clear = "\n\n";
 
1211
        }
 
1212
 
 
1213
        sc_move = ltgetstr("cm", &sp);
 
1214
        if (sc_move == NULL || *sc_move == '\0')
 
1215
        {
 
1216
                /*
 
1217
                 * This is not an error here, because we don't 
 
1218
                 * always need sc_move.
 
1219
                 * We need it only if we don't have home or lower-left.
 
1220
                 */
 
1221
                sc_move = "";
 
1222
                can_goto_line = 0;
 
1223
        } else
 
1224
                can_goto_line = 1;
 
1225
 
 
1226
        tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp);
 
1227
        tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp);
 
1228
        tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp);
 
1229
        tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp);
 
1230
 
 
1231
        sc_visual_bell = ltgetstr("vb", &sp);
 
1232
        if (sc_visual_bell == NULL)
 
1233
                sc_visual_bell = "";
 
1234
 
 
1235
        if (ltgetflag("bs"))
 
1236
                sc_backspace = "\b";
 
1237
        else
 
1238
        {
 
1239
                sc_backspace = ltgetstr("bc", &sp);
 
1240
                if (sc_backspace == NULL || *sc_backspace == '\0')
 
1241
                        sc_backspace = "\b";
 
1242
        }
 
1243
 
 
1244
        /*
 
1245
         * Choose between using "ho" and "cm" ("home" and "cursor move")
 
1246
         * to move the cursor to the upper left corner of the screen.
 
1247
         */
 
1248
        t1 = ltgetstr("ho", &sp);
 
1249
        if (t1 == NULL)
 
1250
                t1 = "";
 
1251
        if (*sc_move == '\0')
 
1252
                t2 = "";
 
1253
        else
 
1254
        {
 
1255
                strcpy(sp, tgoto(sc_move, 0, 0));
 
1256
                t2 = sp;
 
1257
                sp += strlen(sp) + 1;
 
1258
        }
 
1259
        sc_home = cheaper(t1, t2, "|\b^");
 
1260
 
 
1261
        /*
 
1262
         * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
 
1263
         * to move the cursor to the lower left corner of the screen.
 
1264
         */
 
1265
        t1 = ltgetstr("ll", &sp);
 
1266
        if (t1 == NULL)
 
1267
                t1 = "";
 
1268
        if (*sc_move == '\0')
 
1269
                t2 = "";
 
1270
        else
 
1271
        {
 
1272
                strcpy(sp, tgoto(sc_move, 0, sc_height-1));
 
1273
                t2 = sp;
 
1274
                sp += strlen(sp) + 1;
 
1275
        }
 
1276
        sc_lower_left = cheaper(t1, t2, "\r");
 
1277
 
 
1278
        /*
 
1279
         * Choose between using "al" or "sr" ("add line" or "scroll reverse")
 
1280
         * to add a line at the top of the screen.
 
1281
         */
 
1282
        t1 = ltgetstr("al", &sp);
 
1283
        if (t1 == NULL)
 
1284
                t1 = "";
 
1285
        t2 = ltgetstr("sr", &sp);
 
1286
        if (t2 == NULL)
 
1287
                t2 = "";
 
1288
#if OS2
 
1289
        if (*t1 == '\0' && *t2 == '\0')
 
1290
                sc_addline = "";
 
1291
        else
 
1292
#endif
 
1293
        if (above_mem)
 
1294
                sc_addline = t1;
 
1295
        else
 
1296
                sc_addline = cheaper(t1, t2, "");
 
1297
        if (*sc_addline == '\0')
 
1298
        {
 
1299
                /*
 
1300
                 * Force repaint on any backward movement.
 
1301
                 */
 
1302
                no_back_scroll = 1;
 
1303
        }
 
1304
#endif /* MSDOS_COMPILER */
 
1305
}
 
1306
 
 
1307
#if !MSDOS_COMPILER
 
1308
/*
 
1309
 * Return the cost of displaying a termcap string.
 
1310
 * We use the trick of calling tputs, but as a char printing function
 
1311
 * we give it inc_costcount, which just increments "costcount".
 
1312
 * This tells us how many chars would be printed by using this string.
 
1313
 * {{ Couldn't we just use strlen? }}
 
1314
 */
 
1315
static int costcount;
 
1316
 
 
1317
/*ARGSUSED*/
 
1318
        static int
 
1319
inc_costcount(c)
 
1320
        int c;
 
1321
{
 
1322
        costcount++;
 
1323
        return (c);
 
1324
}
 
1325
 
 
1326
        static int
 
1327
cost(t)
 
1328
        char *t;
 
1329
{
 
1330
        costcount = 0;
 
1331
        tputs(t, sc_height, inc_costcount);
 
1332
        return (costcount);
 
1333
}
 
1334
 
 
1335
/*
 
1336
 * Return the "best" of the two given termcap strings.
 
1337
 * The best, if both exist, is the one with the lower 
 
1338
 * cost (see cost() function).
 
1339
 */
 
1340
        static char *
 
1341
cheaper(t1, t2, def)
 
1342
        char *t1, *t2;
 
1343
        char *def;
 
1344
{
 
1345
        if (*t1 == '\0' && *t2 == '\0')
 
1346
        {
 
1347
                missing_cap = 1;
 
1348
                return (def);
 
1349
        }
 
1350
        if (*t1 == '\0')
 
1351
                return (t2);
 
1352
        if (*t2 == '\0')
 
1353
                return (t1);
 
1354
        if (cost(t1) < cost(t2))
 
1355
                return (t1);
 
1356
        return (t2);
 
1357
}
 
1358
 
 
1359
        static void
 
1360
tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp)
 
1361
        char *incap;
 
1362
        char *outcap;
 
1363
        char **instr;
 
1364
        char **outstr;
 
1365
        char *def_instr;
 
1366
        char *def_outstr;
 
1367
        char **spp;
 
1368
{
 
1369
        *instr = ltgetstr(incap, spp);
 
1370
        if (*instr == NULL)
 
1371
        {
 
1372
                /* Use defaults. */
 
1373
                *instr = def_instr;
 
1374
                *outstr = def_outstr;
 
1375
                return;
 
1376
        }
 
1377
 
 
1378
        *outstr = ltgetstr(outcap, spp);
 
1379
        if (*outstr == NULL)
 
1380
                /* No specific out capability; use "me". */
 
1381
                *outstr = ltgetstr("me", spp);
 
1382
        if (*outstr == NULL)
 
1383
                /* Don't even have "me"; use a null string. */
 
1384
                *outstr = "";
 
1385
}
 
1386
 
 
1387
#endif /* MSDOS_COMPILER */
 
1388
 
 
1389
 
 
1390
/*
 
1391
 * Below are the functions which perform all the 
 
1392
 * terminal-specific screen manipulation.
 
1393
 */
 
1394
 
 
1395
 
 
1396
#if MSDOS_COMPILER
 
1397
 
 
1398
#if MSDOS_COMPILER==WIN32C
 
1399
        static void
 
1400
_settextposition(int row, int col)
 
1401
{
 
1402
        COORD cpos;
 
1403
        CONSOLE_SCREEN_BUFFER_INFO csbi;
 
1404
 
 
1405
        GetConsoleScreenBufferInfo(con_out, &csbi);
 
1406
        cpos.X = csbi.srWindow.Left + (col - 1);
 
1407
        cpos.Y = csbi.srWindow.Top + (row - 1);
 
1408
        SetConsoleCursorPosition(con_out, cpos);
 
1409
}
 
1410
#endif
 
1411
 
 
1412
/*
 
1413
 * Initialize the screen to the correct color at startup.
 
1414
 */
 
1415
        static void
 
1416
initcolor()
 
1417
{
 
1418
        SETCOLORS(nm_fg_color, nm_bg_color);
 
1419
#if 0
 
1420
        /*
 
1421
         * This clears the screen at startup.  This is different from
 
1422
         * the behavior of other versions of less.  Disable it for now.
 
1423
         */
 
1424
        char *blanks;
 
1425
        int row;
 
1426
        int col;
 
1427
        
 
1428
        /*
 
1429
         * Create a complete, blank screen using "normal" colors.
 
1430
         */
 
1431
        SETCOLORS(nm_fg_color, nm_bg_color);
 
1432
        blanks = (char *) ecalloc(width+1, sizeof(char));
 
1433
        for (col = 0;  col < sc_width;  col++)
 
1434
                blanks[col] = ' ';
 
1435
        blanks[sc_width] = '\0';
 
1436
        for (row = 0;  row < sc_height;  row++)
 
1437
                _outtext(blanks);
 
1438
        free(blanks);
 
1439
#endif
 
1440
}
 
1441
#endif
 
1442
 
 
1443
#if MSDOS_COMPILER==WIN32C
 
1444
 
 
1445
/*
 
1446
 * Termcap-like init with a private win32 console.
 
1447
 */
 
1448
        static void
 
1449
win32_init_term()
 
1450
{
 
1451
        CONSOLE_SCREEN_BUFFER_INFO scr;
 
1452
        COORD size;
 
1453
 
 
1454
        if (con_out_save == INVALID_HANDLE_VALUE)
 
1455
                return;
 
1456
 
 
1457
        GetConsoleScreenBufferInfo(con_out_save, &scr);
 
1458
 
 
1459
        if (con_out_ours == INVALID_HANDLE_VALUE)
 
1460
        {
 
1461
                /*
 
1462
                 * Create our own screen buffer, so that we
 
1463
                 * may restore the original when done.
 
1464
                 */
 
1465
                con_out_ours = CreateConsoleScreenBuffer(
 
1466
                        GENERIC_WRITE | GENERIC_READ,
 
1467
                        FILE_SHARE_WRITE | FILE_SHARE_READ,
 
1468
                        (LPSECURITY_ATTRIBUTES) NULL,
 
1469
                        CONSOLE_TEXTMODE_BUFFER,
 
1470
                        (LPVOID) NULL);
 
1471
        }
 
1472
 
 
1473
        size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
 
1474
        size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
 
1475
        SetConsoleScreenBufferSize(con_out_ours, size);
 
1476
        SetConsoleActiveScreenBuffer(con_out_ours);
 
1477
        con_out = con_out_ours;
 
1478
}
 
1479
 
 
1480
/*
 
1481
 * Restore the startup console.
 
1482
 */
 
1483
static void
 
1484
win32_deinit_term()
 
1485
{
 
1486
        if (con_out_save == INVALID_HANDLE_VALUE)
 
1487
                return;
 
1488
        if (quitting)
 
1489
                (void) CloseHandle(con_out_ours);
 
1490
        SetConsoleActiveScreenBuffer(con_out_save);
 
1491
        con_out = con_out_save;
 
1492
}
 
1493
 
 
1494
#endif
 
1495
 
 
1496
/*
 
1497
 * Initialize terminal
 
1498
 */
 
1499
        public void
 
1500
init()
 
1501
{
 
1502
#if !MSDOS_COMPILER
 
1503
        if (!no_init)
 
1504
                tputs(sc_init, sc_height, putchr);
 
1505
        if (!no_keypad)
 
1506
                tputs(sc_s_keypad, sc_height, putchr);
 
1507
#else
 
1508
#if MSDOS_COMPILER==WIN32C
 
1509
        if (!no_init)
 
1510
                win32_init_term();
 
1511
#endif
 
1512
        initcolor();
 
1513
        flush();
 
1514
#endif
 
1515
        init_done = 1;
 
1516
}
 
1517
 
 
1518
/*
 
1519
 * Deinitialize terminal
 
1520
 */
 
1521
        public void
 
1522
deinit()
 
1523
{
 
1524
        if (!init_done)
 
1525
                return;
 
1526
#if !MSDOS_COMPILER
 
1527
        if (!no_keypad)
 
1528
                tputs(sc_e_keypad, sc_height, putchr);
 
1529
        if (!no_init)
 
1530
                tputs(sc_deinit, sc_height, putchr);
 
1531
#else
 
1532
        /* Restore system colors. */
 
1533
        SETCOLORS(sy_fg_color, sy_bg_color);
 
1534
#if MSDOS_COMPILER==WIN32C
 
1535
        if (!no_init)
 
1536
                win32_deinit_term();
 
1537
#else
 
1538
        /* Need clreol to make SETCOLORS take effect. */
 
1539
        clreol();
 
1540
#endif
 
1541
#endif
 
1542
        init_done = 0;
 
1543
}
 
1544
 
 
1545
/*
 
1546
 * Home cursor (move to upper left corner of screen).
 
1547
 */
 
1548
        public void
 
1549
home()
 
1550
{
 
1551
#if !MSDOS_COMPILER
 
1552
        tputs(sc_home, 1, putchr);
 
1553
#else
 
1554
        flush();
 
1555
        _settextposition(1,1);
 
1556
#endif
 
1557
}
 
1558
 
 
1559
/*
 
1560
 * Add a blank line (called with cursor at home).
 
1561
 * Should scroll the display down.
 
1562
 */
 
1563
        public void
 
1564
add_line()
 
1565
{
 
1566
#if !MSDOS_COMPILER
 
1567
        tputs(sc_addline, sc_height, putchr);
 
1568
#else
 
1569
        flush();
 
1570
#if MSDOS_COMPILER==MSOFTC
 
1571
        _scrolltextwindow(_GSCROLLDOWN);
 
1572
        _settextposition(1,1);
 
1573
#else
 
1574
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
1575
        movetext(1,1, sc_width,sc_height-1, 1,2);
 
1576
        gotoxy(1,1);
 
1577
        clreol();
 
1578
#else
 
1579
#if MSDOS_COMPILER==WIN32C
 
1580
    {
 
1581
        CHAR_INFO fillchar;
 
1582
        SMALL_RECT rcSrc, rcClip;
 
1583
        COORD new_org;
 
1584
        CONSOLE_SCREEN_BUFFER_INFO csbi;
 
1585
 
 
1586
        GetConsoleScreenBufferInfo(con_out,&csbi);
 
1587
 
 
1588
        /* The clip rectangle is the entire visible screen. */
 
1589
        rcClip.Left = csbi.srWindow.Left;
 
1590
        rcClip.Top = csbi.srWindow.Top;
 
1591
        rcClip.Right = csbi.srWindow.Right;
 
1592
        rcClip.Bottom = csbi.srWindow.Bottom;
 
1593
 
 
1594
        /* The source rectangle is the visible screen minus the last line. */
 
1595
        rcSrc = rcClip;
 
1596
        rcSrc.Bottom--;
 
1597
 
 
1598
        /* Move the top left corner of the source window down one row. */
 
1599
        new_org.X = rcSrc.Left;
 
1600
        new_org.Y = rcSrc.Top + 1;
 
1601
 
 
1602
        /* Fill the right character and attributes. */
 
1603
        fillchar.Char.AsciiChar = ' ';
 
1604
        curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
 
1605
        fillchar.Attributes = curr_attr;
 
1606
        ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
 
1607
        _settextposition(1,1);
 
1608
    }
 
1609
#endif
 
1610
#endif
 
1611
#endif
 
1612
#endif
 
1613
}
 
1614
 
 
1615
#if 0
 
1616
/*
 
1617
 * Remove the n topmost lines and scroll everything below it in the 
 
1618
 * window upward.  This is needed to stop leaking the topmost line 
 
1619
 * into the scrollback buffer when we go down-one-line (in WIN32).
 
1620
 */
 
1621
        public void
 
1622
remove_top(n)
 
1623
        int n;
 
1624
{
 
1625
#if MSDOS_COMPILER==WIN32C
 
1626
        SMALL_RECT rcSrc, rcClip;
 
1627
        CHAR_INFO fillchar;
 
1628
        COORD new_org;
 
1629
        CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
 
1630
 
 
1631
        if (n >= sc_height - 1)
 
1632
        {
 
1633
                clear();
 
1634
                home();
 
1635
                return;
 
1636
        }
 
1637
 
 
1638
        flush();
 
1639
 
 
1640
        GetConsoleScreenBufferInfo(con_out, &csbi);
 
1641
 
 
1642
        /* Get the extent of all-visible-rows-but-the-last. */
 
1643
        rcSrc.Left    = csbi.srWindow.Left;
 
1644
        rcSrc.Top     = csbi.srWindow.Top + n;
 
1645
        rcSrc.Right   = csbi.srWindow.Right;
 
1646
        rcSrc.Bottom  = csbi.srWindow.Bottom;
 
1647
 
 
1648
        /* Get the clip rectangle. */
 
1649
        rcClip.Left   = rcSrc.Left;
 
1650
        rcClip.Top    = csbi.srWindow.Top;
 
1651
        rcClip.Right  = rcSrc.Right;
 
1652
        rcClip.Bottom = rcSrc.Bottom ;
 
1653
 
 
1654
        /* Move the source window up n rows. */
 
1655
        new_org.X = rcSrc.Left;
 
1656
        new_org.Y = rcSrc.Top - n;
 
1657
 
 
1658
        /* Fill the right character and attributes. */
 
1659
        fillchar.Char.AsciiChar = ' ';
 
1660
        curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
 
1661
        fillchar.Attributes = curr_attr;
 
1662
 
 
1663
        ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
 
1664
 
 
1665
        /* Position cursor on first blank line. */
 
1666
        goto_line(sc_height - n - 1);
 
1667
#endif
 
1668
}
 
1669
#endif
 
1670
 
 
1671
#if MSDOS_COMPILER==WIN32C
 
1672
/*
 
1673
 * Clear the screen.
 
1674
 */
 
1675
        static void
 
1676
win32_clear()
 
1677
{
 
1678
        /*
 
1679
         * This will clear only the currently visible rows of the NT
 
1680
         * console buffer, which means none of the precious scrollback
 
1681
         * rows are touched making for faster scrolling.  Note that, if
 
1682
         * the window has fewer columns than the console buffer (i.e.
 
1683
         * there is a horizontal scrollbar as well), the entire width
 
1684
         * of the visible rows will be cleared.
 
1685
         */
 
1686
        COORD topleft;
 
1687
        DWORD nchars;
 
1688
        DWORD winsz;
 
1689
        CONSOLE_SCREEN_BUFFER_INFO csbi;
 
1690
 
 
1691
        /* get the number of cells in the current buffer */
 
1692
        GetConsoleScreenBufferInfo(con_out, &csbi);
 
1693
        winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
 
1694
        topleft.X = 0;
 
1695
        topleft.Y = csbi.srWindow.Top;
 
1696
 
 
1697
        curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
 
1698
        FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars);
 
1699
        FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars);
 
1700
}
 
1701
 
 
1702
/*
 
1703
 * Remove the n topmost lines and scroll everything below it in the 
 
1704
 * window upward.
 
1705
 */
 
1706
        public void
 
1707
win32_scroll_up(n)
 
1708
        int n;
 
1709
{
 
1710
        SMALL_RECT rcSrc, rcClip;
 
1711
        CHAR_INFO fillchar;
 
1712
        COORD topleft;
 
1713
        COORD new_org;
 
1714
        DWORD nchars;
 
1715
        DWORD size;
 
1716
        CONSOLE_SCREEN_BUFFER_INFO csbi;
 
1717
 
 
1718
        if (n <= 0)
 
1719
                return;
 
1720
 
 
1721
        if (n >= sc_height - 1)
 
1722
        {
 
1723
                win32_clear();
 
1724
                _settextposition(1,1);
 
1725
                return;
 
1726
        }
 
1727
 
 
1728
        /* Get the extent of what will remain visible after scrolling. */
 
1729
        GetConsoleScreenBufferInfo(con_out, &csbi);
 
1730
        rcSrc.Left    = csbi.srWindow.Left;
 
1731
        rcSrc.Top     = csbi.srWindow.Top + n;
 
1732
        rcSrc.Right   = csbi.srWindow.Right;
 
1733
        rcSrc.Bottom  = csbi.srWindow.Bottom;
 
1734
 
 
1735
        /* Get the clip rectangle. */
 
1736
        rcClip.Left   = rcSrc.Left;
 
1737
        rcClip.Top    = csbi.srWindow.Top;
 
1738
        rcClip.Right  = rcSrc.Right;
 
1739
        rcClip.Bottom = rcSrc.Bottom ;
 
1740
 
 
1741
        /* Move the source text to the top of the screen. */
 
1742
        new_org.X = rcSrc.Left;
 
1743
        new_org.Y = 0;
 
1744
 
 
1745
        /* Fill the right character and attributes. */
 
1746
        fillchar.Char.AsciiChar = ' ';
 
1747
        fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color);
 
1748
 
 
1749
        /* Scroll the window. */
 
1750
        SetConsoleTextAttribute(con_out, fillchar.Attributes);
 
1751
        ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
 
1752
 
 
1753
        /* Clear remaining lines at bottom. */
 
1754
        topleft.X = csbi.dwCursorPosition.X;
 
1755
        topleft.Y = rcSrc.Bottom - n;
 
1756
        size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X);
 
1757
        FillConsoleOutputCharacter(con_out, ' ', size, topleft,
 
1758
                &nchars);
 
1759
        FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft,
 
1760
                &nchars);
 
1761
        SetConsoleTextAttribute(con_out, curr_attr);
 
1762
 
 
1763
        /* Move cursor n lines up from where it was. */
 
1764
        csbi.dwCursorPosition.Y -= n;
 
1765
        SetConsoleCursorPosition(con_out, csbi.dwCursorPosition);
 
1766
}
 
1767
#endif
 
1768
 
 
1769
/*
 
1770
 * Move cursor to lower left corner of screen.
 
1771
 */
 
1772
        public void
 
1773
lower_left()
 
1774
{
 
1775
#if !MSDOS_COMPILER
 
1776
        tputs(sc_lower_left, 1, putchr);
 
1777
#else
 
1778
        flush();
 
1779
        _settextposition(sc_height, 1);
 
1780
#endif
 
1781
}
 
1782
 
 
1783
/*
 
1784
 * Check if the console size has changed and reset internals 
 
1785
 * (in lieu of SIGWINCH for WIN32).
 
1786
 */
 
1787
        public void
 
1788
check_winch()
 
1789
{
 
1790
#if MSDOS_COMPILER==WIN32C
 
1791
        CONSOLE_SCREEN_BUFFER_INFO scr;
 
1792
        COORD size;
 
1793
 
 
1794
        if (con_out == INVALID_HANDLE_VALUE)
 
1795
                return;
 
1796
 
 
1797
        flush();
 
1798
        GetConsoleScreenBufferInfo(con_out, &scr);
 
1799
        size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
 
1800
        size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
 
1801
        if (size.Y != sc_height || size.X != sc_width)
 
1802
        {
 
1803
                sc_height = size.Y;
 
1804
                sc_width = size.X;
 
1805
                if (!no_init && con_out_ours == con_out)
 
1806
                        SetConsoleScreenBufferSize(con_out, size);
 
1807
                pos_init();
 
1808
                wscroll = (sc_height + 1) / 2;
 
1809
                screen_trashed = 1;
 
1810
        }
 
1811
#endif
 
1812
}
 
1813
 
 
1814
/*
 
1815
 * Goto a specific line on the screen.
 
1816
 */
 
1817
        public void
 
1818
goto_line(slinenum)
 
1819
        int slinenum;
 
1820
{
 
1821
#if !MSDOS_COMPILER
 
1822
        tputs(tgoto(sc_move, 0, slinenum), 1, putchr);
 
1823
#else
 
1824
        flush();
 
1825
        _settextposition(slinenum+1, 1);
 
1826
#endif
 
1827
}
 
1828
 
 
1829
#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC
 
1830
/*
 
1831
 * Create an alternate screen which is all white.
 
1832
 * This screen is used to create a "flash" effect, by displaying it
 
1833
 * briefly and then switching back to the normal screen.
 
1834
 * {{ Yuck!  There must be a better way to get a visual bell. }}
 
1835
 */
 
1836
        static void
 
1837
create_flash()
 
1838
{
 
1839
#if MSDOS_COMPILER==MSOFTC
 
1840
        struct videoconfig w;
 
1841
        char *blanks;
 
1842
        int row, col;
 
1843
        
 
1844
        _getvideoconfig(&w);
 
1845
        videopages = w.numvideopages;
 
1846
        if (videopages < 2)
 
1847
        {
 
1848
                so_enter();
 
1849
                so_exit();
 
1850
        } else
 
1851
        {
 
1852
                _setactivepage(1);
 
1853
                so_enter();
 
1854
                blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
 
1855
                for (col = 0;  col < w.numtextcols;  col++)
 
1856
                        blanks[col] = ' ';
 
1857
                for (row = w.numtextrows;  row > 0;  row--)
 
1858
                        _outmem(blanks, w.numtextcols);
 
1859
                _setactivepage(0);
 
1860
                _setvisualpage(0);
 
1861
                free(blanks);
 
1862
                so_exit();
 
1863
        }
 
1864
#else
 
1865
#if MSDOS_COMPILER==BORLANDC
 
1866
        register int n;
 
1867
 
 
1868
        whitescreen = (unsigned short *) 
 
1869
                malloc(sc_width * sc_height * sizeof(short));
 
1870
        if (whitescreen == NULL)
 
1871
                return;
 
1872
        for (n = 0;  n < sc_width * sc_height;  n++)
 
1873
                whitescreen[n] = 0x7020;
 
1874
#else
 
1875
#if MSDOS_COMPILER==WIN32C
 
1876
        register int n;
 
1877
 
 
1878
        whitescreen = (WORD *)
 
1879
                malloc(sc_height * sc_width * sizeof(WORD));
 
1880
        if (whitescreen == NULL)
 
1881
                return;
 
1882
        /* Invert the standard colors. */
 
1883
        for (n = 0;  n < sc_width * sc_height;  n++)
 
1884
                whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color);
 
1885
#endif
 
1886
#endif
 
1887
#endif
 
1888
        flash_created = 1;
 
1889
}
 
1890
#endif /* MSDOS_COMPILER */
 
1891
 
 
1892
/*
 
1893
 * Output the "visual bell", if there is one.
 
1894
 */
 
1895
        public void
 
1896
vbell()
 
1897
{
 
1898
#if !MSDOS_COMPILER
 
1899
        if (*sc_visual_bell == '\0')
 
1900
                return;
 
1901
        tputs(sc_visual_bell, sc_height, putchr);
 
1902
#else
 
1903
#if MSDOS_COMPILER==DJGPPC
 
1904
        ScreenVisualBell();
 
1905
#else
 
1906
#if MSDOS_COMPILER==MSOFTC
 
1907
        /*
 
1908
         * Create a flash screen on the second video page.
 
1909
         * Switch to that page, then switch back.
 
1910
         */
 
1911
        if (!flash_created)
 
1912
                create_flash();
 
1913
        if (videopages < 2)
 
1914
                return;
 
1915
        _setvisualpage(1);
 
1916
        delay(100);
 
1917
        _setvisualpage(0);
 
1918
#else
 
1919
#if MSDOS_COMPILER==BORLANDC
 
1920
        unsigned short *currscreen;
 
1921
 
 
1922
        /*
 
1923
         * Get a copy of the current screen.
 
1924
         * Display the flash screen.
 
1925
         * Then restore the old screen.
 
1926
         */
 
1927
        if (!flash_created)
 
1928
                create_flash();
 
1929
        if (whitescreen == NULL)
 
1930
                return;
 
1931
        currscreen = (unsigned short *) 
 
1932
                malloc(sc_width * sc_height * sizeof(short));
 
1933
        if (currscreen == NULL) return;
 
1934
        gettext(1, 1, sc_width, sc_height, currscreen);
 
1935
        puttext(1, 1, sc_width, sc_height, whitescreen);
 
1936
        delay(100);
 
1937
        puttext(1, 1, sc_width, sc_height, currscreen);
 
1938
        free(currscreen);
 
1939
#else
 
1940
#if MSDOS_COMPILER==WIN32C
 
1941
        /* paint screen with an inverse color */
 
1942
        clear();
 
1943
 
 
1944
        /* leave it displayed for 100 msec. */
 
1945
        Sleep(100);
 
1946
 
 
1947
        /* restore with a redraw */
 
1948
        repaint();
 
1949
#endif
 
1950
#endif
 
1951
#endif
 
1952
#endif
 
1953
#endif
 
1954
}
 
1955
 
 
1956
/*
 
1957
 * Make a noise.
 
1958
 */
 
1959
        static void
 
1960
beep()
 
1961
{
 
1962
#if !MSDOS_COMPILER
 
1963
        putchr(CONTROL('G'));
 
1964
#else
 
1965
#if MSDOS_COMPILER==WIN32C
 
1966
        MessageBeep(0);
 
1967
#else
 
1968
        write(1, "\7", 1);
 
1969
#endif
 
1970
#endif
 
1971
}
 
1972
 
 
1973
/*
 
1974
 * Ring the terminal bell.
 
1975
 */
 
1976
        public void
 
1977
bell()
 
1978
{
 
1979
        if (quiet == VERY_QUIET)
 
1980
                vbell();
 
1981
        else
 
1982
                beep();
 
1983
}
 
1984
 
 
1985
/*
 
1986
 * Clear the screen.
 
1987
 */
 
1988
        public void
 
1989
clear()
 
1990
{
 
1991
#if !MSDOS_COMPILER
 
1992
        tputs(sc_clear, sc_height, putchr);
 
1993
#else
 
1994
        flush();
 
1995
#if MSDOS_COMPILER==WIN32C
 
1996
        win32_clear();
 
1997
#else
 
1998
        _clearscreen(_GCLEARSCREEN);
 
1999
#endif
 
2000
#endif
 
2001
}
 
2002
 
 
2003
/*
 
2004
 * Clear from the cursor to the end of the cursor's line.
 
2005
 * {{ This must not move the cursor. }}
 
2006
 */
 
2007
        public void
 
2008
clear_eol()
 
2009
{
 
2010
#if !MSDOS_COMPILER
 
2011
        tputs(sc_eol_clear, 1, putchr);
 
2012
#else
 
2013
#if MSDOS_COMPILER==MSOFTC
 
2014
        short top, left;
 
2015
        short bot, right;
 
2016
        struct rccoord tpos;
 
2017
        
 
2018
        flush();
 
2019
        /*
 
2020
         * Save current state.
 
2021
         */
 
2022
        tpos = _gettextposition();
 
2023
        _gettextwindow(&top, &left, &bot, &right);
 
2024
        /*
 
2025
         * Set a temporary window to the current line,
 
2026
         * from the cursor's position to the right edge of the screen.
 
2027
         * Then clear that window.
 
2028
         */
 
2029
        _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
 
2030
        _clearscreen(_GWINDOW);
 
2031
        /*
 
2032
         * Restore state.
 
2033
         */
 
2034
        _settextwindow(top, left, bot, right);
 
2035
        _settextposition(tpos.row, tpos.col);
 
2036
#else
 
2037
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
2038
        flush();
 
2039
        clreol();
 
2040
#else
 
2041
#if MSDOS_COMPILER==WIN32C
 
2042
        DWORD           nchars;
 
2043
        COORD           cpos;
 
2044
        CONSOLE_SCREEN_BUFFER_INFO scr;
 
2045
 
 
2046
        flush();
 
2047
        memset(&scr, 0, sizeof(scr));
 
2048
        GetConsoleScreenBufferInfo(con_out, &scr);
 
2049
        cpos.X = scr.dwCursorPosition.X;
 
2050
        cpos.Y = scr.dwCursorPosition.Y;
 
2051
        curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
 
2052
        FillConsoleOutputAttribute(con_out, curr_attr,
 
2053
                scr.dwSize.X - cpos.X, cpos, &nchars);
 
2054
        FillConsoleOutputCharacter(con_out, ' ',
 
2055
                scr.dwSize.X - cpos.X, cpos, &nchars);
 
2056
#endif
 
2057
#endif
 
2058
#endif
 
2059
#endif
 
2060
}
 
2061
 
 
2062
/*
 
2063
 * Clear the current line.
 
2064
 * Clear the screen if there's off-screen memory below the display.
 
2065
 */
 
2066
        static void
 
2067
clear_eol_bot()
 
2068
{
 
2069
#if MSDOS_COMPILER
 
2070
        clear_eol();
 
2071
#else
 
2072
        if (below_mem)
 
2073
                tputs(sc_eos_clear, 1, putchr);
 
2074
        else
 
2075
                tputs(sc_eol_clear, 1, putchr);
 
2076
#endif
 
2077
}
 
2078
 
 
2079
/*
 
2080
 * Clear the bottom line of the display.
 
2081
 * Leave the cursor at the beginning of the bottom line.
 
2082
 */
 
2083
        public void
 
2084
clear_bot()
 
2085
{
 
2086
        /*
 
2087
         * If we're in a non-normal attribute mode, temporarily exit
 
2088
         * the mode while we do the clear.  Some terminals fill the
 
2089
         * cleared area with the current attribute.
 
2090
         */
 
2091
        lower_left();
 
2092
        switch (attrmode)
 
2093
        {
 
2094
        case AT_STANDOUT:
 
2095
                so_exit();
 
2096
                clear_eol_bot();
 
2097
                so_enter();
 
2098
                break;
 
2099
        case AT_UNDERLINE:
 
2100
                ul_exit();
 
2101
                clear_eol_bot();
 
2102
                ul_enter();
 
2103
                break;
 
2104
        case AT_BOLD:
 
2105
                bo_exit();
 
2106
                clear_eol_bot();
 
2107
                bo_enter();
 
2108
                break;
 
2109
        case AT_BLINK:
 
2110
                bl_exit();
 
2111
                clear_eol_bot();
 
2112
                bl_enter();
 
2113
                break;
 
2114
        default:
 
2115
                clear_eol_bot();
 
2116
                break;
 
2117
        }
 
2118
}
 
2119
 
 
2120
/*
 
2121
 * Begin "standout" (bold, underline, or whatever).
 
2122
 */
 
2123
        public void
 
2124
so_enter()
 
2125
{
 
2126
#if !MSDOS_COMPILER
 
2127
        tputs(sc_s_in, 1, putchr);
 
2128
#else
 
2129
        flush();
 
2130
        SETCOLORS(so_fg_color, so_bg_color);
 
2131
#endif
 
2132
        attrmode = AT_STANDOUT;
 
2133
}
 
2134
 
 
2135
/*
 
2136
 * End "standout".
 
2137
 */
 
2138
        public void
 
2139
so_exit()
 
2140
{
 
2141
#if !MSDOS_COMPILER
 
2142
        tputs(sc_s_out, 1, putchr);
 
2143
#else
 
2144
        flush();
 
2145
        SETCOLORS(nm_fg_color, nm_bg_color);
 
2146
#endif
 
2147
        attrmode = AT_NORMAL;
 
2148
}
 
2149
 
 
2150
/*
 
2151
 * Begin "underline" (hopefully real underlining, 
 
2152
 * otherwise whatever the terminal provides).
 
2153
 */
 
2154
        public void
 
2155
ul_enter()
 
2156
{
 
2157
#if !MSDOS_COMPILER
 
2158
        tputs(sc_u_in, 1, putchr);
 
2159
#else
 
2160
        flush();
 
2161
        SETCOLORS(ul_fg_color, ul_bg_color);
 
2162
#endif
 
2163
        attrmode = AT_UNDERLINE;
 
2164
}
 
2165
 
 
2166
/*
 
2167
 * End "underline".
 
2168
 */
 
2169
        public void
 
2170
ul_exit()
 
2171
{
 
2172
#if !MSDOS_COMPILER
 
2173
        tputs(sc_u_out, 1, putchr);
 
2174
#else
 
2175
        flush();
 
2176
        SETCOLORS(nm_fg_color, nm_bg_color);
 
2177
#endif
 
2178
        attrmode = AT_NORMAL;
 
2179
}
 
2180
 
 
2181
/*
 
2182
 * Begin "bold"
 
2183
 */
 
2184
        public void
 
2185
bo_enter()
 
2186
{
 
2187
#if !MSDOS_COMPILER
 
2188
        tputs(sc_b_in, 1, putchr);
 
2189
#else
 
2190
        flush();
 
2191
        SETCOLORS(bo_fg_color, bo_bg_color);
 
2192
#endif
 
2193
        attrmode = AT_BOLD;
 
2194
}
 
2195
 
 
2196
/*
 
2197
 * End "bold".
 
2198
 */
 
2199
        public void
 
2200
bo_exit()
 
2201
{
 
2202
#if !MSDOS_COMPILER
 
2203
        tputs(sc_b_out, 1, putchr);
 
2204
#else
 
2205
        flush();
 
2206
        SETCOLORS(nm_fg_color, nm_bg_color);
 
2207
#endif
 
2208
        attrmode = AT_NORMAL;
 
2209
}
 
2210
 
 
2211
/*
 
2212
 * Begin "blink"
 
2213
 */
 
2214
        public void
 
2215
bl_enter()
 
2216
{
 
2217
#if !MSDOS_COMPILER
 
2218
        tputs(sc_bl_in, 1, putchr);
 
2219
#else
 
2220
        flush();
 
2221
        SETCOLORS(bl_fg_color, bl_bg_color);
 
2222
#endif
 
2223
        attrmode = AT_BLINK;
 
2224
}
 
2225
 
 
2226
/*
 
2227
 * End "blink".
 
2228
 */
 
2229
        public void
 
2230
bl_exit()
 
2231
{
 
2232
#if !MSDOS_COMPILER
 
2233
        tputs(sc_bl_out, 1, putchr);
 
2234
#else
 
2235
        flush();
 
2236
        SETCOLORS(nm_fg_color, nm_bg_color);
 
2237
#endif
 
2238
        attrmode = AT_NORMAL;
 
2239
}
 
2240
 
 
2241
#if 0 /* No longer used */
 
2242
/*
 
2243
 * Erase the character to the left of the cursor 
 
2244
 * and move the cursor left.
 
2245
 */
 
2246
        public void
 
2247
backspace()
 
2248
{
 
2249
#if !MSDOS_COMPILER
 
2250
        /* 
 
2251
         * Erase the previous character by overstriking with a space.
 
2252
         */
 
2253
        tputs(sc_backspace, 1, putchr);
 
2254
        putchr(' ');
 
2255
        tputs(sc_backspace, 1, putchr);
 
2256
#else
 
2257
#if MSDOS_COMPILER==MSOFTC
 
2258
        struct rccoord tpos;
 
2259
        
 
2260
        flush();
 
2261
        tpos = _gettextposition();
 
2262
        if (tpos.col <= 1)
 
2263
                return;
 
2264
        _settextposition(tpos.row, tpos.col-1);
 
2265
        _outtext(" ");
 
2266
        _settextposition(tpos.row, tpos.col-1);
 
2267
#else
 
2268
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
2269
        cputs("\b");
 
2270
#else
 
2271
#if MSDOS_COMPILER==WIN32C
 
2272
        COORD cpos;
 
2273
        DWORD cChars;
 
2274
        CONSOLE_SCREEN_BUFFER_INFO scr;
 
2275
 
 
2276
        flush();
 
2277
        GetConsoleScreenBufferInfo(con_out, &scr);
 
2278
        cpos = scr.dwCursorPosition;
 
2279
        if (cpos.X <= 0)
 
2280
                return;
 
2281
        cpos.X--;
 
2282
        SetConsoleCursorPosition(con_out, cpos);
 
2283
        FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars);
 
2284
        SetConsoleCursorPosition(con_out, cpos);
 
2285
#endif
 
2286
#endif
 
2287
#endif
 
2288
#endif
 
2289
}
 
2290
#endif /* 0 */
 
2291
 
 
2292
/*
 
2293
 * Output a plain backspace, without erasing the previous char.
 
2294
 */
 
2295
        public void
 
2296
putbs()
 
2297
{
 
2298
#if !MSDOS_COMPILER
 
2299
        tputs(sc_backspace, 1, putchr);
 
2300
#else
 
2301
        int row, col;
 
2302
 
 
2303
        flush();
 
2304
        {
 
2305
#if MSDOS_COMPILER==MSOFTC
 
2306
                struct rccoord tpos;
 
2307
                tpos = _gettextposition();
 
2308
                row = tpos.row;
 
2309
                col = tpos.col;
 
2310
#else
 
2311
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 
2312
                row = wherey();
 
2313
                col = wherex();
 
2314
#else
 
2315
#if MSDOS_COMPILER==WIN32C
 
2316
                CONSOLE_SCREEN_BUFFER_INFO scr;
 
2317
                GetConsoleScreenBufferInfo(con_out, &scr);
 
2318
                row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1;
 
2319
                col = scr.dwCursorPosition.X - scr.srWindow.Left + 1;
 
2320
#endif
 
2321
#endif
 
2322
#endif
 
2323
        }
 
2324
        if (col <= 1)
 
2325
                return;
 
2326
        _settextposition(row, col-1);
 
2327
#endif /* MSDOS_COMPILER */
 
2328
}
 
2329
 
 
2330
#if MSDOS_COMPILER==WIN32C
 
2331
/*
 
2332
 * Determine whether an input character is waiting to be read.
 
2333
 */
 
2334
        static int
 
2335
win32_kbhit(tty)
 
2336
        HANDLE tty;
 
2337
{
 
2338
        INPUT_RECORD ip;
 
2339
        DWORD read;
 
2340
 
 
2341
        if (keyCount > 0)
 
2342
                return (TRUE);
 
2343
 
 
2344
        currentKey.ascii = 0;
 
2345
        currentKey.scan = 0;
 
2346
 
 
2347
        /*
 
2348
         * Wait for a real key-down event, but
 
2349
         * ignore SHIFT and CONTROL key events.
 
2350
         */
 
2351
        do
 
2352
        {
 
2353
                PeekConsoleInput(tty, &ip, 1, &read);
 
2354
                if (read == 0)
 
2355
                        return (FALSE);
 
2356
                ReadConsoleInput(tty, &ip, 1, &read);
 
2357
        } while (ip.EventType != KEY_EVENT ||
 
2358
                ip.Event.KeyEvent.bKeyDown != TRUE ||
 
2359
                ip.Event.KeyEvent.wVirtualScanCode == 0 ||
 
2360
                ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
 
2361
                ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL ||
 
2362
                ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU);
 
2363
                
 
2364
        currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar;
 
2365
        currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode;
 
2366
        keyCount = ip.Event.KeyEvent.wRepeatCount;
 
2367
 
 
2368
        if (ip.Event.KeyEvent.dwControlKeyState & 
 
2369
                (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
 
2370
        {
 
2371
                switch (currentKey.scan)
 
2372
                {
 
2373
                case PCK_ALT_E:     /* letter 'E' */
 
2374
                        currentKey.ascii = 0;
 
2375
                        break;
 
2376
                }
 
2377
        } else if (ip.Event.KeyEvent.dwControlKeyState & 
 
2378
                (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
 
2379
        {
 
2380
                switch (currentKey.scan)
 
2381
                {
 
2382
                case PCK_RIGHT: /* right arrow */
 
2383
                        currentKey.scan = PCK_CTL_RIGHT;
 
2384
                        break;
 
2385
                case PCK_LEFT: /* left arrow */
 
2386
                        currentKey.scan = PCK_CTL_LEFT;
 
2387
                        break;
 
2388
                case PCK_DELETE: /* delete */
 
2389
                        currentKey.scan = PCK_CTL_DELETE;
 
2390
                        break;
 
2391
                }
 
2392
        }
 
2393
        return (TRUE);
 
2394
}
 
2395
 
 
2396
/*
 
2397
 * Read a character from the keyboard.
 
2398
 */
 
2399
        public char
 
2400
WIN32getch(tty)
 
2401
        int tty;
 
2402
{
 
2403
        int ascii;
 
2404
 
 
2405
        if (pending_scancode)
 
2406
        {
 
2407
                pending_scancode = 0;
 
2408
                return ((char)(currentKey.scan & 0x00FF));
 
2409
        }
 
2410
 
 
2411
        while (win32_kbhit((HANDLE)tty) == FALSE)
 
2412
        {
 
2413
                Sleep(20);
 
2414
                if (ABORT_SIGS())
 
2415
                        return ('\003');
 
2416
                continue;
 
2417
        }
 
2418
        keyCount --;
 
2419
        ascii = currentKey.ascii;
 
2420
        /*
 
2421
         * On PC's, the extended keys return a 2 byte sequence beginning 
 
2422
         * with '00', so if the ascii code is 00, the next byte will be 
 
2423
         * the lsb of the scan code.
 
2424
         */
 
2425
        pending_scancode = (ascii == 0x00);
 
2426
        return ((char)ascii);
 
2427
}
 
2428
#endif