Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame^] | 1 | /* vi:set ts=8 sts=4 sw=4: |
| 2 | * |
| 3 | * VIM - Vi IMproved by Bram Moolenaar |
| 4 | * BeBox port Copyright 1997 by Olaf Seibert. |
| 5 | * |
| 6 | * Do ":help uganda" in Vim to read copying and usage conditions. |
| 7 | * Do ":help credits" in Vim to see a list of people who contributed. |
| 8 | * See README.txt for an overview of the Vim source code. |
| 9 | */ |
| 10 | /* |
| 11 | * os_beos.c Additional stuff for BeOS (rest is in os_unix.c) |
| 12 | */ |
| 13 | |
| 14 | #include <float.h> |
| 15 | #include <termios.h> |
| 16 | #include <kernel/OS.h> |
| 17 | #include "vim.h" |
| 18 | |
| 19 | #if USE_THREAD_FOR_INPUT_WITH_TIMEOUT |
| 20 | |
| 21 | #ifdef PROTO /* making prototypes on Unix */ |
| 22 | #define sem_id int |
| 23 | #define thread_id int |
| 24 | #endif |
| 25 | |
| 26 | char_u charbuf; |
| 27 | signed char charcount; |
| 28 | sem_id character_present; |
| 29 | sem_id character_wanted; |
| 30 | thread_id read_thread_id; |
| 31 | |
| 32 | #define TRY_ABORT 0 /* This code does not work so turn it off. */ |
| 33 | |
| 34 | #if TRY_ABORT |
| 35 | static void |
| 36 | mostly_ignore(int sig) |
| 37 | { |
| 38 | } |
| 39 | #endif |
| 40 | |
| 41 | static long |
| 42 | read_thread(void *dummy) |
| 43 | { |
| 44 | signal(SIGINT, SIG_IGN); |
| 45 | signal(SIGQUIT, SIG_IGN); |
| 46 | #if TRY_ABORT |
| 47 | signal(SIGUSR1, mostly_ignore); |
| 48 | #endif |
| 49 | |
| 50 | for (;;) { |
| 51 | if (acquire_sem(character_wanted) != B_NO_ERROR) |
| 52 | break; |
| 53 | charcount = read(read_cmd_fd, &charbuf, 1); |
| 54 | release_sem(character_present); |
| 55 | } |
| 56 | |
| 57 | return 0; |
| 58 | } |
| 59 | |
| 60 | void |
| 61 | beos_cleanup_read_thread(void) |
| 62 | { |
| 63 | if (character_present > 0) |
| 64 | delete_sem(character_present); |
| 65 | character_present = 0; |
| 66 | if (read_thread_id > 0) |
| 67 | kill_thread(read_thread_id); |
| 68 | read_thread_id = 0; |
| 69 | } |
| 70 | |
| 71 | #endif |
| 72 | |
| 73 | /* |
| 74 | * select() emulation. Hopefully, in DR9 there will be something |
| 75 | * useful supplied by the system. ... Alas, not. Not in AAPR, nor |
| 76 | * in PR or even PR2... R3 then maybe? I don't think so! |
| 77 | */ |
| 78 | |
| 79 | int |
| 80 | beos_select(int nbits, |
| 81 | struct fd_set *rbits, |
| 82 | struct fd_set *wbits, |
| 83 | struct fd_set *ebits, |
| 84 | struct timeval *timeout) |
| 85 | { |
| 86 | bigtime_t tmo; |
| 87 | |
| 88 | if (nbits == 0) { |
| 89 | /* select is purely being used for delay */ |
| 90 | snooze(timeout->tv_sec * 1e6 + timeout->tv_usec); |
| 91 | return 0; |
| 92 | } |
| 93 | #if 0 |
| 94 | /* |
| 95 | * This does not seem to work either. Reads here are not supposed to |
| 96 | * block indefinitely, yet they do. This is most annoying. |
| 97 | */ |
| 98 | if (FD_ISSET(0, rbits)) { |
| 99 | char cbuf[1]; |
| 100 | int count; |
| 101 | struct termios told; |
| 102 | struct termios tnew; |
| 103 | tcgetattr(0, &told); |
| 104 | tnew = told; |
| 105 | tnew.c_lflag &= ~ICANON; |
| 106 | tnew.c_cc[VMIN] = 0; |
| 107 | tnew.c_cc[VTIME] = timeout->tv_sec * 10 + timeout->tv_usec / 100000; |
| 108 | tcsetattr(0, TCSANOW, &tnew); |
| 109 | |
| 110 | count = read(0, &cbuf, sizeof(cbuf)); |
| 111 | tcsetattr(0, TCSANOW, &told); |
| 112 | if (count > 0) { |
| 113 | add_to_input_buf(&cbuf[0], count); |
| 114 | return 1; |
| 115 | } |
| 116 | return 0; |
| 117 | } |
| 118 | #endif |
| 119 | #if USE_THREAD_FOR_INPUT_WITH_TIMEOUT |
| 120 | /* |
| 121 | * Check if the operation is really on stdin... |
| 122 | */ |
| 123 | if (FD_ISSET(read_cmd_fd, rbits)) |
| 124 | { |
| 125 | int acquired; |
| 126 | |
| 127 | /* |
| 128 | * Is this the first time through? |
| 129 | * Then start up the thread and initialise the semaphores. |
| 130 | */ |
| 131 | if (character_present == 0) { |
| 132 | character_present = create_sem(0, "vim character_present"); |
| 133 | character_wanted = create_sem(1, "vim character_wanted"); |
| 134 | read_thread_id = spawn_thread(read_thread, "vim async read", |
| 135 | B_NORMAL_PRIORITY, NULL); |
| 136 | atexit(beos_cleanup_read_thread); |
| 137 | resume_thread(read_thread_id); |
| 138 | } |
| 139 | |
| 140 | /* timeout == NULL means "indefinitely" */ |
| 141 | if (timeout) { |
| 142 | tmo = timeout->tv_sec * 1e6 + timeout->tv_usec; |
| 143 | /* 0 means "don't wait, which is impossible to do exactly. */ |
| 144 | if (tmo == 0) |
| 145 | tmo = 1.0; |
| 146 | } |
| 147 | #if TRY_ABORT |
| 148 | release_sem(character_wanted); |
| 149 | #endif |
| 150 | if (timeout) |
| 151 | acquired = acquire_sem_etc(character_present, 1, B_TIMEOUT, tmo); |
| 152 | else |
| 153 | acquired = acquire_sem(character_present); |
| 154 | if (acquired == B_NO_ERROR) { |
| 155 | if (charcount > 0) { |
| 156 | add_to_input_buf(&charbuf, 1); |
| 157 | #if !TRY_ABORT |
| 158 | release_sem(character_wanted); |
| 159 | #endif |
| 160 | |
| 161 | return 1; |
| 162 | } else { |
| 163 | #if !TRY_ABORT |
| 164 | release_sem(character_wanted); |
| 165 | #endif |
| 166 | |
| 167 | return 0; |
| 168 | } |
| 169 | } |
| 170 | #if TRY_ABORT |
| 171 | else { |
| 172 | /* |
| 173 | * Timeout occurred. Break the read() call by sending |
| 174 | * a signal. Problem: it may be just read()ing it now. |
| 175 | * Therefore we still have to finish the handshake with |
| 176 | * the thread and maybe remember the character. |
| 177 | */ |
| 178 | kill(read_thread_id, SIGUSR1); |
| 179 | /* |
| 180 | * If some other error occurred, don't hang now. |
| 181 | * (We will most likely hang later anyway...) |
| 182 | */ |
| 183 | if (acquired == B_TIMED_OUT) |
| 184 | acquire_sem(character_present); |
| 185 | if (charcount > 0) { |
| 186 | add_to_input_buf(&charbuf, 1); |
| 187 | return 1; |
| 188 | } |
| 189 | return 0; |
| 190 | } |
| 191 | #endif |
| 192 | } |
| 193 | #endif |
| 194 | |
| 195 | #if FEAT_GUI_BEOS |
| 196 | /* |
| 197 | * If not reading from terminal, pretend there is input. |
| 198 | * This makes the pty reading (for the GUI) "work" for |
| 199 | * :!ls but not for :r !ls ... weird. |
| 200 | */ |
| 201 | if (gui.in_use && State == EXTERNCMD) |
| 202 | return 1; |
| 203 | #endif |
| 204 | return 0; |
| 205 | } |
| 206 | |