1 /* libctl: flexible Guile-based control files for scientific software
2  * Copyright (C) 1998-2020 Massachusetts Institute of Technology and Steven G. Johnson
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA  02111-1307, USA.
18  *
19  * Steven G. Johnson can be contacted at stevenj@alum.mit.edu.
20  */
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <math.h>
26 
27 #include "ctl.h"
28 
29 /**************************************************************************/
30 
31 /* Functions missing from Guile 1.2: */
32 
33 #if !defined(HAVE_GH_BOOL2SCM) && !defined(HAVE_NO_GH)
34 /* Guile 1.2 is missing gh_bool2scm for some reason; redefine: */
ctl_gh_bool2scm(boolean b)35 SCM ctl_gh_bool2scm(boolean b) { return (b ? SCM_BOOL_T : SCM_BOOL_F); }
36 #endif
37 
38 #if defined(HAVE_NO_GH)
39 #define gh_length(x) scm_to_long(scm_length(x))
40 #elif !defined(HAVE_GH_LENGTH)
41 #define gh_length gh_list_length
42 #endif
43 
44 #if defined(HAVE_NO_GH)
45 #define list_ref(l, index) scm_list_ref(l, scm_from_int(index))
46 #elif !defined(HAVE_GH_LIST_REF)
47 /* Guile 1.2 doesn't have the gh_list_ref function.  Sigh. */
48 /* Note: index must be in [0,list_length(l) - 1].  We don't check! */
list_ref(list l,int index)49 static SCM list_ref(list l, int index) {
50   SCM cur = SCM_UNSPECIFIED, rest = l;
51 
52   while (index >= 0) {
53     cur = gh_car(rest);
54     rest = gh_cdr(rest);
55     --index;
56   }
57   return cur;
58 }
59 #else /* HAVE_GH_LIST_REF */
60 #define list_ref(l, index) gh_list_ref(l, gh_int2scm(index))
61 #endif
62 
63 #if defined(HAVE_NO_GH)
64 #define vector_ref(v, i) scm_c_vector_ref(v, i)
65 #elif !defined(HAVE_GH_VECTOR_REF)
66 #define vector_ref(v, i) gh_vref(v, gh_int2scm(i))
67 #else
68 #define vector_ref(v, i) gh_vector_ref(v, gh_int2scm(i))
69 #endif
70 
71 /**************************************************************************/
72 
73 /* Scheme file loading (don't use gh_load directly because subsequent
74    loads won't use the correct path name).  Uses our "include" function
75    from include.scm, or defaults to gh_load if this function isn't
76    defined. */
77 
ctl_include(const char * filename)78 void ctl_include(const char *filename) {
79   SCM include_proc = gh_lookup("include");
80   if (include_proc == SCM_UNDEFINED)
81     gh_load(filename);
82   else
83 #ifdef HAVE_NO_GH
84     scm_call_1(include_proc, ctl_convert_string_to_scm(filename));
85 #else
86     gh_call1(include_proc, gh_str02scm(filename));
87 #endif
88 }
89 
90 /* convert a pathname into one relative to the current include dir */
ctl_fix_path(const char * path)91 char *ctl_fix_path(const char *path) {
92   char *newpath;
93   if (path[0] != '/') {
94     SCM include_dir = gh_lookup("include-dir");
95     if (include_dir != SCM_UNDEFINED) {
96       char *dir = ctl_convert_string_to_c(include_dir);
97       newpath = (char *)malloc(sizeof(char) * (strlen(dir) + strlen(path) + 2));
98       strcpy(newpath, dir);
99       free(dir);
100       if (newpath[0] && newpath[strlen(newpath) - 1] != '/') strcat(newpath, "/");
101       strcat(newpath, path);
102       return newpath;
103     }
104   }
105   newpath = (char *)malloc(sizeof(char) * (strlen(path) + 1));
106   strcpy(newpath, path);
107   return newpath;
108 }
109 
110 /**************************************************************************/
111 
112 /* type conversion */
113 
scm2vector3(SCM sv)114 vector3 scm2vector3(SCM sv) {
115   vector3 v;
116 
117   v.x = ctl_convert_number_to_c(vector_ref(sv, 0));
118   v.y = ctl_convert_number_to_c(vector_ref(sv, 1));
119   v.z = ctl_convert_number_to_c(vector_ref(sv, 2));
120   return v;
121 }
122 
scm2matrix3x3(SCM sm)123 matrix3x3 scm2matrix3x3(SCM sm) {
124   matrix3x3 m;
125 
126   m.c0 = scm2vector3(vector_ref(sm, 0));
127   m.c1 = scm2vector3(vector_ref(sm, 1));
128   m.c2 = scm2vector3(vector_ref(sm, 2));
129   return m;
130 }
131 
make_vector3(SCM x,SCM y,SCM z)132 static SCM make_vector3(SCM x, SCM y, SCM z) {
133   SCM vscm;
134   vscm = scm_c_make_vector(3, SCM_UNSPECIFIED);
135 #ifdef SCM_SIMPLE_VECTOR_SET
136   SCM_SIMPLE_VECTOR_SET(vscm, 0, x);
137   SCM_SIMPLE_VECTOR_SET(vscm, 1, y);
138   SCM_SIMPLE_VECTOR_SET(vscm, 2, z);
139 #else
140   {
141     SCM *data;
142     data = SCM_VELTS(vscm);
143     data[0] = x;
144     data[1] = y;
145     data[2] = z;
146   }
147 #endif
148   return vscm;
149 }
150 
vector32scm(vector3 v)151 SCM vector32scm(vector3 v) {
152   return make_vector3(ctl_convert_number_to_scm(v.x), ctl_convert_number_to_scm(v.y),
153                       ctl_convert_number_to_scm(v.z));
154 }
155 
matrix3x32scm(matrix3x3 m)156 SCM matrix3x32scm(matrix3x3 m) {
157   return make_vector3(vector32scm(m.c0), vector32scm(m.c1), vector32scm(m.c2));
158 }
159 
scm2cnumber(SCM sx)160 cnumber scm2cnumber(SCM sx) {
161 #ifdef HAVE_SCM_COMPLEXP
162   if (scm_real_p(sx) && !(SCM_COMPLEXP(sx)))
163     return make_cnumber(ctl_convert_number_to_c(sx), 0.0);
164   else
165     return make_cnumber(SCM_COMPLEX_REAL(sx), SCM_COMPLEX_IMAG(sx));
166 #else
167   if (scm_real_p(sx) && !(SCM_NIMP(sx) && SCM_INEXP(sx) && SCM_CPLXP(sx)))
168     return make_cnumber(ctl_convert_number_to_c(sx), 0.0);
169   else
170     return make_cnumber(SCM_REALPART(sx), SCM_IMAG(sx));
171 #endif
172 }
173 
cnumber2scm(cnumber x)174 SCM cnumber2scm(cnumber x) {
175 #if defined(HAVE_SCM_C_MAKE_RECTANGULAR)     /* Guile 1.6.5 */
176   return scm_c_make_rectangular(x.re, x.im); /* Guile 1.5 */
177 #elif defined(HAVE_SCM_MAKE_COMPLEX)
178   return scm_make_complex(x.re, x.im); /* Guile 1.5 */
179 #else
180   if (x.im == 0.0)
181     return ctl_convert_number_to_scm(x.re);
182   else
183     return scm_makdbl(x.re, x.im);
184 #endif
185 }
186 
scm2cvector3(SCM sv)187 cvector3 scm2cvector3(SCM sv) {
188   cvector3 v;
189 
190   v.x = scm2cnumber(vector_ref(sv, 0));
191   v.y = scm2cnumber(vector_ref(sv, 1));
192   v.z = scm2cnumber(vector_ref(sv, 2));
193   return v;
194 }
195 
scm2cmatrix3x3(SCM sm)196 cmatrix3x3 scm2cmatrix3x3(SCM sm) {
197   cmatrix3x3 m;
198 
199   m.c0 = scm2cvector3(vector_ref(sm, 0));
200   m.c1 = scm2cvector3(vector_ref(sm, 1));
201   m.c2 = scm2cvector3(vector_ref(sm, 2));
202   return m;
203 }
204 
cvector32scm(cvector3 v)205 SCM cvector32scm(cvector3 v) {
206   return make_vector3(cnumber2scm(v.x), cnumber2scm(v.y), cnumber2scm(v.z));
207 }
208 
cmatrix3x32scm(cmatrix3x3 m)209 SCM cmatrix3x32scm(cmatrix3x3 m) {
210   return make_vector3(cvector32scm(m.c0), cvector32scm(m.c1), cvector32scm(m.c2));
211 }
212 
213 /**************************************************************************/
214 
215 /* variable get/set functions */
216 
217 /**** Getters ****/
218 
ctl_get_integer(const char * identifier)219 integer ctl_get_integer(const char *identifier) {
220   return (ctl_convert_integer_to_c(gh_lookup(identifier)));
221 }
222 
ctl_get_number(const char * identifier)223 number ctl_get_number(const char *identifier) {
224   return (ctl_convert_number_to_c(gh_lookup(identifier)));
225 }
226 
ctl_get_cnumber(const char * identifier)227 cnumber ctl_get_cnumber(const char *identifier) { return (scm2cnumber(gh_lookup(identifier))); }
228 
ctl_get_boolean(const char * identifier)229 boolean ctl_get_boolean(const char *identifier) {
230   return (ctl_convert_boolean_to_c(gh_lookup(identifier)));
231 }
232 
ctl_get_string(const char * identifier)233 char *ctl_get_string(const char *identifier) {
234   return (ctl_convert_string_to_c(gh_lookup(identifier)));
235 }
236 
ctl_get_vector3(const char * identifier)237 vector3 ctl_get_vector3(const char *identifier) { return (scm2vector3(gh_lookup(identifier))); }
238 
ctl_get_matrix3x3(const char * identifier)239 matrix3x3 ctl_get_matrix3x3(const char *identifier) {
240   return (scm2matrix3x3(gh_lookup(identifier)));
241 }
242 
ctl_get_cvector3(const char * identifier)243 cvector3 ctl_get_cvector3(const char *identifier) { return (scm2cvector3(gh_lookup(identifier))); }
244 
ctl_get_cmatrix3x3(const char * identifier)245 cmatrix3x3 ctl_get_cmatrix3x3(const char *identifier) {
246   return (scm2cmatrix3x3(gh_lookup(identifier)));
247 }
248 
ctl_get_list(const char * identifier)249 list ctl_get_list(const char *identifier) { return (gh_lookup(identifier)); }
250 
ctl_get_object(const char * identifier)251 object ctl_get_object(const char *identifier) { return (gh_lookup(identifier)); }
252 
ctl_get_function(const char * identifier)253 function ctl_get_function(const char *identifier) { return (gh_lookup(identifier)); }
254 
ctl_get_SCM(const char * identifier)255 SCM ctl_get_SCM(const char *identifier) { return (gh_lookup(identifier)); }
256 
257 /**** Setters ****/
258 
259 /* UGLY hack alert!  There doesn't seem to be any clean way of setting
260    Scheme variables from C in Guile (e.g. no gh_* interface).
261 
262    One option is to use scm_symbol_set_x (symbol-set! in Scheme), but
263    I'm not sure how to get this to work in Guile 1.3 because of the
264    %&*@^-ing module system (I need to pass some module for the first
265    parameter, but I don't know what to pass).
266 
267    Instead, I hacked together the following my_symbol_set_x routine,
268    using the functions scm_symbol_value0 and scm_symbol_set_x from the
269    Guile 1.3 sources. (scm_symbol_value0 has the virtue of looking in
270    the correct module somehow; I also used this function to replace
271    gh_lookup, which broke in Guile 1.3 as well...sigh.)
272 
273    Note that I can't call "set!" because it is really a macro.
274 
275    All the ugliness is confined to the set_value() routine, though.
276 
277    Update: in Guile 1.5, we can call scm_variable_set_x (equivalent
278    to variable-set!) to set values of variables, which are looked up
279    via scm_c_lookup (which doesn't exist in Guile 1.3.x). */
280 
281 #if !(defined(HAVE_SCM_VARIABLE_SET_X) && defined(HAVE_SCM_C_LOOKUP))
282 #define USE_MY_SYMBOL_SET_X 1 /* use the hack */
283 #endif
284 
285 #ifdef USE_MY_SYMBOL_SET_X
my_symbol_set_x(const char * name,SCM v)286 static SCM my_symbol_set_x(const char *name, SCM v) {
287   /* code swiped from scm_symbol_value0 and scm_symbol_set_x */
288   SCM symbol = scm_intern_obarray_soft(name, strlen(name), scm_symhash, 0);
289   SCM vcell = scm_sym2vcell(SCM_CAR(symbol), SCM_CDR(scm_top_level_lookup_closure_var), SCM_BOOL_F);
290   if (SCM_FALSEP(vcell)) return SCM_UNDEFINED;
291   SCM_SETCDR(vcell, v);
292   return SCM_UNSPECIFIED;
293 }
294 #endif
295 
set_value(const char * identifier,SCM value)296 static void set_value(const char *identifier, SCM value) {
297 #if defined(USE_SCM_SYMBOL_SET_X) /* worked in Guile 1.1, 1.2 */
298   scm_symbol_set_x(SCM_BOOL_F, gh_symbol2scm(identifier), value);
299 #elif defined(HAVE_SCM_VARIABLE_SET_X) && defined(HAVE_SCM_C_LOOKUP)
300   scm_variable_set_x(scm_c_lookup(identifier), value);
301 #elif defined(USE_MY_SYMBOL_SET_X)
302   my_symbol_set_x(identifier, value);
303 #endif
304 }
305 
ctl_set_integer(const char * identifier,integer value)306 void ctl_set_integer(const char *identifier, integer value) {
307   set_value(identifier, ctl_convert_integer_to_scm(value));
308 }
309 
ctl_set_number(const char * identifier,number value)310 void ctl_set_number(const char *identifier, number value) {
311   set_value(identifier, ctl_convert_number_to_scm(value));
312 }
313 
ctl_set_cnumber(const char * identifier,cnumber value)314 void ctl_set_cnumber(const char *identifier, cnumber value) {
315   set_value(identifier, cnumber2scm(value));
316 }
317 
ctl_set_boolean(const char * identifier,boolean value)318 void ctl_set_boolean(const char *identifier, boolean value) {
319   set_value(identifier, ctl_convert_boolean_to_scm(value));
320 }
321 
ctl_set_string(const char * identifier,const char * value)322 void ctl_set_string(const char *identifier, const char *value) {
323   set_value(identifier, ctl_convert_string_to_scm(value));
324 }
325 
ctl_set_vector3(const char * identifier,vector3 value)326 void ctl_set_vector3(const char *identifier, vector3 value) {
327   set_value(identifier, vector32scm(value));
328 }
329 
ctl_set_matrix3x3(const char * identifier,matrix3x3 value)330 void ctl_set_matrix3x3(const char *identifier, matrix3x3 value) {
331   set_value(identifier, matrix3x32scm(value));
332 }
333 
ctl_set_cvector3(const char * identifier,cvector3 value)334 void ctl_set_cvector3(const char *identifier, cvector3 value) {
335   set_value(identifier, cvector32scm(value));
336 }
337 
ctl_set_cmatrix3x3(const char * identifier,cmatrix3x3 value)338 void ctl_set_cmatrix3x3(const char *identifier, cmatrix3x3 value) {
339   set_value(identifier, cmatrix3x32scm(value));
340 }
341 
ctl_set_list(const char * identifier,list value)342 void ctl_set_list(const char *identifier, list value) { set_value(identifier, value); }
343 
ctl_set_object(const char * identifier,object value)344 void ctl_set_object(const char *identifier, object value) { set_value(identifier, value); }
345 
ctl_set_function(const char * identifier,function value)346 void ctl_set_function(const char *identifier, function value) { set_value(identifier, value); }
347 
ctl_set_SCM(const char * identifier,SCM value)348 void ctl_set_SCM(const char *identifier, SCM value) { set_value(identifier, value); }
349 
350 /**************************************************************************/
351 
352 /* list traversal */
353 
list_length(list l)354 int list_length(list l) { return (gh_length(l)); }
355 
integer_list_ref(list l,int index)356 integer integer_list_ref(list l, int index) {
357   return (ctl_convert_integer_to_c(list_ref(l, index)));
358 }
359 
number_list_ref(list l,int index)360 number number_list_ref(list l, int index) { return (ctl_convert_number_to_c(list_ref(l, index))); }
361 
cnumber_list_ref(list l,int index)362 cnumber cnumber_list_ref(list l, int index) { return (scm2cnumber(list_ref(l, index))); }
363 
boolean_list_ref(list l,int index)364 boolean boolean_list_ref(list l, int index) { return (SCM_BOOL_F != list_ref(l, index)); }
365 
string_list_ref(list l,int index)366 char *string_list_ref(list l, int index) { return (ctl_convert_string_to_c(list_ref(l, index))); }
367 
vector3_list_ref(list l,int index)368 vector3 vector3_list_ref(list l, int index) { return (scm2vector3(list_ref(l, index))); }
369 
matrix3x3_list_ref(list l,int index)370 matrix3x3 matrix3x3_list_ref(list l, int index) { return (scm2matrix3x3(list_ref(l, index))); }
371 
cvector3_list_ref(list l,int index)372 cvector3 cvector3_list_ref(list l, int index) { return (scm2cvector3(list_ref(l, index))); }
373 
cmatrix3x3_list_ref(list l,int index)374 cmatrix3x3 cmatrix3x3_list_ref(list l, int index) { return (scm2cmatrix3x3(list_ref(l, index))); }
375 
list_list_ref(list l,int index)376 list list_list_ref(list l, int index) { return (list_ref(l, index)); }
377 
object_list_ref(list l,int index)378 object object_list_ref(list l, int index) { return (list_ref(l, index)); }
379 
function_list_ref(list l,int index)380 function function_list_ref(list l, int index) { return (list_ref(l, index)); }
381 
SCM_list_ref(list l,int index)382 SCM SCM_list_ref(list l, int index) { return (list_ref(l, index)); }
383 
384 /**************************************************************************/
385 
386 /* list creation */
387 
388 #define MAKE_LIST(conv)                                                                            \
389   {                                                                                                \
390     int i;                                                                                         \
391     list cur_list = SCM_EOL;                                                                       \
392     for (i = num_items - 1; i >= 0; --i)                                                           \
393       cur_list = gh_cons(conv(items[i]), cur_list);                                                \
394     return (cur_list);                                                                             \
395   }
396 
397 #ifdef HAVE_NO_GH
398 
make_integer_list(int num_items,const integer * items)399 list make_integer_list(int num_items, const integer *items) MAKE_LIST(scm_from_int)
400 
401     list make_boolean_list(int num_items, const boolean *items) MAKE_LIST(scm_from_bool)
402 
403         list make_string_list(int num_items, const char **items) MAKE_LIST(scm_from_locale_string)
404 
405             list make_number_list(int num_items, const number *items) MAKE_LIST(scm_from_double)
406 
407 #else /* ! HAVE_NO_GH */
408 
409 list make_integer_list(int num_items, const integer *items) MAKE_LIST(gh_int2scm)
410 
411     list make_boolean_list(int num_items, const boolean *items) MAKE_LIST(gh_bool2scm)
412 
413         list make_string_list(int num_items, const char **items) MAKE_LIST(gh_str02scm)
414 
415             list make_number_list(int num_items, const number *items) MAKE_LIST(gh_double2scm)
416 
417 #endif /* ! HAVE_NO_GH */
418 
419                 list make_cnumber_list(int num_items, const cnumber *items) MAKE_LIST(cnumber2scm)
420 
421                     list
422     make_vector3_list(int num_items, const vector3 *items) MAKE_LIST(vector32scm)
423 
424         list make_matrix3x3_list(int num_items, const matrix3x3 *items) MAKE_LIST(matrix3x32scm)
425 
426             list make_cvector3_list(int num_items, const cvector3 *items) MAKE_LIST(cvector32scm)
427 
428                 list
429     make_cmatrix3x3_list(int num_items, const cmatrix3x3 *items) MAKE_LIST(cmatrix3x32scm)
430 
431 #define NO_CONVERSION
432 
433         list make_list_list(int num_items, const list *items) MAKE_LIST(NO_CONVERSION)
434 
435             list make_object_list(int num_items, const object *items) MAKE_LIST(NO_CONVERSION)
436 
437                 list make_function_list(int num_items, const object *items) MAKE_LIST(NO_CONVERSION)
438 
439                     list make_SCM_list(int num_items, const object *items) MAKE_LIST(NO_CONVERSION)
440 
441     /**************************************************************************/
442 
443     /* object properties */
444 
445     boolean object_is_member(const char *type_name, object o) {
446   return (SCM_BOOL_F != gh_call2(gh_lookup("object-member?"), gh_symbol2scm(type_name), o));
447 }
448 
object_property_value(object o,const char * property_name)449 static SCM object_property_value(object o, const char *property_name) {
450   return (gh_call2(gh_lookup("object-property-value"), o, gh_symbol2scm(property_name)));
451 }
452 
integer_object_property(object o,const char * property_name)453 integer integer_object_property(object o, const char *property_name) {
454   return (ctl_convert_integer_to_c(object_property_value(o, property_name)));
455 }
456 
number_object_property(object o,const char * property_name)457 number number_object_property(object o, const char *property_name) {
458   return (ctl_convert_number_to_c(object_property_value(o, property_name)));
459 }
460 
cnumber_object_property(object o,const char * property_name)461 cnumber cnumber_object_property(object o, const char *property_name) {
462   return (scm2cnumber(object_property_value(o, property_name)));
463 }
464 
boolean_object_property(object o,const char * property_name)465 boolean boolean_object_property(object o, const char *property_name) {
466   return (SCM_BOOL_F != object_property_value(o, property_name));
467 }
468 
string_object_property(object o,const char * property_name)469 char *string_object_property(object o, const char *property_name) {
470   return (ctl_convert_string_to_c(object_property_value(o, property_name)));
471 }
472 
vector3_object_property(object o,const char * property_name)473 vector3 vector3_object_property(object o, const char *property_name) {
474   return (scm2vector3(object_property_value(o, property_name)));
475 }
476 
matrix3x3_object_property(object o,const char * property_name)477 matrix3x3 matrix3x3_object_property(object o, const char *property_name) {
478   return (scm2matrix3x3(object_property_value(o, property_name)));
479 }
480 
cvector3_object_property(object o,const char * property_name)481 cvector3 cvector3_object_property(object o, const char *property_name) {
482   return (scm2cvector3(object_property_value(o, property_name)));
483 }
484 
cmatrix3x3_object_property(object o,const char * property_name)485 cmatrix3x3 cmatrix3x3_object_property(object o, const char *property_name) {
486   return (scm2cmatrix3x3(object_property_value(o, property_name)));
487 }
488 
list_object_property(object o,const char * property_name)489 list list_object_property(object o, const char *property_name) {
490   return (object_property_value(o, property_name));
491 }
492 
object_object_property(object o,const char * property_name)493 object object_object_property(object o, const char *property_name) {
494   return (object_property_value(o, property_name));
495 }
496 
function_object_property(object o,const char * property_name)497 function function_object_property(object o, const char *property_name) {
498   return (object_property_value(o, property_name));
499 }
500 
SCM_object_property(object o,const char * property_name)501 SCM SCM_object_property(object o, const char *property_name) {
502   return (object_property_value(o, property_name));
503 }
504