*** empty log message ***
[bpt/guile.git] / libguile / options.c
CommitLineData
11d49f54 1/* Copyright (C) 1995,1996,1998,2000,2001 Free Software Foundation
1a413ab9
MD
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
1a413ab9
MD
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 * The author can be reached at djurfeldt@nada.kth.se
82892bed 43 * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
6e8d25a6 44
1a413ab9
MD
45\f
46
a0599745 47#include "libguile/_scm.h"
11d49f54 48#include "libguile/mallocs.h"
a0599745 49#include "libguile/strings.h"
c96d76b8 50#include "libguile/lang.h"
1a413ab9 51
a0599745 52#include "libguile/options.h"
1a413ab9
MD
53\f
54
55/* {Run-time options}
56 *
57 * This is the basic interface for low-level configuration of the
58 * Guile library. It is used for configuring the reader, evaluator,
59 * printer and debugger.
cbff1d89
MD
60 *
61 * Motivation:
62 *
63 * 1. Altering option settings can have side effects.
64 * 2. Option values can be stored in native format.
65 * (Important for efficiency in, e. g., the evaluator.)
66 * 3. Doesn't use up name space.
67 * 4. Options can be naturally grouped => ease of use.
1a413ab9
MD
68 */
69
cbff1d89
MD
70/* scm_options is the core of all options interface procedures.
71 *
72 * Some definitions:
73 *
74 * Run time options in Guile are arranged in groups. Each group
75 * affects a certain aspect of the behaviour of the library.
76 *
77 * An "options interface procedure" manages one group of options. It
78 * can be used to check or set options, or to get documentation for
79 * all options of a group. The options interface procedure is not
80 * intended to be called directly by the user. The user should
81 * instead call
82 *
83 * (<group>-options)
84 * (<group>-options 'help)
85 * (<group>-options 'full)
86 *
87 * to display current option settings (The second version also
88 * displays documentation. The third version also displays
89 * information about programmer's options.), and
90 *
91 * (<group>-enable '<option-symbol>)
92 * (<group>-disable '<option-symbol>)
93 * (<group>-set! <option-symbol> <value>)
94 * (<group>-options <option setting>)
95 *
96 * to alter the state of an option (The last version sets all
97 * options according to <option setting>.) where <group> is the name
98 * of the option group.
99 *
100 * An "option setting" represents the state of all low-level options
101 * managed by one options interface procedure. It is a list of
102 * single symbols and symbols followed by a value.
103 *
104 * For boolean options, the presence of the symbol of that option in
105 * the option setting indicates a true value. If the symbol isn't a
a0fcb308 106 * member of the option setting this represents a false value.
cbff1d89 107 *
a0fcb308 108 * Other options are represented by a symbol followed by the value.
cbff1d89
MD
109 *
110 * If scm_options is called without arguments, the current option
111 * setting is returned. If the argument is an option setting, options
112 * are altered and the old setting is returned. If the argument isn't
113 * a list, a list of sublists is returned, where each sublist contains
114 * option name, value and documentation string.
115 */
116
117SCM_SYMBOL (scm_yes_sym, "yes");
118SCM_SYMBOL (scm_no_sym, "no");
119
11d49f54 120static SCM protected_objects = SCM_EOL;
1cc91f1b 121
11d49f54
DH
122
123/* Return a list of the current option setting. The format of an option
124 * setting is described in the above documentation. */
125static SCM
126get_option_setting (const scm_t_option options[], unsigned int n)
127{
128 unsigned int i;
129 SCM ls = SCM_EOL;
130 for (i = 0; i != n; ++i)
131 {
132 switch (options[i].type)
133 {
134 case SCM_OPTION_BOOLEAN:
135 if (options[i].val)
136 ls = scm_cons (SCM_PACK (options[i].name), ls);
137 break;
138 case SCM_OPTION_INTEGER:
139 ls = scm_cons (SCM_MAKINUM (options[i].val), ls);
140 ls = scm_cons (SCM_PACK (options[i].name), ls);
141 break;
142 case SCM_OPTION_SCM:
143 ls = scm_cons (SCM_PACK (options[i].val), ls);
144 ls = scm_cons (SCM_PACK (options[i].name), ls);
145 }
146 }
147 return ls;
148}
149
150
151/* Return a list of sublists, where each sublist contains option name, value
152 * and documentation string. */
153static SCM
154get_documented_option_setting (const scm_t_option options[], unsigned int n)
1a413ab9 155{
11d49f54
DH
156 SCM ans = SCM_EOL;
157 unsigned int i;
158
159 for (i = 0; i != n; ++i)
1a413ab9 160 {
11d49f54 161 SCM ls = scm_cons (scm_str2string (options[i].doc), SCM_EOL);
cbff1d89
MD
162 switch (options[i].type)
163 {
164 case SCM_OPTION_BOOLEAN:
11d49f54 165 ls = scm_cons (options[i].val ? scm_yes_sym : scm_no_sym, ls);
cbff1d89
MD
166 break;
167 case SCM_OPTION_INTEGER:
1be6b49c 168 ls = scm_cons (SCM_MAKINUM (options[i].val), ls);
cbff1d89
MD
169 break;
170 case SCM_OPTION_SCM:
11d49f54 171 ls = scm_cons (SCM_PACK (options[i].val), ls);
cbff1d89 172 }
11d49f54
DH
173 ls = scm_cons (SCM_PACK (options[i].name), ls);
174 ans = scm_cons (ls, ans);
175 }
176 return ans;
177}
178
179
180/* Alters options according to the given option setting 'args'. The value of
181 * args is known to be a list, but it is not known whether the list is a well
182 * formed option setting, i. e. if for every non-boolean option a value is
183 * given. For this reason, the function applies all changes to a copy of the
184 * original setting in memory. Only if 'args' was successfully processed,
185 * the new setting will overwrite the old one. */
186static void
187change_option_setting (SCM args, scm_t_option options[], unsigned int n, const char *s)
188{
189 unsigned int i;
190 SCM locally_protected_args = args;
191 SCM malloc_obj = scm_malloc_obj (n * sizeof (scm_t_bits));
192 scm_t_bits *flags = (scm_t_bits *) SCM_MALLOCDATA (malloc_obj);
193
194 for (i = 0; i != n; ++i)
195 {
196 if (options[i].type == SCM_OPTION_BOOLEAN)
197 flags[i] = 0;
198 else
199 flags[i] = options[i].val;
cbff1d89 200 }
11d49f54 201
c96d76b8 202 while (!SCM_NULL_OR_NIL_P (args))
cbff1d89 203 {
11d49f54
DH
204 SCM name = SCM_CAR (args);
205 int found = 0;
206
207 for (i = 0; i != n && !found; ++i)
1a413ab9 208 {
11d49f54
DH
209 if (SCM_EQ_P (name, SCM_PACK (options[i].name)))
210 {
1a413ab9
MD
211 switch (options[i].type)
212 {
213 case SCM_OPTION_BOOLEAN:
214 flags[i] = 1;
11d49f54 215 break;
1a413ab9 216 case SCM_OPTION_INTEGER:
11d49f54
DH
217 args = SCM_CDR (args);
218 SCM_ASSERT (SCM_CONSP (args), args, SCM_ARG1, s);
219 SCM_ASSERT (SCM_INUMP (SCM_CAR (args)), args, SCM_ARG1, s);
220 flags[i] = SCM_INUM (SCM_CAR (args));
221 break;
cbff1d89 222 case SCM_OPTION_SCM:
11d49f54
DH
223 args = SCM_CDR (args);
224 SCM_ASSERT (SCM_CONSP (args), args, SCM_ARG1, s);
225 flags[i] = SCM_UNPACK (SCM_CAR (args));
226 break;
1a413ab9 227 }
11d49f54
DH
228 found = 1;
229 }
1a413ab9 230 }
11d49f54
DH
231
232 if (!found)
233 scm_misc_error (s, "Unknown option name: ~S", scm_list_1 (name));
234
235 args = SCM_CDR (args);
236 }
237
238 for (i = 0; i != n; ++i)
239 {
240 if (options[i].type == SCM_OPTION_SCM)
263a691f 241 {
11d49f54
DH
242 SCM old = SCM_PACK (options[i].val);
243 SCM new = SCM_PACK (flags[i]);
244 if (!SCM_IMP (old))
245 protected_objects = scm_delq1_x (old, protected_objects);
246 if (!SCM_IMP (new))
247 protected_objects = scm_cons (new, protected_objects);
263a691f 248 }
11d49f54
DH
249 options[i].val = flags[i];
250 }
251
252 scm_remember_upto_here_2 (locally_protected_args, malloc_obj);
253}
254
255
256SCM
257scm_options (SCM args, scm_t_option options[], unsigned int n, const char *s)
258{
259 if (SCM_UNBNDP (args))
260 return get_option_setting (options, n);
c96d76b8 261 else if (!SCM_NULL_OR_NIL_P (args) && !SCM_CONSP (args))
11d49f54
DH
262 /* Dirk:FIXME:: This criterion should be improved. IMO it is better to
263 * demand that args is #t if documentation should be shown than to say
264 * that every argument except a list will print out documentation. */
265 return get_documented_option_setting (options, n);
266 else
267 {
268 SCM old_setting;
269 SCM_ASSERT (!SCM_FALSEP (scm_list_p (args)), args, 1, s);
270 old_setting = get_option_setting (options, n);
271 change_option_setting (args, options, n, s);
272 return old_setting;
1a413ab9 273 }
1a413ab9
MD
274}
275
1cc91f1b 276
1a413ab9 277void
11d49f54 278scm_init_opts (SCM (*func) (SCM), scm_t_option options[], unsigned int n)
1a413ab9 279{
11d49f54 280 unsigned int i;
1a413ab9 281
11d49f54 282 for (i = 0; i != n; ++i)
cbff1d89 283 {
11d49f54
DH
284 SCM name = scm_str2symbol (options[i].name);
285 options[i].name = (char *) SCM_UNPACK (name);
85db4a2c 286 scm_permanent_object (name);
cbff1d89 287 }
1a413ab9
MD
288 func (SCM_UNDEFINED);
289}
290
1cc91f1b 291
1a413ab9
MD
292void
293scm_init_options ()
1a413ab9 294{
11d49f54
DH
295 scm_gc_register_root (&protected_objects);
296
a0599745 297#include "libguile/options.x"
1a413ab9 298}
89e00824
ML
299
300/*
301 Local Variables:
302 c-file-style: "gnu"
303 End:
304*/