1 /*
2
3 Copyright (c) 2009-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 #include <sys/param.h>
45 #include <errno.h>
46
47 #ifdef HAVE_POLL_H
48 #include <poll.h>
49 #elif defined(HAVE_SYS_POLL_H)
50 #include <sys/poll.h>
51 #else
52 #include "bsd-poll.h"
53 #endif
54
55 #include "uim.h"
56 #include "uim-internal.h"
57 #include "uim-scm.h"
58 #include "uim-scm-abbrev.h"
59 #include "uim-posix.h"
60 #include "uim-notify.h"
61 #include "gettext.h"
62 #include "dynlib.h"
63
64 typedef struct {
65 int flag;
66 char *arg;
67 } opt_args;
68
69 static uim_lisp
make_arg_cons(const opt_args * arg)70 make_arg_cons(const opt_args *arg)
71 {
72 return CONS(MAKE_SYM(arg->arg), MAKE_INT(arg->flag));
73 }
74
75 static uim_lisp
make_arg_list(const opt_args * list)76 make_arg_list(const opt_args *list)
77 {
78 uim_lisp ret_;
79 int i = 0;
80
81 ret_ = uim_scm_null();
82 while (list[i].arg != 0) {
83 ret_ = CONS((uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)make_arg_cons,
84 (void *)&list[i]), ret_);
85 i++;
86 }
87 return ret_;
88 }
89
90 const static opt_args open_flags[] = {
91 { O_RDONLY, "$O_RDONLY" },
92 { O_WRONLY, "$O_WRONLY" },
93 { O_RDWR, "$O_RDWR" },
94
95 #ifdef O_NONBLOCK
96 { O_NONBLOCK, "$O_NONBLOCK" },
97 #endif
98 #ifdef O_APPEND
99 { O_APPEND, "$O_APPEND" },
100 #endif
101
102 #ifdef O_SHLOCK
103 { O_SHLOCK, "$O_SHLOCK" },
104 #endif
105 #ifdef O_EXLOCK
106 { O_EXLOCK, "$O_EXLOCK" },
107 #endif
108
109 #ifdef O_NOFOLLOW
110 { O_NOFOLLOW, "$O_NOFOLLOW" },
111 #endif
112
113 #ifdef O_SYNC
114 { O_SYNC, "$O_SYNC" },
115 #endif
116
117 { O_CREAT, "$O_CREAT" },
118 { O_TRUNC, "$O_TRUNC" },
119 { O_EXCL, "$O_EXCL" },
120
121 { 0, 0 }
122 };
123
124 const static opt_args open_mode[] = {
125 { S_IRWXU, "$S_IRWXU" },
126 { S_IRUSR, "$S_IRUSR" },
127 { S_IWUSR, "$S_IWUSR" },
128 { S_IXUSR, "$S_IXUSR" },
129
130 { S_IRWXG, "$S_IRWXG" },
131 { S_IRGRP, "$S_IRGRP" },
132 { S_IWGRP, "$S_IWGRP" },
133 { S_IXGRP, "$S_IXGRP" },
134
135 { S_IRWXO, "$S_IRWXO" },
136 { S_IROTH, "$S_IROTH" },
137 { S_IWOTH, "$S_IWOTH" },
138 { S_IXOTH, "$S_IXOTH" },
139 { 0, 0 }
140 };
141
142
143 static uim_lisp uim_lisp_open_flags;
144 static uim_lisp
c_file_open_flags(void)145 c_file_open_flags(void)
146 {
147 return uim_lisp_open_flags;
148 }
149
150 static uim_lisp uim_lisp_open_mode;
151 static uim_lisp
c_file_open_mode(void)152 c_file_open_mode(void)
153 {
154 return uim_lisp_open_mode;
155 }
156
157 static uim_lisp
c_file_open(uim_lisp path_,uim_lisp flags_,uim_lisp mode_)158 c_file_open(uim_lisp path_, uim_lisp flags_, uim_lisp mode_)
159 {
160 return MAKE_INT(open(REFER_C_STR(path_), C_INT(flags_), C_INT(mode_)));
161 }
162
163 static uim_lisp
c_file_close(uim_lisp fd_)164 c_file_close(uim_lisp fd_)
165 {
166 return MAKE_INT(close(C_INT(fd_)));
167 }
168
169 struct c_file_read_args {
170 const unsigned char *buf;
171 int nr;
172 };
173
174 static uim_lisp
c_file_read_internal(struct c_file_read_args * args)175 c_file_read_internal(struct c_file_read_args *args)
176 {
177 int i;
178 uim_lisp ret_ = uim_scm_null();
179 const unsigned char *p = args->buf;
180
181 ret_ = uim_scm_null();
182 for (i = 0; i < args->nr; i++) {
183 ret_ = CONS(MAKE_CHAR(*p), ret_);
184 p++;
185 }
186 return ret_;
187 }
188
189 static uim_lisp
c_file_read(uim_lisp d_,uim_lisp nbytes_)190 c_file_read(uim_lisp d_, uim_lisp nbytes_)
191 {
192 unsigned char *buf;
193 uim_lisp ret_;
194 int nbytes = C_INT(nbytes_);
195 int nr;
196 struct c_file_read_args args;
197
198 buf = uim_malloc(nbytes);
199 if ((nr = read(C_INT(d_), buf, nbytes)) == 0)
200 return uim_scm_eof();
201 if (nr < 0)
202 return uim_scm_f();
203
204 args.buf = buf;
205 args.nr = nr;
206 ret_ = (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)c_file_read_internal,
207 (void *)&args);
208 free(buf);
209 return uim_scm_callf("reverse", "o", ret_);
210 }
211
212 static uim_lisp
c_file_write(uim_lisp d_,uim_lisp buf_)213 c_file_write(uim_lisp d_, uim_lisp buf_)
214 {
215 int nbytes = uim_scm_length(buf_);
216 uim_lisp ret_;
217 unsigned char *buf;
218 unsigned char *p;
219
220 buf = p = uim_malloc(nbytes);
221 while (!NULLP(buf_)) {
222 *p = C_CHAR(CAR(buf_));
223 p++;
224 buf_ = CDR(buf_);
225 }
226 ret_ = MAKE_INT((int)write(C_INT(d_), buf, nbytes));
227 free(buf);
228 return ret_;
229 }
230
231 const static opt_args position_whence[] = {
232 { SEEK_SET, "$SEEK_SET" },
233 { SEEK_CUR, "$SEEK_CUR" },
234 { SEEK_END, "$SEEK_END" },
235 { 0, 0 }
236 };
237
238 static uim_lisp uim_lisp_position_whence;
239 static uim_lisp
c_file_position_whence(void)240 c_file_position_whence(void)
241 {
242 return uim_lisp_position_whence;
243 }
244
245 static uim_lisp
c_file_position_set(uim_lisp fildes_,uim_lisp offset_,uim_lisp whence_)246 c_file_position_set(uim_lisp fildes_, uim_lisp offset_, uim_lisp whence_)
247 {
248 int ret = 0;
249
250 ret = lseek(C_INT(fildes_), C_INT(offset_), C_INT(whence_));
251 if (ret == -1) {
252 uim_lisp err_ = LIST3(fildes_, offset_, whence_);
253 ERROR_OBJ(strerror(errno), err_);
254 }
255 return MAKE_INT(ret);
256 }
257
258 static uim_lisp
c_duplicate2_fileno(uim_lisp oldd_,uim_lisp newd_)259 c_duplicate2_fileno(uim_lisp oldd_, uim_lisp newd_)
260 {
261 if (FALSEP(newd_))
262 return MAKE_INT(dup(C_INT(oldd_)));
263 return MAKE_INT(dup2(C_INT(oldd_), C_INT(newd_)));
264 }
265
266 const static opt_args poll_flags[] = {
267 { POLLIN, "$POLLIN" },
268 #ifdef POLLPRI
269 { POLLPRI, "$POLLPRI" },
270 #endif
271 { POLLOUT, "$POLLOUT" },
272 { POLLERR, "$POLLERR" },
273 #ifdef POLLHUP
274 { POLLHUP, "$POLLHUP"},
275 #endif
276 #ifdef POLLNVAL
277 { POLLNVAL, "$POLLNVAL"},
278 #endif
279 #ifdef POLLRDNORM
280 { POLLRDNORM, "$POLLRDNORM"},
281 #endif
282 #ifdef POLLNORM
283 { POLLNORM, "$POLLNORM"},
284 #endif
285 #ifdef POLLWRNORM
286 { POLLWRNORM, "$POLLWRNORM"},
287 #endif
288 #ifdef POLLRDBAND
289 { POLLRDBAND, "$POLLRDBAND"},
290 #endif
291 #ifdef POLLWRBAND
292 { POLLWRBAND, "$POLLWRBAND"},
293 #endif
294 { 0, 0 }
295 };
296
297 static uim_lisp uim_lisp_poll_flags;
298 static uim_lisp
c_file_poll_flags(void)299 c_file_poll_flags(void)
300 {
301 return uim_lisp_poll_flags;
302 }
303
304 struct c_file_poll_args {
305 struct pollfd *fds;
306 int nfds;
307 };
308
309 static uim_lisp
c_file_poll_internal(struct c_file_poll_args * args)310 c_file_poll_internal(struct c_file_poll_args *args)
311 {
312 int i;
313 uim_lisp ret_ = uim_scm_null();
314 struct pollfd *fds = args->fds;
315
316 for (i = 0; i < args->nfds; i++)
317 if (fds[i].revents != 0)
318 ret_ = CONS(CONS(MAKE_INT(fds[i].fd), MAKE_INT(fds[i].revents)), ret_);
319 return ret_;
320 }
321
322 static uim_lisp
c_file_poll(uim_lisp fds_,uim_lisp timeout_)323 c_file_poll(uim_lisp fds_, uim_lisp timeout_)
324 {
325 struct pollfd *fds;
326 int timeout = C_INT(timeout_);
327 int nfds = uim_scm_length(fds_);
328 uim_lisp fd_ = uim_scm_f();
329 int i;
330 int ret;
331 uim_lisp ret_;
332 struct c_file_poll_args args;
333
334 fds = uim_calloc(nfds, sizeof(struct pollfd));
335
336 for (i = 0; i < nfds; i++) {
337 fd_ = CAR(fds_);
338 fds[i].fd = C_INT(CAR(fd_));
339 fds[i].events = C_INT(CDR(fd_));
340 fds_ = CDR(fds_);
341 }
342
343 ret = poll(fds, nfds, timeout);
344 if (ret == -1)
345 return uim_scm_f();
346 else if (ret == 0)
347 return uim_scm_null();
348
349 args.fds = fds;
350 args.nfds = nfds;
351 ret_ = (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)c_file_poll_internal,
352 (void *)&args);
353 free(fds);
354 return uim_scm_callf("reverse", "o", ret_);
355 }
356
357 static uim_lisp
c_create_pipe(void)358 c_create_pipe(void)
359 {
360 int fildes[2];
361
362 if (pipe(fildes) == -1)
363 return uim_scm_f();
364 return CONS(MAKE_INT(fildes[0]), MAKE_INT(fildes[1]));
365 }
366
367 void
uim_plugin_instance_init(void)368 uim_plugin_instance_init(void)
369 {
370 uim_scm_init_proc3("file-open", c_file_open);
371 uim_scm_init_proc0("file-open-flags?", c_file_open_flags);
372 uim_scm_init_proc0("file-open-mode?", c_file_open_mode);
373 uim_lisp_open_flags = make_arg_list(open_flags);
374 uim_lisp_open_mode = make_arg_list(open_mode);
375 uim_scm_gc_protect(&uim_lisp_open_flags);
376 uim_scm_gc_protect(&uim_lisp_open_mode);
377
378 uim_scm_init_proc1("file-close", c_file_close);
379 uim_scm_init_proc2("file-read", c_file_read);
380 uim_scm_init_proc2("file-write", c_file_write);
381 uim_scm_init_proc3("file-position-set!", c_file_position_set);
382 uim_scm_init_proc0("file-position-whence?", c_file_position_whence);
383 uim_lisp_position_whence = make_arg_list(position_whence);
384 uim_scm_gc_protect(&uim_lisp_position_whence);
385
386 uim_scm_init_proc2("duplicate2-fileno", c_duplicate2_fileno);
387
388 uim_scm_init_proc2("file-poll", c_file_poll);
389 uim_scm_init_proc0("file-poll-flags?", c_file_poll_flags);
390 uim_lisp_poll_flags = make_arg_list(poll_flags);
391 uim_scm_gc_protect(&uim_lisp_poll_flags);
392
393 uim_scm_init_proc0("create-pipe", c_create_pipe);
394 }
395
396 void
uim_plugin_instance_quit(void)397 uim_plugin_instance_quit(void)
398 {
399 uim_scm_gc_unprotect(&uim_lisp_open_flags);
400 uim_scm_gc_unprotect(&uim_lisp_open_mode);
401 uim_scm_gc_unprotect(&uim_lisp_position_whence);
402 uim_scm_gc_unprotect(&uim_lisp_poll_flags);
403 }
404