mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
1227 lines
26 KiB
C++
1227 lines
26 KiB
C++
#ifdef __DJGPP
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "elinks.h"
|
|
|
|
#define DOS_OVERRIDES_SELF
|
|
|
|
#include <pc.h>
|
|
#include <dpmi.h>
|
|
#include <bios.h>
|
|
#include <go32.h>
|
|
#include <libc/dosio.h>
|
|
#include <sys/exceptn.h>
|
|
#include <sys/movedata.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/socket.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <values.h>
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
#include "ecmascript/quickjs/heartbeat.h"
|
|
#endif
|
|
#include "intl/libintl.h"
|
|
#include "main/main.h"
|
|
#include "main/select.h"
|
|
#include "network/connection.h"
|
|
#include "osdep/dos/dos.h"
|
|
#include "terminal/event.h"
|
|
#include "util/error.h"
|
|
#include "util/memory.h"
|
|
|
|
#define VIRTUAL_PIPE_SIZE 512
|
|
|
|
#define DOS_MOUSE_FLUSH_TIME 300
|
|
|
|
//#define TRACE_PIPES 1
|
|
|
|
#undef read
|
|
#undef write
|
|
#undef pipe
|
|
#undef close
|
|
#undef select
|
|
|
|
#ifdef HAVE_LONG_LONG
|
|
typedef unsigned long long uttime;
|
|
typedef unsigned long long tcount;
|
|
#else
|
|
typedef unsigned long uttime;
|
|
typedef unsigned long tcount;
|
|
#endif
|
|
|
|
#define DUMMY ((void *)-1L)
|
|
|
|
#ifdef __ICC
|
|
/* ICC OpenMP bug */
|
|
#define overalloc_condition 0
|
|
#else
|
|
#define overalloc_condition 1
|
|
#endif
|
|
|
|
#define overalloc_at(f, l) \
|
|
do { \
|
|
ERROR("ERROR: attempting to allocate too large block at %s:%d", f, l);\
|
|
fflush(stdout); \
|
|
fflush(stderr); \
|
|
exit(RET_FATAL); \
|
|
} while (overalloc_condition) /* while (1) is not a typo --- it's here to allow the compiler
|
|
that doesn't know that fatal_exit doesn't return to do better
|
|
optimizations */
|
|
|
|
#define overalloc() overalloc_at(__FILE__, __LINE__)
|
|
|
|
int
|
|
is_xterm(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_system_env(void)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
set_nonblocking_fd(int fd)
|
|
{
|
|
#ifdef O_NONBLOCK
|
|
int rs;
|
|
EINTRLOOP(rs, fcntl(fd, F_SETFL, O_NONBLOCK));
|
|
#elif defined(FIONBIO)
|
|
int rs;
|
|
int on = 1;
|
|
EINTRLOOP(rs, ioctl(fd, FIONBIO, &on));
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static uttime
|
|
get_absolute_time(void)
|
|
{
|
|
struct timeval tv;
|
|
int rs;
|
|
EINTRLOOP(rs, gettimeofday(&tv, NULL));
|
|
|
|
if (rs) {
|
|
ERROR("gettimeofday failed: %d", errno);
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
exit(RET_FATAL);
|
|
}
|
|
|
|
return (uttime)tv.tv_sec * 1000 + (unsigned)tv.tv_usec / 1000;
|
|
}
|
|
|
|
static uttime
|
|
get_time(void)
|
|
{
|
|
#if defined(OS2) || defined(WIN)
|
|
static unsigned last_tim = 0;
|
|
static uttime add = 0;
|
|
unsigned tim;
|
|
#if defined(OS2)
|
|
int rc;
|
|
rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &tim, sizeof tim);
|
|
if (rc) {
|
|
ERROR("DosQuerySysInfo failed: %d", rc);
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
exit(RET_FATAL);
|
|
}
|
|
#elif defined(WIN)
|
|
tim = GetTickCount();
|
|
#endif
|
|
if (tim < last_tim) {
|
|
add += (uttime)1 << 31 << 1;
|
|
}
|
|
last_tim = tim;
|
|
return tim | add;
|
|
#else
|
|
#if defined(HAVE_CLOCK_GETTIME) && defined(TIME_WITH_SYS_TIME) && (defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC))
|
|
struct timespec ts;
|
|
int rs;
|
|
#if defined(CLOCK_MONOTONIC_RAW)
|
|
EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC_RAW, &ts));
|
|
if (!rs) return (uttime)ts.tv_sec * 1000 + (unsigned)ts.tv_nsec / 1000000;
|
|
#endif
|
|
#if defined(CLOCK_MONOTONIC)
|
|
EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC, &ts));
|
|
if (!rs) return (uttime)ts.tv_sec * 1000 + (unsigned)ts.tv_nsec / 1000000;
|
|
#endif
|
|
#endif
|
|
return get_absolute_time();
|
|
#endif
|
|
}
|
|
|
|
#define fd_lock() do { } while (0)
|
|
#define fd_unlock() do { } while (0)
|
|
|
|
#ifndef SA_RESTART
|
|
#define SA_RESTART 0
|
|
#endif
|
|
|
|
static void
|
|
new_fd_cloexec(int fd)
|
|
{
|
|
int rs;
|
|
EINTRLOOP(rs, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
|
}
|
|
|
|
static int
|
|
cleanup_fds(void)
|
|
{
|
|
#ifdef ENFILE
|
|
if (errno == ENFILE) {
|
|
abort_background_connections();
|
|
return 0;
|
|
}
|
|
#endif
|
|
#ifdef EMFILE
|
|
if (errno == EMFILE) {
|
|
abort_background_connections();
|
|
return 0;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
c_socket(int d, int t, int p)
|
|
{
|
|
int h;
|
|
do {
|
|
fd_lock();
|
|
EINTRLOOP(h, socket(d, t, p));
|
|
if (h != -1) new_fd_cloexec(h);
|
|
fd_unlock();
|
|
} while (h == -1 && cleanup_fds());
|
|
return h;
|
|
}
|
|
|
|
|
|
/*
|
|
* Asynchronous exits from signal handler cause a crash if they interrupt
|
|
* networking in a wrong place. So, we use synchronous exit.
|
|
*/
|
|
static volatile unsigned char break_pressed = 0;
|
|
static volatile unsigned char break_exiting = 0;
|
|
|
|
void dos_poll_break(void)
|
|
{
|
|
if (break_pressed && !break_exiting) {
|
|
break_exiting = 1;
|
|
ERROR("Exiting on Ctrl+Break");
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
exit(RET_FATAL);
|
|
}
|
|
}
|
|
|
|
static void sigbreak(int sig)
|
|
{
|
|
break_pressed = 1;
|
|
}
|
|
|
|
void get_terminal_size(int fd, int *x, int *y)
|
|
{
|
|
*x = ScreenCols();
|
|
*y = ScreenRows();
|
|
}
|
|
|
|
void handle_terminal_resize(int fd, void (*fn)(void))
|
|
{
|
|
}
|
|
|
|
void
|
|
unhandle_terminal_resize(int fd)
|
|
{
|
|
}
|
|
|
|
static size_t init_seq_len;
|
|
|
|
static unsigned char screen_initialized = 0;
|
|
static unsigned char *screen_backbuffer = NULL;
|
|
static int screen_backbuffer_x;
|
|
static int screen_backbuffer_y;
|
|
static int saved_cursor_x;
|
|
static int saved_cursor_y;
|
|
static unsigned char screen_default_attr;
|
|
|
|
static unsigned cursor_x;
|
|
static unsigned cursor_y;
|
|
static unsigned current_attr;
|
|
|
|
static unsigned char dos_mouse_initialized = 0;
|
|
static unsigned char dos_mouse_buttons;
|
|
|
|
static int dos_mouse_last_x;
|
|
static int dos_mouse_last_y;
|
|
static int dos_mouse_last_button;
|
|
static uttime dos_mouse_time;
|
|
|
|
static struct interlink_event *dos_mouse_queue = NULL;
|
|
static int dos_mouse_queue_n;
|
|
|
|
static void (*txt_mouse_handler)(void *, char *, int) = NULL;
|
|
static void *txt_mouse_data;
|
|
|
|
static int dos_mouse_coord(int v)
|
|
{
|
|
#if 0
|
|
if (!F) v /= 8;
|
|
#endif
|
|
return v / 8;
|
|
}
|
|
|
|
static void dos_mouse_show(void)
|
|
{
|
|
if (dos_mouse_initialized) { // && !F) {
|
|
__dpmi_regs r;
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 1;
|
|
__dpmi_int(0x33, &r);
|
|
}
|
|
}
|
|
|
|
static void dos_mouse_hide(void)
|
|
{
|
|
if (dos_mouse_initialized) { // && !F) {
|
|
__dpmi_regs r;
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 2;
|
|
__dpmi_int(0x33, &r);
|
|
}
|
|
}
|
|
|
|
static void dos_mouse_init(unsigned x, unsigned y)
|
|
{
|
|
__dpmi_regs r;
|
|
memset(&r, 0, sizeof r);
|
|
__dpmi_int(0x33, &r);
|
|
if (r.x.ax != 0xffff) return;
|
|
dos_mouse_buttons = r.x.bx == 3 ? 3 : 2;
|
|
dos_mouse_initialized = 1;
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 7;
|
|
r.x.cx = 0;
|
|
r.x.dx = x - 1;
|
|
__dpmi_int(0x33, &r);
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 8;
|
|
r.x.cx = 0;
|
|
r.x.dx = y - 1;
|
|
__dpmi_int(0x33, &r);
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 3;
|
|
__dpmi_int(0x33, &r);
|
|
dos_mouse_last_x = dos_mouse_coord(r.x.cx);
|
|
dos_mouse_last_y = dos_mouse_coord(r.x.dx);
|
|
dos_mouse_last_button = r.x.bx;
|
|
dos_mouse_time = get_time();
|
|
}
|
|
|
|
void dos_mouse_terminate(void)
|
|
{
|
|
mem_free_set(&dos_mouse_queue, NULL);
|
|
dos_mouse_queue_n = 0;
|
|
dos_mouse_hide();
|
|
}
|
|
|
|
static void dos_mouse_enqueue(int x, int y, int b)
|
|
{
|
|
if (dos_mouse_queue_n && ((b & BM_ACT) == B_DRAG || (b & BM_ACT) == B_MOVE) && (b & BM_ACT) == (dos_mouse_queue[dos_mouse_queue_n - 1].info.mouse.button & BM_ACT)) {
|
|
dos_mouse_queue_n--;
|
|
goto set_last;
|
|
}
|
|
if ((unsigned)dos_mouse_queue_n > (unsigned)MAXINT / sizeof(struct interlink_event) - 1) {
|
|
overalloc();
|
|
}
|
|
if (dos_mouse_queue == NULL) {
|
|
dos_mouse_queue = (struct interlink_event *)mem_alloc((dos_mouse_queue_n + 1) * sizeof(struct interlink_event));
|
|
} else {
|
|
dos_mouse_queue = (struct interlink_event *)mem_realloc(dos_mouse_queue, (dos_mouse_queue_n + 1) * sizeof(struct interlink_event));
|
|
}
|
|
set_last:
|
|
dos_mouse_queue[dos_mouse_queue_n].ev = EVENT_MOUSE;
|
|
dos_mouse_queue[dos_mouse_queue_n].info.mouse.x = x;
|
|
dos_mouse_queue[dos_mouse_queue_n].info.mouse.y = y;
|
|
dos_mouse_queue[dos_mouse_queue_n].info.mouse.button = b;
|
|
dos_mouse_queue_n++;
|
|
}
|
|
|
|
static int dos_mouse_button(int b)
|
|
{
|
|
switch (b) {
|
|
default:
|
|
case 0: return B_LEFT;
|
|
case 1: return B_RIGHT;
|
|
case 2: return B_MIDDLE;
|
|
}
|
|
}
|
|
|
|
static void dos_mouse_poll(void)
|
|
{
|
|
int i;
|
|
int cx, cy;
|
|
__dpmi_regs r;
|
|
dos_poll_break();
|
|
if (dos_mouse_initialized) {
|
|
if (dos_mouse_initialized == 1 && get_time() - dos_mouse_time > DOS_MOUSE_FLUSH_TIME)
|
|
dos_mouse_initialized = 2;
|
|
for (i = 0; i < dos_mouse_buttons; i++) {
|
|
if (dos_mouse_initialized == 1 && i > 0) {
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 5;
|
|
r.x.bx = i;
|
|
__dpmi_int(0x33, &r);
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 6;
|
|
r.x.bx = i;
|
|
__dpmi_int(0x33, &r);
|
|
continue;
|
|
}
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = !(dos_mouse_last_button & (1 << i)) ? 5 : 6;
|
|
r.x.bx = i;
|
|
__dpmi_int(0x33, &r);
|
|
px:
|
|
if (r.x.bx) {
|
|
dos_mouse_last_x = dos_mouse_coord(r.x.cx);
|
|
dos_mouse_last_y = dos_mouse_coord(r.x.dx);
|
|
dos_mouse_last_button ^= 1 << i;
|
|
dos_mouse_enqueue(dos_mouse_last_x, dos_mouse_last_y, dos_mouse_button(i) | (dos_mouse_last_button & (1 << i) ? B_DOWN : B_UP));
|
|
/*printf("%s %d %d\n", dos_mouse_last_button & (1 << i) ? "press" : "release", r.x.cx, r.x.dx);*/
|
|
if (!((dos_mouse_last_button ^ r.x.ax) & (1 << i))) {
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = !(dos_mouse_last_button & (1 << i)) ? 5 : 6;
|
|
r.x.bx = i;
|
|
__dpmi_int(0x33, &r);
|
|
if ((dos_mouse_last_button ^ r.x.ax) & (1 << i))
|
|
goto px;
|
|
}
|
|
}
|
|
}
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 3;
|
|
__dpmi_int(0x33, &r);
|
|
cx = dos_mouse_coord(r.x.cx);
|
|
cy = dos_mouse_coord(r.x.dx);
|
|
if (r.h.bh) {
|
|
dos_mouse_enqueue(cx, cy, (char)r.h.bh < 0 ? (B_DOWN | B_WHEEL_UP) : (B_DOWN | B_WHEEL_DOWN));
|
|
goto x;
|
|
}
|
|
if (cx != dos_mouse_last_x || cy != dos_mouse_last_y) {
|
|
for (i = 0; i < dos_mouse_buttons; i++)
|
|
if (dos_mouse_last_button & (1 << i)) {
|
|
dos_mouse_enqueue(cx, cy, B_DRAG | dos_mouse_button(i));
|
|
goto x;
|
|
}
|
|
// if (F) dos_mouse_enqueue(cx, cy, B_MOVE);
|
|
x:
|
|
dos_mouse_last_x = cx;
|
|
dos_mouse_last_y = cy;
|
|
}
|
|
}
|
|
#if defined(G) && defined(GRDRV_GRX)
|
|
if (grx_mouse_initialized) {
|
|
grx_mouse_poll();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void *handle_mouse(int cons, void (*fn)(void *, char *, int), void *data)
|
|
{
|
|
int x, y;
|
|
get_terminal_size(cons, &x, &y);
|
|
dos_mouse_init(x * 8, y * 8);
|
|
|
|
if (!dos_mouse_initialized) return NULL;
|
|
dos_mouse_show();
|
|
txt_mouse_handler = fn;
|
|
txt_mouse_data = data;
|
|
|
|
return DUMMY;
|
|
}
|
|
|
|
void unhandle_mouse(void *data)
|
|
{
|
|
dos_mouse_terminate();
|
|
txt_mouse_handler = NULL;
|
|
}
|
|
|
|
void
|
|
suspend_mouse(void *data)
|
|
{
|
|
}
|
|
|
|
void
|
|
resume_mouse(void *data)
|
|
{
|
|
}
|
|
|
|
void want_draw(void)
|
|
{
|
|
dos_mouse_hide();
|
|
}
|
|
|
|
void done_draw(void)
|
|
{
|
|
dos_mouse_show();
|
|
}
|
|
|
|
static int dos_mouse_event(void)
|
|
{
|
|
if (dos_mouse_queue_n) {
|
|
if (/*!F &&*/ txt_mouse_handler) {
|
|
struct interlink_event *q = dos_mouse_queue;
|
|
int ql = dos_mouse_queue_n;
|
|
dos_mouse_queue = NULL;
|
|
dos_mouse_queue_n = 0;
|
|
txt_mouse_handler(txt_mouse_data, (char *)(void *)q, ql * sizeof(struct interlink_event));
|
|
mem_free(q);
|
|
return 1;
|
|
}
|
|
}
|
|
#if defined(G) && defined(GRDRV_GRX)
|
|
if (grx_mouse_initialized) {
|
|
return grx_mouse_event();
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void save_terminal(void)
|
|
{
|
|
unsigned char *sc;
|
|
want_draw();
|
|
screen_backbuffer_x = ScreenCols();
|
|
screen_backbuffer_y = ScreenRows();
|
|
screen_default_attr = ScreenAttrib;
|
|
if (screen_backbuffer) {
|
|
sc = screen_backbuffer;
|
|
screen_backbuffer = NULL;
|
|
mem_free(sc);
|
|
}
|
|
sc = (unsigned char *)mem_alloc(2 * screen_backbuffer_x * screen_backbuffer_y);
|
|
ScreenRetrieve(sc);
|
|
ScreenGetCursor(&saved_cursor_y, &saved_cursor_x);
|
|
screen_backbuffer = sc;
|
|
done_draw();
|
|
}
|
|
|
|
void restore_terminal(void)
|
|
{
|
|
want_draw();
|
|
if (screen_backbuffer) {
|
|
unsigned char *sc;
|
|
if (ScreenCols() == screen_backbuffer_x && ScreenRows() == screen_backbuffer_y) {
|
|
ScreenUpdate(screen_backbuffer);
|
|
ScreenSetCursor(saved_cursor_y, saved_cursor_x);
|
|
}
|
|
sc = screen_backbuffer;
|
|
screen_backbuffer = NULL;
|
|
mem_free(sc);
|
|
}
|
|
done_draw();
|
|
}
|
|
|
|
static void ansi_initialize(void)
|
|
{
|
|
if (screen_initialized)
|
|
return;
|
|
|
|
ScreenClear();
|
|
cursor_x = 0;
|
|
cursor_y = 0;
|
|
current_attr = screen_default_attr;
|
|
screen_initialized = 1;
|
|
}
|
|
|
|
static void ansi_terminate(void)
|
|
{
|
|
if (!screen_initialized)
|
|
return;
|
|
|
|
ScreenSetCursor(0, 0);
|
|
screen_initialized = 0;
|
|
}
|
|
|
|
static unsigned ansi2pc(unsigned c)
|
|
{
|
|
return ((c & 4) >> 2) | (c & 2) | ((c & 1) << 2);
|
|
}
|
|
|
|
static unsigned char init_seq[] = "\033)0\0337";
|
|
|
|
static inline
|
|
unsigned upcase(unsigned a)
|
|
{
|
|
if (a >= 'a' && a <= 'z') a -= 0x20;
|
|
return a;
|
|
}
|
|
|
|
static inline
|
|
unsigned locase(unsigned a)
|
|
{
|
|
if (a >= 'A' && a <= 'Z') a += 0x20;
|
|
return a;
|
|
}
|
|
static inline
|
|
int srch_cmp(unsigned char c1, unsigned char c2)
|
|
{
|
|
return upcase(c1) != upcase(c2);
|
|
}
|
|
|
|
static void ansi_write(const unsigned char *str, size_t size)
|
|
{
|
|
if (!screen_initialized) {
|
|
if (size >= init_seq_len && !memcmp(str, init_seq, init_seq_len)) {
|
|
ansi_initialize();
|
|
goto process_ansi;
|
|
}
|
|
write(1, str, size);
|
|
return;
|
|
}
|
|
process_ansi:
|
|
while (size--) {
|
|
unsigned char c = *str++;
|
|
unsigned char buffer[128];
|
|
unsigned buf_size;
|
|
unsigned clen;
|
|
unsigned x, y;
|
|
switch (c) {
|
|
case 7:
|
|
continue;
|
|
case 10:
|
|
cursor_y++;
|
|
/*-fallthrough*/
|
|
case 13:
|
|
cursor_x = 0;
|
|
break;
|
|
case 27:
|
|
if (!size--) goto ret;
|
|
switch (*str++) {
|
|
case ')':
|
|
if (!size--) goto ret;
|
|
str++;
|
|
continue;
|
|
case '7':
|
|
default:
|
|
continue;
|
|
case '8':
|
|
ansi_terminate();
|
|
goto ret2;
|
|
case '[':
|
|
clen = 0;
|
|
while (1) {
|
|
unsigned char u;
|
|
if (clen >= size) goto ret;
|
|
u = upcase(str[clen]);
|
|
if (u >= 'A' && u <= 'Z')
|
|
break;
|
|
clen++;
|
|
}
|
|
}
|
|
if (clen >= sizeof(buffer)) goto ret;
|
|
memcpy(buffer, str, clen);
|
|
buffer[clen] = 0;
|
|
switch (str[clen]) {
|
|
case 'J':
|
|
if (!strcmp((const char *) buffer, "2"))
|
|
ScreenClear();
|
|
break;
|
|
case 'H':
|
|
if (sscanf((const char *) buffer, "%u;%u", &y, &x) == 2) {
|
|
cursor_x = x - 1;
|
|
cursor_y = y - 1;
|
|
}
|
|
break;
|
|
case 'm':
|
|
while (buffer[0] >= '0' && buffer[0] < '9') {
|
|
unsigned long a;
|
|
char *e;
|
|
a = strtoul((const char *) buffer, &e, 10);
|
|
if (*e == ';') e++;
|
|
memmove(buffer, e, strlen((const char *) e) + 1);
|
|
switch (a) {
|
|
case 0:
|
|
current_attr = screen_default_attr;
|
|
break;
|
|
case 1:
|
|
current_attr |= 0x08;
|
|
break;
|
|
case 7:
|
|
current_attr = ((screen_default_attr & 0x70) >> 4) | ((screen_default_attr & 0x07) << 4);
|
|
break;
|
|
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
|
current_attr = (current_attr & 0x78) | ansi2pc(a - 30);
|
|
break;
|
|
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
|
current_attr = (current_attr & 0x0f) | (ansi2pc(a - 40) << 4);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
str += clen + 1;
|
|
size -= clen + 1;
|
|
continue;
|
|
default:
|
|
buffer[0] = c;
|
|
buf_size = 1;
|
|
while (size && *str >= ' ' && buf_size < sizeof(buffer) - 1) {
|
|
buffer[buf_size++] = *str++;
|
|
size--;
|
|
}
|
|
buffer[buf_size] = 0;
|
|
ScreenPutString((const char *) buffer, current_attr, cursor_x, cursor_y);
|
|
cursor_x += buf_size;
|
|
break;
|
|
}
|
|
}
|
|
ret:
|
|
ScreenSetCursor(cursor_y, cursor_x);
|
|
ret2:;
|
|
}
|
|
|
|
#ifdef DOS_EXTRA_KEYBOARD
|
|
|
|
static short dos_buffered_char = -1;
|
|
|
|
static int dos_select_keyboard(void)
|
|
{
|
|
int bk;
|
|
if (dos_buffered_char >= 0) return 1;
|
|
bk = bioskey(0x11);
|
|
return !!bk;
|
|
}
|
|
|
|
static int dos_read_keyboard(void *buf, size_t size)
|
|
{
|
|
int k;
|
|
if (!size) return 0;
|
|
if (dos_buffered_char >= 0) {
|
|
*(unsigned char *)buf = dos_buffered_char;
|
|
dos_buffered_char = -1;
|
|
return 1;
|
|
}
|
|
k = getkey();
|
|
if (!k) return 0;
|
|
/*printf("returned key %04x\n", k);*/
|
|
if (k < 0x100) {
|
|
*(unsigned char *)buf = k;
|
|
return 1;
|
|
} else {
|
|
*(unsigned char *)buf = 0;
|
|
if (size >= 2) {
|
|
*((unsigned char *)buf + 1) = k;
|
|
return 2;
|
|
} else {
|
|
dos_buffered_char = k & 0xff;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static inline void pipe_lock(void)
|
|
{
|
|
}
|
|
|
|
static inline void pipe_unlock(void)
|
|
{
|
|
}
|
|
|
|
static inline void pipe_unlock_wait(void)
|
|
{
|
|
}
|
|
|
|
static inline void pipe_wake(void)
|
|
{
|
|
}
|
|
|
|
#include "vpipe.inc"
|
|
|
|
int dos_pipe(int fd[2])
|
|
{
|
|
int r = vpipe_create(fd);
|
|
/*printf("dos_pipe: (%d) : %d,%d\n", r, fd[0], fd[1]);*/
|
|
return r;
|
|
}
|
|
|
|
int dos_read(int fd, void *buf, size_t size)
|
|
{
|
|
int r;
|
|
dos_mouse_poll();
|
|
r = vpipe_read(fd, buf, size);
|
|
/*printf("dos_read(%d,%d) : %d,%d\n", r, errno, fd, size);*/
|
|
if (r != -2) return r;
|
|
#ifdef DOS_EXTRA_KEYBOARD
|
|
if (fd == 0) return dos_read_keyboard(buf, size);
|
|
#endif
|
|
return read(fd, buf, size);
|
|
}
|
|
|
|
int dos_write(int fd, const void *buf, size_t size)
|
|
{
|
|
int r;
|
|
dos_mouse_poll();
|
|
r = vpipe_write(fd, buf, size);
|
|
/*printf("dos_write(%d,%d) : %d,%d\n", r, errno, fd, size);*/
|
|
if (r != -2) return r;
|
|
if (fd == 1) {
|
|
ansi_write((const unsigned char *)buf, size);
|
|
return size;
|
|
}
|
|
return write(fd, buf, size);
|
|
}
|
|
|
|
int dos_close(int fd)
|
|
{
|
|
int r;
|
|
r = vpipe_close(fd);
|
|
if (r != -2) return r;
|
|
return close(fd);
|
|
}
|
|
|
|
int dos_select(int n, fd_set *rs, fd_set *ws, fd_set *es, struct timeval *t, int from_main_loop)
|
|
{
|
|
int i;
|
|
int last_pass = 0;
|
|
int ret_cnt = 0;
|
|
|
|
int r;
|
|
fd_set rsb, wsb, esb;
|
|
struct timeval xtime;
|
|
|
|
dos_mouse_poll();
|
|
|
|
pipe_lock();
|
|
for (i = 0; i < n; i++) {
|
|
int ts = 0;
|
|
if (rs && FD_ISSET(i, rs)) {
|
|
int signaled = 0;
|
|
if (pipe_desc[i]) {
|
|
if (vpipe_may_read(i))
|
|
signaled = 1;
|
|
else
|
|
FD_CLR(i, rs);
|
|
/*printf("dos_select_read(%d) : %d\n", i, vpipe_may_read(i));*/
|
|
} else {
|
|
}
|
|
if (!last_pass) {
|
|
if (signaled) {
|
|
clear_inactive(rs, i);
|
|
clear_inactive(ws, i);
|
|
clear_inactive(es, i);
|
|
last_pass = 1;
|
|
}
|
|
} else {
|
|
if (!signaled) FD_CLR(i, rs);
|
|
}
|
|
ts |= signaled;
|
|
}
|
|
if (ws && FD_ISSET(i, ws)) {
|
|
int signaled = 0;
|
|
if (pipe_desc[i]) {
|
|
if (vpipe_may_write(i))
|
|
signaled = 1;
|
|
else
|
|
FD_CLR(i, ws);
|
|
/*printf("dos_select_write(%d) : %d\n", i, vpipe_may_write(i));*/
|
|
} else {
|
|
}
|
|
if (!last_pass) {
|
|
if (signaled) {
|
|
clear_inactive(rs, i + 1);
|
|
clear_inactive(ws, i);
|
|
clear_inactive(es, i);
|
|
last_pass = 1;
|
|
}
|
|
} else {
|
|
if (!signaled) FD_CLR(i, ws);
|
|
}
|
|
ts |= signaled;
|
|
}
|
|
if (es && FD_ISSET(i, es)) {
|
|
int signaled = 0;
|
|
if (pipe_desc[i]) {
|
|
FD_CLR(i, es);
|
|
} else {
|
|
}
|
|
if (!last_pass) {
|
|
if (signaled) {
|
|
clear_inactive(rs, i + 1);
|
|
clear_inactive(ws, i + 1);
|
|
clear_inactive(es, i);
|
|
last_pass = 1;
|
|
}
|
|
} else {
|
|
if (!signaled) FD_CLR(i, es);
|
|
}
|
|
ts |= signaled;
|
|
}
|
|
if (last_pass) ret_cnt += ts;
|
|
}
|
|
pipe_unlock();
|
|
if (last_pass) {
|
|
/*printf("ret_cnt: %d\n", ret_cnt);*/
|
|
return ret_cnt;
|
|
}
|
|
/*printf("real select\n");*/
|
|
/*return select(n, rs, ws, es, t);*/
|
|
if (rs) rsb = *rs;
|
|
else FD_ZERO(&rsb);
|
|
if (ws) wsb = *ws;
|
|
else FD_ZERO(&wsb);
|
|
if (es) esb = *es;
|
|
else FD_ZERO(&esb);
|
|
if (t) {
|
|
EINTRLOOP(r, gettimeofday(&xtime, NULL));
|
|
if (r) {
|
|
ERROR("gettimeofday failed: %d", errno);
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
exit(RET_FATAL);
|
|
}
|
|
xtime.tv_usec += t->tv_usec;
|
|
if (xtime.tv_usec >= 1000000) {
|
|
xtime.tv_usec -= 1000000;
|
|
xtime.tv_sec++;
|
|
}
|
|
xtime.tv_sec += t->tv_sec;
|
|
}
|
|
while (1) {
|
|
struct timeval zero = { 0, 0 };
|
|
struct timeval now;
|
|
#ifdef DOS_EXTRA_KEYBOARD
|
|
if (rs && FD_ISSET(0, rs)) {
|
|
if (dos_select_keyboard()) {
|
|
FD_ZERO(rs);
|
|
FD_SET(0, rs);
|
|
if (ws) FD_ZERO(ws);
|
|
if (es) FD_ZERO(es);
|
|
if (from_main_loop && dos_mouse_event())
|
|
check_bottom_halves();
|
|
return 1;
|
|
}
|
|
FD_CLR(0, rs);
|
|
}
|
|
#endif
|
|
if (from_main_loop && dos_mouse_event()) {
|
|
check_bottom_halves();
|
|
return 0;
|
|
}
|
|
r = select(n, rs, ws, es, &zero);
|
|
if (r == -1 && errno == EBADF) {
|
|
/* DJGPP occasionally returns EBADF */
|
|
int re = 0;
|
|
if (rs) FD_ZERO(rs);
|
|
if (ws) FD_ZERO(ws);
|
|
if (es) FD_ZERO(es);
|
|
i = 0;
|
|
#ifdef DOS_EXTRA_KEYBOARD
|
|
i++;
|
|
#endif
|
|
for (; i < n; i++) {
|
|
fd_set rsx;
|
|
fd_set wsx;
|
|
fd_set esx;
|
|
int x, s;
|
|
if (!FD_ISSET(i, &rsb) &&
|
|
!FD_ISSET(i, &wsb) &&
|
|
!FD_ISSET(i, &esb))
|
|
continue;
|
|
FD_ZERO(&rsx);
|
|
FD_ZERO(&wsx);
|
|
FD_ZERO(&esx);
|
|
if (FD_ISSET(i, &rsb)) FD_SET(i, &rsx);
|
|
if (FD_ISSET(i, &wsb)) FD_SET(i, &wsx);
|
|
if (FD_ISSET(i, &esb)) FD_SET(i, &esx);
|
|
zero.tv_sec = 0;
|
|
zero.tv_usec = 0;
|
|
x = select(i + 1, &rsx, &wsx, &esx, &zero);
|
|
s = 0;
|
|
if (FD_ISSET(i, &rsb) && (x < 0 || (x > 0 && FD_ISSET(i, &rsx)))) FD_SET(i, rs), s = 1;
|
|
if (FD_ISSET(i, &wsb) && (x < 0 || (x > 0 && FD_ISSET(i, &wsx)))) FD_SET(i, ws), s = 1;
|
|
if (FD_ISSET(i, &esb) && (x < 0 || (x > 0 && FD_ISSET(i, &esx)))) FD_SET(i, es), s = 1;
|
|
if (s) re++;
|
|
}
|
|
if (re) return re;
|
|
r = 0;
|
|
}
|
|
if (r) return r;
|
|
EINTRLOOP(r, gettimeofday(&now, NULL));
|
|
if (r) {
|
|
ERROR("gettimeofday failed: %d", errno);
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
exit(RET_FATAL);
|
|
}
|
|
if (t) {
|
|
if (now.tv_sec > xtime.tv_sec ||
|
|
(now.tv_sec == xtime.tv_sec && now.tv_usec >= xtime.tv_usec))
|
|
return 0;
|
|
}
|
|
if (rs) *rs = rsb;
|
|
if (ws) *ws = wsb;
|
|
if (es) *es = esb;
|
|
dos_mouse_poll();
|
|
__dpmi_yield();
|
|
dos_mouse_poll();
|
|
}
|
|
}
|
|
|
|
#ifdef DOS_EXTRA_KEYBOARD
|
|
|
|
int dos_setraw(int ctl, int save)
|
|
{
|
|
__djgpp_set_ctrl_c(0);
|
|
return 0;
|
|
}
|
|
|
|
void setcooked(int ctl)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
#define RANDOM_POOL_SIZE 65536
|
|
|
|
void os_seed_random(unsigned char **pool, int *pool_size)
|
|
{
|
|
unsigned *random_pool, *tmp_pool;
|
|
int a, i;
|
|
random_pool = (unsigned *)mem_alloc(RANDOM_POOL_SIZE);
|
|
tmp_pool = (unsigned *)mem_alloc(RANDOM_POOL_SIZE);
|
|
for (a = 0; a <= 640 * 1024 - RANDOM_POOL_SIZE; a += RANDOM_POOL_SIZE) {
|
|
dosmemget(a, RANDOM_POOL_SIZE, tmp_pool);
|
|
for (i = 0; i < RANDOM_POOL_SIZE / 4; i++)
|
|
random_pool[i] += tmp_pool[i];
|
|
}
|
|
mem_free(tmp_pool);
|
|
*pool = (unsigned char *)(void *)random_pool;
|
|
*pool_size = RANDOM_POOL_SIZE;
|
|
}
|
|
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
_go32_dpmi_seginfo OldISR, NewISR;
|
|
#define TIMER 8
|
|
//Simple Example of chaining interrupt handlers
|
|
//Adopted from Matthew Mastracci's code
|
|
//macros by Shawn Hargreaves from the Allegro library for locking
|
|
//functions and variables.
|
|
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void *)&x,(long)sizeof(x));
|
|
#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x,(long)sizeof(x));
|
|
|
|
static void
|
|
TickHandler(void)
|
|
{
|
|
static int internal = 0;
|
|
|
|
if (internal++ >= 19) {
|
|
internal = 0;
|
|
check_heartbeats(NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void init_osdep(void)
|
|
{
|
|
int s, rs;
|
|
struct sigaction sa;
|
|
|
|
#ifdef _STAT_INODE
|
|
_djstat_flags |= _STAT_INODE;
|
|
#endif
|
|
#ifdef _STAT_EXEC_EXT
|
|
_djstat_flags |= _STAT_EXEC_EXT;
|
|
#endif
|
|
#ifdef _STAT_EXEC_MAGIC
|
|
_djstat_flags |= _STAT_EXEC_MAGIC;
|
|
#endif
|
|
|
|
init_seq_len = strlen((const char *) init_seq);
|
|
|
|
/* preload the packet driver */
|
|
s = c_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (s >= 0) {
|
|
EINTRLOOP(rs, close(s));
|
|
}
|
|
|
|
//tcp_cbreak(1);
|
|
|
|
memset(&sa, 0, sizeof sa);
|
|
sa.sa_handler = sigbreak;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART;
|
|
EINTRLOOP(rs, sigaction(SIGINT, &sa, NULL));
|
|
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
LOCK_FUNCTION(TickHandler);
|
|
LOCK_FUNCTION(check_heartbeats);
|
|
//load the address of the old timer ISR into the OldISR structure
|
|
_go32_dpmi_get_protected_mode_interrupt_vector(TIMER, &OldISR);
|
|
//point NewISR to the proper selector:offset for handler
|
|
//function
|
|
NewISR.pm_offset = (int)TickHandler;
|
|
NewISR.pm_selector = _go32_my_cs();
|
|
//chain the new ISR onto the old one so that first the old
|
|
//timer ISR
|
|
//will be called, then the new timer ISR
|
|
_go32_dpmi_chain_protected_mode_interrupt_vector(TIMER, &NewISR);
|
|
#endif
|
|
}
|
|
|
|
void terminate_osdep(void)
|
|
{
|
|
if (screen_backbuffer)
|
|
mem_free(screen_backbuffer);
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
_go32_dpmi_set_protected_mode_interrupt_vector(TIMER, &OldISR);
|
|
#endif
|
|
}
|
|
|
|
#define LINKS_BIN_SEARCH(entries, eq, ab, key, result) \
|
|
{ \
|
|
int s_ = 0, e_ = (entries) - 1; \
|
|
(result) = -1; \
|
|
while (s_ <= e_) { \
|
|
int m_ = (int)(((unsigned)s_ + (unsigned)e_) / 2); \
|
|
if (eq((m_), (key))) { \
|
|
(result) = m_; \
|
|
break; \
|
|
} \
|
|
if (ab((m_), (key))) e_ = m_ - 1; \
|
|
else s_ = m_ + 1; \
|
|
} \
|
|
}
|
|
|
|
#define array_elements(a) (sizeof(a) / sizeof(*a))
|
|
|
|
int
|
|
get_country_language(int c)
|
|
{
|
|
static const struct {
|
|
int code;
|
|
const char *language;
|
|
} countries[] = {
|
|
{ 1, "English" },
|
|
{ 2, "French" },
|
|
{ 3, "Spanish" },
|
|
{ 4, "English" },
|
|
{ 7, "Russian" },
|
|
{ 27, "English" },
|
|
{ 30, "Greek" },
|
|
{ 31, "Dutch" },
|
|
{ 32, "Dutch" },
|
|
{ 33, "French" },
|
|
{ 34, "Spanish" },
|
|
{ 36, "Hungarian" },
|
|
{ 38, "Serbian" },
|
|
{ 39, "Italian" },
|
|
{ 40, "Romanian" },
|
|
{ 41, "Swiss German" },
|
|
{ 42, "Czech" },
|
|
{ 43, "German" },
|
|
{ 44, "English" },
|
|
{ 45, "Danish" },
|
|
{ 46, "Swedish" },
|
|
{ 47, "Norwegian" },
|
|
{ 48, "Polish" },
|
|
{ 49, "German" },
|
|
{ 52, "Spanish" },
|
|
{ 54, "Spanish" },
|
|
{ 55, "Brazilian Portuguese" },
|
|
{ 56, "Spanish" },
|
|
{ 57, "Spanish" },
|
|
{ 58, "Spanish" },
|
|
{ 61, "English" },
|
|
{ 64, "English" },
|
|
{ 65, "English" },
|
|
{ 90, "Turkish" },
|
|
{ 99, "English" },
|
|
{ 351, "Portuguese" },
|
|
{ 353, "English" },
|
|
{ 354, "Icelandic" },
|
|
{ 358, "Finnish" },
|
|
{ 359, "Bulgarian" },
|
|
{ 371, "Lithuanian" },
|
|
{ 372, "Estonian" },
|
|
{ 381, "Serbian" },
|
|
{ 384, "Croatian" },
|
|
{ 385, "Croatian" },
|
|
#ifdef DOS
|
|
{ 421, "Slovak" },
|
|
#else
|
|
{ 421, "Czech" },
|
|
#endif
|
|
{ 422, "Slovak" },
|
|
{ 593, "Spanish" },
|
|
};
|
|
int idx = -1;
|
|
#define C_EQUAL(a, b) countries[a].code == (b)
|
|
#define C_ABOVE(a, b) countries[a].code > (b)
|
|
|
|
#if !defined(CONFIG_NLS) && !defined(CONFIG_GETTEXT)
|
|
return 1;
|
|
#else
|
|
LINKS_BIN_SEARCH(array_elements(countries), C_EQUAL, C_ABOVE, c, idx);
|
|
if (idx == -1)
|
|
return 1;
|
|
return name_to_language(countries[idx].language);
|
|
#endif
|
|
}
|
|
|
|
int os_default_language(void)
|
|
{
|
|
__dpmi_regs r;
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 0x3800;
|
|
r.x.dx = __tb_offset;
|
|
r.x.ds = __tb_segment;
|
|
__dpmi_int(0x21, &r);
|
|
if (!(r.x.flags & 1)) {
|
|
return get_country_language(r.x.bx);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int os_default_charset(void)
|
|
{
|
|
__dpmi_regs r;
|
|
memset(&r, 0, sizeof r);
|
|
r.x.ax = 0x6601;
|
|
__dpmi_int(0x21, &r);
|
|
if (!(r.x.flags & 1)) {
|
|
char a[8];
|
|
int cp;
|
|
snprintf((char *) a, sizeof a, "%d", r.x.bx);
|
|
if ((cp = get_cp_index(a)) >= 0 && !is_cp_utf8(cp))
|
|
return cp;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int dos_is_bw(void)
|
|
{
|
|
unsigned char cfg;
|
|
dosmemget(0x410, sizeof cfg, &cfg);
|
|
return (cfg & 0x30) == 0x30;
|
|
}
|
|
|
|
#else
|
|
|
|
typedef int dos_c_no_empty_unit;
|
|
|
|
#endif
|