2
* (c) 2002 Mikulas Patocka
3
* This file is a part of the Links program, released under GPL.
8
#ifdef HAVE_SYS_IOCTL_H
12
#if defined(HAVE_LIBGPM) && defined(HAVE_GPM_H)
21
int is_safe_in_shell(unsigned char c)
23
return c == '@' || c == '+' || c == '-' || c == '.' || c == ',' || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
26
int is_safe_in_url(unsigned char c)
28
return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80;
31
void check_shell_security(unsigned char **cmd)
33
unsigned char *c = *cmd;
35
if (!is_safe_in_shell(*c)) *c = '_';
40
int check_shell_url(unsigned char *url)
43
if (!is_safe_in_url(*url)) return -1;
49
unsigned char *escape_path(unsigned char *path)
51
unsigned char *result;
53
if (strchr(path, '"')) return stracpy(path);
54
for (i = 0; path[i]; i++) if (!is_safe_in_url(path[i])) goto do_esc;
57
result = stracpy("\"");
58
add_to_strn(&result, path);
59
add_to_strn(&result, "\"");
63
static int get_e(char *env)
66
if ((v = getenv(env))) return atoi(v);
70
void ignore_signals(void)
72
signal(SIGPIPE, SIG_IGN);
74
signal(SIGXFSZ, SIG_IGN);
78
unsigned char *clipboard = NULL;
88
#define INCL_DOSPROCESS
89
#define INCL_DOSERRORS
90
#define INCL_DOSMODULEMGR
92
#define INCL_WINCLIPBOARD
93
#define INCL_WINSWITCHLIST
97
#include <sys/video.h>
98
#ifdef HAVE_SYS_FMUTEX_H
99
#include <sys/builtin.h>
100
#include <sys/fmutex.h>
104
/* from xf86sup - XFree86 OS/2 support driver */
110
#if defined(O_SIZE) && defined(__EMX__)
112
int open_prealloc(char *name, int flags, int mode, off_t siz)
114
return open(name, flags | O_SIZE, mode, (unsigned long)siz);
117
void prealloc_truncate(int h, off_t siz)
128
/* Cygwin has a bug and loses SIGWINCH sometimes, so poll it */
130
static void winch_thread(void *p, int l)
132
static int old_xsize, old_ysize;
133
static int cur_xsize, cur_ysize;
134
if (get_terminal_size(0, &old_xsize, &old_ysize)) return;
136
if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
137
if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
138
old_xsize = cur_xsize;
139
old_ysize = cur_ysize;
146
static void win32_resize_poll(void)
148
static int winch_thread_running = 0;
149
if (!winch_thread_running) {
150
if (start_thread(winch_thread, NULL, 0) >= 0)
151
winch_thread_running = 1;
157
#if defined(UNIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(WIN32) || defined(SPAD)
159
static void sigwinch(void *s)
161
((void (*)(void))s)();
164
void handle_terminal_resize(int fd, void (*fn)(void))
166
install_signal_handler(SIGWINCH, sigwinch, fn, 0);
172
void unhandle_terminal_resize(int fd)
174
install_signal_handler(SIGWINCH, NULL, NULL, 0);
177
int get_terminal_size(int fd, int *x, int *y)
180
if (!x || !y) return -1;
181
if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
182
if (!(*x = ws.ws_col) && !(*x = get_e("COLUMNS"))) *x = 80;
183
if (!(*y = ws.ws_row) && !(*y = get_e("LINES"))) *y = 24;
186
if (!(*x = get_e("COLUMNS"))) *x = 80;
187
if (!(*y = get_e("LINES"))) *y = 24;
194
#define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2
199
if (xt == -1) xt = !!getenv("WINDOWID");
204
int winch_thread_running = 0;
206
#define WINCH_SLEEPTIME 500 /* time in ms for winch thread to sleep */
208
static void winch_thread(void)
210
/* A thread which regularly checks whether the size of
211
window has changed. Then raise SIGWINCH or notifiy
212
the thread responsible to handle this. */
213
static int old_xsize, old_ysize;
214
static int cur_xsize, cur_ysize;
217
if (get_terminal_size(1, &old_xsize, &old_ysize)) return;
219
if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
220
if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
221
old_xsize = cur_xsize;
222
old_ysize = cur_ysize;
223
write(winch_pipe[1], "x", 1);
224
/* Resizing may take some time. So don't send a flood
226
_sleep2(2*WINCH_SLEEPTIME);
229
_sleep2(WINCH_SLEEPTIME);
233
static void winch(void *s)
236
while (can_read(winch_pipe[0]) && read(winch_pipe[0], &c, 1) == 1);
237
((void (*)(void))s)();
240
void handle_terminal_resize(int fd, void (*fn)(void))
242
if (!is_xterm()) return;
243
if (!winch_thread_running) {
244
if (c_pipe(winch_pipe) < 0) return;
245
winch_thread_running = 1;
246
_beginthread((void (*)(void *))winch_thread, NULL, 0x32000, NULL);
248
set_handlers(winch_pipe[0], winch, NULL, NULL, fn);
251
void unhandle_terminal_resize(int fd)
253
set_handlers(winch_pipe[0], NULL, NULL, NULL, NULL);
256
int get_terminal_size(int fd, int *x, int *y)
258
if (!x || !y) return -1;
265
/* fd = STDIN_FILENO; */
266
arc = ptioctl(1, TIOCGWINSZ, &win);
286
*x = get_e("COLUMNS");
287
if (*x == 0) *x = 80;
291
if (*y == 0) *y = 24;
303
#if defined(UNIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
314
#elif defined(OS2) || defined(WIN32)
318
setmode(fd, O_BINARY);
324
if (!r) set_bin(fd[0]), set_bin(fd[1]);
332
int check_file_name(unsigned char *file)
334
return 1; /* !!! FIXME */
339
int can_twterm(void) /* Check if it make sense to call a twterm. */
342
if (xt == -1) xt = !!getenv("TWDISPLAY");
347
#if defined(UNIX) || defined(SPAD)
352
if (xt == -1) xt = getenv("DISPLAY") && *getenv("DISPLAY");
356
#elif defined(BEOS) || defined(ATHEOS)
368
if (xt == -1) xt = !!getenv("WINDOWID");
372
#elif defined(RISCOS)
381
tcount resize_count = 0;
383
void close_fork_tty(void)
387
struct connection *c;
389
foreach (t, terminals) if (t->fdin > 0) close(t->fdin);
390
foreach (d, downloads) if (d->handle > 0) close(d->handle);
391
foreach (c, queue) close_socket(&c->sock1), close_socket(&c->sock2);
392
foreach (k, keepalive_connections) close(k->conn);
397
void get_path_to_exe(void)
399
/* Standard method (argv[0]) doesn't work, if links is executed from
400
symlink --- it returns symlink name and cmd.exe is unable to start
403
static unsigned char path[4096];
404
r = GetModuleFileName(NULL, path, sizeof path);
405
if (r <= 0 || r >= sizeof path) {
406
path_to_exe = g_argv[0];
414
void get_path_to_exe(void)
416
/* If you spawn links with quotation marks from cmd.exe,
417
the quotation marks will be present in g_argv[0] ... and will
418
prevent executing it */
419
static char path[270];
421
path_to_exe = g_argv[0];
422
/*if (!strchr(path_to_exe, ' ') && !strchr(path_to_exe, '"')) return;*/
423
DosGetInfoBlocks(NULL, &pib);
425
if (DosQueryModuleName(pib->pib_hmte, sizeof path, path)) return;
431
void get_path_to_exe(void)
433
path_to_exe = g_argv[0];
438
#if defined(UNIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
440
#if defined(BEOS) && defined(HAVE_SETPGID)
442
int exe(char *path, int fg)
446
fg=fg; /* ignore flag */
452
if (p > 0) waitpid(p, &s, 0);
453
else return system(path);
460
int exe(char *path, int fg)
463
if (F && drv->exec) return drv->exec(path, fg);
466
signal(SIGTSTP, SIG_DFL);
469
signal(SIGCONT, SIG_DFL);
472
signal(SIGWINCH, SIG_DFL);
479
/* clipboard -> links */
480
unsigned char *get_clipboard_text(struct terminal *term)
483
if(term && term->dev && term->dev->drv && !strcmp(term->dev->drv->name,"x")) {
484
return x_get_clipboard_text();
487
return stracpy(clipboard);
490
/* links -> clipboard */
491
void set_clipboard_text(struct terminal *term, unsigned char *data)
494
if(term && term->dev && term->dev->drv && !strcmp(term->dev->drv->name,"x")) {
495
x_set_clipboard_text(term->dev, data);
499
if (clipboard) mem_free(clipboard);
500
clipboard = stracpy(data);
503
int clipboard_support(struct terminal *term)
506
if(term && term->dev && term->dev->drv && !strcmp(term->dev->drv->name,"x")) {
513
void set_window_title(unsigned char *title)
518
unsigned char *get_window_title(void)
524
int resize_window(int x, int y)
531
static int is_winnt(void)
534
v.dwOSVersionInfoSize = sizeof v;
535
if (!GetVersionEx(&v)) return 0;
536
return v.dwPlatformId >= VER_PLATFORM_WIN32_NT;
539
#define WIN32_START_STRING "start /wait "
541
int exe(char *path, int fg)
543
/* This is very tricky. We must have exactly 3 arguments, the first
544
one shell and the second one "/c", otherwise Cygwin would quote
545
the arguments and trash them */
553
if (!x1) x1 = DEFAULT_SHELL;
554
arg = alloca(strlen(WIN32_START_STRING) + 3 + strlen(path) + 1);
555
strcpy(arg, WIN32_START_STRING);
556
if (*path == '"' && strlen(x1) >= 7 && !strcasecmp(x1 + strlen(x1) - 7, "cmd.exe")) strcat(arg, "\"\" ");
558
ct = GetConsoleTitle(buffer, sizeof buffer);
559
if (!(pid = fork())) {
561
/* Win98 crashes if we spawn command.com and have some sockets open */
562
for (i = 0; i < FD_SETSIZE; i++) close(i);
563
open("nul", O_RDONLY);
564
open("nul", O_WRONLY);
565
open("nul", O_WRONLY);
566
execlp(x1, x1, "/c", arg, NULL);
571
if (ct && GetConsoleTitle(buffer2, sizeof buffer2) && !casecmp(buffer2, "start", 5)) {
572
SetConsoleTitle(buffer);
575
if (pid != -1) waitpid(pid, NULL, 0);
579
unsigned char *get_clipboard_text(struct terminal *term)
582
unsigned char *str, *s, *d;
585
int h = open("/dev/clipboard", O_RDONLY);
586
if (h == -1) return stracpy(clipboard);
587
set_bin(h); /* O_TEXT doesn't work on clipboard handle */
590
while ((r = hard_read(h, buffer, sizeof buffer)) > 0)
591
add_bytes_to_str(&str, &l, buffer, r);
593
for (s = str, d = str; *s; s++)
594
if (!(s[0] == '\r' && s[1] == '\n')) *d++ = *s;
599
/* Putting Czech characters to clipboard doesn't work, but it should be fixed
600
rather in Cygwin than here */
601
void set_clipboard_text(struct terminal *term, unsigned char *data)
603
unsigned char *conv_data;
606
if (clipboard) mem_free(clipboard);
607
clipboard = stracpy(data);
608
h = open("/dev/clipboard", O_WRONLY);
610
set_bin(h); /* O_TEXT doesn't work on clipboard handle */
611
conv_data = init_str();
613
for (; *data; data++)
614
if (*data == '\n') add_to_str(&conv_data, &l, "\r\n");
615
else add_chr_to_str(&conv_data, &l, *data);
616
hard_write(h, conv_data, l);
621
int clipboard_support(struct terminal *term)
627
static int get_windows_cp(void)
631
static int win_cp_idx = -1;
632
if (win_cp_idx != -1) return win_cp_idx;
633
cp = GetConsoleOutputCP();
634
if (cp <= 0 || cp >= 100000) return 0;
635
sprintf(str, "%d", cp);
636
if ((idx = get_cp_index(str)) < 0) return 0;
641
static int get_utf8_cp(void)
644
return idx >= 0 ? idx : (idx = get_cp_index("utf-8"));
647
void set_window_title(unsigned char *title)
650
struct conv_table *ct;
651
if (is_xterm()) return;
652
ct = get_translation_table(get_utf8_cp(), get_windows_cp());
653
t = convert_string(ct, title, strlen(title), NULL);
658
unsigned char *get_window_title(void)
660
struct conv_table *ct;
663
if (is_xterm()) return NULL;
664
if (!(r = GetConsoleTitle(buffer, sizeof buffer))) return NULL;
665
ct = get_translation_table(get_windows_cp(), get_utf8_cp());
666
return convert_string(ct, buffer, r, NULL);
669
static void call_resize(unsigned char *x1, int x, int y)
672
unsigned char arg[40];
673
sprintf(arg, "mode %d,%d", x, y);
674
if (!(pid = fork())) {
676
/* Win98 crashes if we spawn command.com and have some sockets open */
677
for (i = 0; i < FD_SETSIZE; i++) if (i != 1 && i != 2) close(i);
678
open("nul", O_WRONLY);
679
execlp(x1, x1, "/c", arg, NULL);
682
if (pid != -1) waitpid(pid, NULL, 0);
685
int resize_window(int x, int y)
688
int ct = 0, fullscreen = 0;
691
if (is_xterm()) return -1;
692
if (get_terminal_size(1, &old_x, &old_y)) return -1;
694
if (!x1) x1 = DEFAULT_SHELL;
696
ct = GetConsoleTitle(buffer, sizeof buffer);
699
call_resize(x1, x, y);
702
/* If we resize console on Win98 in fullscreen mode, it won't be
703
notified by Cygwin (it is valid for all Cygwin apps). So we must
704
switch to windowed mode, resize it again (twice, because resizing
705
to the same size won't have an effect) and switch back to full-screen
707
/* I'm not sure what's the behavior on WinNT 4. Anybody wants to test?
709
if (!fullscreen && !get_terminal_size(1, &new_x, &new_y) && (new_x != x || new_y != y)) {
711
keybd_event(VK_MENU, 0x38, 0, 0);
712
keybd_event(VK_RETURN, 0x1c, 0, 0);
713
keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
714
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
715
if (y != 25) call_resize(x1, 80, 25);
716
else call_resize(x1, 80, 50);
717
call_resize(x1, x, y);
718
if (get_terminal_size(1, &new_x, &new_y) || new_x != x || new_y != y) call_resize(x1, old_x, old_y);
719
keybd_event(VK_MENU, 0x38, 0, 0);
720
keybd_event(VK_RETURN, 0x1c, 0, 0);
721
keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
722
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
724
if (ct) SetConsoleTitle(buffer);
733
int fd_mutex_init = 0;
736
int exe(char *path, int fg)
738
int flags = P_SESSION;
742
int old0 = 0, old1 = 1, old2 = 2;
745
fg=fg; /* ignore flag */
746
if (!(shell = GETSHELL)) shell = DEFAULT_SHELL;
747
if (is_xterm()) flags |= P_BACKGROUND;
750
if (!fd_mutex_init) {
751
if (_fmutex_create(&fd_mutex, 0)) return -1;
754
_fmutex_request(&fd_mutex, _FMR_IGNINT);
761
open("con", O_RDONLY);
762
open("con", O_WRONLY);
763
open("con", O_WRONLY);
766
pid = spawnlp(flags, shell, shell, "/c", path, NULL);
775
_fmutex_release(&fd_mutex);
778
if (pid != -1) waitpid(pid, &ret, 0);
783
unsigned char *get_clipboard_text(struct terminal *term)
792
DosGetInfoBlocks(&tib, &pib);
794
oldType = pib->pib_ultype;
798
if ((hab = WinInitialize(0)) != NULLHANDLE) {
799
if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
801
if (WinOpenClipbrd(hab)) {
804
if (WinQueryClipbrdFmtInfo(hab, CF_TEXT, &fmtInfo)!=FALSE)
806
ULONG selClipText = WinQueryClipbrdData(hab, CF_TEXT);
811
PCHAR pchClipText = (PCHAR)selClipText;
812
ret = mem_alloc(strlen(pchClipText)+1);
813
strcpy(ret, pchClipText);
814
while ((u = strchr(ret, 13))) memmove(u, u + 1, strlen(u + 1) + 1);
818
WinCloseClipbrd(hab);
824
struct conv_table *ct;
827
int c = WinQueryCp(hmq);
829
snprintf(a, 64, "%d", c);
830
if ((cp = get_cp_index(a)) < 0 || is_cp_special(cp)) cp = 0;
832
ct = get_translation_table(cp, get_cp_index("utf-8"));
833
d = convert_string(ct, ret, strlen(ret), NULL);
838
WinDestroyMsgQueue(hmq);
843
pib->pib_ultype = oldType;
848
void set_clipboard_text(struct terminal * term, unsigned char *data)
856
unsigned char *d = NULL;
858
DosGetInfoBlocks(&tib, &pib);
860
oldType = pib->pib_ultype;
864
if ((hab = WinInitialize(0)) != NULLHANDLE) {
865
if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
869
struct conv_table *ct;
871
int c = WinQueryCp(hmq);
873
snprintf(a, 64, "%d", c);
874
if ((cp = get_cp_index(a)) < 0 || is_cp_special(cp)) cp = 0;
876
ct = get_translation_table(get_cp_index("utf-8"), cp);
877
d = convert_string(ct, data, strlen(data), NULL);
881
if(WinOpenClipbrd(hab)) {
882
PVOID pvShrObject = NULL;
883
if (DosAllocSharedMem(&pvShrObject, NULL, strlen(data)+1, PAG_COMMIT | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) {
884
strcpy(pvShrObject, data);
885
WinEmptyClipbrd(hab);
886
WinSetClipbrdData(hab, (ULONG)pvShrObject, CF_TEXT, CFI_POINTER);
888
WinCloseClipbrd(hab);
890
WinDestroyMsgQueue(hmq);
895
pib->pib_ultype = oldType;
900
int clipboard_support(struct terminal *term)
905
unsigned char *get_window_title(void)
908
/*char *org_switch_title;*/
909
char *org_win_title = NULL;
910
static PTIB tib = NULL;
911
static PPIB pib = NULL;
913
HSWITCH hSw = NULLHANDLE;
918
/* save current process title */
920
if (!pib) DosGetInfoBlocks(&tib, &pib);
921
oldType = pib->pib_ultype;
922
memset(&swData, 0, sizeof swData);
923
if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
924
if (hSw!=NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
925
/*org_switch_title = mem_alloc(strlen(swData.szSwtitle)+1);
926
strcpy(org_switch_title, swData.szSwtitle);*/
929
if ((hab = WinInitialize(0)) != NULLHANDLE) {
930
if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
931
org_win_title = mem_alloc(MAXNAMEL+1);
932
WinQueryWindowText(swData.hwnd, MAXNAMEL+1, org_win_title);
933
org_win_title[MAXNAMEL] = 0;
935
WinDestroyMsgQueue(hmq);
939
pib->pib_ultype = oldType;
941
return org_win_title;
947
void set_window_title(unsigned char *title)
958
if (!pib) DosGetInfoBlocks(&tib, &pib);
959
oldType = pib->pib_ultype;
960
memset(&swData, 0, sizeof swData);
961
if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
962
if (hSw!=NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
963
strncpy(swData.szSwtitle, title, MAXNAMEL-1);
964
swData.szSwtitle[MAXNAMEL-1] = 0;
965
WinChangeSwitchEntry(hSw, &swData);
968
if ((hab = WinInitialize(0)) != NULLHANDLE) {
969
if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
971
WinSetWindowText(swData.hwnd, title);
973
WinDestroyMsgQueue(hmq);
978
pib->pib_ultype = oldType;
982
int resize_window(int x, int y)
985
A_DECL(VIOMODEINFO, vmi);
987
if (is_xterm()) return -1;
988
vmi->cb = sizeof(*vmi);
989
if (VioGetMode(vmi, 0)) return -1;
992
/*debug("%d %d %d", vmi->buf_length, vmi->full_length, vmi->partial_length);*/
993
for (xfont = 9; xfont >= 8; xfont--)
994
for (yfont = 16; yfont >= 8; yfont--) {
995
vmi->hres = x * xfont;
996
vmi->vres = y * yfont;
997
if (vmi->vres <= 400) vmi->vres = 400;
998
else if (vmi->vres <= 480) vmi->vres = 480;
999
vmi->buf_length = vmi->full_length = vmi->partial_length = x * ((vmi->vres + yfont - 1) / yfont) * 2;
1000
vmi->full_length = (vmi->full_length + 4095) & ~4095;
1001
vmi->partial_length = (vmi->partial_length + 4095) & ~4095;
1002
if (!VioSetMode(vmi, 0)) return 0;
1012
void (*fn)(void *, int);
1014
unsigned char data[1];
1017
#if defined(HAVE_BEGINTHREAD) || defined(BEOS) || defined(HAVE_PTHREADS) || defined(HAVE_ATHEOS_THREADS_H)
1019
static void bgt(struct tdata *t)
1022
t->fn(t->data, t->h);
1023
write(t->h, "x", 1);
1028
#ifdef HAVE_PTHREADS
1029
static void *bgpt(struct tdata *t)
1036
#ifdef HAVE_ATHEOS_THREADS_H
1037
#include <atheos/threads.h>
1038
static uint32 abgt(void *t)
1047
#if defined(UNIX) || defined(OS2) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(WIN32)
1049
void terminate_osdep(void) {}
1055
void block_stdin(void) {}
1056
void unblock_stdin(void) {}
1062
#include <be/kernel/OS.h>
1064
int thr_sem_init = 0;
1067
struct list_head active_threads = { &active_threads, &active_threads };
1069
struct active_thread {
1070
struct active_thread *next;
1071
struct active_thread *prev;
1077
int32 started_thr(void *data)
1079
struct active_thread *thrd = data;
1080
thrd->fn(thrd->data);
1081
if (acquire_sem(thr_sem) < B_NO_ERROR) return 0;
1082
del_from_list(thrd);
1084
release_sem(thr_sem);
1088
int start_thr(void (*fn)(void *), void *data, unsigned char *name)
1090
struct active_thread *thrd;
1092
if (!thr_sem_init) {
1093
if ((thr_sem = create_sem(0, "thread_sem")) < B_NO_ERROR) return -1;
1095
} else if (acquire_sem(thr_sem) < B_NO_ERROR) return -1;
1096
if (!(thrd = malloc(sizeof(struct active_thread)))) goto rel;
1099
if ((tid = thrd->tid = spawn_thread(started_thr, name, B_NORMAL_PRIORITY, thrd)) < B_NO_ERROR) {
1102
release_sem(thr_sem);
1105
resume_thread(thrd->tid);
1106
add_to_list(active_threads, thrd);
1107
release_sem(thr_sem);
1111
void terminate_osdep(void)
1113
struct list_head *p;
1114
struct active_thread *thrd;
1115
if (acquire_sem(thr_sem) < B_NO_ERROR) return;
1116
foreach(thrd, active_threads) kill_thread(thrd->tid);
1117
while ((p = active_threads.next) != &active_threads) {
1121
release_sem(thr_sem);
1124
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1128
if (c_pipe(p) < 0) return -1;
1129
if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
1132
memcpy(t->data, ptr, l);
1133
if (start_thr((void (*)(void *))bgt, t, "links_thread") < 0) {
1143
#elif defined(HAVE_BEGINTHREAD)
1145
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1149
if (c_pipe(p) < 0) return -1;
1150
fcntl(p[0], F_SETFL, O_NONBLOCK);
1151
fcntl(p[1], F_SETFL, O_NONBLOCK);
1152
if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
1155
memcpy(t->data, ptr, l);
1156
if (_beginthread((void (*)(void *))bgt, NULL, 65536, t) == -1) {
1165
#ifdef HAVE_READ_KBD
1170
static void input_thread(void *p)
1176
/*c[0] = _read_kbd(0, 1, 1);
1177
if (c[0]) if (write(h, c, 1) <= 0) break;
1180
printf("1");fflush(stdout);
1181
c[1] = _read_kbd(0, 1, 1);
1182
printf("2");fflush(stdout);
1184
printf("3");fflush(stdout);
1186
if (w == 1) if (write(h, c+1, 1) <= 0) break;
1187
printf("4");fflush(stdout);
1190
_read_kbd(0, 1, 1) will
1191
read a char, don't echo it, wait for one available and
1193
Knowing that, I suggest we replace this call completly!
1195
*c = _read_kbd(0, 1, 1);
1200
#endif /* #ifdef HAVE_READ_KBD */
1202
#if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
1204
#define USING_OS2_MOUSE
1206
#ifdef HAVE_SYS_FMUTEX_H
1207
_fmutex mouse_mutex;
1208
int mouse_mutex_init = 0;
1212
struct os2_mouse_spec {
1214
void (*fn)(void *, unsigned char *, int);
1216
unsigned char buffer[sizeof(struct event)];
1221
static void mouse_thread(void *p)
1224
struct os2_mouse_spec *oms = p;
1226
A_DECL(MOUEVENTINFO, ms);
1228
A_DECL(USHORT, mask);
1232
if (MouOpen(NULL, mh)) goto ret;
1234
*mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
1235
MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
1236
MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
1238
MouSetEventMask(mask, *mh);
1243
if (MouReadEventQue(ms, rd, *mh)) break;
1244
#ifdef HAVE_SYS_FMUTEX_H
1245
_fmutex_request(&mouse_mutex, _FMR_IGNINT);
1247
if (!oms->terminate) MouDrawPtr(*mh);
1248
#ifdef HAVE_SYS_FMUTEX_H
1249
_fmutex_release(&mouse_mutex);
1253
/*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/
1254
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_MIDDLE : B_RIGHT);
1255
else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
1256
int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_MIDDLE : B_RIGHT;
1257
if (status == -1) b |= B_DOWN;
1262
if (status == -1) continue;
1263
ev.b = (status & BM_BUTT) | B_UP;
1266
if (hard_write(oms->p[1], (unsigned char *)&ev, sizeof(struct event)) != sizeof(struct event)) break;
1268
#ifdef HAVE_SYS_FMUTEX_H
1269
_fmutex_request(&mouse_mutex, _FMR_IGNINT);
1273
#ifdef HAVE_SYS_FMUTEX_H
1274
_fmutex_release(&mouse_mutex);
1281
static void mouse_handle(struct os2_mouse_spec *oms)
1284
if ((r = read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct event) - oms->bufptr)) <= 0) {
1285
unhandle_mouse(oms);
1288
if ((oms->bufptr += r) == sizeof(struct event)) {
1290
oms->fn(oms->data, oms->buffer, sizeof(struct event));
1294
void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
1296
struct os2_mouse_spec *oms;
1297
if (is_xterm()) return NULL;
1298
#ifdef HAVE_SYS_FMUTEX_H
1299
if (!mouse_mutex_init) {
1300
if (_fmutex_create(&mouse_mutex, 0)) return NULL;
1301
mouse_mutex_init = 1;
1304
/* This is never freed but it's allocated only once */
1305
if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) return NULL;
1310
if (c_pipe(oms->p)) {
1314
_beginthread(mouse_thread, NULL, 0x10000, (void *)oms);
1315
set_handlers(oms->p[0], (void (*)(void *))mouse_handle, NULL, NULL, oms);
1319
void unhandle_mouse(void *om)
1321
struct os2_mouse_spec *oms = om;
1324
set_handlers(oms->p[0], NULL, NULL, NULL, NULL);
1329
void want_draw(void)
1331
A_DECL(NOPTRRECT, pa);
1332
#ifdef HAVE_SYS_FMUTEX_H
1333
if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT);
1335
if (mouse_h != -1) {
1336
static int x = -1, y = -1;
1337
static tcount c = -1;
1338
if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(1, &x, &y), c = resize_count;
1343
MouRemovePtr(pa, mouse_h);
1347
void done_draw(void)
1349
#ifdef HAVE_SYS_FMUTEX_H
1350
if (mouse_mutex_init) _fmutex_release(&mouse_mutex);
1354
#endif /* if HAVE_MOUOPEN */
1356
#elif defined(HAVE_CLONE)
1358
/* This is maybe buggy... */
1362
struct thread_stack {
1363
struct thread_stack *next;
1364
struct thread_stack *prev;
1367
void (*fn)(void *, int);
1370
unsigned char data[1];
1373
void bglt(struct thread_stack *ts)
1375
ts->fn(ts->data, ts->h);
1376
write(ts->h, "x", 1);
1380
struct list_head thread_stacks = { &thread_stacks, &thread_stacks };
1382
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1384
struct thread_stack *ts;
1387
if (c_pipe(p) < 0) return -1;
1388
fcntl(p[0], F_SETFL, O_NONBLOCK);
1389
fcntl(p[1], F_SETFL, O_NONBLOCK);
1390
/*if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
1393
memcpy(t->data, ptr, l);*/
1394
foreach(ts, thread_stacks) {
1395
if (ts->pid == -1 || kill(ts->pid, 0)) {
1396
if (ts->l >= l) goto ts_ok;
1398
struct thread_stack *tts = ts;
1400
del_from_list(tts); free(tts->stack); free(tts);
1404
if (!(ts = malloc(sizeof(struct thread_stack) + l))) goto fail;
1405
if (!(ts->stack = malloc(0x10000))) {
1410
add_to_list(thread_stacks, ts);
1414
memcpy(ts->data, ptr, l);
1415
if ((ts->pid = __clone((int (*)(void *))bglt, (char *)ts->stack + 0x8000, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, ts)) == -1) {
1424
#elif defined(HAVE_PTHREADS)
1426
#include <pthread.h>
1428
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1433
if (c_pipe(p) < 0) return -1;
1434
fcntl(p[0], F_SETFL, O_NONBLOCK);
1435
fcntl(p[1], F_SETFL, O_NONBLOCK);
1436
if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
1439
memcpy(t->data, ptr, l);
1440
if (pthread_create(&thread, NULL, (void *(*)(void *))bgpt, t)) {
1449
#elif defined(HAVE_ATHEOS_THREADS_H) && defined(HAVE_SPAWN_THREAD) && defined(HAVE_RESUME_THREAD)
1451
#include <atheos/threads.h>
1453
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1458
if (c_pipe(p) < 0) return -1;
1459
fcntl(p[0], F_SETFL, O_NONBLOCK);
1460
fcntl(p[1], F_SETFL, O_NONBLOCK);
1461
if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
1464
memcpy(t->data, ptr, l);
1465
if ((f = spawn_thread("links_lookup", abgt, 0, 0, t)) == -1) {
1475
#else /* HAVE_BEGINTHREAD */
1477
int start_thread(void (*fn)(void *, int), void *ptr, int l)
1481
if (c_pipe(p) < 0) return -1;
1482
fcntl(p[0], F_SETFL, O_NONBLOCK);
1483
fcntl(p[1], F_SETFL, O_NONBLOCK);
1484
if (!(f = fork())) {
1488
write(p[1], "x", 1);
1503
#ifndef USING_OS2_MOUSE
1504
void want_draw(void) {}
1505
void done_draw(void) {}
1508
int get_output_handle(void) { return 1; }
1512
int get_ctl_handle(void) { return get_input_handle(); }
1516
int get_ctl_handle(void) { return 0; }
1522
#elif defined(HAVE_BEGINTHREAD) && defined(HAVE_READ_KBD)
1523
int get_input_handle(void)
1526
if (ti != -1) return ti;
1527
if (is_xterm()) return 0;
1528
if (c_pipe(fd) < 0) return 0;
1531
_beginthread(input_thread, NULL, 0x10000, (void *)tp);
1533
#if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
1534
_beginthread(mouse_thread, NULL, 0x10000, (void *)tp);
1542
int get_input_handle(void)
1547
#endif /* defined(HAVE_BEGINTHREAD) && defined(HAVE_READ_KBD) */
1550
void os_cfmakeraw(struct termios *t)
1552
#ifdef HAVE_CFMAKERAW
1558
t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1559
t->c_oflag &= ~OPOST;
1560
t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1561
t->c_cflag &= ~(CSIZE|PARENB);
1570
struct gpm_mouse_spec {
1572
void (*fn)(void *, unsigned char *, int);
1576
/* GPM installs its own signal handlers and we don't want them */
1578
sigset_t gpm_sigset;
1579
char gpm_sigset_valid;
1581
struct sigaction gpm_winch;
1582
char gpm_winch_valid;
1585
struct sigaction gpm_tstp;
1586
char gpm_tstp_valid;
1589
static void save_gpm_signals(void)
1594
sigaddset(&sig, SIGWINCH);
1597
sigaddset(&sig, SIGTSTP);
1599
gpm_sigset_valid = !sigprocmask(SIG_BLOCK, &sig, &gpm_sigset);
1601
gpm_winch_valid = !sigaction(SIGWINCH, NULL, &gpm_winch);
1604
gpm_tstp_valid = !sigaction(SIGTSTP, NULL, &gpm_tstp);
1608
static void restore_gpm_signals(void)
1611
if (gpm_winch_valid) sigaction(SIGWINCH, &gpm_winch, NULL);
1614
if (gpm_tstp_valid) sigaction(SIGTSTP, &gpm_tstp, NULL);
1616
if (gpm_sigset_valid) sigprocmask(SIG_SETMASK, &gpm_sigset, NULL);
1619
static void gpm_mouse_in(struct gpm_mouse_spec *gms)
1625
g = Gpm_GetEvent(&gev);
1626
restore_gpm_signals();
1628
set_handlers(gms->h, NULL, NULL, NULL, NULL);
1635
if (ev.x < 0) ev.x = 0;
1636
if (ev.y < 0) ev.y = 0;
1637
if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT;
1638
else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE;
1639
else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT;
1641
if (gev.type & GPM_DOWN) ev.b |= B_DOWN;
1642
else if (gev.type & GPM_UP) ev.b |= B_UP;
1643
else if (gev.type & GPM_DRAG) ev.b |= B_DRAG;
1645
gms->fn(gms->data, (char *)&ev, sizeof(struct event));
1648
void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
1652
struct gpm_mouse_spec *gms;
1653
conn.eventMask = ~GPM_MOVE;
1654
conn.defaultMask = GPM_MOVE;
1658
h = Gpm_Open(&conn, cons);
1659
restore_gpm_signals();
1660
if (h < 0) return NULL;
1661
gms = mem_alloc(sizeof(struct gpm_mouse_spec));
1665
set_handlers(h, (void (*)(void *))gpm_mouse_in, NULL, NULL, gms);
1669
void unhandle_mouse(void *h)
1671
struct gpm_mouse_spec *gms = h;
1672
if (gms->h != -1) set_handlers(gms->h, NULL, NULL, NULL, NULL);
1675
restore_gpm_signals();
1679
#elif !defined(USING_OS2_MOUSE)
1681
void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) { return NULL; }
1682
void unhandle_mouse(void *data) { }
1684
#endif /* #ifdef USE_GPM */
1688
int get_system_env(void)
1690
if (is_xterm()) return 0;
1691
return ENV_OS2VIO; /* !!! FIXME: telnet */
1696
int get_system_env(void)
1698
unsigned char *term = getenv("TERM");
1699
if (!term || (upcase(term[0]) == 'B' && upcase(term[1]) == 'E')) return ENV_BE;
1703
#elif defined(WIN32)
1705
int get_system_env(void)
1707
if (is_xterm()) return 0;
1713
int get_system_env(void)
1720
static void exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe, unsigned char *param)
1723
str = mem_alloc(strlen(xterm) + 1 + strlen(exe) + 1 + strlen(param) + 1);
1724
if (*xterm) sprintf(str, "%s %s %s", xterm, exe, param);
1725
else sprintf(str, "%s %s", exe, param);
1726
exec_on_terminal(term, str, "", 2);
1730
static void open_in_new_twterm(struct terminal *term, unsigned char *exe, unsigned char *param)
1732
unsigned char *twterm;
1733
if (!(twterm = getenv("LINKS_TWTERM"))) twterm = "twterm -e";
1734
exec_new_links(term, twterm, exe, param);
1737
static void open_in_new_xterm(struct terminal *term, unsigned char *exe, unsigned char *param)
1739
unsigned char *xterm;
1740
if (!(xterm = getenv("LINKS_XTERM"))) xterm = "xterm -e";
1741
exec_new_links(term, xterm, exe, param);
1744
static void open_in_new_screen(struct terminal *term, unsigned char *exe, unsigned char *param)
1746
exec_new_links(term, "screen", exe, param);
1750
static void open_in_new_vio(struct terminal *term, unsigned char *exe, unsigned char *param)
1752
unsigned char *x = stracpy("\"");
1753
add_to_strn(&x, exe);
1754
add_to_strn(&x, "\"");
1755
exec_new_links(term, "start \"Links\" /c /f /win", x, param);
1759
static void open_in_new_fullscreen(struct terminal *term, unsigned char *exe, unsigned char *param)
1761
unsigned char *x = stracpy("\"");
1762
add_to_strn(&x, exe);
1763
add_to_strn(&x, "\"");
1764
exec_new_links(term, "start \"Links\" /c /f /fs", x, param);
1770
static void open_in_new_win32(struct terminal *term, unsigned char *exe, unsigned char *param)
1772
exec_new_links(term, "", exe, param);
1777
static void open_in_new_be(struct terminal *term, unsigned char *exe, unsigned char *param)
1779
exec_new_links(term, "Terminal", exe, param);
1784
static void open_in_new_g(struct terminal *term, unsigned char *exe, unsigned char *param)
1787
unsigned char *target=NULL;
1790
unsigned char *url = "";
1791
if (!cmpbeg(param, "-target "))
1794
target=param+strlen("-target ");
1795
for (p=target;*p!=' '&&*p;p++);
1799
if (!cmpbeg(param, "-base-session ")) {
1800
base = atoi(param + strlen("-base-session "));
1804
if ((info = create_session_info(base, url, target, &len))) attach_g_terminal(info, len);
1810
void (*fn)(struct terminal *term, unsigned char *, unsigned char *);
1811
unsigned char *text;
1814
{ENV_XWIN, open_in_new_xterm, TEXT_(T_XTERM), TEXT_(T_HK_XTERM)},
1815
{ENV_TWIN, open_in_new_twterm, TEXT_(T_TWTERM), TEXT_(T_HK_TWTERM)},
1816
{ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN)},
1818
{ENV_OS2VIO, open_in_new_vio, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
1819
{ENV_OS2VIO, open_in_new_fullscreen, TEXT_(T_FULL_SCREEN), TEXT_(T_HK_FULL_SCREEN)},
1822
{ENV_WIN32, open_in_new_win32, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
1825
{ENV_BE, open_in_new_be, TEXT_(T_BEOS_TERMINAL), TEXT_(T_HK_BEOS_TERMINAL)},
1828
{ENV_G, open_in_new_g, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
1830
{0, NULL, NULL, NULL}
1833
struct open_in_new *get_open_in_new(int environment)
1836
struct open_in_new *oin = DUMMY;
1838
if (anonymous) return NULL;
1839
if (environment & ENV_G) environment = ENV_G;
1840
for (i = 0; oinw[i].env; i++) if ((environment & oinw[i].env) == oinw[i].env) {
1841
if ((unsigned)noin > MAXINT / sizeof(struct open_in_new) - 2) overalloc();
1842
oin = mem_realloc(oin, (noin + 2) * sizeof(struct open_in_new));
1843
oin[noin].text = oinw[i].text;
1844
oin[noin].hk = oinw[i].hk;
1845
oin[noin].fn = oinw[i].fn;
1847
oin[noin].text = NULL;
1848
oin[noin].hk = NULL;
1849
oin[noin].fn = NULL;
1851
if (oin == DUMMY) return NULL;
1855
int can_resize_window(int environment)
1857
if (environment & (ENV_OS2VIO | ENV_WIN32)) return 1;
1861
int can_open_os_shell(int environment)
1864
if (environment & ENV_XWIN) return 0;
1870
void set_highpri(void)
1874
void set_highpri(void)
1876
DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0);
1880
#ifndef HAVE_SNPRINTF
1884
char snprtintf_buffer[B_SZ];
1886
int my_snprintf(char *str, int n, char *f, ...)
1892
vsprintf(snprtintf_buffer, f, l);
1894
i = strlen(snprtintf_buffer);
1896
error("String size too large!");
1902
memcpy(str, snprtintf_buffer, n);
1907
strcpy(str, snprtintf_buffer);
1914
#ifndef HAVE_MEMMOVE
1918
typedef long word; /* "word" used for optimal copy speed */
1920
#define wsize sizeof(word)
1921
#define wmask (wsize - 1)
1924
* Copy a block of memory, handling overlap.
1925
* This is the routine that actually implements
1926
* (the portable versions of) bcopy, memcpy, and memmove.
1929
memmove(dst0, src0, length)
1935
const char *src = src0;
1939
if (length == 0 || dst == src) /* nothing to do */
1943
* Macros: loop-t-times; and loop-t-times, t>0
1945
#define TLOOP(s) if (t) TLOOP1(s)
1946
#define TLOOP1(s) do { s; } while (--t)
1948
if ((unsigned long)dst < (unsigned long)src) {
1952
u = (unsigned long)src; /* only need low bits */
1953
if ((u | (unsigned long)dst) & wmask) {
1955
* Try to align operands. This cannot be done
1956
* unless the low bits match.
1958
if ((u ^ (unsigned long)dst) & wmask || length < wsize)
1961
t = wsize - (size_t)(u & wmask);
1963
TLOOP1(*dst++ = *src++);
1966
* Copy whole words, then mop up any trailing bytes.
1969
TLOOP(*(word *)(void *)dst = *(const word *)(const void *)src; src += wsize; dst += wsize);
1971
TLOOP(*dst++ = *src++);
1974
* Copy backwards. Otherwise essentially the same.
1975
* Alignment works as before, except that it takes
1976
* (t&wmask) bytes to align, not wsize-(t&wmask).
1980
u = (unsigned long)src;
1981
if ((u | (unsigned long)dst) & wmask) {
1982
if ((u ^ (unsigned long)dst) & wmask || length <= wsize)
1985
t = (size_t)(u & wmask);
1987
TLOOP1(*--dst = *--src);
1990
TLOOP(src -= wsize; dst -= wsize; *(word *)(void *)dst = *(const word *)(const void *)src);
1992
TLOOP(*--dst = *--src);
1995
#if defined(MEMCOPY) || defined(MEMMOVE)
2011
return(kill(getpid(), s));
2019
#ifndef HAVE_STRTOUL
2021
/****yes bad fix***/
2022
unsigned long strtoul(const char *nptr, char **endptr, int base) {
2023
return (unsigned long)strtol(nptr,endptr,base);
2028
#ifndef HAVE_STRERROR
2031
char *strerror(int errnum) { return sys_errlist[errnum];};
2035
#ifndef HAVE_GETTIMEOFDAY
2036
int gettimeofday(struct timeval *tv, struct timezone *tz)
2038
if (tv) tv->tv_sec = time(NULL), tv->tv_usec = 0;
2039
if (tz) tz->tz_minuteswest = tz->tz_dsttime = 0;
2043
#ifndef HAVE_STRCSPN
2044
size_t strcspn(const char *s, const char *reject)
2047
for (r = 0; *s; r++, s++) {
2049
for (rj = reject; *rj; rj++) if (*s == *rj) goto brk;
2056
char *strstr(const char *haystack, const char *needle)
2058
size_t hs = strlen(haystack);
2059
size_t ns = strlen(needle);
2061
if (!memcmp(haystack, needle, ns)) return haystack;
2067
#ifndef HAVE_TEMPNAM
2068
char *tempnam(const char *dir, const char *pfx)
2070
static int counter = 0;
2071
unsigned char *d, *s, *a;
2073
if (!(d = getenv("TMPDIR"))) {
2074
if (dir) d = (unsigned char *)dir;
2075
else if (!(d = getenv("TMP")) && !(d = getenv("TEMP"))) {
2085
add_to_str(&s, &l, d);
2086
if (s[0] && s[strlen(s) - 1] != '/') add_chr_to_str(&s, &l, '/');
2087
add_to_str(&s, &l, (unsigned char *)pfx);
2088
add_num_to_str(&s, &l, counter++);