utilunix.c(mc_tmpdir): Check return value of getpwuid() for NULL.
[midnight-commander.git] / src / slint.c
blob1ec2119f3806ea035ff9dfdc32836204c44a0796
1 /* Slang interface to the Midnight Commander
2 This emulates some features of ncurses on top of slang
4 Copyright (C) 1995, 1996 The Free Software Foundation.
6 Author Miguel de Icaza
7 Norbert Warmuth
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <termios.h>
27 #include <signal.h>
28 #include <string.h>
30 #include "global.h"
31 #include "tty.h"
32 #include "color.h"
33 #include "mouse.h" /* Gpm_Event is required in key.h */
34 #include "key.h" /* define_sequence */
35 #include "main.h" /* extern: force_colors */
36 #include "win.h" /* do_exit_ca_mode */
37 #include "setup.h"
38 #include "background.h" /* we_are_background */
40 #ifdef HAVE_SLANG
42 /* Taken from S-Lang's slutty.c */
43 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
44 # define NULL_VALUE -1
45 #else
46 # ifdef _POSIX_VDISABLE
47 # define NULL_VALUE _POSIX_VDISABLE
48 # else
49 # define NULL_VALUE 255
50 # endif
51 #endif
53 /* Taken from S-Lang's sldisply.c file */
54 #ifndef USE_TERMCAP
55 # define tgetstr(a,b) SLtt_tgetstr (a)
56 #else
57 extern char *tgetstr(char *, char **);
58 #endif
60 #ifndef SA_RESTART
61 # define SA_RESTART 0
62 #endif
64 /* Various saved termios settings that we control here */
65 static struct termios boot_mode;
66 static struct termios new_mode;
68 /* Set if we get an interrupt */
69 static int slinterrupt;
71 /* Controls whether we should wait for input in getch */
72 static int no_slang_delay;
74 /* {{{ Copied from ../slang/slgetkey.c, removed the DEC_8Bit_HACK, */
75 extern unsigned char SLang_Input_Buffer [];
76 #if SLANG_VERSION >= 10000
77 extern unsigned int _SLsys_getkey (void);
78 extern int _SLsys_input_pending (int);
79 #else
80 extern unsigned int SLsys_getkey (void);
81 extern int SLsys_input_pending (int);
82 #endif
84 /* Forward declarations */
85 static void load_terminfo_keys (void);
87 static unsigned int SLang_getkey2 (void)
89 unsigned int imax;
90 unsigned int ch;
92 if (SLang_Input_Buffer_Len)
94 ch = (unsigned int) *SLang_Input_Buffer;
95 SLang_Input_Buffer_Len--;
96 imax = SLang_Input_Buffer_Len;
98 memmove ((char *) SLang_Input_Buffer,
99 (char *) (SLang_Input_Buffer + 1), imax);
100 return(ch);
102 #if SLANG_VERSION >= 10000
103 else return(_SLsys_getkey ());
104 #else
105 else return(SLsys_getkey());
106 #endif
109 static int SLang_input_pending2 (int tsecs)
111 int n, i;
112 unsigned char c;
114 if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
115 #if SLANG_VERSION >= 10000
116 n = _SLsys_input_pending (tsecs);
117 #else
118 n = SLsys_input_pending (tsecs);
119 #endif
120 if (n <= 0) return 0;
122 i = SLang_getkey2 ();
123 if (i == SLANG_GETKEY_ERROR)
124 return 0; /* don't put crippled error codes into the input buffer */
125 c = (unsigned char)i;
126 SLang_ungetkey_string (&c, 1);
128 return n;
130 /* }}} */
132 static void
133 slang_intr (int signo)
135 slinterrupt = 1;
138 void
139 enable_interrupt_key(void)
141 struct sigaction act;
143 act.sa_handler = slang_intr;
144 sigemptyset (&act.sa_mask);
145 act.sa_flags = 0;
146 sigaction (SIGINT, &act, NULL);
147 slinterrupt = 0;
150 void
151 disable_interrupt_key(void)
153 struct sigaction act;
155 act.sa_handler = SIG_IGN;
156 act.sa_flags = 0;
157 sigemptyset (&act.sa_mask);
158 sigaction (SIGINT, &act, NULL);
162 got_interrupt (void)
164 int t;
166 t = slinterrupt;
167 slinterrupt = 0;
168 return t;
171 /* Only done the first time */
172 void
173 slang_init (void)
175 struct sigaction act, oact;
177 SLtt_get_terminfo ();
180 * If the terminal in not in terminfo but begins with a well-known
181 * string such as "linux" or "xterm" S-Lang will go on, but the
182 * terminal size and several other variables won't be initialized
183 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
184 * small, large and negative screen dimensions.
186 if ((COLS < 10) || (LINES < 5) || (COLS > 255) || (LINES > 255)) {
187 fprintf (stderr,
188 _("Screen size %dx%d is not supported.\n"
189 "Check the TERM environment variable.\n"),
190 COLS, LINES);
191 exit (1);
194 tcgetattr (fileno (stdin), &boot_mode);
195 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
196 SLang_init_tty (XCTRL('c'), 1, 0);
198 /* If SLang uses fileno(stderr) for terminal input MC will hang
199 if we call SLang_getkey between calls to open_error_pipe and
200 close_error_pipe, e.g. when we do a growing view of an gzipped
201 file. */
202 if (SLang_TT_Read_FD == fileno (stderr))
203 SLang_TT_Read_FD = fileno (stdin);
205 if (force_ugly_line_drawing)
206 SLtt_Has_Alt_Charset = 0;
207 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
208 #ifdef VDSUSP
209 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
210 #endif
211 #ifdef VLNEXT
212 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
213 #endif
214 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
216 slang_prog_mode ();
217 load_terminfo_keys ();
218 act.sa_handler = slang_intr;
219 sigemptyset (&act.sa_mask);
220 act.sa_flags = SA_RESTART;
221 sigaction (SIGINT, &act, &oact);
222 SLtt_Blink_Mode = 0;
225 void
226 slang_set_raw_mode (void)
228 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
231 /* Done each time we come back from done mode */
232 void
233 slang_prog_mode (void)
235 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
236 SLsmg_init_smg ();
237 SLsmg_touch_lines (0, LINES);
240 /* Called each time we want to shutdown slang screen manager */
241 void
242 slang_shell_mode (void)
244 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
247 void
248 slang_shutdown (void)
250 char *op_cap;
252 slang_shell_mode ();
253 do_exit_ca_mode ();
254 SLang_reset_tty ();
256 /* Load the op capability to reset the colors to those that were
257 * active when the program was started up
259 op_cap = SLtt_tgetstr ("op");
260 if (op_cap){
261 fprintf (stdout, "%s", op_cap);
262 fflush (stdout);
266 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
267 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
268 consequence is that function keys don't work in MC sometimes.
269 Unfortunately I don't now the one and only escape sequence to turn off
270 softkeys (elm uses three different capabilities to turn on softkeys and two
271 capabilities to turn them off).
272 Among other things elm uses the pair we already use in slang_keypad. That's
273 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
274 something better the softkeys are programmed to their defaults from the
275 termcap/terminfo database.
276 The escape sequence to program the softkeys is taken from elm and it is
277 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this
278 sequence. -- Norbert
281 static void
282 slang_reset_softkeys (void)
284 int key;
285 char *send;
286 static const char display[] = " ";
287 char tmp[BUF_SMALL];
289 for (key = 1; key < 9; key++) {
290 g_snprintf (tmp, sizeof (tmp), "k%d", key);
291 send = (char *) SLtt_tgetstr (tmp);
292 if (send) {
293 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
294 (int) (sizeof (display) - 1), (int) strlen (send),
295 display, send);
296 SLtt_write_string (tmp);
301 /* keypad routines */
302 void
303 slang_keypad (int set)
305 char *keypad_string;
306 extern int reset_hp_softkeys;
308 keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
309 if (keypad_string)
310 SLtt_write_string (keypad_string);
311 if (set && reset_hp_softkeys)
312 slang_reset_softkeys ();
315 void
316 set_slang_delay (int v)
318 no_slang_delay = v;
321 void
322 hline (int ch, int len)
324 int last_x, last_y;
326 last_x = SLsmg_get_column ();
327 last_y = SLsmg_get_row ();
329 if (ch == 0)
330 ch = ACS_HLINE;
332 if (ch == ACS_HLINE){
333 SLsmg_draw_hline (len);
334 } else {
335 while (len--)
336 addch (ch);
338 move (last_y, last_x);
341 void
342 vline (int character, int len)
344 if (!slow_terminal){
345 SLsmg_draw_vline (len);
346 } else {
347 int last_x, last_y, pos = 0;
349 last_x = SLsmg_get_column ();
350 last_y = SLsmg_get_row ();
352 while (len--){
353 move (last_y + pos++, last_x);
354 addch (' ');
356 move (last_x, last_y);
360 int has_colors (void)
362 char *terminal = getenv ("TERM");
363 char *cts = color_terminal_string, *s;
364 size_t i;
366 if (force_colors)
367 SLtt_Use_Ansi_Colors = 1;
368 if (NULL != getenv ("COLORTERM"))
369 SLtt_Use_Ansi_Colors = 1;
371 /* We want to allow overwriding */
372 if (!disable_colors){
373 /* check color_terminal_string */
374 if (*cts)
376 while (*cts)
378 while (*cts == ' ' || *cts == '\t') cts++;
380 s = cts;
381 i = 0;
383 while (*cts && *cts != ',')
385 cts++;
386 i++;
388 if (i && i == strlen(terminal) && strncmp(s, terminal, i) == 0)
389 SLtt_Use_Ansi_Colors = 1;
391 if (*cts == ',') cts++;
396 /* Setup emulated colors */
397 if (SLtt_Use_Ansi_Colors){
398 if (use_colors){
399 mc_init_pair (A_REVERSE, "black", "white");
400 mc_init_pair (A_BOLD, "white", "black");
401 } else {
402 mc_init_pair (A_REVERSE, "black", "lightgray");
403 mc_init_pair (A_BOLD, "white", "black");
404 mc_init_pair (A_BOLD_REVERSE, "white", "lightgray");
406 } else {
407 SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
408 SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
409 SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
411 return SLtt_Use_Ansi_Colors;
414 void
415 attrset (int color)
417 if (!SLtt_Use_Ansi_Colors){
418 SLsmg_set_color (color);
419 return;
422 if (color & A_BOLD){
423 if (color == A_BOLD)
424 SLsmg_set_color (A_BOLD);
425 else
426 SLsmg_set_color ((color & (~A_BOLD)) + 8);
427 return;
430 if (color == A_REVERSE)
431 SLsmg_set_color (A_REVERSE);
432 else
433 SLsmg_set_color (color);
436 /* This table describes which capabilities we want and which values we
437 * assign to them.
439 static const struct {
440 int key_code;
441 char *key_name;
442 } key_table [] = {
443 { KEY_F(0), "k0" },
444 { KEY_F(1), "k1" },
445 { KEY_F(2), "k2" },
446 { KEY_F(3), "k3" },
447 { KEY_F(4), "k4" },
448 { KEY_F(5), "k5" },
449 { KEY_F(6), "k6" },
450 { KEY_F(7), "k7" },
451 { KEY_F(8), "k8" },
452 { KEY_F(9), "k9" },
453 { KEY_F(10), "k;" },
454 { KEY_F(11), "F1" },
455 { KEY_F(12), "F2" },
456 { KEY_F(13), "F3" },
457 { KEY_F(14), "F4" },
458 { KEY_F(15), "F5" },
459 { KEY_F(16), "F6" },
460 { KEY_F(17), "F7" },
461 { KEY_F(18), "F8" },
462 { KEY_F(19), "F9" },
463 { KEY_F(20), "FA" },
464 { KEY_IC, "kI" },
465 { KEY_NPAGE, "kN" },
466 { KEY_PPAGE, "kP" },
467 { KEY_LEFT, "kl" },
468 { KEY_RIGHT, "kr" },
469 { KEY_UP, "ku" },
470 { KEY_DOWN, "kd" },
471 { KEY_DC, "kD" },
472 { KEY_BACKSPACE, "kb" },
473 { KEY_HOME, "kh" },
474 { KEY_END, "@7" },
475 { 0, 0}
478 static void
479 do_define_key (int code, char *strcap)
481 char *seq;
483 seq = (char *) SLtt_tgetstr (strcap);
484 if (seq)
485 define_sequence (code, seq, MCKEY_NOACTION);
488 static void
489 load_terminfo_keys (void)
491 int i;
493 for (i = 0; key_table [i].key_code; i++)
494 do_define_key (key_table [i].key_code, key_table [i].key_name);
498 getch (void)
500 int c;
501 if (no_slang_delay)
502 if (SLang_input_pending2 (0) == 0)
503 return -1;
505 c = SLang_getkey2 ();
506 if (c == SLANG_GETKEY_ERROR) {
507 fprintf (stderr,
508 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
509 "Assuming EOF on stdin and exiting\n");
510 exit (1);
512 return c;
515 #else
517 /* Non slang builds do not understand got_interrupt */
518 int got_interrupt (void)
520 return 0;
522 #endif /* HAVE_SLANG */
524 void
525 mc_refresh (void)
527 #ifdef WITH_BACKGROUND
528 if (!we_are_background)
529 #endif /* WITH_BACKGROUND */
530 refresh ();