diff options
Diffstat (limited to 'os_dep.c')
-rw-r--r-- | os_dep.c | 2689 |
1 files changed, 2689 insertions, 0 deletions
diff --git a/os_dep.c b/os_dep.c new file mode 100644 index 0000000..791b2c0 --- /dev/null +++ b/os_dep.c @@ -0,0 +1,2689 @@ +/* os_dep.c + * (c) 2002 Mikulas Patocka + * This file is a part of the Links program, released under GPL. + */ + +#include "links.h" + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef USE_GPM +#include <gpm.h> +#endif + + +int is_safe_in_shell(unsigned char c) +{ + return c == '@' || c == '+' || c == '-' || c == '.' || c == ',' || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z'); +} + +int is_safe_in_url(unsigned char c) +{ + return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80; +} + +void check_shell_security(unsigned char **cmd) +{ + unsigned char *c = *cmd; + while (*c) { + if (!is_safe_in_shell(*c)) *c = '_'; + c++; + } +} + +int check_shell_url(unsigned char *url) +{ + while (*url) { + if (!is_safe_in_url(*url)) return -1; + url++; + } + return 0; +} + +unsigned char *escape_path(unsigned char *path) +{ + unsigned char *result; + size_t i; + if (strchr(path, '"')) return stracpy(path); + for (i = 0; path[i]; i++) if (!is_safe_in_url(path[i])) goto do_esc; + return stracpy(path); + do_esc: + result = stracpy("\""); + add_to_strn(&result, path); + add_to_strn(&result, "\""); + return result; +} + +static int get_e(unsigned char *env) +{ + unsigned char *v; + if ((v = getenv(env))) return atoi(v); + return 0; +} + +void ignore_signals(void) +{ + errno = 0; + while (signal(SIGPIPE, SIG_IGN) == SIG_ERR && errno == EINTR) errno = 0; +#ifdef SIGXFSZ + errno = 0; + while (signal(SIGXFSZ, SIG_IGN) == SIG_ERR && errno == EINTR) errno = 0; +#endif +} + +unsigned char *clipboard = NULL; + +#if defined(WIN32) +#include <windows.h> +#endif + +#if defined(OS2) + +#define INCL_MOU +#define INCL_VIO +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#define INCL_DOSMODULEMGR +#define INCL_DOSMISC +#define INCL_WIN +#define INCL_WINCLIPBOARD +#define INCL_WINSWITCHLIST +#include <os2.h> +#include <io.h> +#include <process.h> +#include <sys/video.h> +#ifdef HAVE_SYS_FMUTEX_H +#include <sys/builtin.h> +#include <sys/fmutex.h> +#endif + +#ifdef X2 +/* from xf86sup - XFree86 OS/2 support driver */ +#include <pty.h> +#endif + +#endif + + +#ifdef OS2 + +/* The process crashes if we write to console from high address - so we must + * never do it. + * TCP/IP 4.0 returns EFAULT if we do I/O to/from high address - we test for + * EFAULT and retry with a bounce buffer. */ + +#define BOUNCE_BUFFER_SIZE 256 + +int bounced_read(int fd, void *buf, size_t size) +{ + unsigned char *bounce_buffer; + size_t xsiz; + int r; + if (fd < 3 && (unsigned long)buf + size > 0x20000000) goto bounce; + r = _read(fd, buf, size); + if (r == -1 && errno == EFAULT) goto bounce; + return r; + bounce: + xsiz = size > BOUNCE_BUFFER_SIZE ? BOUNCE_BUFFER_SIZE : size; + bounce_buffer = alloca(xsiz); + r = _read(fd, bounce_buffer, xsiz); + if (r > 0) memcpy(buf, bounce_buffer, r); + return r; +} + +int bounced_write(int fd, const void *buf, size_t size) +{ + unsigned char *bounce_buffer; + size_t xsiz; + int r; + if (fd < 3 && (unsigned long)buf + size > 0x20000000) goto bounce; + r = _write(fd, buf, size); + if (r == -1 && errno == EFAULT) goto bounce; + return r; + bounce: + xsiz = size > BOUNCE_BUFFER_SIZE ? BOUNCE_BUFFER_SIZE : size; + bounce_buffer = alloca(xsiz); + memcpy(bounce_buffer, buf, xsiz); + return _write(fd, bounce_buffer, xsiz); +} + +#endif + +#ifdef OS2_ADVANCED_HEAP + +#include <umalloc.h> + +#ifndef OBJ_ANY +#define OBJ_ANY 0x0400 +#endif + +unsigned long mem_requested = 0; +unsigned long blocks_requested = 0; + +static int dosallocmem_attrib = PAG_READ | PAG_WRITE | PAG_COMMIT; + +#define HEAP_ALIGN 0x10000 +#define HEAP_PAD 2 +#define HEAP_MAXPAD 0x1000000 + +static void heap_release(Heap_t h, void *ptr, size_t len) +{ + int rc; + mem_requested -= ((len | 4095) + 1); + blocks_requested--; + rc = DosFreeMem(ptr); + /*fprintf(stderr, "heap free %p -> %d\n", ptr, rc);*/ + if (rc) { + error("DosFreeMem failed: %d", rc); + fatal_tty_exit(); + exit(RET_FATAL); + } +} + +static void *heap_alloc(Heap_t h, size_t *size, int *pclean) +{ + void *result; + int rc; + /* If we rounded up to page size, EMX would join all allocations + * to one segment and refuse to free memory. So round up to + * page size - 1 */ + size_t real_size = *size; + if (real_size < HEAP_MAXPAD / HEAP_PAD) { + real_size *= HEAP_PAD; + real_size = real_size | (HEAP_ALIGN - 1); + } else { + real_size |= 1; + } + rc = DosAllocMem(&result, real_size, dosallocmem_attrib); + /*fprintf(stderr, "heap alloc %d -> %p, %d\n", *size, result, rc);*/ + if (!rc) { + /* + * Hitting the shared arena has a negative impact on the whole + * system. Therefore, we fake failure (so that Links frees + * some caches) and try allocating near the shared arena only + * as a last resort. + */ + if ((unsigned long)result >= 0x12000000 && + (unsigned long)result < 0x20000000) { + if (!malloc_try_hard) { + heap_release(NULL, result, real_size); + return NULL; + } + } + *size = real_size; + *pclean = _BLOCK_CLEAN; + mem_requested += ((real_size | 4095) + 1); + blocks_requested++; + return result; + } else { + return NULL; + } +} + +static void init_os2_heap(void) +{ + Heap_t new_heap; + size_t init_size = _HEAP_MIN_SIZE; + void *init_mem; + int init_clean; + dosallocmem_attrib |= OBJ_ANY; + init_mem = heap_alloc(NULL, &init_size, &init_clean); + if (!init_mem) { + dosallocmem_attrib &= ~OBJ_ANY; + init_mem = heap_alloc(NULL, &init_size, &init_clean); + if (!init_mem) { + return; + } + } + new_heap = _ucreate(init_mem, init_size, init_clean, _HEAP_REGULAR, heap_alloc, heap_release); + if (!new_heap) { + heap_release(NULL, init_mem, init_size); + return; + } + if (_uopen(new_heap) == -1) { +#if defined(HAVE__UDESTROY) && defined(_FORCE) + _udestroy(new_heap, _FORCE); +#else + heap_release(NULL, init_mem, init_size); +#endif + return; + } + _udefault(new_heap); +} + +#endif + +#if defined(O_SIZE) && defined(__EMX__) + +int open_prealloc(unsigned char *name, int flags, int mode, off_t siz) +{ + int h; + EINTRLOOP(h, open(name, flags | O_SIZE, mode, (unsigned long)siz)); + return h; +} + +#endif + +/* Terminal size */ + +#ifdef WIN32 + +/* Cygwin has a bug and loses SIGWINCH sometimes, so poll it */ + +static void winch_thread(void *p, int l) +{ + static int old_xsize, old_ysize; + static int cur_xsize, cur_ysize; + if (get_terminal_size(0, &old_xsize, &old_ysize)) return; + while (1) { + if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return; + if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) { + int rr; + old_xsize = cur_xsize; + old_ysize = cur_ysize; + EINTRLOOP(rr, raise(SIGWINCH)); + } + sleep(1); + } +} + +static void win32_resize_poll(void) +{ + static int winch_thread_running = 0; + if (!winch_thread_running) { + if (start_thread(winch_thread, NULL, 0) >= 0) + winch_thread_running = 1; + } +} + +#endif + +#if defined(UNIX) || defined(WIN32) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) + +static void sigwinch(void *s) +{ + ((void (*)(void))s)(); +} + +void handle_terminal_resize(int fd, void (*fn)(void)) +{ + install_signal_handler(SIGWINCH, sigwinch, fn, 0); +#ifdef WIN32 + win32_resize_poll(); +#endif +} + +void unhandle_terminal_resize(int fd) +{ + install_signal_handler(SIGWINCH, NULL, NULL, 0); +} + +int get_terminal_size(int fd, int *x, int *y) +{ + volatile struct winsize ws; /* Sun Studio misoptimizes it */ + int rs; + if (!x || !y) return -1; + EINTRLOOP(rs, ioctl(1, TIOCGWINSZ, &ws)); + if (rs != -1) { + if (!(*x = ws.ws_col) && !(*x = get_e("COLUMNS"))) *x = 80; + if (!(*y = ws.ws_row) && !(*y = get_e("LINES"))) *y = 24; + return 0; + } else { + if (!(*x = get_e("COLUMNS"))) *x = 80; + if (!(*y = get_e("LINES"))) *y = 24; + } + return 0; +} + +#elif defined(OS2) + +#define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2 + +int is_xterm(void) +{ + static int xt = -1; + if (xt == -1) xt = !!getenv("WINDOWID"); + return xt; +} + +static int winch_pipe[2]; +static unsigned char winch_thread_running = 0; + +#define WINCH_SLEEPTIME 500 /* time in ms for winch thread to sleep */ + +static void winch_thread(void) +{ + /* A thread which regularly checks whether the size of + window has changed. Then raise SIGWINCH or notifiy + the thread responsible to handle this. */ + static int old_xsize, old_ysize; + static int cur_xsize, cur_ysize; + + ignore_signals(); + if (get_terminal_size(1, &old_xsize, &old_ysize)) return; + while (1) { + if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return; + if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) { + int wr; + old_xsize = cur_xsize; + old_ysize = cur_ysize; + EINTRLOOP(wr, write(winch_pipe[1], "x", 1)); + /* Resizing may take some time. So don't send a flood + of requests?! */ + _sleep2(2*WINCH_SLEEPTIME); + } + else + _sleep2(WINCH_SLEEPTIME); + } +} + +static void winch(void *s) +{ + unsigned char c; + while (can_read(winch_pipe[0])) { + int rd; + EINTRLOOP(rd, read(winch_pipe[0], &c, 1)); + if (rd != 1) break; + } + ((void (*)(void))s)(); +} + +void handle_terminal_resize(int fd, void (*fn)(void)) +{ + if (!is_xterm()) return; + if (!winch_thread_running) { + if (c_pipe(winch_pipe) < 0) return; + winch_thread_running = 1; + if (_beginthread((void (*)(void *))winch_thread, NULL, 0x32000, NULL) == -1) { + } + } + set_handlers(winch_pipe[0], winch, NULL, NULL, fn); +} + +void unhandle_terminal_resize(int fd) +{ + set_handlers(winch_pipe[0], NULL, NULL, NULL, NULL); +} + +int get_terminal_size(int fd, int *x, int *y) +{ + if (!x || !y) return -1; + if (is_xterm()) { +#ifdef X2 + int arc; + struct winsize win; + + /* fd = STDIN_FILENO; */ + arc = ptioctl(1, TIOCGWINSZ, &win); + if (arc) { + *x = 80; + *y = 24; + return 0; + } + *y = win.ws_row; + *x = win.ws_col; + goto set_default; +#else + *x = 80; *y = 24; + return 0; +#endif + } else { + int a[2] = { 0, 0 }; + _scrsize(a); + *x = a[0]; + *y = a[1]; +#ifdef X2 + set_default: +#endif + if (*x == 0) { + *x = get_e("COLUMNS"); + if (*x == 0) *x = 80; + } + if (*y == 0) { + *y = get_e("LINES"); + if (*y == 0) *y = 24; + } + } + return 0; +} + +#endif + +/* Pipe */ + +#if defined(OS2) || (defined(WIN32) && !defined(_UWIN)) + +void set_bin(int fd) +{ + setmode(fd, O_BINARY); +} + +#else + +void set_bin(int fd) +{ +} + +#endif + +int c_pipe(int *fd) +{ + int r; + EINTRLOOP(r, pipe(fd)); + if (!r) set_bin(fd[0]), set_bin(fd[1]); + return r; +} + +/* Exec */ + +int can_twterm(void) /* Check if it make sense to call a twterm. */ +{ + static int xt = -1; + if (xt == -1) xt = !!getenv("TWDISPLAY"); + return xt; +} + + +#if defined(UNIX) || defined(SPAD) + +int is_xterm(void) +{ + static int xt = -1; + if (xt == -1) xt = getenv("DISPLAY") && *getenv("DISPLAY"); + return xt; +} + +#elif defined(BEOS) || defined(ATHEOS) + +int is_xterm(void) +{ + return 0; +} + +#elif defined(WIN32) || defined(INTERIX) + +int is_xterm(void) +{ + static int xt = -1; + if (xt == -1) xt = !!getenv("WINDOWID"); + return xt; +} + +#elif defined(RISCOS) + +int is_xterm(void) +{ + return 1; +} + +#endif + +void close_fork_tty(void) +{ + struct terminal *t; + struct download *d; + struct connection *c; + struct k_conn *k; + int rs; + foreach (t, terminals) if (t->fdin > 0) + EINTRLOOP(rs, close(t->fdin)); + foreach (d, downloads) if (d->handle > 0) + EINTRLOOP(rs, close(d->handle)); + foreach (c, queue) close_socket(&c->sock1), close_socket(&c->sock2); + foreach (k, keepalive_connections) + EINTRLOOP(rs, close(k->conn)); +} + +void init_os(void) +{ +#ifdef OS2_ADVANCED_HEAP + init_os2_heap(); +#endif +#if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) +#define RLIMIT_NOFILE RLIMIT_OFILE +#endif +#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit limit; + int rs; + EINTRLOOP(rs, getrlimit(RLIMIT_NOFILE, &limit)); + if (rs) + goto skip_limit; + if (limit.rlim_cur > FD_SETSIZE) { + limit.rlim_cur = FD_SETSIZE; + EINTRLOOP(rs, setrlimit(RLIMIT_NOFILE, &limit)); + } +skip_limit:; +#endif +} + +#if defined(WIN32) + +void get_path_to_exe(void) +{ + /* Standard method (argv[0]) doesn't work, if links is executed from + symlink --- it returns symlink name and cmd.exe is unable to start + it */ + unsigned r; + static unsigned char path[4096]; + r = GetModuleFileName(NULL, path, sizeof path); + if (r <= 0 || r >= sizeof path) { + path_to_exe = g_argv[0]; + return; + } + path_to_exe = path; +} + +#elif defined(OS2) + +static int os2_full_screen = 0; +static int os2_detached = 0; + +void get_path_to_exe(void) +{ + /* If you spawn links with quotation marks from cmd.exe, + the quotation marks will be present in g_argv[0] ... and will + prevent executing it */ + static unsigned char path[270]; + PTIB tib = NULL; + PPIB pib = NULL; + path_to_exe = g_argv[0]; + DosGetInfoBlocks(&tib, &pib); + if (!pib) return; + os2_full_screen = pib->pib_ultype == 0; + os2_detached = pib->pib_ultype == 4; + if (DosQueryModuleName(pib->pib_hmte, sizeof path, path)) return; + path_to_exe = path; +} + +int os_get_system_name(unsigned char *buffer) +{ + ULONG version[3]; + if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, version, sizeof version)) + return -1; + if (version[0] == 20) { + version[0] = 2; + if (version[1] == 10) { + version[1] = 1; + } else if (version[1] >= 30) { + version[0] = version[1] / 10; + version[1] %= 10; + } + } + sprintf(buffer, "OS/2 %d.%d i386", (int)version[0], (int)version[1]); + return 0; +} + +#else + +void get_path_to_exe(void) +{ + path_to_exe = g_argv[0]; +} + +#endif + +void init_os_terminal(void) +{ +#ifdef INTERIX + /* Some sort of terminal bug in Interix, if we run xterm -e links, + terminal doesn't switch to raw mode, executing "stty sane" fixes it. + Don't do this workaround on console. */ + unsigned char *term = getenv("TERM"); + if (!term || strncasecmp(term, "interix", 7)) { + int rr; + errno = 0; + EINTRLOOP(rr, system("stty sane 2>/dev/null")); + } +#endif +#ifdef OS2 + if (os2_detached) { + error("Links doesn't work in detached session"); + fatal_tty_exit(); + exit(RET_FATAL); + } +#endif +} + +#ifdef INTERIX + +static inline void cut_program_path(unsigned char *prog, unsigned char **prog_start, unsigned char **prog_end) +{ + while (WHITECHAR(*prog)) prog++; + if (prog[0] == '"' || prog[0] == '\'') { + *prog_start = prog + 1; + *prog_end = strchr(prog + 1, prog[0]); + if (!*prog_end) + *prog_end = strchr(prog, 0); + } else { + *prog_start = prog; + *prog_end = prog + strcspn(prog, " "); + } +} + +static inline int is_windows_drive(unsigned char *prog_start, unsigned char *prog_end) +{ + if (prog_end - prog_start >= 3 && upcase(prog_start[0]) >= 'A' && upcase(prog_start[0]) <= 'Z' && prog_start[1] == ':') + return 1; + return 0; +} + +static inline int is_windows_program(unsigned char *prog_start, unsigned char *prog_end) +{ + if (prog_end - prog_start > 4 && ( + !strncasecmp(prog_end - 4, ".exe", 4) || + !strncasecmp(prog_end - 4, ".bat", 4))) + return 1; + return 0; +} + +#endif + +#if defined(WIN32) && defined(HAVE_CYGWIN_CONV_PATH) + +unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog) +{ + unsigned char *new_path; + ssize_t sz; + sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, NULL, 0); + if (sz < 0) return stracpy(file); + new_path = mem_alloc(sz); + sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, new_path, sz); + if (sz < 0) { + mem_free(new_path); + return stracpy(file); + } + return new_path; +} + +#elif defined(WIN32) && defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH) + +unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog) +{ +#ifdef MAX_PATH + unsigned char new_path[MAX_PATH]; +#else + unsigned char new_path[1024]; +#endif + *new_path = 0; + cygwin_conv_to_full_win32_path(file, new_path); + if (!*new_path) return stracpy(file); + return stracpy(new_path); +} + +#elif defined(WIN32) && defined(HAVE_UWIN_PATH) + +unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog) +{ + unsigned char *new_path; + ssize_t sz, sz2; + sz = uwin_path(file, NULL, 0); + if (sz < 0) return stracpy(file); + new_path = mem_alloc(sz + 1); + sz2 = uwin_path(file, new_path, sz + 1); + if (sz2 < 0 || sz2 > sz) { + mem_free(new_path); + return stracpy(file); + } + return new_path; +} + +#elif defined(INTERIX) && defined(HAVE_UNIXPATH2WIN) + +unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog) +{ + unsigned char *prog_start, *prog_end; + cut_program_path(prog, &prog_start, &prog_end); + /* Convert path only if the program has ".exe" or ".bat" extension */ + if (is_windows_program(prog_start, prog_end)) { +#ifdef MAX_PATH + unsigned char new_path[MAX_PATH]; +#else + unsigned char new_path[512]; +#endif + unsigned char *newstr; + int newstrl; + unsigned char *p; + if (unixpath2win(file, 0, new_path, sizeof(new_path))) + goto copy_path; + /*return stracpy(new_path);*/ + newstr = init_str(); + newstrl = 0; + for (p = new_path; *p; p++) { + /* + * Unix shell hates backslash and Windows applications + * accept '/' + */ + if (*p == '\\') add_to_str(&newstr, &newstrl, "/"); + else add_chr_to_str(&newstr, &newstrl, *p); + } + return newstr; + } + copy_path: + return stracpy(file); +} + +#else + +unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog) +{ + return stracpy(file); +} + +#endif + +#if defined(INTERIX) && defined(HAVE_WINPATH2UNIX) + +unsigned char *os_fixup_external_program(unsigned char *prog) +{ + unsigned char *prog_start, *prog_end; + cut_program_path(prog, &prog_start, &prog_end); + if (is_windows_drive(prog_start, prog_end)) { +#ifdef MAX_PATH + unsigned char new_path[MAX_PATH]; +#else + unsigned char new_path[1024]; +#endif + unsigned char *newstr; + int newstrl; + unsigned char *xpath; + if (is_windows_program(prog_start, prog_end)) { + /* + * There is some bug in Interix. Executing Win32 + * binaries works from the console but doesn't work + * from xterm. So we prepend "cmd /c" to the program + * as a workaround. + */ + newstr = init_str(); + newstrl = 0; + add_to_str(&newstr, &newstrl, "cmd /c "); + add_to_str(&newstr, &newstrl, prog); + return newstr; + } + xpath = memacpy(prog_start, prog_end - prog_start); + if (winpath2unix(xpath, 0, new_path, sizeof(new_path))) { + mem_free(xpath); + goto copy_prog; + } + mem_free(xpath); + newstr = init_str(); + newstrl = 0; + add_bytes_to_str(&newstr, &newstrl, prog, prog_start - prog); + add_to_str(&newstr, &newstrl, new_path); + add_to_str(&newstr, &newstrl, prog_end); + return newstr; + } + copy_prog: + return stracpy(prog); +} + +#else + +unsigned char *os_fixup_external_program(unsigned char *prog) +{ + return stracpy(prog); +} + +#endif + + +#if defined(UNIX) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) + +#if defined(BEOS) && defined(HAVE_SETPGID) + +int exe(unsigned char *path, int fg) +{ + pid_t p, rp; + int s, rs; + EINTRLOOP(p, fork()); + if (!p) { + EINTRLOOP(rs, setpgid(0, 0)); + errno = 0; + EINTRLOOP(rs, system(path)); + _exit(0); + } + if (p > 0) { + EINTRLOOP(rp, waitpid(p, &s, 0)); + } else { + errno = 0; + EINTRLOOP(rs, system(path)); + return rs; + } + return 0; +} + +#else + +/* UNIX */ +int exe(unsigned char *path, int fg) +{ + int rs; +#ifdef G + if (F && drv->exec) return drv->exec(path, fg); +#endif +#ifdef SIGTSTP + errno = 0; + while (signal(SIGTSTP, SIG_DFL) == SIG_ERR && errno == EINTR) errno = 0; +#endif +#ifdef SIGCONT + errno = 0; + while (signal(SIGCONT, SIG_DFL) == SIG_ERR && errno == EINTR) errno = 0; +#endif +#ifdef SIGWINCH + errno = 0; + while (signal(SIGWINCH, SIG_DFL) == SIG_ERR && errno == EINTR) errno = 0; +#endif + errno = 0; + EINTRLOOP(rs, system(path)); + return rs; +} + +#endif + +/* clipboard -> links */ +unsigned char *get_clipboard_text(struct terminal *term) +{ +#ifdef G + if (F && drv->get_clipboard_text) { + return drv->get_clipboard_text(); + } +#endif + return stracpy(clipboard); +} + +/* links -> clipboard */ +void set_clipboard_text(struct terminal *term, unsigned char *data) +{ +#ifdef G + if (F && drv->set_clipboard_text) { + drv->set_clipboard_text(term->dev, data); + return; + } +#endif + if (clipboard) mem_free(clipboard); + clipboard = stracpy(data); +} + +int clipboard_support(struct terminal *term) +{ +#ifdef G + if (F && drv->set_clipboard_text) { + return 1; + } +#endif + return 0; +} + +void set_window_title(unsigned char *title) +{ + /* !!! FIXME */ +} + +unsigned char *get_window_title(void) +{ + /* !!! FIXME */ + return NULL; +} + +int resize_window(int x, int y) +{ + return -1; +} + +#elif defined(WIN32) + +static int is_winnt(void) +{ + OSVERSIONINFO v; + v.dwOSVersionInfoSize = sizeof v; + if (!GetVersionEx(&v)) return 0; + return v.dwPlatformId >= VER_PLATFORM_WIN32_NT; +} + +#define WIN32_START_STRING "start /wait " + +int exe(unsigned char *path, int fg) +{ + /* This is very tricky. We must have exactly 3 arguments, the first + one shell and the second one "/c", otherwise Cygwin would quote + the arguments and trash them */ + int ct; + unsigned char buffer[1024]; + unsigned char buffer2[1024]; + size_t want_alloc; + pid_t pid, rp; + int rs; + unsigned char *x1; + unsigned char *arg; + x1 = GETSHELL; + if (!x1) x1 = DEFAULT_SHELL; + + want_alloc = strlen(WIN32_START_STRING) + 3 + strlen(path) + 1; +#ifdef _UWIN + want_alloc += strlen(x1) + 4; + want_alloc *= 2; +#endif + + arg = malloc(want_alloc); + if (!arg) return -1; + *arg = 0; +#ifdef _UWIN + strcat(arg, x1); + strcat(arg, " /c "); +#endif + strcat(arg, WIN32_START_STRING); + if (*path == '"' && strlen(x1) >= 7 && !strcasecmp(x1 + strlen(x1) - 7, "cmd.exe")) strcat(arg, "\"\" "); + strcat(arg, path); + ct = GetConsoleTitle(buffer, sizeof buffer); +#if defined(_UWIN) && !defined(__DMC__) + { + unsigned char *q1 = arg, *q2 = arg; + while (*q1) { + if (*q1 == '\\') q2++; + q2++; + q1++; + } + while (1) { + *q2 = *q1; + if (*q1 == '\\') { + q2--; + *q2 = '\\'; + } + if (q1 == arg) break; + q1--; + q2--; + } + } + /* UWin corrupts heap if we use threads and fork */ + pid = spawnl("/bin/sh", "/bin/sh", "-c", arg, NULL); +#else +#if 0 /* spawn breaks mouse, don't use this */ + if (is_winnt()) { + /* spawn crashes on Win98 */ + spawnlp(_P_WAIT, x1, x1, "/c", arg, NULL); + goto free_ret; + } else +#endif + { + EINTRLOOP(pid, fork()); + if (!pid) { + int i; + /* Win98 crashes if we spawn command.com and have some sockets open */ + for (i = 0; i < FD_SETSIZE; i++) + EINTRLOOP(rs, close(i)); + EINTRLOOP(rs, open("nul", O_RDONLY)); + EINTRLOOP(rs, open("nul", O_WRONLY)); + EINTRLOOP(rs, open("nul", O_WRONLY)); + EINTRLOOP(rs, execlp(x1, x1, "/c", arg, NULL)); + _exit(1); + } + } +#endif + if (!is_winnt()) { + sleep(1); + if (ct && GetConsoleTitle(buffer2, sizeof buffer2) && !casecmp(buffer2, "start", 5)) { + SetConsoleTitle(buffer); + } + } + if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0)); + goto free_ret; + + free_ret: + free(arg); + return 0; +} + +unsigned char *get_clipboard_text(struct terminal *term) +{ + unsigned char buffer[256]; + unsigned char *str, *s, *d; + int l; + int r; + int rs; + int h; + EINTRLOOP(h, open("/dev/clipboard", O_RDONLY)); + if (h == -1) return stracpy(clipboard); + set_bin(h); /* O_TEXT doesn't work on clipboard handle */ + str = init_str(); + l = 0; + /* Don't use hard_read because UWin has buggy end-of-file signalling. + It resets the position to the beginning after signalling eof. */ + while (1) { + EINTRLOOP(r, read(h, buffer, sizeof buffer)); + if (r <= 0) break; + add_bytes_to_str(&str, &l, buffer, r); + } + EINTRLOOP(rs, close(h)); + for (s = str, d = str; *s; s++) + if (!(s[0] == '\r' && s[1] == '\n')) *d++ = *s; + *d = 0; + return str; +} + +/* Putting Czech characters to clipboard doesn't work, but it should be fixed + rather in Cygwin than here */ +void set_clipboard_text(struct terminal *term, unsigned char *data) +{ + unsigned char *conv_data; + int l; + int h; + int rs; + if (clipboard) mem_free(clipboard); + clipboard = stracpy(data); + EINTRLOOP(h, open("/dev/clipboard", O_WRONLY)); + if (h == -1) return; + set_bin(h); /* O_TEXT doesn't work on clipboard handle */ + conv_data = init_str(); + l = 0; + for (; *data; data++) + if (*data == '\n') add_to_str(&conv_data, &l, "\r\n"); + else add_chr_to_str(&conv_data, &l, *data); + hard_write(h, conv_data, l); + mem_free(conv_data); + EINTRLOOP(rs, close(h)); +} + +int clipboard_support(struct terminal *term) +{ + struct stat st; + int rs; + EINTRLOOP(rs, stat("/dev/clipboard", &st)); + return !rs; +} + + +static int get_windows_cp(void) +{ + unsigned char str[6]; + int cp, idx; + static int win_cp_idx = -1; + if (win_cp_idx != -1) return win_cp_idx; + if (is_winnt()) + cp = GetConsoleOutputCP(); + else + cp = GetACP(); + if (cp <= 0 || cp >= 100000) return 0; + sprintf(str, "%d", cp); + if ((idx = get_cp_index(str)) < 0) return 0; + win_cp_idx = idx; + return idx; +} + +void set_window_title(unsigned char *title) +{ + unsigned char *t, *p; + struct conv_table *ct; + if (!title) return; + if (is_xterm()) return; + ct = get_translation_table(utf8_table, get_windows_cp()); + t = convert_string(ct, title, strlen(title), NULL); + for (p = strchr(t, 1); p; p = strchr(p + 1, 1)) + *p = ' '; + SetConsoleTitle(t); + mem_free(t); +} + +unsigned char *get_window_title(void) +{ + struct conv_table *ct; + int r; + unsigned char buffer[1024]; + if (is_xterm()) return NULL; + if (!(r = GetConsoleTitle(buffer, sizeof buffer))) return NULL; + ct = get_translation_table(get_windows_cp(), utf8_table); + return convert_string(ct, buffer, r, NULL); +} + +static void call_resize(unsigned char *x1, int x, int y) +{ + pid_t pid, rp; + int rs; + unsigned char arg[MAX_STR_LEN]; +#ifdef _UWIN + x++; +#endif + sprintf(arg, "mode %d,%d", x, y); +#if defined(_UWIN) && !defined(__DMC__) + pid = spawnlp(x1, x1, "/c", arg, NULL); +#else +#if 0 /* spawn breaks mouse, don't use this */ + if (is_winnt()) { + /* spawn crashes on Win98 */ + spawnlp(_P_WAIT, x1, x1, "/c", arg, NULL); + return; + } else +#endif + { + EINTRLOOP(pid, fork()); + if (!pid) { + int i; + /* Win98 crashes if we spawn command.com and have some sockets open */ + for (i = 0; i < FD_SETSIZE; i++) if (i != 1 && i != 2) + EINTRLOOP(rs, close(i)); + EINTRLOOP(rs, open("nul", O_WRONLY)); + EINTRLOOP(rs, execlp(x1, x1, "/c", arg, NULL)); + _exit(1); + } + } +#endif + if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0)); +} + +int resize_window(int x, int y) +{ + int old_x, old_y; + int ct = 0, fullscreen = 0; + unsigned char buffer[1024]; + unsigned char *x1; + if (is_xterm()) return -1; + if (get_terminal_size(1, &old_x, &old_y)) return -1; + x1 = GETSHELL; + if (!x1) x1 = DEFAULT_SHELL; + if (!is_winnt()) { + ct = GetConsoleTitle(buffer, sizeof buffer); + } + + call_resize(x1, x, y); + if (!is_winnt()) { + int new_x, new_y; + /* If we resize console on Win98 in fullscreen mode, it won't be + notified by Cygwin (it is valid for all Cygwin apps). So we must + switch to windowed mode, resize it again (twice, because resizing + to the same size won't have an effect) and switch back to full-screen + mode. */ + /* I'm not sure what's the behavior on WinNT 4. Anybody wants to test? + */ + if (!fullscreen && !get_terminal_size(1, &new_x, &new_y) && (new_x != x || new_y != y)) { + fullscreen = 1; +#ifdef __CYGWIN__ + keybd_event(VK_MENU, 0x38, 0, 0); + keybd_event(VK_RETURN, 0x1c, 0, 0); + keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0); + keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0); +#endif + if (y != 25) call_resize(x1, 80, 25); + else call_resize(x1, 80, 50); + call_resize(x1, x, y); + if (get_terminal_size(1, &new_x, &new_y) || new_x != x || new_y != y) call_resize(x1, old_x, old_y); +#ifdef __CYGWIN__ + keybd_event(VK_MENU, 0x38, 0, 0); + keybd_event(VK_RETURN, 0x1c, 0, 0); + keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0); + keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0); +#endif + } + if (ct) SetConsoleTitle(buffer); + } + return 0; +} + +#elif defined(OS2) + +#ifdef G +static _fmutex fd_mutex; +static unsigned char fd_mutex_init = 0; +#endif + +int exe(unsigned char *path, int fg) +{ + int flags = P_SESSION; + pid_t pid, rs; + int ret; +#ifdef G + int old0 = 0, old1 = 1, old2 = 2; +#endif + unsigned char *shell; + if (!(shell = GETSHELL)) shell = DEFAULT_SHELL; + if (is_xterm()) flags |= P_BACKGROUND; +#ifdef G + if (F) { + if (!fd_mutex_init) { + if (_fmutex_create(&fd_mutex, 0)) return -1; + fd_mutex_init = 1; + } + _fmutex_request(&fd_mutex, _FMR_IGNINT); + EINTRLOOP(old0, dup(0)); + EINTRLOOP(old1, dup(1)); + EINTRLOOP(old2, dup(2)); + if (old0 >= 0) EINTRLOOP(rs, close(0)); + if (old1 >= 0) EINTRLOOP(rs, close(1)); + if (old2 >= 0) EINTRLOOP(rs, close(2)); + if (old0 >= 0) EINTRLOOP(rs, open("con", O_RDONLY)); + if (old1 >= 0) EINTRLOOP(rs, open("con", O_WRONLY)); + if (old2 >= 0) EINTRLOOP(rs, open("con", O_WRONLY)); + } +#endif + pid = spawnlp(flags, shell, shell, "/c", path, NULL); +#ifdef G + if (F) { + if (old0 >= 0) EINTRLOOP(rs, dup2(old0, 0)); + if (old1 >= 0) EINTRLOOP(rs, dup2(old1, 1)); + if (old2 >= 0) EINTRLOOP(rs, dup2(old2, 2)); + if (old0 >= 0) EINTRLOOP(rs, close(old0)); + if (old1 >= 0) EINTRLOOP(rs, close(old1)); + if (old2 >= 0) EINTRLOOP(rs, close(old2)); + _fmutex_release(&fd_mutex); + } +#endif + if (pid != -1) EINTRLOOP(rs, waitpid(pid, &ret, 0)); + else ret = -1; + return ret; +} + +unsigned char *get_clipboard_text(struct terminal *term) +{ + PTIB tib; + PPIB pib; + HAB hab; + HMQ hmq; + ULONG oldType; + unsigned char *ret = NULL; + + DosGetInfoBlocks(&tib, &pib); + + oldType = pib->pib_ultype; + + pib->pib_ultype = 3; + + if ((hab = WinInitialize(0)) != NULLHANDLE) { + if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) { + + if (WinOpenClipbrd(hab)) { + ULONG fmtInfo = 0; + + if (WinQueryClipbrdFmtInfo(hab, CF_TEXT, &fmtInfo)!=FALSE) + { + ULONG selClipText = WinQueryClipbrdData(hab, CF_TEXT); + + if (selClipText) + { + unsigned char *u; + PCHAR pchClipText = (PCHAR)selClipText; + ret = mem_alloc(strlen(pchClipText)+1); + strcpy(ret, pchClipText); + while ((u = strchr(ret, 13))) memmove(u, u + 1, strlen(u + 1) + 1); + } + } + + WinCloseClipbrd(hab); + } + +#ifdef G + if (F && ret) { + static int cp = -1; + struct conv_table *ct; + unsigned char *d; + if (cp == -1) { + int c = WinQueryCp(hmq); + unsigned char a[64]; + snprintf(a, 64, "%d", c); + if ((cp = get_cp_index(a)) < 0 || cp == utf8_table) cp = 0; + } + ct = get_translation_table(cp, utf8_table); + d = convert_string(ct, ret, strlen(ret), NULL); + mem_free(ret); + ret = d; + } +#endif + WinDestroyMsgQueue(hmq); + } + WinTerminate(hab); + } + + pib->pib_ultype = oldType; + + return ret; +} + +void set_clipboard_text(struct terminal * term, unsigned char *data) +{ + PTIB tib; + PPIB pib; + HAB hab; + HMQ hmq; + ULONG oldType; + + unsigned char *d = NULL; + + DosGetInfoBlocks(&tib, &pib); + + oldType = pib->pib_ultype; + + pib->pib_ultype = 3; + + if ((hab = WinInitialize(0)) != NULLHANDLE) { + if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) { +#ifdef G + if (F) { + static int cp = -1; + struct conv_table *ct; + unsigned char *p; + if (cp == -1) { + int c = WinQueryCp(hmq); + unsigned char a[64]; + snprintf(a, 64, "%d", c); + if ((cp = get_cp_index(a)) < 0 || cp == utf8_table) cp = 0; + } + ct = get_translation_table(utf8_table, cp); + d = convert_string(ct, data, strlen(data), NULL); + for (p = strchr(d, 1); p; p = strchr(p + 1, 1)) + *p = ' '; + data = d; + } +#endif + if (WinOpenClipbrd(hab)) { + PVOID pvShrObject = NULL; + if (DosAllocSharedMem(&pvShrObject, NULL, strlen(data)+1, PAG_COMMIT | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) { + strcpy(pvShrObject, data); + WinEmptyClipbrd(hab); + WinSetClipbrdData(hab, (ULONG)pvShrObject, CF_TEXT, CFI_POINTER); + } + WinCloseClipbrd(hab); + } + WinDestroyMsgQueue(hmq); + } + WinTerminate(hab); + } + + pib->pib_ultype = oldType; + + if (d) mem_free(d); +} + +int clipboard_support(struct terminal *term) +{ + return 1; +} + +unsigned char *get_window_title(void) +{ +#ifndef OS2_DEBUG + /*char *org_switch_title;*/ + unsigned char *org_win_title = NULL; + static PTIB tib = NULL; + static PPIB pib = NULL; + ULONG oldType; + HSWITCH hSw = NULLHANDLE; + SWCNTRL swData; + HAB hab; + HMQ hmq; + + /* save current process title */ + + if (!pib) DosGetInfoBlocks(&tib, &pib); + oldType = pib->pib_ultype; + memset(&swData, 0, sizeof swData); + if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid); + if (hSw != NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) { + /*org_switch_title = mem_alloc(strlen(swData.szSwtitle)+1); + strcpy(org_switch_title, swData.szSwtitle);*/ + /* Go to PM */ + pib->pib_ultype = 3; + if ((hab = WinInitialize(0)) != NULLHANDLE) { + if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) { + org_win_title = mem_alloc(MAXNAMEL+1); + WinQueryWindowText(swData.hwnd, MAXNAMEL+1, org_win_title); + org_win_title[MAXNAMEL] = 0; + /* back From PM */ + WinDestroyMsgQueue(hmq); + } + WinTerminate(hab); + } + pib->pib_ultype = oldType; + } + return org_win_title; +#else + return NULL; +#endif +} + +void set_window_title(unsigned char *title) +{ +#ifndef OS2_DEBUG + static PTIB tib; + static PPIB pib; + ULONG oldType; + static HSWITCH hSw; + SWCNTRL swData; + HAB hab; + HMQ hmq; + if (!title) return; + if (!pib) DosGetInfoBlocks(&tib, &pib); + oldType = pib->pib_ultype; + memset(&swData, 0, sizeof swData); + if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid); + if (hSw!=NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) { + safe_strncpy(swData.szSwtitle, title, MAXNAMEL); + WinChangeSwitchEntry(hSw, &swData); + /* Go to PM */ + pib->pib_ultype = 3; + if ((hab = WinInitialize(0)) != NULLHANDLE) { + if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) { + if(swData.hwnd) + WinSetWindowText(swData.hwnd, title); + /* back From PM */ + WinDestroyMsgQueue(hmq); + } + WinTerminate(hab); + } + pib->pib_ultype = oldType; + } +#endif +} + +static tcount resize_count = 0; + +int resize_window(int x, int y) +{ + int xfont, yfont; + A_DECL(VIOMODEINFO, vmi); + resize_count++; + if (is_xterm()) return -1; + vmi->cb = sizeof(*vmi); + if (VioGetMode(vmi, 0)) return -1; + vmi->col = x; + vmi->row = y; + /*debug("%d %d %d", vmi->buf_length, vmi->full_length, vmi->partial_length);*/ + for (xfont = 9; xfont >= 8; xfont--) + for (yfont = 16; yfont >= 8; yfont--) { + vmi->hres = x * xfont; + vmi->vres = y * yfont; + if (vmi->vres <= 400) vmi->vres = 400; + else if (vmi->vres <= 480) vmi->vres = 480; + vmi->buf_length = vmi->full_length = vmi->partial_length = x * ((vmi->vres + yfont - 1) / yfont) * 2; + vmi->full_length = (vmi->full_length + 4095) & ~4095; + vmi->partial_length = (vmi->partial_length + 4095) & ~4095; + if (!VioSetMode(vmi, 0)) return 0; + } + return -1; +} + +#endif + +/* Threads */ + +#if (defined(HAVE_BEGINTHREAD) && defined(OS2)) || defined(BEOS) || defined(HAVE_PTHREADS) || defined(HAVE_ATHEOS_THREADS_H) + +struct tdata { + void (*fn)(void *, int); + int h; + unsigned char data[1]; +}; + +static void bgt(struct tdata *t) +{ + int rs; + ignore_signals(); + t->fn(t->data, t->h); + EINTRLOOP(rs, write(t->h, "x", 1)); + EINTRLOOP(rs, close(t->h)); + free(t); +} + +#ifdef HAVE_PTHREADS +static void *bgpt(struct tdata *t) +{ + bgt(t); + return NULL; +} +#endif + +#ifdef HAVE_ATHEOS_THREADS_H +#include <atheos/threads.h> +static uint32 abgt(void *t) +{ + bgt(t); + return 0; +} +#endif + +#endif + +#if defined(UNIX) || defined(OS2) || defined(WIN32) || defined(INTERIX) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) + +void terminate_osdep(void) {} + +#endif + +#ifndef BEOS + +void block_stdin(void) {} +void unblock_stdin(void) {} + +#endif + +#if defined(BEOS) + +#include <be/kernel/OS.h> + +static int thr_sem_init = 0; +static sem_id thr_sem; + +static struct list_head active_threads = { &active_threads, &active_threads }; + +struct active_thread { + struct active_thread *next; + struct active_thread *prev; + thread_id tid; + void (*fn)(void *); + void *data; +}; + +static int32 started_thr(void *data) +{ + struct active_thread *thrd = data; + thrd->fn(thrd->data); + if (acquire_sem(thr_sem) < B_NO_ERROR) return 0; + del_from_list(thrd); + free(thrd); + release_sem(thr_sem); + return 0; +} + +int start_thr(void (*fn)(void *), void *data, unsigned char *name) +{ + struct active_thread *thrd; + int tid; + if (!thr_sem_init) { + if ((thr_sem = create_sem(0, "thread_sem")) < B_NO_ERROR) return -1; + thr_sem_init = 1; + } else if (acquire_sem(thr_sem) < B_NO_ERROR) return -1; + retry: + if (!(thrd = malloc(sizeof(struct active_thread)))) { + if (out_of_memory(NULL, 0)) + goto retry; + goto rel; + } + thrd->fn = fn; + thrd->data = data; + if ((tid = thrd->tid = spawn_thread(started_thr, name, B_NORMAL_PRIORITY, thrd)) < B_NO_ERROR) { + free(thrd); + rel: + release_sem(thr_sem); + return -1; + } + resume_thread(thrd->tid); + add_to_list(active_threads, thrd); + release_sem(thr_sem); + return tid; +} + +void terminate_osdep(void) +{ + struct list_head *p; + struct active_thread *thrd; + if (acquire_sem(thr_sem) < B_NO_ERROR) return; + foreach(thrd, active_threads) kill_thread(thrd->tid); + while ((p = active_threads.next) != &active_threads) { + del_from_list(p); + free(p); + } + release_sem(thr_sem); +} + +int start_thread(void (*fn)(void *, int), void *ptr, int l) +{ + int p[2]; + struct tdata *t; + int rs; + if (c_pipe(p) < 0) return -1; + retry: + if (!(t = malloc(sizeof(struct tdata) + l))) { + if (out_of_memory(NULL, 0)) + goto retry; + return -1; + } + t->fn = fn; + t->h = p[1]; + memcpy(t->data, ptr, l); + if (start_thr((void (*)(void *))bgt, t, "links_thread") < 0) { + EINTRLOOP(rs, close(p[0])); + EINTRLOOP(rs, close(p[1])); + free(t); + return -1; + } + return p[0]; +} + + +#elif defined(HAVE_BEGINTHREAD) && defined(OS2) + +int start_thread(void (*fn)(void *, int), void *ptr, int l) +{ + int p[2]; + struct tdata *t; + int rs; + if (c_pipe(p) < 0) return -1; + EINTRLOOP(rs, fcntl(p[0], F_SETFL, O_NONBLOCK)); + EINTRLOOP(rs, fcntl(p[1], F_SETFL, O_NONBLOCK)); + retry: + if (!(t = malloc(sizeof(struct tdata) + l))) { + if (out_of_memory(NULL, 0)) + goto retry; + return -1; + } + t->fn = fn; + t->h = p[1]; + memcpy(t->data, ptr, l); + if (_beginthread((void (*)(void *))bgt, NULL, 65536, t) == -1) { + EINTRLOOP(rs, close(p[0])); + EINTRLOOP(rs, close(p[1])); + free(t); + return -1; + } + return p[0]; +} + +#ifdef HAVE__READ_KBD + +static int tp = -1; +static int ti = -1; + +static void input_thread(void *p) +{ + unsigned char c[2]; + int h = (int)p; + int rs; + ignore_signals(); + while (1) { + /* for the records: + _read_kbd(0, 1, 1) will + read a char, don't echo it, wait for one available and + accept CTRL-C. + Knowing that, I suggest we replace this call completly! + */ + *c = _read_kbd(0, 1, 1); + EINTRLOOP(rs, write(h, c, 1)); + } + EINTRLOOP(rs, close(h)); +} +#endif /* #ifdef HAVE__READ_KBD */ + +#if defined(HAVE_MOUOPEN) && !defined(USE_GPM) + +#define USING_OS2_MOUSE + +#ifdef HAVE_SYS_FMUTEX_H +static _fmutex mouse_mutex; +static unsigned char mouse_mutex_init = 0; +#endif +static int mouse_h = -1; + +struct os2_mouse_spec { + int p[2]; + void (*fn)(void *, unsigned char *, int); + void *data; + unsigned char buffer[sizeof(struct event)]; + int bufptr; + int terminate; +}; + +#define MOU_EMULATE_CURSOR + +#ifdef MOU_EMULATE_CURSOR +static int mouse_x = -1, mouse_y = -1; +static unsigned char mouse_attr; +#endif + +static void mouse_remove_pointer(void) +{ +#ifndef MOU_EMULATE_CURSOR + A_DECL(NOPTRRECT, pa); + static int x = -1, y = -1; + static tcount c = -1; + if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(1, &x, &y), c = resize_count; + pa->row = 0; + pa->col = 0; + pa->cRow = y - 1; + pa->cCol = x - 1; + MouRemovePtr(pa, mouse_h); +#else + if (mouse_x >= 0 && mouse_y >= 0) { + VioWrtNAttr(&mouse_attr, 1, mouse_y, mouse_x, 0); + } + mouse_x = -1, mouse_y = -1; +#endif +} + +static void mouse_draw_pointer(int x, int y) +{ +#ifndef MOU_EMULATE_CURSOR + MouDrawPtr(mouse_h); +#else + unsigned char str[4]; + USHORT str_len; + unsigned char attr; + unsigned char fg, bg; + int r; + if (!os2_full_screen) + return; + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); + if (mouse_x == x && mouse_y == y) + return; + mouse_remove_pointer(); + str_len = sizeof(str); + r = VioReadCellStr(str, &str_len, y, x, 0); + if (r || str_len < 2) return; + mouse_attr = str[1]; + fg = mouse_attr & 0x07; + bg = (mouse_attr & 0x70) >> 4; + if (fg == bg) fg ^= 0x07, bg ^= 0x07; + attr = (mouse_attr & 0x88) | (fg << 4) | bg; + r = VioWrtNAttr(&attr, 1, y, x, 0); + if (r) return; + mouse_x = x, mouse_y = y, mouse_attr = str[1]; +#endif +} + +static void mouse_thread(void *p) +{ + int status; + int rs; + struct os2_mouse_spec *oms = p; + A_DECL(HMOU, mh); + A_DECL(MOUEVENTINFO, ms); + A_DECL(USHORT, rd); + A_DECL(USHORT, mask); + struct event ev; + ignore_signals(); + ev.ev = EV_MOUSE; + if (MouOpen(NULL, mh)) goto ret; + mouse_h = *mh; + *mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN | + MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN | + MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN | + MOUSE_MOTION; + MouSetEventMask(mask, *mh); + *rd = MOU_WAIT; + status = -1; + while (1) { + /*int w, ww;*/ + if (MouReadEventQue(ms, rd, *mh)) break; +#ifdef HAVE_SYS_FMUTEX_H + _fmutex_request(&mouse_mutex, _FMR_IGNINT); +#endif + if (!oms->terminate) mouse_draw_pointer(ms->col, ms->row); +#ifdef HAVE_SYS_FMUTEX_H + _fmutex_release(&mouse_mutex); +#endif + ev.x = ms->col; + ev.y = ms->row; + /*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/ + if (ms->fs & (MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN)) ev.b = status = B_DOWN | (ms->fs & MOUSE_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_BN2_DOWN ? B_RIGHT : B_MIDDLE); + else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) { + int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_RIGHT : B_MIDDLE; + if (status == -1) b |= B_DOWN; + else b |= B_DRAG; + ev.b = status = b; + } + else { + if (status == -1) continue; + ev.b = (status & BM_BUTT) | B_UP; + status = -1; + } + if (hard_write(oms->p[1], (unsigned char *)&ev, sizeof(struct event)) != sizeof(struct event)) break; + } +#ifdef HAVE_SYS_FMUTEX_H + _fmutex_request(&mouse_mutex, _FMR_IGNINT); +#endif + mouse_h = -1; + MouClose(*mh); +#ifdef HAVE_SYS_FMUTEX_H + _fmutex_release(&mouse_mutex); +#endif + ret: + EINTRLOOP(rs, close(oms->p[1])); + /*free(oms);*/ +} + +static void mouse_handle(struct os2_mouse_spec *oms) +{ + int r; + EINTRLOOP(r, read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct event) - oms->bufptr)); + if (r <= 0) { + unhandle_mouse(oms); + return; + } + if ((oms->bufptr += r) == sizeof(struct event)) { + oms->bufptr = 0; + oms->fn(oms->data, oms->buffer, sizeof(struct event)); + } +} + +void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) +{ + struct os2_mouse_spec *oms; + if (is_xterm()) return NULL; +#ifdef HAVE_SYS_FMUTEX_H + if (!mouse_mutex_init) { + if (_fmutex_create(&mouse_mutex, 0)) return NULL; + mouse_mutex_init = 1; + } +#endif + /* This is never freed but it's allocated only once */ + retry: + if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) { + if (out_of_memory(NULL, 0)) + goto retry; + return NULL; + } + oms->fn = fn; + oms->data = data; + oms->bufptr = 0; + oms->terminate = 0; + if (c_pipe(oms->p)) { + free(oms); + return NULL; + } + if (_beginthread(mouse_thread, NULL, 0x10000, (void *)oms) == -1) { + } + set_handlers(oms->p[0], (void (*)(void *))mouse_handle, NULL, NULL, oms); + return oms; +} + +void unhandle_mouse(void *om) +{ + struct os2_mouse_spec *oms = om; + int rs; + want_draw(); + oms->terminate = 1; + set_handlers(oms->p[0], NULL, NULL, NULL, NULL); + EINTRLOOP(rs, close(oms->p[0])); + done_draw(); +} + +void want_draw(void) +{ + static int ansi = 0; +#ifdef HAVE_SYS_FMUTEX_H + if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT); +#endif + if (!ansi) { + VioSetAnsi(1, 0); + ansi = 1; + } + if (mouse_h != -1) { + mouse_remove_pointer(); + } +} + +void done_draw(void) +{ +#ifdef HAVE_SYS_FMUTEX_H + if (mouse_mutex_init) _fmutex_release(&mouse_mutex); +#endif +} + +#endif /* if HAVE_MOUOPEN */ + +#elif defined(HAVE_PTHREADS) + +#include <pthread.h> + +int start_thread(void (*fn)(void *, int), void *ptr, int l) +{ + pthread_t thread; + struct tdata *t; + int p[2]; + int rs; + if (c_pipe(p) < 0) return -1; + EINTRLOOP(rs, fcntl(p[0], F_SETFL, O_NONBLOCK)); + EINTRLOOP(rs, fcntl(p[1], F_SETFL, O_NONBLOCK)); + retry: + if (!(t = malloc(sizeof(struct tdata) + l))) { + if (out_of_memory(NULL, 0)) + goto retry; + return -1; + } + t->fn = fn; + t->h = p[1]; + memcpy(t->data, ptr, l); + if (pthread_create(&thread, NULL, (void *(*)(void *))bgpt, t)) { + EINTRLOOP(rs, close(p[0])); + EINTRLOOP(rs, close(p[1])); + free(t); + return -1; + } + return p[0]; +} + +#elif defined(HAVE_ATHEOS_THREADS_H) && defined(HAVE_SPAWN_THREAD) && defined(HAVE_RESUME_THREAD) + +#include <atheos/threads.h> + +int start_thread(void (*fn)(void *, int), void *ptr, int l) +{ + int p[2]; + int rs; + thread_id f; + struct tdata *t; + if (c_pipe(p) < 0) return -1; + EINTRLOOP(rs, fcntl(p[0], F_SETFL, O_NONBLOCK)); + EINTRLOOP(rs, fcntl(p[1], F_SETFL, O_NONBLOCK)); + retry: + if (!(t = malloc(sizeof(struct tdata) + l))) { + if (out_of_memory(NULL, 0)) + goto retry; + return -1; + } + t->fn = fn; + t->h = p[1]; + memcpy(t->data, ptr, l); + if ((f = spawn_thread("links_lookup", abgt, 0, 0, t)) == -1) { + EINTRLOOP(rs, close(p[0])); + EINTRLOOP(rs, close(p[1])); + mem_free(t); + return -1; + } + resume_thread(f); + return p[0]; +} + +#else /* HAVE_BEGINTHREAD */ + +int start_thread(void (*fn)(void *, int), void *ptr, int l) +{ + int p[2]; + pid_t f; + int rs; + if (c_pipe(p) < 0) return -1; + EINTRLOOP(rs, fcntl(p[0], F_SETFL, O_NONBLOCK)); + EINTRLOOP(rs, fcntl(p[1], F_SETFL, O_NONBLOCK)); + EINTRLOOP(f, fork()); + if (!f) { + close_fork_tty(); + EINTRLOOP(rs, close(p[0])); + fn(ptr, p[1]); + EINTRLOOP(rs, write(p[1], "x", 1)); + EINTRLOOP(rs, close(p[1])); + _exit(0); + } + if (f == -1) { + EINTRLOOP(rs, close(p[0])); + EINTRLOOP(rs, close(p[1])); + return -1; + } + EINTRLOOP(rs, close(p[1])); + return p[0]; +} + +#endif + +#ifndef USING_OS2_MOUSE +void want_draw(void) {} +void done_draw(void) {} +#endif + +int get_output_handle(void) { return 1; } + +#if defined(OS2) + +int get_ctl_handle(void) { return get_input_handle(); } + +#else + +int get_ctl_handle(void) { return 0; } + +#endif + +#if defined(BEOS) + +#elif defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD) +int get_input_handle(void) +{ + int fd[2]; + if (ti != -1) return ti; + if (is_xterm()) return 0; + if (c_pipe(fd) < 0) return 0; + ti = fd[0]; + tp = fd[1]; + _beginthread(input_thread, NULL, 0x10000, (void *)tp); +/* +#if defined(HAVE_MOUOPEN) && !defined(USE_GPM) + _beginthread(mouse_thread, NULL, 0x10000, (void *)tp); +#endif +*/ + return fd[0]; +} + +#else + +int get_input_handle(void) +{ + return 0; +} + +#endif /* defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD) */ + + +void os_cfmakeraw(struct termios *t) +{ +#ifdef HAVE_CFMAKERAW + cfmakeraw(t); +#ifdef VMIN + t->c_cc[VMIN] = 1; +#endif +#else + t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + t->c_cflag &= ~(CSIZE|PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +#endif +#if defined(NO_CTRL_Z) && defined(VSUSP) + t->c_cc[VSUSP] = 0; +#endif + /*fprintf(stderr, "\n"); + fprintf(stderr, "%08x %08x %08x\n", t->c_iflag, t->c_oflag, t->c_lflag); + { + int i; + for (i = 0; i < sizeof(t->c_cc) / sizeof(*t->c_cc); i++) { + fprintf(stderr, "%d - %d\n", i, t->c_cc[i]); + } + } + sleep(10);*/ +} + +#ifdef USE_GPM + +struct gpm_mouse_spec { + int h; + void (*fn)(void *, unsigned char *, int); + void *data; +}; + +/* GPM installs its own signal handlers and we don't want them */ + +static sigset_t gpm_sigset; +static unsigned char gpm_sigset_valid; +#ifdef SIGWINCH +static struct sigaction gpm_winch; +static unsigned char gpm_winch_valid; +#endif +#ifdef SIGTSTP +static struct sigaction gpm_tstp; +static unsigned char gpm_tstp_valid; +#endif + +static void save_gpm_signals(void) +{ + sigset_t sig; + int rs; + sigemptyset(&sig); +#ifdef SIGWINCH + sigaddset(&sig, SIGWINCH); +#endif +#ifdef SIGTSTP + sigaddset(&sig, SIGTSTP); +#endif + EINTRLOOP(rs, sigprocmask(SIG_BLOCK, &sig, &gpm_sigset)); + gpm_sigset_valid = !rs; +#ifdef SIGWINCH + EINTRLOOP(rs, sigaction(SIGWINCH, NULL, &gpm_winch)); + gpm_winch_valid = !rs; +#endif +#ifdef SIGTSTP + EINTRLOOP(rs, sigaction(SIGTSTP, NULL, &gpm_tstp)); + gpm_tstp_valid = !rs; +#endif +} + +static void restore_gpm_signals(void) +{ + int rs; +#ifdef SIGWINCH + if (gpm_winch_valid) + EINTRLOOP(rs, sigaction(SIGWINCH, &gpm_winch, NULL)); +#endif +#ifdef SIGTSTP + if (gpm_tstp_valid) + EINTRLOOP(rs, sigaction(SIGTSTP, &gpm_tstp, NULL)); +#endif + if (gpm_sigset_valid) + EINTRLOOP(rs, sigprocmask(SIG_SETMASK, &gpm_sigset, NULL)); +} + +static void gpm_mouse_in(struct gpm_mouse_spec *gms) +{ + int g; + Gpm_Event gev; + struct event ev; + save_gpm_signals(); + g = Gpm_GetEvent(&gev); + restore_gpm_signals(); + if (g <= 0) { + set_handlers(gms->h, NULL, NULL, NULL, NULL); + gms->h = -1; + return; + } + ev.ev = EV_MOUSE; + ev.x = gev.x - 1; + ev.y = gev.y - 1; + if (ev.x < 0) ev.x = 0; + if (ev.y < 0) ev.y = 0; + if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT; + else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE; + else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT; + else return; + if (gev.type & GPM_DOWN) ev.b |= B_DOWN; + else if (gev.type & GPM_UP) ev.b |= B_UP; + else if (gev.type & GPM_DRAG) ev.b |= B_DRAG; + else return; + gms->fn(gms->data, (unsigned char *)&ev, sizeof(struct event)); +} + +void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) +{ + int h; + Gpm_Connect conn; + struct gpm_mouse_spec *gms; + conn.eventMask = ~GPM_MOVE; + conn.defaultMask = GPM_MOVE; + conn.minMod = 0; + conn.maxMod = 0; + save_gpm_signals(); + h = Gpm_Open(&conn, cons); + restore_gpm_signals(); + if (h < 0) return NULL; + gms = mem_alloc(sizeof(struct gpm_mouse_spec)); + gms->h = h; + gms->fn = fn; + gms->data = data; + set_handlers(h, (void (*)(void *))gpm_mouse_in, NULL, NULL, gms); + return gms; +} + +void unhandle_mouse(void *h) +{ + struct gpm_mouse_spec *gms = h; + if (gms->h != -1) set_handlers(gms->h, NULL, NULL, NULL, NULL); + save_gpm_signals(); + Gpm_Close(); + restore_gpm_signals(); + mem_free(gms); +} + +void add_gpm_version(unsigned char **s, int *l) +{ + add_to_str(s, l, "GPM"); +#ifdef HAVE_GPM_GETLIBVERSION + add_to_str(s, l, " ("); + add_to_str(s, l, (unsigned char *)Gpm_GetLibVersion(NULL)); + add_to_str(s, l, ")"); +#endif +} + +#elif !defined(USING_OS2_MOUSE) + +void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) { return NULL; } +void unhandle_mouse(void *data) { } + +#endif /* #ifdef USE_GPM */ + + +#if defined(WIN32) || defined(INTERIX) + +static int is_remote_connection(void) +{ + return !!getenv("SSH_CONNECTION"); +} + +#endif + + +#if defined(OS2) + +int get_system_env(void) +{ + if (is_xterm()) return 0; + return ENV_OS2VIO; /* !!! FIXME: telnet */ +} + +#elif defined(BEOS) + +int get_system_env(void) +{ + unsigned char *term = getenv("TERM"); + if (!term || (upcase(term[0]) == 'B' && upcase(term[1]) == 'E')) return ENV_BE; + return 0; +} + +#elif defined(WIN32) + +int get_system_env(void) +{ + if (is_xterm()) return 0; + if (is_remote_connection()) return 0; + return ENV_WIN32; +} + +#elif defined(INTERIX) + +#define INTERIX_START_COMMAND "/usr/contrib/win32/bin/start" + +int get_system_env(void) +{ + if (is_xterm()) return 0; + if (is_remote_connection()) return 0; + if (!access(INTERIX_START_COMMAND, X_OK)) return ENV_INTERIX; + return 0; +} + +#else + +int get_system_env(void) +{ + return 0; +} + +#endif + +static void exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe, unsigned char *param) +{ + unsigned char *str; + str = mem_alloc(strlen(xterm) + 1 + strlen(exe) + 1 + strlen(param) + 1); + if (*xterm) sprintf(str, "%s %s %s", xterm, exe, param); + else sprintf(str, "%s %s", exe, param); + exec_on_terminal(term, str, "", 2); + mem_free(str); +} + +static int open_in_new_twterm(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + unsigned char *twterm; + if (!(twterm = getenv("LINKS_TWTERM"))) twterm = "twterm -e"; + exec_new_links(term, twterm, exe, param); + return 0; +} + +static int open_in_new_xterm(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + unsigned char *xterm; + if (!(xterm = getenv("LINKS_XTERM"))) xterm = "xterm -e"; + exec_new_links(term, xterm, exe, param); + return 0; +} + +static int open_in_new_screen(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + exec_new_links(term, "screen", exe, param); + return 0; +} + +#ifdef OS2 +static int open_in_new_vio(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + unsigned char *x = stracpy("\""); + add_to_strn(&x, exe); + add_to_strn(&x, "\""); + exec_new_links(term, "start \"Links\" /c /f /win", x, param); + mem_free(x); + return 0; +} + +static int open_in_new_fullscreen(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + unsigned char *x = stracpy("\""); + add_to_strn(&x, exe); + add_to_strn(&x, "\""); + exec_new_links(term, "start \"Links\" /c /f /fs", x, param); + mem_free(x); + return 0; +} +#endif + +#ifdef WIN32 +static int open_in_new_win32(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + exec_new_links(term, "", exe, param); + return 0; +} +#endif + +#ifdef INTERIX +static int open_in_new_interix(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + unsigned char *param_x = stracpy(param); + add_to_strn(¶m_x, "'"); + exec_new_links(term, INTERIX_START_COMMAND " '\"Links\"' posix /u /c /bin/sh -c '", exe, param_x); + mem_free(param_x); + return 0; +} +#endif + +#ifdef BEOS +static int open_in_new_be(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + exec_new_links(term, "Terminal", exe, param); + return 0; +} +#endif + +#ifdef G +static int open_in_new_g(struct terminal *term, unsigned char *exe, unsigned char *param) +{ + void *info; + unsigned char *target = NULL; + int len; + int base = 0; + unsigned char *url; + if (!cmpbeg(param, "-base-session ")) { + param = strchr(param, ' ') + 1; + base = atoi(param); + param += strcspn(param, " "); + if (*param == ' ') param++; + } + if (!cmpbeg(param, "-target ")) { + param = strchr(param, ' ') + 1; + target = param; + param += strcspn(param, " "); + if (*param == ' ') *param++ = 0; + } + url = param; + if (!(info = create_session_info(base, url, target, &len))) + return -1; + return attach_g_terminal(info, len); +} +#endif + +static struct { + int env; + int (*open_window_fn)(struct terminal *term, unsigned char *, unsigned char *); + unsigned char *text; + unsigned char *hk; +} oinw[] = { + {ENV_XWIN, open_in_new_xterm, TEXT_(T_XTERM), TEXT_(T_HK_XTERM)}, + {ENV_TWIN, open_in_new_twterm, TEXT_(T_TWTERM), TEXT_(T_HK_TWTERM)}, + {ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN)}, +#ifdef OS2 + {ENV_OS2VIO, open_in_new_vio, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)}, + {ENV_OS2VIO, open_in_new_fullscreen, TEXT_(T_FULL_SCREEN), TEXT_(T_HK_FULL_SCREEN)}, +#endif +#ifdef WIN32 + {ENV_WIN32, open_in_new_win32, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)}, +#endif +#ifdef INTERIX + {ENV_INTERIX, open_in_new_interix, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)}, +#endif +#ifdef BEOS + {ENV_BE, open_in_new_be, TEXT_(T_BEOS_TERMINAL), TEXT_(T_HK_BEOS_TERMINAL)}, +#endif +#ifdef G + {ENV_G, open_in_new_g, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)}, +#endif + {0, NULL, NULL, NULL} +}; + +struct open_in_new *get_open_in_new(int environment) +{ + int i; + struct open_in_new *oin = DUMMY; + int noin = 0; + if (anonymous) return NULL; + if (environment & ENV_G) environment = ENV_G; + for (i = 0; oinw[i].env; i++) if ((environment & oinw[i].env) == oinw[i].env) { + if ((unsigned)noin > MAXINT / sizeof(struct open_in_new) - 2) overalloc(); + oin = mem_realloc(oin, (noin + 2) * sizeof(struct open_in_new)); + oin[noin].text = oinw[i].text; + oin[noin].hk = oinw[i].hk; + oin[noin].open_window_fn = oinw[i].open_window_fn; + noin++; + oin[noin].text = NULL; + oin[noin].hk = NULL; + oin[noin].open_window_fn = NULL; + } + if (oin == DUMMY) return NULL; + return oin; +} + +int can_resize_window(struct terminal *term) +{ +#if defined(OS2) || defined(WIN32) + if (!strncmp(term->term, "xterm", 5)) return 0; + if (term->environment & (ENV_OS2VIO | ENV_WIN32)) return 1; +#endif + return 0; +} + +int can_open_os_shell(int environment) +{ +#ifdef OS2 + if (environment & ENV_XWIN) return 0; +#endif +#ifdef WIN32 + if (!(environment & ENV_WIN32)) return 0; +#endif +#ifdef BEOS + if (!(environment & ENV_BE)) return 0; +#endif +#ifdef G + if (F && drv->flags & GD_NO_OS_SHELL) return 0; +#endif + return 1; +} + +#ifndef OS2 +void set_highpri(void) +{ +} +#else +void set_highpri(void) +{ + DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0); +} +#endif + +#ifndef HAVE_SNPRINTF + +#define B_SZ 65536 + +static char snprtintf_buffer[B_SZ]; + +int my_snprintf(char *str, int n, char *f, ...) +{ + int i; + va_list l; + if (!n) return -1; + va_start(l, f); + vsprintf(snprtintf_buffer, f, l); + va_end(l); + i = strlen(snprtintf_buffer); + if (i >= B_SZ) { + error("String size too large!"); + fatal_tty_exit(); + exit(RET_FATAL); + } + if (i >= n) { + memcpy(str, snprtintf_buffer, n); + str[n - 1] = 0; + return -1; + } + strcpy(str, snprtintf_buffer); + return i; +} + +#endif + +#ifndef HAVE_RAISE +int raise(int s) +{ +#ifdef HAVE_GETPID + pid_t p; + EINTRLOOP(p, getpid()); + if (p == -1) return -1; + return kill(p, s); +#else + return 0; +#endif +}; +#endif +#ifndef HAVE_GETTIMEOFDAY +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + time_t t; + EINTRLOOP(t, time(NULL)); + if (tv) tv->tv_sec = t, tv->tv_usec = 0; + if (tz) tz->tz_minuteswest = tz->tz_dsttime = 0; + return 0; +} +#endif +#ifndef HAVE_TEMPNAM +char *tempnam(const char *dir, const char *pfx) +{ + static int counter = 0; + unsigned char *d, *s, *a; + int l; + if (!(d = getenv("TMPDIR"))) { + if (dir) d = (unsigned char *)dir; + else if (!(d = getenv("TMP")) && !(d = getenv("TEMP"))) { +#ifdef P_tmpdir + d = P_tmpdir; +#else + d = "/tmp"; +#endif + } + } + l = 0; + s = init_str(); + add_to_str(&s, &l, d); + if (s[0] && s[strlen(s) - 1] != '/') add_chr_to_str(&s, &l, '/'); + add_to_str(&s, &l, (unsigned char *)pfx); + add_num_to_str(&s, &l, counter++); + a = strdup(s); + mem_free(s); + return a; +} +#endif +#ifndef HAVE_SIGFILLSET +int sigfillset(sigset_t *set) +{ + memset(set, -1, sizeof(sigset_t)); + return 0; +} +#endif +#ifndef HAVE_STRTOUL +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + if (*nptr == '-') { + if (endptr) *endptr = nptr; + return 0; + } + return (unsigned long)strtol(nptr,endptr,base); +}; +#endif +#ifndef HAVE_STRLEN +size_t strlen(const char *s) +{ + size_t len = 0; + while (s[len]) len++; + return len; +} +#endif +#ifndef HAVE_STRCPY +char *strcpy(char *dst, const char *src) +{ + return memcpy(dst, src, strlen(src) + 1); +} +#endif +#ifndef HAVE_STRCHR +char *strchr(const char *s, int c) +{ + do { + if (*s == (char)c) + return (char *)s; + } while (*s++); + return NULL; +} +#endif +#ifndef HAVE_STRRCHR +char *strrchr(const char *s, int c) +{ + char *ret = NULL; + do { + if (*s == (char)c) + ret = (char *)s; + } while (*s++); + return ret; +} +#endif +#ifndef HAVE_STRCMP +int strcmp(const char *s1, const char *s2) +{ + while (1) { + if (*s1 != *s2) { + return (int)(unsigned char)*s1 - (int)(unsigned char)*s2; + } + if (!*s1) break; + s1++, s2++; + } + return 0; +} +#endif +#ifndef HAVE_STRNCMP +int strncmp(const char *s1, const char *s2, size_t n) +{ + while (n--) { + if (*s1 != *s2) { + return (int)(unsigned char)*s1 - (int)(unsigned char)*s2; + } + if (!*s1) break; + s1++, s2++; + } + return 0; +} +#endif +#ifndef HAVE_STRCSPN +size_t strcspn(const char *s, const char *reject) +{ + size_t r; + for (r = 0; *s; r++, s++) { + const char *rj; + for (rj = reject; *rj; rj++) if (*s == *rj) goto brk; + } + brk: + return r; +} +#endif +#ifndef HAVE_STRSTR +char *strstr(const char *haystack, const char *needle) +{ + size_t hs = strlen(haystack); + size_t ns = strlen(needle); + while (hs >= ns) { + if (!memcmp(haystack, needle, ns)) return (char *)haystack; + haystack++, hs--; + } + return NULL; +} +#endif +#ifndef HAVE_MEMMOVE +void *memmove(void *dst0, const void *src0, size_t length) +{ + unsigned char *dst = dst0; + const unsigned char *src = src0; + + if ((const unsigned char *)dst == src || !length) + return dst0; + + if ((const unsigned char *)dst <= src) { + while (length--) *dst++ = *src++; + } else { + dst += length - 1; + src += length - 1; + while (length--) *dst-- = *src--; + } + return dst0; +} +#endif +#ifndef HAVE_STRERROR +extern char *sys_errlist[]; +extern int sys_nerr; +char *strerror(int errnum) +{ + if (errnum < 0 || errnum >= sys_nerr) return "Unknown error"; + return sys_errlist[errnum]; +}; +#endif |