* Makefile.in: Rebuilt.
[bpt/guile.git] / libguile / fluids.c
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42 #include <assert.h>
43
44 #include "_scm.h"
45 #include "print.h"
46 #include "smob.h"
47 #include "dynwind.h"
48 #include "fluids.h"
49 #include "alist.h"
50 #include "eval.h"
51
52 #define INITIAL_FLUIDS 10
53
54 static volatile int n_fluids;
55 long scm_tc16_fluid;
56
57 SCM
58 scm_make_initial_fluids ()
59 {
60 return scm_make_vector (SCM_MAKINUM (INITIAL_FLUIDS),
61 SCM_BOOL_F, SCM_BOOL_F);
62 }
63
64 static void grow_fluids SCM_P ((scm_root_state *, int new_length));
65 static void
66 grow_fluids (root_state, new_length)
67 scm_root_state *root_state;
68 int new_length;
69 {
70 SCM old_fluids, new_fluids;
71 int old_length, i;
72
73 old_fluids = root_state->fluids;
74 assert (SCM_NIMP (old_fluids) && SCM_VECTORP (old_fluids));
75 old_length = SCM_LENGTH (old_fluids);
76 assert (old_length <= new_length);
77 new_fluids = scm_make_vector (SCM_MAKINUM (new_length),
78 SCM_BOOL_F, SCM_BOOL_F);
79 i = 0;
80 while (i < old_length)
81 {
82 SCM_VELTS(new_fluids)[i] = SCM_VELTS(old_fluids)[i];
83 i++;
84 }
85 while (i < new_length)
86 {
87 SCM_VELTS(new_fluids)[i] = SCM_BOOL_F;
88 i++;
89 }
90
91 root_state->fluids = new_fluids;
92 }
93
94 void
95 scm_copy_fluids (root_state)
96 scm_root_state *root_state;
97 {
98 grow_fluids (root_state, SCM_LENGTH(root_state->fluids));
99 }
100
101 static int print_fluid SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
102 static int
103 print_fluid (exp, port, pstate)
104 SCM exp;
105 SCM port;
106 scm_print_state *pstate;
107 {
108 scm_puts ("#<fluid ", port);
109 scm_intprint (SCM_FLUID_NUM (exp), 10, port);
110 scm_putc ('>', port);
111 return 1;
112 }
113
114 static scm_smobfuns fluid_smob = {
115 scm_mark0,
116 scm_free0,
117 print_fluid
118 };
119
120 static
121 int next_fluid_num ()
122 {
123 int n;
124 #ifdef USE_THREADS
125 SCM_THREAD_CRITICAL_SECTION_START;
126 #endif
127 n = n_fluids++;
128 #ifdef USE_THREADS
129 SCM_THREAD_CRITICAL_SECTION_END;
130 #endif
131 return n;
132 }
133
134 SCM_PROC (s_make_fluid, "make-fluid", 0, 0, 0, scm_make_fluid);
135
136 SCM
137 scm_make_fluid ()
138 {
139 SCM z;
140 int n;
141
142 SCM_DEFER_INTS;
143 n = next_fluid_num ();
144 SCM_NEWCELL (z);
145 SCM_SETCAR (z, scm_tc16_fluid);
146 SCM_SETCDR (z, n);
147 SCM_ALLOW_INTS;
148
149 return z;
150 }
151
152 SCM_PROC (s_fluid_p, "fluid?", 1, 0, 0, scm_fluid_p);
153
154 SCM
155 scm_fluid_p (fl)
156 SCM fl;
157 {
158 return (SCM_NIMP (fl) && SCM_FLUIDP (fl))? SCM_BOOL_T : SCM_BOOL_F;
159 }
160
161 SCM_PROC (s_fluid_ref, "fluid-ref", 1, 0, 0, scm_fluid_ref);
162
163 SCM
164 scm_fluid_ref (fl)
165 SCM fl;
166 {
167 int n;
168
169 SCM_ASSERT (SCM_NIMP (fl) && SCM_FLUIDP (fl), fl, SCM_ARG1, s_fluid_ref);
170
171 n = SCM_FLUID_NUM (fl);
172 assert (n >= 0 && n < n_fluids);
173
174 if (SCM_LENGTH (scm_root->fluids) <= n)
175 grow_fluids (scm_root, n+1);
176 return SCM_VELTS(scm_root->fluids)[n];
177 }
178
179 SCM_PROC (s_fluid_set_x, "fluid-set!", 2, 0, 0, scm_fluid_set_x);
180
181 SCM
182 scm_fluid_set_x (fl, val)
183 SCM fl;
184 SCM val;
185 {
186 int n;
187
188 SCM_ASSERT (SCM_NIMP (fl) && SCM_FLUIDP (fl), fl, SCM_ARG1, s_fluid_set_x);
189
190 n = SCM_FLUID_NUM (fl);
191 assert (n >= 0 && n < n_fluids);
192
193 if (SCM_LENGTH (scm_root->fluids) <= n)
194 grow_fluids (scm_root, n+1);
195 SCM_VELTS(scm_root->fluids)[n] = val;
196 return val;
197 }
198
199 void
200 scm_swap_fluids (fluids, vals)
201 SCM fluids, vals;
202 {
203 while (SCM_NIMP (fluids))
204 {
205 SCM fl = SCM_CAR (fluids);
206 SCM old_val = scm_fluid_ref (fl);
207 scm_fluid_set_x (fl, SCM_CAR (vals));
208 SCM_SETCAR (vals, old_val);
209 fluids = SCM_CDR (fluids);
210 vals = SCM_CDR (vals);
211 }
212 }
213
214 /* Swap the fluid values in reverse order. This is important when the
215 same fluid appears multiple times in the fluids list. */
216
217 void
218 scm_swap_fluids_reverse (fluids, vals)
219 SCM fluids, vals;
220 {
221 if (SCM_NIMP (fluids))
222 {
223 SCM fl, old_val;
224
225 scm_swap_fluids_reverse (SCM_CDR (fluids), SCM_CDR (vals));
226 fl = SCM_CAR (fluids);
227 old_val = scm_fluid_ref (fl);
228 scm_fluid_set_x (fl, SCM_CAR (vals));
229 SCM_SETCAR (vals, old_val);
230 }
231 }
232
233 SCM_PROC (s_with_fluids, "with-fluids*", 3, 0, 0, scm_with_fluids);
234
235 SCM
236 scm_internal_with_fluids (fluids, vals, cproc, cdata)
237 SCM fluids, vals;
238 SCM (*cproc) ();
239 void *cdata;
240 {
241 SCM ans;
242
243 int flen = scm_ilength (fluids);
244 int vlen = scm_ilength (vals);
245 SCM_ASSERT (flen >= 0, fluids, SCM_ARG1, s_with_fluids);
246 SCM_ASSERT (vlen >= 0, vals, SCM_ARG2, s_with_fluids);
247 if (flen != vlen)
248 scm_out_of_range (s_with_fluids, vals);
249
250 scm_swap_fluids (fluids, vals);
251 scm_dynwinds = scm_acons (fluids, vals, scm_dynwinds);
252 ans = cproc (cdata);
253 scm_dynwinds = SCM_CDR (scm_dynwinds);
254 scm_swap_fluids_reverse (fluids, vals);
255 return ans;
256 }
257
258 static SCM
259 apply_thunk (void *thunk)
260 {
261 return scm_apply ((SCM) thunk, SCM_EOL, SCM_EOL);
262 }
263
264 SCM
265 scm_with_fluids (fluids, vals, thunk)
266 SCM fluids, vals, thunk;
267 {
268 return scm_internal_with_fluids (fluids, vals, apply_thunk, (void *)thunk);
269 }
270
271 void
272 scm_init_fluids ()
273 {
274 scm_tc16_fluid = scm_newsmob(&fluid_smob);
275 #include "fluids.x"
276 }