options.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* Copyright (C) 1995,1996,1998,2000,2001, 2006, 2008, 2009, 2010, 2011 Free Software Foundation
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include "libguile/_scm.h"
  22. #include "libguile/mallocs.h"
  23. #include "libguile/strings.h"
  24. #include "libguile/options.h"
  25. /* {Run-time options}
  26. *
  27. * This is the basic interface for low-level configuration of the
  28. * Guile library. It is used for configuring the reader, evaluator,
  29. * printer and debugger.
  30. *
  31. * Motivation:
  32. *
  33. * 1. Altering option settings can have side effects.
  34. * 2. Option values can be stored in native format.
  35. * (Important for efficiency in, e. g., the evaluator.)
  36. * 3. Doesn't use up name space.
  37. * 4. Options can be naturally grouped => ease of use.
  38. */
  39. /* scm_options is the core of all options interface procedures.
  40. *
  41. * Some definitions:
  42. *
  43. * Run time options in Guile are arranged in groups. Each group
  44. * affects a certain aspect of the behaviour of the library.
  45. *
  46. * An "options interface procedure" manages one group of options. It
  47. * can be used to check or set options, or to get documentation for
  48. * all options of a group. The options interface procedure is not
  49. * intended to be called directly by the user. The user should
  50. * instead call
  51. *
  52. * (<group>-options)
  53. * (<group>-options 'help)
  54. * (<group>-options 'full)
  55. *
  56. * to display current option settings (The second version also
  57. * displays documentation. The third version also displays
  58. * information about programmer's options.), and
  59. *
  60. * (<group>-enable '<option-symbol>)
  61. * (<group>-disable '<option-symbol>)
  62. * (<group>-set! <option-symbol> <value>)
  63. * (<group>-options <option setting>)
  64. *
  65. * to alter the state of an option (The last version sets all
  66. * options according to <option setting>.) where <group> is the name
  67. * of the option group.
  68. *
  69. * An "option setting" represents the state of all low-level options
  70. * managed by one options interface procedure. It is a list of
  71. * single symbols and symbols followed by a value.
  72. *
  73. * For boolean options, the presence of the symbol of that option in
  74. * the option setting indicates a true value. If the symbol isn't a
  75. * member of the option setting this represents a false value.
  76. *
  77. * Other options are represented by a symbol followed by the value.
  78. *
  79. * If scm_options is called without arguments, the current option
  80. * setting is returned. If the argument is an option setting, options
  81. * are altered and the old setting is returned. If the argument isn't
  82. * a list, a list of sublists is returned, where each sublist contains
  83. * option name, value and documentation string.
  84. */
  85. SCM_SYMBOL (scm_yes_sym, "yes");
  86. SCM_SYMBOL (scm_no_sym, "no");
  87. /* Return a list of the current option setting. The format of an
  88. * option setting is described in the above documentation. */
  89. static SCM
  90. get_option_setting (const scm_t_option options[])
  91. {
  92. unsigned int i;
  93. SCM ls = SCM_EOL;
  94. for (i = 0; options[i].name; ++i)
  95. {
  96. switch (options[i].type)
  97. {
  98. case SCM_OPTION_BOOLEAN:
  99. if (options[i].val)
  100. ls = scm_cons (SCM_PACK (options[i].name), ls);
  101. break;
  102. case SCM_OPTION_INTEGER:
  103. ls = scm_cons (scm_from_unsigned_integer (options[i].val), ls);
  104. ls = scm_cons (SCM_PACK (options[i].name), ls);
  105. break;
  106. case SCM_OPTION_SCM:
  107. ls = scm_cons (SCM_PACK (options[i].val), ls);
  108. ls = scm_cons (SCM_PACK (options[i].name), ls);
  109. }
  110. }
  111. return ls;
  112. }
  113. /* Return a list of sublists, where each sublist contains option name, value
  114. * and documentation string. */
  115. static SCM
  116. get_documented_option_setting (const scm_t_option options[])
  117. {
  118. SCM ans = SCM_EOL;
  119. unsigned int i;
  120. for (i = 0; options[i].name; ++i)
  121. {
  122. SCM ls = scm_cons (scm_from_utf8_string (options[i].doc), SCM_EOL);
  123. switch (options[i].type)
  124. {
  125. case SCM_OPTION_BOOLEAN:
  126. ls = scm_cons (options[i].val ? scm_yes_sym : scm_no_sym, ls);
  127. break;
  128. case SCM_OPTION_INTEGER:
  129. ls = scm_cons (scm_from_unsigned_integer (options[i].val), ls);
  130. break;
  131. case SCM_OPTION_SCM:
  132. ls = scm_cons (SCM_PACK (options[i].val), ls);
  133. }
  134. ls = scm_cons (SCM_PACK (options[i].name), ls);
  135. ans = scm_cons (ls, ans);
  136. }
  137. return scm_reverse_x (ans, SCM_UNDEFINED);
  138. }
  139. static int
  140. options_length (scm_t_option options[])
  141. {
  142. unsigned int i = 0;
  143. for (; options[i].name != NULL; ++i)
  144. ;
  145. return i;
  146. }
  147. /* Alters options according to the given option setting 'args'. The value of
  148. * args is known to be a list, but it is not known whether the list is a well
  149. * formed option setting, i. e. if for every non-boolean option a value is
  150. * given. For this reason, the function applies all changes to a copy of the
  151. * original setting in memory. Only if 'args' was successfully processed,
  152. * the new setting will overwrite the old one.
  153. *
  154. * If DRY_RUN is set, don't change anything. This is useful for trying out an option
  155. * before entering a critical section.
  156. */
  157. static void
  158. change_option_setting (SCM args, scm_t_option options[], const char *s,
  159. int dry_run)
  160. {
  161. unsigned int i;
  162. scm_t_bits *new_vals;
  163. new_vals = scm_gc_malloc (options_length (options) * sizeof (scm_t_bits),
  164. "new-options");
  165. for (i = 0; options[i].name; ++i)
  166. {
  167. if (options[i].type == SCM_OPTION_BOOLEAN)
  168. new_vals[i] = 0;
  169. else
  170. new_vals[i] = options[i].val;
  171. }
  172. while (!SCM_NULL_OR_NIL_P (args))
  173. {
  174. SCM name = SCM_CAR (args);
  175. int found = 0;
  176. for (i = 0; options[i].name && !found; ++i)
  177. {
  178. if (scm_is_eq (name, SCM_PACK (options[i].name)))
  179. {
  180. switch (options[i].type)
  181. {
  182. case SCM_OPTION_BOOLEAN:
  183. new_vals[i] = 1;
  184. break;
  185. case SCM_OPTION_INTEGER:
  186. args = SCM_CDR (args);
  187. new_vals[i] = scm_to_size_t (scm_car (args));
  188. break;
  189. case SCM_OPTION_SCM:
  190. args = SCM_CDR (args);
  191. new_vals[i] = SCM_UNPACK (scm_car (args));
  192. break;
  193. }
  194. found = 1;
  195. }
  196. }
  197. if (!found)
  198. scm_misc_error (s, "Unknown option name: ~S", scm_list_1 (name));
  199. args = SCM_CDR (args);
  200. }
  201. if (dry_run)
  202. return;
  203. for (i = 0; options[i].name; ++i)
  204. options[i].val = new_vals[i];
  205. }
  206. SCM
  207. scm_options (SCM args, scm_t_option options[], const char *s)
  208. {
  209. return scm_options_try (args, options, s, 0);
  210. }
  211. SCM
  212. scm_options_try (SCM args, scm_t_option options[], const char *s,
  213. int dry_run)
  214. {
  215. if (SCM_UNBNDP (args))
  216. return get_option_setting (options);
  217. else if (!SCM_NULL_OR_NIL_P (args) && !scm_is_pair (args))
  218. /* Dirk:FIXME:: This criterion should be improved. IMO it is better to
  219. * demand that args is #t if documentation should be shown than to say
  220. * that every argument except a list will print out documentation. */
  221. return get_documented_option_setting (options);
  222. else
  223. {
  224. SCM old_setting;
  225. SCM_ASSERT (scm_is_true (scm_list_p (args)), args, 1, s);
  226. old_setting = get_option_setting (options);
  227. change_option_setting (args, options, s, dry_run);
  228. return old_setting;
  229. }
  230. }
  231. void
  232. scm_init_opts (SCM (*func) (SCM), scm_t_option options[])
  233. {
  234. unsigned int i;
  235. for (i = 0; options[i].name; ++i)
  236. {
  237. SCM name = scm_from_utf8_symbol (options[i].name);
  238. options[i].name = (char *) SCM_UNPACK (name);
  239. }
  240. func (SCM_UNDEFINED);
  241. }
  242. void
  243. scm_init_options ()
  244. {
  245. #include "libguile/options.x"
  246. }
  247. /*
  248. Local Variables:
  249. c-file-style: "gnu"
  250. End:
  251. */