"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/src/curses.c" (9 Dec 2022, 26542 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "curses.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.6.0_vs_2.6.1.
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
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
52 int cLINES = DEFAULT_LINES_ON_TERMINAL - 1;
53 int cCOLS = DEFAULT_COLUMNS_ON_TERMINAL;
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? */
57 t_bool have_linescroll = FALSE;
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
106 static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
107 *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
108 *_xclickinit, *_xclickend, *_cursoron, *_cursoroff,
109 *_terminalinit, *_terminalend, *_keypadlocal, *_keypadxmit,
110 *_scrollregion, *_scrollfwd, *_scrollback,
111 *_reset, *_reversevideo, *_blink, *_dim, *_bold;
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
152 ScreenSize(
153 int *num_lines,
154 int *num_columns)
155 {
156 if (!_lines)
157 _lines = DEFAULT_LINES_ON_TERMINAL;
158 if (!_columns)
159 _columns = DEFAULT_COLUMNS_ON_TERMINAL;
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
170 setup_screen(
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 */
180 set_win_size(&cLINES, &cCOLS);
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
216 get_termcaps(
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) {
262 my_fprintf(stderr, _(txt_no_term_set), tin_progname);
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) {
272 my_fprintf(stderr, _(txt_cannot_get_term_entry), tin_progname);
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)) {
301 my_fprintf(stderr, _(txt_no_term_clearscreen), tin_progname);
302 return FALSE;
303 }
304 if (NO_CAP(_moveto)) {
305 my_fprintf(stderr, _(txt_no_term_cursor_motion), tin_progname);
306 return FALSE;
307 }
308 if (NO_CAP(_cleartoeoln)) {
309 my_fprintf(stderr, _(txt_no_term_clear_eol), tin_progname);
310 return FALSE;
311 }
312 if (NO_CAP(_cleartoeos)) {
313 my_fprintf(stderr, _(txt_no_term_clear_eos), tin_progname);
314 return FALSE;
315 }
316 if (_lines == -1)
317 _lines = DEFAULT_LINES_ON_TERMINAL;
318 if (_columns == -1)
319 _columns = DEFAULT_COLUMNS_ON_TERMINAL;
320
321 if (_lines < MIN_LINES_ON_TERMINAL || _columns < MIN_COLUMNS_ON_TERMINAL) {
322 my_fprintf(stderr, _(txt_screen_too_small), tin_progname);
323 return FALSE;
324 }
325 /*
326 * kludge to workaround no inverse
327 */
328 if (NO_CAP(_setinverse)) {
329 _setinverse = _setunderline;
330 _clearinverse = _clearunderline;
331 if (NO_CAP(_setinverse))
332 tinrc.draw_arrow = 1;
333 }
334 if (NO_CAP(_scrollregion) || NO_CAP(_scrollfwd) || NO_CAP(_scrollback))
335 have_linescroll = FALSE;
336 else
337 have_linescroll = TRUE;
338 return TRUE;
339 }
340
341
342 int
343 InitScreen(
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
355 InitWin(
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
368 EndWin(
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
381 set_keypad_on(
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
394 set_keypad_off(
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
410 ClearScreen(
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
441 MoveCursor(
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
458 CleartoEOLN(
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
470 CleartoEOS(
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
487 static int _topscrregion, _bottomscrregion;
488
489 void
490 SetScrollRegion(
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
509 ScrollScreen(
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++) {
520 MoveCursor(_topscrregion, 0);
521 tputs(_scrollback, 1, outchar);
522 }
523 }
524 } else
525 if (_scrollfwd) {
526 i = lines_to_scroll;
527 while (i--) {
528 MoveCursor(_bottomscrregion, 0);
529 tputs(_scrollfwd, 1, outchar);
530 }
531 }
532 my_flush();
533 }
534
535
536 /*
537 * set inverse video mode
538 */
539 void
540 StartInverse(
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
564 EndInverse(
565 void)
566 {
567 /* in_inverse = 0; */
568 if (_clearinverse && tinrc.inverse_okay) {
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
604 RawState(
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
624 Raw(
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 */
655 OUTC_FUNCTION(
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
670 xclick(
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
691 set_xclick_on(
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
703 set_xclick_off(
704 void)
705 {
706 if (tinrc.use_mouse)
707 xclick(FALSE);
708 }
709
710
711 void
712 cursoron(
713 void)
714 {
715 if (_cursoron)
716 tputs(_cursoron, 1, outchar);
717 }
718
719
720 void
721 cursoroff(
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
733 highlight_string(
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 */
773 void
774 word_highlight_string(
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] = ' ';
838 str_trim(output);
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] = ' ';
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
890 input_pending(
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
961 get_arrow_key(
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
1110 ReadCh(
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 = (int) read(0, &ch, 1)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1142 if (need_resize) {
1143 handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
1144 need_resize = cNo;
1145 }
1146 }
1147 allow_resize(FALSE);
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 = (int) read(0, mbs, 1)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1196 if (need_resize) {
1197 handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
1198 need_resize = cNo;
1199 }
1200 }
1201 allow_resize(FALSE);
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
1261 allow_resize(TRUE);
1262 while ((result = (int) read(0, mbs + 1, (size_t) to_read)) < 0 && errno == EINTR) { /* spin on signal interrupts */
1263 if (need_resize) {
1264 handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
1265 need_resize = cNo;
1266 }
1267 }
1268 allow_resize(FALSE);
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 */