iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / osdep / os2 / os2.c
blob6477bb46e2600b81bfe1ef2b817d3f7ba55f7cfb
1 /* OS/2 support fo ELinks. It has pretty different life than rest of ELinks. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "osdep/system.h"
9 #ifdef X2
10 /* from xf86sup - XFree86 OS/2 support driver */
11 #include <pty.h>
12 #endif
14 #include <errno.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
19 #include "elinks.h"
21 #include "osdep/os2/os2.h"
22 #include "osdep/osdep.h"
23 #include "terminal/mouse.h"
24 #include "terminal/terminal.h"
25 #include "util/conv.h"
28 #define INCL_MOU
29 #define INCL_VIO
30 #define INCL_DOSPROCESS
31 #define INCL_DOSERRORS
32 #define INCL_WINCLIPBOARD
33 #define INCL_WINSWITCHLIST
34 #include <os2.h>
35 #include <io.h>
36 #include <process.h>
37 #include <sys/video.h>
38 #ifdef HAVE_SYS_FMUTEX_H
39 #include <sys/builtin.h>
40 #include <sys/fmutex.h>
41 #endif
44 #define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2
46 int
47 is_xterm(void)
49 static int xt = -1;
51 if (xt == -1) xt = !!getenv("WINDOWID");
53 return xt;
56 int winch_pipe[2];
57 int winch_thread_running = 0;
59 #define WINCH_SLEEPTIME 500 /* time in ms for winch thread to sleep */
61 static void
62 winch_thread(void)
64 /* A thread which regularly checks whether the size of
65 window has changed. Then raise SIGWINCH or notifiy
66 the thread responsible to handle this. */
67 static int old_xsize, old_ysize;
68 static int cur_xsize, cur_ysize;
70 signal(SIGPIPE, SIG_IGN);
71 if (get_terminal_size(0, &old_xsize, &old_ysize)) return;
72 while (1) {
73 if (get_terminal_size(0, &cur_xsize, &cur_ysize)) return;
74 if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
75 old_xsize = cur_xsize;
76 old_ysize = cur_ysize;
77 write(winch_pipe[1], "x", 1);
78 /* Resizing may take some time. So don't send a flood
79 * of requests?! */
80 _sleep2(2 * WINCH_SLEEPTIME);
81 } else {
82 _sleep2(WINCH_SLEEPTIME);
87 static void
88 winch(void *s)
90 unsigned char c;
92 while (can_read(winch_pipe[0]) && safe_read(winch_pipe[0], &c, 1) == 1);
93 ((void (*)()) s)();
96 void
97 handle_terminal_resize(int fd, void (*fn)())
99 if (!is_xterm()) return;
100 if (!winch_thread_running) {
101 if (c_pipe(winch_pipe) < 0) return;
102 winch_thread_running = 1;
103 _beginthread((void (*)(void *)) winch_thread, NULL, 0x32000, NULL);
105 set_handlers(winch_pipe[0], winch, NULL, NULL, fn);
108 void
109 unhandle_terminal_resize(int fd)
111 clear_handlers(winch_pipe[0]);
114 void
115 get_terminal_size(int fd, int *x, int *y)
117 if (is_xterm()) {
118 #ifdef X2
119 /* int fd; */
120 int arc;
121 struct winsize win;
123 /* fd = STDIN_FILENO; */
124 arc = ptioctl(1, TIOCGWINSZ, &win);
125 if (arc) {
127 DBG("%d", errno);
129 *x = DEFAULT_TERMINAL_WIDTH;
130 *y = DEFAULT_TERMINAL_HEIGHT;
131 return 0;
133 *y = win.ws_row;
134 *x = win.ws_col;
136 DBG("%d %d", *x, *y);
139 #else
140 *x = DEFAULT_TERMINAL_WIDTH;
141 *y = DEFAULT_TERMINAL_HEIGHT;
142 #endif
143 } else {
144 int a[2] = {0, 0};
146 _scrsize(a);
147 *x = a[0];
148 *y = a[1];
149 if (!*x) {
150 *x = get_e("COLUMNS");
151 if (!*x) *x = DEFAULT_TERMINAL_WIDTH;
153 if (!*y) {
154 *y = get_e("LINES");
155 if (!*y) *y = DEFAULT_TERMINAL_HEIGHT;
162 exe(unsigned char *path)
164 int flags = P_SESSION;
165 int pid;
166 int ret = -1;
167 unsigned char *shell = get_shell();
169 if (is_xterm()) flags |= P_BACKGROUND;
171 pid = spawnlp(flags, shell, shell, "/c", path, (char *) NULL);
172 if (pid != -1)
173 waitpid(pid, &ret, 0);
175 return ret;
178 unsigned char *
179 get_clipboard_text(void)
181 PTIB tib;
182 PPIB pib;
183 HAB hab;
184 HMQ hmq;
185 ULONG oldType;
186 unsigned char *ret = 0;
188 DosGetInfoBlocks(&tib, &pib);
190 oldType = pib->pib_ultype;
192 pib->pib_ultype = 3;
194 hab = WinInitialize(0);
195 if (hab != NULLHANDLE) {
196 hmq = WinCreateMsgQueue(hab, 0);
197 if (hmq != NULLHANDLE) {
198 if (WinOpenClipbrd(hab)) {
199 ULONG fmtInfo = 0;
201 if (WinQueryClipbrdFmtInfo(hab, CF_TEXT, &fmtInfo) != FALSE) {
202 ULONG selClipText = WinQueryClipbrdData(hab, CF_TEXT);
204 if (selClipText) {
205 PCHAR pchClipText = (PCHAR) selClipText;
207 ret = stracpy(pchClipText);
210 WinCloseClipbrd(hab);
212 WinDestroyMsgQueue(hmq);
214 WinTerminate(hab);
217 pib->pib_ultype = oldType;
219 return ret;
222 void
223 set_clipboard_text(unsigned char *data)
225 PTIB tib;
226 PPIB pib;
227 HAB hab;
228 HMQ hmq;
229 ULONG oldType;
231 DosGetInfoBlocks(&tib, &pib);
233 oldType = pib->pib_ultype;
235 pib->pib_ultype = 3;
237 hab = WinInitialize(0);
238 if (hab != NULLHANDLE) {
239 hmq = WinCreateMsgQueue(hab, 0);
240 if (hmq != NULLHANDLE) {
241 if (WinOpenClipbrd(hab)) {
242 PVOID pvShrObject = NULL;
243 if (DosAllocSharedMem(&pvShrObject, NULL, strlen(data) + 1, PAG_COMMIT | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) {
244 strcpy(pvShrObject, data);
245 WinSetClipbrdData(hab, (ULONG) pvShrObject, CF_TEXT, CFI_POINTER);
247 WinCloseClipbrd(hab);
249 WinDestroyMsgQueue(hmq);
251 WinTerminate(hab);
254 pib->pib_ultype = oldType;
257 unsigned char *
258 get_window_title(int codepage)
260 #ifndef DEBUG_OS2
261 unsigned char *org_switch_title;
262 unsigned char *org_win_title = NULL;
263 static PTIB tib = NULL;
264 static PPIB pib = NULL;
265 ULONG oldType;
266 HSWITCH hSw = NULLHANDLE;
267 SWCNTRL swData;
268 HAB hab;
269 HMQ hmq;
271 /* save current process title */
273 if (!pib) DosGetInfoBlocks(&tib, &pib);
274 oldType = pib->pib_ultype;
275 memset(&swData, 0, sizeof(swData));
276 if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
277 if (hSw != NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
278 /*org_switch_title = mem_alloc(strlen(swData.szSwtitle)+1);
279 strcpy(org_switch_title, swData.szSwtitle);*/
280 /* Go to PM */
281 pib->pib_ultype = 3;
282 hab = WinInitialize(0);
283 if (hab != NULLHANDLE) {
284 hmq = WinCreateMsgQueue(hab, 0);
285 if (hmq != NULLHANDLE) {
286 org_win_title = mem_alloc(MAXNAMEL + 1);
287 if (org_win_title)
288 WinQueryWindowText(swData.hwnd,
289 MAXNAMEL + 1,
290 org_win_title);
291 org_win_title[MAXNAMEL] = 0;
292 /* back From PM */
293 WinDestroyMsgQueue(hmq);
295 WinTerminate(hab);
297 pib->pib_ultype = oldType;
299 return org_win_title;
300 #else
301 return NULL;
302 #endif
305 void
306 set_window_title(unsigned char *title, int codepage)
308 #ifndef DEBUG_OS2
309 static PTIB tib;
310 static PPIB pib;
311 ULONG oldType;
312 static HSWITCH hSw;
313 SWCNTRL swData;
314 HAB hab;
315 HMQ hmq;
316 unsigned char new_title[MAXNAMEL];
318 if (!title) return;
319 if (!pib) DosGetInfoBlocks(&tib, &pib);
320 oldType = pib->pib_ultype;
321 memset(&swData, 0, sizeof(swData));
322 if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
323 if (hSw != NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
324 unsigned char *p;
326 safe_strncpy(new_title, title, MAXNAMEL - 1);
327 sanitize_title(new_title);
328 safe_strncpy(swData.szSwtitle, new_title, MAXNAMEL - 1);
329 WinChangeSwitchEntry(hSw, &swData);
330 /* Go to PM */
331 pib->pib_ultype = 3;
332 hab = WinInitialize(0);
333 if (hab != NULLHANDLE) {
334 hmq = WinCreateMsgQueue(hab, 0);
335 if (hmq != NULLHANDLE) {
336 if (swData.hwnd)
337 WinSetWindowText(swData.hwnd, new_title);
338 /* back From PM */
339 WinDestroyMsgQueue(hmq);
341 WinTerminate(hab);
344 pib->pib_ultype = oldType;
345 #endif
348 #if 0
349 void
350 set_window_title(int init, const char *url)
352 static char *org_switch_title;
353 static char *org_win_title;
354 static PTIB tib;
355 static PPIB pib;
356 static ULONG oldType;
357 static HSWITCH hSw;
358 static SWCNTRL swData;
359 HAB hab;
360 HMQ hmq;
361 char new_title[MAXNAMEL];
363 switch (init) {
364 case 1:
365 DosGetInfoBlocks(&tib, &pib);
366 oldType = pib->pib_ultype;
367 memset(&swData, 0, sizeof(swData));
368 hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
369 if (hSw != NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
370 org_switch_title = mem_alloc(strlen(swData.szSwtitle) + 1);
371 strcpy(org_switch_title, swData.szSwtitle);
372 pib->pib_ultype = 3;
373 hab = WinInitialize(0);
374 hmq = WinCreateMsgQueue(hab, 0);
375 if (hab != NULLHANDLE && hmq != NULLHANDLE) {
376 org_win_title = mem_alloc(MAXNAMEL + 1);
377 WinQueryWindowText(swData.hwnd, MAXNAMEL + 1, org_win_title);
378 WinDestroyMsgQueue(hmq);
379 WinTerminate(hab);
381 pib->pib_ultype = oldType;
383 break;
384 case -1:
385 pib->pib_ultype = 3;
386 hab = WinInitialize(0);
387 hmq = WinCreateMsgQueue(hab, 0);
388 if (hSw != NULLHANDLE && hab != NULLHANDLE && hmq != NULLHANDLE) {
389 safe_strncpy(swData.szSwtitle, org_switch_title, MAXNAMEL);
390 WinChangeSwitchEntry(hSw, &swData);
392 if (swData.hwnd)
393 WinSetWindowText(swData.hwnd, org_win_title);
394 WinDestroyMsgQueue(hmq);
395 WinTerminate(hab);
397 pib->pib_ultype = oldType;
398 mem_free(org_switch_title);
399 mem_free(org_win_title);
400 break;
401 case 0:
402 if (url && *url) {
403 safe_strncpy(new_title, url, MAXNAMEL - 10);
404 strcat(new_title, " - Links");
405 pib->pib_ultype = 3;
406 hab = WinInitialize(0);
407 hmq = WinCreateMsgQueue(hab, 0);
408 if (hSw != NULLHANDLE && hab != NULLHANDLE && hmq != NULLHANDLE) {
409 safe_strncpy(swData.szSwtitle, new_title, MAXNAMEL);
410 WinChangeSwitchEntry(hSw, &swData);
412 if (swData.hwnd)
413 WinSetWindowText(swData.hwnd, new_title);
414 WinDestroyMsgQueue(hmq);
415 WinTerminate(hab);
417 pib->pib_ultype = oldType;
419 break;
422 #endif
425 resize_window(int x, int y, int old_width, int old_height)
427 A_DECL(VIOMODEINFO, vmi);
429 resize_count++;
430 if (is_xterm()) return -1;
431 vmi->cb = sizeof(*vmi);
432 if (VioGetMode(vmi, 0)) return -1;
433 vmi->col = x;
434 vmi->row = y;
435 if (VioSetMode(vmi, 0)) return -1;
436 #if 0
437 unsigned char cmdline[16];
438 sprintf(cmdline, "mode ");
439 ulongcat(cmdline + 5, NULL, x, 5, 0);
440 strcat(cmdline, ",");
441 ulongcat(cmdline + strlen(cmdline), NULL, y, 5, 0);
442 #endif
443 return 0;
447 #if OS2_MOUSE
449 #ifdef HAVE_SYS_FMUTEX_H
450 _fmutex mouse_mutex;
451 int mouse_mutex_init = 0;
452 #endif
453 int mouse_h = -1;
455 struct os2_mouse_spec {
456 int p[2];
457 void (*fn)(void *, unsigned char *, int);
458 void *data;
459 unsigned char buffer[sizeof(struct interlink_event)];
460 int bufptr;
461 int terminate;
464 void
465 mouse_thread(void *p)
467 int status;
468 struct os2_mouse_spec *oms = p;
469 A_DECL(HMOU, mh);
470 A_DECL(MOUEVENTINFO, ms);
471 A_DECL(USHORT, rd);
472 A_DECL(USHORT, mask);
474 signal(SIGPIPE, SIG_IGN);
475 if (MouOpen(NULL, mh)) goto ret;
476 mouse_h = *mh;
477 *mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
478 MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
479 MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
480 MOUSE_MOTION;
481 MouSetEventMask(mask, *mh);
482 *rd = MOU_WAIT;
483 status = -1;
485 while (1) {
486 struct interlink_event ev;
487 struct interlink_event_mouse mouse;
488 int w, ww;
490 if (MouReadEventQue(ms, rd, *mh)) break;
491 #ifdef HAVE_SYS_FMUTEX_H
492 _fmutex_request(&mouse_mutex, _FMR_IGNINT);
493 #endif
494 if (!oms->terminate) MouDrawPtr(*mh);
495 #ifdef HAVE_SYS_FMUTEX_H
496 _fmutex_release(&mouse_mutex);
497 #endif
498 mouse.x = ms->col;
499 mouse.y = ms->row;
500 /*DBG("status: %d %d %d", ms->col, ms->row, ms->fs);*/
501 if (ms->fs & (MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN))
502 mouse.button = status = B_DOWN | (ms->fs & MOUSE_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_BN2_DOWN ? B_MIDDLE : B_RIGHT);
503 else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
504 int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_MIDDLE : B_RIGHT;
506 if (status == -1)
507 b |= B_DOWN;
508 else
509 b |= B_DRAG;
510 mouse.button = status = b;
511 } else {
512 if (status == -1) continue;
513 mouse.button = (status & BM_BUTT) | B_UP;
514 status = -1;
517 set_mouse_interlink_event(&ev, mouse.x, mouse.y, mouse.button);
518 if (hard_write(oms->p[1], (unsigned char *) &ev, sizeof(ev)) != sizeof(ev)) break;
520 #ifdef HAVE_SYS_FMUTEX_H
521 _fmutex_request(&mouse_mutex, _FMR_IGNINT);
522 #endif
523 mouse_h = -1;
524 MouClose(*mh);
525 #ifdef HAVE_SYS_FMUTEX_H
526 _fmutex_release(&mouse_mutex);
527 #endif
529 ret:
530 close(oms->p[1]);
531 /*free(oms);*/
534 void
535 mouse_handle(struct os2_mouse_spec *oms)
537 ssize_t r = safe_read(oms->p[0], oms->buffer + oms->bufptr,
538 sizeof(struct interlink_event) - oms->bufptr);
540 if (r <= 0) {
541 unhandle_mouse(oms);
542 return;
545 oms->bufptr += r;
546 if (oms->bufptr == sizeof(struct interlink_event)) {
547 oms->bufptr = 0;
548 oms->fn(oms->data, oms->buffer, sizeof(struct interlink_event));
552 void *
553 handle_mouse(int cons, void (*fn)(void *, unsigned char *, int),
554 void *data)
556 struct os2_mouse_spec *oms;
558 if (is_xterm()) return NULL;
559 #ifdef HAVE_SYS_FMUTEX_H
560 if (!mouse_mutex_init) {
561 if (_fmutex_create(&mouse_mutex, 0)) return NULL;
562 mouse_mutex_init = 1;
564 #endif
565 /* This is never freed but it's allocated only once */
566 oms = malloc(sizeof(*oms));
567 if (!oms) return NULL;
568 oms->fn = fn;
569 oms->data = data;
570 oms->bufptr = 0;
571 oms->terminate = 0;
572 if (c_pipe(oms->p)) {
573 free(oms);
574 return NULL;
576 _beginthread(mouse_thread, NULL, 0x10000, (void *) oms);
577 set_handlers(oms->p[0], (select_handler_T) mouse_handle, NULL, NULL, oms);
579 return oms;
582 void
583 unhandle_mouse(void *om)
585 struct os2_mouse_spec *oms = om;
587 want_draw();
588 oms->terminate = 1;
589 clear_handlers(oms->p[0]);
590 close(oms->p[0]);
591 done_draw();
594 void
595 suspend_mouse(void *om)
599 void
600 resume_mouse(void *om)
604 void
605 want_draw(void)
607 A_DECL(NOPTRRECT, pa);
608 #ifdef HAVE_SYS_FMUTEX_H
609 if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT);
610 #endif
611 if (mouse_h != -1) {
612 static int x = -1, y = -1;
613 static int c = -1;
615 if (x == -1 || y == -1 || (c != resize_count)) {
616 get_terminal_size(1, &x, &y);
617 c = resize_count;
620 pa->row = 0;
621 pa->col = 0;
622 pa->cRow = y - 1;
623 pa->cCol = x - 1;
624 MouRemovePtr(pa, mouse_h);
628 void
629 done_draw(void)
631 #ifdef HAVE_SYS_FMUTEX_H
632 if (mouse_mutex_init) _fmutex_release(&mouse_mutex);
633 #endif
636 #endif /* OS2_MOUSE */
640 get_ctl_handle(void)
642 return get_input_handle();
647 get_system_env(void)
649 int env = get_common_env();
651 /* !!! FIXME: telnet */
652 if (!is_xterm()) env |= ENV_OS2VIO;
654 return env;
658 void
659 set_highpri(void)
661 DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0);
666 can_open_os_shell(int environment)
668 if (environment & ENV_XWIN) return 0;
669 return 1;
673 #if defined(HAVE_BEGINTHREAD)
676 start_thread(void (*fn)(void *, int), void *ptr, int l)
678 int p[2];
679 struct tdata *t;
681 if (c_pipe(p) < 0) return -1;
682 if (set_nonblocking_fd(p[0]) < 0) return -1;
683 if (set_nonblocking_fd(p[1]) < 0) return -1;
685 t = malloc(sizeof(*t) + l);
686 if (!t) return -1;
687 t->fn = fn;
688 t->h = p[1];
689 memcpy(t->data, ptr, l);
690 if (_beginthread((void (*)(void *)) bgt, NULL, 65536, t) == -1) {
691 close(p[0]);
692 close(p[1]);
693 mem_free(t);
694 return -1;
697 return p[0];
700 #if defined(HAVE_READ_KBD)
702 int tp = -1;
703 int ti = -1;
705 void
706 input_thread(void *p)
708 unsigned char c[2];
709 int h = (int) p;
711 signal(SIGPIPE, SIG_IGN);
712 while (1) {
713 #if 0
714 c[0] = _read_kbd(0, 1, 1);
715 if (c[0]) if (safe_write(h, c, 1) <= 0) break;
716 else {
717 int w;
718 printf("1");fflush(stdout);
719 c[1] = _read_kbd(0, 1, 1);
720 printf("2");fflush(stdout);
721 w = safe_write(h, c, 2);
722 printf("3");fflush(stdout);
723 if (w <= 0) break;
724 if (w == 1) if (safe_write(h, c+1, 1) <= 0) break;
725 printf("4");fflush(stdout);
727 #endif
728 /* for the records:
729 * _read_kbd(0, 1, 1) will
730 * read a char, don't echo it, wait for one available and
731 * accept CTRL-C.
732 * Knowing that, I suggest we replace this call completly!
734 *c = _read_kbd(0, 1, 1);
735 write(h, c, 1);
737 close(h);
741 get_input_handle(void)
743 int fd[2];
745 if (ti != -1) return ti;
746 if (is_xterm()) return 0;
747 if (c_pipe(fd) < 0) return 0;
748 ti = fd[0];
749 tp = fd[1];
750 _beginthread(input_thread, NULL, 0x10000, (void *) tp);
751 return fd[0];
754 #endif
756 #endif
759 #ifdef USE_OPEN_PREALLOC
761 open_prealloc(unsigned char *name, int flags, int mode, off_t siz)
763 /* This is good for OS/2, where this will prevent file fragmentation,
764 * preallocating the desired file size upon open(). */
765 return open(name, flags | O_SIZE, mode, (unsigned long) siz);
768 void
769 prealloc_truncate(int h, off_t siz)
771 ftruncate(h, siz);
773 #endif