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(¶m, 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, ¶m))
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, ¶m))
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(¶m_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