1 /* os_dep.c
2 * (c) 2002 Mikulas Patocka
3 * This file is a part of the Links program, released under GPL.
4 */
5
6 #include "links.h"
7
8 #ifdef HAVE_SYS_IOCTL_H
9 #include <sys/ioctl.h>
10 #endif
11
12 #ifdef USE_GPM
13 #include <gpm.h>
14 #endif
15
16 #ifdef WIN
17 /*#define UNICODE*/
18 /*#define NO_STRICT*/
19 #include <windows.h>
20 #endif
21
22 #if defined(__CYGWIN__) && defined(HAVE_LOCALE_H)
23 #include <locale.h>
24 #ifdef HAVE_LANGINFO_H
25 #include <langinfo.h>
26 #endif
27
28 #endif
29
30 #ifdef HAVE_PTHREADS
31 #include <pthread.h>
32 #endif
33
34 #ifdef OS2
35
36 #define INCL_MOU
37 #define INCL_VIO
38 #define INCL_DOSPROCESS
39 #define INCL_DOSERRORS
40 #define INCL_DOSMODULEMGR
41 #define INCL_DOSMISC
42 #define INCL_DOSNLS
43 #define INCL_WIN
44 #define INCL_WINCLIPBOARD
45 #define INCL_WINSWITCHLIST
46 #include <os2.h>
47 #include <io.h>
48 #include <process.h>
49 #include <sys/video.h>
50 #ifdef HAVE_SYS_FMUTEX_H
51 #include <sys/builtin.h>
52 #include <sys/fmutex.h>
53 #endif
54
55 #ifdef X2
56 /* from xf86sup - XFree86 OS/2 support driver */
57 #include <pty.h>
58 #endif
59
60 #define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2
61
62 #endif
63
64 #ifdef OS2
65
66 /* The process crashes if we write to console from high address - so we must
67 * never do it.
68 * TCP/IP 4.0 returns EFAULT if we do I/O to/from high address - we test for
69 * EFAULT and retry with a bounce buffer. */
70
71 #define BOUNCE_BUFFER_SIZE 3584
72
bounced_read(int fd,void * buf,size_t size)73 int bounced_read(int fd, void *buf, size_t size)
74 {
75 unsigned char *bounce_buffer;
76 int r;
77
78 if (fd < 3 && (my_uintptr_t)buf + size >= 0x20000000UL) goto bounce;
79 r = _read(fd, buf, size);
80 if (r == -1 && errno == EFAULT) goto bounce;
81 return r;
82
83 bounce:
84 bounce_buffer = NULL;
85 if (size > BOUNCE_BUFFER_SIZE) {
86 bounce_buffer = os2_orig_malloc(size);
87 if (!bounce_buffer)
88 size = BOUNCE_BUFFER_SIZE;
89 }
90 if (!bounce_buffer)
91 bounce_buffer = alloca(size);
92 r = _read(fd, bounce_buffer, size);
93 if (r > 0) memcpy(buf, bounce_buffer, r);
94 if (size > BOUNCE_BUFFER_SIZE)
95 free(bounce_buffer);
96 return r;
97 }
98
bounced_write(int fd,const void * buf,size_t size)99 int bounced_write(int fd, const void *buf, size_t size)
100 {
101 unsigned char *bounce_buffer;
102 int r;
103
104 if (fd < 3 && (my_uintptr_t)buf + size >= 0x20000000UL) goto bounce;
105 r = _write(fd, buf, size);
106 if (r == -1 && errno == EFAULT) goto bounce;
107 return r;
108
109 bounce:
110 bounce_buffer = NULL;
111 if (size > BOUNCE_BUFFER_SIZE) {
112 bounce_buffer = os2_orig_malloc(size);
113 if (!bounce_buffer)
114 size = BOUNCE_BUFFER_SIZE;
115 }
116 if (!bounce_buffer)
117 bounce_buffer = alloca(size);
118 memcpy(bounce_buffer, buf, size);
119 r = _write(fd, bounce_buffer, size);
120 if (size > BOUNCE_BUFFER_SIZE)
121 free(bounce_buffer);
122 return r;
123 }
124
portable_sleep(unsigned msec)125 void portable_sleep(unsigned msec)
126 {
127 DosSleep(msec);
128 }
129 #endif
130
131 #ifdef OS2_ADVANCED_HEAP
132
133 #include <umalloc.h>
134
135 #ifndef OBJ_ANY
136 #define OBJ_ANY 0x0400
137 #endif
138
139 unsigned long mem_requested = 0;
140 unsigned long blocks_requested = 0;
141
142 static int dosallocmem_attrib = PAG_READ | PAG_WRITE | PAG_COMMIT;
143
144 #define HEAP_ALIGN 0x10000
145 #define HEAP_MAX_ALIGN 0x20000
146
virtual_free(void * ptr,size_t len)147 void virtual_free(void *ptr, size_t len)
148 {
149 int rc;
150 rc = DosFreeMem(ptr);
151 /*fprintf(stderr, "heap free %p -> %d\n", ptr, rc);*/
152 if (rc)
153 fatal_exit("DosFreeMem failed: %d", rc);
154 if (len & 4095)
155 len = (len | 4095) + 1;
156 mem_requested -= len;
157 blocks_requested--;
158 }
159
heap_release(Heap_t h,void * ptr,size_t len)160 static void heap_release(Heap_t h, void *ptr, size_t len)
161 {
162 virtual_free(ptr, len);
163 }
164
virtual_alloc(size_t len)165 void *virtual_alloc(size_t len)
166 {
167 void *result;
168 int rc;
169 rc = DosAllocMem(&result, len, dosallocmem_attrib);
170 if (rc)
171 return NULL;
172 /*
173 * Hitting the shared arena has a negative impact on the whole
174 * system. Therefore, we fake failure (so that Links frees
175 * some caches) and try allocating near the shared arena only
176 * as a last resort.
177 */
178 if ((unsigned long)result >= 0x12000000 &&
179 (unsigned long)result < 0x20000000) {
180 if (!malloc_try_hard) {
181 heap_release(NULL, result, len);
182 return NULL;
183 }
184 }
185 if (len & 4095)
186 len = (len | 4095) + 1;
187 mem_requested += len;
188 blocks_requested++;
189 return result;
190 }
191
heap_alloc(Heap_t h,size_t * size,int * pclean)192 static void *heap_alloc(Heap_t h, size_t *size, int *pclean)
193 {
194 void *result;
195 /* If we rounded up to page size, EMX would join all allocations
196 * to one segment and refuse to free memory. So round up to
197 * page size - 1 */
198 size_t real_size = *size;
199 if (real_size < HEAP_MAX_ALIGN) {
200 real_size = real_size | (HEAP_ALIGN - 1);
201 } else {
202 real_size |= 1;
203 }
204 result = virtual_alloc(real_size);
205 /*fprintf(stderr, "heap alloc %d,%d -> %p\n", *size, real_size, result);*/
206 if (result) {
207 *size = real_size;
208 *pclean = _BLOCK_CLEAN;
209 }
210 return result;
211 }
212
213 static Heap_t original_heap = NULL;
214
init_os2_heap(void)215 static void init_os2_heap(void)
216 {
217 Heap_t new_heap;
218 size_t init_size = _HEAP_MIN_SIZE;
219 void *init_mem;
220 int init_clean;
221
222 dosallocmem_attrib |= OBJ_ANY;
223 init_mem = heap_alloc(NULL, &init_size, &init_clean);
224 if (!init_mem) {
225 dosallocmem_attrib &= ~OBJ_ANY;
226 init_mem = heap_alloc(NULL, &init_size, &init_clean);
227 if (!init_mem) {
228 return;
229 }
230 }
231 new_heap = _ucreate(init_mem, init_size, init_clean, _HEAP_REGULAR, heap_alloc, heap_release);
232 if (!new_heap) {
233 heap_release(NULL, init_mem, init_size);
234 return;
235 }
236 if (_uopen(new_heap) == -1) {
237 #if defined(HAVE__UDESTROY) && defined(_FORCE)
238 _udestroy(new_heap, _FORCE);
239 #else
240 heap_release(NULL, init_mem, init_size);
241 #endif
242 return;
243 }
244 if (dosallocmem_attrib & OBJ_ANY) {
245 /* call malloc to initialize the default heap */
246 void *p = malloc(1);
247 if (p) free(p);
248 original_heap = _udefault(new_heap);
249 } else {
250 _udefault(new_heap);
251 }
252 }
253
os2_orig_malloc(size_t len)254 void *os2_orig_malloc(size_t len)
255 {
256 if (original_heap)
257 return _umalloc(original_heap, len);
258 return malloc(len);
259 }
260
261 #endif
262
263
264 #ifdef OS2
265 static int os2_full_screen = 0;
266 static int os2_detached = 0;
267 static PTIB os2_tib = NULL;
268 PPIB os2_pib = NULL;
269 static HSWITCH os2_switchhandle = NULLHANDLE;
270 #ifdef HAVE_SYS_FMUTEX_H
271 static _fmutex fd_mutex;
272 #endif
273 #elif defined(HAVE_PTHREADS) && !defined(OPENVMS)
274 static pthread_mutex_t pth_mutex;
275 static void fd_lock(void);
276 static void fd_unlock(void);
fd_init(void)277 static void fd_init(void)
278 {
279 int r;
280 r = pthread_mutex_init(&pth_mutex, NULL);
281 if (r)
282 fatal_exit("pthread_mutex_create failed: %s", strerror(r));
283 }
284 #endif
285
286 int page_size = 4096;
287
init_page_size(void)288 void init_page_size(void)
289 {
290 long getpg = -1;
291 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
292 if (getpg < 0)
293 EINTRLOOP(getpg, sysconf(_SC_PAGESIZE));
294 #endif
295 #ifdef HAVE_GETPAGESIZE
296 if (getpg < 0)
297 getpg = getpagesize();
298 #endif
299 if (getpg > 0 && !(getpg & (getpg - 1))) page_size = (int)getpg;
300 }
301
302 #if !defined(OPENVMS) && !defined(DOS)
init_os(void)303 void init_os(void)
304 {
305 /* Disable per-thread heap */
306 #if defined(HAVE_MALLOPT) && defined(M_ARENA_TEST)
307 mallopt(M_ARENA_TEST, 1);
308 #endif
309 #if defined(HAVE_MALLOPT) && defined(M_ARENA_MAX)
310 mallopt(M_ARENA_MAX, 1);
311 #endif
312
313 #ifdef OS2
314 DosGetInfoBlocks(&os2_tib, &os2_pib);
315 if (os2_pib) {
316 os2_switchhandle = WinQuerySwitchHandle(0, os2_pib->pib_ulpid);
317 os2_full_screen = os2_pib->pib_ultype == 0;
318 os2_detached = os2_pib->pib_ultype == 4;
319 if (os2_pib->pib_ultype == 3) force_g = 1;
320 }
321 #ifdef HAVE_SYS_FMUTEX_H
322 if (_fmutex_create(&fd_mutex, 0))
323 fatal_exit("failed to create fd mutex");
324 #endif
325 #elif defined(HAVE_PTHREADS) && !defined(OPENVMS)
326 {
327 int r;
328 fd_init();
329 r = pthread_atfork(fd_lock, fd_unlock, fd_init);
330 if (r)
331 fatal_exit("pthread_atfork failed: %s", strerror(r));
332 }
333 #endif
334
335 #ifdef OS2_ADVANCED_HEAP
336 init_os2_heap();
337 #endif
338
339 #ifdef WIN
340 if (!GetConsoleCP())
341 force_g = 1;
342 #if defined(__CYGWIN__) && defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
343 {
344 unsigned char *l = cast_uchar setlocale(LC_CTYPE, "");
345 if (!l || !casestrcmp(l, cast_uchar "C")) {
346 setlocale(LC_CTYPE, "en_US.utf-8");
347 }
348 }
349 #endif
350 #if defined(__CYGWIN__)
351 /*
352 * When started from cmd.exe and the argument contains some characters
353 * not valid in the current locale, cygwin doesn't remove the quotation
354 * marks around the argument. So, we must remove the quotation marks
355 * here.
356 */
357 if (getppid() == 1) {
358 int i;
359 for (i = 1; i < g_argc; i++) {
360 unsigned char *a = cast_uchar g_argv[i];
361 int l = (int)strlen(cast_const_char a);
362 if (l >= 3 && a[0] == '"' && a[l - 1] == '"') {
363 unsigned char *a2 = cast_uchar strdup(cast_const_char (a + 1));
364 if (a2) {
365 unsigned char *p, *q;
366 a2[l - 2] = 0;
367 for (p = q = a2; *p; p++) {
368 if (p[0] == '\\' && p[1] == '"')
369 continue;
370 *q++ = *p;
371 }
372 *q = 0;
373 g_argv[i] = cast_char a2;
374 }
375 }
376 }
377 }
378 #endif
379 #endif
380 #if defined(BEOS) || defined(HAIKU)
381 if (getenv("TERM") == NULL) {
382 /* probably launched from Tracker or Deskbar, force graphics mode */
383 force_g = 1;
384 }
385 #endif
386 }
387 #endif
388
389
is_safe_in_shell(unsigned char c)390 int is_safe_in_shell(unsigned char c)
391 {
392 return c == '@' || c == '+' || c == '-' || c == '.' || c == ',' || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
393 }
394
is_safe_in_file(unsigned char c)395 static inline int is_safe_in_file(unsigned char c)
396 {
397 return !(c < ' ' || c == '"' || c == '*' || c == '/' || c == ':' || c == '<' || c == '>' || c == '\\' || c == '|' || c >= 0x80);
398 }
399
is_safe_in_url(unsigned char c)400 static inline int is_safe_in_url(unsigned char c)
401 {
402 return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80;
403 }
404
check_shell_security(unsigned char ** cmd)405 void check_shell_security(unsigned char **cmd)
406 {
407 unsigned char *c = *cmd;
408 while (*c) {
409 if (!is_safe_in_shell(*c)) *c = '_';
410 c++;
411 }
412 }
413
check_filename(unsigned char ** file)414 void check_filename(unsigned char **file)
415 {
416 unsigned char *c = *file;
417 while (*c) {
418 if (!is_safe_in_file(*c)) *c = '_';
419 c++;
420 }
421 }
422
check_shell_url(unsigned char * url)423 int check_shell_url(unsigned char *url)
424 {
425 while (*url) {
426 if (!is_safe_in_url(*url)) return -1;
427 url++;
428 }
429 return 0;
430 }
431
escape_path(unsigned char * path)432 unsigned char *escape_path(unsigned char *path)
433 {
434 unsigned char *result;
435 size_t i;
436 if (strchr(cast_const_char path, '"')) return stracpy(path);
437 for (i = 0; path[i]; i++) if (!is_safe_in_url(path[i])) goto do_esc;
438 return stracpy(path);
439 do_esc:
440 result = stracpy(cast_uchar "\"");
441 add_to_strn(&result, path);
442 add_to_strn(&result, cast_uchar "\"");
443 return result;
444 }
445
get_e(unsigned char * env)446 static inline int get_e(unsigned char *env)
447 {
448 unsigned char *v;
449 if ((v = cast_uchar getenv(cast_const_char env))) return atoi(cast_const_char v);
450 return 0;
451 }
452
do_signal(int sig,void (* handler)(int))453 void do_signal(int sig, void (*handler)(int))
454 {
455 errno = 0;
456 while (signal(sig, handler) == SIG_ERR && errno == EINTR) errno = 0;
457 }
458
ignore_signals(void)459 void ignore_signals(void)
460 {
461 do_signal(SIGPIPE, SIG_IGN);
462 #ifdef SIGXFSZ
463 do_signal(SIGXFSZ, SIG_IGN);
464 #endif
465 #ifdef OPENVMS
466 #ifdef SIGCHLD
467 do_signal(SIGCHLD, SIG_IGN);
468 #endif
469 #ifdef SIGWINCH
470 do_signal(SIGWINCH, SIG_IGN);
471 #endif
472 #endif
473 }
474
get_absolute_seconds(void)475 time_t get_absolute_seconds(void)
476 {
477 time_t t;
478 errno = 0;
479 EINTRLOOPX(t, time(NULL), (time_t)-1);
480 return t;
481 }
482
get_absolute_time(void)483 uttime get_absolute_time(void)
484 {
485 struct timeval tv;
486 int rs;
487 EINTRLOOP(rs, gettimeofday(&tv, NULL));
488 if (rs) fatal_exit("gettimeofday failed: %d", errno);
489 return (uttime)tv.tv_sec * 1000 + (unsigned)tv.tv_usec / 1000;
490 }
491
get_time(void)492 uttime get_time(void)
493 {
494 #if defined(OS2) || defined(WIN)
495 static unsigned last_tim = 0;
496 static uttime add = 0;
497 unsigned tim;
498 #if defined(OS2)
499 int rc;
500 rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &tim, sizeof tim);
501 if (rc) fatal_exit("DosQuerySysInfo failed: %d", rc);
502 #elif defined(WIN)
503 tim = GetTickCount();
504 #endif
505 if (tim < last_tim) {
506 add += (uttime)1 << 31 << 1;
507 }
508 last_tim = tim;
509 return tim | add;
510 #else
511 #if defined(HAVE_CLOCK_GETTIME) && defined(TIME_WITH_SYS_TIME) && (defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC))
512 struct timespec ts;
513 int rs;
514 #if defined(CLOCK_MONOTONIC_RAW)
515 EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC_RAW, &ts));
516 if (!rs) return (uttime)ts.tv_sec * 1000 + (unsigned)ts.tv_nsec / 1000000;
517 #endif
518 #if defined(CLOCK_MONOTONIC)
519 EINTRLOOP(rs, clock_gettime(CLOCK_MONOTONIC, &ts));
520 if (!rs) return (uttime)ts.tv_sec * 1000 + (unsigned)ts.tv_nsec / 1000000;
521 #endif
522 #endif
523 return get_absolute_time();
524 #endif
525 }
526
527
528 static unsigned char *clipboard = NULL;
529
os_free_clipboard(void)530 void os_free_clipboard(void)
531 {
532 if (clipboard) mem_free(clipboard), clipboard = NULL;
533 }
534
535 /* Terminal size */
536
537 #if defined(UNIX) || defined(OS2) || defined(WIN) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(OPENVMS) || defined(HAIKU)
538 static void (*terminal_resize_callback)(int, int);
539 #endif
540
541 #if (defined(OS2) && defined(X2)) || defined(WIN) || defined(OPENVMS)
542
543 #define TERMINAL_SIZE_POLLING
544
545 /* Cygwin has a bug and loses SIGWINCH sometimes, so poll it */
546
547 static struct timer *terminal_resize_timer = NULL;
548 static int old_xsize, old_ysize;
549
terminal_resize_fn(void * p)550 static void terminal_resize_fn(void *p)
551 {
552 int cur_xsize, cur_ysize;
553 terminal_resize_timer = install_timer(TERMINAL_POLL_TIMEOUT, terminal_resize_fn, NULL);
554 get_terminal_size(&cur_xsize, &cur_ysize);
555 if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
556 old_xsize = cur_xsize;
557 old_ysize = cur_ysize;
558 terminal_resize_callback(cur_xsize, cur_ysize);
559 }
560 }
561
terminal_resize_poll(int x,int y)562 static void terminal_resize_poll(int x, int y)
563 {
564 if (terminal_resize_timer)
565 internal_error("terminal_resize_poll: timer already active");
566 old_xsize = x;
567 old_ysize = y;
568 #ifdef OS2
569 if (!is_xterm())
570 return;
571 #endif
572 terminal_resize_timer = install_timer(TERMINAL_POLL_TIMEOUT, terminal_resize_fn, NULL);
573 }
574
575 #endif
576
577 #if defined(UNIX) || defined(OS2) || defined(WIN) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(OPENVMS) || defined(HAIKU)
578
579 #if defined(SIGWINCH) && !defined(OS2) && !defined(OPENVMS)
sigwinch(void * s)580 static void sigwinch(void *s)
581 {
582 int cur_xsize, cur_ysize;
583 get_terminal_size(&cur_xsize, &cur_ysize);
584 #ifdef TERMINAL_SIZE_POLLING
585 old_xsize = cur_xsize;
586 old_ysize = cur_ysize;
587 #endif
588 terminal_resize_callback(cur_xsize, cur_ysize);
589 }
590 #endif
591
handle_terminal_resize(void (* fn)(int,int),int * x,int * y)592 void handle_terminal_resize(void (*fn)(int, int), int *x, int *y)
593 {
594 terminal_resize_callback = fn;
595 get_terminal_size(x, y);
596 #if defined(SIGWINCH) && !defined(OS2) && !defined(OPENVMS)
597 install_signal_handler(SIGWINCH, sigwinch, NULL, 0);
598 #endif
599 #ifdef TERMINAL_SIZE_POLLING
600 terminal_resize_poll(*x, *y);
601 #endif
602 }
603
unhandle_terminal_resize(void)604 void unhandle_terminal_resize(void)
605 {
606 #if defined(SIGWINCH) && !defined(OS2) && !defined(OPENVMS)
607 install_signal_handler(SIGWINCH, NULL, NULL, 0);
608 #endif
609 #ifdef TERMINAL_SIZE_POLLING
610 if (terminal_resize_timer) {
611 kill_timer(terminal_resize_timer);
612 terminal_resize_timer = NULL;
613 }
614 #endif
615 }
616
617 #if defined(OS2)
618
get_terminal_size(int * x,int * y)619 void get_terminal_size(int *x, int *y)
620 {
621 if (is_xterm()) {
622 #ifdef X2
623 int arc;
624 struct winsize win;
625
626 /* fd = STDIN_FILENO; */
627 arc = ptioctl(1, TIOCGWINSZ, &win);
628 if (arc) {
629 *x = 80;
630 *y = 24;
631 return;
632 }
633 *y = win.ws_row;
634 *x = win.ws_col;
635 goto set_default;
636 #else
637 *x = 80; *y = 24;
638 #endif
639 } else {
640 int a[2] = { 0, 0 };
641 _scrsize(a);
642 *x = a[0];
643 *y = a[1];
644 #ifdef X2
645 set_default:
646 #endif
647 if (*x == 0) {
648 *x = get_e("COLUMNS");
649 if (*x == 0) *x = 80;
650 }
651 if (*y == 0) {
652 *y = get_e("LINES");
653 if (*y == 0) *y = 24;
654 }
655 }
656 }
657
658 #elif !defined(OPENVMS)
659
get_terminal_size(int * x,int * y)660 void get_terminal_size(int *x, int *y)
661 {
662 int rs = -1;
663 #ifdef TIOCGWINSZ
664 /* Sun Studio misoptimizes it */
665 sun_volatile struct winsize ws;
666 EINTRLOOP(rs, ioctl(1, TIOCGWINSZ, &ws));
667 #endif
668 if ((rs == -1
669 #ifdef TIOCGWINSZ
670 || !(*x = ws.ws_col)
671 #endif
672 ) && !(*x = get_e(cast_uchar "COLUMNS"))) {
673 *x = 80;
674 #ifdef _UWIN
675 *x = 79;
676 #endif
677 }
678 if ((rs == -1
679 #ifdef TIOCGWINSZ
680 || !(*y = ws.ws_row)
681 #endif
682 ) && !(*y = get_e(cast_uchar "LINES"))) {
683 *y = 24;
684 }
685 }
686
687 #endif
688
689 #endif
690
691
692 #if defined(OS2) && defined(HAVE_SYS_FMUTEX_H)
693
fd_lock(void)694 static void fd_lock(void)
695 {
696 _fmutex_request(&fd_mutex, _FMR_IGNINT);
697 }
698
fd_unlock(void)699 static void fd_unlock(void)
700 {
701 _fmutex_release(&fd_mutex);
702 }
703
704 #elif defined(HAVE_PTHREADS) && !defined(OPENVMS)
705
fd_lock(void)706 static void fd_lock(void)
707 {
708 int r;
709 r = pthread_mutex_lock(&pth_mutex);
710 if (r)
711 fatal_exit("pthread_mutex_lock failed: %s", strerror(r));
712 }
713
fd_unlock(void)714 static void fd_unlock(void)
715 {
716 int r;
717 r = pthread_mutex_unlock(&pth_mutex);
718 if (r)
719 fatal_exit("pthread_mutex_lock failed: %s", strerror(r));
720 }
721
722 #else
723
724 #define fd_lock() do { } while (0)
725 #define fd_unlock() do { } while (0)
726
727 #endif
728
new_fd_cloexec(int fd)729 static void new_fd_cloexec(int fd)
730 {
731 int rs;
732 EINTRLOOP(rs, fcntl(fd, F_SETFD, FD_CLOEXEC));
733 }
734
new_fd_bin(int fd)735 static void new_fd_bin(int fd)
736 {
737 new_fd_cloexec(fd);
738 #if defined(OS2) || (defined(WIN) && !defined(_UWIN)) || defined(DOS)
739 setmode(fd, O_BINARY);
740 #endif
741 }
742
743 #if !defined(OPENVMS)
744
set_nonblock(int fd)745 void set_nonblock(int fd)
746 {
747 #ifdef O_NONBLOCK
748 int rs;
749 EINTRLOOP(rs, fcntl(fd, F_SETFL, O_NONBLOCK));
750 #elif defined(FIONBIO)
751 int rs;
752 int on = 1;
753 EINTRLOOP(rs, ioctl(fd, FIONBIO, &on));
754 #endif
755 }
756
757 #endif
758
cleanup_fds(void)759 static int cleanup_fds(void)
760 {
761 #ifdef ENFILE
762 if (errno == ENFILE) return abort_background_connections();
763 #endif
764 #ifdef EMFILE
765 if (errno == EMFILE) return abort_background_connections();
766 #endif
767 return 0;
768 }
769
770 /* Pipe */
771
c_pipe(int fd[2])772 int c_pipe(int fd[2])
773 {
774 int r;
775 do {
776 fd_lock();
777 EINTRLOOP(r, pipe(fd));
778 if (!r) new_fd_bin(fd[0]), new_fd_bin(fd[1]);
779 fd_unlock();
780 } while (r == -1 && cleanup_fds());
781 return r;
782 }
783
c_dup(int oh)784 int c_dup(int oh)
785 {
786 int h;
787 do {
788 fd_lock();
789 EINTRLOOP(h, dup(oh));
790 if (h != -1) new_fd_cloexec(h);
791 fd_unlock();
792 } while (h == -1 && cleanup_fds());
793 return h;
794 }
795
c_socket(int d,int t,int p)796 int c_socket(int d, int t, int p)
797 {
798 int h;
799 do {
800 fd_lock();
801 EINTRLOOP(h, socket(d, t, p));
802 if (h != -1) new_fd_cloexec(h);
803 fd_unlock();
804 } while (h == -1 && cleanup_fds());
805 return h;
806 }
807
c_accept(int sh,struct sockaddr * addr,socklen_t * addrlen)808 int c_accept(int sh, struct sockaddr *addr, socklen_t *addrlen)
809 {
810 int h;
811 do {
812 fd_lock();
813 EINTRLOOP(h, accept(sh, addr, addrlen));
814 if (h != -1) new_fd_cloexec(h);
815 fd_unlock();
816 } while (h == -1 && cleanup_fds());
817 return h;
818 }
819
c_open(unsigned char * path,int flags)820 int c_open(unsigned char *path, int flags)
821 {
822 int h;
823 do {
824 fd_lock();
825 EINTRLOOP(h, open(cast_const_char path, flags));
826 if (h != -1) new_fd_bin(h);
827 fd_unlock();
828 } while (h == -1 && cleanup_fds());
829 return h;
830 }
831
c_open3(unsigned char * path,int flags,int mode)832 int c_open3(unsigned char *path, int flags, int mode)
833 {
834 int h;
835 do {
836 fd_lock();
837 EINTRLOOP(h, open(cast_const_char path, flags, mode));
838 if (h != -1) new_fd_bin(h);
839 fd_unlock();
840 } while (h == -1 && cleanup_fds());
841 return h;
842 }
843
c_opendir(unsigned char * path)844 DIR *c_opendir(unsigned char *path)
845 {
846 DIR *d;
847 do {
848 fd_lock();
849 ENULLLOOP(d, opendir(cast_const_char path));
850 #ifdef HAVE_DIRFD
851 if (d) {
852 int h;
853 EINTRLOOP(h, dirfd(d));
854 if (h != -1) new_fd_cloexec(h);
855 }
856 #endif
857 fd_unlock();
858 } while (!d && cleanup_fds());
859 return d;
860 }
861
862 #if defined(O_SIZE) && defined(__EMX__)
863
open_prealloc(unsigned char * name,int flags,int mode,off_t siz)864 int open_prealloc(unsigned char *name, int flags, int mode, off_t siz)
865 {
866 int h;
867 fd_lock();
868 EINTRLOOP(h, open(cast_const_char name, flags | O_SIZE, mode, (unsigned long)siz));
869 if (h != -1) new_fd_bin(h);
870 fd_unlock();
871 return h;
872 }
873
874 #elif defined(HAVE_OPEN_PREALLOC)
875
open_prealloc(unsigned char * name,int flags,int mode,off_t siz)876 int open_prealloc(unsigned char *name, int flags, int mode, off_t siz)
877 {
878 int h, rs;
879 fd_lock();
880 EINTRLOOP(h, open(cast_const_char name, flags, mode));
881 if (h == -1) {
882 fd_unlock();
883 return -1;
884 }
885 new_fd_bin(h);
886 fd_unlock();
887 #if defined(HAVE_FALLOCATE)
888 #if defined(FALLOC_FL_KEEP_SIZE)
889 EINTRLOOP(rs, fallocate(h, FALLOC_FL_KEEP_SIZE, 0, siz));
890 #else
891 EINTRLOOP(rs, fallocate(h, 0, 0, siz));
892 #endif
893 if (!rs) return h;
894 #endif
895 #if defined(HAVE_POSIX_FALLOCATE)
896 /* posix_fallocate may fall back to overwriting the file with zeros,
897 so don't use it on too big files */
898 if (siz > 134217728)
899 return h;
900 do {
901 rs = posix_fallocate(h, 0, siz);
902 } while (rs == EINTR);
903 if (!rs) return h;
904 #endif
905 return h;
906 }
907
908 #endif
909
910 /* Exec */
911
912 #if defined(UNIX) || defined(ATHEOS) || defined(INTERIX)
913
is_twterm(void)914 int is_twterm(void)
915 {
916 static int xt = -1;
917 if (xt == -1) xt = !!getenv("TWDISPLAY");
918 return xt;
919 }
920
921 #else
922
is_twterm(void)923 int is_twterm(void)
924 {
925 return 0;
926 }
927
928 #endif
929
930 #if defined(UNIX) || defined(ATHEOS) || defined(INTERIX)
931
is_screen(void)932 int is_screen(void)
933 {
934 static int xt = -1;
935 if (xt == -1) xt = !!getenv("STY");
936 return xt;
937 }
938
939 #else
940
is_screen(void)941 int is_screen(void)
942 {
943 return 0;
944 }
945
946 #endif
947
948 #if defined(UNIX) || defined(SPAD)
949
is_xterm(void)950 int is_xterm(void)
951 {
952 static int xt = -1;
953 if (xt == -1) xt = getenv("DISPLAY") && *(char *)getenv("DISPLAY");
954 return xt;
955 }
956
957 #elif defined(BEOS) || defined(ATHEOS) || defined(DOS) || defined(HAIKU)
958
is_xterm(void)959 int is_xterm(void)
960 {
961 return 0;
962 }
963
964 #elif defined(WIN) || defined(INTERIX) || defined(OS2)
965
is_xterm(void)966 int is_xterm(void)
967 {
968 static int xt = -1;
969 if (xt == -1) xt = !!getenv("WINDOWID");
970 return xt;
971 }
972
973 #elif defined(RISCOS)
974
is_xterm(void)975 int is_xterm(void)
976 {
977 return 1;
978 }
979
980 #endif
981
982 #if defined(__linux__) || defined(__LINUX__)
983 static int cons_control[2] = { -1, -1 };
984 static int cons_status[2] = { -1, -1 };
985 #endif
986
close_fork_tty(void)987 void close_fork_tty(void)
988 {
989 struct terminal *t;
990 struct list_head *lt;
991 struct download *d;
992 struct list_head *ld;
993 struct connection *c;
994 struct list_head *lc;
995 struct k_conn *k;
996 struct list_head *lk;
997 int rs;
998 #ifndef NO_SIGNAL_HANDLERS
999 if (signal_pipe[0] != -1) EINTRLOOP(rs, close(signal_pipe[0]));
1000 #ifndef __minix__
1001 if (signal_pipe[1] != -1) EINTRLOOP(rs, close(signal_pipe[1]));
1002 #endif
1003 #endif
1004 #if defined(__linux__) || defined(__LINUX__)
1005 if (cons_control[0] != -1) EINTRLOOP(rs, close(cons_control[0]));
1006 if (cons_control[1] != -1) EINTRLOOP(rs, close(cons_control[1]));
1007 if (cons_status[0] != -1) EINTRLOOP(rs, close(cons_status[0]));
1008 if (cons_status[1] != -1) EINTRLOOP(rs, close(cons_status[1]));
1009 #endif
1010 #ifdef G
1011 if (drv && drv->after_fork) drv->after_fork();
1012 #endif
1013 if (terminal_pipe[1] != -1) EINTRLOOP(rs, close(terminal_pipe[1]));
1014 if (s_unix_fd != -1) EINTRLOOP(rs, close(s_unix_fd));
1015 foreach(struct terminal, t, lt, terminals) {
1016 if (t->fdin > 0)
1017 EINTRLOOP(rs, close(t->fdin));
1018 if (t->handle_to_close >= 0)
1019 EINTRLOOP(rs, close(t->handle_to_close));
1020 }
1021 foreach(struct download, d, ld, downloads) if (d->handle > 0)
1022 EINTRLOOP(rs, close(d->handle));
1023 foreach(struct connection, c, lc, queue) {
1024 if (c->sock1 >= 0) EINTRLOOP(rs, close(c->sock1));
1025 if (c->sock2 >= 0) EINTRLOOP(rs, close(c->sock2));
1026 }
1027 foreach(struct k_conn, k, lk, keepalive_connections)
1028 EINTRLOOP(rs, close(k->conn));
1029 }
1030
1031
1032 #if defined(WIN)
1033
get_path_to_exe(void)1034 void get_path_to_exe(void)
1035 {
1036 /* Standard method (argv[0]) doesn't work, if links is executed from
1037 symlink --- it returns symlink name and cmd.exe is unable to start
1038 it */
1039 unsigned r;
1040 static unsigned char path[4096];
1041 r = GetModuleFileNameA(NULL, cast_char path, sizeof path);
1042 if (r <= 0 || r >= sizeof path) {
1043 path_to_exe = cast_uchar g_argv[0];
1044 return;
1045 }
1046 path_to_exe = path;
1047 }
1048
1049 #elif defined(OS2)
1050
get_path_to_exe(void)1051 void get_path_to_exe(void)
1052 {
1053 /* If you spawn links with quotation marks from cmd.exe,
1054 the quotation marks will be present in g_argv[0] ... and will
1055 prevent executing it */
1056 static unsigned char path[270];
1057 path_to_exe = cast_uchar g_argv[0];
1058 if (!os2_pib) return;
1059 if (DosQueryModuleName(os2_pib->pib_hmte, sizeof path, path)) return;
1060 path_to_exe = path;
1061 }
1062
1063 static ULONG os2_old_type;
1064 static HAB os2_hab;
1065 static HMQ os2_hmq;
1066
os2_init_pm(void)1067 static int os2_init_pm(void)
1068 {
1069 if (!os2_pib) goto err0;
1070 os2_old_type = os2_pib->pib_ultype;
1071 os2_pib->pib_ultype = 3;
1072 os2_hab = WinInitialize(0);
1073 if (os2_hab == NULLHANDLE) goto err1;
1074 os2_hmq = WinCreateMsgQueue(os2_hab, 0);
1075 if (os2_hmq == NULLHANDLE) goto err2;
1076 return 0;
1077 err2:
1078 WinTerminate(os2_hab);
1079 err1:
1080 os2_pib->pib_ultype = os2_old_type;
1081 err0:
1082 return -1;
1083 }
1084
os2_exit_pm(void)1085 static void os2_exit_pm(void)
1086 {
1087 WinDestroyMsgQueue(os2_hmq);
1088 WinTerminate(os2_hab);
1089 os2_pib->pib_ultype = os2_old_type;
1090 }
1091
os_get_system_name(unsigned char * buffer)1092 int os_get_system_name(unsigned char *buffer)
1093 {
1094 ULONG version[3];
1095 if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, version, sizeof version))
1096 return -1;
1097 if (version[0] == 20) {
1098 version[0] = 2;
1099 if (version[1] == 10) {
1100 version[1] = 1;
1101 } else if (version[1] >= 30) {
1102 version[0] = version[1] / 10;
1103 version[1] %= 10;
1104 }
1105 }
1106 sprintf(cast_char buffer, "OS/2 %d.%d i386", (int)version[0], (int)version[1]);
1107 return 0;
1108 }
1109
1110 #elif !defined(OPENVMS)
1111
get_path_to_exe(void)1112 void get_path_to_exe(void)
1113 {
1114 path_to_exe = cast_uchar g_argv[0];
1115 }
1116
1117 #endif
1118
init_os_terminal(void)1119 void init_os_terminal(void)
1120 {
1121 #ifdef INTERIX
1122 {
1123 /* Some sort of terminal bug in Interix, if we run xterm -e links,
1124 terminal doesn't switch to raw mode, executing "stty sane" fixes it.
1125 Don't do this workaround on console. */
1126 unsigned char *term = cast_uchar getenv("TERM");
1127 if (!term || casecmp(term, cast_uchar "interix", 7)) {
1128 system("stty sane 2>/dev/null");
1129 }
1130 }
1131 #endif
1132 #ifdef OS2
1133 if (os2_detached) {
1134 fatal_exit("Links doesn't work in detached session");
1135 }
1136 #endif
1137 }
1138
1139 #ifdef INTERIX
1140
cut_program_path(unsigned char * prog,unsigned char ** prog_start,unsigned char ** prog_end)1141 static inline void cut_program_path(unsigned char *prog, unsigned char **prog_start, unsigned char **prog_end)
1142 {
1143 while (WHITECHAR(*prog)) prog++;
1144 if (prog[0] == '"' || prog[0] == '\'') {
1145 *prog_start = prog + 1;
1146 *prog_end = cast_uchar strchr(cast_const_char(prog + 1), prog[0]);
1147 if (!*prog_end)
1148 *prog_end = cast_uchar strchr(cast_const_char prog, 0);
1149 } else {
1150 *prog_start = prog;
1151 *prog_end = prog + strcspn(cast_const_char prog, " ");
1152 }
1153 }
1154
is_windows_drive(unsigned char * prog_start,unsigned char * prog_end)1155 static inline int is_windows_drive(unsigned char *prog_start, unsigned char *prog_end)
1156 {
1157 if (prog_end - prog_start >= 3 && upcase(prog_start[0]) >= 'A' && upcase(prog_start[0]) <= 'Z' && prog_start[1] == ':')
1158 return 1;
1159 return 0;
1160 }
1161
is_windows_program(unsigned char * prog_start,unsigned char * prog_end)1162 static inline int is_windows_program(unsigned char *prog_start, unsigned char *prog_end)
1163 {
1164 if (prog_end - prog_start > 4 && (
1165 !casecmp(prog_end - 4, cast_uchar ".exe", 4) ||
1166 !casecmp(prog_end - 4, cast_uchar ".bat", 4)))
1167 return 1;
1168 return 0;
1169 }
1170
1171 #endif
1172
1173 #if defined(WIN) && defined(HAVE_CYGWIN_CONV_PATH)
1174
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1175 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1176 {
1177 unsigned char *new_path;
1178 ssize_t sz;
1179 sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, NULL, 0);
1180 if (sz < 0 || sz >= MAXINT) return stracpy(file);
1181 new_path = mem_alloc(sz);
1182 sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, new_path, sz);
1183 if (sz < 0) {
1184 mem_free(new_path);
1185 return stracpy(file);
1186 }
1187 return new_path;
1188 }
1189
1190 #elif defined(WIN) && defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH)
1191
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1192 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1193 {
1194 #ifdef MAX_PATH
1195 unsigned char new_path[MAX_PATH];
1196 #else
1197 unsigned char new_path[1024];
1198 #endif
1199 *new_path = 0;
1200 cygwin_conv_to_full_win32_path(cast_const_char file, cast_char new_path);
1201 if (!*new_path) return stracpy(file);
1202 return stracpy(new_path);
1203 }
1204
1205 #elif defined(WIN) && defined(HAVE_UWIN_PATH)
1206
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1207 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1208 {
1209 unsigned char *new_path;
1210 ssize_t sz, sz2;
1211 sz = uwin_path(file, NULL, 0);
1212 if (sz < 0 || sz >= MAXINT) return stracpy(file);
1213 new_path = mem_alloc(sz + 1);
1214 sz2 = uwin_path(file, new_path, sz + 1);
1215 if (sz2 < 0 || sz2 > sz) {
1216 mem_free(new_path);
1217 return stracpy(file);
1218 }
1219 return new_path;
1220 }
1221
1222 #elif defined(INTERIX) && defined(HAVE_UNIXPATH2WIN)
1223
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1224 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1225 {
1226 unsigned char *prog_start, *prog_end;
1227 if (!prog) prog = ".exe";
1228 cut_program_path(prog, &prog_start, &prog_end);
1229 /* Convert path only if the program has ".exe" or ".bat" extension */
1230 if (is_windows_program(prog_start, prog_end)) {
1231 #ifdef MAX_PATH
1232 unsigned char new_path[MAX_PATH];
1233 #else
1234 unsigned char new_path[512];
1235 #endif
1236 unsigned char *newstr;
1237 int newstrl;
1238 unsigned char *p;
1239 if (unixpath2win(file, 0, new_path, sizeof(new_path)))
1240 goto copy_path;
1241 /*return stracpy(new_path);*/
1242 newstr = init_str();
1243 newstrl = 0;
1244 for (p = new_path; *p; p++) {
1245 /*
1246 * Unix shell hates backslash and Windows applications
1247 * accept '/'
1248 */
1249 if (*p == '\\') add_chr_to_str(&newstr, &newstrl, '/');
1250 else add_chr_to_str(&newstr, &newstrl, *p);
1251 }
1252 return newstr;
1253 }
1254 copy_path:
1255 return stracpy(file);
1256 }
1257
1258 #elif defined(OS2) || defined(DOS)
1259
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1260 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1261 {
1262 unsigned char *f, *x;
1263 f = stracpy(file);
1264 #ifdef OS2
1265 if (prog)
1266 return f;
1267 #endif
1268 x = f;
1269 while ((x = cast_uchar strchr(cast_const_char x, '/'))) *x = '\\';
1270 return f;
1271 }
1272
1273
1274 #else
1275
os_conv_to_external_path(unsigned char * file,unsigned char * prog)1276 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
1277 {
1278 return stracpy(file);
1279 }
1280
1281 #endif
1282
1283 #if defined(INTERIX) && defined(HAVE_WINPATH2UNIX)
1284
os_fixup_external_program(unsigned char * prog)1285 unsigned char *os_fixup_external_program(unsigned char *prog)
1286 {
1287 unsigned char *prog_start, *prog_end;
1288 cut_program_path(prog, &prog_start, &prog_end);
1289 if (is_windows_drive(prog_start, prog_end)) {
1290 #ifdef MAX_PATH
1291 unsigned char new_path[MAX_PATH];
1292 #else
1293 unsigned char new_path[1024];
1294 #endif
1295 unsigned char *newstr;
1296 int newstrl;
1297 unsigned char *xpath;
1298 if (is_windows_program(prog_start, prog_end)) {
1299 /*
1300 * There is some bug in Interix. Executing Win32
1301 * binaries works from the console but doesn't work
1302 * from xterm. So we prepend "cmd /c" to the program
1303 * as a workaround.
1304 */
1305 newstr = init_str();
1306 newstrl = 0;
1307 add_to_str(&newstr, &newstrl, cast_uchar "cmd /c ");
1308 add_to_str(&newstr, &newstrl, prog);
1309 return newstr;
1310 }
1311 xpath = memacpy(prog_start, prog_end - prog_start);
1312 if (winpath2unix(xpath, 0, new_path, sizeof(new_path))) {
1313 mem_free(xpath);
1314 goto copy_prog;
1315 }
1316 mem_free(xpath);
1317 newstr = init_str();
1318 newstrl = 0;
1319 add_bytes_to_str(&newstr, &newstrl, prog, prog_start - prog);
1320 add_to_str(&newstr, &newstrl, new_path);
1321 add_to_str(&newstr, &newstrl, prog_end);
1322 return newstr;
1323 }
1324 copy_prog:
1325 return stracpy(prog);
1326 }
1327
1328 #else
1329
os_fixup_external_program(unsigned char * prog)1330 unsigned char *os_fixup_external_program(unsigned char *prog)
1331 {
1332 return stracpy(prog);
1333 }
1334
1335 #endif
1336
1337
1338 #if defined(UNIX) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(OPENVMS) || defined(DOS) || defined(HAIKU)
1339
1340 #if defined(BEOS) && defined(HAVE_SETPGID)
1341
exe(unsigned char * path,int fg)1342 int exe(unsigned char *path, int fg)
1343 {
1344 pid_t p, rp;
1345 int s, rs;
1346 EINTRLOOP(p, fork());
1347 if (!p) {
1348 EINTRLOOP(rs, setpgid(0, 0));
1349 system(path);
1350 _exit(0);
1351 }
1352 if (p > 0) {
1353 EINTRLOOP(rp, waitpid(p, &s, 0));
1354 } else {
1355 rs = system(path);
1356 return rs;
1357 }
1358 return 0;
1359 }
1360
1361 #else
1362
1363 /* UNIX */
exe(unsigned char * path,int fg)1364 int exe(unsigned char *path, int fg)
1365 {
1366 #ifdef OPENVMS
1367 if (!strcmp(cast_const_char path, DEFAULT_SHELL))
1368 path = cast_uchar "";
1369 #endif
1370 #ifndef EXEC_IN_THREADS
1371 #ifdef SIGCHLD
1372 do_signal(SIGCHLD, SIG_DFL);
1373 #endif
1374 do_signal(SIGPIPE, SIG_DFL);
1375 #ifdef SIGXFSZ
1376 do_signal(SIGXFSZ, SIG_DFL);
1377 #endif
1378 #ifdef SIGTSTP
1379 do_signal(SIGTSTP, SIG_DFL);
1380 #endif
1381 #ifdef SIGCONT
1382 do_signal(SIGCONT, SIG_DFL);
1383 #endif
1384 #ifdef SIGWINCH
1385 do_signal(SIGWINCH, SIG_DFL);
1386 #endif
1387 #endif
1388 #ifdef G
1389 if (F && drv->exec) return drv->exec(path, fg);
1390 #endif
1391 return system(cast_const_char path);
1392 }
1393
1394 #endif
1395
1396 /* clipboard -> links */
get_clipboard_text(struct terminal * term)1397 unsigned char *get_clipboard_text(struct terminal *term)
1398 {
1399 #ifdef G
1400 if (F && drv->get_clipboard_text) {
1401 return drv->get_clipboard_text();
1402 }
1403 #endif
1404 if (!clipboard)
1405 return NULL;
1406 return convert(utf8_table, term_charset(term), clipboard, NULL);
1407 }
1408
1409 /* links -> clipboard */
set_clipboard_text(struct terminal * term,unsigned char * data)1410 void set_clipboard_text(struct terminal *term, unsigned char *data)
1411 {
1412 #ifdef G
1413 if (F && drv->set_clipboard_text) {
1414 drv->set_clipboard_text(data);
1415 return;
1416 }
1417 #endif
1418 if (clipboard) mem_free(clipboard);
1419 clipboard = convert(term_charset(term), utf8_table, data, NULL);
1420 }
1421
clipboard_support(struct terminal * term)1422 int clipboard_support(struct terminal *term)
1423 {
1424 #ifdef G
1425 if (F && drv->set_clipboard_text) {
1426 return 1;
1427 }
1428 #endif
1429 return 0;
1430 }
1431
set_window_title(unsigned char * title)1432 void set_window_title(unsigned char *title)
1433 {
1434 /* !!! FIXME */
1435 }
1436
get_window_title(void)1437 unsigned char *get_window_title(void)
1438 {
1439 /* !!! FIXME */
1440 return NULL;
1441 }
1442
resize_window(int x,int y)1443 int resize_window(int x, int y)
1444 {
1445 return -1;
1446 }
1447
1448 #elif defined(WIN)
1449
is_winnt(void)1450 int is_winnt(void)
1451 {
1452 OSVERSIONINFO v;
1453 v.dwOSVersionInfoSize = sizeof v;
1454 if (!GetVersionEx(&v)) return 0;
1455 return v.dwPlatformId >= VER_PLATFORM_WIN32_NT;
1456 }
1457
close_handles(int keep_output)1458 static void close_handles(int keep_output)
1459 {
1460 int i, rs;
1461 for (i = 0; i < FD_SETSIZE; i++) {
1462 if (keep_output && (i == 1 || i == 2)) continue;
1463 EINTRLOOP(rs, close(i));
1464 }
1465 EINTRLOOP(rs, open("nul", O_RDONLY));
1466 if (!keep_output) {
1467 EINTRLOOP(rs, open("nul", O_WRONLY));
1468 EINTRLOOP(rs, open("nul", O_WRONLY));
1469 }
1470 }
1471
1472 #define WIN32_START_STRING "start /wait "
1473
exe(unsigned char * path,int fg)1474 int exe(unsigned char *path, int fg)
1475 {
1476 /* This is very tricky. We must have exactly 3 arguments, the first
1477 one shell and the second one "/c", otherwise Cygwin would quote
1478 the arguments and trash them */
1479 int ct = 0;
1480 unsigned char buffer[1024];
1481 unsigned char buffer2[1024];
1482 size_t want_alloc;
1483 pid_t pid, rp;
1484 #ifndef _UWIN
1485 int rs;
1486 #endif
1487 unsigned char *x1;
1488 unsigned char *arg;
1489 x1 = cast_uchar GETSHELL;
1490 if (!x1) x1 = cast_uchar DEFAULT_SHELL;
1491
1492 want_alloc = strlen(cast_const_char WIN32_START_STRING) + 3 + strlen(cast_const_char path) + 1;
1493 #ifdef _UWIN
1494 want_alloc += strlen(cast_const_char x1) + 4;
1495 want_alloc *= 2;
1496 #endif
1497
1498 arg = malloc(want_alloc);
1499 if (!arg) return -1;
1500 *arg = 0;
1501 #ifdef _UWIN
1502 strcat(cast_char arg, cast_const_char x1);
1503 strcat(cast_char arg, " /c ");
1504 #endif
1505 strcat(cast_char arg, cast_const_char WIN32_START_STRING);
1506 if (*path == '"' && is_winnt()) strcat(cast_char arg, "\"\" ");
1507 strcat(cast_char arg, cast_const_char path);
1508 if (!is_winnt()) ct = GetConsoleTitleA(cast_char buffer, sizeof buffer);
1509 #if defined(_UWIN) && !defined(__DMC__)
1510 {
1511 unsigned char *q1 = arg, *q2 = arg;
1512 while (*q1) {
1513 if (*q1 == '\\') q2++;
1514 q2++;
1515 q1++;
1516 }
1517 while (1) {
1518 *q2 = *q1;
1519 if (*q1 == '\\') {
1520 q2--;
1521 *q2 = '\\';
1522 }
1523 if (q1 == arg) break;
1524 q1--;
1525 q2--;
1526 }
1527 }
1528 /* UWin corrupts heap if we use threads and fork */
1529 fd_lock();
1530 pid = spawnl("/bin/sh", "/bin/sh", "-c", arg, (char *)NULL);
1531 fd_unlock();
1532 #else
1533 #if 1 /* spawn breaks mouse, do this only in graphics mode */
1534 if (F && is_winnt()) {
1535 /* spawn crashes on Win98 */
1536 fd_lock();
1537 spawnlp(_P_WAIT, cast_const_char x1, cast_const_char x1, "/c", cast_const_char arg, (char *)NULL);
1538 fd_unlock();
1539 /*FreeConsole();*/
1540 goto free_ret;
1541 } else
1542 #endif
1543 {
1544 EINTRLOOP(pid, fork());
1545 if (!pid) {
1546 /* Win98 crashes if we spawn command.com and have some sockets open */
1547 close_handles(0);
1548 EINTRLOOP(rs, execlp(cast_const_char x1, cast_const_char x1, "/c", cast_const_char arg, (char *)NULL));
1549 _exit(1);
1550 }
1551 }
1552 #endif
1553 if (!is_winnt()) {
1554 portable_sleep(1000);
1555 if (ct && GetConsoleTitleA(cast_char buffer2, sizeof buffer2) && !casecmp(buffer2, cast_uchar "start", 5)) {
1556 SetConsoleTitleA(cast_const_char buffer);
1557 }
1558 }
1559 if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0));
1560 goto free_ret;
1561
1562 free_ret:
1563 free(arg);
1564 return 0;
1565 }
1566
exe_on_background(unsigned char * path,unsigned char * del)1567 int exe_on_background(unsigned char *path, unsigned char *del)
1568 {
1569 #ifdef __CYGWIN__
1570 unsigned char *x1;
1571 unsigned char *arg;
1572 unsigned char *delx;
1573 int use_create_process = 0;
1574 #if CYGWIN_VERSION_API_MAJOR > 1 || CYGWIN_VERSION_API_MINOR >= 154
1575 if (is_winnt()) {
1576 use_create_process = 1;
1577 if (cygwin_internal(CW_SYNC_WINENV))
1578 use_create_process = 0;
1579 }
1580 #endif
1581
1582 if (!is_winnt()) {
1583 if (del && *del)
1584 return -1;
1585 }
1586
1587 x1 = cast_uchar GETSHELL;
1588 if (!x1) x1 = cast_uchar DEFAULT_SHELL;
1589
1590 arg = stracpy(cast_uchar "");
1591 if (use_create_process) {
1592 add_to_strn(&arg, x1);
1593 add_to_strn(&arg, cast_uchar " /c ");
1594 }
1595 add_to_strn(&arg, cast_uchar WIN32_START_STRING);
1596 if (is_winnt()) if (*path == '"') add_to_strn(&arg, cast_uchar "\"\" ");
1597 add_to_strn(&arg, path);
1598 if (del && *del) {
1599 add_to_strn(&arg, cast_uchar " & ");
1600 add_to_strn(&arg, cast_uchar "del \"");
1601 delx = os_conv_to_external_path(del, path);
1602 add_to_strn(&arg, delx);
1603 mem_free(delx);
1604 add_to_strn(&arg, cast_uchar "\"");
1605 }
1606
1607 /*debug("'%s'", arg);*/
1608
1609 if (use_create_process) {
1610 PROCESS_INFORMATION pi;
1611 STARTUPINFOA si;
1612 memset(&pi, 0, sizeof pi);
1613 memset(&si, 0, sizeof si);
1614 si.cb = sizeof si;
1615 fd_lock();
1616 if (CreateProcessA(cast_char x1, cast_char arg, NULL, NULL, FALSE, CREATE_NO_WINDOW | (is_winnt() ? DETACHED_PROCESS : 0), NULL, NULL, &si, &pi)) {
1617 CloseHandle(pi.hProcess);
1618 CloseHandle(pi.hThread);
1619 }
1620 fd_unlock();
1621 } else {
1622 /* We need to fork here so that we can close handles */
1623 pid_t pid;
1624 /*int rs;*/
1625 EINTRLOOP(pid, fork());
1626 if (!pid) {
1627 close_handles(0);
1628 /*EINTRLOOP(rs, execlp(cast_const_char x1, cast_const_char x1, "/c", cast_const_char arg, (char *)NULL));*/
1629 spawnlp(_P_DETACH, cast_const_char x1, cast_const_char x1, "/c", cast_const_char arg, (char *)NULL);
1630 _exit(1);
1631 }
1632 }
1633
1634 mem_free(arg);
1635 return 0;
1636 #else
1637 return -1;
1638 #endif
1639 }
1640
windows_charset(void)1641 int windows_charset(void)
1642 {
1643 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_LANGINFO_H) && defined(CODESET)
1644 int idx;
1645 unsigned char *cp;
1646 cp = cast_uchar nl_langinfo(CODESET);
1647 idx = get_cp_index(cp);
1648 if (idx >= 0)
1649 return idx;
1650 #endif
1651 return utf8_table;
1652 }
1653
get_clipboard_text(struct terminal * term)1654 unsigned char *get_clipboard_text(struct terminal *term)
1655 {
1656 unsigned char buffer[256];
1657 unsigned char *str, *s, *d, *result;
1658 int l;
1659 int r;
1660 int rs;
1661 int h;
1662 if (!clipboard_support(term)) {
1663 str = stracpy(clipboard);
1664 goto cvt_ret;
1665 }
1666 /* O_TEXT doesn't work on clipboard handle */
1667 h = c_open(cast_uchar "/dev/clipboard", O_RDONLY);
1668 if (h == -1) return stracpy(clipboard);
1669 str = init_str();
1670 l = 0;
1671 /* Don't use hard_read because UWin has buggy end-of-file signalling.
1672 It resets the position to the beginning after signalling eof. */
1673 while (1) {
1674 EINTRLOOP(r, (int)read(h, buffer, sizeof buffer));
1675 if (r <= 0) break;
1676 add_bytes_to_str(&str, &l, buffer, r);
1677 }
1678 EINTRLOOP(rs, close(h));
1679 for (s = str, d = str; *s; s++)
1680 if (!(s[0] == '\r' && s[1] == '\n')) *d++ = *s;
1681 *d = 0;
1682
1683 cvt_ret:
1684 result = convert(windows_charset(), term_charset(term), str, NULL);
1685 mem_free(str);
1686 return result;
1687 }
1688
set_clipboard_text(struct terminal * term,unsigned char * data)1689 void set_clipboard_text(struct terminal *term, unsigned char *data)
1690 {
1691 unsigned char *p;
1692 unsigned char *conv_data;
1693 int l;
1694 int h;
1695 int rs;
1696 if (clipboard) mem_free(clipboard);
1697 clipboard = convert(term_charset(term), windows_charset(), data, NULL);
1698 if (!clipboard_support(term)) return;
1699 /* O_TEXT doesn't work on clipboard handle */
1700 h = c_open(cast_uchar "/dev/clipboard", O_WRONLY);
1701 if (h == -1) return;
1702 conv_data = init_str();
1703 l = 0;
1704 for (p = clipboard; *p; p++) {
1705 if (*p == '\n') add_to_str(&conv_data, &l, cast_uchar "\r\n");
1706 else add_chr_to_str(&conv_data, &l, *p);
1707 }
1708 hard_write(h, conv_data, l);
1709 mem_free(conv_data);
1710 EINTRLOOP(rs, close(h));
1711 }
1712
clipboard_support(struct terminal * term)1713 int clipboard_support(struct terminal *term)
1714 {
1715 struct stat st;
1716 int rs;
1717 EINTRLOOP(rs, stat("/dev/clipboard", &st));
1718 return !rs && S_ISCHR(st.st_mode);
1719 }
1720
get_windows_cp(int cons)1721 int get_windows_cp(int cons)
1722 {
1723 unsigned char str[8];
1724 int cp, idx;
1725 if (cons && is_winnt())
1726 cp = GetConsoleOutputCP();
1727 else
1728 cp = GetACP();
1729 if (cp <= 0 || cp >= 100000) return 0;
1730 if (cp == 874) cp = 28605;
1731 if (cp >= 28591 && cp <= 28605) {
1732 sprintf(cast_char str, "8859-%d", cp - 28590);
1733 } else {
1734 sprintf(cast_char str, "%d", cp);
1735 }
1736 if ((idx = get_cp_index(str)) < 0) return 0;
1737 return idx;
1738 }
1739
set_window_title(unsigned char * title)1740 void set_window_title(unsigned char *title)
1741 {
1742 unsigned char *t, *p;
1743 if (!title) return;
1744 if (is_xterm()) return;
1745 t = convert(utf8_table, get_windows_cp(1), title, NULL);
1746 for (p = cast_uchar strchr(cast_const_char t, 1); p; p = cast_uchar strchr(cast_const_char(p + 1), 1))
1747 *p = ' ';
1748 SetConsoleTitleA(cast_const_char t);
1749 mem_free(t);
1750 }
1751
get_window_title(void)1752 unsigned char *get_window_title(void)
1753 {
1754 int r;
1755 unsigned char buffer[1024];
1756 if (is_xterm()) return NULL;
1757 if (!(r = GetConsoleTitleA(cast_char buffer, sizeof buffer))) return NULL;
1758 if (r >= 1024) r = 1023;
1759 buffer[r] = 0;
1760 return convert(get_windows_cp(1), utf8_table, buffer, NULL);
1761 }
1762
call_resize(unsigned char * x1,int x,int y)1763 static void call_resize(unsigned char *x1, int x, int y)
1764 {
1765 pid_t pid, rp;
1766 #ifndef _UWIN
1767 int rs;
1768 #endif
1769 unsigned char arg[64];
1770 #ifdef _UWIN
1771 x++;
1772 #endif
1773 snprintf(cast_char arg, (int)sizeof(arg), "mode %d,%d", x, y);
1774 #if defined(_UWIN) && !defined(__DMC__)
1775 pid = spawnlp(x1, x1, "/c", arg, (char *)NULL);
1776 #else
1777 #if 0 /* spawn breaks mouse, don't use this */
1778 if (is_winnt()) {
1779 /* spawn crashes on Win98 */
1780 fd_lock();
1781 spawnlp(_P_WAIT, x1, x1, "/c", arg, (char *)NULL);
1782 fd_unlock();
1783 return;
1784 } else
1785 #endif
1786 {
1787 EINTRLOOP(pid, fork());
1788 if (!pid) {
1789 /* Win98 crashes if we spawn command.com and have some sockets open */
1790 close_handles(1);
1791 EINTRLOOP(rs, execlp(cast_const_char x1, cast_const_char x1, "/c", cast_const_char arg, (char *)NULL));
1792 _exit(1);
1793 }
1794 }
1795 #endif
1796 if (pid != -1) EINTRLOOP(rp, waitpid(pid, NULL, 0));
1797 }
1798
resize_window(int x,int y)1799 int resize_window(int x, int y)
1800 {
1801 int old_x, old_y;
1802 int ct = 0, fullscreen = 0;
1803 unsigned char buffer[1024];
1804 unsigned char *x1;
1805 if (is_xterm()) return -1;
1806 get_terminal_size(&old_x, &old_y);
1807 x1 = cast_uchar GETSHELL;
1808 if (!x1) x1 = cast_uchar DEFAULT_SHELL;
1809 if (!is_winnt()) {
1810 ct = GetConsoleTitleA(cast_char buffer, sizeof buffer);
1811 }
1812
1813 call_resize(x1, x, y);
1814 if (!is_winnt()) {
1815 int new_x, new_y;
1816 /* If we resize console on Win98 in fullscreen mode, it won't be
1817 notified by Cygwin (it is valid for all Cygwin apps). So we must
1818 switch to windowed mode, resize it again (twice, because resizing
1819 to the same size won't have an effect) and switch back to full-screen
1820 mode. */
1821 /* I'm not sure what's the behavior on WinNT 4. Anybody wants to test?
1822 */
1823 if (!fullscreen && (get_terminal_size(&new_x, &new_y), (new_x != x || new_y != y))) {
1824 fullscreen = 1;
1825 #ifdef __CYGWIN__
1826 keybd_event(VK_MENU, 0x38, 0, 0);
1827 keybd_event(VK_RETURN, 0x1c, 0, 0);
1828 keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
1829 keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
1830 #endif
1831 if (y != 25) call_resize(x1, 80, 25);
1832 else call_resize(x1, 80, 50);
1833 call_resize(x1, x, y);
1834 get_terminal_size(&new_x, &new_y);
1835 if (new_x != x || new_y != y) call_resize(x1, old_x, old_y);
1836 #ifdef __CYGWIN__
1837 keybd_event(VK_MENU, 0x38, 0, 0);
1838 keybd_event(VK_RETURN, 0x1c, 0, 0);
1839 keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
1840 keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
1841 #endif
1842 }
1843 if (ct) SetConsoleTitleA(cast_const_char buffer);
1844 }
1845 return 0;
1846 }
1847
1848 #elif defined(OS2)
1849
exe(unsigned char * path,int fg)1850 int exe(unsigned char *path, int fg)
1851 {
1852 int flags = P_SESSION;
1853 pid_t pid, rs;
1854 int ret;
1855 #ifdef G
1856 int old0 = 0, old1 = 1, old2 = 2;
1857 #endif
1858 unsigned char *shell;
1859 if (!(shell = GETSHELL)) shell = DEFAULT_SHELL;
1860 if (is_xterm()) flags |= P_BACKGROUND;
1861 #ifdef G
1862 if (F) {
1863 old0 = c_dup(0);
1864 old1 = c_dup(1);
1865 old2 = c_dup(2);
1866 fd_lock();
1867 if (old0 >= 0) EINTRLOOP(rs, close(0));
1868 if (old1 >= 0) EINTRLOOP(rs, close(1));
1869 if (old2 >= 0) EINTRLOOP(rs, close(2));
1870 if (old0 >= 0) EINTRLOOP(rs, open("con", O_RDONLY));
1871 if (old1 >= 0) EINTRLOOP(rs, open("con", O_WRONLY));
1872 if (old2 >= 0) EINTRLOOP(rs, open("con", O_WRONLY));
1873 } else
1874 #endif
1875 {
1876 fd_lock();
1877 }
1878 pid = spawnlp(flags, shell, shell, "/c", path, (char *)NULL);
1879 #ifdef G
1880 if (F) {
1881 if (old0 >= 0) EINTRLOOP(rs, dup2(old0, 0));
1882 if (old1 >= 0) EINTRLOOP(rs, dup2(old1, 1));
1883 if (old2 >= 0) EINTRLOOP(rs, dup2(old2, 2));
1884 if (old0 >= 0) EINTRLOOP(rs, close(old0));
1885 if (old1 >= 0) EINTRLOOP(rs, close(old1));
1886 if (old2 >= 0) EINTRLOOP(rs, close(old2));
1887 }
1888 #endif
1889 fd_unlock();
1890 if (pid != -1) EINTRLOOP(rs, waitpid(pid, &ret, 0));
1891 else ret = -1;
1892 return ret;
1893 }
1894
get_clipboard_text(struct terminal * term)1895 unsigned char *get_clipboard_text(struct terminal *term)
1896 {
1897 unsigned char *ret = NULL;
1898
1899 if (os2_init_pm()) return NULL;
1900
1901 if (WinOpenClipbrd(os2_hab)) {
1902 ULONG fmtInfo = 0;
1903
1904 if (WinQueryClipbrdFmtInfo(os2_hab, CF_TEXT, &fmtInfo)!=FALSE)
1905 {
1906 ULONG selClipText = WinQueryClipbrdData(os2_hab, CF_TEXT);
1907
1908 if (selClipText) {
1909 unsigned char *u;
1910 PCHAR pchClipText = (PCHAR)selClipText;
1911 ret = stracpy(pchClipText);
1912 while ((u = cast_uchar strchr(cast_const_char ret, 13))) memmove(u, u + 1, strlen(cast_const_char(u + 1)) + 1);
1913 }
1914 }
1915
1916 WinCloseClipbrd(os2_hab);
1917 }
1918
1919 #ifdef G
1920 if (F && ret) {
1921 static int cp = -1;
1922 unsigned char *d;
1923 if (cp == -1) {
1924 int c = WinQueryCp(os2_hmq);
1925 unsigned char a[8];
1926 snprintf(cast_char a, sizeof a, "%d", c);
1927 if ((cp = get_cp_index(a)) < 0 || cp == utf8_table) cp = 0;
1928 }
1929 d = convert(cp, utf8_table, ret, NULL);
1930 mem_free(ret);
1931 ret = d;
1932 }
1933 #endif
1934
1935 os2_exit_pm();
1936
1937 return ret;
1938 }
1939
set_clipboard_text(struct terminal * term,unsigned char * data)1940 void set_clipboard_text(struct terminal *term, unsigned char *data)
1941 {
1942 unsigned char *d = NULL;
1943
1944 if (os2_init_pm()) return;
1945
1946 #ifdef G
1947 if (F) {
1948 static int cp = -1;
1949 unsigned char *p;
1950 if (cp == -1) {
1951 int c = WinQueryCp(os2_hmq);
1952 unsigned char a[8];
1953 snprintf(cast_char a, sizeof a, "%d", c);
1954 if ((cp = get_cp_index(a)) < 0 || cp == utf8_table) cp = 0;
1955 }
1956 d = convert(utf8_table, cp, data, NULL);
1957 for (p = cast_uchar strchr(cast_const_char d, 1); p; p = cast_uchar strchr(cast_const_char(p + 1), 1))
1958 *p = ' ';
1959 data = d;
1960 }
1961 #endif
1962 if (WinOpenClipbrd(os2_hab)) {
1963 PVOID pvShrObject = NULL;
1964 if (DosAllocSharedMem(&pvShrObject, NULL, strlen(cast_const_char data)+1, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) {
1965 strcpy(cast_char pvShrObject, cast_const_char data);
1966 WinEmptyClipbrd(os2_hab);
1967 WinSetClipbrdData(os2_hab, (ULONG)pvShrObject, CF_TEXT, CFI_POINTER);
1968 }
1969 WinCloseClipbrd(os2_hab);
1970 }
1971
1972 os2_exit_pm();
1973
1974 if (d) mem_free(d);
1975 }
1976
clipboard_support(struct terminal * term)1977 int clipboard_support(struct terminal *term)
1978 {
1979 return 1;
1980 }
1981
get_window_title(void)1982 unsigned char *get_window_title(void)
1983 {
1984 #ifndef OS2_DEBUG
1985 unsigned char *win_title = NULL;
1986 SWCNTRL swData;
1987
1988 memset(&swData, 0, sizeof swData);
1989 if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData)) {
1990 swData.szSwtitle[MAXNAMEL - 1] = 0;
1991 win_title = stracpy(swData.szSwtitle);
1992 if (swData.hwnd != NULLHANDLE && !os2_init_pm()) {
1993 LONG len = WinQueryWindowTextLength(swData.hwnd);
1994 if (len > 0 && len < MAXINT) {
1995 mem_free(win_title);
1996 win_title = mem_alloc(len + 1);
1997 win_title[0] = 0;
1998 WinQueryWindowText(swData.hwnd, len + 1, win_title);
1999 win_title[len] = 0;
2000 }
2001 os2_exit_pm();
2002 }
2003 }
2004
2005 return win_title;
2006 #else
2007 return NULL;
2008 #endif
2009 }
2010
set_window_title(unsigned char * title)2011 void set_window_title(unsigned char *title)
2012 {
2013 #ifndef OS2_DEBUG
2014 SWCNTRL swData;
2015
2016 if (!title) return;
2017
2018 memset(&swData, 0, sizeof swData);
2019 if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData)) {
2020 safe_strncpy(swData.szSwtitle, title, MAXNAMEL);
2021 WinChangeSwitchEntry(os2_switchhandle, &swData);
2022 if (swData.hwnd != NULLHANDLE && !os2_init_pm()) {
2023 WinSetWindowText(swData.hwnd, title);
2024 os2_exit_pm();
2025 }
2026 }
2027 #endif
2028 }
2029
2030 static tcount resize_count = 0;
2031
resize_window(int x,int y)2032 int resize_window(int x, int y)
2033 {
2034 int xfont, yfont;
2035 A_DECL(VIOMODEINFO, vmi);
2036 SWCNTRL swData;
2037
2038 resize_count++;
2039 if (is_xterm()) return -1;
2040 vmi->cb = sizeof(*vmi);
2041 if (VioGetMode(vmi, 0)) return -1;
2042 vmi->col = x;
2043 vmi->row = y;
2044 /*debug("%d %d %d", vmi->buf_length, vmi->full_length, vmi->partial_length);*/
2045 for (xfont = 9; xfont >= 8; xfont--)
2046 for (yfont = 16; yfont >= 8; yfont--) {
2047 vmi->hres = x * xfont;
2048 vmi->vres = y * yfont;
2049 if (vmi->vres <= 400) vmi->vres = 400;
2050 else if (vmi->vres <= 480) vmi->vres = 480;
2051 vmi->buf_length = vmi->full_length = vmi->partial_length = x * ((vmi->vres + yfont - 1) / yfont) * 2;
2052 vmi->full_length = (vmi->full_length + 4095) & ~4095;
2053 vmi->partial_length = (vmi->partial_length + 4095) & ~4095;
2054 if (!VioSetMode(vmi, 0)) goto resized;
2055 }
2056 return -1;
2057
2058 resized:
2059 memset(&swData, 0, sizeof swData);
2060 if (os2_switchhandle != NULLHANDLE && !WinQuerySwitchEntry(os2_switchhandle, &swData) && swData.hwnd != NULLHANDLE && !os2_init_pm()) {
2061 SWP swp;
2062 if (WinQueryWindowPos(swData.hwnd, &swp) && !(swp.fl & (SWP_MAXIMIZE | SWP_MINIMIZE | SWP_HIDE))) {
2063 const int expand = 16383;
2064 WinSetWindowPos(swData.hwnd, NULLHANDLE, swp.x, swp.y - expand, swp.cx + expand, swp.cy + expand, SWP_MOVE | SWP_SIZE);
2065 }
2066 os2_exit_pm();
2067 }
2068 return 0;
2069 }
2070
2071 #endif
2072
2073 /* Threads */
2074
2075 #if (defined(HAVE_BEGINTHREAD) && defined(OS2)) || defined(BEOS) || defined(HAVE_PTHREADS) || defined(HAVE_ATHEOS_THREADS_H)
2076
2077 struct tdata {
2078 void (*fn)(void *, int);
2079 int h;
2080 int counted;
2081 unsigned char data[1];
2082 };
2083
bgt(void * t_)2084 static void bgt(void *t_)
2085 {
2086 struct tdata *t = t_;
2087 int rs;
2088 ignore_signals();
2089 t->fn(t->data, t->h);
2090 EINTRLOOP(rs, (int)write(t->h, "x", 1));
2091 EINTRLOOP(rs, close(t->h));
2092 free(t);
2093 }
2094
2095 #ifdef HAVE_ATHEOS_THREADS_H
2096 #include <atheos/threads.h>
bgat(void * t)2097 static uint32 bgat(void *t)
2098 {
2099 bgt(t);
2100 return 0;
2101 }
2102 #endif
2103
2104 #endif
2105
2106 #if defined(UNIX) || defined(OS2) || defined(WIN) || defined(INTERIX) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD) || defined(HAIKU)
2107
terminate_osdep(void)2108 void terminate_osdep(void)
2109 {
2110 }
2111
2112 #endif
2113
2114 #ifndef BEOS
2115
block_stdin(void)2116 void block_stdin(void) {}
unblock_stdin(void)2117 void unblock_stdin(void) {}
2118
2119 #endif
2120
2121 #if defined(BEOS)
2122
2123 #include <be/kernel/OS.h>
2124
2125 static int thr_sem_init = 0;
2126 static sem_id thr_sem;
2127
2128 static struct list_head active_threads = { &active_threads, &active_threads };
2129
2130 struct active_thread {
2131 list_entry_1st
2132 thread_id tid;
2133 void (*fn)(void *);
2134 void *data;
2135 list_entry_last
2136 };
2137
started_thr(void * data)2138 static int32 started_thr(void *data)
2139 {
2140 struct active_thread *thrd = data;
2141 thrd->fn(thrd->data);
2142 if (acquire_sem(thr_sem) < B_NO_ERROR) return 0;
2143 del_from_list(thrd);
2144 free(thrd);
2145 release_sem(thr_sem);
2146 return 0;
2147 }
2148
start_thr(void (* fn)(void *),void * data,unsigned char * name)2149 int start_thr(void (*fn)(void *), void *data, unsigned char *name)
2150 {
2151 struct active_thread *thrd;
2152 int tid;
2153 if (!thr_sem_init) {
2154 if ((thr_sem = create_sem(0, "thread_sem")) < B_NO_ERROR) return -1;
2155 thr_sem_init = 1;
2156 } else if (acquire_sem(thr_sem) < B_NO_ERROR) return -1;
2157 retry:
2158 if (!(thrd = malloc(sizeof(struct active_thread)))) {
2159 if (out_of_memory(0, NULL, 0))
2160 goto retry;
2161 goto err1;
2162 }
2163 thrd->fn = fn;
2164 thrd->data = data;
2165 if ((tid = thrd->tid = spawn_thread(started_thr, name, B_NORMAL_PRIORITY, thrd)) < B_NO_ERROR)
2166 goto err2;
2167 resume_thread(thrd->tid);
2168 add_to_list(active_threads, thrd);
2169 release_sem(thr_sem);
2170 return tid;
2171
2172 err2:
2173 free(thrd);
2174 err1:
2175 release_sem(thr_sem);
2176 return -1;
2177 }
2178
terminate_osdep(void)2179 void terminate_osdep(void)
2180 {
2181 struct list_head *p;
2182 struct active_thread *thrd;
2183 struct list_head *lthrd;
2184 if (acquire_sem(thr_sem) < B_NO_ERROR) return;
2185 foreach(struct active_thread, thrd, lthrd, active_threads) kill_thread(thrd->tid);
2186 while (!list_empty(active_threads)) {
2187 thrd = list_struct(active_threads.next, struct active_thread);
2188 del_from_list(thrd);
2189 free(thrd);
2190 }
2191 release_sem(thr_sem);
2192 }
2193
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2194 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2195 {
2196 int p[2];
2197 struct tdata *t;
2198 int rs;
2199 if (c_pipe(p) < 0) return -1;
2200 retry:
2201 if (!(t = malloc(sizeof(struct tdata) + l))) {
2202 if (out_of_memory(0, NULL, 0))
2203 goto retry;
2204 goto err1;
2205 }
2206 t->fn = fn;
2207 t->h = p[1];
2208 t->counted = counted;
2209 memcpy(t->data, ptr, l);
2210 if (start_thr(bgt, t, cast_uchar "links_thread") < 0)
2211 goto err2;
2212 return p[0];
2213
2214 err2:
2215 free(t);
2216 err1:
2217 EINTRLOOP(rs, close(p[0]));
2218 EINTRLOOP(rs, close(p[1]));
2219 return -1;
2220 }
2221
2222
2223 #elif defined(HAVE_BEGINTHREAD) && defined(OS2)
2224
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2225 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2226 {
2227 int p[2];
2228 struct tdata *t;
2229 int rs;
2230 if (c_pipe(p) < 0) return -1;
2231 retry:
2232 if (!(t = malloc(sizeof(struct tdata) + l))) {
2233 if (out_of_memory(0, NULL, 0))
2234 goto retry;
2235 goto err1;
2236 }
2237 t->fn = fn;
2238 t->h = p[1];
2239 t->counted = counted;
2240 memcpy(t->data, ptr, l);
2241 if (_beginthread(bgt, NULL, 65536, t) == -1)
2242 goto err2;
2243 return p[0];
2244
2245 err2:
2246 free(t);
2247 err1:
2248 EINTRLOOP(rs, close(p[0]));
2249 EINTRLOOP(rs, close(p[1]));
2250 return -1;
2251 }
2252
2253 #ifdef HAVE__READ_KBD
2254
2255 static int tp = -1;
2256 static int ti = -1;
2257
input_thread(void * p)2258 static void input_thread(void *p)
2259 {
2260 unsigned char c[2];
2261 int h = (int)p;
2262 int rs;
2263 ignore_signals();
2264 while (1) {
2265 /* for the records:
2266 _read_kbd(0, 1, 1) will
2267 read a char, don't echo it, wait for one available and
2268 accept CTRL-C.
2269 Knowing that, I suggest we replace this call completly!
2270 */
2271 *c = _read_kbd(0, 1, 1);
2272 EINTRLOOP(rs, (int)write(h, c, 1));
2273 }
2274 EINTRLOOP(rs, close(h));
2275 }
2276 #endif /* #ifdef HAVE__READ_KBD */
2277
2278 #if defined(HAVE_MOUOPEN) && defined(HAVE_BEGINTHREAD) && !defined(USE_GPM)
2279
2280 #define USING_OS2_MOUSE
2281
2282 static int mouse_h = -1;
2283
2284 struct os2_mouse_spec {
2285 int p[2];
2286 void (*fn)(void *, unsigned char *, int);
2287 void *data;
2288 unsigned char buffer[sizeof(struct links_event)];
2289 int bufptr;
2290 int terminate;
2291 };
2292
2293 #define MOU_EMULATE_CURSOR
2294
2295 #ifdef MOU_EMULATE_CURSOR
2296 static int mouse_x = -1, mouse_y = -1;
2297 static unsigned char mouse_attr;
2298 #endif
2299
mouse_remove_pointer(void)2300 static void mouse_remove_pointer(void)
2301 {
2302 #ifndef MOU_EMULATE_CURSOR
2303 A_DECL(NOPTRRECT, pa);
2304 static int x = -1, y = -1;
2305 static tcount c = -1;
2306 if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(&x, &y), c = resize_count;
2307 pa->row = 0;
2308 pa->col = 0;
2309 pa->cRow = y - 1;
2310 pa->cCol = x - 1;
2311 MouRemovePtr(pa, mouse_h);
2312 #else
2313 if (mouse_x >= 0 && mouse_y >= 0) {
2314 VioWrtNAttr(&mouse_attr, 1, mouse_y, mouse_x, 0);
2315 }
2316 mouse_x = -1, mouse_y = -1;
2317 #endif
2318 }
2319
mouse_draw_pointer(int x,int y)2320 static void mouse_draw_pointer(int x, int y)
2321 {
2322 #ifndef MOU_EMULATE_CURSOR
2323 MouDrawPtr(mouse_h);
2324 #else
2325 unsigned char str[4];
2326 USHORT str_len;
2327 unsigned char attr;
2328 unsigned char fg, bg;
2329 int r;
2330 if (!os2_full_screen)
2331 return;
2332 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
2333 if (mouse_x == x && mouse_y == y)
2334 return;
2335 mouse_remove_pointer();
2336 str_len = sizeof(str);
2337 r = VioReadCellStr(str, &str_len, y, x, 0);
2338 if (r || str_len < 2) return;
2339 mouse_attr = str[1];
2340 fg = mouse_attr & 0x07;
2341 bg = (mouse_attr & 0x70) >> 4;
2342 if (fg == bg) fg ^= 0x07, bg ^= 0x07;
2343 attr = (mouse_attr & 0x88) | (fg << 4) | bg;
2344 r = VioWrtNAttr(&attr, 1, y, x, 0);
2345 if (r) return;
2346 mouse_x = x, mouse_y = y, mouse_attr = str[1];
2347 #endif
2348 }
2349
mouse_thread(void * p)2350 static void mouse_thread(void *p)
2351 {
2352 int status;
2353 int rs;
2354 struct os2_mouse_spec *oms = p;
2355 A_DECL(HMOU, mh);
2356 A_DECL(MOUEVENTINFO, ms);
2357 A_DECL(USHORT, rd);
2358 A_DECL(USHORT, mask);
2359 struct links_event ev;
2360 ignore_signals();
2361 ev.ev = EV_MOUSE;
2362 if (MouOpen(NULL, mh)) goto ret;
2363 mouse_h = *mh;
2364 *mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
2365 MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
2366 MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
2367 MOUSE_MOTION;
2368 MouSetEventMask(mask, *mh);
2369 *rd = MOU_WAIT;
2370 status = -1;
2371 while (1) {
2372 /*int w, ww;*/
2373 if (MouReadEventQue(ms, rd, *mh)) break;
2374 fd_lock();
2375 if (!oms->terminate) mouse_draw_pointer(ms->col, ms->row);
2376 fd_unlock();
2377 ev.x = ms->col;
2378 ev.y = ms->row;
2379 /*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/
2380 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);
2381 else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
2382 int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_RIGHT : B_MIDDLE;
2383 if (status == -1) b |= B_DOWN;
2384 else b |= B_DRAG;
2385 ev.b = status = b;
2386 }
2387 else {
2388 if (status == -1) continue;
2389 ev.b = (status & BM_BUTT) | B_UP;
2390 status = -1;
2391 }
2392 if (hard_write(oms->p[1], (unsigned char *)&ev, sizeof(struct links_event)) != sizeof(struct links_event)) break;
2393 }
2394 fd_lock();
2395 mouse_h = -1;
2396 MouClose(*mh);
2397 fd_unlock();
2398 ret:
2399 EINTRLOOP(rs, close(oms->p[1]));
2400 /*free(oms);*/
2401 }
2402
mouse_handle(void * oms_)2403 static void mouse_handle(void *oms_)
2404 {
2405 struct os2_mouse_spec *oms = (struct os2_mouse_spec *)oms_;
2406 int r;
2407 EINTRLOOP(r, (int)read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct links_event) - oms->bufptr));
2408 if (r <= 0) {
2409 unhandle_mouse(oms);
2410 return;
2411 }
2412 if ((oms->bufptr += r) == sizeof(struct links_event)) {
2413 oms->bufptr = 0;
2414 oms->fn(oms->data, oms->buffer, sizeof(struct links_event));
2415 }
2416 }
2417
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)2418 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
2419 {
2420 struct os2_mouse_spec *oms;
2421 if (is_xterm()) return NULL;
2422 /* This is never freed but it's allocated only once */
2423 retry:
2424 if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) {
2425 if (out_of_memory(0, NULL, 0))
2426 goto retry;
2427 return NULL;
2428 }
2429 oms->fn = fn;
2430 oms->data = data;
2431 oms->bufptr = 0;
2432 oms->terminate = 0;
2433 if (c_pipe(oms->p)) {
2434 free(oms);
2435 return NULL;
2436 }
2437 if (_beginthread(mouse_thread, NULL, 0x10000, (void *)oms) == -1) {
2438 }
2439 set_handlers(oms->p[0], mouse_handle, NULL, oms);
2440 return oms;
2441 }
2442
unhandle_mouse(void * om)2443 void unhandle_mouse(void *om)
2444 {
2445 struct os2_mouse_spec *oms = om;
2446 want_draw();
2447 oms->terminate = 1;
2448 close_socket(&oms->p[0]);
2449 done_draw();
2450 }
2451
want_draw(void)2452 void want_draw(void)
2453 {
2454 static int ansi = 0;
2455 fd_lock();
2456 if (!ansi) {
2457 VioSetAnsi(1, 0);
2458 ansi = 1;
2459 }
2460 if (mouse_h != -1) {
2461 mouse_remove_pointer();
2462 }
2463 }
2464
done_draw(void)2465 void done_draw(void)
2466 {
2467 fd_unlock();
2468 }
2469
2470 #endif /* if HAVE_MOUOPEN */
2471
2472 #elif defined(HAVE_PTHREADS)
2473
2474 #ifdef OPENVMS
2475 #define THREAD_NEED_STACK_SIZE 65536
2476 int vms_thread_high_priority = 0;
2477 #endif
2478
2479 #ifndef OPENVMS
2480 static unsigned thread_count = 0;
2481 #endif
2482
reset_thread_count(void)2483 static inline void reset_thread_count(void)
2484 {
2485 #ifndef OPENVMS
2486 fd_lock();
2487 thread_count = 0;
2488 fd_unlock();
2489 #endif
2490 }
2491
inc_thread_count(void)2492 static void inc_thread_count(void)
2493 {
2494 #ifndef OPENVMS
2495 fd_lock();
2496 thread_count++;
2497 fd_unlock();
2498 #endif
2499 }
2500
dec_thread_count(void)2501 static void dec_thread_count(void)
2502 {
2503 #ifndef OPENVMS
2504 fd_lock();
2505 if (!thread_count)
2506 internal_error("thread_count underflow");
2507 thread_count--;
2508 fd_unlock();
2509 #endif
2510 }
2511
get_thread_count(void)2512 static inline unsigned get_thread_count(void)
2513 {
2514 #ifndef OPENVMS
2515 unsigned val;
2516 fd_lock();
2517 val = thread_count;
2518 fd_unlock();
2519 return val;
2520 #else
2521 return 0;
2522 #endif
2523 }
2524
bgpt(void * t)2525 static void *bgpt(void *t)
2526 {
2527 int counted = ((struct tdata *)t)->counted;
2528 bgt(t);
2529 if (counted) dec_thread_count();
2530 return NULL;
2531 }
2532
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2533 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2534 {
2535 pthread_attr_t attr;
2536 pthread_t thread;
2537 struct tdata *t;
2538 int p[2];
2539 int rs;
2540 if (c_pipe(p) < 0) return -1;
2541 retry1:
2542 if (!(t = malloc(sizeof(struct tdata) + l))) {
2543 if (out_of_memory(0, NULL, 0))
2544 goto retry1;
2545 goto err1;
2546 }
2547 t->fn = fn;
2548 t->h = p[1];
2549 t->counted = counted;
2550 memcpy(t->data, ptr, l);
2551 retry2:
2552 if (pthread_attr_init(&attr)) {
2553 if (out_of_memory(0, NULL, 0))
2554 goto retry2;
2555 goto err2;
2556 }
2557 retry3:
2558 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
2559 if (out_of_memory(0, NULL, 0))
2560 goto retry3;
2561 goto err3;
2562 }
2563 #ifdef THREAD_NEED_STACK_SIZE
2564 retry4:
2565 if (pthread_attr_setstacksize(&attr, THREAD_NEED_STACK_SIZE)) {
2566 if (out_of_memory(0, NULL, 0))
2567 goto retry4;
2568 goto err3;
2569 }
2570 #endif
2571 #ifdef OPENVMS
2572 if (vms_thread_high_priority) {
2573 struct sched_param param;
2574 memset(¶m, 0, sizeof param);
2575 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED))
2576 goto err3;
2577 if (vms_thread_high_priority > 0) {
2578 if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO))
2579 goto err3;
2580 param.sched_priority = PRI_FIFO_MIN;
2581 if (pthread_attr_setschedparam(&attr, ¶m))
2582 goto err3;
2583 } else {
2584 if (pthread_attr_setschedpolicy(&attr, SCHED_LFI_NP))
2585 goto err3;
2586 param.sched_priority = PRI_BG_MIN_NP;
2587 if (pthread_attr_setschedparam(&attr, ¶m))
2588 goto err3;
2589 }
2590 }
2591 #endif
2592 if (counted) inc_thread_count();
2593 if (pthread_create(&thread, &attr, bgpt, t)) {
2594 if (counted) dec_thread_count();
2595 goto err3;
2596 }
2597 pthread_attr_destroy(&attr);
2598 return p[0];
2599
2600 err3:
2601 pthread_attr_destroy(&attr);
2602 err2:
2603 free(t);
2604 err1:
2605 EINTRLOOP(rs, close(p[0]));
2606 EINTRLOOP(rs, close(p[1]));
2607 return -1;
2608 }
2609
2610 #elif defined(HAVE_ATHEOS_THREADS_H) && defined(HAVE_SPAWN_THREAD) && defined(HAVE_RESUME_THREAD)
2611
2612 #include <atheos/threads.h>
2613
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2614 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2615 {
2616 int p[2];
2617 int rs;
2618 thread_id f;
2619 struct tdata *t;
2620 if (c_pipe(p) < 0) return -1;
2621 retry:
2622 if (!(t = malloc(sizeof(struct tdata) + l))) {
2623 if (out_of_memory(0, NULL, 0))
2624 goto retry;
2625 goto err1;
2626 }
2627 t->fn = fn;
2628 t->h = p[1];
2629 t->counted = counted;
2630 memcpy(t->data, ptr, l);
2631 if ((f = spawn_thread("links_lookup", bgat, 0, 0, t)) == -1)
2632 goto err2;
2633 resume_thread(f);
2634 return p[0];
2635
2636 err2:
2637 free(t);
2638 err1:
2639 EINTRLOOP(rs, close(p[0]));
2640 EINTRLOOP(rs, close(p[1]));
2641 return -1;
2642 }
2643
2644 #elif defined(DOS)
2645
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2646 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2647 {
2648 int p[2];
2649 int rs;
2650 if (c_pipe(p) < 0) return -1;
2651 fn(ptr, p[1]);
2652 EINTRLOOP(rs, close(p[1]));
2653 return p[0];
2654 }
2655
2656 #else /* HAVE_BEGINTHREAD */
2657
start_thread(void (* fn)(void *,int),void * ptr,int l,int counted)2658 int start_thread(void (*fn)(void *, int), void *ptr, int l, int counted)
2659 {
2660 int p[2];
2661 pid_t f;
2662 int rs;
2663 if (c_pipe(p) < 0) return -1;
2664 EINTRLOOP(f, fork());
2665 if (!f) {
2666 close_fork_tty();
2667 EINTRLOOP(rs, close(p[0]));
2668 fn(ptr, p[1]);
2669 EINTRLOOP(rs, (int)write(p[1], "x", 1));
2670 EINTRLOOP(rs, close(p[1]));
2671 _exit(0);
2672 }
2673 if (f == -1) {
2674 EINTRLOOP(rs, close(p[0]));
2675 EINTRLOOP(rs, close(p[1]));
2676 return -1;
2677 }
2678 EINTRLOOP(rs, close(p[1]));
2679 return p[0];
2680 }
2681
2682 #endif
2683
2684 #if !defined(USING_OS2_MOUSE) && !defined(DOS)
want_draw(void)2685 void want_draw(void) {}
done_draw(void)2686 void done_draw(void) {}
2687 #endif
2688
get_output_handle(void)2689 int get_output_handle(void) { return 1; }
2690
2691 #if defined(OS2)
2692
get_ctl_handle(void)2693 int get_ctl_handle(void) { return get_input_handle(); }
2694
2695 #else
2696
get_ctl_handle(void)2697 int get_ctl_handle(void) { return 0; }
2698
2699 #endif
2700
2701 #if defined(BEOS)
2702
2703 #elif defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD)
2704
get_input_handle(void)2705 int get_input_handle(void)
2706 {
2707 int rs;
2708 int fd[2];
2709 if (ti != -1) return ti;
2710 if (is_xterm()) return 0;
2711 if (c_pipe(fd) < 0) return 0;
2712 ti = fd[0];
2713 tp = fd[1];
2714 if (_beginthread(input_thread, NULL, 0x10000, (void *)tp) == -1) {
2715 EINTRLOOP(rs, close(fd[0]));
2716 EINTRLOOP(rs, close(fd[1]));
2717 return 0;
2718 }
2719 /*
2720 #if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
2721 _beginthread(mouse_thread, NULL, 0x10000, (void *)tp);
2722 #endif
2723 */
2724 return fd[0];
2725 }
2726
2727 #elif !defined(OPENVMS)
2728
get_input_handle(void)2729 int get_input_handle(void)
2730 {
2731 return 0;
2732 }
2733
2734 #endif /* defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD) */
2735
2736
2737 #if defined(__linux__) || defined(__LINUX__)
is_on_linux_console(void)2738 static unsigned char *is_on_linux_console(void)
2739 {
2740 static unsigned char tty_name[MAX_STR_LEN];
2741 int r = readlink("/proc/self/fd/0", cast_char tty_name, sizeof tty_name);
2742 if (r >= 1 && r < (int)sizeof(tty_name)) {
2743 #define pfx1 "/dev/tty"
2744 #define pfx2 "/dev/vc/"
2745 unsigned char c;
2746 tty_name[r] = 0;
2747 if (!memcmp(tty_name, pfx1, strlen(pfx1))) {
2748 c = tty_name[strlen(pfx1)];
2749 if (!(c >= '1' && c <= '9'))
2750 return NULL;
2751 return tty_name;
2752 }
2753 if (!memcmp(tty_name, pfx2, strlen(pfx2))) {
2754 c = tty_name[strlen(pfx2)];
2755 if (!(c >= '1' && c <= '9'))
2756 return NULL;
2757 return tty_name;
2758 }
2759 #undef pfx1
2760 #undef pfx2
2761 }
2762 return NULL;
2763 }
2764 #endif
2765
2766
2767 #if defined(USE_GPM) || defined(GRDRV_FB)
2768
2769 /* GPM installs its own signal handlers and we don't want them */
2770
2771 static sigset_t gpm_sigset;
2772 static unsigned char gpm_sigset_valid;
2773 #ifdef SIGWINCH
2774 static struct sigaction gpm_winch;
2775 static unsigned char gpm_winch_valid;
2776 #endif
2777 #ifdef SIGTSTP
2778 static struct sigaction gpm_tstp;
2779 static unsigned char gpm_tstp_valid;
2780 #endif
2781
save_gpm_signals(void)2782 void save_gpm_signals(void)
2783 {
2784 sigset_t sig;
2785 int rs;
2786 sigemptyset(&sig);
2787 #ifdef SIGWINCH
2788 sigaddset(&sig, SIGWINCH);
2789 #endif
2790 #ifdef SIGTSTP
2791 sigaddset(&sig, SIGTSTP);
2792 #endif
2793 EINTRLOOP(rs, do_sigprocmask(SIG_BLOCK, &sig, &gpm_sigset));
2794 gpm_sigset_valid = !rs;
2795 #ifdef SIGWINCH
2796 EINTRLOOP(rs, sigaction(SIGWINCH, NULL, &gpm_winch));
2797 gpm_winch_valid = !rs;
2798 #endif
2799 #ifdef SIGTSTP
2800 EINTRLOOP(rs, sigaction(SIGTSTP, NULL, &gpm_tstp));
2801 gpm_tstp_valid = !rs;
2802 #endif
2803 }
2804
restore_gpm_signals(void)2805 void restore_gpm_signals(void)
2806 {
2807 int rs;
2808 #ifdef SIGWINCH
2809 if (gpm_winch_valid)
2810 EINTRLOOP(rs, sigaction(SIGWINCH, &gpm_winch, NULL));
2811 #endif
2812 #ifdef SIGTSTP
2813 if (gpm_tstp_valid)
2814 EINTRLOOP(rs, sigaction(SIGTSTP, &gpm_tstp, NULL));
2815 #endif
2816 if (gpm_sigset_valid)
2817 EINTRLOOP(rs, do_sigprocmask(SIG_SETMASK, &gpm_sigset, NULL));
2818 }
2819
2820 #endif
2821
2822 #ifdef USE_GPM
2823
2824 struct gpm_mouse_spec {
2825 int h;
2826 void (*fn)(void *, unsigned char *, int);
2827 void *data;
2828 };
2829
gpm_mouse_in(void * gms_)2830 static void gpm_mouse_in(void *gms_)
2831 {
2832 struct gpm_mouse_spec *gms = (struct gpm_mouse_spec *)gms_;
2833 int g;
2834 Gpm_Event gev;
2835 struct links_event ev;
2836 set_handlers(gms->h, NULL, NULL, NULL);
2837 save_gpm_signals();
2838 g = Gpm_GetEvent(&gev);
2839 restore_gpm_signals();
2840 if (g <= 0) {
2841 gms->h = -1;
2842 return;
2843 }
2844 set_handlers(gms->h, gpm_mouse_in, NULL, gms);
2845 ev.ev = EV_MOUSE;
2846 ev.x = gev.x - 1;
2847 ev.y = gev.y - 1;
2848 if (ev.x < 0) ev.x = 0;
2849 if (ev.y < 0) ev.y = 0;
2850 if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT;
2851 else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE;
2852 else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT;
2853 #ifdef GPM_B_FOURTH
2854 else if (gev.buttons & GPM_B_FOURTH) ev.b = B_FOURTH;
2855 #endif
2856 #ifdef GPM_B_UP
2857 else if (gev.buttons & GPM_B_UP) ev.b = B_FIFTH;
2858 #endif
2859 #ifdef GPM_B_DOWN
2860 else if (gev.buttons & GPM_B_DOWN) ev.b = B_SIXTH;
2861 #endif
2862 else return;
2863 if ((int)gev.type & GPM_DOWN) ev.b |= B_DOWN;
2864 else if ((int)gev.type & GPM_UP) ev.b |= B_UP;
2865 else if ((int)gev.type & GPM_DRAG) ev.b |= B_DRAG;
2866 else return;
2867 gms->fn(gms->data, (unsigned char *)&ev, sizeof(struct links_event));
2868 }
2869
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)2870 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
2871 {
2872 int h;
2873 Gpm_Connect conn;
2874 struct gpm_mouse_spec *gms;
2875
2876 #if defined(__linux__) || defined(__LINUX__)
2877 if (!is_on_linux_console())
2878 return NULL;
2879 #endif
2880
2881 conn.eventMask = (unsigned short)~(unsigned)GPM_MOVE;
2882 conn.defaultMask = GPM_MOVE;
2883 conn.minMod = 0;
2884 conn.maxMod = 0;
2885 save_gpm_signals();
2886 h = Gpm_Open(&conn, cons);
2887 restore_gpm_signals();
2888 if (h < 0) return NULL;
2889 gms = mem_alloc(sizeof(struct gpm_mouse_spec));
2890 gms->h = h;
2891 gms->fn = fn;
2892 gms->data = data;
2893 set_handlers(h, gpm_mouse_in, NULL, gms);
2894 return gms;
2895 }
2896
unhandle_mouse(void * h)2897 void unhandle_mouse(void *h)
2898 {
2899 struct gpm_mouse_spec *gms = h;
2900 if (gms->h != -1) set_handlers(gms->h, NULL, NULL, NULL);
2901 save_gpm_signals();
2902 Gpm_Close();
2903 restore_gpm_signals();
2904 mem_free(gms);
2905 }
2906
add_gpm_version(unsigned char ** s,int * l)2907 void add_gpm_version(unsigned char **s, int *l)
2908 {
2909 add_to_str(s, l, cast_uchar "GPM");
2910 #ifdef HAVE_GPM_GETLIBVERSION
2911 add_to_str(s, l, cast_uchar " (");
2912 add_to_str(s, l, cast_uchar Gpm_GetLibVersion(NULL));
2913 add_chr_to_str(s, l, ')');
2914 #endif
2915 }
2916
2917 #elif !defined(USING_OS2_MOUSE) && !defined(DOS)
2918
handle_mouse(int cons,void (* fn)(void *,unsigned char *,int),void * data)2919 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) { return NULL; }
unhandle_mouse(void * data)2920 void unhandle_mouse(void *data) { }
2921
2922 #endif /* #ifdef USE_GPM */
2923
2924
2925 #if defined(WIN) || defined(INTERIX)
2926
is_remote_connection(void)2927 static int is_remote_connection(void)
2928 {
2929 return !!getenv("SSH_CONNECTION");
2930 }
2931
2932 #endif
2933
2934
2935 #if defined(OS2)
2936
get_system_env(void)2937 int get_system_env(void)
2938 {
2939 if (is_xterm()) return 0;
2940 return ENV_OS2VIO; /* !!! FIXME: telnet */
2941 }
2942
2943 #elif defined(BEOS)
2944
get_system_env(void)2945 int get_system_env(void)
2946 {
2947 unsigned char *term = cast_uchar getenv("TERM");
2948 if (!term || (upcase(term[0]) == 'B' && upcase(term[1]) == 'E')) return ENV_BE;
2949 return 0;
2950 }
2951
2952 #elif defined(HAIKU)
2953
get_system_env(void)2954 int get_system_env(void)
2955 {
2956 if (!getenv("SSH_CONNECTION")) return ENV_BE;
2957 return 0;
2958 }
2959
2960 #elif defined(WIN)
2961
get_system_env(void)2962 int get_system_env(void)
2963 {
2964 if (is_xterm()) return 0;
2965 if (is_remote_connection()) return 0;
2966 return ENV_WIN32;
2967 }
2968
2969 #elif defined(INTERIX)
2970
2971 #define INTERIX_START_COMMAND "/usr/contrib/win32/bin/start"
2972
get_system_env(void)2973 int get_system_env(void)
2974 {
2975 if (is_xterm()) return 0;
2976 if (is_remote_connection()) return 0;
2977 if (!access(INTERIX_START_COMMAND, X_OK)) return ENV_INTERIX;
2978 return 0;
2979 }
2980
2981 #else
2982
get_system_env(void)2983 int get_system_env(void)
2984 {
2985 return 0;
2986 }
2987
2988 #endif
2989
exec_new_links(struct terminal * term,unsigned char * xterm,unsigned char * exe,unsigned char * param)2990 static void exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe, unsigned char *param)
2991 {
2992 unsigned char *str;
2993 str = stracpy(cast_uchar "");
2994 if (*xterm) {
2995 add_to_strn(&str, xterm);
2996 add_to_strn(&str, cast_uchar " ");
2997 }
2998 add_to_strn(&str, exe);
2999 add_to_strn(&str, cast_uchar " ");
3000 add_to_strn(&str, param);
3001 exec_on_terminal(term, str, cast_uchar "", 2);
3002 mem_free(str);
3003 }
3004
open_in_new_twterm(struct terminal * term,unsigned char * exe,unsigned char * param)3005 static int open_in_new_twterm(struct terminal *term, unsigned char *exe, unsigned char *param)
3006 {
3007 unsigned char *twterm;
3008 if (!(twterm = cast_uchar getenv("LINKS_TWTERM"))) twterm = cast_uchar "twterm -e";
3009 exec_new_links(term, twterm, exe, param);
3010 return 0;
3011 }
3012
links_xterm(void)3013 unsigned char *links_xterm(void)
3014 {
3015 unsigned char *xterm;
3016 if (!(xterm = cast_uchar getenv("LINKS_XTERM"))) {
3017 #ifdef OPENVMS
3018 xterm = cast_uchar "CREATE /TERMINAL /WAIT";
3019 #elif defined(HAIKU)
3020 xterm = cast_uchar "Terminal";
3021 #else
3022 xterm = cast_uchar "xterm -e";
3023 #endif
3024 }
3025 return xterm;
3026 }
3027
open_in_new_xterm(struct terminal * term,unsigned char * exe,unsigned char * param)3028 static int open_in_new_xterm(struct terminal *term, unsigned char *exe, unsigned char *param)
3029 {
3030 exec_new_links(term, links_xterm(), exe, param);
3031 return 0;
3032 }
3033
open_in_new_screen(struct terminal * term,unsigned char * exe,unsigned char * param)3034 static int open_in_new_screen(struct terminal *term, unsigned char *exe, unsigned char *param)
3035 {
3036 exec_new_links(term, cast_uchar "screen", exe, param);
3037 return 0;
3038 }
3039
3040 #ifdef OS2
open_in_new_vio(struct terminal * term,unsigned char * exe,unsigned char * param)3041 static int open_in_new_vio(struct terminal *term, unsigned char *exe, unsigned char *param)
3042 {
3043 unsigned char *x = stracpy(cast_uchar "\"");
3044 add_to_strn(&x, exe);
3045 add_to_strn(&x, cast_uchar "\"");
3046 exec_new_links(term, cast_uchar "start \"Links\" /c /f /win", x, param);
3047 mem_free(x);
3048 return 0;
3049 }
3050
open_in_new_fullscreen(struct terminal * term,unsigned char * exe,unsigned char * param)3051 static int open_in_new_fullscreen(struct terminal *term, unsigned char *exe, unsigned char *param)
3052 {
3053 unsigned char *x = stracpy(cast_uchar "\"");
3054 add_to_strn(&x, exe);
3055 add_to_strn(&x, cast_uchar "\"");
3056 exec_new_links(term, cast_uchar "start \"Links\" /c /f /fs", x, param);
3057 mem_free(x);
3058 return 0;
3059 }
3060 #endif
3061
3062 #ifdef WIN
open_in_new_win32(struct terminal * term,unsigned char * exe,unsigned char * param)3063 static int open_in_new_win32(struct terminal *term, unsigned char *exe, unsigned char *param)
3064 {
3065 exec_new_links(term, cast_uchar "", exe, param);
3066 return 0;
3067 }
3068 #endif
3069
3070 #ifdef INTERIX
open_in_new_interix(struct terminal * term,unsigned char * exe,unsigned char * param)3071 static int open_in_new_interix(struct terminal *term, unsigned char *exe, unsigned char *param)
3072 {
3073 unsigned char *param_x = stracpy(param);
3074 add_to_strn(¶m_x, cast_uchar "'");
3075 exec_new_links(term, cast_uchar(INTERIX_START_COMMAND " '\"Links\"' posix /u /c /bin/sh -c '"), exe, param_x);
3076 mem_free(param_x);
3077 return 0;
3078 }
3079 #endif
3080
3081 #if defined(BEOS) || defined(HAIKU)
open_in_new_be(struct terminal * term,unsigned char * exe,unsigned char * param)3082 static int open_in_new_be(struct terminal *term, unsigned char *exe, unsigned char *param)
3083 {
3084 exec_new_links(term, cast_uchar "Terminal", exe, param);
3085 return 0;
3086 }
3087 #endif
3088
3089 #ifdef G
open_in_new_g(struct terminal * term,unsigned char * exe,unsigned char * param)3090 static int open_in_new_g(struct terminal *term, unsigned char *exe, unsigned char *param)
3091 {
3092 void *info;
3093 unsigned char *target = NULL;
3094 int len;
3095 int base = 0;
3096 unsigned char *url;
3097 if (!cmpbeg(param, cast_uchar "-base-session ")) {
3098 param = cast_uchar strchr(cast_const_char param, ' ') + 1;
3099 base = atoi(cast_const_char param);
3100 param += strcspn(cast_const_char param, " ");
3101 if (*param == ' ') param++;
3102 }
3103 if (!cmpbeg(param, cast_uchar "-target ")) {
3104 param = cast_uchar strchr(cast_const_char param, ' ') + 1;
3105 target = param;
3106 param += strcspn(cast_const_char param, " ");
3107 if (*param == ' ') *param++ = 0;
3108 }
3109 url = param;
3110 info = create_session_info(base, url, target, &len);
3111 return attach_g_terminal(term->cwd, info, len);
3112 }
3113 #endif
3114
3115 static const struct {
3116 int env;
3117 int (*open_window_fn)(struct terminal *term, unsigned char *, unsigned char *);
3118 unsigned char *text;
3119 unsigned char *hk;
3120 } oinw[] = {
3121 {ENV_XWIN, open_in_new_xterm, TEXT_(T_XTERM), TEXT_(T_HK_XTERM)},
3122 {ENV_TWIN, open_in_new_twterm, TEXT_(T_TWTERM), TEXT_(T_HK_TWTERM)},
3123 {ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN)},
3124 #ifdef OS2
3125 {ENV_OS2VIO, open_in_new_vio, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
3126 {ENV_OS2VIO, open_in_new_fullscreen, TEXT_(T_FULL_SCREEN), TEXT_(T_HK_FULL_SCREEN)},
3127 #endif
3128 #ifdef WIN
3129 {ENV_WIN32, open_in_new_win32, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
3130 #endif
3131 #ifdef INTERIX
3132 {ENV_INTERIX, open_in_new_interix, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
3133 #endif
3134 #if defined(BEOS) || defined(HAIKU)
3135 {ENV_BE, open_in_new_be, TEXT_(T_BEOS_TERMINAL), TEXT_(T_HK_BEOS_TERMINAL)},
3136 #endif
3137 #ifdef G
3138 {ENV_G, open_in_new_g, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
3139 #endif
3140 };
3141
get_open_in_new(int environment)3142 struct open_in_new *get_open_in_new(int environment)
3143 {
3144 int i;
3145 struct open_in_new *oin = DUMMY;
3146 int noin = 0;
3147 if (anonymous) return NULL;
3148 if (environment & ENV_G) environment = ENV_G;
3149 for (i = 0; i < (int)array_elements(oinw); i++) if ((environment & oinw[i].env) == oinw[i].env) {
3150 if ((unsigned)noin > MAXINT / sizeof(struct open_in_new) - 2) overalloc();
3151 oin = mem_realloc(oin, (noin + 2) * sizeof(struct open_in_new));
3152 oin[noin].text = oinw[i].text;
3153 oin[noin].hk = oinw[i].hk;
3154 oin[noin].open_window_fn = &oinw[i].open_window_fn;
3155 noin++;
3156 oin[noin].text = NULL;
3157 oin[noin].hk = NULL;
3158 oin[noin].open_window_fn = NULL;
3159 }
3160 if (oin == DUMMY) return NULL;
3161 return oin;
3162 }
3163
can_resize_window(struct terminal * term)3164 int can_resize_window(struct terminal *term)
3165 {
3166 #if defined(OS2) || defined(WIN)
3167 if (!strncmp(cast_const_char term->term, "xterm", 5)) return 0;
3168 if (term->environment & (ENV_OS2VIO | ENV_WIN32)) return 1;
3169 #endif
3170 return 0;
3171 }
3172
can_open_os_shell(int environment)3173 int can_open_os_shell(int environment)
3174 {
3175 #ifdef OS2
3176 if (environment & ENV_XWIN) return 0;
3177 #endif
3178 #ifdef WIN
3179 if (!F && !(environment & ENV_WIN32)) return 0;
3180 #endif
3181 #ifdef BEOS
3182 if (!(environment & ENV_BE)) return 0;
3183 #endif
3184 #ifdef G
3185 if (F && drv->flags & GD_NO_OS_SHELL) return 0;
3186 #endif
3187 return 1;
3188 }
3189
set_highpri(void)3190 void set_highpri(void)
3191 {
3192 #ifdef OS2
3193 DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0);
3194 #endif
3195 }
3196
3197 #if !defined(DOS) && !defined(OPENVMS)
os_seed_random(unsigned char ** pool,int * pool_size)3198 void os_seed_random(unsigned char **pool, int *pool_size)
3199 {
3200 *pool = DUMMY;
3201 *pool_size = 0;
3202 }
3203 #endif
3204
3205 #if defined(WIN)
os_send_fg_cookie(int h)3206 int os_send_fg_cookie(int h)
3207 {
3208 DWORD pid;
3209 pid = GetCurrentProcessId();
3210 if (hard_write(h, (unsigned char *)&pid, sizeof pid) != sizeof pid)
3211 return -1;
3212 return 0;
3213 }
os_receive_fg_cookie(int h)3214 int os_receive_fg_cookie(int h)
3215 {
3216 DWORD pid;
3217 BOOL (WINAPI *fn_AllowSetForegroundWindow)(DWORD);
3218 if (hard_read(h, (unsigned char *)&pid, sizeof pid) != sizeof pid)
3219 return -1;
3220 fn_AllowSetForegroundWindow = (BOOL (WINAPI *)(DWORD))(void *)GetProcAddress(GetModuleHandleA("user32.dll"), "AllowSetForegroundWindow");
3221 if (fn_AllowSetForegroundWindow)
3222 fn_AllowSetForegroundWindow(pid);
3223 return 0;
3224 }
3225 #else
os_send_fg_cookie(int h)3226 int os_send_fg_cookie(int h)
3227 {
3228 return 0;
3229 }
os_receive_fg_cookie(int h)3230 int os_receive_fg_cookie(int h)
3231 {
3232 return 0;
3233 }
3234 #endif
3235
3236 int need_detach_console = 0;
3237
os_detach_console(void)3238 void os_detach_console(void)
3239 {
3240 #if defined(WIN)
3241 if (is_winnt())
3242 FreeConsole();
3243 #endif
3244 #if !defined(NO_FORK_ON_EXIT)
3245 {
3246 pid_t rp;
3247 /* Intel and PathScale handle fork gracefully */
3248 #if !defined(__ICC) && !defined(__PATHSCALE__)
3249 disable_openmp = 1;
3250 #endif
3251 EINTRLOOP(rp, fork());
3252 if (!rp) {
3253 reinit_child();
3254 #if defined(HAVE_PTHREADS)
3255 reset_thread_count();
3256 #endif
3257 }
3258 if (rp > 0) {
3259 #if defined(HAVE_PTHREADS)
3260 while (get_thread_count()) {
3261 portable_sleep(1000);
3262 }
3263 #endif
3264 _exit(0);
3265 }
3266 }
3267 #endif
3268 }
3269
3270 #if defined(OS2) || defined(DOS)
3271
get_country_language(int c)3272 int get_country_language(int c)
3273 {
3274 static_const struct {
3275 int code;
3276 unsigned char *language;
3277 } countries[] = {
3278 { 1, cast_uchar "English" },
3279 { 2, cast_uchar "French" },
3280 { 3, cast_uchar "Spanish" },
3281 { 4, cast_uchar "English" },
3282 { 7, cast_uchar "Russian" },
3283 { 27, cast_uchar "English" },
3284 { 30, cast_uchar "Greek" },
3285 { 31, cast_uchar "Dutch" },
3286 { 32, cast_uchar "Dutch" },
3287 { 33, cast_uchar "French" },
3288 { 34, cast_uchar "Spanish" },
3289 { 36, cast_uchar "Hungarian" },
3290 { 38, cast_uchar "Serbian" },
3291 { 39, cast_uchar "Italian" },
3292 { 40, cast_uchar "Romanian" },
3293 { 41, cast_uchar "Swiss German" },
3294 { 42, cast_uchar "Czech" },
3295 { 43, cast_uchar "German" },
3296 { 44, cast_uchar "English" },
3297 { 45, cast_uchar "Danish" },
3298 { 46, cast_uchar "Swedish" },
3299 { 47, cast_uchar "Norwegian" },
3300 { 48, cast_uchar "Polish" },
3301 { 49, cast_uchar "German" },
3302 { 52, cast_uchar "Spanish" },
3303 { 54, cast_uchar "Spanish" },
3304 { 55, cast_uchar "Brazilian Portuguese" },
3305 { 56, cast_uchar "Spanish" },
3306 { 57, cast_uchar "Spanish" },
3307 { 58, cast_uchar "Spanish" },
3308 { 61, cast_uchar "English" },
3309 { 64, cast_uchar "English" },
3310 { 65, cast_uchar "English" },
3311 { 90, cast_uchar "Turkish" },
3312 { 99, cast_uchar "English" },
3313 { 351, cast_uchar "Portuguese" },
3314 { 353, cast_uchar "English" },
3315 { 354, cast_uchar "Icelandic" },
3316 { 358, cast_uchar "Finnish" },
3317 { 359, cast_uchar "Bulgarian" },
3318 { 371, cast_uchar "Lithuanian" },
3319 { 372, cast_uchar "Estonian" },
3320 { 381, cast_uchar "Serbian" },
3321 { 384, cast_uchar "Croatian" },
3322 { 385, cast_uchar "Croatian" },
3323 #ifdef DOS
3324 { 421, cast_uchar "Slovak" },
3325 #else
3326 { 421, cast_uchar "Czech" },
3327 #endif
3328 { 422, cast_uchar "Slovak" },
3329 { 593, cast_uchar "Spanish" },
3330 };
3331 int idx, i;
3332 #define C_EQUAL(a, b) countries[a].code == (b)
3333 #define C_ABOVE(a, b) countries[a].code > (b)
3334 BIN_SEARCH(array_elements(countries), C_EQUAL, C_ABOVE, c, idx);
3335 if (idx == -1)
3336 return -1;
3337 for (i = 0; i < n_languages(); i++)
3338 if (!casestrcmp(language_name(i), countries[idx].language))
3339 return i;
3340 return -1;
3341 }
3342
3343 #endif
3344
3345 #if defined(OS2)
3346
os_default_language(void)3347 int os_default_language(void)
3348 {
3349 COUNTRYCODE cc;
3350 COUNTRYINFO ci;
3351 ULONG ul;
3352 int rc;
3353 memset(&cc, 0, sizeof cc);
3354 rc = DosQueryCtryInfo(sizeof ci, &cc, &ci, &ul);
3355 if (!rc)
3356 return get_country_language(ci.country);
3357 return -1;
3358 }
3359
3360 #elif defined(WIN)
3361
os_default_language(void)3362 int os_default_language(void)
3363 {
3364 LCID id;
3365 unsigned char iso639[9];
3366 unsigned char iso3166[9];
3367 unsigned char loc[8 + 1 + 8 + 1];
3368 unsigned char *lang;
3369 lang = cast_uchar getenv("LANG");
3370 if (lang) {
3371 int l = get_language_from_lang(lang);
3372 if (l >= 0)
3373 return l;
3374 }
3375 id = GetUserDefaultUILanguage();
3376 if (!GetLocaleInfoA(id, LOCALE_SISO639LANGNAME, cast_char iso639, 9))
3377 return -1;
3378 iso3166[0] = 0;
3379 GetLocaleInfoA(id, LOCALE_SISO3166CTRYNAME, cast_char iso3166, 9);
3380 strcpy(cast_char loc, cast_const_char iso639);
3381 if (id >= 0x400 && iso3166[0]) {
3382 strcat(cast_char loc, "_");
3383 strcat(cast_char loc, cast_const_char iso3166);
3384 }
3385 return get_language_from_lang(loc);
3386 }
3387
3388 #elif !defined(DOS)
3389
os_default_language(void)3390 int os_default_language(void)
3391 {
3392 return -1;
3393 }
3394
3395 #endif
3396
3397 #if defined(WIN) && defined(__CYGWIN__) && defined(HAVE_CYGWIN_CONV_PATH)
3398
os_default_charset(void)3399 int os_default_charset(void)
3400 {
3401 unsigned char *term = cast_uchar getenv("TERM");
3402 if (term) {
3403 if (!casestrcmp(term, cast_uchar "cygwin")) {
3404 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_LANGINFO_H) && defined(CODESET)
3405 return windows_charset();
3406 #endif
3407 }
3408 if (!casestrcmp(term, cast_uchar "xterm")) {
3409 return utf8_table;
3410 }
3411 }
3412 return -1;
3413 }
3414
3415 #elif defined(OS2)
3416
os_default_charset(void)3417 int os_default_charset(void)
3418 {
3419 ULONG os2_cp[1];
3420 ULONG size = 0;
3421 int rc;
3422
3423 if (is_xterm())
3424 return 0;
3425
3426 rc = DosQueryCp(sizeof(os2_cp), os2_cp, &size);
3427 if ((!rc || rc == ERROR_CPLIST_TOO_SMALL) && size >= sizeof(ULONG)) {
3428 unsigned char a[8];
3429 int cp;
3430 snprintf(cast_char a, sizeof a, "%lu", os2_cp[0]);
3431 if ((cp = get_cp_index(a)) >= 0 && cp != utf8_table)
3432 return cp;
3433 }
3434 return 0;
3435 }
3436
3437 #elif !defined(DOS)
3438
os_default_charset(void)3439 int os_default_charset(void)
3440 {
3441 return -1;
3442 }
3443
3444 #endif
3445
3446
3447 #if defined(__linux__) || defined(__LINUX__)
3448
3449 static pid_t cons_pid = -1;
3450
3451 static int cons_x = -1, cons_y = -1;
3452
abort_save(void)3453 static void abort_save(void)
3454 {
3455 if (cons_pid > 0)
3456 kill(cons_pid, SIGKILL);
3457 cons_pid = -1;
3458 close_socket(&cons_control[0]);
3459 close_socket(&cons_control[1]);
3460 close_socket(&cons_status[0]);
3461 close_socket(&cons_status[1]);
3462 }
3463
3464 static const char * const cons_savers[] = {
3465 "/usr/lib/mc/cons.saver",
3466 "/usr/libexec/mc/cons.saver",
3467 };
3468
save_terminal(void)3469 void save_terminal(void)
3470 {
3471 int rs;
3472 int p;
3473 unsigned char *cons;
3474 unsigned char st;
3475
3476 if (!(cons = is_on_linux_console()))
3477 return;
3478
3479 for (p = 0; p < (int)array_elements(cons_savers); p++) {
3480 EINTRLOOP(rs, access(cons_savers[p], X_OK));
3481 if (!rs)
3482 goto ok;
3483 }
3484 return;
3485 ok:
3486
3487 c_pipe(cons_control);
3488 c_pipe(cons_status);
3489
3490 block_signals(SIGTERM, 0);
3491
3492 cons_pid = fork();
3493 if (!cons_pid) {
3494 EINTRLOOP(rs, dup2(cons_control[0], 0));
3495 if (rs < 0) _exit(1);
3496 EINTRLOOP(rs, dup2(cons_status[1], 1));
3497 if (rs < 0) _exit(1);
3498 close_fork_tty();
3499
3500 execl(cons_savers[p], cons_savers[p], cast_const_char cons, NULL);
3501 _exit(1);
3502 }
3503 if (cons_pid < 0) {
3504 abort_save();
3505 goto ret;
3506 }
3507 close_socket(&cons_control[0]);
3508 close_socket(&cons_status[1]);
3509
3510 if (hard_read(cons_status[0], &st, 1) != 1 || st != 3) {
3511 abort_save();
3512 goto ret;
3513 }
3514
3515 if (hard_write(cons_control[1], cast_uchar "1", 1) != 1) {
3516 abort_save();
3517 goto ret;
3518 }
3519 if (hard_read(cons_status[0], &st, 1) != 1 || st != 3) {
3520 abort_save();
3521 goto ret;
3522 }
3523
3524 if (hard_write(cons_control[1], cast_uchar "3", 1) != 1) {
3525 abort_save();
3526 goto ret;
3527 }
3528 if (hard_read(cons_status[0], &st, 1) != 1 || st != 3) {
3529 abort_save();
3530 goto ret;
3531 }
3532
3533 get_terminal_size(&cons_x, &cons_y);
3534
3535 ret:
3536 unblock_signals();
3537 }
3538
restore_terminal(void)3539 void restore_terminal(void)
3540 {
3541 if (cons_pid > 0) {
3542 int cx, cy;
3543 unsigned char st;
3544
3545 get_terminal_size(&cx, &cy);
3546 if (cons_x == cx && cons_y == cy) {
3547 if (hard_write(cons_control[1], cast_uchar "4", 1) != 1) {
3548 abort_save();
3549 return;
3550 }
3551 if (hard_read(cons_status[0], &st, 1) != 1 || st != 3) {
3552 abort_save();
3553 return;
3554 }
3555 }
3556 if (hard_write(cons_control[1], cast_uchar "2", 1) != 1) {
3557 abort_save();
3558 return;
3559 }
3560 cons_pid = -1;
3561 close_socket(&cons_control[1]);
3562 close_socket(&cons_status[0]);
3563 }
3564 }
3565
3566 #elif defined(OS2)
3567
3568 static int saved_x, saved_y;
3569 static USHORT saved_len;
3570 static unsigned char *saved_buffer;
3571 static USHORT cursor_x, cursor_y;
3572
save_terminal(void)3573 void save_terminal(void)
3574 {
3575 size_t len;
3576 if (is_xterm())
3577 return;
3578 get_terminal_size(&saved_x, &saved_y);
3579 len = saved_x * saved_y * 4;
3580 saved_len = len;
3581 if (len != saved_len)
3582 return;
3583 saved_buffer = _tmalloc(saved_len);
3584 if (!saved_buffer)
3585 return;
3586 if (VioReadCellStr(saved_buffer, &saved_len, 0, 0, 0))
3587 goto x;
3588 if (VioGetCurPos(&cursor_y, &cursor_x, 0))
3589 goto x;
3590 return;
3591 x:
3592 _tfree(saved_buffer);
3593 saved_buffer = NULL;
3594 }
3595
restore_terminal(void)3596 void restore_terminal(void)
3597 {
3598 int x, y;
3599 if (is_xterm())
3600 return;
3601 if (!saved_buffer)
3602 return;
3603 get_terminal_size(&x, &y);
3604 if (x != saved_x || y != saved_y)
3605 goto x;
3606 VioWrtCellStr(saved_buffer, saved_len, 0, 0, 0);
3607 VioSetCurPos(cursor_y, cursor_x, 0);
3608 x:
3609 _tfree(saved_buffer);
3610 saved_buffer = NULL;
3611 }
3612
3613 #elif defined(DOS)
3614
3615 #else
3616
save_terminal(void)3617 void save_terminal(void)
3618 {
3619 }
3620
restore_terminal(void)3621 void restore_terminal(void)
3622 {
3623 }
3624
3625 #endif
3626
os_report_error_va(const char * caption,const char * msg,va_list l)3627 void os_report_error_va(const char *caption, const char *msg, va_list l)
3628 {
3629 #ifdef OS2
3630 char msg_buffer[OS_REPORT_ERROR_BUFFER];
3631 vsnprintf(msg_buffer, sizeof msg_buffer, msg, l);
3632 if (os2_init_pm()) return;
3633 WinMessageBox(HWND_DESKTOP, NULLHANDLE, msg_buffer, caption, 0, MB_CANCEL | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
3634 os2_exit_pm();
3635 #endif
3636 #if defined(WIN) && !(defined(_UWIN) && !defined(GRDRV_PMSHELL))
3637 char msg_buffer[OS_REPORT_ERROR_BUFFER];
3638 vsnprintf(msg_buffer, sizeof msg_buffer, msg, l);
3639 MessageBoxA(NULL, msg_buffer, caption, MB_OK | MB_ICONEXCLAMATION);
3640 #endif
3641 }
3642
os_report_error(const char * caption,const char * msg,...)3643 void os_report_error(const char *caption, const char *msg, ...)
3644 {
3645 va_list l;
3646 va_start(l, msg);
3647 os_report_error_va(caption, msg, l);
3648 va_end(l);
3649 }
3650