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