1 #include "links.h"
2 
3 #ifdef HAVE_SYS_IOCTL_H
4 #include <sys/ioctl.h>
5 #endif
6 
7 #ifdef USE_GPM
8 #include <gpm.h>
9 #endif
10 
is_safe_in_shell(unsigned char c)11 int is_safe_in_shell(unsigned char c)
12 {
13 	return c == '@' || c == '+' || c == '-' || c == '.' || c == ',' || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
14 }
15 
is_safe_in_file(unsigned char c)16 static inline int is_safe_in_file(unsigned char c)
17 {
18 	return !(c < ' ' || c == '"' || c == '*' || c == '/' || c == ':' || c == '<' || c == '>' || c == '\\' || c == '|' || c >= 0x80);
19 }
20 
is_safe_in_url(unsigned char c)21 static inline int is_safe_in_url(unsigned char c)
22 {
23 	return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80;
24 }
25 
check_shell_security(unsigned char ** cmd)26 void check_shell_security(unsigned char **cmd)
27 {
28 	unsigned char *c = *cmd;
29 	while (*c) {
30 		if (!is_safe_in_shell(*c)) *c = '_';
31 		c++;
32 	}
33 }
34 
check_filename(unsigned char ** file)35 void check_filename(unsigned char **file)
36 {
37 	unsigned char *c = *file;
38 	while (*c) {
39 		if (!is_safe_in_file(*c)) *c = '_';
40 		c++;
41 	}
42 }
43 
check_shell_url(unsigned char * url)44 int check_shell_url(unsigned char *url)
45 {
46 	while (*url) {
47 		if (!is_safe_in_url(*url)) return -1;
48 		url++;
49 	}
50 	return 0;
51 }
52 
escape_path(unsigned char * path)53 unsigned char *escape_path(unsigned char *path)
54 {
55 	unsigned char *result;
56 	size_t i;
57 	if (strchr(path, '"')) return stracpy(path);
58 	for (i = 0; path[i]; i++) if (!is_safe_in_url(path[i])) goto do_esc;
59 	return stracpy(path);
60 	do_esc:
61 	result = stracpy("\"");
62 	add_to_strn(&result, path);
63 	add_to_strn(&result, "\"");
64 	return result;
65 }
66 
get_e(unsigned char * env)67 static inline int get_e(unsigned char *env)
68 {
69 	unsigned char *v;
70 	if ((v = getenv(env))) return atoi(v);
71 	return 0;
72 }
73 
do_signal(int sig,void (* handler)(int))74 void do_signal(int sig, void (*handler)(int))
75 {
76 	errno = 0;
77 	while (signal(sig, handler) == SIG_ERR && errno == EINTR) errno = 0;
78 }
79 
ignore_signals(void)80 void ignore_signals(void)
81 {
82 	do_signal(SIGPIPE, SIG_IGN);
83 #ifdef SIGXFSZ
84 	do_signal(SIGXFSZ, SIG_IGN);
85 #endif
86 #ifdef OPENVMS
87 	do_signal(SIGCHLD, SIG_IGN);
88 	do_signal(SIGINT, SIG_IGN);
89 #endif
90 }
91 
92 #ifdef WIN32
93 #include <windows.h>
94 #endif
95 
96 #ifdef OS2
97 
98 #define INCL_MOU
99 #define INCL_VIO
100 #define INCL_DOSPROCESS
101 #define INCL_DOSERRORS
102 #define INCL_DOSMODULEMGR
103 #define INCL_DOSMISC
104 #define INCL_WINCLIPBOARD
105 #define INCL_WINSWITCHLIST
106 #include <os2.h>
107 #include <io.h>
108 #include <process.h>
109 #include <sys/video.h>
110 #ifdef HAVE_SYS_FMUTEX_H
111 #include <sys/builtin.h>
112 #include <sys/fmutex.h>
113 #endif
114 
115 #ifdef X2
116 /* from xf86sup - XFree86 OS/2 support driver */
117 #include <pty.h>
118 #endif
119 
120 #endif
121 
122 #if defined(O_SIZE) && defined(__EMX__)
123 
can_prealloc(unsigned char * name)124 int can_prealloc(unsigned char *name)
125 {
126 	return name[0] && name[1] == ':' && dir_sep(name[2]);
127 }
128 
open_prealloc(unsigned char * name,int flags,int mode,off_t siz)129 int open_prealloc(unsigned char *name, int flags, int mode, off_t siz)
130 {
131 	int h;
132 	EINTRLOOP(h, open(name, flags | O_SIZE, mode, (unsigned long)siz));
133 	return h;
134 }
135 
prealloc_truncate(int h,off_t siz)136 void prealloc_truncate(int h, off_t siz)
137 {
138 	int rs;
139 	EINTRLOOP(rs, ftruncate(h, siz));
140 }
141 
142 #endif
143 
144 /* Terminal size */
145 
146 #if defined(WIN32) || defined(OPENVMS)
147 
148 /* Cygwin has a bug and loses SIGWINCH sometimes, so poll it */
149 
winch_thread(void * p,int l)150 static void winch_thread(void *p, int l)
151 {
152 	static int old_xsize, old_ysize;
153 	static int cur_xsize, cur_ysize;
154 	if (get_terminal_size(1, &old_xsize, &old_ysize)) return;
155 	while (1) {
156 		if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
157 		if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
158 			int rr;
159 			old_xsize = cur_xsize;
160 			old_ysize = cur_ysize;
161 			EINTRLOOP(rr, raise(SIGWINCH));
162 		}
163 		sleep(1);
164 	}
165 }
166 
terminal_resize_poll(void)167 static void terminal_resize_poll(void)
168 {
169 	static int winch_thread_running = 0;
170 	if (!winch_thread_running) {
171 		if (start_thread(winch_thread, NULL, 0) >= 0)
172 			winch_thread_running = 1;
173 	}
174 }
175 
176 #endif
177 
178 #if defined(UNIX) || defined(WIN32) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(OPENVMS)
179 
180 #ifdef SIGWINCH
sigwinch(void * s)181 void sigwinch(void *s)
182 {
183 	((void (*)())s)();
184 }
185 #endif
186 
handle_terminal_resize(int fd,void (* fn)())187 void handle_terminal_resize(int fd, void (*fn)())
188 {
189 #ifdef SIGWINCH
190 	install_signal_handler(SIGWINCH, sigwinch, fn, 0);
191 #endif
192 #ifdef WIN32
193 	terminal_resize_poll();
194 #endif
195 #ifdef OPENVMS
196 	if (is_xterm())
197 		terminal_resize_poll();
198 #endif
199 }
200 
unhandle_terminal_resize(int fd)201 void unhandle_terminal_resize(int fd)
202 {
203 #ifdef SIGWINCH
204 	install_signal_handler(SIGWINCH, NULL, NULL, 0);
205 #endif
206 }
207 
208 #if !defined(OPENVMS)
209 
get_terminal_size(int fd,int * x,int * y)210 int get_terminal_size(int fd, int *x, int *y)
211 {
212 	int rs = -1;
213 #ifdef TIOCGWINSZ
214 #ifdef __SUNPRO_C
215 	volatile	/* Sun Studio misoptimizes it */
216 #endif
217 	struct winsize ws;
218 	EINTRLOOP(rs, ioctl(1, TIOCGWINSZ, &ws));
219 #endif
220 	if ((rs == -1
221 #ifdef TIOCGWINSZ
222 		|| !(*x = ws.ws_col)
223 #endif
224 		) && !(*x = get_e("COLUMNS"))) {
225 		*x = 80;
226 #ifdef _UWIN
227 		*x = 79;
228 #endif
229 	}
230 	if ((rs == -1
231 #ifdef TIOCGWINSZ
232 		|| !(*y = ws.ws_row)
233 #endif
234 		) && !(*y = get_e("LINES"))) {
235 		*y = 24;
236 	}
237 	return 0;
238 }
239 
240 #endif
241 
242 #elif defined(OS2)
243 
244 #define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2
245 
is_xterm(void)246 int is_xterm(void)
247 {
248 	static int xt = -1;
249 	if (xt == -1) xt = !!getenv("WINDOWID");
250 	return xt;
251 }
252 
253 int winch_pipe[2];
254 int winch_thread_running = 0;
255 
256 #define WINCH_SLEEPTIME 500 /* time in ms for winch thread to sleep */
257 
winch_thread(void)258 void winch_thread(void)
259 {
260 	/* A thread which regularly checks whether the size of
261 	   window has changed. Then raise SIGWINCH or notifiy
262 	   the thread responsible to handle this. */
263 	static int old_xsize, old_ysize;
264 	static int cur_xsize, cur_ysize;
265 
266 	ignore_signals();
267 	if (get_terminal_size(1, &old_xsize, &old_ysize)) return;
268 	while (1) {
269 		if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
270 		if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
271 			int wr;
272 			old_xsize = cur_xsize;
273 			old_ysize = cur_ysize;
274 			EINTRLOOP(wr, write(winch_pipe[1], "x", 1));
275 			/* Resizing may take some time. So don't send a flood
276 			   of requests?! */
277 			_sleep2(2*WINCH_SLEEPTIME);
278 		}
279 		else
280 			_sleep2(WINCH_SLEEPTIME);
281 	}
282 }
283 
winch(void * s)284 void winch(void *s)
285 {
286 	unsigned char c;
287 	while (can_read(winch_pipe[0])) {
288 		int rd;
289 		EINTRLOOP(rd, read(winch_pipe[0], &c, 1));
290 		if (rd != 1) break;
291 	}
292 	((void (*)())s)();
293 }
294 
handle_terminal_resize(int fd,void (* fn)())295 void handle_terminal_resize(int fd, void (*fn)())
296 {
297 	if (!is_xterm()) return;
298 	if (!winch_thread_running) {
299 		if (c_pipe(winch_pipe) < 0) return;
300 		winch_thread_running = 1;
301 		_beginthread((void (*)(void *))winch_thread, NULL, 0x32000, NULL);
302 	}
303 	set_handlers(winch_pipe[0], winch, NULL, NULL, fn);
304 }
305 
unhandle_terminal_resize(int fd)306 void unhandle_terminal_resize(int fd)
307 {
308 	if (!winch_thread_running) return;
309 	set_handlers(winch_pipe[0], NULL, NULL, NULL, NULL);
310 }
311 
get_terminal_size(int fd,int * x,int * y)312 int get_terminal_size(int fd, int *x, int *y)
313 {
314 	if (is_xterm()) {
315 #ifdef X2
316 		int arc;
317 		struct winsize win;
318 
319 		/* fd = STDIN_FILENO; */
320 		arc = ptioctl(1, TIOCGWINSZ, &win);
321 		if (arc) {
322 			*x = 80;
323 			*y = 24;
324 			return 0;
325 		}
326 		*y = win.ws_row;
327 		*x = win.ws_col;
328 		goto set_default;
329 #else
330 		*x = 80; *y = 24;
331 		return 0;
332 #endif
333 	} else {
334 		int a[2] = { 0, 0 };
335 		_scrsize(a);
336 		*x = a[0];
337 		*y = a[1];
338 #ifdef X2
339 		set_default:
340 #endif
341 		if (*x == 0) {
342 			*x = get_e("COLUMNS");
343 			if (*x == 0) *x = 80;
344 		}
345 		if (*y == 0) {
346 			*y = get_e("LINES");
347 			if (*y == 0) *y = 24;
348 		}
349 	}
350 	return 0;
351 }
352 
353 #endif
354 
355 /* Pipe */
356 
357 #if defined(OS2) || (defined(WIN32) && !defined(_UWIN))
358 
set_bin(int fd)359 void set_bin(int fd)
360 {
361 	setmode(fd, O_BINARY);
362 }
363 
364 #else
365 
set_bin(int fd)366 void set_bin(int fd)
367 {
368 }
369 
370 #endif
371 
372 #if !defined(OPENVMS)
373 
c_pipe(int * fd)374 int c_pipe(int *fd)
375 {
376 	int r;
377 	EINTRLOOP(r, pipe(fd));
378 	if (!r) set_bin(fd[0]), set_bin(fd[1]);
379 	return r;
380 }
381 
set_nonblock(int fd)382 void set_nonblock(int fd)
383 {
384 #ifdef O_NONBLOCK
385 	int rs;
386 	EINTRLOOP(rs, fcntl(fd, F_SETFL, O_NONBLOCK));
387 #elif defined(FIONBIO)
388 	int rs;
389 	int on = 1;
390 	EINTRLOOP(rs, ioctl(fd, FIONBIO, &on));
391 #endif
392 }
393 
394 #endif
395 
396 /* Exec */
397 
398 #if defined(UNIX) || defined(ATHEOS) || defined(INTERIX)
399 
is_twterm()400 int is_twterm()
401 {
402 	static int xt = -1;
403 	if (xt == -1) xt = !!getenv("TWDISPLAY");
404 	return xt;
405 }
406 
407 #else
408 
is_twterm()409 int is_twterm()
410 {
411 	return 0;
412 }
413 
414 #endif
415 
416 #if defined(UNIX) || defined(ATHEOS) || defined(INTERIX)
417 
is_screen()418 int is_screen()
419 {
420 	static int xt = -1;
421 	if (xt == -1) xt = !!getenv("STY");
422 	return xt;
423 }
424 
425 #else
426 
is_screen()427 int is_screen()
428 {
429 	return 0;
430 }
431 
432 #endif
433 
434 #if defined(UNIX) || defined(SPAD)
435 
is_xterm()436 int is_xterm()
437 {
438 	static int xt = -1;
439 	if (xt == -1) xt = getenv("DISPLAY") && *getenv("DISPLAY");
440 	return xt;
441 }
442 
443 #elif defined(BEOS) || defined(ATHEOS)
444 
is_xterm()445 int is_xterm()
446 {
447 	return 0;
448 }
449 
450 #elif defined(WIN32) || defined(INTERIX)
451 
is_xterm(void)452 int is_xterm(void)
453 {
454 	static int xt = -1;
455 	if (xt == -1) xt = !!getenv("WINDOWID");
456 	return xt;
457 }
458 
459 #elif defined(RISCOS)
460 
is_xterm()461 int is_xterm()
462 {
463        return 1;
464 }
465 
466 #endif
467 
468 tcount resize_count = 0;
469 
close_fork_tty()470 void close_fork_tty()
471 {
472 	struct terminal *t;
473 	struct download *d;
474 	struct connection *c;
475 	struct k_conn *k;
476 	int rs;
477 	foreach (t, terminals) if (t->fdin > 0)
478 		EINTRLOOP(rs, close(t->fdin));
479 	foreach (d, downloads) if (d->handle > 0)
480 		EINTRLOOP(rs, close(d->handle));
481 	foreach (c, queue) close_socket(&c->sock1), close_socket(&c->sock2);
482 	foreach (k, keepalive_connections)
483 		EINTRLOOP(rs, close(k->conn));
484 }
485 
486 #ifdef OS2
487 static int os2_full_screen = 0;
488 static int os2_detached = 0;
489 static PTIB os2_tib = NULL;
490 static PPIB os2_pib = NULL;
491 static HSWITCH os2_switchhandle = NULLHANDLE;
492 #endif
493 
494 #ifndef OPENVMS
init_os(void)495 void init_os(void)
496 {
497 #ifdef OS2
498 	DosGetInfoBlocks(&os2_tib, &os2_pib);
499 	if (os2_pib) {
500 		os2_switchhandle = WinQuerySwitchHandle(0, os2_pib->pib_ulpid);
501 		os2_full_screen = os2_pib->pib_ultype == 0;
502 		os2_detached = os2_pib->pib_ultype == 4 || os2_pib->pib_ultype == 3;
503 	}
504 #endif
505 #if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
506 #define RLIMIT_NOFILE RLIMIT_OFILE
507 #endif
508 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
509 	struct rlimit limit;
510 	int rs;
511 	EINTRLOOP(rs, getrlimit(RLIMIT_NOFILE, &limit));
512 	if (rs)
513 		goto skip_limit;
514 	if (limit.rlim_cur > FD_SETSIZE) {
515 		limit.rlim_cur = FD_SETSIZE;
516 		EINTRLOOP(rs, setrlimit(RLIMIT_NOFILE, &limit));
517 	}
518 skip_limit:;
519 #endif
520 }
521 #endif
522 
523 #if defined(WIN32)
524 
get_path_to_exe(void)525 void get_path_to_exe(void)
526 {
527 	/* Standard method (argv[0]) doesn't work, if links is executed from
528 	   symlink --- it returns symlink name and cmd.exe is unable to start
529 	   it */
530 	unsigned r;
531 	static unsigned char path[4096];
532 	r = GetModuleFileName(NULL, path, sizeof path);
533 	if (r <= 0 || r >= sizeof path) {
534 		path_to_exe = g_argv[0];
535 		return;
536 	}
537 	path_to_exe = path;
538 }
539 
540 #elif defined(OS2)
541 
get_path_to_exe(void)542 void get_path_to_exe(void)
543 {
544 	/* If you spawn links with quotation marks from cmd.exe,
545 	   the quotation marks will be present in g_argv[0] ... and will
546 	   prevent executing it */
547 	static unsigned char path[270];
548 	path_to_exe = g_argv[0];
549 	if (DosQueryModuleName(os2_pib->pib_hmte, sizeof path, path)) return;
550 	path_to_exe = path;
551 }
552 
553 static ULONG os2_old_type;
554 static HAB os2_hab;
555 static HMQ os2_hmq;
556 
os2_init_pm(void)557 static int os2_init_pm(void)
558 {
559 	if (!os2_pib) goto err0;
560 	os2_old_type = os2_pib->pib_ultype;
561 	os2_pib->pib_ultype = 3;
562 	os2_hab = WinInitialize(0);
563 	if (os2_hab == NULLHANDLE) goto err1;
564 	os2_hmq = WinCreateMsgQueue(os2_hab, 0);
565 	if (os2_hmq == NULLHANDLE) goto err2;
566 	return 0;
567 err2:
568 	WinTerminate(os2_hab);
569 err1:
570 	os2_pib->pib_ultype = os2_old_type;
571 err0:
572 	return -1;
573 }
574 
os2_exit_pm(void)575 static void os2_exit_pm(void)
576 {
577 	WinDestroyMsgQueue(os2_hmq);
578 	WinTerminate(os2_hab);
579 	os2_pib->pib_ultype = os2_old_type;
580 }
581 
os_get_system_name(unsigned char * buffer)582 int os_get_system_name(unsigned char *buffer)
583 {
584 	ULONG version[3];
585 	if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, version, sizeof version))
586 		return -1;
587 	if (version[0] == 20) {
588 		version[0] = 2;
589 		if (version[1] == 10) {
590 			version[1] = 1;
591 		} else if (version[1] >= 30) {
592 			version[0] = version[1] / 10;
593 			version[1] %= 10;
594 		}
595 	}
596 	sprintf(buffer, "OS/2 %d.%d i386", (int)version[0], (int)version[1]);
597 	return 0;
598 }
599 
600 #elif !defined(OPENVMS)
601 
get_path_to_exe(void)602 void get_path_to_exe(void)
603 {
604 	path_to_exe = g_argv[0];
605 }
606 
607 #endif
608 
init_os_terminal(void)609 void init_os_terminal(void)
610 {
611 #ifdef INTERIX
612 	/* Some sort of terminal bug in Interix, if we run xterm -e links,
613 	   terminal doesn't switch to raw mode, executing "stty sane" fixes it.
614 	   Don't do this workaround on console. */
615 	unsigned char *term = getenv("TERM");
616 	if (!term || strncasecmp(term, "interix", 7)) {
617 		system("stty sane 2>/dev/null");
618 	}
619 #endif
620 #ifdef OS2
621 	if (os2_detached) {
622 		error("Links doesn't work in detached or PM session");
623 		fatal_tty_exit();
624 		exit(RET_FATAL);
625 	}
626 #endif
627 }
628 
629 #ifdef INTERIX
630 
cut_program_path(unsigned char * prog,unsigned char ** prog_start,unsigned char ** prog_end)631 static inline void cut_program_path(unsigned char *prog, unsigned char **prog_start, unsigned char **prog_end)
632 {
633 	while (WHITECHAR(*prog)) prog++;
634 	if (prog[0] == '"' || prog[0] == '\'') {
635 		*prog_start = prog + 1;
636 		*prog_end = strchr(prog + 1, prog[0]);
637 		if (!*prog_end)
638 			*prog_end = strchr(prog, 0);
639 	} else {
640 		*prog_start = prog;
641 		*prog_end = prog + strcspn(prog, " ");
642 	}
643 }
644 
is_windows_drive(unsigned char * prog_start,unsigned char * prog_end)645 static inline int is_windows_drive(unsigned char *prog_start, unsigned char *prog_end)
646 {
647 	if (prog_end - prog_start >= 3 && upcase(prog_start[0]) >= 'A' && upcase(prog_start[0]) <= 'Z' && prog_start[1] == ':')
648 		return 1;
649 	return 0;
650 }
651 
is_windows_program(unsigned char * prog_start,unsigned char * prog_end)652 static inline int is_windows_program(unsigned char *prog_start, unsigned char *prog_end)
653 {
654 	if (prog_end - prog_start > 4 && (
655 		!strncasecmp(prog_end - 4, ".exe", 4) ||
656 		!strncasecmp(prog_end - 4, ".bat", 4)))
657 			return 1;
658 	return 0;
659 }
660 
661 #endif
662 
663 #if defined(WIN32) && defined(HAVE_CYGWIN_CONV_PATH)
664 
os_conv_to_external_path(unsigned char * file,unsigned char * prog)665 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
666 {
667 	unsigned char *new_path;
668 	ssize_t sz;
669 	sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, NULL, 0);
670 	if (sz < 0) return stracpy(file);
671 	new_path = mem_alloc(sz);
672 	sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, new_path, sz);
673 	if (sz < 0) {
674 		mem_free(new_path);
675 		return stracpy(file);
676 	}
677 	return new_path;
678 }
679 
680 #elif defined(WIN32) && defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH)
681 
os_conv_to_external_path(unsigned char * file,unsigned char * prog)682 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
683 {
684 #ifdef MAX_PATH
685 	unsigned char new_path[MAX_PATH];
686 #else
687 	unsigned char new_path[1024];
688 #endif
689 	*new_path = 0;
690 	cygwin_conv_to_full_win32_path(file, new_path);
691 	if (!*new_path) return stracpy(file);
692 	return stracpy(new_path);
693 }
694 
695 #elif defined(WIN32) && defined(HAVE_UWIN_PATH)
696 
os_conv_to_external_path(unsigned char * file,unsigned char * prog)697 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
698 {
699 	unsigned char *new_path;
700 	ssize_t sz, sz2;
701 	sz = uwin_path(file, NULL, 0);
702 	if (sz < 0) return stracpy(file);
703 	new_path = mem_alloc(sz + 1);
704 	sz2 = uwin_path(file, new_path, sz + 1);
705 	if (sz2 < 0 || sz2 > sz) {
706 		mem_free(new_path);
707 		return stracpy(file);
708 	}
709 	return new_path;
710 }
711 
712 #elif defined(INTERIX) && defined(HAVE_UNIXPATH2WIN)
713 
os_conv_to_external_path(unsigned char * file,unsigned char * prog)714 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
715 {
716 	unsigned char *prog_start, *prog_end;
717 	cut_program_path(prog, &prog_start, &prog_end);
718 	/* Convert path only if the program has ".exe" or ".bat" extension */
719 	if (is_windows_program(prog_start, prog_end)) {
720 #ifdef MAX_PATH
721 		unsigned char new_path[MAX_PATH];
722 #else
723 		unsigned char new_path[512];
724 #endif
725 		unsigned char *newstr;
726 		int newstrl;
727 		unsigned char *p;
728 		if (unixpath2win(file, 0, new_path, sizeof(new_path)))
729 			goto copy_path;
730 		/*return stracpy(new_path);*/
731 		newstr = init_str();
732 		newstrl = 0;
733 		for (p = new_path; *p; p++) {
734 			/*
735 			 * Unix shell hates backslash and Windows applications
736 			 * accept '/'
737 			 */
738 			if (*p == '\\') add_to_str(&newstr, &newstrl, "/");
739 			else add_chr_to_str(&newstr, &newstrl, *p);
740 		}
741 		return newstr;
742 	}
743 	copy_path:
744 	return stracpy(file);
745 }
746 
747 #else
748 
os_conv_to_external_path(unsigned char * file,unsigned char * prog)749 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
750 {
751 	return stracpy(file);
752 }
753 
754 #endif
755 
756 #if defined(INTERIX) && defined(HAVE_WINPATH2UNIX)
757 
os_fixup_external_program(unsigned char * prog)758 unsigned char *os_fixup_external_program(unsigned char *prog)
759 {
760 	unsigned char *prog_start, *prog_end;
761 	cut_program_path(prog, &prog_start, &prog_end);
762 	if (is_windows_drive(prog_start, prog_end)) {
763 #ifdef MAX_PATH
764 		unsigned char new_path[MAX_PATH];
765 #else
766 		unsigned char new_path[1024];
767 #endif
768 		unsigned char *newstr;
769 		int newstrl;
770 		unsigned char *xpath;
771 		if (is_windows_program(prog_start, prog_end)) {
772 			/*
773 			 * There is some bug in Interix. Executing Win32
774 			 * binaries works from the console but doesn't work
775 			 * from xterm. So we prepend "cmd /c" to the program
776 			 * as a workaround.
777 			 */
778 			newstr = init_str();
779 			newstrl = 0;
780 			add_to_str(&newstr, &newstrl, "cmd /c ");
781 			add_to_str(&newstr, &newstrl, prog);
782 			return newstr;
783 		}
784 		xpath = memacpy(prog_start, prog_end - prog_start);
785 		if (winpath2unix(xpath, 0, new_path, sizeof(new_path))) {
786 			mem_free(xpath);
787 			goto copy_prog;
788 		}
789 		mem_free(xpath);
790 		newstr = init_str();
791 		newstrl = 0;
792 		add_bytes_to_str(&newstr, &newstrl, prog, prog_start - prog);
793 		add_to_str(&newstr, &newstrl, new_path);
794 		add_to_str(&newstr, &newstrl, prog_end);
795 		return newstr;
796 	}
797 	copy_prog:
798 	return stracpy(prog);
799 }
800 
801 #else
802 
os_fixup_external_program(unsigned char * prog)803 unsigned char *os_fixup_external_program(unsigned char *prog)
804 {
805 	return stracpy(prog);
806 }
807 
808 #endif
809 
810 
811 #if defined(UNIX) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(OPENVMS)
812 
813 #if defined(BEOS) && defined(HAVE_SETPGID)
814 
exe(unsigned char * path)815 int exe(unsigned char *path)
816 {
817 	pid_t p, rp;
818 	int s, rs;
819 	EINTRLOOP(p, fork());
820 	if (!p) {
821 		EINTRLOOP(rs, setpgid(0, 0));
822 		system(path);
823 		_exit(0);
824 	}
825 	if (p > 0) {
826 		EINTRLOOP(rp, waitpid(p, &s, 0));
827 	} else {
828 		return system(path);
829 	}
830 	return 0;
831 }
832 
833 #else
834 
835 /* UNIX */
exe(unsigned char * path)836 int exe(unsigned char *path)
837 {
838 #ifndef EXEC_IN_THREADS
839 	do_signal(SIGPIPE, SIG_DFL);
840 #ifdef SIGXFSZ
841 	do_signal(SIGXFSZ, SIG_DFL);
842 #endif
843 #ifdef SIGTSTP
844 	do_signal(SIGTSTP, SIG_DFL);
845 #endif
846 #ifdef SIGCONT
847 	do_signal(SIGCONT, SIG_DFL);
848 #endif
849 #ifdef SIGWINCH
850 	do_signal(SIGWINCH, SIG_DFL);
851 #endif
852 #endif
853 #ifdef OPENVMS
854 	if (!strcmp(path, DEFAULT_SHELL))
855 		path = "";
856 #endif
857 	return system(path);
858 }
859 
860 #endif
861 
get_clipboard_text()862 unsigned char *get_clipboard_text()	/* !!! FIXME */
863 {
864 	return stracpy("");
865 }
866 
set_clipboard_text(unsigned char * data)867 void set_clipboard_text(unsigned char *data)
868 {
869 	/* !!! FIXME */
870 }
871 
set_window_title(unsigned char * title)872 void set_window_title(unsigned char *title)
873 {
874 	/* !!! FIXME */
875 }
876 
get_window_title()877 unsigned char *get_window_title()
878 {
879 	/* !!! FIXME */
880 	return NULL;
881 }
882 
resize_window(int x,int y)883 int resize_window(int x, int y)
884 {
885 	return -1;
886 }
887 
888 #elif defined(WIN32)
889 
is_winnt(void)890 static int is_winnt(void)
891 {
892 	OSVERSIONINFO v;
893 	v.dwOSVersionInfoSize = sizeof v;
894 	if (!GetVersionEx(&v)) return 0;
895 	return v.dwPlatformId >= VER_PLATFORM_WIN32_NT;
896 }
897 
898 #define WIN32_START_STRING	"start /wait "
899 
exe(unsigned char * path)900 int exe(unsigned char *path)
901 {
902 	/* This is very tricky. We must have exactly 3 arguments, the first
903 	   one shell and the second one "/c", otherwise Cygwin would quote
904 	   the arguments and trash them */
905 	int ct;
906 	unsigned char buffer[1024];
907 	unsigned char buffer2[1024];
908 	size_t want_alloc;
909 	pid_t pid, rp;
910 	int rs;
911 	unsigned char *x1;
912 	unsigned char *arg;
913 	x1 = GETSHELL;
914 	if (!x1) x1 = DEFAULT_SHELL;
915 
916 	want_alloc = strlen(WIN32_START_STRING) + 3 + strlen(path) + 1;
917 #ifdef _UWIN
918 	want_alloc += strlen(x1) + 4;
919 	want_alloc *= 2;
920 #endif
921 
922 	arg = malloc(want_alloc);
923 	if (!arg) return -1;
924 	*arg = 0;
925 #ifdef _UWIN
926 	strcat(arg, x1);
927 	strcat(arg, " /c ");
928 #endif
929 	strcat(arg, WIN32_START_STRING);
930 	if (*path == '"' && strlen(x1) >= 7 && !strcasecmp(x1 + strlen(x1) - 7, "cmd.exe")) strcat(arg, "\"\" ");
931 	strcat(arg, path);
932 	ct = GetConsoleTitle(buffer, sizeof buffer);
933 #if defined(_UWIN) && !defined(__DMC__)
934 	{
935 		unsigned char *q1 = arg, *q2 = arg;
936 		while (*q1) {
937 			if (*q1 == '\\') q2++;
938 			q2++;
939 			q1++;
940 		}
941 		while (1) {
942 			*q2 = *q1;
943 			if (*q1 == '\\') {
944 				q2--;
945 				*q2 = '\\';
946 			}
947 			if (q1 == arg) break;
948 			q1--;
949 			q2--;
950 		}
951 	}
952 	/* UWin corrupts heap if we use threads and fork */
953 	pid = spawnl("/bin/sh", "/bin/sh", "-c", arg, NULL);
954 #else
955 #if 0		/* spawn breaks mouse, don't use this */
956 	if (is_winnt()) {
957 		/* spawn crashes on Win98 */
958 		spawnlp(_P_WAIT, x1, x1, "/c", arg, NULL);
959 		goto free_ret;
960 	} else
961 #endif
962 	{
963 		EINTRLOOP(pid, fork());
964 		if (!pid) {
965 			int i;
966 	/* Win98 crashes if we spawn command.com and have some sockets open */
967 			for (i = 0; i < FD_SETSIZE; i++)
968 				EINTRLOOP(rs, close(i));
969 			EINTRLOOP(rs, open("nul", O_RDONLY));
970 			EINTRLOOP(rs, open("nul", O_WRONLY));
971 			EINTRLOOP(rs, open("nul", O_WRONLY));
972 			EINTRLOOP(rs, execlp(x1, x1, "/c", arg, NULL));
973 			_exit(1);
974 		}
975 	}
976 #endif
977 	if (!is_winnt()) {
978 		sleep(1);
979 		if (ct && GetConsoleTitle(buffer2, sizeof buffer2) && !casecmp(buffer2, "start", 5)) {
980 			SetConsoleTitle(buffer);
981 		}
982 	}
983 	if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0));
984 	goto free_ret;
985 
986 	free_ret:
987 	free(arg);
988 	return 0;
989 }
990 
get_clipboard_text()991 unsigned char *get_clipboard_text()
992 {
993 	unsigned char buffer[256];
994 	unsigned char *str, *s, *d;
995 	int l;
996 	int r;
997 	int rs;
998 	int h;
999 	EINTRLOOP(h, open("/dev/clipboard", O_RDONLY));
1000 	if (h == -1) return stracpy("");
1001 	set_bin(h);	/* O_TEXT doesn't work on clipboard handle */
1002 	str = init_str();
1003 	l = 0;
1004 	/* Don't use hard_read because UWin has buggy end-of-file signalling.
1005 	   It resets the position to the beginning after signalling eof. */
1006 	while (1) {
1007 		EINTRLOOP(r, read(h, buffer, sizeof buffer));
1008 		if (r <= 0) break;
1009 		add_bytes_to_str(&str, &l, buffer, r);
1010 	}
1011 	EINTRLOOP(rs, close(h));
1012 	for (s = str, d = str; *s; s++)
1013 		if (!(s[0] == '\r' && s[1] == '\n')) *d++ = *s;
1014 	*d = 0;
1015 	return str;
1016 }
1017 
1018 /* Putting Czech characters to clipboard doesn't work, but it should be fixed
1019    rather in Cygwin than here */
set_clipboard_text(unsigned char * data)1020 void set_clipboard_text(unsigned char *data)
1021 {
1022 	unsigned char *conv_data;
1023 	int l;
1024 	int h;
1025 	int rs;
1026 	EINTRLOOP(h, open("/dev/clipboard", O_WRONLY));
1027 	if (h == -1) return;
1028 	set_bin(h);	/* O_TEXT doesn't work on clipboard handle */
1029 	conv_data = init_str();
1030 	l = 0;
1031 	for (; *data; data++)
1032 		if (*data == '\n') add_to_str(&conv_data, &l, "\r\n");
1033 		else add_chr_to_str(&conv_data, &l, *data);
1034 	hard_write(h, conv_data, l);
1035 	mem_free(conv_data);
1036 	EINTRLOOP(rs, close(h));
1037 }
1038 
clipboard_support(struct terminal * term)1039 int clipboard_support(struct terminal *term)
1040 {
1041 	struct stat st;
1042 	int rs;
1043 	EINTRLOOP(rs, stat("/dev/clipboard", &st));
1044 	return !rs;
1045 }
1046 
1047 
get_windows_cp(void)1048 static int get_windows_cp(void)
1049 {
1050 	unsigned char str[8];
1051 	int cp, idx;
1052 	if (is_winnt())
1053 		cp = GetConsoleOutputCP();
1054 	else
1055 		cp = GetACP();
1056 	if (cp <= 0 || cp >= 100000) return 0;
1057 	if (cp == 874) cp = 28605;
1058 	if (cp >= 28591 && cp <= 28605) {
1059 		sprintf(str, "8859-%d", cp - 28590);
1060 	} else {
1061 		sprintf(str, "%d", cp);
1062 	}
1063 	if ((idx = get_cp_index(str)) < 0) return 0;
1064 	return idx;
1065 }
1066 
get_utf8_cp(void)1067 static int get_utf8_cp(void)
1068 {
1069 	static int idx = -1;
1070 	return idx >= 0 ? idx : (idx = get_cp_index("utf-8"));
1071 }
1072 
set_window_title(unsigned char * title)1073 void set_window_title(unsigned char *title)
1074 {
1075 	unsigned char *t, *p;
1076 	struct conv_table *ct;
1077 	if (!title) return;
1078 	if (is_xterm()) return;
1079 	ct = get_translation_table(get_utf8_cp(), get_windows_cp());
1080 	t = convert_string(ct, title, strlen(title));
1081 	for (p = strchr(t, 1); p; p = strchr(p + 1, 1))
1082 		*p = ' ';
1083 	SetConsoleTitle(t);
1084 	mem_free(t);
1085 }
1086 
get_window_title(void)1087 unsigned char *get_window_title(void)
1088 {
1089 	struct conv_table *ct;
1090 	int r;
1091 	unsigned char buffer[1024];
1092 	if (is_xterm()) return NULL;
1093 	if (!(r = GetConsoleTitle(buffer, sizeof buffer))) return NULL;
1094 	ct = get_translation_table(get_windows_cp(), get_utf8_cp());
1095 	return convert_string(ct, buffer, r);
1096 }
1097 
call_resize(unsigned char * x1,int x,int y)1098 static void call_resize(unsigned char *x1, int x, int y)
1099 {
1100 	pid_t pid, rp;
1101 	int rs;
1102 	unsigned char arg[MAX_STR_LEN];
1103 #ifdef _UWIN
1104 	x++;
1105 #endif
1106 	sprintf(arg, "mode %d,%d", x, y);
1107 #if defined(_UWIN) && !defined(__DMC__)
1108 	pid = spawnlp(x1, x1, "/c", arg, NULL);
1109 #else
1110 #if 0		/* spawn breaks mouse, don't use this */
1111 	if (is_winnt()) {
1112 		/* spawn crashes on Win98 */
1113 		spawnlp(_P_WAIT, x1, x1, "/c", arg, NULL);
1114 		return;
1115 	} else
1116 #endif
1117 	{
1118 		EINTRLOOP(pid, fork());
1119 		if (!pid) {
1120 			int i;
1121 	/* Win98 crashes if we spawn command.com and have some sockets open */
1122 			for (i = 0; i < FD_SETSIZE; i++) if (i != 1 && i != 2)
1123 				EINTRLOOP(rs, close(i));
1124 			EINTRLOOP(rs, open("nul", O_WRONLY));
1125 			EINTRLOOP(rs, execlp(x1, x1, "/c", arg, NULL));
1126 			_exit(1);
1127 		}
1128 	}
1129 #endif
1130 	if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0));
1131 }
1132 
resize_window(int x,int y)1133 int resize_window(int x, int y)
1134 {
1135 	int old_x, old_y;
1136 	int ct = 0, fullscreen = 0;
1137 	unsigned char buffer[1024];
1138 	unsigned char *x1;
1139 	if (is_xterm()) return -1;
1140 	if (get_terminal_size(1, &old_x, &old_y)) return -1;
1141 	x1 = GETSHELL;
1142 	if (!x1) x1 = DEFAULT_SHELL;
1143 	if (!is_winnt()) {
1144 		ct = GetConsoleTitle(buffer, sizeof buffer);
1145 	}
1146 
1147 	call_resize(x1, x, y);
1148 	if (!is_winnt()) {
1149 		int new_x, new_y;
1150 	/* If we resize console on Win98 in fullscreen mode, it won't be
1151 	   notified by Cygwin (it is valid for all Cygwin apps). So we must
1152 	   switch to windowed mode, resize it again (twice, because resizing
1153 	   to the same size won't have an effect) and switch back to full-screen
1154 	   mode. */
1155 	/* I'm not sure what's the behavior on WinNT 4. Anybody wants to test?
1156 	   */
1157 		if (!fullscreen && !get_terminal_size(1, &new_x, &new_y) && (new_x != x || new_y != y)) {
1158 			fullscreen = 1;
1159 #ifdef __CYGWIN__
1160 			keybd_event(VK_MENU, 0x38, 0, 0);
1161 			keybd_event(VK_RETURN, 0x1c, 0, 0);
1162 			keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
1163 			keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
1164 #endif
1165 			if (y != 25) call_resize(x1, 80, 25);
1166 			else call_resize(x1, 80, 50);
1167 			call_resize(x1, x, y);
1168 			if (get_terminal_size(1, &new_x, &new_y) || new_x != x || new_y != y) call_resize(x1, old_x, old_y);
1169 #ifdef __CYGWIN__
1170 			keybd_event(VK_MENU, 0x38, 0, 0);
1171 			keybd_event(VK_RETURN, 0x1c, 0, 0);
1172 			keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
1173 			keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
1174 #endif
1175 		}
1176 		if (ct) SetConsoleTitle(buffer);
1177 	}
1178 	return 0;
1179 }
1180 
1181 #elif defined(OS2)
1182 
exe(unsigned char * path)1183 int exe(unsigned char *path)
1184 {
1185 	int flags = P_SESSION;
1186 	pid_t pid, rp;
1187 	int ret;
1188 	unsigned char *shell;
1189 	if (!(shell = GETSHELL)) shell = DEFAULT_SHELL;
1190 	if (is_xterm()) flags |= P_BACKGROUND;
1191 	if ((pid = spawnlp(flags, shell, shell, "/c", path, NULL)) != -1)
1192 		EINTRLOOP(rp, waitpid(pid, &ret, 0));
1193 	else ret = -1;
1194 	return ret;
1195 }
1196 
get_clipboard_text()1197 unsigned char *get_clipboard_text()
1198 {
1199 	unsigned char *ret = NULL;
1200 
1201 	if (os2_init_pm()) return NULL;
1202 
1203 	if (WinOpenClipbrd(os2_hab)) {
1204 		ULONG fmtInfo = 0;
1205 
1206 		if (WinQueryClipbrdFmtInfo(os2_hab, CF_TEXT, &fmtInfo)!=FALSE)
1207 		{
1208 			ULONG selClipText = WinQueryClipbrdData(os2_hab, CF_TEXT);
1209 
1210 			if (selClipText) {
1211 				unsigned char *u;
1212 				PCHAR pchClipText = (PCHAR)selClipText;
1213 				ret = stracpy(pchClipText);
1214 				while ((u = strchr(ret, 13))) memmove(u, u + 1, strlen(u + 1) + 1);
1215 			}
1216 		}
1217 
1218 		WinCloseClipbrd(os2_hab);
1219 	}
1220 
1221 	os2_exit_pm();
1222 
1223 	return ret;
1224 }
1225 
set_clipboard_text(unsigned char * data)1226 void set_clipboard_text(unsigned char *data)
1227 {
1228 	if (os2_init_pm()) return;
1229 
1230 	if (WinOpenClipbrd(os2_hab)) {
1231 		PVOID pvShrObject = NULL;
1232 		if (DosAllocSharedMem(&pvShrObject, NULL, strlen(data)+1, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) {
1233 			strcpy(pvShrObject, data);
1234 			WinEmptyClipbrd(os2_hab);
1235 			WinSetClipbrdData(os2_hab, (ULONG)pvShrObject, CF_TEXT, CFI_POINTER);
1236 		}
1237 		WinCloseClipbrd(os2_hab);
1238 	}
1239 
1240 	os2_exit_pm();
1241 }
1242 
get_window_title()1243 unsigned char *get_window_title()
1244 {
1245 #ifndef OS2_DEBUG
1246 	unsigned char *win_title = NULL;
1247 	SWCNTRL swData;
1248 
1249 	memset(&swData, 0, sizeof swData);
1250 	if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData)) {
1251 		swData.szSwtitle[MAXNAMEL - 1] = 0;
1252 		win_title = stracpy(swData.szSwtitle);
1253 		if (swData.hwnd != NULLHANDLE && !os2_init_pm()) {
1254 			LONG len = WinQueryWindowTextLength(swData.hwnd);
1255 			if (len > 0) {
1256 				mem_free(win_title);
1257 				win_title = mem_alloc(len + 1);
1258 				win_title[0] = 0;
1259 				WinQueryWindowText(swData.hwnd, len + 1, win_title);
1260 				win_title[len] = 0;
1261 			}
1262 			os2_exit_pm();
1263 		}
1264 	}
1265 
1266 	return win_title;
1267 #else
1268 	return NULL;
1269 #endif
1270 }
1271 
set_window_title(unsigned char * title)1272 void set_window_title(unsigned char *title)
1273 {
1274 #ifndef OS2_DEBUG
1275 	SWCNTRL swData;
1276 
1277 	if (!title) return;
1278 
1279 	memset(&swData, 0, sizeof swData);
1280 	if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData)) {
1281 		safe_strncpy(swData.szSwtitle, title, MAXNAMEL);
1282 		WinChangeSwitchEntry(os2_switchhandle, &swData);
1283 		if (swData.hwnd != NULLHANDLE && !os2_init_pm()) {
1284 			WinSetWindowText(swData.hwnd, title);
1285 			os2_exit_pm();
1286 		}
1287 	}
1288 #endif
1289 }
1290 
resize_window(int x,int y)1291 int resize_window(int x, int y)
1292 {
1293 	int xfont, yfont;
1294 	A_DECL(VIOMODEINFO, vmi);
1295 	SWCNTRL swData;
1296 
1297 	resize_count++;
1298 	if (is_xterm()) return -1;
1299 	vmi->cb = sizeof(*vmi);
1300 	if (VioGetMode(vmi, 0)) return -1;
1301 	vmi->col = x;
1302 	vmi->row = y;
1303 	/*debug("%d %d %d", vmi->buf_length, vmi->full_length, vmi->partial_length);*/
1304 	for (xfont = 9; xfont >= 8; xfont--)
1305 		for (yfont = 16; yfont >= 8; yfont--) {
1306 			vmi->hres = x * xfont;
1307 			vmi->vres = y * yfont;
1308 			if (vmi->vres <= 400) vmi->vres = 400;
1309 			else if (vmi->vres <= 480) vmi->vres = 480;
1310 			vmi->buf_length = vmi->full_length = vmi->partial_length = x * ((vmi->vres + yfont - 1) / yfont) * 2;
1311 			vmi->full_length = (vmi->full_length + 4095) & ~4095;
1312 			vmi->partial_length = (vmi->partial_length + 4095) & ~4095;
1313 			if (!VioSetMode(vmi, 0)) goto resized;
1314 		}
1315 	return -1;
1316 
1317 	resized:
1318 	memset(&swData, 0, sizeof swData);
1319 	if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData) && swData.hwnd != NULLHANDLE && !os2_init_pm()) {
1320 		SWP swp;
1321 		if (WinQueryWindowPos(swData.hwnd, &swp) && !(swp.fl & (SWP_MAXIMIZE | SWP_MINIMIZE | SWP_HIDE))) {
1322 			const int expand = 16383;
1323 			WinSetWindowPos(swData.hwnd, NULLHANDLE, swp.x, swp.y - expand, swp.cx + expand, swp.cy + expand, SWP_MOVE | SWP_SIZE);
1324 		}
1325 		os2_exit_pm();
1326 	}
1327 	return 0;
1328 }
1329 
1330 #endif
1331 
1332 /* Threads */
1333 
1334 #if (defined(HAVE_BEGINTHREAD) && defined(OS2)) || defined(BEOS) || defined(HAVE_PTHREADS)
1335 
1336 struct tdata {
1337 	void (*fn)(void *, int);
1338 	int h;
1339 	unsigned char data[1];
1340 };
1341 
bgt(struct tdata * t)1342 void bgt(struct tdata *t)
1343 {
1344 	int rs;
1345 	ignore_signals();
1346 	t->fn(t->data, t->h);
1347 	EINTRLOOP(rs, write(t->h, "x", 1));
1348 	EINTRLOOP(rs, close(t->h));
1349 	free(t);
1350 }
1351 
1352 #ifdef HAVE_PTHREADS
bgpt(struct tdata * t)1353 void *bgpt(struct tdata *t)
1354 {
1355 	bgt(t);
1356 	return NULL;
1357 }
1358 #endif
1359 
1360 #endif
1361 
1362 #if defined(UNIX) || defined(OS2) || defined(WIN32) || defined(INTERIX) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
1363 
terminate_osdep()1364 void terminate_osdep()
1365 {
1366 }
1367 
1368 #endif
1369 
1370 #ifndef BEOS
1371 
block_stdin()1372 void block_stdin() {}
unblock_stdin()1373 void unblock_stdin() {}
1374 
1375 #endif
1376 
1377 #if defined(BEOS)
1378 
1379 #include <be/kernel/OS.h>
1380 
1381 int thr_sem_init = 0;
1382 sem_id thr_sem;
1383 
1384 struct list_head active_threads = { &active_threads, &active_threads };
1385 
1386 struct active_thread {
1387 	struct active_thread *next;
1388 	struct active_thread *prev;
1389 	thread_id tid;
1390 	void (*fn)(void *);
1391 	void *data;
1392 };
1393 
started_thr(void * data)1394 int32 started_thr(void *data)
1395 {
1396 	struct active_thread *thrd = data;
1397 	thrd->fn(thrd->data);
1398 	if (acquire_sem(thr_sem) < B_NO_ERROR) return 0;
1399 	del_from_list(thrd);
1400 	free(thrd);
1401 	release_sem(thr_sem);
1402 	return 0;
1403 }
1404 
start_thr(void (* fn)(void *),void * data,unsigned char * name)1405 int start_thr(void (*fn)(void *), void *data, unsigned char *name)
1406 {
1407 	struct active_thread *thrd;
1408 	int tid;
1409 	if (!thr_sem_init) {
1410 		if ((thr_sem = create_sem(0, "thread_sem")) < B_NO_ERROR) return -1;
1411 		thr_sem_init = 1;
1412 	} else if (acquire_sem(thr_sem) < B_NO_ERROR) return -1;
1413 	if (!(thrd = malloc(sizeof(struct active_thread)))) goto err1;
1414 	thrd->fn = fn;
1415 	thrd->data = data;
1416 	if ((tid = thrd->tid = spawn_thread(started_thr, name, B_NORMAL_PRIORITY, thrd)) < B_NO_ERROR)
1417 		goto err2;
1418 	resume_thread(thrd->tid);
1419 	add_to_list(active_threads, thrd);
1420 	release_sem(thr_sem);
1421 	return tid;
1422 
1423 	err2:
1424 	free(thrd);
1425 	err1:
1426 	release_sem(thr_sem);
1427 	return -1;
1428 }
1429 
terminate_osdep()1430 void terminate_osdep()
1431 {
1432 	struct list_head *p;
1433 	struct active_thread *thrd;
1434 	if (acquire_sem(thr_sem) < B_NO_ERROR) return;
1435 	foreach(thrd, active_threads) kill_thread(thrd->tid);
1436 	while ((p = active_threads.next) != &active_threads) {
1437 		del_from_list(p);
1438 		free(p);
1439 	}
1440 	release_sem(thr_sem);
1441 }
1442 
start_thread(void (* fn)(void *,int),void * ptr,int l)1443 int start_thread(void (*fn)(void *, int), void *ptr, int l)
1444 {
1445 	int p[2];
1446 	struct tdata *t;
1447 	int rs;
1448 	if (c_pipe(p) < 0) return -1;
1449 	if (!(t = malloc(sizeof(struct tdata) + l))) goto err1;
1450 	t->fn = fn;
1451 	t->h = p[1];
1452 	memcpy(t->data, ptr, l);
1453 	if (start_thr((void (*)(void *))bgt, t, "links_thread") < 0)
1454 		goto err2;
1455 	return p[0];
1456 
1457 	err2:
1458 	free(t);
1459 	err1:
1460 	EINTRLOOP(rs, close(p[0]));
1461 	EINTRLOOP(rs, close(p[1]));
1462 	return -1;
1463 }
1464 
1465 
1466 #elif defined(HAVE_BEGINTHREAD) && defined(OS2)
1467 
start_thread(void (* fn)(void *,int),void * ptr,int l)1468 int start_thread(void (*fn)(void *, int), void *ptr, int l)
1469 {
1470 	int p[2];
1471 	struct tdata *t;
1472 	int rs;
1473 	if (c_pipe(p) < 0) return -1;
1474 	if (!(t = malloc(sizeof(struct tdata) + l))) goto err1;
1475 	t->fn = fn;
1476 	t->h = p[1];
1477 	memcpy(t->data, ptr, l);
1478 	if (_beginthread((void (*)(void *))bgt, NULL, 65536, t) == -1)
1479 		goto err2;
1480 	return p[0];
1481 
1482 	err2:
1483 	free(t);
1484 	err1:
1485 	EINTRLOOP(rs, close(p[0]));
1486 	EINTRLOOP(rs, close(p[1]));
1487 	return -1;
1488 }
1489 
1490 #ifdef HAVE__READ_KBD
1491 
1492 int tp = -1;
1493 int ti = -1;
1494 
input_thread(void * p)1495 void input_thread(void *p)
1496 {
1497 	unsigned char c[2];
1498 	int h = (int)p;
1499 	int rs;
1500 	ignore_signals();
1501 	while (1) {
1502 	   /* for the records:
1503 		 _read_kbd(0, 1, 1) will
1504 		 read a char, don't echo it, wait for one available and
1505 		 accept CTRL-C.
1506 		 Knowing that, I suggest we replace this call completly!
1507 	    */
1508 		*c = _read_kbd(0, 1, 1);
1509 		EINTRLOOP(rs, write(h, c, 1));
1510 	}
1511 	EINTRLOOP(rs, close(h));
1512 }
1513 #endif /* #ifdef HAVE__READ_KBD */
1514 
1515 #if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
1516 
1517 #define USING_OS2_MOUSE
1518 
1519 #ifdef HAVE_SYS_FMUTEX_H
1520 _fmutex mouse_mutex;
1521 int mouse_mutex_init = 0;
1522 #endif
1523 int mouse_h = -1;
1524 
1525 struct os2_mouse_spec {
1526 	int p[2];
1527 	void (*fn)(void *, unsigned char *, int);
1528 	void *data;
1529 	unsigned char buffer[sizeof(struct event)];
1530 	int bufptr;
1531 	int terminate;
1532 };
1533 
1534 #define MOU_EMULATE_CURSOR
1535 
1536 #ifdef MOU_EMULATE_CURSOR
1537 static int mouse_x = -1, mouse_y = -1;
1538 static unsigned char mouse_attr;
1539 #endif
1540 
mouse_remove_pointer(void)1541 static void mouse_remove_pointer(void)
1542 {
1543 #ifndef MOU_EMULATE_CURSOR
1544 	A_DECL(NOPTRRECT, pa);
1545 	static int x = -1, y = -1;
1546 	static tcount c = -1;
1547 	if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(1, &x, &y), c = resize_count;
1548 	pa->row = 0;
1549 	pa->col = 0;
1550 	pa->cRow = y - 1;
1551 	pa->cCol = x - 1;
1552 	MouRemovePtr(pa, mouse_h);
1553 #else
1554 	if (mouse_x >= 0 && mouse_y >= 0) {
1555 		VioWrtNAttr(&mouse_attr, 1, mouse_y, mouse_x, 0);
1556 	}
1557 	mouse_x = -1, mouse_y = -1;
1558 #endif
1559 }
1560 
mouse_draw_pointer(int x,int y)1561 static void mouse_draw_pointer(int x, int y)
1562 {
1563 #ifndef MOU_EMULATE_CURSOR
1564 	MouDrawPtr(mouse_h);
1565 #else
1566 	unsigned char str[4];
1567 	USHORT str_len;
1568 	unsigned char attr;
1569 	unsigned char fg, bg;
1570 	int r;
1571 	if (!os2_full_screen)
1572 		return;
1573 	DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
1574 	if (mouse_x == x && mouse_y == y)
1575 		return;
1576 	mouse_remove_pointer();
1577 	str_len = sizeof(str);
1578 	r = VioReadCellStr(str, &str_len, y, x, 0);
1579 	if (r || str_len < 2) return;
1580 	mouse_attr = str[1];
1581 	fg = mouse_attr & 0x07;
1582 	bg = (mouse_attr & 0x70) >> 4;
1583 	if (fg == bg) fg ^= 0x07, bg ^= 0x07;
1584 	attr = (mouse_attr & 0x88) | (fg << 4) | bg;
1585 	r = VioWrtNAttr(&attr, 1, y, x, 0);
1586 	if (r) return;
1587 	mouse_x = x, mouse_y = y, mouse_attr = str[1];
1588 #endif
1589 }
1590 
mouse_thread(void * p)1591 void mouse_thread(void *p)
1592 {
1593 	int status;
1594 	int rs;
1595 	struct os2_mouse_spec *oms = p;
1596 	A_DECL(HMOU, mh);
1597 	A_DECL(MOUEVENTINFO, ms);
1598 	A_DECL(USHORT, rd);
1599 	A_DECL(USHORT, mask);
1600 	struct event ev;
1601 	ignore_signals();
1602 	ev.ev = EV_MOUSE;
1603 	if (MouOpen(NULL, mh)) goto ret;
1604 	mouse_h = *mh;
1605 	*mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
1606 		MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
1607 		MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
1608 		MOUSE_MOTION;
1609 	MouSetEventMask(mask, *mh);
1610 	*rd = MOU_WAIT;
1611 	status = -1;
1612 	while (1) {
1613 		if (MouReadEventQue(ms, rd, *mh)) break;
1614 #ifdef HAVE_SYS_FMUTEX_H
1615 		_fmutex_request(&mouse_mutex, _FMR_IGNINT);
1616 #endif
1617 		if (!oms->terminate) mouse_draw_pointer(ms->col, ms->row);
1618 #ifdef HAVE_SYS_FMUTEX_H
1619 		_fmutex_release(&mouse_mutex);
1620 #endif
1621 		ev.x = ms->col;
1622 		ev.y = ms->row;
1623 		/*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/
1624 		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);
1625 		else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
1626 			int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_RIGHT : B_MIDDLE;
1627 			if (status == -1) b |= B_DOWN;
1628 			else b |= B_DRAG;
1629 			ev.b = status = b;
1630 		}
1631 		else {
1632 			if (status == -1) continue;
1633 			ev.b = (status & BM_BUTT) | B_UP;
1634 			status = -1;
1635 		}
1636 		if (hard_write(oms->p[1], (unsigned char *)&ev, sizeof(struct event)) != sizeof(struct event)) break;
1637 	}
1638 #ifdef HAVE_SYS_FMUTEX_H
1639 	_fmutex_request(&mouse_mutex, _FMR_IGNINT);
1640 #endif
1641 	mouse_h = -1;
1642 	MouClose(*mh);
1643 #ifdef HAVE_SYS_FMUTEX_H
1644 	_fmutex_release(&mouse_mutex);
1645 #endif
1646 	ret:
1647 	EINTRLOOP(rs, close(oms->p[1]));
1648 	/*free(oms);*/
1649 }
1650 
mouse_handle(struct os2_mouse_spec * oms)1651 void mouse_handle(struct os2_mouse_spec *oms)
1652 {
1653 	int r;
1654 	EINTRLOOP(r, read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct event) - oms->bufptr));
1655 	if (r <= 0) {
1656 		unhandle_mouse(oms);
1657 		return;
1658 	}
1659 	if ((oms->bufptr += r) == sizeof(struct event)) {
1660 		oms->bufptr = 0;
1661 		oms->fn(oms->data, oms->buffer, sizeof(struct event));
1662 	}
1663 }
1664 
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)1665 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
1666 {
1667 	struct os2_mouse_spec *oms;
1668 	if (is_xterm()) return NULL;
1669 #ifdef HAVE_SYS_FMUTEX_H
1670 	if (!mouse_mutex_init) {
1671 		if (_fmutex_create(&mouse_mutex, 0)) return NULL;
1672 		mouse_mutex_init = 1;
1673 	}
1674 #endif
1675 		/* This is never freed but it's allocated only once */
1676 	if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) return NULL;
1677 	oms->fn = fn;
1678 	oms->data = data;
1679 	oms->bufptr = 0;
1680 	oms->terminate = 0;
1681 	if (c_pipe(oms->p)) {
1682 		free(oms);
1683 		return NULL;
1684 	}
1685 	_beginthread(mouse_thread, NULL, 0x10000, (void *)oms);
1686 	set_handlers(oms->p[0], (void (*)(void *))mouse_handle, NULL, NULL, oms);
1687 	return oms;
1688 }
1689 
unhandle_mouse(void * om)1690 void unhandle_mouse(void *om)
1691 {
1692 	struct os2_mouse_spec *oms = om;
1693 	int rs;
1694 	want_draw();
1695 	oms->terminate = 1;
1696 	set_handlers(oms->p[0], NULL, NULL, NULL, NULL);
1697 	EINTRLOOP(rs, close(oms->p[0]));
1698 	done_draw();
1699 }
1700 
want_draw()1701 void want_draw()
1702 {
1703 	static int ansi = 0;
1704 #ifdef HAVE_SYS_FMUTEX_H
1705 	if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT);
1706 #endif
1707 	if (!ansi) {
1708 		VioSetAnsi(1, 0);
1709 		ansi = 1;
1710 	}
1711 	if (mouse_h != -1) {
1712 		mouse_remove_pointer();
1713 	}
1714 }
1715 
done_draw()1716 void done_draw()
1717 {
1718 #ifdef HAVE_SYS_FMUTEX_H
1719 	if (mouse_mutex_init) _fmutex_release(&mouse_mutex);
1720 #endif
1721 }
1722 
1723 #endif /* if HAVE_MOUOPEN */
1724 
1725 #elif defined(HAVE_PTHREADS)
1726 
1727 #include <pthread.h>
1728 
1729 #ifdef OPENVMS
1730 #define THREAD_NEED_STACK_SIZE		65536
1731 int vms_thread_high_priority = 0;
1732 #endif
1733 
start_thread(void (* fn)(void *,int),void * ptr,int l)1734 int start_thread(void (*fn)(void *, int), void *ptr, int l)
1735 {
1736 #ifdef THREAD_NEED_STACK_SIZE
1737 	pthread_attr_t attr;
1738 #endif
1739 	pthread_t thread;
1740 	struct tdata *t;
1741 	int p[2];
1742 	int rs;
1743 	if (c_pipe(p) < 0) return -1;
1744 	if (!(t = malloc(sizeof(struct tdata) + l))) goto err1;
1745 	t->fn = fn;
1746 	t->h = p[1];
1747 	memcpy(t->data, ptr, l);
1748 #ifdef THREAD_NEED_STACK_SIZE
1749 	if (pthread_attr_init(&attr))
1750 		goto err2;
1751 	if (pthread_attr_setstacksize(&attr, THREAD_NEED_STACK_SIZE))
1752 		goto err3;
1753 	if (vms_thread_high_priority) {
1754 		struct sched_param param;
1755 		memset(&param, 0, sizeof param);
1756 		if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED))
1757 			goto err3;
1758 		if (vms_thread_high_priority > 0) {
1759 			if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO))
1760 				goto err3;
1761 			param.sched_priority = PRI_FIFO_MIN;
1762 			if (pthread_attr_setschedparam(&attr, &param))
1763 				goto err3;
1764 		} else {
1765 			if (pthread_attr_setschedpolicy(&attr, SCHED_LFI_NP))
1766 				goto err3;
1767 			param.sched_priority = PRI_BG_MIN_NP;
1768 			if (pthread_attr_setschedparam(&attr, &param))
1769 				goto err3;
1770 		}
1771 	}
1772 	if (pthread_create(&thread, &attr, (void *(*)(void *))bgpt, t))
1773 		goto err3;
1774 	pthread_attr_destroy(&attr);
1775 #else
1776 	if (pthread_create(&thread, NULL, (void *(*)(void *))bgpt, t))
1777 		goto err3;
1778 #endif
1779 	return p[0];
1780 
1781 	err3:
1782 #ifdef THREAD_NEED_STACK_SIZE
1783 	pthread_attr_destroy(&attr);
1784 	err2:
1785 #endif
1786 	free(t);
1787 	err1:
1788 	EINTRLOOP(rs, close(p[0]));
1789 	EINTRLOOP(rs, close(p[1]));
1790 	return -1;
1791 }
1792 
1793 #elif defined(DOS)
1794 
start_thread(void (* fn)(void *,int),void * ptr,int l)1795 int start_thread(void (*fn)(void *, int), void *ptr, int l)
1796 {
1797 	int fd;
1798 	fd = open("/dev/null", O_RDONLY);
1799 	if (fd == -1) return -1;
1800 	fn(ptr, l);
1801 	return fd;
1802 }
1803 
1804 #else /* HAVE_BEGINTHREAD */
1805 
start_thread(void (* fn)(void *,int),void * ptr,int l)1806 int start_thread(void (*fn)(void *, int), void *ptr, int l)
1807 {
1808 	int p[2];
1809 	pid_t f;
1810 	int rs;
1811 	if (c_pipe(p) < 0) return -1;
1812 	EINTRLOOP(f, fork());
1813 	if (!f) {
1814 		close_fork_tty();
1815 		EINTRLOOP(rs, close(p[0]));
1816 		fn(ptr, p[1]);
1817 		EINTRLOOP(rs, write(p[1], "x", 1));
1818 		EINTRLOOP(rs, close(p[1]));
1819 		_exit(0);
1820 	}
1821 	if (f == -1) {
1822 		EINTRLOOP(rs, close(p[0]));
1823 		EINTRLOOP(rs, close(p[1]));
1824 		return -1;
1825 	}
1826 	EINTRLOOP(rs, close(p[1]));
1827 	return p[0];
1828 }
1829 
1830 #endif
1831 
1832 #ifndef USING_OS2_MOUSE
want_draw()1833 void want_draw() {}
done_draw()1834 void done_draw() {}
1835 #endif
1836 
get_output_handle()1837 int get_output_handle() { return 1; }
1838 
1839 #if defined(OS2)
1840 
get_ctl_handle()1841 int get_ctl_handle() { return get_input_handle(); }
1842 
1843 #else
1844 
get_ctl_handle()1845 int get_ctl_handle() { return 0; }
1846 
1847 #endif
1848 
1849 #if defined(BEOS)
1850 
1851 #elif defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD)
get_input_handle()1852 int get_input_handle()
1853 {
1854 	int rs;
1855 	int fd[2];
1856 	if (ti != -1) return ti;
1857 	if (is_xterm()) return 0;
1858 	if (c_pipe(fd) < 0) return 0;
1859 	ti = fd[0];
1860 	tp = fd[1];
1861 	if (_beginthread(input_thread, NULL, 0x10000, (void *)tp) == -1) {
1862 		EINTRLOOP(rs, close(fd[0]));
1863 		EINTRLOOP(rs, close(fd[1]));
1864 		return 0;
1865 	}
1866 /*
1867 #if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
1868 	_beginthread(mouse_thread, NULL, 0x10000, (void *)tp);
1869 #endif
1870 */
1871 	return fd[0];
1872 }
1873 
1874 #elif !defined(OPENVMS)
1875 
get_input_handle()1876 int get_input_handle()
1877 {
1878 	return 0;
1879 }
1880 
1881 #endif /* defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD) */
1882 
1883 #ifdef USE_GPM
1884 
1885 struct gpm_mouse_spec {
1886 	int h;
1887 	void (*fn)(void *, unsigned char *, int);
1888 	void *data;
1889 };
1890 
1891 /* GPM installs its own signal handlers and we don't want them */
1892 
1893 sigset_t gpm_sigset;
1894 char gpm_sigset_valid;
1895 #ifdef SIGWINCH
1896 struct sigaction gpm_winch;
1897 char gpm_winch_valid;
1898 #endif
1899 #ifdef SIGTSTP
1900 struct sigaction gpm_tstp;
1901 char gpm_tstp_valid;
1902 #endif
1903 
save_gpm_signals(void)1904 static void save_gpm_signals(void)
1905 {
1906 	sigset_t sig;
1907 	int rs;
1908 	sigemptyset(&sig);
1909 #ifdef SIGWINCH
1910 	sigaddset(&sig, SIGWINCH);
1911 #endif
1912 #ifdef SIGTSTP
1913 	sigaddset(&sig, SIGTSTP);
1914 #endif
1915 	EINTRLOOP(rs, do_sigprocmask(SIG_BLOCK, &sig, &gpm_sigset));
1916 	gpm_sigset_valid = !rs;
1917 #ifdef SIGWINCH
1918 	EINTRLOOP(rs, sigaction(SIGWINCH, NULL, &gpm_winch));
1919 	gpm_winch_valid = !rs;
1920 #endif
1921 #ifdef SIGTSTP
1922 	EINTRLOOP(rs, sigaction(SIGTSTP, NULL, &gpm_tstp));
1923 	gpm_tstp_valid = !rs;
1924 #endif
1925 }
1926 
restore_gpm_signals(void)1927 static void restore_gpm_signals(void)
1928 {
1929 	int rs;
1930 #ifdef SIGWINCH
1931 	if (gpm_winch_valid)
1932 		EINTRLOOP(rs, sigaction(SIGWINCH, &gpm_winch, NULL));
1933 #endif
1934 #ifdef SIGTSTP
1935 	if (gpm_tstp_valid)
1936 		EINTRLOOP(rs, sigaction(SIGTSTP, &gpm_tstp, NULL));
1937 #endif
1938 	if (gpm_sigset_valid)
1939 		EINTRLOOP(rs, do_sigprocmask(SIG_SETMASK, &gpm_sigset, NULL));
1940 }
1941 
gpm_mouse_in(struct gpm_mouse_spec * gms)1942 void gpm_mouse_in(struct gpm_mouse_spec *gms)
1943 {
1944 	int g;
1945 	Gpm_Event gev;
1946 	struct event ev;
1947 	save_gpm_signals();
1948 	g = Gpm_GetEvent(&gev);
1949 	restore_gpm_signals();
1950 	if (g <= 0) {
1951 		set_handlers(gms->h, NULL, NULL, NULL, NULL);
1952 		gms->h = -1;
1953 		return;
1954 	}
1955 	ev.ev = EV_MOUSE;
1956 	ev.x = gev.x - 1;
1957 	ev.y = gev.y - 1;
1958 	if (ev.x < 0) ev.x = 0;
1959 	if (ev.y < 0) ev.y = 0;
1960 	if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT;
1961 	else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE;
1962 	else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT;
1963 	else return;
1964 	if (gev.type & GPM_DOWN) ev.b |= B_DOWN;
1965 	else if (gev.type & GPM_UP) ev.b |= B_UP;
1966 	else if (gev.type & GPM_DRAG) ev.b |= B_DRAG;
1967 	else return;
1968 	gms->fn(gms->data, (unsigned char *)&ev, sizeof(struct event));
1969 }
1970 
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)1971 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
1972 {
1973 	int h;
1974 	Gpm_Connect conn;
1975 	struct gpm_mouse_spec *gms;
1976 	conn.eventMask = ~GPM_MOVE;
1977 	conn.defaultMask = GPM_MOVE;
1978 	conn.minMod = 0;
1979 	conn.maxMod = 0;
1980 	save_gpm_signals();
1981 	h = Gpm_Open(&conn, cons);
1982 	restore_gpm_signals();
1983 	if (h < 0) return NULL;
1984 	gms = mem_alloc(sizeof(struct gpm_mouse_spec));
1985 	gms->h = h;
1986 	gms->fn = fn;
1987 	gms->data = data;
1988 	set_handlers(h, (void (*)(void *))gpm_mouse_in, NULL, NULL, gms);
1989 	return gms;
1990 }
1991 
unhandle_mouse(void * h)1992 void unhandle_mouse(void *h)
1993 {
1994 	struct gpm_mouse_spec *gms = h;
1995 	if (gms->h != -1) set_handlers(gms->h, NULL, NULL, NULL, NULL);
1996 	save_gpm_signals();
1997 	Gpm_Close();
1998 	restore_gpm_signals();
1999 	mem_free(gms);
2000 }
2001 
add_gpm_version(unsigned char ** s,int * l)2002 void add_gpm_version(unsigned char **s, int *l)
2003 {
2004 	add_to_str(s, l, "GPM");
2005 #ifdef HAVE_GPM_GETLIBVERSION
2006 	add_to_str(s, l, " (");
2007 	add_to_str(s, l, (unsigned char *)Gpm_GetLibVersion(NULL));
2008 	add_to_str(s, l, ")");
2009 #endif
2010 }
2011 
2012 #elif !defined(USING_OS2_MOUSE)
2013 
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)2014 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) { return NULL; }
unhandle_mouse(void * data)2015 void unhandle_mouse(void *data) { }
2016 
2017 #endif /* #ifdef USE_GPM */
2018 
2019 #if defined(WIN32) || defined(INTERIX)
2020 
is_remote_connection(void)2021 static int is_remote_connection(void)
2022 {
2023 	return !!getenv("SSH_CONNECTION");
2024 }
2025 
2026 #endif
2027 
2028 #if defined(OS2)
2029 
get_system_env()2030 int get_system_env()
2031 {
2032 	if (is_xterm()) return 0;
2033 	return ENV_OS2VIO;		/* !!! FIXME: telnet */
2034 }
2035 
2036 #elif defined(BEOS)
2037 
get_system_env()2038 int get_system_env()
2039 {
2040 	unsigned char *term = getenv("TERM");
2041 	if (!term || (upcase(term[0]) == 'B' && upcase(term[1]) == 'E')) return ENV_BE;
2042 	return 0;
2043 }
2044 
2045 #elif defined(WIN32)
2046 
get_system_env()2047 int get_system_env()
2048 {
2049 	if (is_xterm()) return 0;
2050 	if (is_remote_connection()) return 0;
2051 	return ENV_WIN32;
2052 }
2053 
2054 #elif defined(INTERIX)
2055 
2056 #define INTERIX_START_COMMAND	"/usr/contrib/win32/bin/start"
2057 
get_system_env(void)2058 int get_system_env(void)
2059 {
2060 	if (is_xterm()) return 0;
2061 	if (is_remote_connection()) return 0;
2062 	if (!access(INTERIX_START_COMMAND, X_OK)) return ENV_INTERIX;
2063 	return 0;
2064 }
2065 
2066 #else
2067 
get_system_env()2068 int get_system_env()
2069 {
2070 	return 0;
2071 }
2072 
2073 #endif
2074 
exec_new_links(struct terminal * term,unsigned char * xterm,unsigned char * exe,unsigned char * param)2075 void exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe, unsigned char *param)
2076 {
2077 	unsigned char *str;
2078 	str = mem_alloc(strlen(xterm) + 1 + strlen(exe) + 1 + strlen(param) + 1);
2079 	if (*xterm) sprintf(str, "%s %s %s", xterm, exe, param);
2080 	else sprintf(str, "%s %s", exe, param);
2081 	exec_on_terminal(term, str, "", 2);
2082 	mem_free(str);
2083 }
2084 
open_in_new_twterm(struct terminal * term,unsigned char * exe,unsigned char * param)2085 void open_in_new_twterm(struct terminal *term, unsigned char *exe, unsigned char *param)
2086 {
2087 	unsigned char *twterm;
2088 	if (!(twterm = getenv("LINKS_TWTERM"))) twterm = "twterm -e";
2089 	exec_new_links(term, twterm, exe, param);
2090 }
2091 
open_in_new_xterm(struct terminal * term,unsigned char * exe,unsigned char * param)2092 void open_in_new_xterm(struct terminal *term, unsigned char *exe, unsigned char *param)
2093 {
2094 	unsigned char *xterm;
2095 	if (!(xterm = getenv("LINKS_XTERM"))) {
2096 #ifdef OPENVMS
2097 		xterm = "CREATE /TERMINAL /WAIT";
2098 #else
2099 		xterm = "xterm -e";
2100 #endif
2101 	}
2102 	exec_new_links(term, xterm, exe, param);
2103 }
2104 
open_in_new_screen(struct terminal * term,unsigned char * exe,unsigned char * param)2105 void open_in_new_screen(struct terminal *term, unsigned char *exe, unsigned char *param)
2106 {
2107 	exec_new_links(term, "screen", exe, param);
2108 }
2109 
2110 #ifdef OS2
open_in_new_vio(struct terminal * term,unsigned char * exe,unsigned char * param)2111 void open_in_new_vio(struct terminal *term, unsigned char *exe, unsigned char *param)
2112 {
2113 	unsigned char *x = stracpy("\"");
2114 	add_to_strn(&x, exe);
2115 	add_to_strn(&x, "\"");
2116 	exec_new_links(term, "start \"Links\" /c /f /win", x, param);
2117 	mem_free(x);
2118 }
2119 
open_in_new_fullscreen(struct terminal * term,unsigned char * exe,unsigned char * param)2120 void open_in_new_fullscreen(struct terminal *term, unsigned char *exe, unsigned char *param)
2121 {
2122 	unsigned char *x = stracpy("\"");
2123 	add_to_strn(&x, exe);
2124 	add_to_strn(&x, "\"");
2125 	exec_new_links(term, "start \"Links\" /c /f /fs", x, param);
2126 	mem_free(x);
2127 }
2128 #endif
2129 
2130 #ifdef WIN32
open_in_new_win32(struct terminal * term,unsigned char * exe,unsigned char * param)2131 void open_in_new_win32(struct terminal *term, unsigned char *exe, unsigned char *param)
2132 {
2133 	exec_new_links(term, "", exe, param);
2134 }
2135 #endif
2136 
2137 #ifdef INTERIX
open_in_new_interix(struct terminal * term,unsigned char * exe,unsigned char * param)2138 static void open_in_new_interix(struct terminal *term, unsigned char *exe, unsigned char *param)
2139 {
2140 	unsigned char *param_x = stracpy(param);
2141 	add_to_strn(&param_x, "'");
2142 	exec_new_links(term, INTERIX_START_COMMAND " '\"Links\"' posix /u /c /bin/sh -c '", exe, param_x);
2143 	mem_free(param_x);
2144 }
2145 #endif
2146 
2147 #ifdef BEOS
open_in_new_be(struct terminal * term,unsigned char * exe,unsigned char * param)2148 void open_in_new_be(struct terminal *term, unsigned char *exe, unsigned char *param)
2149 {
2150 	exec_new_links(term, "Terminal", exe, param);
2151 }
2152 #endif
2153 
2154 struct {
2155 	int env;
2156 	void (*fn)(struct terminal *term, unsigned char *, unsigned char *);
2157 	unsigned char *text;
2158 	unsigned char *hk;
2159 } oinw[] = {
2160 	{ ENV_XWIN, open_in_new_xterm, TEXT_(T_XTERM), TEXT_(T_HK_XTERM) },
2161 	{ ENV_TWIN, open_in_new_twterm, TEXT_(T_TWTERM), TEXT_(T_HK_TWTERM) },
2162 	{ ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN) },
2163 #ifdef OS2
2164 	{ ENV_OS2VIO, open_in_new_vio, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW) },
2165 	{ ENV_OS2VIO, open_in_new_fullscreen, TEXT_(T_FULL_SCREEN), TEXT_(T_HK_FULL_SCREEN) },
2166 #endif
2167 #ifdef WIN32
2168 	{ ENV_WIN32, open_in_new_win32, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW) },
2169 #endif
2170 #ifdef INTERIX
2171 	{ENV_INTERIX, open_in_new_interix, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
2172 #endif
2173 #ifdef BEOS
2174 	{ ENV_BE, open_in_new_be, TEXT_(T_BEOS_TERMINAL), TEXT_(T_HK_BEOS_TERMINAL) },
2175 #endif
2176 	{ 0, NULL, NULL, NULL },
2177 };
2178 
get_open_in_new(int environment)2179 struct open_in_new *get_open_in_new(int environment)
2180 {
2181 	int i;
2182 	struct open_in_new *oin = DUMMY;
2183 	int noin = 0;
2184 	if (anonymous) return NULL;
2185 	for (i = 0; oinw[i].env; i++) if ((environment & oinw[i].env) == oinw[i].env) {
2186 		if ((unsigned)noin > MAXINT / sizeof(struct open_in_new) - 2) overalloc();
2187 		oin = mem_realloc(oin, (noin + 2) * sizeof(struct open_in_new));
2188 		oin[noin].text = oinw[i].text;
2189 		oin[noin].hk = oinw[i].hk;
2190 		oin[noin].fn = oinw[i].fn;
2191 		noin++;
2192 		oin[noin].text = NULL;
2193 		oin[noin].hk = NULL;
2194 		oin[noin].fn = NULL;
2195 	}
2196 	if (oin == DUMMY) return NULL;
2197 	return oin;
2198 }
2199 
can_resize_window(struct terminal * term)2200 int can_resize_window(struct terminal *term)
2201 {
2202 	if (!strncmp(term->term, "xterm", 5)) return 0;
2203 	if (term->environment & (ENV_OS2VIO | ENV_WIN32)) return 1;
2204 	return 0;
2205 }
2206 
can_open_os_shell(int environment)2207 int can_open_os_shell(int environment)
2208 {
2209 #ifdef OS2
2210 	if (environment & ENV_XWIN) return 0;
2211 #endif
2212 #ifdef WIN32
2213 	if (!(environment & ENV_WIN32)) return 0;
2214 #endif
2215 #ifdef BEOS
2216 	if (!(environment & ENV_BE)) return 0;
2217 #endif
2218 	return 1;
2219 }
2220 
set_highpri()2221 void set_highpri()
2222 {
2223 #ifdef OS2
2224 	DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0);
2225 #endif
2226 }
2227 
2228