6 email: Christophe.Troestler@umh.ac.be
7 WWW: http://www.umh.ac.be/math/an/software/
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public License
11 version 2.1 as published by the Free Software Foundation, with the
12 special exception on linking described in file LICENSE.
14 This library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
17 LICENSE for more details.
21 #include "../../../config/config.h"
22 #include <caml/mlvalues.h>
23 #include <caml/memory.h>
24 #include <caml/alloc.h>
25 #include <caml/custom.h>
26 #include <caml/fail.h>
27 #include <caml/callback.h>
31 #define _XOPEN_SOURCE 600
35 /* Outputs an error message and terminates the program. */
37 fprintf(stderr, "DEBUG magic_stub: " __VA_ARGS__); \
40 #define CAML_MAGIC_VERSION "0.2"
46 static void raise_magic_failure(const char * msg
)
48 static value
* exn
= NULL
;
49 if (exn
== NULL
) exn
= caml_named_value("Magiclib.Failure");
50 raise_with_string(*exn
, (char *) msg
);
53 /* [fname] is the function name. */
54 static void raise_on_error(const char* fname
, magic_t cookie
)
56 const char *err_magic
;
57 char *errmsg
; /* For thread safety of error messages */
61 if ((err_magic
= magic_error(cookie
)) != NULL
) {
62 if ((errmsg
= malloc(flen
+ strlen(err_magic
) + 1)) == NULL
)
63 raise_out_of_memory();
64 strcpy(errmsg
, fname
);
65 strcpy(errmsg
+ flen
, err_magic
);
66 raise_magic_failure(errmsg
);
69 int len
= 80; /* Initial buffer length */
72 /* Allocate buffer [errmsg] until there is enough space for the
74 err
= magic_errno(cookie
);
75 if ((errmsg
= malloc(len
)) == NULL
) raise_out_of_memory();
76 strcpy(errmsg
, fname
);
77 #ifdef HAVE_STRERROR_R
78 while (strerror_r(err
, errmsg
+ flen
, len
- flen
) < 0) {
80 errmsg
= realloc(errmsg
, len
);
81 if (errmsg
== NULL
) raise_out_of_memory();
84 strcat (errmsg
, strerror(err
));
86 raise_sys_error(copy_string(errmsg
));
95 /* magic_t is a pointer on 'struct magic_set' so one can set it to NULL */
96 #define COOKIE_VAL(v) (* ((magic_t *) Data_custom_val(v)))
98 /* If the cookie has not been forcibly closed with [magic_close], free it. */
99 static void free_cookie(value c
)
101 magic_t cookie
= COOKIE_VAL(c
);
102 if (cookie
!= NULL
) {
104 COOKIE_VAL(c
) = NULL
;
108 /* compare magic_t pointers (=> total order) */
109 static int compare_cookie(value c1
, value c2
)
111 magic_t cookie1
= COOKIE_VAL(c1
), cookie2
= COOKIE_VAL(c2
);
113 if (cookie1
== cookie2
) return 0;
114 else if (cookie1
< cookie2
) return -1;
118 static struct custom_operations cookie_ops
= {
119 /* identifier */ "be.ac.umh.math/magic.cookie." CAML_MAGIC_VERSION
,
120 /* finalize */ free_cookie
,
121 /* compare */ compare_cookie
,
122 /* hash */ custom_hash_default
,
123 /* serialize */ custom_serialize_default
,
124 /* deserialize */ custom_deserialize_default
127 #define ALLOC_COOKIE alloc_custom(&cookie_ops, sizeof(magic_t), \
128 sizeof(magic_t), 40 * sizeof(magic_t))
134 CAMLprim value
ocaml_magic_open(value flags
)
142 if ((COOKIE_VAL(c
) = magic_open(Int_val(flags
) | MAGIC_ERROR
)) == NULL
) {
144 /* An unsupported value for flags was given */
145 raise_magic_failure("Magiclib.create: Preserve_atime not supported");
147 /* No cookie yet, so one cannot use the above generic err fun */
148 if ((errmsg
= malloc(len
)) == NULL
) raise_out_of_memory();
149 strcpy(errmsg
, "Magiclib.create: "); /* 14 chars */
150 #ifdef HAVE_STRERROR_R
151 while (strerror_r(errno
, errmsg
+ 14, len
- 14) < 0) {
153 if ((errmsg
= realloc(errmsg
, len
)) == NULL
) raise_out_of_memory();
156 strcat (errmsg
, strerror(errno
));
158 raise_sys_error(copy_string(errmsg
));
164 CAMLprim value
ocaml_magic_close(value c
)
167 magic_t cookie
= COOKIE_VAL(c
);
168 if (cookie
!= NULL
) /* if first time it is called */
170 COOKIE_VAL(c
) = NULL
; /* For the finalization function & multiple calls */
171 CAMLreturn(Val_unit
);
175 CAMLprim value
ocaml_magic_file(value c
, value fname
)
177 CAMLparam2(c
, fname
);
179 magic_t cookie
= COOKIE_VAL(c
);
181 if (cookie
== NULL
) invalid_argument("Magiclib.file");
182 if ((ans
= magic_file(cookie
, String_val(fname
))) == NULL
) {
183 raise_on_error("Magiclib.file: ", cookie
);
185 CAMLreturn(copy_string(ans
));
188 CAMLprim value
ocaml_magic_buffer(value c
, value buf
, value len
)
190 CAMLparam3(c
, buf
, len
);
192 magic_t cookie
= COOKIE_VAL(c
);
194 if (cookie
== NULL
) caml_invalid_argument("Magiclib.buffer");
195 if ((ans
= magic_buffer(cookie
, String_val(buf
), Int_val(len
)))
197 raise_on_error("Magiclib.buffer: ", cookie
);
198 CAMLreturn(copy_string(ans
));
202 CAMLprim value
ocaml_magic_setflags(value c
, value flags
)
204 CAMLparam2(c
, flags
);
205 magic_t cookie
= COOKIE_VAL(c
);
207 if (cookie
== NULL
) caml_invalid_argument("Magiclib.setflags");
208 if (magic_setflags(cookie
, Int_val(flags
)) < 0)
209 raise_magic_failure("Magiclib.setflags: Preserve_atime not supported");
210 CAMLreturn(Val_unit
);
215 #define CHECK(fname) \
216 magic_t cookie = COOKIE_VAL(c); \
218 if (cookie == NULL) caml_invalid_argument("Magiclib.check"); \
219 if (magic_check(cookie, fname) < 0) \
220 CAMLreturn(Val_false); \
224 CAMLprim value
ocaml_magic_check_default(value c
)
229 CAMLprim value
ocaml_magic_check(value c
, value filenames
)
231 CAMLparam2(c
, filenames
);
232 CHECK(String_val(filenames
));
237 #define COMPILE(fname) \
238 magic_t cookie = COOKIE_VAL(c); \
240 if (cookie == NULL) caml_invalid_argument("Magiclib.compile"); \
241 if (magic_compile(cookie, fname) < 0) \
242 raise_on_error("Magiclib.compile: ", cookie); \
245 CAMLprim value
ocaml_magic_compile_default(value c
)
251 CAMLprim value
ocaml_magic_compile(value c
, value filenames
)
253 CAMLparam2(c
, filenames
);
254 COMPILE(String_val(filenames
));
259 #define LOAD(fname) \
260 magic_t cookie = COOKIE_VAL(c); \
262 if (cookie == NULL) caml_invalid_argument("Magiclib.load"); \
263 if (magic_load(cookie, fname) < 0) \
264 raise_on_error("Magiclib.load: ", cookie); \
268 value
ocaml_magic_load_default(value c
)
275 value
ocaml_magic_load(value c
, value filenames
)
277 CAMLparam2(c
, filenames
);
278 LOAD(String_val(filenames
));