tin  2.4.4
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.4.4.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 : 2019-03-12
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 
40 void my_dummy(void) { } /* ANSI C requires non-empty file */
41 t_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 
54 int _hp_glitch = FALSE; /* stdout not erased by overwriting on HP terms */
55 static int _inraw = FALSE; /* are we IN rawmode? */
56 static 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 
92 static TTY _raw_tty, _original_tty;
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 
113 static int _columns, _line, _lines, _colors;
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  */
143 static int input_pending(int delay);
144 static void ScreenSize(int *num_lines, int *num_columns);
145 static void xclick(int state);
146 
147 
148 /*
149  * returns the number of lines and columns on the display.
150  */
151 static 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  */
169 void
171  void)
172 {
173  _line = 1;
174  ScreenSize(&cLINES, &cCOLS);
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 
215 int
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 
342 int
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 
354 void
356  void)
357 {
358  if (_terminalinit) {
359  tputs(_terminalinit, 1, outchar);
360  my_flush();
361  }
362  set_keypad_on();
363  set_xclick_on();
364 }
365 
366 
367 void
369  void)
370 {
371  if (_terminalend) {
372  tputs(_terminalend, 1, outchar);
373  my_flush();
374  }
375  set_keypad_off();
376  set_xclick_off();
377 }
378 
379 
380 void
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 
393 void
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  */
409 void
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
424 void
425 reset_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  */
440 void
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  */
457 void
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  */
469 void
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 
489 void
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 
508 void
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  */
539 void
541  void)
542 {
543 /* in_inverse = 1; */
544  if (_setinverse && tinrc.inverse_okay) {
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  */
563 void
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  */
588 void
589 ToggleInverse(
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  */
603 int
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  */
623 void
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  */
656  outchar)
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  */
669 static 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  */
690 void
692  void)
693 {
694  if (tinrc.use_mouse)
695  xclick(TRUE);
696 }
697 
698 
699 /*
700  * switch off monitoring of mouse buttons
701  */
702 void
704  void)
705 {
706  if (tinrc.use_mouse)
707  xclick(FALSE);
708 }
709 
710 
711 void
713  void)
714 {
715  if (_cursoron)
716  tputs(_cursoron, 1, outchar);
717 }
718 
719 
720 void
722  void)
723 {
724  if (_cursoroff)
725  tputs(_cursoroff, 1, outchar);
726 }
727 
728 
729 /*
730  * Inverse 'size' chars at (row,col)
731  */
732 void
734  int row,
735  int col,
736  int size)
737 {
738  char output[LEN];
739 
740  my_strncpy(output, &(screen[row].col[col]), 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) {
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  */
773 void
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);
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] = ' ';
838  str_trim(output);
839  strncpy(&(screen[row].col[byte_offset]), output, 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] = ' ';
854  str_trim(output);
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  */
889 static 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 */
960 int
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  */
1109 int
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 
1140  allow_resize(TRUE);
1141  while ((result = 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  */
1163 static wint_t
1164 convert_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 
1178 wint_t
1179 ReadWch(
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
1194  allow_resize(TRUE);
1195  while ((result = 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 = 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
1261  allow_resize(TRUE);
1262  while ((result = read(0, mbs + 1, 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, 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 = 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 */
EOF
#define EOF
Definition: tin.h:2445
_clearunderline
static char * _clearunderline
Definition: curses.c:107
KEYMAP_END
#define KEYMAP_END
Definition: tin.h:1073
set_xclick_off
void set_xclick_off(void)
Definition: curses.c:703
_
#define _(Text)
Definition: tin.h:94
txt_no_term_clear_eos
constext txt_no_term_clear_eos[]
Definition: lang.c:692
_xclickinit
static char * _xclickinit
Definition: curses.c:108
_setinverse
static char * _setinverse
Definition: curses.c:107
KEYMAP_INS
#define KEYMAP_INS
Definition: tin.h:1075
_reversevideo
static char * _reversevideo
Definition: curses.c:111
str_trim
char * str_trim(char *string)
Definition: string.c:532
input_pending
static int input_pending(int delay)
Definition: curses.c:890
dCAPNAME
#define dCAPNAME(a, b)
Definition: curses.c:198
KEYMAP_RIGHT
#define KEYMAP_RIGHT
Definition: tin.h:1069
_dim
static char * _dim
Definition: curses.c:111
ESC
#define ESC
Definition: keymap.h:140
screen
struct t_screen * screen
Definition: screen.c:51
InitScreen
int InitScreen(void)
Definition: curses.c:343
_colors
static int _colors
Definition: curses.c:113
xclick
static void xclick(int state)
Definition: curses.c:670
my_flush
#define my_flush()
Definition: tcurses.h:171
t_config::word_h_display_marks
int word_h_display_marks
Definition: tinrc.h:188
t_config::use_mouse
t_bool use_mouse
Definition: tinrc.h:257
table
static struct t_hashnode * table[2411]
Definition: hashstr.c:61
_inraw
static int _inraw
Definition: curses.c:55
_terminalinit
static char * _terminalinit
Definition: curses.c:109
tinrc
struct t_config tinrc
Definition: init.c:191
cLINES
int cLINES
Definition: curses.c:52
value
Definition: plp_snprintf.c:180
cCOLS
int cCOLS
Definition: curses.c:53
DEFAULT_LINES_ON_TERMINAL
#define DEFAULT_LINES_ON_TERMINAL
Definition: curses.c:49
word_highlight_string
void word_highlight_string(int row, int col, int size, int color)
Definition: curses.c:774
_bold
static char * _bold
Definition: curses.c:111
_cleartoeos
static char * _cleartoeos
Definition: curses.c:106
MIN_COLUMNS_ON_TERMINAL
#define MIN_COLUMNS_ON_TERMINAL
Definition: tin.h:1085
txt_screen_too_small
constext txt_screen_too_small[]
Definition: lang.c:819
KEYMAP_HOME
#define KEYMAP_HOME
Definition: tin.h:1072
_clearscreen
static char * _clearscreen
Definition: curses.c:106
outchar
OUTC_RETTYPE outchar(OUTC_ARGS)
state
state
Definition: save.c:56
tcurses.h
_keypadlocal
static char * _keypadlocal
Definition: curses.c:109
have_linescroll
t_bool have_linescroll
Definition: curses.c:57
CleartoEOLN
void CleartoEOLN(void)
Definition: curses.c:458
SetScrollRegion
void SetScrollRegion(int topline, int bottomline)
Definition: curses.c:490
tin.h
MAX
#define MAX(a, b)
Definition: tin.h:802
KEYMAP_UNKNOWN
#define KEYMAP_UNKNOWN
Definition: tin.h:1065
_reset
static char * _reset
Definition: curses.c:111
MAX_ATTR
#define MAX_ATTR
Definition: tin.h:998
txt_no_term_clear_eol
constext txt_no_term_clear_eol[]
Definition: lang.c:691
tin_progname
char * tin_progname
Definition: init.c:105
my_fprintf
#define my_fprintf
Definition: tcurses.h:170
_hp_glitch
int _hp_glitch
Definition: curses.c:54
need_resize
int need_resize
Definition: signal.c:107
KEYMAP_LEFT
#define KEYMAP_LEFT
Definition: tin.h:1068
get_termcaps
int get_termcaps(void)
Definition: curses.c:216
_scrollregion
static char * _scrollregion
Definition: curses.c:110
STRCMPEQ
#define STRCMPEQ(s1, s2)
Definition: tin.h:816
MIN_LINES_ON_TERMINAL
#define MIN_LINES_ON_TERMINAL
Definition: tin.h:1084
my_strncpy
void my_strncpy(char *p, const char *q, size_t n)
Definition: string.c:190
_moveto
static char * _moveto
Definition: curses.c:106
set_keypad_off
void set_keypad_off(void)
Definition: curses.c:394
txt_cannot_get_term_entry
constext txt_cannot_get_term_entry[]
Definition: lang.c:1211
KEYMAP_DEL
#define KEYMAP_DEL
Definition: tin.h:1074
KEYMAP_MOUSE
#define KEYMAP_MOUSE
Definition: tin.h:1076
txt_no_term_cursor_motion
constext txt_no_term_cursor_motion[]
Definition: lang.c:694
xrow
int xrow
Definition: init.c:122
get_arrow_key
int get_arrow_key(int prech)
Definition: curses.c:961
cmd_line
t_bool cmd_line
Definition: init.c:128
Raw
void Raw(int state)
Definition: curses.c:624
setup_screen
void setup_screen(void)
Definition: curses.c:170
ARRAY_SIZE
#define ARRAY_SIZE(array)
Definition: tin.h:2201
TGETNUM
#define TGETNUM(a)
Definition: curses.c:200
ReadCh
int ReadCh(void)
Definition: curses.c:1110
MAX_COLOR
#define MAX_COLOR
Definition: tin.h:992
NO_CAP
#define NO_CAP(s)
Definition: curses.c:202
xclicks
static int xclicks
Definition: curses.c:56
_line
static int _line
Definition: curses.c:113
stow_cursor
void stow_cursor(void)
Definition: screen.c:59
set_xclick_on
void set_xclick_on(void)
Definition: curses.c:691
StartInverse
void StartInverse(void)
Definition: curses.c:540
handle_resize
void handle_resize(t_bool repaint)
Definition: signal.c:249
LEN
#define LEN
Definition: tin.h:854
STDIN_FILENO
#define STDIN_FILENO
Definition: tin.h:391
txt_no_term_set
constext txt_no_term_set[]
Definition: lang.c:695
RawState
int RawState(void)
Definition: curses.c:604
OUTC_FUNCTION
OUTC_FUNCTION(outchar)
Definition: curses.c:655
my_dummy
void my_dummy(void)
cNo
@ cNo
Definition: tin.h:109
_lines
static int _lines
Definition: curses.c:113
DEFAULT_COLUMNS_ON_TERMINAL
#define DEFAULT_COLUMNS_ON_TERMINAL
Definition: curses.c:50
set_keypad_on
void set_keypad_on(void)
Definition: curses.c:381
my_fputs
#define my_fputs(str, stream)
Definition: tcurses.h:153
xcol
int xcol
Definition: init.c:122
KEYMAP_PAGE_DOWN
#define KEYMAP_PAGE_DOWN
Definition: tin.h:1071
cursoroff
void cursoroff(void)
Definition: curses.c:721
_cleartoeoln
static char * _cleartoeoln
Definition: curses.c:106
_setunderline
static char * _setunderline
Definition: curses.c:107
set_win_size
t_bool set_win_size(int *num_lines, int *num_cols)
Definition: signal.c:582
CleartoEOS
void CleartoEOS(void)
Definition: curses.c:470
_blink
static char * _blink
Definition: curses.c:111
KEYMAP_PAGE_UP
#define KEYMAP_PAGE_UP
Definition: tin.h:1070
highlight_string
void highlight_string(int row, int col, int size)
Definition: curses.c:733
CAPNAME
#define CAPNAME(a, b)
Definition: curses.c:197
t_screen::col
char * col
Definition: tin.h:1930
cursoron
void cursoron(void)
Definition: curses.c:712
_bottomscrregion
static int _bottomscrregion
Definition: curses.c:487
EndWin
void EndWin(void)
Definition: curses.c:368
_cursoroff
static char * _cursoroff
Definition: curses.c:108
FALSE
#define FALSE
Definition: bool.h:70
ScreenSize
static void ScreenSize(int *num_lines, int *num_columns)
Definition: curses.c:152
TGETSTR
#define TGETSTR(a, bufp)
Definition: curses.c:199
_xclickend
static char * _xclickend
Definition: curses.c:108
_cursoron
static char * _cursoron
Definition: curses.c:108
_columns
static int _columns
Definition: curses.c:113
xmouse
int xmouse
Definition: init.c:122
_scrollback
static char * _scrollback
Definition: curses.c:110
cRedraw
@ cRedraw
Definition: tin.h:109
tnntp.h
ScrollScreen
void ScrollScreen(int lines_to_scroll)
Definition: curses.c:509
_clearinverse
static char * _clearinverse
Definition: curses.c:107
_topscrregion
static int _topscrregion
Definition: curses.c:487
IS_LOCAL_CHARSET
#define IS_LOCAL_CHARSET(c)
Definition: tin.h:776
_keypadxmit
static char * _keypadxmit
Definition: curses.c:109
InitWin
void InitWin(void)
Definition: curses.c:355
MoveCursor
void MoveCursor(int row, int col)
Definition: curses.c:441
missing_fd.h
t_bool
unsigned t_bool
Definition: bool.h:77
errno
int errno
_scrollfwd
static char * _scrollfwd
Definition: curses.c:110
TFORMAT
#define TFORMAT(fmt, a, b)
Definition: curses.c:208
output
static char * output
Definition: plp_snprintf.c:204
TRUE
#define TRUE
Definition: bool.h:74
t_config::inverse_okay
t_bool inverse_okay
Definition: tinrc.h:216
SECOND_CHARACTER_DELAY
#define SECOND_CHARACTER_DELAY
Definition: tin.h:461
TGETFLAG
#define TGETFLAG(a)
Definition: curses.c:201
_raw_tty
static TTY _raw_tty
Definition: curses.c:92
txt_no_term_clearscreen
constext txt_no_term_clearscreen[]
Definition: lang.c:693
_terminalend
static char * _terminalend
Definition: curses.c:109
EndInverse
void EndInverse(void)
Definition: curses.c:564
KEYMAP_UP
#define KEYMAP_UP
Definition: tin.h:1066
_original_tty
static TTY _original_tty
Definition: curses.c:92
KEYMAP_DOWN
#define KEYMAP_DOWN
Definition: tin.h:1067
ClearScreen
void ClearScreen(void)
Definition: curses.c:410
t_config::draw_arrow
t_bool draw_arrow
Definition: tinrc.h:212
allow_resize
void allow_resize(t_bool allow)
Definition: signal.c:203
my_malloc
#define my_malloc(size)
Definition: tin.h:2196