1 /* Features which vary with the OS */
9 #include <io.h> /* For win32 && set_bin(). */
15 #ifdef HAVE_SYS_IOCTL_H
16 #include <sys/ioctl.h>
18 #ifdef HAVE_SYS_SIGNAL_H
19 #include <sys/signal.h>
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 #include <sys/socket.h> /* Need to be after sys/types.h */
26 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
29 /* We need to have it here. Stupid BSD. */
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
37 /* This is for some exotic TOS mangling when handling passive FTP sockets. */
38 #ifdef HAVE_NETINET_IN_SYSTM_H
39 #include <netinet/in_systm.h>
41 #ifdef HAVE_NETINET_IN_SYSTEM_H
42 #include <netinet/in_system.h>
45 #ifdef HAVE_NETINET_IP_H
46 #include <netinet/ip.h>
58 /* For the sake of SunOS, keep this away from files including
59 * intl/gettext/libintl.h because <locale.h> includes system <libintl.h> which
60 * either includes system gettext header or contains gettext function
67 #include <X11/Xutil.h>
73 #include "main/select.h"
74 #include "osdep/osdep.h"
75 #include "osdep/signals.h"
76 #include "terminal/terminal.h"
77 #include "util/conv.h"
78 #include "util/memory.h"
79 #include "util/string.h"
82 /* Set a file descriptor to non-blocking mode. It returns a non-zero value
85 set_nonblocking_fd(int fd
)
87 #if defined(O_NONBLOCK) || defined(O_NDELAY)
88 int flags
= fcntl(fd
, F_GETFL
, 0);
90 if (flags
< 0) return -1;
91 #if defined(O_NONBLOCK)
92 return fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
94 return fcntl(fd
, F_SETFL
, flags
| O_NDELAY
);
97 #elif defined(FIONBIO)
100 return ioctl(fd
, FIONBIO
, &flag
);
106 /* Set a file descriptor to blocking mode. It returns a non-zero value on
109 set_blocking_fd(int fd
)
111 #if defined(O_NONBLOCK) || defined(O_NDELAY)
112 int flags
= fcntl(fd
, F_GETFL
, 0);
114 if (flags
< 0) return -1;
115 #if defined(O_NONBLOCK)
116 return fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
);
118 return fcntl(fd
, F_SETFL
, flags
& ~O_NDELAY
);
121 #elif defined(FIONBIO)
124 return ioctl(fd
, FIONBIO
, &flag
);
131 set_ip_tos_throughput(int socket
)
133 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
134 int on
= IPTOS_THROUGHPUT
;
136 setsockopt(socket
, IPPROTO_IP
, IP_TOS
, (char *) &on
, sizeof(on
));
141 get_e(unsigned char *env
)
143 char *v
= getenv(env
);
145 return (v
? atoi(v
) : 0);
155 buf
= mem_alloc(bufsize
);
156 if (!buf
) return NULL
;
157 if (getcwd(buf
, bufsize
)) return buf
;
160 if (errno
== EINTR
) continue;
161 if (errno
!= ERANGE
) return NULL
;
169 set_cwd(unsigned char *path
)
171 if (path
) while (chdir(path
) && errno
== EINTR
);
177 unsigned char *shell
= GETSHELL
;
179 if (!shell
|| !*shell
)
180 shell
= DEFAULT_SHELL
;
188 #if !defined(CONFIG_OS_OS2) && !defined(CONFIG_OS_WIN32)
193 ((void (*)(void)) s
)();
197 handle_terminal_resize(int fd
, void (*fn
)(void))
199 install_signal_handler(SIGWINCH
, sigwinch
, fn
, 0);
203 unhandle_terminal_resize(int fd
)
205 install_signal_handler(SIGWINCH
, NULL
, NULL
, 0);
209 get_terminal_size(int fd
, int *x
, int *y
)
213 if (ioctl(1, TIOCGWINSZ
, &ws
) != -1) {
222 *x
= get_e("COLUMNS");
223 if (!*x
) *x
= DEFAULT_TERMINAL_WIDTH
;
227 if (!*y
) *y
= DEFAULT_TERMINAL_HEIGHT
;
235 #if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_BEOS) || defined(CONFIG_OS_RISCOS)
248 #elif defined(CONFIG_OS_OS2) || defined(CONFIG_OS_WIN32)
253 setmode(fd
, O_BINARY
);
274 is_twterm(void) /* Check if it make sense to call a twterm. */
278 if (tw
== -1) tw
= !!getenv("TWDISPLAY");
286 static int screen
= -1;
288 if (screen
== -1) screen
= !!getenv("STY");
294 #if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_WIN32)
302 /* Paraphrased from debian bug 228977:
304 * It is not enough to simply check the DISPLAY env variable,
305 * as it is pretty legal to have a DISPLAY set. While these
306 * days this practice is pretty uncommon, it still makes sense
307 * sometimes, especially for people who prefer the text mode
308 * for some reason. Only relying on DISPLAY will results in bad
309 * codes being written to the terminal.
311 * Any real xterm derivative sets WINDOWID as well.
312 * Unfortunately, konsole is an exception, and it needs to be
313 * checked for separately.
315 * FIXME: The code below still fails to detect some terminals
316 * that do support a title (like the popular PuTTY ssh client).
317 * In general, proper xterm detection is a nightmarish task...
319 * -- Adam Borowski <kilobyte@mimuw.edu.pl> */
320 unsigned char *display
= getenv("DISPLAY");
321 unsigned char *windowid
= getenv("WINDOWID");
323 if (!windowid
|| !*windowid
)
324 windowid
= getenv("KONSOLE_DCOP_SESSION");
325 xt
= (display
&& *display
&& windowid
&& *windowid
);
333 unsigned int resize_count
= 0;
335 #ifndef CONFIG_OS_OS2
337 #if !(defined(CONFIG_OS_BEOS) && defined(HAVE_SETPGID)) && !defined(CONFIG_OS_WIN32)
340 exe(unsigned char *path
)
347 static unsigned char *clipboard
;
350 get_clipboard_text(void)
352 /* The following support for GNU Screen's clipboard is
353 * disabled for two reasons:
355 * 1. It does not actually return the string from that
356 * clipboard, but rather causes the clipboard contents to
357 * appear in stdin. get_clipboard_text is normally called
358 * because the user pressed a Paste key in an input field,
359 * so the characters end up being inserted in that field;
360 * but if there are newlines in the clipboard, then the
361 * field may lose focus, in which case the remaining
362 * characters may trigger arbitrary actions in ELinks.
364 * 2. It pastes from both GNU Screen's clipboard and the ELinks
365 * internal clipboard. Because set_clipboard_text also sets
366 * them both, the same text would typically get pasted twice.
368 * Users can instead use the GNU Screen key bindings to run the
369 * paste command. This method still suffers from problem 1 but
370 * any user of GNU Screen should know that already. */
372 /* GNU Screen's clipboard */
373 if (is_gnuscreen()) {
376 if (!init_string(&str
)) return NULL
;
378 add_to_string(&str
, "screen -X paste .");
379 if (str
.length
) exe(str
.source
);
380 if (str
.source
) done_string(&str
);
384 return stracpy(empty_string_or_(clipboard
));
388 set_clipboard_text(unsigned char *data
)
390 /* GNU Screen's clipboard */
391 if (is_gnuscreen()) {
394 if (!init_string(&str
)) return;
396 add_to_string(&str
, "screen -X register . ");
397 add_shell_quoted_to_string(&str
, data
, strlen(data
));
399 if (str
.length
) exe(str
.source
);
400 if (str
.source
) done_string(&str
);
403 /* Shouldn't complain about leaks. */
404 if (clipboard
) free(clipboard
);
405 clipboard
= strdup(data
);
408 /* Set xterm-like term window's title. */
410 set_window_title(unsigned char *title
, int codepage
)
412 struct string filtered
;
414 #ifndef HAVE_SYS_CYGWIN_H
415 /* Check if we're in a xterm-like terminal. */
416 if (!is_xterm()) return;
419 if (!init_string(&filtered
)) return;
421 /* Copy title to filtered if different from NULL */
423 unsigned char *scan
= title
;
424 unsigned char *end
= title
+ strlen(title
);
426 /* Remove control characters, so that they cannot
427 * interfere with the command we send to the terminal.
428 * However, do not attempt to limit the title length
429 * to terminal width, because the title is usually
430 * drawn in a different font anyway. */
431 /* Note that this is the right place where to do it, since
432 * potential alternative set_window_title() routines might
433 * want to take different precautions. */
435 unsigned char *charbegin
= scan
;
436 unicode_val_T unicode
437 = cp_to_unicode(codepage
, &scan
, end
);
438 int charlen
= scan
- charbegin
;
440 if (unicode
== UCS_NO_CHAR
)
443 /* This need not recognize all Unicode control
444 * characters. Only those that can make the
445 * terminal misparse the command. */
447 || (unicode
>= 0x7F && unicode
< 0xA0))
450 /* If the title is getting too long, truncate
451 * it and add an ellipsis.
453 * xterm entirely rejects 1024-byte or longer
454 * titles. GNU Screen 4.00.03 misparses
455 * titles longer than 765 bytes, and is unable
456 * to display the title in hardstatus if the
457 * title and other stuff together exceed 766
458 * bytes. So set the limit quite a bit lower. */
459 if (filtered
.length
+ charlen
>= 600 - 3) {
460 add_to_string(&filtered
, "...");
464 add_bytes_to_string(&filtered
, charbegin
, charlen
);
468 /* Send terminal escape sequence + title string */
469 printf("\033]0;%s\a", filtered
.source
);
472 /* Miciah don't like this so it is disabled because it changes the
473 * default window name. --jonas */
474 /* Set the GNU screen window name */
476 printf("\033k%s\033\134", filtered
.source
);
481 done_string(&filtered
);
485 static int x_error
= 0;
494 /** Convert a STRING XTextProperty to a string in the specified codepage.
496 * @return the string that the caller must free with mem_free(),
497 * or NULL on error. */
498 static unsigned char *
499 xprop_to_string(Display
*display
, const XTextProperty
*text_prop
, int to_cp
)
504 struct conv_table
*convert_table
;
505 unsigned char *ret
= NULL
;
507 /* <X11/Xlib.h> defines X_HAVE_UTF8_STRING if
508 * Xutf8TextPropertyToTextList is available.
510 * The X...TextPropertyToTextList functions return a negative
511 * error code, or Success=0, or the number of unconvertible
512 * characters. Use the result even if some characters were
513 * unconvertible, because convert_string() can be lossy too,
514 * and it seems better to restore an approximation of the
515 * original title than to restore a default title that may be
516 * entirely different. */
517 #if defined(CONFIG_UTF8) && defined(X_HAVE_UTF8_STRING)
519 from_cp
= get_cp_index("UTF-8");
520 if (Xutf8TextPropertyToTextList(display
, text_prop
, &list
,
524 #else /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */
526 from_cp
= get_cp_index("System");
527 if (XmbTextPropertyToTextList(display
, text_prop
, &list
,
531 #endif /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */
533 convert_table
= get_translation_table(from_cp
, to_cp
);
534 if (count
>= 1 && convert_table
)
535 ret
= convert_string(convert_table
, list
[0], strlen(list
[0]),
536 to_cp
, CSM_NONE
, NULL
, NULL
, NULL
);
538 XFreeStringList(list
);
541 #endif /* HAVE_X11 */
544 get_window_title(int codepage
)
547 /* Following code is stolen from our beloved vim. */
548 unsigned char *winid
;
550 Window window
, root
, parent
, *children
;
551 XTextProperty text_prop
;
553 unsigned int num_children
;
554 unsigned char *ret
= NULL
;
559 winid
= getenv("WINDOWID");
562 window
= (Window
) atol(winid
);
566 display
= XOpenDisplay(NULL
);
570 /* If WINDOWID is bad, we don't want X to abort us. */
572 XSetErrorHandler((int (*)(Display
*, XErrorEvent
*)) catch_x_error
);
574 status
= XGetWMName(display
, window
, &text_prop
);
575 /* status = XGetWMIconName(x11_display, x11_window, &text_prop); */
576 while (!x_error
&& (!status
|| !text_prop
.value
)) {
577 if (!XQueryTree(display
, window
, &root
, &parent
, &children
, &num_children
))
580 XFree((void *) children
);
581 if (parent
== root
|| parent
== 0)
584 status
= XGetWMName(display
, window
, &text_prop
);
587 if (!x_error
&& status
&& text_prop
.value
) {
588 ret
= xprop_to_string(display
, &text_prop
, codepage
);
589 XFree(text_prop
.value
);
592 XCloseDisplay(display
);
596 /* At least reset the window title to a blank one. */
602 resize_window(int width
, int height
, int old_width
, int old_height
)
605 /* Following code is stolen from our beloved vim. */
606 unsigned char *winid
;
610 XWindowAttributes attributes
;
615 winid
= getenv("WINDOWID");
618 window
= (Window
) atol(winid
);
622 display
= XOpenDisplay(NULL
);
626 /* If WINDOWID is bad, we don't want X to abort us. */
628 XSetErrorHandler((int (*)(Display
*, XErrorEvent
*)) catch_x_error
);
630 status
= XGetWindowAttributes(display
, window
, &attributes
);
632 while (!x_error
&& !status
) {
633 Window root
, parent
, *children
;
634 unsigned int num_children
;
636 if (!XQueryTree(display
, window
, &root
, &parent
, &children
, &num_children
))
639 XFree((void *) children
);
640 if (parent
== root
|| parent
== 0)
643 status
= XGetWindowAttributes(display
, window
, &attributes
);
646 if (!x_error
&& status
) {
647 XSizeHints
*size_hints
;
652 /* With xterm 210, a window with 80x24 characters at
653 * a 6x13 font appears to have 484x316 pixels; both
654 * the width and height include four extra pixels.
655 * Computing a new size by scaling these values often
656 * results in windows that cannot display as many
657 * characters as was intended. We can do better if we
658 * can find out the actual size of character cells.
659 * If the terminal emulator has set a window size
660 * increment, assume that is the cell size. */
661 size_hints
= XAllocSizeHints();
662 if (size_hints
!= NULL
663 && XGetWMNormalHints(display
, window
, size_hints
, &mask
)
664 && (mask
& PResizeInc
) != 0) {
665 px_width
= attributes
.width
666 + (width
- old_width
) * size_hints
->width_inc
;
667 px_height
= attributes
.height
668 + (height
- old_height
) * size_hints
->height_inc
;
670 if (px_width
<= 0 || px_height
<= 0) {
671 double ratio_width
= (double) attributes
.width
/ old_width
;
672 double ratio_height
= (double) attributes
.height
/ old_height
;
674 px_width
= (int) ((double) width
* ratio_width
);
675 px_height
= (int) ((double) height
* ratio_height
);
681 status
= XResizeWindow(display
, window
, px_width
, px_height
);
682 while (!x_error
&& !status
) {
683 Window root
, parent
, *children
;
684 unsigned int num_children
;
686 if (!XQueryTree(display
, window
, &root
, &parent
, &children
, &num_children
))
689 XFree((void *) children
);
690 if (parent
== root
|| parent
== 0)
693 status
= XResizeWindow(display
, window
, px_width
, px_height
);
697 XCloseDisplay(display
);
710 #if defined(HAVE_BEGINTHREAD) || defined(CONFIG_OS_BEOS)
713 void (*fn
)(void *, int);
715 unsigned char data
[1];
722 signal(SIGPIPE
, SIG_IGN
);
724 t
->fn(t
->data
, t
->h
);
733 start_thread(void (*fn
)(void *, int), void *ptr
, int l
)
738 if (c_pipe(p
) < 0) return -1;
739 if (set_nonblocking_fd(p
[0]) < 0) return -1;
740 if (set_nonblocking_fd(p
[1]) < 0) return -1;
744 struct terminal
*term
;
746 /* Close input in this thread; otherwise, if it will live
747 * longer than its parent, it'll block the terminal until it'll
748 * quit as well; this way it will hopefully just die unseen and
749 * in background, causing no trouble. */
750 /* Particularly, when async dns resolving was in progress and
751 * someone quitted ELinks, it could make a delay before the
752 * terminal would be really freed and returned to shell. */
753 foreach (term
, terminals
)
761 /* We use _exit() here instead of exit(), see
762 * http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC6 for
763 * reasons. Fixed by Sven Neumann <sven@convergence.de>. */
792 #if !defined(CONFIG_OS_WIN32)
794 get_output_handle(void)
804 if (isatty(0)) return 0;
805 if (fd
< 0) fd
= open("/dev/tty", O_RDONLY
);
811 #if !defined(CONFIG_OS_BEOS) && !(defined(HAVE_BEGINTHREAD) && defined(HAVE_READ_KBD)) \
812 && !defined(CONFIG_OS_WIN32)
815 get_input_handle(void)
817 return get_ctl_handle();
822 #ifndef CONFIG_OS_WIN32
828 setlocale(LC_ALL
, "");
834 #if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_OS2) || defined(CONFIG_OS_RISCOS)
837 terminate_osdep(void)
843 #ifndef CONFIG_OS_BEOS
859 elinks_cfmakeraw(struct termios
*t
)
861 /* This elinks_cfmakeraw() intentionally leaves the following
862 * settings unchanged, even though the standard cfmakeraw()
863 * would change some of them:
865 * - c_cflag & CSIZE: number of bits per character.
866 * Bug 54 asked ELinks not to change this.
867 * - c_cflag & (PARENB | PARODD): parity bit in characters.
868 * Bug 54 asked ELinks not to change this.
869 * - c_iflag & (IXON | IXOFF | IXANY): XON/XOFF flow control.
871 * The reasoning is, if the user has set up unusual values for
872 * those settings before starting ELinks, then the terminal
873 * probably expects those values and ELinks should not mess
875 t
->c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
|INLCR
|IGNCR
|ICRNL
);
876 t
->c_oflag
&= ~OPOST
;
877 t
->c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|ISIG
|IEXTEN
);
882 #if !defined(CONFIG_MOUSE) || (!defined(CONFIG_GPM) && !defined(CONFIG_SYSMOUSE) && !defined(OS2_MOUSE))
885 handle_mouse(int cons
, void (*fn
)(void *, unsigned char *, int),
892 unhandle_mouse(void *data
)
897 suspend_mouse(void *data
)
902 resume_mouse(void *data
)
908 #ifndef CONFIG_OS_WIN32
909 /* Create a bitmask consisting from system-independent envirnoment modifiers.
910 * This is then complemented by system-specific modifiers in an appropriate
911 * get_system_env() routine. */
917 if (is_xterm()) env
|= ENV_XWIN
;
918 if (is_twterm()) env
|= ENV_TWIN
;
919 if (is_gnuscreen()) env
|= ENV_SCREEN
;
921 /* ENV_CONSOLE is always set now and indicates that we are working w/ a
922 * displaying-capable character-adressed terminal. Sounds purely
923 * theoretically now, but it already makes some things easier and it
924 * could give us interesting opportunities later (after graphical
925 * frontends will be introduced, when working in some mysterious daemon
926 * mode or who knows what ;). --pasky */
933 #if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_RISCOS)
937 return get_common_env();
943 can_resize_window(int environment
)
945 return !!(environment
& (ENV_OS2VIO
| ENV_XWIN
));
948 #ifndef CONFIG_OS_OS2
950 can_open_os_shell(int environment
)
963 get_system_str(int xwin
)
965 return xwin
? SYSTEM_STR
"-xwin" : SYSTEM_STR
;