tin  2.6.1
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.6.1.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

curses.c
Go to the documentation of this file.
1/*
2 * Project : tin - a Usenet reader
3 * Module : curses.c
4 * Author : D. Taylor & I. Lea
5 * Created : 1986-01-01
6 * Updated : 2021-09-20
7 * Notes : This is a screen management library borrowed with permission
8 * from the Elm mail system. This library was hacked to provide
9 * what tin needs.
10 * Copyright : Copyright (c) 1986-99 Dave Taylor & Iain Lea
11 * The Elm Mail System - @Revision: 2.1 $ $State: Exp @
12 */
13
14#ifndef TIN_H
15# include "tin.h"
16#endif /* !TIN_H */
17#ifndef TCURSES_H
18# include "tcurses.h"
19#endif /* !TCURSES_H */
20#ifndef TNNTP_H
21# include "tnntp.h"
22#endif /* !TNNTP_H */
23#ifndef TIN_MISSING_FD_H
24# include <missing_fd.h>
25#endif /* TIN_MISSING_FD_H */
26
27/* local prototype */
28#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
29 static wint_t convert_c2wc (const char *input);
30#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
31
32#ifdef USE_CURSES
33
34# define ReadCh cmdReadCh
35# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
36# define ReadWch cmdReadWch
37# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
38# define get_arrow_key cmd_get_arrow_key
39
40void my_dummy(void) { } /* ANSI C requires non-empty file */
41t_bool have_linescroll = TRUE; /* USE_CURSES always allows line scrolling */
42
43#else /* !USE_CURSES */
44
45# ifndef ns32000
46# undef sinix
47# endif /* !ns32000 */
48
49# define DEFAULT_LINES_ON_TERMINAL 24
50# define DEFAULT_COLUMNS_ON_TERMINAL 80
51
54int _hp_glitch = FALSE; /* stdout not erased by overwriting on HP terms */
55static int _inraw = FALSE; /* are we IN rawmode? */
56static int xclicks = FALSE; /* do we have an xterm? */
58
59# define TTYIN 0
60
61# if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR) && defined(HAVE_TCSETATTR)
62# ifdef HAVE_IOCTL_H
63# include <ioctl.h>
64# else
65# ifdef HAVE_SYS_IOCTL_H
66# include <sys/ioctl.h>
67# endif /* HAVE_SYS_IOCTL_H */
68# endif /* HAVE_IOCTL_H */
69# if !defined(sun) || !defined(NL0)
70# include <termios.h>
71# endif /* !sun || !NL0 */
72# define USE_POSIX_TERMIOS 1
73# define TTY struct termios
74# else
75# ifdef HAVE_TERMIO_H
76# include <termio.h>
77# define USE_TERMIO 1
78# define TTY struct termio
79# else
80# ifdef HAVE_SGTTY_H
81# include <sgtty.h>
82# define USE_SGTTY 1
83# define TTY struct sgttyb
84/*
85 # else
86 # error "No termios.h, termio.h or sgtty.h found"
87*/
88# endif /* HAVE_SGTTY_H */
89# endif /* HAVE_TERMIO_H */
90# endif /* HAVE_TERMIOS_H && HAVE_TCGETATTR && HAVE_TCSETATTR */
91
93
94
95# ifndef USE_SGTTY
96# define USE_SGTTY 0
97# endif /* !USE_SGTTY */
98
99# ifndef USE_POSIX_TERMIOS
100# define USE_POSIX_TERMIOS 0
101# ifndef USE_TERMIO
102# define USE_TERMIO 0
103# endif /* !USE_TERMIO */
104# endif /* !USE_POSIX_TERMIOS */
105
112
114
115# undef SET_TTY
116# undef GET_TTY
117# if USE_POSIX_TERMIOS
118# define SET_TTY(arg) tcsetattr(TTYIN, TCSANOW, arg)
119# define GET_TTY(arg) tcgetattr(TTYIN, arg)
120# else
121# if USE_TERMIO
122# define SET_TTY(arg) ioctl(TTYIN, TCSETAW, arg)
123# define GET_TTY(arg) ioctl(TTYIN, TCGETA, arg)
124# else
125# if USE_SGTTY
126# define SET_TTY(arg) stty(TTYIN, arg)
127# define GET_TTY(arg) gtty(TTYIN, arg)
128/*
129 # else
130 # error "No termios.h, termio.h or sgtty.h found"
131*/
132# endif /* USE_SGTTY */
133# endif /* USE_TERMIO */
134# endif /* USE_POSIX_TERMIOS */
135
136# if 0
137 static int in_inverse; /* 1 when in inverse, 0 otherwise */
138# endif /* 0 */
139
140/*
141 * Local prototypes
142 */
143static int input_pending(int delay);
144static void ScreenSize(int *num_lines, int *num_columns);
145static void xclick(int state);
146
147
148/*
149 * returns the number of lines and columns on the display.
150 */
151static void
153 int *num_lines,
154 int *num_columns)
155{
156 if (!_lines)
158 if (!_columns)
160
161 *num_lines = _lines - 1; /* assume index from zero */
162 *num_columns = _columns; /* assume index from one */
163}
164
165
166/*
167 * get screen size from termcap entry & setup sizes
168 */
169void
171 void)
172{
173 _line = 1;
175 cmd_line = FALSE;
176 Raw(TRUE);
177# ifdef HAVE_COLOR
178 bcol(tinrc.col_back);
179# endif /* HAVE_COLOR */
181}
182
183
184# ifdef USE_TERMINFO
185# define CAPNAME(a,b) b
186# define dCAPNAME(a,b) strcpy(_terminal, b)
187# define TGETSTR(b,bufp) tigetstr(b)
188# define TGETNUM(b) tigetnum(b) /* may be tigetint() */
189# define TGETFLAG(b) tigetflag(b)
190# define NO_CAP(s) (s == 0 || s == (char *) -1)
191# if !defined(HAVE_TIGETNUM) && defined(HAVE_TIGETINT)
192# define tigetnum tigetint
193# endif /* !HAVE_TIGETNUM && HAVE_TIGETINT */
194# else /* USE_TERMCAP */
195# undef USE_TERMCAP
196# define USE_TERMCAP 1
197# define CAPNAME(a,b) a
198# define dCAPNAME(a,b) a
199# define TGETSTR(a, bufp) tgetstr(a, bufp)
200# define TGETNUM(a) tgetnum(a)
201# define TGETFLAG(a) tgetflag(a)
202# define NO_CAP(s) (s == 0)
203# endif /* USE_TERMINFO */
204
205# ifdef HAVE_TPARM
206# define TFORMAT(fmt, a, b) tparm(fmt, b, a)
207# else
208# define TFORMAT(fmt, a, b) tgoto(fmt, b, a)
209# endif /* HAVE_TPARM */
210
211# ifdef HAVE_EXTERN_TCAP_PC
212 extern char PC; /* used in 'tputs()' */
213# endif /* HAVE_EXTERN_TCAP_PC */
214
215int
217 void)
218{
219 static struct {
220 char **value;
221 char capname[6];
222 } table[] = {
223 { &_clearinverse, CAPNAME("se", "rmso") },
224 { &_clearscreen, CAPNAME("cl", "clear") },
225 { &_cleartoeoln, CAPNAME("ce", "el") },
226 { &_cleartoeos, CAPNAME("cd", "ed") },
227 { &_clearunderline, CAPNAME("ue", "rmul") },
228 { &_cursoroff, CAPNAME("vi", "civis") },
229 { &_cursoron, CAPNAME("ve", "cnorm") },
230 { &_keypadlocal, CAPNAME("ke", "rmkx") },
231 { &_keypadxmit, CAPNAME("ks", "smkx") },
232 { &_moveto, CAPNAME("cm", "cup") },
233 { &_scrollback, CAPNAME("sr", "ri") },
234 { &_scrollfwd, CAPNAME("sf", "ind") },
235 { &_scrollregion, CAPNAME("cs", "csr") },
236 { &_setinverse, CAPNAME("so", "smso") },
237 { &_setunderline, CAPNAME("us", "smul") },
238 { &_terminalend, CAPNAME("te", "rmcup") },
239 { &_terminalinit, CAPNAME("ti", "smcup") },
240 /* extra caps needed for word highlighting */
241 { &_reset, CAPNAME("me", "sgr0") },
242 { &_reversevideo, CAPNAME("mr", "rev") },
243 { &_blink, CAPNAME("mb", "blink") },
244 { &_dim, CAPNAME("mh", "dim") },
245 { &_bold, CAPNAME("mb", "bold") },
246 };
247
248 static char _terminal[1024]; /* Storage for terminal entry */
249
250# if defined(USE_TERMCAP)
251 static char _capabilities[1024]; /* String for cursor motion */
252 static char *ptr = _capabilities; /* for buffering */
253# if defined(HAVE_EXTERN_TCAP_PC)
254 char *t;
255# endif /* HAVE_EXTERN_TCAP_PC */
256# endif /* USE_TERMCAP */
257
258 char the_termname[40], *p;
259 unsigned n;
260
261 if ((p = getenv("TERM")) == NULL) {
263 return FALSE;
264 }
265
266 my_strncpy(the_termname, p, sizeof(the_termname) - 1);
267
268# ifdef USE_TERMINFO
269 setupterm(the_termname, fileno(stdout), (int *) 0);
270# else
271 if (tgetent(_terminal, the_termname) != 1) {
273 return FALSE;
274 }
275# endif /* USE_TERMINFO */
276
277 /* load in all those pesky values */
278 for (n = 0; n < ARRAY_SIZE(table); n++) {
279 *(table[n].value) = TGETSTR(table[n].capname, &ptr);
280 }
281 _lines = TGETNUM(dCAPNAME("li", "lines"));
282 _colors = TGETNUM(dCAPNAME("Co", "colors"));
283 _columns = TGETNUM(dCAPNAME("co", "cols"));
284 _hp_glitch = TGETFLAG(dCAPNAME("xs", "xhp"));
285
286# if defined(USE_TERMCAP) && defined(HAVE_EXTERN_TCAP_PC)
287 t = TGETSTR(CAPNAME("pc", "pad"), &p);
288 if (t != 0)
289 PC = *t;
290# endif /* USE_TERMCAP && HAVE_EXTERN_TCAP_PC */
291
292 if (STRCMPEQ(the_termname, "xterm")) {
293 static char x_init[] = "\033[?9h";
294 static char x_end[] = "\033[?9l";
295 xclicks = TRUE;
296 _xclickinit = x_init;
297 _xclickend = x_end;
298 }
299
300 if (NO_CAP(_clearscreen)) {
302 return FALSE;
303 }
304 if (NO_CAP(_moveto)) {
306 return FALSE;
307 }
308 if (NO_CAP(_cleartoeoln)) {
310 return FALSE;
311 }
312 if (NO_CAP(_cleartoeos)) {
314 return FALSE;
315 }
316 if (_lines == -1)
318 if (_columns == -1)
320
323 return FALSE;
324 }
325 /*
326 * kludge to workaround no inverse
327 */
328 if (NO_CAP(_setinverse)) {
331 if (NO_CAP(_setinverse))
332 tinrc.draw_arrow = 1;
333 }
336 else
338 return TRUE;
339}
340
341
342int
344 void)
345{
346 InitWin();
347# ifdef HAVE_COLOR
348 postinit_colors(MAX(_colors, MAX_COLOR + 1)); /* postinit_colors(_colors) would be correct */
349# endif /* HAVE_COLOR */
350 return TRUE;
351}
352
353
354void
356 void)
357{
358 if (_terminalinit) {
359 tputs(_terminalinit, 1, outchar);
360 my_flush();
361 }
364}
365
366
367void
369 void)
370{
371 if (_terminalend) {
372 tputs(_terminalend, 1, outchar);
373 my_flush();
374 }
377}
378
379
380void
382 void)
383{
384# ifdef HAVE_KEYPAD
385 if (tinrc.use_keypad && _keypadxmit) {
386 tputs(_keypadxmit, 1, outchar);
387 my_flush();
388 }
389# endif /* HAVE_KEYPAD */
390}
391
392
393void
395 void)
396{
397# ifdef HAVE_KEYPAD
398 if (tinrc.use_keypad && _keypadlocal) {
399 tputs(_keypadlocal, 1, outchar);
400 my_flush();
401 }
402# endif /* HAVE_KEYPAD */
403}
404
405
406/*
407 * clear the screen
408 */
409void
411 void)
412{
413# ifdef HAVE_COLOR
414 fcol(tinrc.col_normal);
415 bcol(tinrc.col_back);
416# endif /* HAVE_COLOR */
417 tputs(_clearscreen, 1, outchar);
418 my_flush(); /* clear the output buffer */
419 _line = 1;
420}
421
422
423# ifdef HAVE_COLOR
424void
425reset_screen_attr(
426 void)
427{
428 if (!NO_CAP(_reset)) {
429 tputs(_reset, 1, outchar);
430 my_flush();
431 }
432}
433# endif /* HAVE_COLOR */
434
435
436/*
437 * move cursor to the specified row column on the screen.
438 * 0,0 is the top left!
439 */
440void
442 int row,
443 int col)
444{
445 char *stuff;
446
447 stuff = tgoto(_moveto, col, row);
448 tputs(stuff, 1, outchar);
449 my_flush();
450 _line = row + 1;
451}
452
453
454/*
455 * clear to end of line
456 */
457void
459 void)
460{
461 tputs(_cleartoeoln, 1, outchar);
462 my_flush(); /* clear the output buffer */
463}
464
465
466/*
467 * clear to end of screen
468 */
469void
471 void)
472{
473 int i;
474
475 if (_cleartoeos) {
476 tputs(_cleartoeos, 1, outchar);
477 } else {
478 for (i = _line - 1; i < _lines; i++) {
479 MoveCursor(i, 0);
480 CleartoEOLN();
481 }
482 }
483 my_flush(); /* clear the output buffer */
484}
485
486
488
489void
491 int topline,
492 int bottomline)
493{
494 char *stuff;
495
496 if (!have_linescroll)
497 return;
498 if (_scrollregion) {
499 stuff = TFORMAT(_scrollregion, topline, bottomline);
500 tputs(stuff, 1, outchar);
501 _topscrregion = topline;
502 _bottomscrregion = bottomline;
503 }
504 my_flush();
505}
506
507
508void
510 int lines_to_scroll)
511{
512 int i;
513
514 if (!have_linescroll || (lines_to_scroll == 0))
515 return;
516 if (lines_to_scroll < 0) {
517 if (_scrollback) {
518 i = lines_to_scroll;
519 while (i++) {
521 tputs(_scrollback, 1, outchar);
522 }
523 }
524 } else
525 if (_scrollfwd) {
526 i = lines_to_scroll;
527 while (i--) {
529 tputs(_scrollfwd, 1, outchar);
530 }
531 }
532 my_flush();
533}
534
535
536/*
537 * set inverse video mode
538 */
539void
541 void)
542{
543/* in_inverse = 1; */
545# ifdef HAVE_COLOR
546 if (use_color) {
547 bcol(tinrc.col_invers_bg);
548 fcol(tinrc.col_invers_fg);
549 } else {
550 tputs(_setinverse, 1, outchar);
551 }
552# else
553 tputs(_setinverse, 1, outchar);
554# endif /* HAVE_COLOR */
555 }
556 my_flush();
557}
558
559
560/*
561 * compliment of startinverse
562 */
563void
565 void)
566{
567/* in_inverse = 0; */
569# ifdef HAVE_COLOR
570 if (use_color) {
571 fcol(tinrc.col_normal);
572 bcol(tinrc.col_back);
573 } else {
574 tputs(_clearinverse, 1, outchar);
575 }
576# else
577 tputs(_clearinverse, 1, outchar);
578# endif /* HAVE_COLOR */
579 }
580 my_flush();
581}
582
583
584# if 0 /* doesn't work correct with ncurses4.x */
585/*
586 * toggle inverse video mode
587 */
588void
589ToggleInverse(
590 void)
591{
592 if (!in_inverse)
593 StartInverse();
594 else
595 EndInverse();
596}
597# endif /* 0 */
598
599
600/*
601 * returns either 1 or 0, for ON or OFF
602 */
603int
605 void)
606{
607 return _inraw;
608}
609
610
611/* SunOS-3.5 - FIXME! */
612#if defined(sun) || defined(__sun) && (!defined(__SVR4) || !defined(__svr4__)) && defined(BSD) && BSD < 199306
613# ifndef ECHO
614# define ECHO 0x00000008 /* echo input */
615# endif /* !ECHO */
616# ifndef CBREAK
617# define CBREAK 0x00000002 /* half-cooked mode */
618# endif /* !CBREAK */
619#endif /* sun || __sun && (!__SVR4 || !__svr4__) && BSD && BSD < 199306 */
620/*
621 * state is either TRUE or FALSE, as indicated by call
622 */
623void
625 int state)
626{
627 if (!state && _inraw) {
628 SET_TTY(&_original_tty);
629 _inraw = 0;
630 } else if (state && !_inraw) {
631 GET_TTY(&_original_tty);
632 GET_TTY(&_raw_tty);
633# if USE_SGTTY
634 _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* echo off */
635 _raw_tty.sg_flags |= CBREAK; /* raw on */
636# else
637# ifdef __FreeBSD__
638 cfmakeraw(&_raw_tty);
639 _raw_tty.c_lflag |= ISIG; /* for ^Z */
640# else
641 _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
642 _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */
643 _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
644# endif /* __FreeBSD__ */
645# endif /* USE_SGTTY */
646 SET_TTY(&_raw_tty);
647 _inraw = 1;
648 }
649}
650
651
652/*
653 * output a character. From tputs... (Note: this CANNOT be a macro!)
654 */
657{
658# ifdef OUTC_RETURN
659 return fputc(c, stdout);
660# else
661 (void) fputc(c, stdout);
662# endif /* OUTC_RETURN */
663}
664
665
666/*
667 * setup to monitor mouse buttons if running in a xterm
668 */
669static void
671 int state)
672{
673 static int prev_state = 999;
674
675 if (xclicks && prev_state != state) {
676 if (state) {
677 tputs(_xclickinit, 1, outchar);
678 } else {
679 tputs(_xclickend, 1, outchar);
680 }
681 my_flush();
682 prev_state = state;
683 }
684}
685
686
687/*
688 * switch on monitoring of mouse buttons
689 */
690void
692 void)
693{
694 if (tinrc.use_mouse)
695 xclick(TRUE);
696}
697
698
699/*
700 * switch off monitoring of mouse buttons
701 */
702void
704 void)
705{
706 if (tinrc.use_mouse)
707 xclick(FALSE);
708}
709
710
711void
713 void)
714{
715 if (_cursoron)
716 tputs(_cursoron, 1, outchar);
717}
718
719
720void
722 void)
723{
724 if (_cursoroff)
725 tputs(_cursoroff, 1, outchar);
726}
727
728
729/*
730 * Inverse 'size' chars at (row,col)
731 */
732void
734 int row,
735 int col,
736 int size)
737{
738 char output[LEN];
739
740 my_strncpy(output, &(screen[row].col[col]), (size_t) size);
741
742# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
743 /*
744 * In a multibyte locale we get byte offsets instead of character
745 * offsets; calculate now the correct starting column
746 */
747 if (col > 0 && col < LEN) {
748 char tmp[LEN];
749 wchar_t *wtmp;
750
751 my_strncpy(tmp, &(screen[row].col[0]), sizeof(tmp) - 1);
752 tmp[col] = '\0';
753 if ((wtmp = char2wchar_t(tmp)) != NULL) {
754 col = wcswidth(wtmp, wcslen(wtmp) + 1);
755 free(wtmp);
756 }
757 }
758# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
759
760 MoveCursor(row, col);
761 StartInverse();
762 my_fputs(output, stdout);
763 EndInverse();
764 my_flush();
765
766 stow_cursor();
767}
768
769
770/*
771 * Color 'size' chars at (row,col) with 'color' and handle marks
772 */
773void
775 int row,
776 int col,
777 int size,
778 int color)
779{
780 /*
781 * Mapping of the tinrc.mono_mark* values to the corresponding escape sequences
782 */
783 char *attributes[MAX_ATTR + 1];
784 char *dest, *src;
785 char output[LEN];
786 int byte_offset = col;
787 int wsize = size;
788# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
789 wchar_t *wtmp;
790# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
791
792 attributes[0] = _reset; /* Normal */
793 attributes[1] = _setinverse; /* Best highlighting */
794 attributes[2] = _setunderline; /* Underline */
795 attributes[3] = _reversevideo; /* Reverse video */
796 attributes[4] = _blink; /* Blink */
797 attributes[5] = _dim; /* Dim */
798 attributes[6] = _bold; /* Bold */
799
800 my_strncpy(output, &(screen[row].col[byte_offset]), (size_t) size);
801
802# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
803 /*
804 * In a multibyte locale we get byte offsets instead of character
805 * offsets; calculate now the correct starting column and
806 * width
807 */
808 if (byte_offset > 0) {
809 char tmp[LEN];
810
811 my_strncpy(tmp, &(screen[row].col[0]), sizeof(tmp) - 1);
812 tmp[byte_offset] = '\0';
813 if ((wtmp = char2wchar_t(tmp)) != NULL) {
814 col = wcswidth(wtmp, wcslen(wtmp) + 1);
815 free(wtmp);
816 }
817 }
818 if ((wtmp = char2wchar_t(output)) != NULL) {
819 wsize = wcswidth(wtmp, wcslen(wtmp) + 1);
820 free(wtmp);
821 }
822# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
823
824 MoveCursor(row, col);
825
826 /* safeguard against bogus regexps */
827 if ((output[0] == '*' && output[size - 1] == '*') ||
828 (output[0] == '/' && output[size - 1] == '/') ||
829 (output[0] == '_' && output[size - 1] == '_') ||
830 (output[0] == '-' && output[size - 1] == '-')) {
831
832 switch (tinrc.word_h_display_marks) {
833 case 0: /* remove marks */
834 MoveCursor(row, col + wsize - 2);
835 CleartoEOLN();
836 my_fputs(&(screen[row].col[byte_offset + size]), stdout);
837 output[0] = output[size - 1] = ' ';
839 strncpy(&(screen[row].col[byte_offset]), output, (size_t) (size - 2));
840 src = &(screen[row].col[byte_offset + size]);
841 dest = &(screen[row].col[byte_offset + size - 2]);
842 while (*src)
843 *dest++ = *src++;
844 *dest++ = '\0';
845 MoveCursor(row, col);
846 break;
847
848 case 2: /* print space */
849 MoveCursor(row, col + wsize - 1);
850 my_fputs(" ", stdout);
851 MoveCursor(row, col);
852 my_fputs(" ", stdout);
853 output[0] = output[size - 1] = ' ';
855 screen[row].col[byte_offset] = ' ';
856 screen[row].col[byte_offset + size - 1] = ' ';
857 break;
858
859 default: /* print mark (case 1) */
860 break;
861 }
862 }
863# ifdef HAVE_COLOR
864 if (use_color)
865 fcol(color);
866 else
867# endif /* HAVE_COLOR */
868 if (color > 0 && color <= MAX_ATTR && !NO_CAP(attributes[color]))
869 tputs(attributes[color], 1, outchar);
870 my_fputs(output, stdout);
871 my_flush();
872# ifdef HAVE_COLOR
873 if (use_color)
874 fcol(tinrc.col_text);
875 else
876# endif /* HAVE_COLOR */
877 if (!NO_CAP(_reset))
878 tputs(_reset, 1, outchar);
879 stow_cursor();
880}
881#endif /* USE_CURSES */
882
883
884/*
885 * input_pending() waits for input during time given
886 * by delay in msec. The original behavior of input_pending()
887 * (in art.c's threading code) is delay=0
888 */
889static int
891 int delay)
892{
893#if 0
894 int ch;
895
896 nodelay(stdscr, TRUE);
897 if ((ch = getch()) != ERR)
898 ungetch(ch);
899 nodelay(stdscr, FALSE);
900 return (ch != ERR);
901
902#else
903
904# ifdef HAVE_SELECT
905 int fd = STDIN_FILENO;
906 fd_set fdread;
907 struct timeval tvptr;
908
909 FD_ZERO(&fdread);
910
911 tvptr.tv_sec = 0;
912 tvptr.tv_usec = delay * 100;
913
914 FD_SET(fd, &fdread);
915
916# ifdef HAVE_SELECT_INTP
917 if (select(1, (int *) &fdread, NULL, NULL, &tvptr))
918# else
919 if (select(1, &fdread, NULL, NULL, &tvptr))
920# endif /* HAVE_SELECT_INTP */
921 {
922 if (FD_ISSET(fd, &fdread))
923 return TRUE;
924 }
925# endif /* HAVE_SELECT */
926
927# if defined(HAVE_POLL) && !defined(HAVE_SELECT)
928 static int Timeout;
929 static long nfds = 1;
930 static struct pollfd fds[] = {{ STDIN_FILENO, POLLIN, 0 }};
931
932 Timeout = delay;
933 if (poll(fds, nfds, Timeout) < 0) /* Error on poll */
934 return FALSE;
935
936 switch (fds[0].revents) {
937 case POLLIN:
938 return TRUE;
939 /*
940 * Other conditions on the stream
941 */
942 case POLLHUP:
943 case POLLERR:
944 default:
945 return FALSE;
946 }
947# endif /* HAVE_POLL && !HAVE_SELECT */
948
949#endif /* 0 */
950
951 return FALSE;
952}
953
954
955#if defined(HAVE_USLEEP) || defined(HAVE_SELECT) || defined(HAVE_POLL)
956# define wait_a_while(i) \
957 while (!input_pending(0) \
958 && i < ((VT_ESCAPE_TIMEOUT * 1000) / SECOND_CHARACTER_DELAY))
959#endif /* HAVE_USLEEP || HAVE_SELECT || HAVE_POLL */
960int
962 int prech)
963{
964 int ch;
965 int ch1;
966#if defined(HAVE_USLEEP) || defined(HAVE_SELECT) || defined(HAVE_POLL)
967 int i = 0;
968#endif /* HAVE_USLEEP || HAVE_SELECT || HAVE_POLL */
969
970 if (!input_pending(0)) {
971#ifdef HAVE_USLEEP
972 wait_a_while(i) {
973 usleep((unsigned long) (SECOND_CHARACTER_DELAY * 1000));
974 i++;
975 }
976#else /* !HAVE_USLEEP */
977# ifdef HAVE_SELECT
978 struct timeval tvptr;
979
980 wait_a_while(i) {
981 tvptr.tv_sec = 0;
982 tvptr.tv_usec = SECOND_CHARACTER_DELAY * 1000;
983 select(0, NULL, NULL, NULL, &tvptr);
984 i++;
985 }
986# else /* !HAVE_SELECT */
987# ifdef HAVE_POLL
988 struct pollfd fds[1];
989
990 wait_a_while(i) {
991 poll(fds, 0, SECOND_CHARACTER_DELAY);
992 i++;
993 }
994# else /* !HAVE_POLL */
995 (void) sleep(1);
996# endif /* HAVE_POLL */
997# endif /* HAVE_SELECT */
998#endif /* HAVE_USLEEP */
999 if (!input_pending(0))
1000 return prech;
1001 }
1002 ch = ReadCh();
1003 if (ch == '[' || ch == 'O')
1004 ch = ReadCh();
1005
1006 switch (ch) {
1007 case 'A':
1008 case 'i':
1009#ifdef QNX42
1010 case 0xA1:
1011#endif /* QNX42 */
1012 return KEYMAP_UP;
1013
1014 case 'B':
1015#ifdef QNX42
1016 case 0xA9:
1017#endif /* QNX42 */
1018 return KEYMAP_DOWN;
1019
1020 case 'D':
1021#ifdef QNX42
1022 case 0xA4:
1023#endif /* QNX42 */
1024 return KEYMAP_LEFT;
1025
1026 case 'C':
1027#ifdef QNX42
1028 case 0xA6:
1029#endif /* QNX42 */
1030 return KEYMAP_RIGHT;
1031
1032 case 'I': /* ansi PgUp */
1033 case 'V': /* at386 PgUp */
1034 case 'S': /* 97801 PgUp */
1035 case 'v': /* emacs style */
1036#ifdef QNX42
1037 case 0xA2:
1038#endif /* QNX42 */
1039 return KEYMAP_PAGE_UP;
1040
1041 case 'G': /* ansi PgDn */
1042 case 'U': /* at386 PgDn */
1043 case 'T': /* 97801 PgDn */
1044#ifdef QNX42
1045 case 0xAA:
1046#endif /* QNX42 */
1047 return KEYMAP_PAGE_DOWN;
1048
1049 case 'H': /* at386 Home */
1050#ifdef QNX42
1051 case 0xA0:
1052#endif /* QNX42 */
1053 return KEYMAP_HOME;
1054
1055 case 'F': /* ansi End */
1056 case 'Y': /* at386 End */
1057#ifdef QNX42
1058 case 0xA8:
1059#endif /* QNX42 */
1060 return KEYMAP_END;
1061
1062 case '2': /* vt200 Ins */
1063 (void) ReadCh(); /* eat the ~ */
1064 return KEYMAP_INS;
1065
1066 case '3': /* vt200 Del */
1067 (void) ReadCh(); /* eat the ~ */
1068 return KEYMAP_DEL;
1069
1070 case '5': /* vt200 PgUp */
1071 (void) ReadCh(); /* eat the ~ (interesting use of words :) */
1072 return KEYMAP_PAGE_UP;
1073
1074 case '6': /* vt200 PgUp */
1075 (void) ReadCh(); /* eat the ~ */
1076 return KEYMAP_PAGE_DOWN;
1077
1078 case '1': /* vt200 PgUp */
1079 ch = ReadCh(); /* eat the ~ */
1080 if (ch == '5') { /* RS/6000 PgUp is 150g, PgDn is 154g */
1081 ch1 = ReadCh();
1082 (void) ReadCh();
1083 if (ch1 == '0')
1084 return KEYMAP_PAGE_UP;
1085 if (ch1 == '4')
1086 return KEYMAP_PAGE_DOWN;
1087 }
1088 return KEYMAP_HOME;
1089
1090 case '4': /* vt200 PgUp */
1091 (void) ReadCh(); /* eat the ~ */
1092 return KEYMAP_END;
1093
1094 case 'M': /* xterminal button press */
1095 xmouse = ReadCh() - ' '; /* button */
1096 xcol = ReadCh() - '!'; /* column */
1097 xrow = ReadCh() - '!'; /* row */
1098 return KEYMAP_MOUSE;
1099
1100 default:
1101 return KEYMAP_UNKNOWN;
1102 }
1103}
1104
1105
1106/*
1107 * The UNIX version of ReadCh, termcap version
1108 */
1109int
1111 void)
1112{
1113 int result;
1114#ifndef READ_CHAR_HACK
1115 char ch;
1116#endif /* !READ_CHAR_HACK */
1117
1118 fflush(stdout);
1119#ifdef READ_CHAR_HACK
1120# undef getc
1121 while ((result = getc(stdin)) == EOF) {
1122 if (feof(stdin))
1123 break;
1124
1125# ifdef EINTR
1126 if (ferror(stdin) && errno != EINTR)
1127# else
1128 if (ferror(stdin))
1129# endif /* EINTR */
1130 break;
1131
1132 clearerr(stdin);
1133 }
1134
1135 return ((result == EOF) ? EOF : result & 0xFF);
1136
1137#else
1138# ifdef EINTR
1139
1141 while ((result = (int) read(0, &ch, 1)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1142 if (need_resize) {
1144 need_resize = cNo;
1145 }
1146 }
1148# else
1149 result = read(0, &ch, 1);
1150# endif /* EINTR */
1151
1152 return ((result <= 0) ? EOF : ch & 0xFF);
1153
1154#endif /* READ_CHAR_HACK */
1155}
1156
1157
1158#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1159/*
1160 * A helper function for ReadWch()
1161 * converts the read input to a wide-char
1162 */
1163static wint_t
1164convert_c2wc(
1165 const char *input)
1166{
1167 int res;
1168 wchar_t wc;
1169
1170 res = mbtowc(&wc, input, MB_CUR_MAX);
1171 if (res == -1)
1172 return WEOF;
1173 else
1174 return (wint_t) wc;
1175}
1176
1177
1178wint_t
1179ReadWch(
1180 void)
1181{
1182 char *mbs = my_malloc(MB_CUR_MAX + 1);
1183 int result, to_read;
1184 wchar_t wch;
1185
1186 fflush(stdout);
1187
1188 /*
1189 * Independent of the pressed key and the used charset we have to
1190 * read at least one byte. The further processing is depending of
1191 * the read byte and the used charset.
1192 */
1193# ifdef EINTR
1195 while ((result = (int) read(0, mbs, 1)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1196 if (need_resize) {
1198 need_resize = cNo;
1199 }
1200 }
1202# else
1203 result = read(0, mbs, 1);
1204# endif /* EINTR */
1205
1206 if (result <= 0) {
1207 free(mbs);
1208 return WEOF;
1209 }
1210
1211 /* Begin of an ESC-sequence. Let get_arrow_key() figure out which it is */
1212 if (mbs[0] == ESC) {
1213 free(mbs);
1214 return (wint_t) ESC;
1215 }
1216
1217 /*
1218 * In an one-byte charset we don't need to read further chars but
1219 * we still need to convert the char to a correct wide-char
1220 */
1221 if (MB_CUR_MAX == 1) {
1222 mbs[1] = '\0';
1223 wch = (wchar_t) convert_c2wc(mbs);
1224 free(mbs);
1225
1226 return (wint_t) wch;
1227 }
1228
1229 /*
1230 * we use a multi-byte charset
1231 */
1232
1233 /*
1234 * UTF-8
1235 */
1236 if (IS_LOCAL_CHARSET("UTF-8")) {
1237 int ch = mbs[0] & 0xFF;
1238
1239 /* determine the count of bytes we have still have to read */
1240 if (ch <= 0x7F) {
1241 /* ASCII char */
1242 to_read = 0;
1243 } else if (ch >= 0xC2 && ch <= 0xDF) {
1244 /* 2-byte sequence */
1245 to_read = 1;
1246 } else if (ch >= 0xE0 && ch <= 0xEF) {
1247 /* 3-byte sequence */
1248 to_read = 2;
1249 } else if (ch >= 0xF0 && ch <= 0xF4) {
1250 /* 4-byte sequence */
1251 to_read = 3;
1252 } else {
1253 /* invalid sequence */
1254 free(mbs);
1255 return WEOF;
1256 }
1257
1258 /* read the missing bytes of the multi-byte sequence */
1259 if (to_read > 0) {
1260# ifdef EINTR
1262 while ((result = (int) read(0, mbs + 1, (size_t) to_read)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1263 if (need_resize) {
1265 need_resize = cNo;
1266 }
1267 }
1269# else
1270 result = read(0, mbs + 1, (size_t) to_read);
1271# endif /* EINTR */
1272 if (result < 0) {
1273 free(mbs);
1274
1275 return WEOF;
1276 }
1277 }
1278 mbs[to_read + 1] = '\0';
1279 wch = (wchar_t) convert_c2wc(mbs);
1280 free (mbs);
1281
1282 return (wint_t) wch;
1283
1284 }
1285
1286 /* FIXME: add support for other multi-byte charsets */
1287
1288 free(mbs);
1289 return WEOF;
1290}
1291#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
unsigned t_bool
Definition: bool.h:77
#define TRUE
Definition: bool.h:74
#define FALSE
Definition: bool.h:70
#define DEFAULT_LINES_ON_TERMINAL
Definition: curses.c:49
static char * _clearunderline
Definition: curses.c:107
void set_keypad_on(void)
Definition: curses.c:381
void word_highlight_string(int row, int col, int size, int color)
Definition: curses.c:774
static char * _setinverse
Definition: curses.c:107
static char * _setunderline
Definition: curses.c:107
static int _bottomscrregion
Definition: curses.c:487
static int _inraw
Definition: curses.c:55
static char * _terminalend
Definition: curses.c:109
t_bool have_linescroll
Definition: curses.c:57
#define TGETSTR(a, bufp)
Definition: curses.c:199
int ReadCh(void)
Definition: curses.c:1110
static char * _scrollfwd
Definition: curses.c:110
static char * _cleartoeoln
Definition: curses.c:106
int get_termcaps(void)
Definition: curses.c:216
void StartInverse(void)
Definition: curses.c:540
int RawState(void)
Definition: curses.c:604
static char * _dim
Definition: curses.c:111
static char * _reversevideo
Definition: curses.c:111
#define dCAPNAME(a, b)
Definition: curses.c:198
#define TGETNUM(a)
Definition: curses.c:200
static char * _terminalinit
Definition: curses.c:109
static char * _keypadxmit
Definition: curses.c:109
static char * _scrollregion
Definition: curses.c:110
void ClearScreen(void)
Definition: curses.c:410
void set_xclick_on(void)
Definition: curses.c:691
void cursoroff(void)
Definition: curses.c:721
#define TFORMAT(fmt, a, b)
Definition: curses.c:208
int _hp_glitch
Definition: curses.c:54
void ScrollScreen(int lines_to_scroll)
Definition: curses.c:509
void set_keypad_off(void)
Definition: curses.c:394
static int input_pending(int delay)
Definition: curses.c:890
static TTY _raw_tty
Definition: curses.c:92
void EndWin(void)
Definition: curses.c:368
static char * _cleartoeos
Definition: curses.c:106
static int _colors
Definition: curses.c:113
void SetScrollRegion(int topline, int bottomline)
Definition: curses.c:490
void MoveCursor(int row, int col)
Definition: curses.c:441
static char * _xclickinit
Definition: curses.c:108
void Raw(int state)
Definition: curses.c:624
void set_xclick_off(void)
Definition: curses.c:703
void InitWin(void)
Definition: curses.c:355
static TTY _original_tty
Definition: curses.c:92
static char * _reset
Definition: curses.c:111
static char * _cursoron
Definition: curses.c:108
static char * _xclickend
Definition: curses.c:108
void cursoron(void)
Definition: curses.c:712
void setup_screen(void)
Definition: curses.c:170
int cCOLS
Definition: curses.c:53
static char * _scrollback
Definition: curses.c:110
static int _topscrregion
Definition: curses.c:487
int cLINES
Definition: curses.c:52
static void ScreenSize(int *num_lines, int *num_columns)
Definition: curses.c:152
#define CAPNAME(a, b)
Definition: curses.c:197
#define DEFAULT_COLUMNS_ON_TERMINAL
Definition: curses.c:50
static char * _keypadlocal
Definition: curses.c:109
static char * _clearscreen
Definition: curses.c:106
void CleartoEOS(void)
Definition: curses.c:470
static int _lines
Definition: curses.c:113
static int xclicks
Definition: curses.c:56
static int _line
Definition: curses.c:113
static char * _moveto
Definition: curses.c:106
int InitScreen(void)
Definition: curses.c:343
static void xclick(int state)
Definition: curses.c:670
static char * _clearinverse
Definition: curses.c:107
static char * _bold
Definition: curses.c:111
void CleartoEOLN(void)
Definition: curses.c:458
void outchar(int c)
Definition: curses.c:656
#define NO_CAP(s)
Definition: curses.c:202
static char * _cursoroff
Definition: curses.c:108
static char * _blink
Definition: curses.c:111
static int _columns
Definition: curses.c:113
void EndInverse(void)
Definition: curses.c:564
#define TGETFLAG(a)
Definition: curses.c:201
void highlight_string(int row, int col, int size)
Definition: curses.c:733
int get_arrow_key(int prech)
Definition: curses.c:961
constext txt_no_term_set[]
Definition: lang.c:706
constext txt_screen_too_small[]
Definition: lang.c:832
constext txt_no_term_clearscreen[]
Definition: lang.c:704
t_bool cmd_line
Definition: init.c:129
int xcol
Definition: init.c:123
constext txt_no_term_clear_eol[]
Definition: lang.c:702
constext txt_cannot_get_term_entry[]
Definition: lang.c:1224
int xrow
Definition: init.c:123
int need_resize
Definition: signal.c:107
constext txt_no_term_clear_eos[]
Definition: lang.c:703
char * tin_progname
Definition: init.c:105
int xmouse
Definition: init.c:123
struct t_config tinrc
Definition: init.c:192
struct t_screen * screen
Definition: screen.c:51
constext txt_no_term_cursor_motion[]
Definition: lang.c:705
static struct t_hashnode * table[222199]
Definition: hashstr.c:56
#define ESC
Definition: keymap.h:140
static char * output
Definition: plp_snprintf.c:204
int errno
char * str_trim(char *string)
Definition: string.c:539
t_bool set_win_size(int *num_lines, int *num_cols)
Definition: signal.c:585
void allow_resize(t_bool allow)
Definition: signal.c:203
void handle_resize(t_bool repaint)
Definition: signal.c:249
void my_strncpy(char *p, const char *q, size_t n)
Definition: string.c:196
void stow_cursor(void)
Definition: screen.c:59
state
Definition: save.c:56
t_bool inverse_okay
Definition: tinrc.h:227
t_bool draw_arrow
Definition: tinrc.h:223
t_bool use_mouse
Definition: tinrc.h:267
int word_h_display_marks
Definition: tinrc.h:200
char * col
Definition: tin.h:1974
#define my_flush()
Definition: tcurses.h:177
#define my_fprintf
Definition: tcurses.h:176
#define my_fputs(str, stream)
Definition: tcurses.h:159
void my_dummy(void)
#define STRCMPEQ(s1, s2)
Definition: tin.h:822
#define LEN
Definition: tin.h:860
#define MAX_COLOR
Definition: tin.h:1003
#define OUTC_FUNCTION(func)
Definition: tin.h:2308
#define KEYMAP_END
Definition: tin.h:1084
#define KEYMAP_RIGHT
Definition: tin.h:1080
#define IS_LOCAL_CHARSET(c)
Definition: tin.h:782
#define KEYMAP_UNKNOWN
Definition: tin.h:1076
#define KEYMAP_UP
Definition: tin.h:1077
#define KEYMAP_LEFT
Definition: tin.h:1079
#define EOF
Definition: tin.h:2516
#define my_malloc(size)
Definition: tin.h:2245
#define KEYMAP_PAGE_DOWN
Definition: tin.h:1082
#define KEYMAP_PAGE_UP
Definition: tin.h:1081
#define ARRAY_SIZE(array)
Definition: tin.h:2250
#define MIN_LINES_ON_TERMINAL
Definition: tin.h:1095
#define _(Text)
Definition: tin.h:94
#define KEYMAP_MOUSE
Definition: tin.h:1087
@ cNo
Definition: tin.h:109
@ cRedraw
Definition: tin.h:109
#define MAX_ATTR
Definition: tin.h:1009
#define SECOND_CHARACTER_DELAY
Definition: tin.h:464
#define KEYMAP_DOWN
Definition: tin.h:1078
#define KEYMAP_INS
Definition: tin.h:1086
#define MIN_COLUMNS_ON_TERMINAL
Definition: tin.h:1096
#define KEYMAP_DEL
Definition: tin.h:1085
#define KEYMAP_HOME
Definition: tin.h:1083
#define MAX(a, b)
Definition: tin.h:808
#define STDIN_FILENO
Definition: tin.h:394