1 /*
2 * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
3 * Copyright (c) 1996-2005 Michael T Pins. All rights reserved.
4 *
5 * Terminal interface.
6 */
7 #define raw __curses__raw__
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <signal.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include "config.h"
19 #include "global.h"
20 #include "execute.h"
21 #include "folder.h"
22 #include "keymap.h"
23 #include "macro.h"
24 #include "nn.h"
25 #include "regexp.h"
26 #include "nn_term.h"
27
28 #if !defined(__FreeBSD__) && !(__NetBSD__) && !defined(NeXT)
29 #include <stropts.h>
30 #else
31 #include <sys/ioctl.h>
32 #endif
33
34 #ifdef RESIZING
35 #include <sys/ioctl.h> /* for TIOCGWINSZ */
36
37 extern int s_resized;
38 #endif /* RESIZING */
39
40 #ifdef FAKE_INTERRUPT
41 #include <setjmp.h>
42 #endif
43
44 #ifdef HAVE_TERMIOS_H
45 #include <termios.h>
46 #endif
47
48 #ifdef USE_TERMINFO
49 #include <curses.h>
50
51 #ifndef VINTR
52 #include <termio.h> /* some systems don't include this in
53 * curses.h */
54 #endif /* VINTR */
55
56 #ifndef auto_left_margin
57 #include <term.h>
58 #endif /* !auto_left_margin */
59
60 #else
61 #define USE_TERMCAP
62
63 #if !defined(SUNOS4) && !defined(NeXT)
64 #include <termcap.h>
65 #endif /* SUNOS4 */
66
67 #endif
68
69 #ifdef HAVE_TERMIO_H
70
71 #ifdef USE_TERMCAP
72 #include <termio.h>
73 #endif /* USE_TERMCAP */
74
75 #else
76
77 #ifndef __FreeBSD__
78 #include <sgtty.h>
79 #endif /* __FreeBSD__ */
80
81 #endif
82
83 #ifdef SYSV_RESIZING
84 #include <sys/stream.h>
85 #include <sys/ptem.h>
86 #endif /* SYSV_RESIZING */
87
88 /* SYSV curses.h clash */
89 #undef raw
90
91 /* AIX term.h clash */
92
93 #ifdef _AIX
94 #undef Lines
95 #undef Columns
96 #endif /* _AIX */
97
98 #ifdef __osf__
99 void cfmakeraw(struct termios * t);
100 #endif
101
102 /* term.c */
103
104 #ifdef HAVE_TERMIOS_H
105 static int outc(int c);
106 #else
107 static int outc(char c);
108 #endif
109
110 static void set_term_speed(register unsigned long sp);
111 static void raw_not_ok_error(void);
112 static sig_type rd_timeout(int n);
113 static int read_char_kbd(int tmo);
114 static void unread_char(int c);
115 static int nnstandout(int);
116
117 static sig_type catch_winch(int n);
118
119 void visual_on(void);
120 void xterm_mouse_on(void);
121 void xterm_mouse_off(void);
122
123 extern int data_bits;
124 extern int batch_mode;
125 extern char *help_directory;
126
127 extern void ding();
128 extern void clrmsg();
129 extern void gotoxy();
130
131 struct msg_list {
132 char *buf;
133 struct msg_list *prev;
134 };
135
136 static struct msg_list *msg_stack = NULL, *msg_ptr = NULL;
137
138 int message_history = 15;
139 char *term_name = NULL;
140 int show_current_time = 1;
141 int conf_dont_sleep = 0;
142 int prompt_length;
143 int terminal_speed = 0;
144 int slow_speed = 1200;
145 int any_message = 0;
146 int flow_control = 1;
147 int use_visible_bell = 1; /* if supported by terminal */
148 int ignore_xon_xoff = 1;
149 int multi_key_guard_time = 2; /* tenths of a second */
150 int guard_double_slash = 0; /* need /// or //+ to clear line */
151 char *shade_on_attr = NULL;
152 char *shade_off_attr = NULL;
153 int mouse_state; /* if xterm is in mouse state */
154 int mouse_usage; /* 0 don't set mouse, 1 only if xterm, 2 set
155 * mouse */
156
157 key_type help_key = '?';
158 key_type comp1_key = SP;
159 key_type comp2_key = TAB;
160 key_type erase_key, kill_key;
161 key_type delword_key = CONTROL_('W');
162
163 static char bell_str[256] = "\007";
164 static int appl_keypad_mode = 0;
165
166 #ifdef USE_TERMINFO
167 #define HAS_CAP(str) (str && *str)
168
169 extern char *tgoto(); /* some systems don't have this in term.h */
170
171 #else
172
173 char *tgoto();
174 char PC;
175 char *BC, *UP;
176 char nnspeed;
177
178 static char XBC[64], XUP[64];
179 static char enter_ca_mode[64], exit_ca_mode[64];
180 static char cursor_home[64];
181 static char cursor_address[128];
182 static char clear_screen[64];
183 static char clr_eol[64];
184 static char clr_eos[64];
185 static char enter_standout_mode[64], exit_standout_mode[64];
186 static char enter_underline_mode[64], exit_underline_mode[64];
187 static char key_down[64], key_up[64], key_right[64], key_left[64];
188 static char keypad_local[64], keypad_xmit[64];
189
190 int magic_cookie_glitch; /* magic cookie size */
191 int ceol_standout_glitch; /* hp brain damage! */
192 int auto_right_margin; /* automatic right margin */
193 int eat_newline_glitch; /* newline ignored at right margin */
194
195 #define putp(str) tputs(str, 1, outc)
196
197 #define HAS_CAP(str) (*str)
198 #endif /* USE_TERMCAP */
199
200 static char key_mouse_d1[64] = "\33[M ";
201 static char key_mouse_d2[64] = "\33[M!";
202 static char key_mouse_d3[64] = "\33[M\"";
203 static char key_mouse_u1[64] = "\33[M#";
204
205 /*
206 * Compute the greatest multiple of p not greater than x.
207 * p must be a power of 2.
208 * x must be nonnegative, for portability to non-2's-complement hosts.
209 */
210 #define DISCARD_REMAINDER(x,p) ((x) & ~((p)-1))
211
212 #ifdef HAVE_TERMIOS_H
213 static int
outc(int c)214 outc(int c)
215 #else
216 static int
217 outc(char c)
218 #endif
219 {
220 putchar(c);
221 return 0; /* XXX What is it supposed to return? */
222 }
223
224 #define putpc(str, cnt) tputs(str, cnt, outc)
225
226 int Lines, Columns; /* screen size */
227 int Name_Length; /* length of displayed name */
228 int cookie_size; /* size of magic cookie */
229 static int two_cookies; /* space needed to enter&exit standout mode */
230 int STANDOUT; /* terminal got standout mode */
231
232 static int curxy_c = 0, curxy_l = -1, savxy_c = 0, savxy_l = -1;
233 static int just_sent_cr = 0; /* just sent \r to avoid 'xn' term
234 * attribute */
235
236 static int *nonsp; /* number of non-space characters on line */
237
238 #ifdef TERM_DEBUG
239 static char *term_debug = NULL;
240 extern char *getenv();
241 #define curxy_nonsp (curxy_l < 0 ? -1 : nonsp[curxy_l])
242 #endif
243
244 #ifdef FAKE_INTERRUPT
245 extern jmp_buf fake_keyb_sig;
246 extern int arm_fake_keyb_sig;
247 extern char fake_keyb_siglist[];
248 #endif /* FAKE_INTERRUPT */
249
250 #if defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)
251 /* This used to be 50, but there are some rather complex bugs in the SYSV */
252 /* TERMIO driver... */
253 #define KEY_BURST 2 /* read bursts of 1 char (or timeout after
254 * 100 ms) */
255
256 #undef CBREAK
257
258 #ifdef HAVE_TERMIOS_H
259 static struct termios norm_tty, raw_tty;
260 #else
261 static struct termio norm_tty, raw_tty;
262 #endif
263
264 #define IntrC ((key_type) norm_tty.c_cc[VINTR])
265 #define EraseC ((key_type) norm_tty.c_cc[VERASE])
266 #define KillC ((key_type) norm_tty.c_cc[VKILL])
267
268 #ifdef HAVE_TERMIOS_H
269 #define SuspC ((key_type) norm_tty.c_cc[VSUSP])
270 #else
271 #define SuspC ((key_type) CONTROL_('Z')) /* norm_tty.c_cc[SWTCH] */
272 #endif
273
274 #else /* V7/BSD TTY DRIVER */
275
276 static struct sgttyb norm_tty, raw_tty;
277 static struct tchars norm_chars;
278
279 #define IntrC ((key_type) norm_chars.t_intrc)
280 #define EraseC ((key_type) norm_tty.sg_erase)
281 #define KillC ((key_type) norm_tty.sg_kill)
282
283 #ifdef TIOCGLTC
284 static struct ltchars spec_chars;
285 #define SuspC ((key_type) spec_chars.t_suspc)
286 #else
287 #define SuspC ((key_type) CONTROL_('Z'))
288 #endif
289
290 #endif
291
292 #ifdef USE_TERMCAP
293 static int
opt_cap(char * cap,char * buf)294 opt_cap(char *cap, char *buf)
295 {
296 char *tgetstr();
297
298 *buf = NUL;
299 return tgetstr(cap, &buf) != NULL;
300 }
301
302 static void
get_cap(char * cap,char * buf)303 get_cap(char *cap, char *buf)
304 {
305 if (!opt_cap(cap, buf))
306 nn_exitmsg(1, "TERMCAP entry for %s has no '%s' capability",
307 term_name, cap);
308 }
309
310 #endif /* USE_TERMCAP */
311
312 /*
313 * timeout in n/10 seconds via SIGALRM
314 */
315
316 static void
micro_alarm(int n)317 micro_alarm(int n)
318 {
319
320 #ifdef HAVE_UALARM
321 ualarm(n <= 1 ? 100000 : n * 100000, 0); /* 4.3 BSD ualarm() */
322 #else
323
324 #ifdef MICRO_ALARM
325 if (n <= 0)
326 n = 1;
327 MICRO_ALARM(n); /* System specific timeout */
328 #else
329 alarm(n <= 10 ? 1 : (n + 9) / 10); /* Standard alarm() call */
330 #endif /* MICRO_ALARM */
331
332 #endif /* HAVE_UALARM */
333 }
334
335 static int multi_keys = 0;
336
337 static struct multi_key {
338 key_type *cur_key;
339 key_type *keys;
340 key_type code;
341 } multi_key_list[MULTI_KEYS];
342
343 void
enter_multi_key(int code,key_type * keys)344 enter_multi_key(int code, key_type * keys)
345 {
346 register int i;
347
348 if (strlen((char *) keys) == 1)
349 /* will ignore arrow keys overlaying these keys */
350 if (*keys == NL || *keys == CR ||
351 *keys == erase_key || *keys == kill_key ||
352 *keys == IntrC)
353 return;
354
355 /* lookup code to see if it is already defined... */
356 for (i = 0; i < multi_keys; i++)
357 if (multi_key_list[i].code == (key_type) code)
358 goto replace_key;
359
360 i = multi_keys++;
361
362 /* now i points to matching or empty slot */
363 if (i >= MULTI_KEYS) {
364 /* should never happen */
365 log_entry('E', "too many multi keys");
366 return;
367 }
368 replace_key:
369
370 multi_key_list[i].keys = keys;
371 multi_key_list[i].code = code;
372 }
373
374 void
dump_multi_keys(void)375 dump_multi_keys(void)
376 {
377 register int i;
378 register key_type *cp;
379
380 clrdisp();
381 pg_init(0, 1);
382
383 for (i = 0; i < multi_keys; i++) {
384 if (pg_next() < 0)
385 break;
386 tprintf("%d\t%s\t", i, key_name(multi_key_list[i].code));
387 for (cp = multi_key_list[i].keys; *cp; cp++)
388 tprintf(" %s", key_name(*cp));
389 }
390
391 pg_end();
392 }
393
394
395 #ifdef RESIZING
396 static sig_type
catch_winch(int n)397 catch_winch(int n)
398 {
399 struct winsize winsize;
400 int i;
401
402 signal(SIGWINCH, catch_winch);
403 if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
404 && (winsize.ws_row != Lines || winsize.ws_col != Columns)) {
405 nonsp = resizeobj(nonsp, int, winsize.ws_row);
406 if ((int) winsize.ws_row > Lines)
407 for (i = Lines; i < (int) winsize.ws_row; i++)
408 nonsp[i] = winsize.ws_col;
409 if ((int) winsize.ws_col < Columns)
410 for (i = 0; i < (int) winsize.ws_row; i++)
411 if (nonsp[i] > (int) winsize.ws_col)
412 nonsp[i] = winsize.ws_col;
413 Lines = winsize.ws_row;
414 Columns = winsize.ws_col;
415 Name_Length = Columns / 5;
416 if (Name_Length < NAME_LENGTH)
417 Name_Length = NAME_LENGTH;
418 curxy_l = -1;
419 s_redraw = 1;
420 s_resized = 1;
421 }
422
423 #ifdef FAKE_INTERRUPT
424 if (fake_keyb_siglist[n] && arm_fake_keyb_sig)
425 longjmp(fake_keyb_sig, 1);
426 #endif /* FAKE_INTERRUPT */
427 }
428
429 #endif /* RESIZING */
430
431 #ifdef SV_INTERRUPT
432
433 #ifdef NO_SIGINTERRUPT
434 static int
siginterrupt(signo,on)435 siginterrupt(signo, on)
436 {
437 struct sigvec sv;
438 sv.sv_handler = signal(signo, SIG_DFL);
439 sv.sv_mask = 0;
440 sv.sv_flags = on ? SV_INTERRUPT : 0;
441 sigvec(signo, &sv, 0);
442 }
443
444 #endif /* NO_SIGINTERRUPT */
445
446 #endif /* SV_INTERRUPT */
447
448 #ifdef FAKE_INTERRUPT
449 #define SV_INTERRUPT
450 static int
siginterrupt(signo,on)451 siginterrupt(signo, on)
452 {
453 fake_keyb_siglist[signo] = on;
454 }
455
456 #endif /* FAKE_INTERRUPT */
457
458 static unsigned sp_table[] = {
459 B9600, 960,
460
461 #ifdef B19200
462 B19200, 1920,
463 #else
464
465 #ifdef EXTA
466 EXTA, 1920,
467 #endif /* EXTA */
468
469 #endif /* B19200 */
470
471 #ifdef B38400
472 B38400, 3840,
473 #else
474
475 #ifdef EXTB
476 EXTB, 3840,
477 #endif /* EXTB */
478
479 #endif /* B38400 */
480
481 B1200, 120,
482 B2400, 240,
483 B4800, 480,
484 B300, 30,
485 0, 0
486 };
487
488 static void
set_term_speed(register unsigned long sp)489 set_term_speed(register unsigned long sp)
490 {
491 register unsigned *tp;
492
493 for (tp = sp_table; *tp; tp += 2)
494 if (*tp == sp) {
495 terminal_speed = tp[1];
496 return;
497 }
498 terminal_speed = 30;
499 }
500
501 static void
raw_not_ok_error(void)502 raw_not_ok_error(void)
503 {
504 if (batch_mode)
505 return;
506 nn_exitmsg(1, "Not prepared for terminal i/o");
507 /* NOTREACHED */
508 }
509
510
511 #define RAW_CHECK if (terminal_speed == 0) {raw_not_ok_error(); return 0;}
512 #define RAW_CHECK_V if (terminal_speed == 0) {raw_not_ok_error(); return;}
513 #define BATCH_CHECK if (terminal_speed == 0) return 0
514 #define BATCH_CHECK_V if (terminal_speed == 0) return
515
516 void
init_term(int full)517 init_term(int full)
518 {
519
520 #ifdef USE_TERMCAP
521 char tbuf[1024];
522 #endif
523
524 int i;
525
526 #ifdef TERM_DEBUG
527 term_debug = getenv("TERM_DEBUG");
528 if (term_debug)
529 fprintf(stderr, "init_term(%d)\n", full);
530 #endif
531
532 if (batch_mode) {
533 term_name = "batch";
534 close(0);
535 open("/dev/null", 0);
536 STANDOUT = 0;
537 cookie_size = 1;
538 return;
539 }
540 if ((term_name = getenv("TERM")) == NULL) {
541 if (full)
542 nn_exitmsg(1, "No TERM variable in environment");
543 else
544 term_name = "unknown";
545 }
546 if (!full)
547 return;
548
549 #ifdef HAVE_TERMIO_H
550 ioctl(0, TCGETA, &norm_tty);
551 #else
552
553 #ifdef HAVE_TERMIOS_H
554 tcgetattr(0, &norm_tty);
555 #else
556 ioctl(0, TIOCGETP, &norm_tty);
557 #endif /* HAVE_TERMIOS_H */
558
559 #endif /* HAVE_TERMIO_H */
560
561 #ifdef USE_TERMINFO
562 setupterm((char *) NULL, 1, (int *) NULL);
563 Columns = columns;
564 Lines = lines;
565 if (use_visible_bell && HAS_CAP(flash_screen))
566 strcpy(bell_str, flash_screen);
567 else if (HAS_CAP(bell))
568 strcpy(bell_str, bell);
569 if (!HAS_CAP(cursor_home))
570 cursor_home = copy_str(tgoto(cursor_address, 0, 0));
571 #else
572
573 if (tgetent(tbuf, term_name) <= 0)
574 nn_exitmsg(1, "Unknown terminal type: %s", term_name);
575
576 if (opt_cap("bc", XBC))
577 BC = XBC;
578 if (opt_cap("up", XUP))
579 UP = XUP;
580 opt_cap("pc", cursor_address); /* temp. usage */
581 PC = cursor_address[0];
582
583 get_cap("cm", cursor_address);
584 if (!opt_cap("ho", cursor_home))
585 strcpy(cursor_home, tgoto(cursor_address, 0, 0));
586
587 get_cap("cl", clear_screen);
588 opt_cap("ce", clr_eol);
589 opt_cap("cd", clr_eos);
590
591 Lines = tgetnum("li");
592 Columns = tgetnum("co");
593
594 opt_cap("so", enter_standout_mode);
595 opt_cap("se", exit_standout_mode);
596
597 opt_cap("us", enter_underline_mode);
598 opt_cap("ue", exit_underline_mode);
599
600 opt_cap("kd", key_down);
601 opt_cap("ku", key_up);
602 opt_cap("kr", key_right);
603 opt_cap("kl", key_left);
604
605 magic_cookie_glitch = tgetnum("sg");
606
607 ceol_standout_glitch = tgetflag("xs");
608 auto_right_margin = tgetflag("am");
609 eat_newline_glitch = tgetflag("xn");
610
611 opt_cap("ti", enter_ca_mode);
612 opt_cap("te", exit_ca_mode);
613 opt_cap("ks", keypad_xmit); /* used to turn "application cursor */
614 opt_cap("ke", keypad_local);/* key" mode on and off (sometimes) */
615
616 if (!use_visible_bell || !opt_cap("vb", bell_str))
617 if (!opt_cap("bl", bell_str))
618 strcpy(bell_str, "\007");
619 #endif /* USE_TERMINFO */
620
621 #ifdef RESIZING
622 {
623 struct winsize winsize;
624
625 if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
626 && winsize.ws_row != 0 && winsize.ws_col != 0) {
627 Lines = winsize.ws_row;
628 Columns = winsize.ws_col;
629 signal(SIGWINCH, catch_winch);
630
631 #ifdef SV_INTERRUPT
632 siginterrupt(SIGWINCH, 1); /* make read from tty interruptable */
633 #endif /* SV_INTERRUPT */
634 }
635 }
636 #endif /* RESIZING */
637
638 /* Stop NN from blowing up if on a *really* dumb terminal, like "dumb" */
639 if (Lines < 1)
640 Lines = 24;
641 if (Columns < 1)
642 Columns = 80;
643
644 nonsp = newobj(int, Lines);
645 for (i = 0; i < Lines; i++)
646 nonsp[i] = Columns;
647
648 STANDOUT = HAS_CAP(enter_standout_mode);
649 cookie_size = magic_cookie_glitch;
650 if (STANDOUT) {
651 if (cookie_size < 0)
652 cookie_size = 0;
653 two_cookies = 2 * cookie_size;
654 } else
655 cookie_size = two_cookies = 0;
656
657 raw_tty = norm_tty;
658
659 #ifdef HAVE_TERMIO_H
660 raw_tty.c_iflag &= ~(BRKINT | INLCR | ICRNL | IGNCR | ISTRIP);
661 raw_tty.c_iflag |= IGNBRK | IGNPAR;
662 raw_tty.c_oflag &= ~OPOST;
663 raw_tty.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | NOFLSH);
664
665 /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
666 raw_tty.c_cc[VMIN] = KEY_BURST;
667 raw_tty.c_cc[VTIME] = ((int) (raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2;
668 set_term_speed((unsigned long) (raw_tty.c_cflag & CBAUD));
669 #else
670
671 #ifdef HAVE_TERMIOS_H
672 cfmakeraw(&raw_tty);
673 /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
674 raw_tty.c_cc[VMIN] = KEY_BURST;
675
676 #if 0
677 raw_tty.c_cc[VTIME] = (cfgetispeed(&raw_tty) > B1200) ? 1 : 2;
678 #else
679 raw_tty.c_cc[VTIME] = 1;
680 #endif /* 0 */
681
682 set_term_speed((unsigned long) cfgetospeed(&raw_tty));
683
684 #ifdef SV_INTERRUPT
685 siginterrupt(SIGTSTP, 1);
686 siginterrupt(SIGALRM, 1);
687 #endif /* SV_INTERRUPT */
688
689 #else
690 ioctl(0, TIOCGETC, &norm_chars);
691
692 #ifdef TIOCGLTC
693 ioctl(0, TIOCGLTC, &spec_chars);
694 #endif /* TIOCGLTC */
695
696 nnspeed = norm_tty.sg_ospeed;
697 set_term_speed((unsigned long) nnspeed);
698
699 raw_tty.sg_flags &= ~(ECHO | CRMOD);
700
701 #ifdef CBREAK
702
703 #ifdef SV_INTERRUPT /* make read from tty interruptable */
704 siginterrupt(SIGTSTP, 1); /* this is necessary to redraw screen */
705 #endif /* SV_INTERRUPT */
706
707 raw_tty.sg_flags |= CBREAK;
708 #else
709 raw_tty.sg_flags |= RAW;
710 #endif /* CBREAK */
711
712 #ifdef SV_INTERRUPT
713 siginterrupt(SIGALRM, 1); /* make read from tty interruptable */
714 #endif /* SV_INTERRUPT */
715
716 #endif /* HAVE_TERMIOS_H */
717
718 #endif /* HAVE_TERMIO_H */
719
720 Name_Length = Columns / 5;
721 if (Name_Length < NAME_LENGTH)
722 Name_Length = NAME_LENGTH;
723
724 erase_key = EraseC;
725 kill_key = KillC;
726
727 if (HAS_CAP(key_down))
728 enter_multi_key(K_down_arrow, (key_type *) key_down);
729 if (HAS_CAP(key_up))
730 enter_multi_key(K_up_arrow, (key_type *) key_up);
731 if (HAS_CAP(key_right))
732 enter_multi_key(K_right_arrow, (key_type *) key_right);
733 if (HAS_CAP(key_left))
734 enter_multi_key(K_left_arrow, (key_type *) key_left);
735
736 enter_multi_key(K_m_d1, (key_type *) key_mouse_d1);
737 enter_multi_key(K_m_d2, (key_type *) key_mouse_d2);
738 enter_multi_key(K_m_d3, (key_type *) key_mouse_d3);
739 enter_multi_key(K_m_u1, (key_type *) key_mouse_u1);
740
741 appl_keypad_mode = (HAS_CAP(keypad_xmit) && HAS_CAP(keypad_local));
742 if (!HAS_CAP(key_up))
743 appl_keypad_mode = 0; /* no cursor keys */
744 if (appl_keypad_mode) {
745 /* Use of ks/ke isn't consistent, so we must guess what to do. */
746 /* If termcap expects keys to send ESC [, don't switch */
747 appl_keypad_mode = (key_up[0] != '\033' || key_up[1] != '[');
748 }
749 if ((mouse_usage == 2) || ((mouse_usage == 1)
750 && !strncmp("xterm", term_name, 5))) {
751 mouse_state = 1;
752 flow_control = 0;
753 } else {
754 mouse_state = 0;
755 }
756 visual_on();
757 }
758
759 void
home(void)760 home(void)
761 {
762 BATCH_CHECK_V;
763
764 #ifdef TERM_DEBUG
765 if (term_debug)
766 fprintf(stderr, "home\n");
767 #endif
768
769 putp(cursor_home);
770 curxy_c = curxy_l = 0;
771 }
772
773 void
save_xy(void)774 save_xy(void)
775 {
776 savxy_c = curxy_c;
777 savxy_l = curxy_l;
778 }
779
780 void
restore_xy(void)781 restore_xy(void)
782 {
783 if (savxy_l < 0)
784 return;
785 gotoxy(savxy_c, savxy_l);
786 fl;
787 }
788
789 void
gotoxy(int c,int l)790 gotoxy(int c, int l)
791 {
792 BATCH_CHECK_V;
793
794 #ifdef TERM_DEBUG
795 if (term_debug)
796 fprintf(stderr, "gotoxy %d %d -> %d %d\n", curxy_c, curxy_l, c, l);
797 #endif
798
799 if (Columns <= (unsigned) c || Lines <= (unsigned) l)
800 return;
801
802 if (!(c | l))
803 putp(cursor_home);
804 else
805 putp(tgoto(cursor_address, c, l));
806 curxy_c = c;
807 curxy_l = l;
808 }
809
810 void
clrdisp(void)811 clrdisp(void)
812 {
813 int i;
814
815 BATCH_CHECK_V;
816
817 #ifdef TERM_DEBUG
818 if (term_debug)
819 fprintf(stderr, "clrdisp\n");
820 #endif
821
822 putpc(clear_screen, Lines);
823 curxy_c = curxy_l = 0;
824 savxy_l = -1;
825 for (i = 0; i < Lines; i++)
826 nonsp[i] = 0;
827 msg_ptr = msg_stack;
828 }
829
830 void clrline_noflush();
831
832 void
clrline(void)833 clrline(void)
834 {
835 BATCH_CHECK_V;
836
837 /* If we moved the cursor left to avoid weird effects, don't clear. */
838 if (just_sent_cr)
839 return;
840
841 clrline_noflush();
842 fl;
843 }
844
845 void
clrline_noflush(void)846 clrline_noflush(void)
847 {
848 int oldxy_c, oldxy_l, spcnt;
849
850 BATCH_CHECK_V;
851
852 #ifdef TERM_DEBUG
853 if (term_debug)
854 fprintf(stderr, "clrline %d %d [%d]", curxy_c, curxy_l, curxy_nonsp);
855 #endif
856
857 if (curxy_l < 0)
858 return;
859
860 /* remainder of line already blank? */
861
862 if (curxy_c >= nonsp[curxy_l]) {
863
864 #ifdef TERM_DEBUG
865 if (term_debug)
866 fprintf(stderr, " ignored\n");
867 #endif
868
869 return;
870 }
871 if (HAS_CAP(clr_eol)) {
872
873 #ifdef TERM_DEBUG
874 if (term_debug)
875 fprintf(stderr, "\n");
876 #endif
877
878 putp(clr_eol);
879 } else {
880 oldxy_c = curxy_c;
881 oldxy_l = curxy_l;
882
883 spcnt = nonsp[curxy_l] - curxy_c;
884
885 /* guard against scroll */
886
887 if (auto_right_margin && curxy_l == Lines - 1 && curxy_c + spcnt == Columns)
888 spcnt--;
889
890 #ifdef TERM_DEBUG
891 if (term_debug)
892 fprintf(stderr, " %d\n", spcnt);
893 #endif /* TERM_DEBUG */
894
895 #ifdef TERM_DEBUG
896 if (term_debug && *term_debug) {
897 while (spcnt--)
898 tputc(*term_debug);
899 spcnt = 0;
900 }
901 #endif
902
903 /* clear out line */
904
905 while (spcnt--)
906 tputc(SP);
907
908 if (curxy_c != oldxy_c || curxy_l != oldxy_l)
909 gotoxy(oldxy_c, oldxy_l);
910 }
911 nonsp[curxy_l] = curxy_c;
912 }
913
914 void
clrpage(void)915 clrpage(void)
916 {
917 int oldxy_c, oldxy_l, i;
918
919 BATCH_CHECK_V;
920
921 #ifdef TERM_DEBUG
922 if (term_debug)
923 fprintf(stderr, "clrpage %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
924 #endif
925
926 if (curxy_l < 0)
927 return;
928
929 oldxy_c = curxy_c;
930 oldxy_l = curxy_l;
931
932 /* code below only handles curxy_c == 0 */
933
934 if (curxy_c != 0) {
935 clrline();
936 if (curxy_l < Lines - 1)
937 gotoxy(0, curxy_l + 1);
938 }
939 /* clear to end of screen */
940
941 if (curxy_c == 0) {
942 if (HAS_CAP(clr_eos)) {
943 putpc(clr_eos, Lines - curxy_l);
944 for (i = curxy_l; i < Lines; i++)
945 nonsp[i] = 0;
946 } else if (curxy_l == 0) {
947 putpc(clear_screen, Lines);
948 for (i = 0; i < Lines; i++)
949 nonsp[i] = 0;
950 } else {
951 for (i = curxy_l; i < Lines; i++) {
952 if (nonsp[i] != 0) {
953 gotoxy(0, i);
954 clrline_noflush();
955 }
956 }
957 }
958 }
959 if (curxy_c != oldxy_c || curxy_l != oldxy_l)
960 gotoxy(oldxy_c, oldxy_l);
961
962 fl;
963 msg_ptr = msg_stack;
964 }
965
966 static char buf[512];
967
968 static void
tvprintf(char * fmt,va_list ap)969 tvprintf(char *fmt, va_list ap)
970 {
971 char *str;
972
973 vsprintf(buf, fmt, ap);
974 for (str = buf; *str; str++)
975 tputc(*str);
976 }
977
978 void
tprintf(char * fmt,...)979 tprintf(char *fmt,...)
980 {
981 va_list ap;
982
983 va_start(ap, fmt);
984 tvprintf(fmt, ap);
985 va_end(ap);
986 }
987
988 void
tputc(int c)989 tputc(int c)
990 {
991 int i;
992
993 #ifdef TERM_DEBUG
994 if (term_debug) {
995 fprintf(stderr, "tputc %d %d [%d] ", curxy_c, curxy_l, curxy_nonsp);
996 if (c < ' ' || c > '~')
997 switch (c) {
998 case 0:
999 fprintf(stderr, "'NUL'");
1000 break;
1001 case 1:
1002 fprintf(stderr, "'SOH'");
1003 break;
1004 case 2:
1005 fprintf(stderr, "'STX'");
1006 break;
1007 case 3:
1008 fprintf(stderr, "'ETX'");
1009 break;
1010 case 4:
1011 fprintf(stderr, "'EOT'");
1012 break;
1013 case 5:
1014 fprintf(stderr, "'ENQ'");
1015 break;
1016 case 6:
1017 fprintf(stderr, "'ACK'");
1018 break;
1019 case 7:
1020 fprintf(stderr, "'BEL'");
1021 break;
1022 case 8:
1023 fprintf(stderr, "'BS'");
1024 break;
1025 case 9:
1026 fprintf(stderr, "'HT'");
1027 break;
1028 case 10:
1029 fprintf(stderr, "'NL'");
1030 break;
1031 case 11:
1032 fprintf(stderr, "'VT'");
1033 break;
1034 case 12:
1035 fprintf(stderr, "'NP'");
1036 break;
1037 case 13:
1038 fprintf(stderr, "'CR'");
1039 break;
1040 case 14:
1041 fprintf(stderr, "'SP'");
1042 break;
1043 case 15:
1044 fprintf(stderr, "'SI'");
1045 break;
1046 case 16:
1047 fprintf(stderr, "'DLE'");
1048 break;
1049 case 17:
1050 fprintf(stderr, "'DC1'");
1051 break;
1052 case 18:
1053 fprintf(stderr, "'DC2'");
1054 break;
1055 case 19:
1056 fprintf(stderr, "'DC3'");
1057 break;
1058 case 20:
1059 fprintf(stderr, "'DC4'");
1060 break;
1061 case 21:
1062 fprintf(stderr, "'NAK'");
1063 break;
1064 case 22:
1065 fprintf(stderr, "'SYN'");
1066 break;
1067 case 23:
1068 fprintf(stderr, "'ETB'");
1069 break;
1070 case 24:
1071 fprintf(stderr, "'CAN'");
1072 break;
1073 case 25:
1074 fprintf(stderr, "'EM'");
1075 break;
1076 case 26:
1077 fprintf(stderr, "'SUB'");
1078 break;
1079 case 27:
1080 fprintf(stderr, "'ESC'");
1081 break;
1082 case 28:
1083 fprintf(stderr, "'FS'");
1084 break;
1085 case 29:
1086 fprintf(stderr, "'GS'");
1087 break;
1088 case 30:
1089 fprintf(stderr, "'RS'");
1090 break;
1091 case 31:
1092 fprintf(stderr, "'US'");
1093 break;
1094 case 32:
1095 fprintf(stderr, "'SP'");
1096 break;
1097 default:
1098 fprintf(stderr, "out of range: ???");
1099 break;
1100 }
1101 else
1102 fprintf(stderr, "'%c'", c);
1103 }
1104 #endif
1105
1106 just_sent_cr = 0;
1107
1108 putchar(c);
1109
1110 switch (c) {
1111
1112 case '\n':
1113 curxy_c = 0;
1114 if (curxy_l >= 0)
1115 curxy_l++;
1116 break;
1117
1118 case '\r':
1119 curxy_c = 0;
1120 break;
1121
1122 case '\t':
1123 curxy_c = DISCARD_REMAINDER(curxy_c + 8, 8);
1124 break;
1125
1126 case '\b':
1127 curxy_c--;
1128 break;
1129
1130 case ' ':
1131 curxy_c++;
1132 if (curxy_l >= 0 && nonsp[curxy_l] == curxy_c)
1133 nonsp[curxy_l]--;
1134 break;
1135
1136 default:
1137 curxy_c++;
1138 if (curxy_l >= 0 && nonsp[curxy_l] < curxy_c)
1139 nonsp[curxy_l] = curxy_c;
1140 break;
1141
1142 }
1143
1144 #ifdef TERM_DEBUG
1145 if (term_debug)
1146 fprintf(stderr, " -> %d %d [%d]", curxy_c, curxy_l, curxy_nonsp);
1147 #endif
1148
1149 /* account for right margin */
1150
1151 if (curxy_c == Columns) {
1152
1153 #ifdef TERM_DEBUG
1154 if (term_debug)
1155 fprintf(stderr, " margin");
1156 #endif
1157
1158 if (auto_right_margin) {
1159 if (eat_newline_glitch) {
1160 putchar(CR);
1161 just_sent_cr = 1;
1162 curxy_c = 0;
1163 } else {
1164 curxy_c = 0;
1165 if (curxy_l >= 0)
1166 curxy_l++;
1167 }
1168 } else
1169 curxy_c--;
1170 }
1171 /* account for vertical scroll */
1172
1173 if (curxy_l == Lines) {
1174
1175 #ifdef TERM_DEBUG
1176 if (term_debug)
1177 fprintf(stderr, " scroll");
1178 #endif
1179
1180 for (i = 1; i < Lines; i++)
1181 nonsp[i - 1] = nonsp[i];
1182 nonsp[--curxy_l] = 0;
1183 }
1184
1185 #ifdef TERM_DEBUG
1186 if (term_debug)
1187 fprintf(stderr, "\n");
1188 #endif
1189 }
1190
1191 static char so_buf[512], *so_p;
1192 static int so_c, so_l, so_b, so_active = 0;
1193
1194 int
so_gotoxy(int c,int l,int blank)1195 so_gotoxy(int c, int l, int blank)
1196 {
1197 if (!STANDOUT && c >= 0) {
1198 if (c >= 0 && l >= 0)
1199 gotoxy(c, l);
1200 return 0;
1201 }
1202 so_active++;
1203 so_c = c;
1204 so_l = l;
1205 so_b = blank;
1206 so_p = so_buf;
1207 *so_p = NUL;
1208
1209 return 1; /* not really true if not standout & c < 0 */
1210 }
1211
1212 static void
so_vprintf(char * fmt,va_list ap)1213 so_vprintf(char *fmt, va_list ap)
1214 {
1215 if (!so_active) {
1216 if (ceol_standout_glitch)
1217 highlight(0); /* xxx why? */
1218 tvprintf(fmt, ap);
1219 return;
1220 }
1221 vsprintf(so_p, fmt, ap);
1222 while (*so_p)
1223 so_p++;
1224 }
1225
1226 void
so_printf(char * fmt,...)1227 so_printf(char *fmt,...)
1228 {
1229 va_list ap;
1230
1231 va_start(ap, fmt);
1232 so_vprintf(fmt, ap);
1233 va_end(ap);
1234 }
1235
1236 void
so_end(void)1237 so_end(void)
1238 {
1239 int len;
1240
1241 if (!so_active)
1242 return;
1243
1244 if (so_l >= 0) {
1245
1246 len = so_p - so_buf + two_cookies;
1247
1248 if (so_c < 0)
1249 so_c = Columns - len - 2;
1250 if (so_c < 0)
1251 so_c = 0;
1252
1253 if (len + so_c >= Columns) {
1254 len = Columns - so_c - two_cookies;
1255 so_buf[len] = NUL;
1256 }
1257 if (cookie_size) {
1258 gotoxy(so_c + len - cookie_size, so_l);
1259 nnstandout(0);
1260 }
1261 gotoxy(so_c, so_l);
1262
1263 }
1264 if ((so_b & 1) && (!STANDOUT || !cookie_size))
1265 tputc(SP);
1266
1267 if (STANDOUT) {
1268 if (ceol_standout_glitch)
1269 clrline();
1270 nnstandout(1);
1271 }
1272 tprintf("%s", so_buf);
1273
1274 if (STANDOUT)
1275 nnstandout(0);
1276
1277 if ((so_b & 2) && (!STANDOUT || !cookie_size))
1278 tputc(SP);
1279
1280 so_active = 0;
1281 }
1282
1283
1284 void
so_printxy(int c,int l,char * fmt,...)1285 so_printxy(int c, int l, char *fmt,...)
1286 {
1287 va_list ap;
1288
1289 va_start(ap, fmt);
1290 so_gotoxy(c, l, 0);
1291 so_vprintf(fmt, ap);
1292 so_end();
1293 va_end(ap);
1294 }
1295
1296
1297 int
underline(int on)1298 underline(int on)
1299 {
1300 if (cookie_size)
1301 return 0;
1302
1303 #ifdef TERM_DEBUG
1304 if (term_debug)
1305 fprintf(stderr, "underline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
1306 #endif
1307
1308 if (!HAS_CAP(enter_underline_mode))
1309 return 0;
1310 putp(on ? enter_underline_mode : exit_underline_mode);
1311 return 1;
1312 }
1313
1314 int
highlight(int on)1315 highlight(int on)
1316 {
1317 if (cookie_size)
1318 return 0;
1319
1320 #ifdef TERM_DEBUG
1321 if (term_debug)
1322 fprintf(stderr, "highlight %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
1323 #endif
1324
1325 if (!HAS_CAP(enter_standout_mode))
1326 return 0;
1327 putp(on ? enter_standout_mode : exit_standout_mode);
1328 return 1;
1329 }
1330
1331 int
shadeline(int on)1332 shadeline(int on)
1333 {
1334 if (cookie_size)
1335 return 0;
1336
1337 #ifdef TERM_DEBUG
1338 if (term_debug)
1339 fprintf(stderr, "shadeline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
1340 #endif
1341
1342 if (shade_on_attr && shade_off_attr) {
1343 putp(on ? shade_on_attr : shade_off_attr);
1344 return 1;
1345 } else
1346 return underline(1);
1347 }
1348
1349 static int
nnstandout(int on)1350 nnstandout(int on)
1351 {
1352
1353 #ifdef TERM_DEBUG
1354 if (term_debug)
1355 fprintf(stderr, "standout %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
1356 #endif
1357
1358 if (!HAS_CAP(enter_standout_mode))
1359 return 0;
1360 putp(on ? enter_standout_mode : exit_standout_mode);
1361 curxy_c += cookie_size;
1362 if (curxy_l >= 0 && curxy_c > nonsp[curxy_l])
1363 nonsp[curxy_l] = curxy_c;
1364
1365 #ifdef TERM_DEBUG
1366 if (term_debug)
1367 fprintf(stderr, " -> %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
1368 #endif
1369
1370 return 1;
1371 }
1372
1373 static int is_visual = 0;
1374 static int is_raw = 0;
1375
1376 #ifdef HAVE_TERMIO_H
1377 #define RAW_MODE_ON ioctl(0, TCSETAW, &raw_tty)
1378 #define RAW_MODE_OFF ioctl(0, TCSETAW, &norm_tty)
1379 #else
1380
1381 #ifdef HAVE_TERMIOS_H
1382 #define RAW_MODE_ON tcsetattr(0, TCSADRAIN, &raw_tty)
1383 #define RAW_MODE_OFF tcsetattr(0, TCSADRAIN, &norm_tty)
1384 #else
1385 #define RAW_MODE_ON ioctl(0, TIOCSETP, &raw_tty)
1386 #define RAW_MODE_OFF ioctl(0, TIOCSETP, &norm_tty)
1387 #endif /* HAVE_TERMIOS_H */
1388
1389 #endif /* HAVE_TERMIO_H */
1390
1391 void
xterm_mouse_on(void)1392 xterm_mouse_on(void)
1393 {
1394 putp("\33[?1000h");
1395 }
1396
1397 void
xterm_mouse_off(void)1398 xterm_mouse_off(void)
1399 {
1400 putp("\33[?1000l");
1401 }
1402
1403 void
visual_on(void)1404 visual_on(void)
1405 {
1406 BATCH_CHECK_V;
1407
1408 if (terminal_speed == 0)
1409 return;
1410
1411 #ifdef TERM_DEBUG
1412 if (term_debug)
1413 fprintf(stderr, "visual_on\n");
1414 #endif
1415
1416 if (!is_visual) {
1417 if (HAS_CAP(enter_ca_mode))
1418 putp(enter_ca_mode);
1419 if (appl_keypad_mode)
1420 putp(keypad_xmit);
1421 if (mouse_state)
1422 xterm_mouse_on();
1423 fl;
1424 }
1425 is_visual = 1;
1426 }
1427
1428 int
visual_off(void)1429 visual_off(void)
1430 {
1431 int was_raw = is_raw;
1432
1433 if (terminal_speed == 0)
1434 return 0;
1435
1436 #ifdef TERM_DEBUG
1437 if (term_debug)
1438 fprintf(stderr, "visual_off\n");
1439 #endif
1440
1441 if (is_visual) {
1442 if (appl_keypad_mode)
1443 putp(keypad_local);
1444 if (HAS_CAP(exit_ca_mode))
1445 putp(exit_ca_mode);
1446 if (mouse_state)
1447 xterm_mouse_off();
1448 fl;
1449 }
1450 is_visual = 0;
1451
1452 is_raw = 1;
1453 unset_raw();
1454
1455 return was_raw;
1456 }
1457
1458
1459 #ifdef CBREAK
1460 void
nn_raw(void)1461 nn_raw(void)
1462 {
1463 RAW_CHECK_V;
1464
1465 if (is_raw == 1)
1466 return;
1467 is_raw = 1;
1468 RAW_MODE_ON;
1469 }
1470
1471 int
no_raw(void)1472 no_raw(void)
1473 {
1474 return 0;
1475 }
1476
1477 int
unset_raw(void)1478 unset_raw(void)
1479 {
1480 if (is_raw == 0)
1481 return 0;
1482 RAW_CHECK;
1483 RAW_MODE_OFF;
1484 is_raw = 0;
1485 return 1;
1486 }
1487
1488 #else /* not CBREAK */
1489 static int must_set_raw = 1;
1490
1491 #undef raw
1492 void
nn_raw(void)1493 nn_raw(void)
1494 {
1495 RAW_CHECK_V;
1496
1497 if (!flow_control) {
1498 if (!must_set_raw)
1499 return;
1500 must_set_raw = 0;
1501 }
1502 if (is_raw)
1503 return;
1504
1505 RAW_MODE_ON;
1506 is_raw++;
1507 }
1508
1509 int
no_raw(void)1510 no_raw(void)
1511 {
1512 if (!flow_control)
1513 return 0;
1514
1515 if (!is_raw)
1516 return 0;
1517
1518 RAW_CHECK;
1519
1520 RAW_MODE_OFF;
1521
1522 is_raw = 0;
1523
1524 return 1;
1525 }
1526
1527 int
unset_raw(void)1528 unset_raw(void)
1529 {
1530 int was_raw = is_raw;
1531
1532 if (is_raw) {
1533 RAW_CHECK;
1534 RAW_MODE_OFF;
1535 is_raw = 0;
1536 }
1537 if (!flow_control)
1538 must_set_raw = 1;
1539 return was_raw;
1540 }
1541
1542 #endif /* CBREAK */
1543
1544 #ifndef KEY_BURST
1545 #define KEY_BURST 32
1546 #endif /* KEY_BURST */
1547
1548 #define RD_PUSHBACK 10
1549 static char rd_buffer[KEY_BURST + RD_PUSHBACK]; /* Holds stuff from read */
1550 static char *rd_ptr;
1551 static int rd_count = 0, rd_alarm = 0;
1552
1553 #ifdef FAKE_INTERRUPT
1554 static jmp_buf fake_alarm_sig;
1555 #endif /* FAKE_INTERRUPT */
1556
1557 static sig_type
rd_timeout(int n)1558 rd_timeout(int n)
1559 {
1560 rd_alarm = 1;
1561
1562 #ifdef FAKE_INTERRUPT
1563 longjmp(fake_alarm_sig, 1);
1564 #endif /* FAKE_INTERRUPT */
1565 }
1566
1567 #define RD_TIMEOUT 0x1000
1568 #define RD_INTERRUPT 0x1001
1569
1570 static int
read_char_kbd(int tmo)1571 read_char_kbd(int tmo)
1572 /* tmo timeout if no input arrives */
1573 {
1574 if (rd_count <= 0) {
1575 if (tmo) {
1576
1577 #ifdef FAKE_INTERRUPT
1578 if (setjmp(fake_alarm_sig))
1579 goto tmout;
1580 #endif /* FAKE_INTERRUPT */
1581
1582 rd_alarm = 0;
1583 signal(SIGALRM, rd_timeout);
1584 micro_alarm(multi_key_guard_time);
1585 }
1586 rd_ptr = rd_buffer + RD_PUSHBACK;
1587 rd_count = read(0, rd_ptr, KEY_BURST);
1588 if (tmo) {
1589 if (rd_alarm)
1590 goto tmout;
1591 alarm(0);
1592 }
1593 if (rd_count < 0) {
1594 if (errno != EINTR)
1595 s_hangup++;
1596 return RD_INTERRUPT;
1597 }
1598 }
1599 --rd_count;
1600 return *rd_ptr++;
1601
1602 tmout:
1603 rd_count = 0;
1604 return RD_TIMEOUT;
1605 }
1606
1607 static void
unread_char(int c)1608 unread_char(int c)
1609 {
1610 if (rd_ptr == rd_buffer)
1611 return;
1612 rd_count++;
1613 *--rd_ptr = c;
1614 }
1615
1616 void
flush_input(void)1617 flush_input(void)
1618 {
1619
1620 #ifndef HAVE_TERMIO_H
1621
1622 #if !defined(HAVE_TERMIOS_H) && defined(FREAD)
1623 int arg;
1624 #endif
1625
1626 #endif
1627
1628 BATCH_CHECK_V;
1629
1630 #ifdef HAVE_TERMIO_H
1631 ioctl(0, TCFLSH, 0);
1632 #else
1633
1634 #ifdef HAVE_TERMIOS_H
1635 ioctl(0, TCIFLUSH);
1636 #else
1637
1638 #ifdef FREAD
1639 arg = FREAD;
1640 ioctl(0, TIOCFLUSH, &arg);
1641 #else
1642 ioctl(0, TIOCFLUSH, 0);
1643 #endif /* FREAD */
1644
1645 #endif /* HAVE_TERMIOS_H */
1646
1647 #endif /* HAVE_TERMIO_H */
1648
1649 rd_count = 0;
1650 }
1651
1652 int enable_stop = 1;
1653
1654 static int do_macro_processing = 1;
1655 int mouse_y = -1;
1656 static int mouse_last = 0;
1657
1658 int
get_c(void)1659 get_c(void)
1660 {
1661 key_type c, first_key;
1662 int key_cnt, mc, n;
1663 register struct multi_key *mk, *multi_match;
1664 register int i;
1665
1666 multi_match = NULL;
1667 first_key = 0;
1668 mouse_y = -1;
1669
1670 next_key:
1671 if (s_hangup)
1672 return K_interrupt;
1673
1674 if (do_macro_processing)
1675 switch (m_getc(&mc)) {
1676 case 0:
1677 break;
1678 case 1:
1679 return mc;
1680 case 2:
1681 return K_interrupt;
1682 }
1683
1684 #ifdef RESIZING
1685 if (s_resized)
1686 goto redraw;
1687 #endif /* RESIZING */
1688
1689 if (batch_mode)
1690 nn_exitmsg(1, "Attempt to read keyboard input in batch mode");
1691
1692 for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
1693 mk->cur_key = mk->keys;
1694 key_cnt = 0;
1695
1696 #ifdef FAKE_INTERRUPT
1697 if (setjmp(fake_keyb_sig))
1698 goto intr;
1699 arm_fake_keyb_sig = 1;
1700 #endif /* FAKE_INTERRUPT */
1701
1702 multi:
1703 switch (n = read_char_kbd(key_cnt)) {
1704
1705 case RD_INTERRUPT:
1706
1707 #ifdef CBREAK
1708 if (s_redraw)
1709 goto redraw;
1710 #endif /* CBREAK */
1711
1712 #ifdef RESIZING
1713 if (s_resized)
1714 goto redraw;
1715 #endif /* RESIZING */
1716
1717 goto intr;
1718
1719 case RD_TIMEOUT:
1720 while (--key_cnt > 0)
1721 unread_char(multi_match->keys[key_cnt]);
1722 c = first_key;
1723 goto got_char;
1724
1725 default:
1726 c = (key_type) n;
1727 if (data_bits < 8)
1728 c &= 0x7f;
1729 if (ignore_xon_xoff)
1730 if (c == CONTROL_('Q') || c == CONTROL_('S'))
1731 goto multi;
1732 break;
1733 }
1734
1735 multi_match = NULL;
1736 for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) {
1737 if (mk->cur_key == NUL)
1738 continue;
1739 if (*(mk->cur_key)++ != c) {
1740 mk->cur_key = NUL;
1741 continue;
1742 }
1743 if (*(mk->cur_key) == NUL) {
1744 c = mk->code;
1745
1746 /*
1747 * xterm mouse specific code, translate cursor position into
1748 * static variables, synthesize key up events
1749 */
1750 if ((c >= K_m_d1) && (c <= K_m_u1)) {
1751 mouse_y = read_char_kbd(key_cnt) - '!';
1752 if (c == K_m_u1) {
1753 if (mouse_last == K_m_d2) {
1754 c = K_m_u2;
1755 } else if (mouse_last == K_m_d3) {
1756 c = K_m_u3;
1757 }
1758 }
1759 mouse_last = c;
1760 }
1761 goto got_char;
1762 }
1763 multi_match = mk;
1764 }
1765
1766 if (multi_match) {
1767 if (key_cnt == 0)
1768 first_key = c;
1769 key_cnt++;
1770 goto multi;
1771 }
1772 if (key_cnt) {
1773 if (key_cnt == 1 && first_key == 033) {
1774 unread_char(c);
1775 c = 033;
1776 goto got_char;
1777 }
1778 ding();
1779 flush_input();
1780 goto next_key;
1781 }
1782 got_char:
1783
1784 #ifdef FAKE_INTERRUPT
1785 arm_fake_keyb_sig = 0;
1786 #endif /* FAKE_INTERRUPT */
1787
1788 c = global_key_map[c];
1789
1790 #ifndef CBREAK
1791 if (c == IntrC)
1792 return K_interrupt; /* don't flush */
1793 if (c == SuspC) {
1794 if (enable_stop && suspend_nn())
1795 goto redraw;
1796 goto next_key;
1797 }
1798 #endif /* CBREAK */
1799
1800 return (int) c;
1801
1802 intr:
1803
1804 #ifdef FAKE_INTERRUPT
1805 arm_fake_keyb_sig = 0;
1806 #endif /* FAKE_INTERRUPT */
1807
1808 rd_count = 0;
1809 return K_interrupt;
1810
1811 redraw:
1812
1813 #ifdef RESIZING
1814 s_resized = 0;
1815 #endif /* RESIZING */
1816
1817 s_redraw = 0;
1818 return GETC_COMMAND | K_REDRAW;
1819 }
1820
1821
1822 /*
1823 * read string with completion, pre-filling, and break on first char
1824 *
1825 * dflt is a string that will be use as default value if the
1826 * space bar is hit as the first character.
1827 *
1828 * prefill pre-fill the buffer with .... and print it
1829 *
1830 * break_chars return immediately if one of these characters
1831 * is entered as the first character.
1832 *
1833 * completion is a function that will fill the buffer with a value
1834 * see the group_completion and file_completion routines
1835 * for examples.
1836 */
1837
1838 char *
get_s(char * dflt,char * prefill,char * break_chars,fct_type completion)1839 get_s(char *dflt, char *prefill, char *break_chars, fct_type completion)
1840 {
1841 static key_type lbuf[GET_S_BUFFER];
1842 register char *cp;
1843 register int i, c, lastc;
1844 char *ret_val = (char *) lbuf;
1845 int comp_used, comp_len;
1846 int ostop, max, did_help;
1847 int hit_count;
1848
1849 switch (m_gets((char *) lbuf)) {
1850 case 0:
1851 break;
1852 case 1:
1853 return (char *) lbuf;
1854 case 2:
1855 return NULL;
1856 }
1857
1858 ostop = enable_stop;
1859 enable_stop = 0;
1860 do_macro_processing = 0;
1861 hit_count = 0;
1862
1863 max = Columns - prompt_length;
1864
1865 if (max >= FILENAME)
1866 max = FILENAME - 1;
1867
1868 i = comp_len = comp_used = did_help = 0;
1869
1870 if (prefill && prefill[0]) {
1871 while ((c = *prefill++)) {
1872 if (i == max)
1873 break;
1874
1875 tputc(c);
1876 lbuf[i] = c;
1877 i++;
1878 }
1879 fl;
1880 }
1881 if (dflt && *dflt == NUL)
1882 dflt = NULL;
1883
1884 if (break_chars && *break_chars == NUL)
1885 break_chars = NULL;
1886
1887 c = NUL;
1888 for (;;) {
1889 lastc = c;
1890 c = get_c();
1891 if (c & GETC_COMMAND)
1892 continue;
1893
1894 kill_prefill_hack:
1895
1896 hit_count++;
1897
1898 if (i == 0) {
1899 if (c == comp1_key && dflt) {
1900 while ((c = *dflt++) != NUL && i < max) {
1901 tputc(c);
1902 lbuf[i] = c;
1903 i++;
1904 }
1905 fl;
1906 dflt = NULL;
1907 continue;
1908 }
1909 if ((cp = break_chars)) { /* Stupid ^@$# GCC!!! */
1910 while (*cp)
1911 if (*cp++ == c) {
1912 lbuf[0] = c;
1913 lbuf[1] = NUL;
1914 goto out;
1915 }
1916 }
1917 }
1918 if (completion != NULL_FCT) {
1919 if (comp_used && c == erase_key) {
1920 if (comp_len) {
1921 i -= comp_len;
1922 while (--comp_len >= 0)
1923 tputc(BS);
1924 clrline();
1925 }
1926 if (!CALL(completion) (lbuf, -(i + 1)) && did_help)
1927 clrmsg(i);
1928 did_help = 0;
1929 comp_len = comp_used = 0;
1930 if (lastc == help_key)
1931 goto no_completion;
1932 continue;
1933 }
1934 if (c == comp1_key || c == comp2_key || c == help_key) {
1935 if (!comp_used || c == comp2_key ||
1936 (c == help_key && lastc != c)) {
1937 lbuf[i] = NUL;
1938 if ((comp_used = CALL(completion) (lbuf, i)) == 0) {
1939 ding();
1940 continue;
1941 }
1942 if (comp_used < 0) {
1943 comp_used = 0;
1944 goto no_completion;
1945 }
1946 comp_len = 0;
1947 }
1948 if (c == help_key) {
1949 if (CALL(completion) ((char *) NULL, 1)) {
1950 gotoxy(prompt_length + i, prompt_line);
1951 fl;
1952 did_help = 1;
1953 }
1954 continue;
1955 }
1956 if (comp_len) {
1957 i -= comp_len;
1958 while (--comp_len >= 0)
1959 tputc(BS);
1960 clrline();
1961 comp_len = 0;
1962 }
1963 switch (CALL(completion) ((char *) NULL, 0)) {
1964
1965 case 0: /* no possible completion */
1966 comp_used = 0;
1967 ding();
1968 continue;
1969
1970 case 2: /* whole new alternative */
1971 while (--i >= 0)
1972 tputc(BS);
1973 clrline();
1974
1975 /* FALLTHRU */
1976 case 1: /* completion */
1977 comp_len = i;
1978 while ((c = lbuf[i])) {
1979 if (i == max)
1980 break;
1981 tputc(c);
1982 i++;
1983 }
1984 fl;
1985 comp_len = i - comp_len;
1986 continue;
1987 }
1988 }
1989 if (comp_used) {
1990 if (!CALL(completion) (lbuf, -(i + 1)) && did_help)
1991 clrmsg(i);
1992 did_help = 0;
1993 comp_len = comp_used = 0;
1994 }
1995 }
1996 no_completion:
1997
1998 if (c == CR || c == NL) {
1999 lbuf[i] = NUL;
2000 break;
2001 }
2002 if (c == erase_key) {
2003 if (i <= 0)
2004 continue;
2005 i--;
2006 tputc(BS);
2007 tputc(' ');
2008 tputc(BS);
2009 fl;
2010 continue;
2011 }
2012 if (c == delword_key) {
2013 if (i <= 0)
2014 continue;
2015 lbuf[i - 1] = 'X';
2016 while (i > 0 && isalnum(lbuf[i - 1])) {
2017 tputc(BS);
2018 i--;
2019 }
2020 clrline();
2021 continue;
2022 }
2023 if (c == kill_key) {
2024 while (i > 0) {
2025 tputc(BS);
2026 i--;
2027 }
2028 clrline();
2029 if (hit_count == 1 && dflt) {
2030 c = comp1_key;
2031 goto kill_prefill_hack;
2032 }
2033 continue;
2034 }
2035 if (c == K_interrupt) {
2036 ret_val = NULL;
2037 break;
2038 }
2039 if (data_bits == 8) {
2040 if (!iso8859(c))
2041 continue;
2042 } else if (!isascii(c) || !isprint(c))
2043 continue;
2044
2045 if (i == max)
2046 continue;
2047
2048 if (i > 0 && lbuf[i - 1] == '/' && (c == '/' || c == '+')) {
2049 if (c != '/' || !guard_double_slash || (i > 1 && lbuf[i - 2] == '/')) {
2050 if (completion == file_completion) {
2051 while (i > 0) {
2052 tputc(BS);
2053 i--;
2054 }
2055 clrline();
2056 }
2057 }
2058 }
2059 tputc(c);
2060 fl;
2061
2062 lbuf[i] = c;
2063 i++;
2064 }
2065 out:
2066 enable_stop = ostop;
2067 do_macro_processing = 1;
2068 return ret_val;
2069 }
2070
2071 int list_offset = 0;
2072
2073 int
list_completion(char * str)2074 list_completion(char *str)
2075 {
2076 static int cols, line;
2077
2078 if (str == NULL) {
2079 cols = Columns;
2080 line = prompt_line + 1;
2081 if (line == Lines - 1)
2082 cols--;
2083
2084 gotoxy(0, line);
2085 clrpage();
2086 return 1;
2087 }
2088 str += list_offset;
2089
2090 for (;;) {
2091 cols -= strlen(str);
2092 if (cols >= 0) {
2093 tprintf("%s%s", str, cols > 0 ? " " : "");
2094 cols--;
2095 return 1;
2096 }
2097 if (line >= Lines - 1)
2098 return 0;
2099 line++;
2100 cols = Columns;
2101 gotoxy(0, line);
2102 if (line == Lines - 1)
2103 cols--;
2104 }
2105 }
2106
2107 int
yes(int must_answer)2108 yes(int must_answer)
2109 {
2110 int c, help = 1, in_macro = 0;
2111
2112 switch (m_yes()) {
2113 case 0:
2114 break;
2115 case 1:
2116 return 0;
2117 case 2:
2118 return 1;
2119 case 3:
2120 do_macro_processing = 0;
2121 in_macro++;
2122 break;
2123 }
2124 fl;
2125
2126 for (;;) {
2127 if (!is_raw) {
2128 nn_raw();
2129 c = get_c();
2130 unset_raw();
2131 } else
2132 c = get_c();
2133
2134 if (c == 'y' || c == 'Y') {
2135 c = 1;
2136 break;
2137 }
2138 if (must_answer == 0 && (c == SP || c == CR || c == NL)) {
2139 c = 1;
2140 break;
2141 }
2142 if (c == 'n' || c == 'N') {
2143 c = 0;
2144 break;
2145 }
2146 if (c == K_interrupt) {
2147 c = -1;
2148 break;
2149 }
2150 if (help) {
2151 tprintf(" y=YES n=NO");
2152 fl;
2153 prompt_length += 11;
2154 help = 0;
2155 }
2156 }
2157
2158 if (in_macro) {
2159 if (c < 0)
2160 m_break();
2161 do_macro_processing = 1;
2162 }
2163 return c;
2164 }
2165
2166 void
ding(void)2167 ding(void)
2168 {
2169 BATCH_CHECK_V;
2170
2171 putp(bell_str);
2172 fl;
2173 }
2174
2175
2176 void
display_file(char * name,int modes)2177 display_file(char *name, int modes)
2178 {
2179 FILE *f;
2180 register int c, stand_on;
2181 int linecnt, headln_cnt, hdline, no_conf;
2182 char headline[128];
2183
2184 headline[0] = 0;
2185 hdline = 0;
2186 no_conf = 0;
2187
2188 headln_cnt = -1;
2189
2190 if (modes & CLEAR_DISPLAY) {
2191 gotoxy(0, 0);
2192 clrdisp();
2193 }
2194 linecnt = Lines - 1;
2195
2196 chain:
2197
2198 if (*name != '/')
2199 name = relative(help_directory, name);
2200 f = open_file(name, OPEN_READ);
2201 if (f == NULL)
2202 tprintf("\r\n\nFile %s is not available\n\n", name);
2203 else {
2204 stand_on = 0;
2205
2206 while ((c = getc(f)) != EOF) {
2207
2208 #ifdef HAVE_JOBCONTROL
2209 if (s_redraw) {
2210 no_conf = 1;
2211 break;
2212 }
2213 #endif /* HAVE_JOBCONTROL */
2214
2215 no_conf = 0;
2216 if (c == '\1') {
2217 if (STANDOUT) {
2218 putp(stand_on ? exit_standout_mode : enter_standout_mode);
2219 curxy_c += cookie_size;
2220 stand_on = !stand_on;
2221 }
2222 continue;
2223 }
2224 if (c == '\2') {
2225 headln_cnt = 0;
2226 continue;
2227 }
2228 if (c == '\3') {
2229 headln_cnt = 0;
2230 while ((c = getc(f)) != EOF && c != NL)
2231 headline[headln_cnt++] = c;
2232 headline[headln_cnt++] = NUL;
2233 name = headline;
2234 fclose(f);
2235 goto chain;
2236 }
2237 if (c == '\4') {
2238 tprintf("%s", version_id);
2239 continue;
2240 }
2241 if (headln_cnt >= 0)
2242 headline[headln_cnt++] = c;
2243
2244 if (hdline) {
2245 tprintf("%s\r", headline);
2246 hdline = 0;
2247 linecnt--;
2248 }
2249 tputc(c);
2250 if (c == NL) {
2251 tputc(CR);
2252 if (headln_cnt >= 0) {
2253 headline[--headln_cnt] = 0;
2254 headln_cnt = -1;
2255 }
2256 if (--linecnt == 0) {
2257 no_conf = 1;
2258 if (any_key(0) == K_interrupt)
2259 break;
2260 linecnt = Lines - 1;
2261 if (modes & CLEAR_DISPLAY) {
2262 gotoxy(0, 0);
2263 clrdisp();
2264 }
2265 hdline = headline[0];
2266 }
2267 }
2268 }
2269
2270 if (stand_on) {
2271 putp(exit_standout_mode);
2272 curxy_c += cookie_size;
2273 }
2274 fclose(f);
2275 }
2276
2277 prompt_line = Lines - 1; /* move prompt to last line */
2278
2279 if (!no_conf && (modes & CONFIRMATION))
2280 any_key(prompt_line);
2281 }
2282
2283
2284 void
nn_exitmsg(int n,char * fmt,...)2285 nn_exitmsg(int n, char *fmt,...)
2286 {
2287 va_list ap;
2288
2289 if (terminal_speed != 0) {
2290 clrdisp();
2291 visual_off();
2292 }
2293 va_start(ap, fmt);
2294 vprintf(fmt, ap);
2295 putchar(NL);
2296 va_end(ap);
2297
2298 nn_exit(n);
2299 /* NOTREACHED */
2300 }
2301
2302 static void
push_msg(char * str)2303 push_msg(char *str)
2304 {
2305 register struct msg_list *mp, *newmsg;
2306 static int slots = 0;
2307
2308 if (str != NULL) {
2309 if (slots > message_history) {
2310 for (mp = newmsg = msg_stack; mp->prev != NULL; mp = mp->prev)
2311 newmsg = mp;
2312 if (newmsg == mp)
2313 msg_stack = NULL;
2314 else {
2315 newmsg->prev = NULL;
2316 newmsg = mp;
2317 }
2318 freeobj(newmsg->buf);
2319 } else {
2320 slots++;
2321 newmsg = newobj(struct msg_list, 1);
2322 }
2323 newmsg->buf = copy_str(str);
2324 newmsg->prev = msg_stack;
2325 msg_stack = newmsg;
2326 }
2327 msg_ptr = msg_stack;
2328 }
2329
2330 void
vmsg(char * fmt,va_list ap)2331 vmsg(char *fmt, va_list ap)
2332 {
2333 char *errmsg;
2334
2335 if (fmt) {
2336 char lbuf[512];
2337
2338 vsprintf(lbuf, fmt, ap);
2339 push_msg(lbuf);
2340 }
2341 if (msg_ptr) {
2342 errmsg = msg_ptr->buf;
2343 msg_ptr = msg_ptr->prev;
2344 } else {
2345 errmsg = "(no more messages)";
2346 msg_ptr = msg_stack;
2347 }
2348
2349 if (terminal_speed == 0) {
2350 tprintf("%s\n", errmsg);
2351 fl;
2352 return;
2353 }
2354 gotoxy(0, Lines - 1);
2355 tprintf("%s", errmsg);
2356 clrline();
2357 any_message = 1;
2358
2359 if (prompt_line != Lines - 1)
2360 gotoxy(prompt_length, prompt_line);
2361 fl;
2362 }
2363
2364 void
msg(char * fmt,...)2365 msg(char *fmt,...)
2366 {
2367 va_list ap;
2368
2369 va_start(ap, fmt);
2370 vmsg(fmt, ap);
2371 va_end(ap);
2372 }
2373
2374 void
clrmsg(int col)2375 clrmsg(int col)
2376 {
2377 BATCH_CHECK_V;
2378
2379 gotoxy(0, prompt_line + 1);
2380 clrpage();
2381 if (col >= 0)
2382 gotoxy(prompt_length + col, prompt_line);
2383 fl;
2384 any_message = 0;
2385 }
2386
2387
2388 void
prompt(char * fmt,...)2389 prompt(char *fmt,...)
2390 {
2391 va_list ap;
2392 register char *cp;
2393 int stand_on;
2394 static char cur_p[FILENAME];
2395 static char saved_p[FILENAME];
2396
2397 BATCH_CHECK_V;
2398
2399 va_start(ap, fmt);
2400
2401 if (fmt == P_VERSION) {
2402 gotoxy(0, prompt_line + 1);
2403 tprintf("Release %s ", version_id);
2404 clrline();
2405 any_message++;
2406
2407 if (prompt_line >= 0)
2408 gotoxy(prompt_length, prompt_line);
2409 goto out;
2410 }
2411 if (fmt == P_SAVE) {
2412 strcpy(saved_p, cur_p);
2413 goto out;
2414 }
2415 if (fmt == P_RESTORE)
2416 strcpy(cur_p, saved_p);
2417
2418 if (prompt_line >= 0)
2419 gotoxy(0, prompt_line);
2420
2421 if (fmt == P_MOVE) {
2422 clrline();
2423 goto out;
2424 }
2425 if (fmt != P_REDRAW && fmt != P_RESTORE)
2426 vsprintf(cur_p, fmt, ap);
2427
2428 tputc(CR);
2429
2430 for (cp = cur_p, stand_on = 0, prompt_length = 0; *cp; cp++) {
2431 if (*cp == '\1') {
2432 if (cp[1] != '\1') {
2433 if (STANDOUT) {
2434 stand_on = !stand_on;
2435 nnstandout(stand_on);
2436 prompt_length += cookie_size;
2437 }
2438 continue;
2439 }
2440 cp++;
2441 } else if (*cp == '\2') {
2442 time_t t;
2443 char *timestr;
2444
2445 #ifdef STATISTICS
2446 t = tick_usage();
2447 #else
2448 t = cur_time();
2449 #endif
2450
2451 if (show_current_time) {
2452 timestr = ctime(&t) + 11;
2453 timestr[5] = NUL;
2454
2455 tprintf("-- %s ", timestr);
2456 prompt_length += 9;
2457 }
2458 if (unread_mail(t)) {
2459 tprintf("Mail ");
2460 prompt_length += 5;
2461 }
2462 continue;
2463 }
2464 tputc(*cp);
2465 prompt_length++;
2466 }
2467 if (stand_on) {
2468 nnstandout(0);
2469 prompt_length += cookie_size;
2470 }
2471 clrline();
2472
2473 if (fmt == P_RESTORE)
2474 restore_xy();
2475
2476 #if notdef
2477 else
2478 curxy_c = -1;
2479 #endif
2480
2481 out:
2482 va_end(ap);
2483 }
2484
2485
2486 int
any_key(int line)2487 any_key(int line)
2488 {
2489 int was_raw, c, dmp;
2490
2491 BATCH_CHECK;
2492
2493 was_raw = is_raw;
2494 if (!is_raw)
2495 nn_raw();
2496 if (line == 0)
2497 line = -1;
2498 else if (line < 0)
2499 line = Lines + line;
2500
2501 if (line != 10000)
2502 so_printxy(0, line, "Hit any key to continue");
2503
2504 clrline();
2505
2506 dmp = do_macro_processing;
2507 do_macro_processing = 0;
2508 c = get_c();
2509 if (c == 'q' || c == 'Q')
2510 c = K_interrupt;
2511 do_macro_processing = dmp;
2512
2513 if (!was_raw)
2514 unset_raw();
2515
2516 return c;
2517 }
2518
2519
2520 static int pg_fline, pg_width, pg_maxw, pg_line, pg_col, pg_quit;
2521 regexp *pg_regexp = NULL;
2522 int pg_new_regexp = 0;
2523
2524 void
pg_init(int first_line,int cols)2525 pg_init(int first_line, int cols)
2526 {
2527 if (pg_regexp) {
2528 freeobj(pg_regexp);
2529 pg_regexp = NULL;
2530 }
2531 pg_new_regexp = 0;
2532
2533 pg_fline = first_line;
2534 pg_line = pg_fline - 1;
2535 pg_quit = pg_col = 0;
2536 pg_width = Columns / cols;
2537 pg_maxw = pg_width * (cols - 1);
2538 }
2539
2540 int
pg_scroll(int n)2541 pg_scroll(int n)
2542 {
2543 pg_line += n;
2544 if (pg_line >= (Lines - 1)) {
2545 pg_line = 0;
2546 if (any_key(0) == K_interrupt)
2547 return 1;
2548 tputc(CR);
2549 clrline();
2550 }
2551 return 0;
2552 }
2553
2554 int
pg_next(void)2555 pg_next(void)
2556 {
2557 int c;
2558
2559 if (batch_mode) {
2560 putchar(NL);
2561 return 0;
2562 }
2563 pg_line++;
2564 if (pg_line < Lines) {
2565 gotoxy(pg_col, pg_line);
2566 if (pg_line == Lines - 1 && pg_col == pg_maxw) {
2567 c = any_key(0);
2568 if (c == '/') {
2569 char *expr;
2570 tputc(CR);
2571 tputc('/');
2572 clrline();
2573 expr = get_s((char *) NULL, (char *) NULL, (char *) NULL, NULL_FCT);
2574 if (expr != NULL && *expr != NUL) {
2575 freeobj(pg_regexp);
2576 pg_regexp = regcomp(expr);
2577 pg_new_regexp = 1;
2578 }
2579 }
2580 gotoxy(0, pg_fline);
2581 clrpage();
2582 pg_col = 0;
2583 pg_line = pg_fline;
2584 if (c == K_interrupt) {
2585 pg_quit = 1;
2586 return -1;
2587 }
2588 return 1;
2589 }
2590 } else {
2591 pg_line = pg_fline;
2592 pg_col += pg_width;
2593 gotoxy(pg_col, pg_line);
2594 }
2595 return 0;
2596 }
2597
2598 void
pg_indent(int pos)2599 pg_indent(int pos)
2600 {
2601 BATCH_CHECK_V;
2602
2603 gotoxy(pg_col + pos, pg_line);
2604 }
2605
2606 int
pg_end(void)2607 pg_end(void)
2608 {
2609 int c;
2610
2611 if (pg_quit == 0 && pg_next() == 0)
2612 c = any_key(0);
2613 else
2614 c = K_interrupt;
2615
2616 if (pg_regexp) {
2617 freeobj(pg_regexp);
2618 pg_regexp = NULL;
2619 }
2620 return c == K_interrupt ? -1 : 0;
2621 }
2622
2623 void
user_delay(int ticks)2624 user_delay(int ticks)
2625 {
2626 BATCH_CHECK_V;
2627
2628 if (ticks <= 0 || conf_dont_sleep) {
2629 tprintf(" <>");
2630 any_key(10000);
2631 } else {
2632 fl;
2633 sleep((unsigned) ticks);
2634 }
2635 }
2636