1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00
elinks/src/osdep/osdep.c

1149 lines
23 KiB
C
Raw Normal View History

/* Features which vary with the OS */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#ifdef HAVE_IO_H
#include <io.h> /* For win32 && set_bin(). */
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> /* Need to be after sys/types.h */
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
#endif
/* We need to have it here. Stupid BSD. */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
/* This is for some exotic TOS mangling when handling passive FTP sockets. */
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#else
#ifdef HAVE_NETINET_IN_SYSTEM_H
#include <netinet/in_system.h>
#endif
#endif
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <locale.h>
#ifdef HAVE_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#endif
#include "elinks.h"
#include "config/options.h"
#include "main/select.h"
#include "osdep/osdep.h"
#include "osdep/signals.h"
#include "session/session.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/file.h"
#include "util/memory.h"
#include "util/string.h"
#ifndef CONFIG_OS_DOS
/* Set a file descriptor to non-blocking mode. It returns a non-zero value
* on error. */
int
set_nonblocking_fd(int fd)
{
2022-05-01 09:07:51 -04:00
#ifdef WIN32
2022-05-01 10:23:31 -04:00
if (fd > 1024) {
u_long mode = 1; // set socket non-blocking
ioctlsocket(fd, FIONBIO, &mode);
return 0;
}
# endif
#if defined(O_NONBLOCK) || defined(O_NDELAY)
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return -1;
#if defined(O_NONBLOCK)
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
return fcntl(fd, F_SETFL, flags | O_NDELAY);
#endif
#elif defined(FIONBIO)
int flag = 1;
return ioctl(fd, FIONBIO, &flag);
#else
return 0;
#endif
}
#endif
/* Set a file descriptor to blocking mode. It returns a non-zero value on
* error. */
int
set_blocking_fd(int fd)
{
2022-05-01 09:07:51 -04:00
#ifdef WIN32
2022-05-01 10:23:31 -04:00
if (fd > 1024) {
u_long mode = 0; // set socket blocking
ioctlsocket(fd, FIONBIO, &mode);
return 0;
}
# endif
#if defined(O_NONBLOCK) || defined(O_NDELAY)
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return -1;
#if defined(O_NONBLOCK)
return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
#else
return fcntl(fd, F_SETFL, flags & ~O_NDELAY);
#endif
#elif defined(FIONBIO)
int flag = 0;
return ioctl(fd, FIONBIO, &flag);
#else
return 0;
#endif
}
void
set_ip_tos_throughput(int socket)
{
#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
int on = IPTOS_THROUGHPUT;
setsockopt(socket, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(on));
#endif
}
int
2022-02-17 15:28:45 -05:00
get_e(const char *env)
{
char *v = getenv(env);
return (v ? atoi(v) : 0);
}
char *
get_cwd(void)
{
int bufsize = 128;
char *buf;
while (1) {
2022-01-16 13:09:27 -05:00
buf = (char *)mem_alloc(bufsize);
if (!buf) return NULL;
if (getcwd(buf, bufsize)) return buf;
mem_free(buf);
if (errno == EINTR) continue;
if (errno != ERANGE) return NULL;
bufsize += 128;
}
return NULL;
}
void
set_cwd(char *path)
{
if (path) while (chdir(path) && errno == EINTR);
}
2022-02-20 07:52:47 -05:00
const char *
get_shell(void)
{
2022-02-20 07:52:47 -05:00
const char *shell = GETSHELL;
if (!shell || !*shell)
shell = DEFAULT_SHELL;
return shell;
}
/* Terminal size */
#if !defined(CONFIG_OS_OS2) && !defined(CONFIG_OS_WIN32) && !defined(CONFIG_OS_DOS)
static void
sigwinch(void *s)
{
((void (*)(void)) s)();
}
void
handle_terminal_resize(int fd, void (*fn)(void))
{
2022-02-21 10:38:36 -05:00
install_signal_handler(SIGWINCH, sigwinch, (void *)fn, 0);
}
void
unhandle_terminal_resize(int fd)
{
install_signal_handler(SIGWINCH, NULL, NULL, 0);
}
void
get_terminal_size(int fd, int *x, int *y)
{
struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
*x = ws.ws_col;
*y = ws.ws_row;
} else {
*x = 0;
*y = 0;
}
if (!*x) {
*x = get_e("COLUMNS");
if (!*x) *x = DEFAULT_TERMINAL_WIDTH;
}
if (!*y) {
*y = get_e("LINES");
if (!*y) *y = DEFAULT_TERMINAL_HEIGHT;
}
}
#endif
/* Pipe */
2006-01-11 14:12:59 -05:00
#if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_BEOS) || defined(CONFIG_OS_RISCOS)
void
set_bin(int fd)
{
}
int
c_pipe(int *fd)
{
return pipe(fd);
}
#elif defined(CONFIG_OS_OS2) || defined(CONFIG_OS_WIN32) || defined(CONFIG_OS_DOS)
void
set_bin(int fd)
{
setmode(fd, O_BINARY);
}
int
c_pipe(int *fd)
{
int r = pipe(fd);
if (!r) {
set_bin(fd[0]);
set_bin(fd[1]);
}
return r;
}
#endif
/* Exec */
int
is_twterm(void) /* Check if it make sense to call a twterm. */
{
static int tw = -1;
if (tw == -1) tw = !!getenv("TWDISPLAY");
return tw;
}
int
is_gnuscreen(void)
{
static int screen = -1;
if (screen == -1) screen = !!getenv("STY");
return screen;
}
2006-01-11 14:10:27 -05:00
#if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_WIN32)
static int
check_more_envs(void)
{
2022-02-17 13:51:11 -05:00
const char *envs[] = { "WINDOWID",
"KONSOLE_DCOP_SESSION",
"GNOME_TERMINAL_SERVICE",
NULL
};
2022-02-17 13:51:11 -05:00
const char **v;
for (v = envs; *v; ++v)
{
char *value = getenv(*v);
if (value && *value) {
return 1;
}
}
return 0;
}
int
is_xterm(void)
{
static int xt = -1;
if (xt == -1) {
/* Paraphrased from debian bug 228977:
*
* It is not enough to simply check the DISPLAY env variable,
* as it is pretty legal to have a DISPLAY set. While these
* days this practice is pretty uncommon, it still makes sense
* sometimes, especially for people who prefer the text mode
* for some reason. Only relying on DISPLAY will results in bad
* codes being written to the terminal.
*
* Any real xterm derivative sets WINDOWID as well.
* Unfortunately, konsole is an exception, and it needs to be
* checked for separately.
*
* FIXME: The code below still fails to detect some terminals
* that do support a title (like the popular PuTTY ssh client).
* In general, proper xterm detection is a nightmarish task...
*
* -- Adam Borowski <kilobyte@mimuw.edu.pl> */
char *display = getenv("DISPLAY");
xt = (display && *display && check_more_envs());
}
return xt;
}
#endif
unsigned int resize_count = 0;
2006-01-11 14:10:26 -05:00
#ifndef CONFIG_OS_OS2
2006-01-11 14:12:59 -05:00
#if !(defined(CONFIG_OS_BEOS) && defined(HAVE_SETPGID)) && !defined(CONFIG_OS_WIN32)
int
exe(char *path)
{
return system(path);
}
#endif
int
exe_no_stdin(char *path) {
int ret;
2022-04-22 15:47:52 -04:00
#ifndef WIN32
#if defined(F_GETFD) && defined(FD_CLOEXEC)
int flags;
flags = fcntl(STDIN_FILENO, F_GETFD);
fcntl(STDIN_FILENO, F_SETFD, flags | FD_CLOEXEC);
ret = exe(path);
fcntl(STDIN_FILENO, F_SETFD, flags);
#else
pid_t pid;
pid = fork();
if (pid == 0) {
close(STDIN_FILENO);
exit(exe(path));
}
else if (pid > 0)
waitpid(pid, &ret, 0);
#endif
#endif
return ret;
}
static char *clipboard;
2006-01-06 06:02:51 -05:00
char *
2006-01-06 06:02:51 -05:00
get_clipboard_text(void)
{
/* The following support for GNU Screen's clipboard is
* disabled for two reasons:
*
* 1. It does not actually return the string from that
* clipboard, but rather causes the clipboard contents to
* appear in stdin. get_clipboard_text is normally called
* because the user pressed a Paste key in an input field,
* so the characters end up being inserted in that field;
* but if there are newlines in the clipboard, then the
* field may lose focus, in which case the remaining
* characters may trigger arbitrary actions in ELinks.
*
* 2. It pastes from both GNU Screen's clipboard and the ELinks
* internal clipboard. Because set_clipboard_text also sets
* them both, the same text would typically get pasted twice.
*
* Users can instead use the GNU Screen key bindings to run the
* paste command. This method still suffers from problem 1 but
* any user of GNU Screen should know that already. */
#if 0
/* GNU Screen's clipboard */
if (is_gnuscreen()) {
struct string str;
if (!init_string(&str)) return NULL;
add_to_string(&str, "screen -X paste .");
if (str.length) exe(str.source);
if (str.source) done_string(&str);
}
#endif
return stracpy(empty_string_or_(clipboard));
}
void
set_clipboard_text(char *data)
{
#ifdef HAVE_ACCESS
char *f = get_ui_clipboard_file();
if (f && *f) {
char *filename = expand_tilde(f);
if (filename) {
if (access(filename, W_OK) >= 0) {
FILE *out = fopen(filename, "a");
if (out) {
fputs(data, out);
fclose(out);
}
}
mem_free(filename);
}
}
#endif
/* GNU Screen's clipboard */
if (is_gnuscreen()) {
struct string str;
if (!init_string(&str)) return;
add_to_string(&str, "screen -X register . ");
add_shell_quoted_to_string(&str, data, strlen(data));
if (str.length) exe(str.source);
if (str.source) done_string(&str);
}
/* Shouldn't complain about leaks. */
if (clipboard) free(clipboard);
clipboard = strdup(data);
}
/* Set xterm-like term window's title. */
void
set_window_title(const char *ctitle, int codepage)
{
struct string filtered;
#ifndef HAVE_SYS_CYGWIN_H
/* Check if we're in a xterm-like terminal. */
if (!is_xterm()) return;
#endif
if (!init_string(&filtered)) {
return;
}
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
/* Copy title to filtered if different from NULL */
if (ctitle) {
char *title = stracpy(ctitle);
if (!title) {
done_string(&filtered);
return;
}
char *scan = title;
char *end = title + strlen(title);
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
/* Remove control characters, so that they cannot
* interfere with the command we send to the terminal.
* However, do not attempt to limit the title length
* to terminal width, because the title is usually
* drawn in a different font anyway. */
/* Note that this is the right place where to do it, since
* potential alternative set_window_title() routines might
* want to take different precautions. */
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
for (;;) {
const char *charbegin = scan;
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
unicode_val_T unicode
= cp_to_unicode(codepage, &scan, end);
int charlen = scan - charbegin;
if (unicode == UCS_NO_CHAR)
break;
/* This need not recognize all Unicode control
* characters. Only those that can make the
* terminal misparse the command. */
if (unicode < 0x20
|| (unicode >= 0x7F && unicode < 0xA0))
continue;
/* If the title is getting too long, truncate
* it and add an ellipsis.
*
* xterm entirely rejects 1024-byte or longer
* titles. GNU Screen 4.00.03 misparses
* titles longer than 765 bytes, and is unable
* to display the title in hardstatus if the
* title and other stuff together exceed 766
* bytes. So set the limit quite a bit lower. */
if (filtered.length + charlen >= 600 - 3) {
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
add_to_string(&filtered, "...");
break;
}
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
add_bytes_to_string(&filtered, charbegin, charlen);
}
mem_free(title);
}
/* Send terminal escape sequence + title string */
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
printf("\033]0;%s\a", filtered.source);
#if 0
/* Miciah don't like this so it is disabled because it changes the
* default window name. --jonas */
/* Set the GNU screen window name */
if (is_gnuscreen())
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
printf("\033k%s\033\134", filtered.source);
#endif
fflush(stdout);
Bug 885: Proper charset support in xterm window title When ELinks runs in an X11 terminal emulator (e.g. xterm), or in GNU Screen, it tries to update the title of the window to match the title of the current document. To do this, ELinks sends an "OSC 1 ; Pt BEL" sequence to the terminal. Unfortunately, xterm expects the Pt string to be in the ISO-8859-1 charset, making it impossible to display e.g. Cyrillic characters. In xterm patch #210 (2006-03-12) however, there is a menu item and a resource that can make xterm take the Pt string in UTF-8 instead, allowing characters from all around the world. The downside is that ELinks apparently cannot ask xterm whether the setting is on or off; so add a terminal._template_.latin1_title option to ELinks and let the user edit that instead. Complete list of changes: - Add the terminal._template_.latin1_title option. But do not add that to the terminal options window because it's already rather crowded there. - In set_window_title(), take a new codepage argument. Use it to decode the title into Unicode characters, and remove only actual control characters. For example, CP437 has graphical characters in the 0x80...0x9F range, so don't remove those, even though ISO-8859-1 has control characters in the same range. Likewise, don't misinterpret single bytes of UTF-8 characters as control characters. - In set_window_title(), do not truncate the title to the width of the window. The font is likely to be different and proportional anyway. But do truncate before 1024 bytes, an xterm limit. - In struct itrm, add a title_codepage member to remember which charset the master said it was going to use in the terminal window title. Initialize title_codepage in handle_trm(), update it in dispatch_special() if the master sends the new request TERM_FN_TITLE_CODEPAGE, and use it in most set_window_title() calls; but not in the one that sets $TERM as the title, because that string was not received from the master and should consist of ASCII characters only. - In set_terminal_title(), convert the caller-provided title to ISO-8859-1 or UTF-8 if appropriate, and report the codepage to the slave with the new TERM_FN_TITLE_CODEPAGE request. The conversion can run out of memory, so return a success/error flag, rather than void. In display_window_title(), check this result and don't update caches on error. - Add a NEWS entry for all of this.
2008-12-28 20:09:53 -05:00
done_string(&filtered);
}
#ifdef HAVE_X11
static int x_error = 0;
static int
catch_x_error(void)
{
x_error = 1;
return 0;
}
/** Convert a STRING XTextProperty to a string in the specified codepage.
*
* @return the string that the caller must free with mem_free(),
* or NULL on error. */
static char *
xprop_to_string(Display *display, const XTextProperty *text_prop, int to_cp)
{
int from_cp;
char **list = NULL;
int count = 0;
struct conv_table *convert_table;
char *ret = NULL;
/* <X11/Xlib.h> defines X_HAVE_UTF8_STRING if
* Xutf8TextPropertyToTextList is available.
*
* The X...TextPropertyToTextList functions return a negative
* error code, or Success=0, or the number of unconvertible
* characters. Use the result even if some characters were
* unconvertible, because convert_string() can be lossy too,
* and it seems better to restore an approximation of the
* original title than to restore a default title that may be
* entirely different. */
#if defined(CONFIG_UTF8) && defined(X_HAVE_UTF8_STRING)
from_cp = get_cp_index("UTF-8");
if (Xutf8TextPropertyToTextList(display, text_prop, &list,
&count) < 0)
return NULL;
#else /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */
from_cp = get_cp_index("System");
if (XmbTextPropertyToTextList(display, text_prop, &list,
&count) < 0)
return NULL;
#endif /* !defined(X_HAVE_UTF8_STRING) || !defined(CONFIG_UTF8) */
convert_table = get_translation_table(from_cp, to_cp);
if (count >= 1 && convert_table)
ret = convert_string(convert_table, list[0], strlen(list[0]),
to_cp, CSM_NONE, NULL, NULL, NULL);
XFreeStringList(list);
return ret;
}
#endif /* HAVE_X11 */
char *
get_window_title(int codepage)
{
#ifdef HAVE_X11
/* Following code is stolen from our beloved vim. */
char *winid;
Display *display;
Window window, root, parent, *children;
XTextProperty text_prop;
Status status;
unsigned int num_children;
char *ret = NULL;
if (!is_xterm())
return NULL;
winid = getenv("WINDOWID");
if (!winid)
return NULL;
window = (Window) atol(winid);
if (!window)
return NULL;
display = XOpenDisplay(NULL);
if (!display)
return NULL;
/* If WINDOWID is bad, we don't want X to abort us. */
x_error = 0;
XSetErrorHandler((int (*)(Display *, XErrorEvent *)) catch_x_error);
status = XGetWMName(display, window, &text_prop);
/* status = XGetWMIconName(x11_display, x11_window, &text_prop); */
while (!x_error && (!status || !text_prop.value)) {
if (!XQueryTree(display, window, &root, &parent, &children, &num_children))
break;
if (children)
XFree((void *) children);
if (parent == root || parent == 0)
break;
window = parent;
status = XGetWMName(display, window, &text_prop);
}
if (!x_error && status && text_prop.value) {
ret = xprop_to_string(display, &text_prop, codepage);
XFree(text_prop.value);
}
XCloseDisplay(display);
return ret;
#else
/* At least reset the window title to a blank one. */
return stracpy("");
#endif
}
int
resize_window(int width, int height, int old_width, int old_height)
{
#ifdef HAVE_X11
/* Following code is stolen from our beloved vim. */
char *winid;
Display *display;
Window window;
Status status;
XWindowAttributes attributes;
if (!is_xterm())
return -1;
winid = getenv("WINDOWID");
if (!winid)
return -1;
window = (Window) atol(winid);
if (!window)
return -1;
display = XOpenDisplay(NULL);
if (!display)
return -1;
/* If WINDOWID is bad, we don't want X to abort us. */
x_error = 0;
XSetErrorHandler((int (*)(Display *, XErrorEvent *)) catch_x_error);
status = XGetWindowAttributes(display, window, &attributes);
while (!x_error && !status) {
Window root, parent, *children;
unsigned int num_children;
if (!XQueryTree(display, window, &root, &parent, &children, &num_children))
break;
if (children)
XFree((void *) children);
if (parent == root || parent == 0)
break;
window = parent;
status = XGetWindowAttributes(display, window, &attributes);
}
if (!x_error && status) {
XSizeHints *size_hints;
long mask;
int px_width = 0;
int px_height = 0;
/* With xterm 210, a window with 80x24 characters at
* a 6x13 font appears to have 484x316 pixels; both
* the width and height include four extra pixels.
* Computing a new size by scaling these values often
* results in windows that cannot display as many
* characters as was intended. We can do better if we
* can find out the actual size of character cells.
* If the terminal emulator has set a window size
* increment, assume that is the cell size. */
size_hints = XAllocSizeHints();
if (size_hints != NULL
&& XGetWMNormalHints(display, window, size_hints, &mask)
&& (mask & PResizeInc) != 0) {
px_width = attributes.width
+ (width - old_width) * size_hints->width_inc;
px_height = attributes.height
+ (height - old_height) * size_hints->height_inc;
}
if (px_width <= 0 || px_height <= 0) {
double ratio_width = (double) attributes.width / old_width;
double ratio_height = (double) attributes.height / old_height;
px_width = (int) ((double) width * ratio_width);
px_height = (int) ((double) height * ratio_height);
}
if (size_hints)
XFree(size_hints);
status = XResizeWindow(display, window, px_width, px_height);
while (!x_error && !status) {
Window root, parent, *children;
unsigned int num_children;
if (!XQueryTree(display, window, &root, &parent, &children, &num_children))
break;
if (children)
XFree((void *) children);
if (parent == root || parent == 0)
break;
window = parent;
status = XResizeWindow(display, window, px_width, px_height);
}
}
XCloseDisplay(display);
return 0;
#else
return -1;
#endif
}
#endif
/* Threads */
#ifdef CONFIG_OS_DOS
int
start_thread(void (*fn)(void *, int), void *ptr, int l)
{
int p[2];
int rs;
if (c_pipe(p) < 0) return -1;
fn(ptr, p[1]);
EINTRLOOP(rs, close(p[1]));
return p[0];
}
#else
2022-04-22 15:47:52 -04:00
#if defined(HAVE_BEGINTHREAD) || defined(CONFIG_OS_BEOS) || defined(CONFIG_OS_WIN32)
struct tdata {
void (*fn)(void *, int);
int h;
unsigned char data[1];
};
void
bgt(struct tdata *t)
{
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
t->fn(t->data, t->h);
2022-06-25 10:15:12 -04:00
(void)!write(t->h, "x", 1);
close(t->h);
free(t);
}
#else
int
start_thread(void (*fn)(void *, int), void *ptr, int l)
{
int p[2];
pid_t pid;
if (c_pipe(p) < 0) return -1;
if (set_nonblocking_fd(p[0]) < 0) return -1;
if (set_nonblocking_fd(p[1]) < 0) return -1;
pid = fork();
if (!pid) {
struct terminal *term;
/* Close input in this thread; otherwise, if it will live
* longer than its parent, it'll block the terminal until it'll
* quit as well; this way it will hopefully just die unseen and
* in background, causing no trouble. */
/* Particularly, when async dns resolving was in progress and
* someone quitted ELinks, it could make a delay before the
* terminal would be really freed and returned to shell. */
foreach (term, terminals)
if (term->fdin > 0)
close(term->fdin);
close(p[0]);
fn(ptr, p[1]);
2022-06-25 10:15:12 -04:00
(void)!write(p[1], "x", 1);
close(p[1]);
/* We use _exit() here instead of exit(), see
* http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC6 for
* reasons. Fixed by Sven Neumann <sven@convergence.de>. */
_exit(0);
}
if (pid == -1) {
close(p[0]);
close(p[1]);
return -1;
}
close(p[1]);
return p[0];
}
#endif
#endif
#if !defined(OS2_MOUSE) && !defined(CONFIG_OS_DOS)
void
want_draw(void)
{
}
void
done_draw(void)
{
}
#endif
2006-01-11 14:10:27 -05:00
#if !defined(CONFIG_OS_WIN32)
int
get_output_handle(void)
{
return 1;
}
int
get_ctl_handle(void)
{
static int fd = -1;
if (isatty(0)) return 0;
if (fd < 0) fd = open("/dev/tty", O_RDONLY);
return fd;
}
#endif
2006-01-11 14:12:59 -05:00
#if !defined(CONFIG_OS_BEOS) && !(defined(HAVE_BEGINTHREAD) && defined(HAVE_READ_KBD)) \
2006-01-11 14:10:27 -05:00
&& !defined(CONFIG_OS_WIN32)
int
get_input_handle(void)
{
return get_ctl_handle();
}
#endif
#if !defined(CONFIG_OS_WIN32) && !defined(CONFIG_OS_DOS)
void
init_osdep(void)
{
setlocale(LC_ALL, "");
}
#endif
2006-01-11 14:10:27 -05:00
#if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_OS2) || defined(CONFIG_OS_RISCOS)
void
terminate_osdep(void)
{
}
#endif
2006-01-11 14:12:59 -05:00
#ifndef CONFIG_OS_BEOS
void
block_stdin(void)
{
}
void
unblock_stdin(void)
{
}
#endif
void
elinks_cfmakeraw(struct termios *t)
{
/* This elinks_cfmakeraw() intentionally leaves the following
* settings unchanged, even though the standard cfmakeraw()
* would change some of them:
*
* - c_cflag & CSIZE: number of bits per character.
* Bug 54 asked ELinks not to change this.
* - c_cflag & (PARENB | PARODD): parity bit in characters.
* Bug 54 asked ELinks not to change this.
* - c_iflag & (IXON | IXOFF | IXANY): XON/XOFF flow control.
*
* The reasoning is, if the user has set up unusual values for
* those settings before starting ELinks, then the terminal
* probably expects those values and ELinks should not mess
* with them. */
t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
t->c_oflag &= ~OPOST;
t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
t->c_cc[VMIN] = 1;
t->c_cc[VTIME] = 0;
}
#if !defined(CONFIG_MOUSE) || (!defined(CONFIG_GPM) && !defined(CONFIG_SYSMOUSE) && !defined(OS2_MOUSE) && !defined(CONFIG_OS_DOS))
void *
handle_mouse(int cons, void (*fn)(void *, char *, int),
void *data)
{
return NULL;
}
void
unhandle_mouse(void *data)
{
}
void
suspend_mouse(void *data)
{
}
void
resume_mouse(void *data)
{
}
#endif
2022-05-13 11:09:14 -04:00
#if !defined(CONFIG_OS_WIN32) && !defined(CONFIG_OS_DOS)
/* Create a bitmask consisting from system-independent envirnoment modifiers.
* This is then complemented by system-specific modifiers in an appropriate
* get_system_env() routine. */
static int
get_common_env(void)
{
int env = 0;
if (is_xterm()) env |= ENV_XWIN;
if (is_twterm()) env |= ENV_TWIN;
if (is_gnuscreen()) env |= ENV_SCREEN;
/* ENV_CONSOLE is always set now and indicates that we are working w/ a
* displaying-capable character-adressed terminal. Sounds purely
* theoretically now, but it already makes some things easier and it
* could give us interesting opportunities later (after graphical
* frontends will be introduced, when working in some mysterious daemon
* mode or who knows what ;). --pasky */
env |= ENV_CONSOLE;
return env;
}
#endif
2006-01-11 14:10:27 -05:00
#if defined(CONFIG_OS_UNIX) || defined(CONFIG_OS_RISCOS)
int
get_system_env(void)
{
return get_common_env();
}
#endif
int
can_resize_window(int environment)
{
return !!(environment & (ENV_OS2VIO | ENV_XWIN));
}
2006-01-11 14:10:26 -05:00
#ifndef CONFIG_OS_OS2
int
can_open_os_shell(int environment)
{
return 1;
}
void
set_highpri(void)
{
}
#endif
2022-02-21 10:41:48 -05:00
const char *
get_system_str(int xwin)
{
return xwin ? SYSTEM_STR "-xwin" : SYSTEM_STR;
}
#ifdef HAVE_MKSTEMPS
/* tempnam() replacement without races */
2022-02-21 10:49:59 -05:00
static int
isdirectory(const char *path)
{
struct stat ss;
if (path == NULL)
return 0;
if (-1 == stat(path, &ss))
return 0;
return S_ISDIR(ss.st_mode);
}
2022-02-21 10:49:59 -05:00
char *
tempname(const char *dir, const char *pfx, char *suff)
{
struct string path;
char *ret;
int fd;
if (isdirectory(getenv("TMPDIR")))
dir = getenv("TMPDIR");
else if (dir != NULL)
2022-06-22 15:39:59 -04:00
; /* dir = dir */
else if (isdirectory(P_tmpdir))
dir = P_tmpdir;
else if (isdirectory("/tmp"))
dir = "/tmp";
else {
errno = ENOTDIR;
return NULL;
}
if (!init_string(&path)) {
errno = ENOMEM;
return NULL;
}
add_to_string(&path, dir);
add_to_string(&path, "/");
add_to_string(&path, pfx);
add_to_string(&path, "XXXXXX");
if (suff)
add_shell_safe_to_string(&path, suff, strlen(suff));
fd = mkstemps(path.source, suff ? strlen(suff) : 0);
if (fd == -1) {
done_string(&path);
errno = ENOENT;
return NULL;
}
close(fd);
ret = stracpy(path.source);
done_string(&path);
return ret;
}
#else
#warning mkstemps does not exist, using tempnam
2022-05-07 13:34:44 -04:00
char *tempname(const char *dir, const char *pfx, char *suff) {
char *temp, *ret;
struct string name;
temp = tempnam(dir, pfx);
if (temp == NULL)
return NULL;
if (!init_string(&name)) {
free(temp);
return NULL;
}
add_to_string(&name, temp);
free(temp);
add_shell_safe_to_string(&name, suff, strlen(suff));
ret = stracpy(name.source);
done_string(&name);
return ret;
}
#endif