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 <stdint.h>
40 #include <sys/types.h>
41 #ifdef HAVE_MMAP
42 #include <sys/mman.h>
43 #endif
44 
45 #include "uim.h"
46 #include "uim-scm.h"
47 #include "uim-scm-abbrev.h"
48 #include "uim-posix.h"
49 #include "uim-notify.h"
50 #include "dynlib.h"
51 
52 typedef struct {
53   int flag;
54   char *arg;
55 } opt_args;
56 
57 static uim_lisp
make_arg_cons(const opt_args * arg)58 make_arg_cons(const opt_args *arg)
59 {
60   return CONS(MAKE_SYM(arg->arg), MAKE_INT(arg->flag));
61 }
62 
63 static uim_lisp
make_arg_list(const opt_args * list)64 make_arg_list(const opt_args *list)
65 {
66   uim_lisp ret_;
67   int i = 0;
68 
69   ret_ = uim_scm_null();
70   while (list[i].arg != 0) {
71     ret_ = CONS((uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)make_arg_cons,
72                                                            (void *)&list[i]), ret_);
73     i++;
74   }
75   return ret_;
76 }
77 
78 static uim_lisp
c_allocate(uim_lisp len_)79 c_allocate(uim_lisp len_)
80 {
81   return MAKE_PTR(malloc(C_INT(len_)));
82 }
83 static uim_lisp
c_free(uim_lisp pointer_)84 c_free(uim_lisp pointer_)
85 {
86   free(C_PTR(pointer_));
87   return uim_scm_t();
88 }
89 static uim_lisp
90 
c_memory_fill(uim_lisp pointer_,uim_lisp c_,uim_lisp len_)91 c_memory_fill(uim_lisp pointer_, uim_lisp c_, uim_lisp len_)
92 {
93   int c;
94 
95   if (CHARP(c_))
96     c = C_CHAR(c_);
97   else if (STRP(c_))
98     c = C_STR(c_)[0];
99   else
100     c = C_INT(c_);
101 
102   memset(C_PTR(pointer_), c, C_INT(len_));
103   return uim_scm_t();
104 }
105 static uim_lisp
c_memory_move(uim_lisp dest_,uim_lisp src_,uim_lisp len_)106 c_memory_move(uim_lisp dest_, uim_lisp src_, uim_lisp len_)
107 {
108   if (STRP(src_))
109     strlcpy(C_PTR(dest_), REFER_C_STR(src_), C_INT(len_));
110   else
111     memmove(C_PTR(dest_), C_PTR(src_), C_INT(len_));
112   return uim_scm_t();
113 }
114 
115 #ifdef HAVE_MMAP
116 
117 const static opt_args mmap_prot_flags[] = {
118   { PROT_EXEC,  "$PROT_EXEC"  },
119   { PROT_READ,  "$PROT_READ"  },
120   { PROT_WRITE, "$PROT_WRITE" },
121   { PROT_NONE,  "$PROT_NONE"  },
122   { 0, 0 }
123 };
124 
125 static uim_lisp uim_lisp_mmap_prot_flags;
126 static uim_lisp
c_mmap_prot_flags(void)127 c_mmap_prot_flags(void)
128 {
129   return uim_lisp_mmap_prot_flags;
130 }
131 
132 const static opt_args mmap_flags[] = {
133 #ifdef MAP_ANON
134   { MAP_ANON,      "$MAP_ANON"  },
135 #endif
136 #ifdef MAP_ANONYMOUS
137   { MAP_ANONYMOUS, "$MAP_ANONYMOUS" },
138 #endif
139 #ifdef MAP_FILE
140   { MAP_FILE,      "$MAP_FILE"  },
141 #endif
142 #ifdef MAP_FIXED
143   { MAP_FIXED,     "$MAP_FIXED" },
144 #endif
145   { MAP_PRIVATE,   "$MAP_PRIVATE"  },
146   { MAP_SHARED,    "$MAP_SHARED"  },
147 #ifdef MAP_COPY
148   { MAP_COPY,      "$MAP_COPY"  },
149 #endif
150   { 0, 0 }
151 };
152 
153 static uim_lisp uim_lisp_mmap_flags;
154 static uim_lisp
c_mmap_flags(void)155 c_mmap_flags(void)
156 {
157   return uim_lisp_mmap_flags;
158 }
159 
160 static uim_lisp
c_mmap(uim_lisp addr_,uim_lisp len_,uim_lisp prot_flags_,uim_lisp fd_,uim_lisp offset_)161 c_mmap(uim_lisp addr_, uim_lisp len_, uim_lisp prot_flags_, uim_lisp fd_, uim_lisp offset_)
162 {
163   void *p = mmap(C_PTR(addr_), C_INT(len_), C_INT(CAR(prot_flags_)), C_INT(CDR(prot_flags_)), C_INT(fd_), C_INT(offset_));
164 
165   if (p == MAP_FAILED)
166     return uim_scm_f();
167   return MAKE_PTR(p);
168 }
169 
170 static uim_lisp
c_munmap(uim_lisp addr_,uim_lisp len_)171 c_munmap(uim_lisp addr_, uim_lisp len_)
172 {
173   return MAKE_INT(munmap(C_PTR(addr_), C_INT(len_)));
174 }
175 
176 #endif
177 
178 static uim_lisp
c_null_pointer(void)179 c_null_pointer(void)
180 {
181   return MAKE_PTR(NULL);
182 }
183 
184 static uim_lisp
c_pointer_offset(uim_lisp pointer_,uim_lisp nth_)185 c_pointer_offset(uim_lisp pointer_, uim_lisp nth_)
186 {
187   return MAKE_PTR((char *)C_PTR(pointer_) + C_INT(nth_));
188 }
189 
190 #define c_pointer_X_ref(X, type)		\
191   static uim_lisp				\
192   c_pointer_ ## X ## _ref(uim_lisp pointer_)	\
193   {						\
194     type *p = C_PTR(pointer_);			\
195     return MAKE_INT(*p);			\
196   }
197 
c_pointer_X_ref(u8,uint8_t)198 c_pointer_X_ref(u8,  uint8_t)
199 c_pointer_X_ref(s8,  int8_t)
200 c_pointer_X_ref(u16, uint16_t)
201 c_pointer_X_ref(s16, int16_t)
202 c_pointer_X_ref(u32, uint32_t)
203 c_pointer_X_ref(s32, int32_t)
204 c_pointer_X_ref(u64, uint64_t)
205 c_pointer_X_ref(s64, int64_t)
206 
207 #define c_pointer_X_set(X, type)				\
208   static uim_lisp						\
209   c_pointer_ ## X ## _set(uim_lisp pointer_, uim_lisp val_)	\
210   {								\
211     type *p = C_PTR(pointer_);					\
212     *p = C_INT(val_);						\
213     return uim_scm_t();						\
214   }
215 
216 c_pointer_X_set(u8,  uint8_t)
217 c_pointer_X_set(s8,  int8_t)
218 c_pointer_X_set(u16, uint16_t)
219 c_pointer_X_set(s16, int16_t)
220 c_pointer_X_set(u32, uint32_t)
221 c_pointer_X_set(s32, int32_t)
222 c_pointer_X_set(u64, uint64_t)
223 c_pointer_X_set(s64, int64_t)
224 
225 static uim_lisp
226 c_string_to_pointer(uim_lisp str_)
227 {
228   return MAKE_PTR(C_STR(str_));
229 }
230 static uim_lisp
c_pointer_to_string(uim_lisp pointer_)231 c_pointer_to_string(uim_lisp pointer_)
232 {
233   return MAKE_STR(C_PTR(pointer_));
234 }
235 
236 
237 #define c_Xlist_to_pointer(X, type)					\
238   static uim_lisp							\
239   c_ ## X ## list_to_pointer(uim_lisp l_)				\
240   {									\
241     type *p;								\
242     int i, len = uim_scm_length(l_);					\
243     									\
244     p = malloc(len * sizeof(type));					\
245     for (i = 0; i < len; i++) {						\
246       uim_lisp h_ = CAR(l_);						\
247       									\
248       p[i] = (type)C_INT(h_);						\
249       l_ = CDR(l_);							\
250     }									\
251     return MAKE_PTR(p);							\
252   }
253 
c_Xlist_to_pointer(s8,int8_t)254 c_Xlist_to_pointer(s8,  int8_t)
255 c_Xlist_to_pointer(u8,  uint8_t)
256 c_Xlist_to_pointer(s16, int16_t)
257 c_Xlist_to_pointer(u16, uint16_t)
258 c_Xlist_to_pointer(s32, int32_t)
259 c_Xlist_to_pointer(u32, uint32_t)
260 c_Xlist_to_pointer(s64, int64_t)
261 c_Xlist_to_pointer(u64, uint64_t)
262 
263 #define c_pointer_to_Xlist(X, type)					\
264   struct c__pointer_to_ ## X ## list_args {				\
265     type *pointer;							\
266     int len;								\
267   };									\
268 									\
269   static uim_lisp							\
270   c_pointer_to_ ## X ## list_internal(struct c__pointer_to_ ## X ## list_args *args) \
271   {									\
272       uim_lisp ret_ = uim_scm_null();					\
273       int i;								\
274       type *p = args->pointer;						\
275       									\
276       for (i = 0; i < args->len; i++)					\
277 	ret_ = CONS(MAKE_INT(*p++), ret_);				\
278       return ret_;							\
279   }									\
280   static uim_lisp							\
281   c_pointer_to_ ## X ## list(uim_lisp pointer_, uim_lisp len_)		\
282   {									\
283     uim_lisp ret_;							\
284     struct c__pointer_to_ ## X ## list_args args;			\
285 									\
286     args.pointer = C_PTR(pointer_);					\
287     args.len = C_INT(len_);						\
288     ret_ = (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)c_pointer_to_ ## X ## list_internal, (void *)&args); \
289     return uim_scm_callf("reverse", "o", ret_);				\
290   }
291 
292 c_pointer_to_Xlist(u8,  uint8_t)
293 c_pointer_to_Xlist(s8,  int8_t)
294 c_pointer_to_Xlist(u16, uint16_t)
295 c_pointer_to_Xlist(s16, int16_t)
296 c_pointer_to_Xlist(u32, uint32_t)
297 c_pointer_to_Xlist(s32, int32_t)
298 c_pointer_to_Xlist(u64, uint64_t)
299 c_pointer_to_Xlist(s64, int64_t)
300 
301 
302 static uim_lisp
303 c_htons(uim_lisp u16_)
304 {
305   return MAKE_INT(htons(C_INT(u16_)));
306 }
307 static uim_lisp
c_htonl(uim_lisp u32_)308 c_htonl(uim_lisp u32_)
309 {
310   return MAKE_INT(htonl(C_INT(u32_)));
311 }
312 
313 static uim_lisp
c_ntohs(uim_lisp u16_)314 c_ntohs(uim_lisp u16_)
315 {
316   return MAKE_INT(ntohs(C_INT(u16_)));
317 }
318 static uim_lisp
c_ntohl(uim_lisp u32_)319 c_ntohl(uim_lisp u32_)
320 {
321   return MAKE_INT(ntohl(C_INT(u32_)));
322 }
323 
324 
325 static uim_lisp
c_u16_to_u8list(uim_lisp u16_)326 c_u16_to_u8list(uim_lisp u16_)
327 {
328   uint16_t u16 = htons(C_INT(u16_));
329 
330   return LIST2(MAKE_INT(u16 & 0xff),
331 	       MAKE_INT((u16 >> 8) & 0xff));
332 }
333 static uim_lisp
c_u32_to_u8list(uim_lisp u32_)334 c_u32_to_u8list(uim_lisp u32_)
335 {
336   uint32_t u32 = htonl(C_INT(u32_));
337 
338   return LIST4(MAKE_INT(u32 & 0xff),
339 	       MAKE_INT((u32 >> 8) & 0xff),
340 	       MAKE_INT((u32 >> 16) & 0xff),
341 	       MAKE_INT((u32 >> 24) & 0xff));
342 }
343 
344 /* (map char->integer (string->list str)) */
345 static uim_lisp
c_string_to_u8list(uim_lisp str_)346 c_string_to_u8list(uim_lisp str_)
347 {
348   const char *str = REFER_C_STR(str_);
349   uim_lisp ret_ = uim_scm_null();
350 
351   while (*str) {
352     ret_ = CONS(MAKE_INT(*str & 0xff), ret_);
353     str++;
354   }
355   ret_ = CONS(MAKE_INT(0), ret_);
356   return uim_scm_callf("reverse", "o", ret_);
357 }
358 
359 static uim_lisp
c_u8list_to_u16(uim_lisp u8list_)360 c_u8list_to_u16(uim_lisp u8list_)
361 {
362   uint8_t u8_1, u8_2;
363 
364   u8_1 = C_INT(CAR(u8list_));
365   u8_2 = C_INT(CAR(CDR(u8list_)));
366   return MAKE_INT(ntohs(u8_1 |
367 			(u8_2 << 8)));
368 }
369 static uim_lisp
c_u8list_to_u32(uim_lisp u8list_)370 c_u8list_to_u32(uim_lisp u8list_)
371 {
372   uint8_t u8_1, u8_2, u8_3, u8_4;
373 
374   u8_1 = C_INT(CAR(u8list_));
375   u8_2 = C_INT(CAR(CDR(u8list_)));
376   u8_3 = C_INT(CAR(CDR(CDR(u8list_))));
377   u8_4 = C_INT(CAR(CDR(CDR(CDR(u8list_)))));
378   return MAKE_INT(ntohl(u8_1 |
379 			(u8_2 << 8) |
380 			(u8_3 << 16) |
381 			(u8_4 << 24)));
382 }
383 static uim_lisp
c_u8list_to_string(uim_lisp u8list_)384 c_u8list_to_string(uim_lisp u8list_)
385 {
386   int len = uim_scm_length(u8list_);
387   int i;
388   char *str = uim_malloc(len + 1);
389 
390   for (i = 0; i < len; i++) {
391     str[i] = (char)C_INT(CAR(u8list_));
392     u8list_ = CDR(u8list_);
393   }
394   str[len] = '\0';
395   return MAKE_STR_DIRECTLY(str);
396 }
397 
398 static uim_lisp
c_u32_to_s32(uim_lisp u32_)399 c_u32_to_s32(uim_lisp u32_)
400 {
401   uint32_t u32 = C_INT(u32_);
402 
403   return MAKE_INT((int32_t)u32);
404 }
405 
406 void
uim_plugin_instance_init(void)407 uim_plugin_instance_init(void)
408 {
409   uim_scm_init_proc1("allocate", c_allocate);
410   uim_scm_init_proc1("free",     c_free);
411 
412   uim_scm_init_proc3("memory-fill!", c_memory_fill);
413   uim_scm_init_proc3("memory-move!", c_memory_move);
414 
415 #ifdef HAVE_MMAP
416   uim_lisp_mmap_prot_flags = make_arg_list(mmap_prot_flags);
417   uim_scm_gc_protect(&uim_lisp_mmap_prot_flags);
418   uim_scm_init_proc0("mmap-prot-flags?", c_mmap_prot_flags);
419   uim_lisp_mmap_flags = make_arg_list(mmap_flags);
420   uim_scm_gc_protect(&uim_lisp_mmap_flags);
421   uim_scm_init_proc0("mmap-flags?", c_mmap_flags);
422 
423   uim_scm_init_proc5("mmap", c_mmap);
424   uim_scm_init_proc2("munmap", c_munmap);
425 #endif
426 
427   uim_scm_init_proc0("null-pointer", c_null_pointer);
428 
429   uim_scm_init_proc2("pointer-offset", c_pointer_offset);
430 
431   uim_scm_init_proc1("pointer-u8-ref",  c_pointer_u8_ref);
432   uim_scm_init_proc1("pointer-s8-ref",  c_pointer_s8_ref);
433   uim_scm_init_proc1("pointer-u16-ref", c_pointer_u16_ref);
434   uim_scm_init_proc1("pointer-s16-ref", c_pointer_s16_ref);
435   uim_scm_init_proc1("pointer-u32-ref", c_pointer_u32_ref);
436   uim_scm_init_proc1("pointer-s32-ref", c_pointer_s32_ref);
437   uim_scm_init_proc1("pointer-u64-ref", c_pointer_u64_ref);
438   uim_scm_init_proc1("pointer-s64-ref", c_pointer_s64_ref);
439 
440   uim_scm_init_proc2("pointer-u8-set!",  c_pointer_u8_set);
441   uim_scm_init_proc2("pointer-s8-set!",  c_pointer_s8_set);
442   uim_scm_init_proc2("pointer-u16-set!", c_pointer_u16_set);
443   uim_scm_init_proc2("pointer-s16-set!", c_pointer_s16_set);
444   uim_scm_init_proc2("pointer-u32-set!", c_pointer_u32_set);
445   uim_scm_init_proc2("pointer-s32-set!", c_pointer_s32_set);
446   uim_scm_init_proc2("pointer-u64-set!", c_pointer_u64_set);
447   uim_scm_init_proc2("pointer-s64-set!", c_pointer_s64_set);
448 
449   uim_scm_init_proc1("string->pointer",  c_string_to_pointer);
450   uim_scm_init_proc1("pointer->string",  c_pointer_to_string);
451 
452   uim_scm_init_proc1("u8list->pointer",  c_u8list_to_pointer);
453   uim_scm_init_proc1("s8list->pointer",  c_s8list_to_pointer);
454   uim_scm_init_proc1("u16list->pointer", c_u16list_to_pointer);
455   uim_scm_init_proc1("s16list->pointer", c_s16list_to_pointer);
456   uim_scm_init_proc1("u32list->pointer", c_u32list_to_pointer);
457   uim_scm_init_proc1("s32list->pointer", c_s32list_to_pointer);
458   uim_scm_init_proc1("u64list->pointer", c_u64list_to_pointer);
459   uim_scm_init_proc1("s64list->pointer", c_s64list_to_pointer);
460 
461   uim_scm_init_proc2("pointer->u8list",  c_pointer_to_u8list);
462   uim_scm_init_proc2("pointer->s8list",  c_pointer_to_s8list);
463   uim_scm_init_proc2("pointer->u16list", c_pointer_to_u16list);
464   uim_scm_init_proc2("pointer->s16list", c_pointer_to_s16list);
465   uim_scm_init_proc2("pointer->u32list", c_pointer_to_u32list);
466   uim_scm_init_proc2("pointer->s32list", c_pointer_to_s32list);
467   uim_scm_init_proc2("pointer->u64list", c_pointer_to_u64list);
468   uim_scm_init_proc2("pointer->s64list", c_pointer_to_s64list);
469 
470   uim_scm_init_proc1("htons", c_htons);
471   uim_scm_init_proc1("htonl", c_htonl);
472   uim_scm_init_proc1("ntohs", c_ntohs);
473   uim_scm_init_proc1("ntohl", c_ntohl);
474 
475   uim_scm_init_proc1("u16->u8list",    c_u16_to_u8list);
476   uim_scm_init_proc1("u32->u8list",    c_u32_to_u8list);
477   uim_scm_init_proc1("string->u8list", c_string_to_u8list);
478 
479   uim_scm_init_proc1("u8list->u16",    c_u8list_to_u16);
480   uim_scm_init_proc1("u8list->u32",    c_u8list_to_u32);
481   uim_scm_init_proc1("u8list->string", c_u8list_to_string);
482 
483   uim_scm_init_proc1("u32->s32", c_u32_to_s32);
484 }
485 
486 void
uim_plugin_instance_quit(void)487 uim_plugin_instance_quit(void)
488 {
489 #ifdef HAVE_MMAP
490   uim_scm_gc_unprotect(&uim_lisp_mmap_prot_flags);
491   uim_scm_gc_unprotect(&uim_lisp_mmap_flags);
492 #endif
493 }
494