1 /******************************************************************************
2  * Copyright 1995-2010,2011 by Thomas E. Dickey                               *
3  * All Rights Reserved.                                                       *
4  *                                                                            *
5  * Permission to use, copy, modify, and distribute this software and its      *
6  * documentation for any purpose and without fee is hereby granted, provided  *
7  * that the above copyright notice appear in all copies and that both that    *
8  * copyright notice and this permission notice appear in supporting           *
9  * documentation, and that the name of the above listed copyright holder(s)   *
10  * not be used in advertising or publicity pertaining to distribution of the  *
11  * software without specific, written prior permission.                       *
12  *                                                                            *
13  * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD   *
14  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND  *
15  * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE  *
16  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES          *
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN      *
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR *
19  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.                *
20  ******************************************************************************/
21 
22 static const char Id[] = "$Id: curses.c,v 1.17 2011/03/06 16:58:53 tom Exp $";
23 
24 /*
25  * Title:	curses.c
26  * Author:	T.E.Dickey
27  * Created:	14 Dec 1995 (split-off from add.c)
28  * Modified:
29  *
30  * Function:	This module hides the curses functional interface from 'add'
31  *
32  */
33 
34 #include <add.h>
35 #include <screen.h>
36 
37 #include <stdarg.h>
38 
39 #if HAVE_XCURSES
40 #include <xcurses.h>
41 #else
42 #include <curses.h>
43 #endif
44 
45 #ifndef PADSLASH		/* PDCURSES */
46 #define PADSLASH '/'
47 #define PADSTAR  '*'
48 #define PADPLUS  '+'
49 #define PADMINUS '-'
50 #define PADENTER '\n'
51 #endif
52 
53 #if !HAVE_COLOR_PAIR && defined(COLOR_PAIR)
54 #define HAVE_COLOR_PAIR 1
55 #endif
56 
57 #if HAVE_COLOR_PAIR
58 #define	CURRENT_COLOR current_color
59 #define SetColors(n)  wattron(stdscr, current_color = COLOR_PAIR(n))
60 #else
61 #define CURRENT_COLOR 0
62 #define SetColors(n)
63 #endif
64 
65 #ifdef A_BOLD
66 #define BeginBold()  wattron (stdscr, A_BOLD    | CURRENT_COLOR)
67 #define EndOfBold()  wattroff(stdscr, A_BOLD)
68 #else
69 #define BeginBold()  standout()
70 #define EndOfBold()  standend()
71 #endif
72 
73 #ifdef A_REVERSE
74 #define BeginHigh()  wattron (stdscr, A_REVERSE | CURRENT_COLOR)
75 #define EndOfHigh()  wattroff(stdscr, A_REVERSE)
76 #else
77 #define BeginHigh()  standout()
78 #define EndOfHigh()  standend()
79 #endif
80 
81 /*
82  * Common data
83  */
84 Bool screen_active;		/* true while we've got curses running */
85 int screen_full;		/* screen-size */
86 int screen_half;		/* scrolling amount */
87 
88 #if HAVE_COLOR_PAIR
89 static chtype current_color;
90 #endif
91 
92 int
is_delete_left(int c)93 is_delete_left(int c)
94 {
95     switch (c) {
96     case '\b':
97     case '\177':
98 #if defined(KEY_BACKSPACE)
99     case KEY_BACKSPACE:
100 #endif
101 #if defined(KEY_DC)
102     case KEY_DC:
103 #endif
104 	return TRUE;
105     default:
106 	return FALSE;
107     }
108 }
109 
110 Bool
is_down_char(int c)111 is_down_char(int c)
112 {
113     switch (c) {
114     case VI_DOWN:
115 #ifdef KEY_DOWN
116     case KEY_DOWN:
117 #endif
118 	return TRUE;
119     default:
120 	return FALSE;
121     }
122 }
123 
124 Bool
is_down_page(int c)125 is_down_page(int c)
126 {
127     switch (c) {
128     case VI_NPAGE:
129 #ifdef KEY_NPAGE
130     case KEY_NPAGE:
131 #endif
132 	return TRUE;
133     default:
134 	return FALSE;
135     }
136 }
137 
138 Bool
is_end_char(int c)139 is_end_char(int c)
140 {
141     switch (c) {
142     case CTL('E'):
143 #ifdef KEY_END
144     case KEY_END:
145 #endif
146 	return TRUE;
147     default:
148 	return FALSE;
149     }
150 }
151 
152 Bool
is_left_char(int c)153 is_left_char(int c)
154 {
155     switch (c) {
156     case CTL('B'):		/* only used in editing comments */
157     case VI_LEFT:
158 #ifdef KEY_LEFT
159     case KEY_LEFT:
160 #endif
161 	return TRUE;
162     default:
163 	return FALSE;
164     }
165 }
166 
167 Bool
is_home_char(int c)168 is_home_char(int c)
169 {
170     switch (c) {
171     case CTL('A'):
172 #ifdef KEY_HOME
173     case KEY_HOME:
174 #endif
175 	return TRUE;
176     default:
177 	return FALSE;
178     }
179 }
180 
181 Bool
is_right_char(int c)182 is_right_char(int c)
183 {
184     switch (c) {
185     case CTL('F'):		/* only used in editing comments */
186     case VI_RIGHT:
187 #ifdef KEY_RIGHT
188     case KEY_RIGHT:
189 #endif
190 	return TRUE;
191     default:
192 	return FALSE;
193     }
194 }
195 
196 Bool
is_up_char(int c)197 is_up_char(int c)
198 {
199     switch (c) {
200     case VI_UP:
201 #ifdef KEY_UP
202     case KEY_UP:
203 #endif
204 	return TRUE;
205     default:
206 	return FALSE;
207     }
208 }
209 
210 Bool
is_up_page(int c)211 is_up_page(int c)
212 {
213     switch (c) {
214     case VI_PPAGE:
215 #ifdef KEY_PPAGE
216     case KEY_PPAGE:
217 #endif
218 	return TRUE;
219     default:
220 	return FALSE;
221     }
222 }
223 
224 /*
225  * Beep (or flash, preferably) when we get a minor error.
226  */
227 void
screen_alarm(void)228 screen_alarm(void)
229 {
230 #if HAVE_FLASH
231     flash();
232 #elif HAVE_BEEP
233     beep();
234 #else
235     (void) write(2, "\007", 1);	/* Real BSD-curses has 'beep()' */
236 #endif
237 }
238 
239 void
screen_clear_bottom(void)240 screen_clear_bottom(void)
241 {
242     clrtobot();
243 }
244 
245 void
screen_clear_endline(void)246 screen_clear_endline(void)
247 {
248     clrtoeol();
249 }
250 
251 /*
252  * Returns current column
253  */
254 int
screen_col(void)255 screen_col(void)
256 {
257     int y, x;
258 
259     getyx(stdscr, y, x);
260     return x;
261 }
262 
263 /*
264  * Returns the columns left on the line, given a starting column
265  */
266 int
screen_cols_left(int col)267 screen_cols_left(int col)
268 {
269     return COLS - 1 - col;
270 }
271 
272 /*
273  * Delete the character at the current position
274  */
275 void
screen_delete_char(void)276 screen_delete_char(void)
277 {
278     delch();
279 }
280 
281 void
screen_finish(void)282 screen_finish(void)
283 {
284     if (screen_active) {
285 	nl();			/* does no harm, some curses don't do it */
286 	endwin();
287 	screen_active = FALSE;	/* flag showing that curses is off */
288     }
289 }
290 
291 /*
292  * Read a character from the terminal
293  */
294 int
screen_getc(void)295 screen_getc(void)
296 {
297     int c;
298 
299     refresh();
300     c = getch();
301     switch (c) {
302     case PADSLASH:
303 	c = OP_DIV;
304 	break;
305     case PADSTAR:
306 	c = OP_MUL;
307 	break;
308     case PADPLUS:
309 	c = OP_ADD;
310 	break;
311     case PADMINUS:
312 	c = OP_SUB;
313 	break;
314     case PADENTER:
315 	c = '\n';
316 	break;
317     }
318     return (c);
319 }
320 
321 /*
322  * Insert a character at the current position
323  */
324 void
screen_insert_char(int c)325 screen_insert_char(int c)
326 {
327     insch((unsigned char) c);
328 }
329 
330 /*
331  * Show text in the status line
332  */
333 void
screen_message(const char * format,...)334 screen_message(const char *format,...)
335 {
336     char msg[BUFSIZ];
337     va_list ap;
338     int y, x;
339 
340     getyx(stdscr, y, x);
341     move(0, 0);
342 
343     va_start(ap, format);
344     vsprintf(msg, format, ap);
345     va_end(ap);
346     addstr(msg);
347 
348     clrtoeol();
349     move(y, x);
350     refresh();
351 }
352 
353 /*
354  * Move left within the given buffer.
355  */
356 int
screen_move_left(int col,int limit)357 screen_move_left(int col, int limit)
358 {
359     if (col > limit) {
360 	register int y, x;
361 	getyx(stdscr, y, x);
362 	move(y, x - 1);
363 	col--;
364     } else
365 	screen_alarm();
366     return col;
367 }
368 
369 /*
370  * Move right within the given buffer.
371  */
372 int
screen_move_right(int col,int limit)373 screen_move_right(int col, int limit)
374 {
375     if (col < limit) {
376 	register int y, x;
377 	getyx(stdscr, y, x);
378 	move(y, x + 1);
379 	col++;
380     } else
381 	screen_alarm();
382     return col;
383 }
384 
385 void
screen_printf(const char * format,...)386 screen_printf(const char *format,...)
387 {
388     char msg[BUFSIZ];
389     va_list ap;
390 
391     va_start(ap, format);
392     vsprintf(msg, format, ap);
393     va_end(ap);
394     addstr(msg);
395 }
396 
397 void
screen_putc(int c)398 screen_putc(int c)
399 {
400     addch((unsigned char) c);
401 }
402 
403 void
screen_puts(const char * string)404 screen_puts(const char *string)
405 {
406     addstr(string);
407 }
408 
409 /*
410  * Returns current row
411  */
412 int
screen_row(void)413 screen_row(void)
414 {
415     int y, x;
416 
417     getyx(stdscr, y, x);
418     return y;
419 }
420 
421 /*
422  * Returns the rows left on the line, given a starting row
423  */
424 int
screen_rows_left(int row)425 screen_rows_left(int row)
426 {
427     return LINES - 1 - row;
428 }
429 
430 void
screen_set_bold(Bool flag)431 screen_set_bold(Bool flag)
432 {
433     if (flag)
434 	BeginBold();
435     else
436 	EndOfBold();
437 }
438 
439 void
screen_set_position(int row,int column)440 screen_set_position(int row, int column)
441 {
442     move(row, column);
443 }
444 
445 void
screen_set_reverse(Bool flag)446 screen_set_reverse(Bool flag)
447 {
448     if (flag)
449 	BeginHigh();
450     else
451 	EndOfHigh();
452 }
453 
454 /*
455  * Setup and run the interactive portion of the program.
456  */
457 void
screen_start(void)458 screen_start(void)
459 {
460     if (initscr() == 0)		/* should return a "WINDOW *" */
461 	exit(EXIT_FAILURE);
462 #if HAVE_KEYPAD
463     keypad(stdscr, TRUE);
464 #endif
465 #if HAVE_DEFINE_KEY
466     define_key("\033Ok", '+');
467     define_key("\033Ol", ',');
468     define_key("\033Om", '-');
469     define_key("\033On", '.');
470     define_key("\033Op", '0');
471     define_key("\033Oq", '1');
472     define_key("\033Or", '2');
473     define_key("\033Os", '3');
474     define_key("\033Ot", '4');
475     define_key("\033Ou", '5');
476     define_key("\033Ov", '6');
477     define_key("\033Ow", '7');
478     define_key("\033Ox", '8');
479     define_key("\033Oy", '9');
480     define_key("\033OM", '\n');
481 #endif
482 #if defined(COLOR_BLUE) && defined(COLOR_WHITE) && HAVE_COLOR_PAIR
483     if (has_colors()) {
484 	start_color();
485 	init_pair(1, COLOR_WHITE, COLOR_BLUE);	/* normal */
486 	SetColors(1);
487 #if HAVE_BKGD
488 	bkgd(CURRENT_COLOR);
489 #endif
490     }
491 #endif
492 #if HAVE_TYPEAHEAD
493     typeahead(-1);		/* disable typeahead */
494 #endif
495 #if SYS_MSDOS && defined(F_GRAY) && defined(B_BLUE)
496     wattrset(stdscr, F_GRAY | B_BLUE);	/* patch for old PD-Curses */
497 #endif
498     raw();
499     nonl();
500     noecho();
501     screen_full = LINES - 1;
502     screen_half = (screen_full + 1) / 2;
503     screen_active = TRUE;
504 
505 #if HAVE_WSETSCRREG
506     setscrreg(2, screen_full);
507 #endif
508 }
509