source: variable.c @ 2650a10

barnowl_perlaimdebianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 2650a10 was 52f8dd6, checked in by Nelson Elhage <nelhage@mit.edu>, 13 years ago
Remove nearly all references to the "basic" style.
  • Property mode set to 100644
File size: 40.0 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <ctype.h>
6#include "owl.h"
7
8static const char fileIdent[] = "$Id$";
9
10static int in_regtest = 0;
11
12#define OWLVAR_BOOL(name,default,summary,description) \
13        { name, OWL_VARIABLE_BOOL, NULL, default, "on,off", summary,description, NULL, \
14        NULL, NULL, NULL, NULL, NULL }
15
16#define OWLVAR_BOOL_FULL(name,default,summary,description,validate,set,get) \
17        { name, OWL_VARIABLE_BOOL, NULL, default, "on,off", summary,description, NULL, \
18        validate, set, NULL, get, NULL }
19
20#define OWLVAR_INT(name,default,summary,description) \
21        { name, OWL_VARIABLE_INT, NULL, default, "<int>", summary,description, NULL, \
22        NULL, NULL, NULL, NULL, NULL, NULL }
23
24#define OWLVAR_INT_FULL(name,default,summary,description,validset,validate,set,get) \
25        { name, OWL_VARIABLE_INT, NULL, default, validset, summary,description, NULL, \
26        validate, set, NULL, get, NULL, NULL }
27
28#define OWLVAR_PATH(name,default,summary,description) \
29        { name, OWL_VARIABLE_STRING, default, 0, "<path>", summary,description,  NULL, \
30        NULL, NULL, NULL, NULL, NULL, NULL }
31
32#define OWLVAR_STRING(name,default,summary,description) \
33        { name, OWL_VARIABLE_STRING, default, 0, "<string>", summary,description, NULL, \
34        NULL, NULL, NULL, NULL, NULL, NULL }
35
36#define OWLVAR_STRING_FULL(name,default,summary,description,validate,set,get) \
37        { name, OWL_VARIABLE_STRING, default, 0, "<string>", summary,description, NULL, \
38        validate, set, NULL, get, NULL, NULL }
39
40/* enums are really integers, but where validset is a comma-separated
41 * list of strings which can be specified.  The tokens, starting at 0,
42 * correspond to the values that may be specified. */
43#define OWLVAR_ENUM(name,default,summary,description,validset) \
44        { name, OWL_VARIABLE_INT, NULL, default, validset, summary,description, NULL, \
45        owl_variable_enum_validate, \
46        NULL, owl_variable_enum_set_fromstring, \
47        NULL, owl_variable_enum_get_tostring, \
48        NULL }
49
50#define OWLVAR_ENUM_FULL(name,default,summary,description,validset,validate, set, get) \
51        { name, OWL_VARIABLE_INT, NULL, default, validset, summary,description, NULL, \
52        validate, \
53        set, owl_variable_enum_set_fromstring, \
54        get, owl_variable_enum_get_tostring, \
55        NULL }
56
57static owl_variable variables_to_init[] = {
58
59  OWLVAR_STRING( "personalbell" /* %OwlVarStub */, "off",
60                 "ring the terminal bell when personal messages are received",
61                 "Can be set to 'on', 'off', or the name of a filter which\n"
62                 "messages need to match in order to ring the bell"),
63
64  OWLVAR_BOOL( "bell" /* %OwlVarStub */, 1,
65               "enable / disable the terminal bell", "" ),
66
67  OWLVAR_BOOL_FULL( "debug" /* %OwlVarStub */, OWL_DEBUG,
68                    "whether debugging is enabled",
69                    "If set to 'on', debugging messages are logged to the\n"
70                    "file specified by the debugfile variable.\n",
71                    NULL, owl_variable_debug_set, NULL),
72
73  OWLVAR_BOOL( "startuplogin" /* %OwlVarStub */, 1,
74               "send a login message when owl starts", "" ),
75
76  OWLVAR_BOOL( "shutdownlogout" /* %OwlVarStub */, 1,
77               "send a logout message when owl exits", "" ),
78
79  OWLVAR_BOOL( "rxping" /* %OwlVarStub */, 0,
80               "display received pings", "" ),
81
82  OWLVAR_BOOL( "txping" /* %OwlVarStub */, 1,
83               "send pings", "" ),
84
85  OWLVAR_BOOL( "sepbar_disable" /* %OwlVarStub */, 0,
86               "disable printing information in the seperator bar", "" ),
87
88  OWLVAR_BOOL( "smartstrip" /* %OwlVarStub */, 1,
89               "strip kerberos instance for reply", ""),
90
91  OWLVAR_BOOL( "newlinestrip" /* %OwlVarStub */, 1,
92               "strip leading and trailing newlines", ""),
93
94  OWLVAR_BOOL( "displayoutgoing" /* %OwlVarStub */, 1,
95               "display outgoing messages", "" ),
96
97  OWLVAR_BOOL( "loginsubs" /* %OwlVarStub */, 1,
98               "load logins from .anyone on startup", "" ),
99
100  OWLVAR_BOOL( "logging" /* %OwlVarStub */, 0,
101               "turn personal logging on or off", 
102               "If this is set to on, personal messages are\n"
103               "logged in the directory specified\n"
104               "by the 'logpath' variable.  The filename in that\n"
105               "directory is derived from the sender of the message.\n" ),
106
107  OWLVAR_BOOL( "classlogging" /* %OwlVarStub */, 0,
108               "turn class logging on or off",
109               "If this is set to on, class messages are\n"
110               "logged in the directory specified\n"
111               "by the 'classlogpath' variable.\n" 
112               "The filename in that directory is derived from\n"
113               "the name of the class to which the message was sent.\n" ),
114
115  OWLVAR_ENUM( "loggingdirection" /* %OwlVarStub */, OWL_LOGGING_DIRECTION_BOTH,
116               "specifices which kind of messages should be logged",
117               "Can be one of 'both', 'in', or 'out'.  If 'in' is\n"
118               "selected, only incoming messages are logged, if 'out'\n"
119               "is selected only outgoing messages are logged.  If 'both'\n"
120               "is selected both incoming and outgoing messages are\n"
121               "logged.",
122               "both,in,out"),
123
124  OWLVAR_BOOL( "colorztext" /* %OwlVarStub */, 1,
125               "allow @color() in zephyrs to change color",
126               "Note that only messages received after this variable\n"
127               "is set will be affected." ),
128
129  OWLVAR_BOOL( "fancylines" /* %OwlVarStub */, 1,
130               "Use 'nice' line drawing on the terminal.",
131               "If turned off, dashes, pipes and pluses will be used\n"
132               "to draw lines on the screen.  Useful when the terminal\n"
133               "is causing problems" ),
134
135  OWLVAR_BOOL( "zcrypt" /* %OwlVarStub */, 1,
136               "Do automatic zcrypt processing",
137               "" ),
138
139  OWLVAR_BOOL_FULL( "pseudologins" /* %OwlVarStub */, 0,
140                    "Enable zephyr pseudo logins",
141                    "When this is enabled, Owl will periodically check the zephyr\n"
142                    "location of users in your .anyone file.  If a user is present\n"
143                    "but sent no login message, or a user is not present that sent no\n"
144                    "logout message a pseudo login or logout message wil be created\n",
145                    NULL, owl_variable_pseudologins_set, NULL),
146
147  OWLVAR_BOOL( "ignorelogins" /* %OwlVarStub */, 0,
148               "Enable printing of login notifications",
149               "When this is enabled, Owl will print login and logout notifications\n"
150               "for AIM, zephyr, or other protocols.  If disabled Owl will not print\n"
151               "login or logout notifications.\n"),
152
153  OWLVAR_STRING( "logfilter" /* %OwlVarStub */, "",
154                 "name of a filter controlling which messages to log",
155
156                 "If non empty, any messages matching the given filter will be logged.\n"
157                 "This is a completely separate mechanisim from the other logging\n"
158                 "variables like logging, classlogging, loglogins, loggingdirection,\n"
159                 "etc.  If you want this variable to control all logging, make sure\n"
160                 "all other logging variables are in their default state.\n"),
161
162  OWLVAR_BOOL( "loglogins" /* %OwlVarStub */, 0,
163               "Enable logging of login notifications",
164               "When this is enabled, Owl will login login and logout notifications\n"
165               "for AIM, zephyr, or other protocols.  If disabled Owl will not print\n"
166               "login or logout notifications.\n"),
167
168  OWLVAR_ENUM_FULL( "disable-ctrl-d" /* %OwlVarStub:lockout_ctrld */, 1,
169                    "don't send zephyrs on C-d",
170                    "If set to 'off', C-d won't send a zephyr from the edit\n"
171                    "window.  If set to 'on', C-d will always send a zephyr\n"
172                    "being composed in the edit window.  If set to 'middle',\n"
173                    "C-d will only ever send a zephyr if the cursor is at\n"
174                    "the end of the message being composed.\n\n"
175                    "Note that this works by changing the C-d keybinding\n"
176                    "in the editmulti keymap.\n",
177                    "off,middle,on",
178                    NULL, owl_variable_disable_ctrl_d_set, NULL),
179
180  OWLVAR_BOOL( "_burningears" /* %OwlVarStub:burningears */, 0,
181               "[NOT YET IMPLEMENTED] beep on messages matching patterns", "" ),
182
183  OWLVAR_BOOL( "_summarymode" /* %OwlVarStub:summarymode */, 0,
184               "[NOT YET IMPLEMENTED]", "" ),
185
186  OWLVAR_PATH( "logpath" /* %OwlVarStub */, "~/zlog/people",
187               "path for logging personal zephyrs", 
188               "Specifies a directory which must exist.\n"
189               "Files will be created in the directory for each sender.\n"),
190
191  OWLVAR_PATH( "classlogpath" /* %OwlVarStub:classlogpath */, "~/zlog/class",
192               "path for logging class zephyrs",
193               "Specifies a directory which must exist.\n"
194               "Files will be created in the directory for each class.\n"),
195
196  OWLVAR_PATH( "debug_file" /* %OwlVarStub */, OWL_DEBUG_FILE,
197               "path for logging debug messages when debugging is enabled",
198               "This file will be logged to if 'debug' is set to 'on'.\n"),
199 
200  OWLVAR_PATH( "zsigproc" /* %OwlVarStub:zsigproc */, NULL,
201               "name of a program to run that will generate zsigs",
202               "This program should produce a zsig on stdout when run.\n"
203               "Note that it is important that this program not block.\n" ),
204
205  OWLVAR_PATH( "newmsgproc" /* %OwlVarStub:newmsgproc */, NULL,
206               "name of a program to run when new messages are present",
207               "The named program will be run when owl recevies new.\n"
208               "messages.  It will not be run again until the first\n"
209               "instance exits"),
210
211  OWLVAR_STRING( "zsender" /* %OwlVarStub */, "",
212             "zephyr sender name",
213         "Allows you to customize the outgoing username in\n"
214         "zephyrs.  If this is unset, it will use your Kerberos\n"
215         "principal. Note that customizing the sender name will\n"
216         "cause your zephyrs to be sent unauthenticated."),
217
218  OWLVAR_STRING( "zsig" /* %OwlVarStub */, "",
219                 "zephyr signature", 
220                 "If 'zsigproc' is not set, this string will be used\n"
221                 "as a zsig.  If this is also unset, the 'zwrite-signature'\n"
222                 "zephyr variable will be used instead.\n"),
223
224  OWLVAR_STRING( "appendtosepbar" /* %OwlVarStub */, "",
225                 "string to append to the end of the sepbar",
226                 "The sepbar is the bar separating the top and bottom\n"
227                 "of the owl screen.  Any string specified here will\n"
228                 "be displayed on the right of the sepbar\n"),
229
230  OWLVAR_BOOL( "zaway" /* %OwlVarStub */, 0,
231               "turn zaway on or off", "" ),
232
233  OWLVAR_STRING( "zaway_msg" /* %OwlVarStub */, 
234                 OWL_DEFAULT_ZAWAYMSG,
235                 "zaway msg for responding to zephyrs when away", "" ),
236
237  OWLVAR_STRING( "zaway_msg_default" /* %OwlVarStub */, 
238                 OWL_DEFAULT_ZAWAYMSG,
239                 "default zaway message", "" ),
240
241  OWLVAR_BOOL_FULL( "aaway" /* %OwlVarStub */, 0,
242                    "Set AIM away status",
243                    "",
244                    NULL, owl_variable_aaway_set, NULL),
245
246  OWLVAR_STRING( "aaway_msg" /* %OwlVarStub */, 
247                 OWL_DEFAULT_AAWAYMSG,
248                 "AIM away msg for responding when away", "" ),
249
250  OWLVAR_STRING( "aaway_msg_default" /* %OwlVarStub */, 
251                 OWL_DEFAULT_AAWAYMSG,
252                 "default AIM away message", "" ),
253
254  OWLVAR_STRING( "view_home" /* %OwlVarStub */, "all",
255                 "home view to switch to after 'X' and 'V'", 
256                 "SEE ALSO: view, filter\n" ),
257
258  OWLVAR_STRING( "alert_filter" /* %OwlVarStub */, "none",
259                 "filter on which to trigger alert actions",
260                 "" ),
261
262  OWLVAR_STRING( "alert_action" /* %OwlVarStub */, "nop",
263                 "owl command to execute for alert actions",
264                 "" ),
265
266  OWLVAR_STRING_FULL( "tty" /* %OwlVarStub */, "", "tty name for zephyr location", "",
267                      NULL, owl_variable_tty_set, NULL),
268
269  OWLVAR_STRING( "default_style" /* %OwlVarStub */, "__unspecified__",
270                 "name of the default formatting style",
271                 "This sets the default message formatting style.\n"
272                 "Styles may be created with the 'style' command.\n"
273                 "Some built-in styles include:\n"
274                 "   default  - the default owl formatting\n"
275                 "   oneline  - one line per-message\n"
276                 "   perl     - legacy perl interface\n"
277                 "\nSEE ALSO: style, show styles, view -s <style>\n"
278                 ),
279
280
281  OWLVAR_INT(    "edit:maxfillcols" /* %OwlVarStub:edit_maxfillcols */, 70,
282                 "maximum number of columns for M-q to fill text to",
283                 "This specifies the maximum number of columns for M-q\n"
284                 "to fill text to.  If set to 0, ther will be no maximum\n"
285                 "limit.  In all cases, the current width of the screen\n"
286                 "will also be taken into account.  It will be used instead\n"
287                 "if it is narrower than the maximum, or if this\n"
288                 "is set to 0.\n" ),
289
290  OWLVAR_INT(    "edit:maxwrapcols" /* %OwlVarStub:edit_maxwrapcols */, 0,
291                 "maximum number of columns for line-wrapping",
292                 "This specifies the maximum number of columns for\n"
293                 "auto-line-wrapping.  If set to 0, ther will be no maximum\n"
294                 "limit.  In all cases, the current width of the screen\n"
295                 "will also be taken into account.  It will be used instead\n"
296                 "if it is narrower than the maximum, or if this\n"
297                 "is set to 0.\n\n"
298                 "It is recommended that outgoing messages be no wider\n"
299                 "than 60 columns, as a courtesy to recipients.\n"),
300
301  OWLVAR_INT( "aim_ignorelogin_timer" /* %OwlVarStub */, 15,
302              "number of seconds after AIM login to ignore login messages",
303              "This specifies the number of seconds to wait after an\n"
304              "AIM login before allowing the recipt of AIM login notifications.\n"
305              "By default this is set to 15.  If you would like to view login\n"
306              "notifications of buddies as soon as you login, set it to 0 instead."),
307
308             
309  OWLVAR_INT_FULL( "typewinsize" /* %OwlVarStub:typwin_lines */, 
310                   OWL_TYPWIN_SIZE,
311                  "number of lines in the typing window", 
312                   "This specifies the height of the window at the\n"
313                   "bottom of the screen where commands are entered\n"
314                   "and where messages are composed.\n",
315                   "int > 0",
316                   owl_variable_int_validate_gt0,
317                   owl_variable_typewinsize_set,
318                   NULL /* use default for get */
319                   ),
320
321  OWLVAR_ENUM( "scrollmode" /* %OwlVarStub */, OWL_SCROLLMODE_NORMAL,
322               "how to scroll up and down",
323               "This controls how the screen is scrolled as the\n"
324               "cursor moves between messages being displayed.\n"
325               "The following modes are supported:\n\n"
326               "   normal      - This is the owl default.  Scrolling happens\n"
327               "                 when it needs to, and an attempt is made to\n"
328               "                 keep the current message roughly near\n"
329               "                 the middle of the screen.\n"
330               "   top         - The current message will always be the\n"
331               "                 the top message displayed.\n"
332               "   neartop     - The current message will be one down\n"
333               "                 from the top message displayed,\n"
334               "                 where possible.\n"
335               "   center      - An attempt is made to keep the current\n"
336               "                 message near the center of the screen.\n"
337               "   paged       - The top message displayed only changes\n"
338               "                 when user moves the cursor to the top\n"
339               "                 or bottom of the screen.  When it moves,\n"
340               "                 the screen will be paged up or down and\n"
341               "                 the cursor will be near the top or\n"
342               "                 the bottom.\n"
343               "   pagedcenter - The top message displayed only changes\n"
344               "                 when user moves the cursor to the top\n"
345               "                 or bottom of the screen.  When it moves,\n"
346               "                 the screen will be paged up or down and\n"
347               "                 the cursor will be near the center.\n",
348               "normal,top,neartop,center,paged,pagedcenter" ),
349
350  OWLVAR_ENUM( "webbrowser" /* %OwlVarStub */, OWL_WEBBROWSER_NETSCAPE,
351               "web browser to use to launch URLs",
352               "When the 'w' key is pressed, this browser is used\n"
353               "to display the requested URL.\n",
354               "none,netscape,galeon,opera" ),
355
356
357  OWLVAR_BOOL( "_followlast" /* %OwlVarStub */, 0,
358               "enable automatic following of the last zephyr",
359               "If the cursor is at the last message, it will\n"
360               "continue to follow the last message if this is set.\n"
361               "Note that this is currently risky as you might accidentally\n"
362               "delete a message right as it came in.\n" ),
363
364  /* This MUST be last... */
365  { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL,
366    NULL, NULL, NULL, NULL, NULL, NULL }
367
368};
369
370/**************************************************************************/
371/*********************** SPECIFIC TO VARIABLES ****************************/
372/**************************************************************************/
373
374
375/* commonly useful */
376
377int owl_variable_int_validate_gt0(owl_variable *v, void *newval)
378{
379  if (newval == NULL) return(0);
380  else if (*(int*)newval < 1) return(0);
381  else return (1);
382}
383
384int owl_variable_int_validate_positive(owl_variable *v, void *newval)
385{
386  if (newval == NULL) return(0);
387  else if (*(int*)newval < 0) return(0);
388  else return (1);
389}
390
391/* typewinsize */
392int owl_variable_typewinsize_set(owl_variable *v, void *newval)
393{
394  int rv;
395  rv = owl_variable_int_set_default(v, newval);
396  if (0 == rv) owl_function_resize();
397  return(rv);
398}
399
400/* debug (cache value in g->debug) */
401int owl_variable_debug_set(owl_variable *v, void *newval)
402{
403  if (newval && (*(int*)newval == 1 || *(int*)newval == 0)) {
404    g.debug = *(int*)newval;
405  }
406  return owl_variable_bool_set_default(v, newval);
407}
408
409/* When 'aaway' is changed, need to notify the AIM server */
410int owl_variable_aaway_set(owl_variable *v, void *newval)
411{
412  if (newval) {
413    if (*(int*)newval == 1) {
414      owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
415    } else if (*(int*)newval == 0) {
416      owl_aim_set_awaymsg("");
417    }
418  }
419  return owl_variable_bool_set_default(v, newval);
420}
421
422int owl_variable_pseudologins_set(owl_variable *v, void *newval)
423{
424  if (newval) {
425    if (*(int*)newval == 1) {
426      owl_function_zephyr_buddy_check(0);
427    }
428  }
429  return owl_variable_bool_set_default(v, newval);
430}
431
432/* note that changing the value of this will clobber
433 * any user setting of this */
434int owl_variable_disable_ctrl_d_set(owl_variable *v, void *newval)
435{
436
437  if (in_regtest) return owl_variable_int_set_default(v, newval);
438
439  if (newval && !owl_context_is_startup(owl_global_get_context(&g))) {
440    if (*(int*)newval == 2) {
441      owl_function_command_norv("bindkey editmulti C-d command edit:delete-next-char");
442    } else if (*(int*)newval == 1) {
443      owl_function_command_norv("bindkey editmulti C-d command editmulti:done-or-delete");
444    } else {
445      owl_function_command_norv("bindkey editmulti C-d command editmulti:done");
446    }
447  } 
448  return owl_variable_int_set_default(v, newval); 
449}
450
451int owl_variable_tty_set(owl_variable *v, void *newval)
452{
453  owl_zephyr_set_locationinfo(owl_global_get_hostname(&g), newval);
454  return(owl_variable_string_set_default(v, newval));
455}
456
457
458/**************************************************************************/
459/****************************** GENERAL ***********************************/
460/**************************************************************************/
461
462int owl_variable_dict_setup(owl_vardict *vd) {
463  owl_variable *var, *cur;
464  if (owl_dict_create(vd)) return(-1);
465  for (var = variables_to_init; var->name != NULL; var++) {
466    cur = owl_malloc(sizeof(owl_variable));
467    memcpy(cur, var, sizeof(owl_variable));
468    switch (cur->type) {
469    case OWL_VARIABLE_OTHER:
470      cur->set_fn(cur, cur->pval_default);
471      break;
472    case OWL_VARIABLE_STRING:
473      if (!cur->validate_fn) 
474        cur->validate_fn = owl_variable_string_validate_default;
475      if (!cur->set_fn) 
476        cur->set_fn = owl_variable_string_set_default;
477      if (!cur->set_fromstring_fn) 
478        cur->set_fromstring_fn = owl_variable_string_set_fromstring_default;
479      if (!cur->get_fn) 
480        cur->get_fn = owl_variable_get_default;
481      if (!cur->get_tostring_fn) 
482        cur->get_tostring_fn = owl_variable_string_get_tostring_default;     
483      if (!cur->free_fn) 
484        cur->free_fn = owl_variable_free_default;
485      cur->set_fn(cur, cur->pval_default);
486      break;
487    case OWL_VARIABLE_BOOL:
488      if (!cur->validate_fn) 
489        cur->validate_fn = owl_variable_bool_validate_default;
490      if (!cur->set_fn) 
491        cur->set_fn = owl_variable_bool_set_default;
492      if (!cur->set_fromstring_fn) 
493        cur->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
494      if (!cur->get_fn) 
495        cur->get_fn = owl_variable_get_default;
496      if (!cur->get_tostring_fn) 
497        cur->get_tostring_fn = owl_variable_bool_get_tostring_default;     
498      if (!cur->free_fn) 
499        cur->free_fn = owl_variable_free_default;
500      cur->val = owl_malloc(sizeof(int));
501      cur->set_fn(cur, &cur->ival_default);
502      break;
503    case OWL_VARIABLE_INT:
504      if (!cur->validate_fn) 
505        cur->validate_fn = owl_variable_int_validate_default;
506      if (!cur->set_fn) 
507        cur->set_fn = owl_variable_int_set_default;
508      if (!cur->set_fromstring_fn) 
509        cur->set_fromstring_fn = owl_variable_int_set_fromstring_default;
510      if (!cur->get_fn) 
511        cur->get_fn = owl_variable_get_default;
512      if (!cur->get_tostring_fn) 
513        cur->get_tostring_fn = owl_variable_int_get_tostring_default;     
514      if (!cur->free_fn) 
515        cur->free_fn = owl_variable_free_default;
516      cur->val = owl_malloc(sizeof(int));
517      cur->set_fn(cur, &cur->ival_default);
518      break;
519    default:
520      fprintf(stderr, "owl_variable_setup: invalid variable type\n");
521      return(-2);
522    }
523    owl_dict_insert_element(vd, cur->name, (void*)cur, NULL);
524  }
525  return 0;
526}
527
528void owl_variable_dict_add_variable(owl_vardict * vardict,
529                                    owl_variable * var) {
530  owl_dict_insert_element(vardict, var->name, (void*)var, (void(*)(void*))owl_variable_free);
531}
532
533owl_variable * owl_variable_newvar(char *name, char *summary, char * description) {
534  owl_variable * var = (owl_variable*)owl_malloc(sizeof(owl_variable));
535  memset(var, 0, sizeof(owl_variable));
536  var->name = owl_strdup(name);
537  var->summary = owl_strdup(summary);
538  var->description = owl_strdup(description);
539  return var;
540}
541
542void owl_variable_update(owl_variable *var, char *summary, char *desc) {
543  if(var->summary) owl_free(var->summary);
544  var->summary = owl_strdup(summary);
545  if(var->description) owl_free(var->description);
546  var->description = owl_strdup(desc);
547}
548
549void owl_variable_dict_newvar_string(owl_vardict * vd, char *name, char *summ, char * desc, char * initval) {
550  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_STRING);
551  if(old) {
552    owl_variable_update(old, summ, desc);
553    if(old->pval_default) owl_free(old->pval_default);
554    old->pval_default = owl_strdup(initval);
555  } else {
556    owl_variable * var = owl_variable_newvar(name, summ, desc);
557    var->type = OWL_VARIABLE_STRING;
558    var->pval_default = owl_strdup(initval);
559    var->set_fn = owl_variable_string_set_default;
560    var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
561    var->get_fn = owl_variable_get_default;
562    var->get_tostring_fn = owl_variable_string_get_tostring_default;
563    var->free_fn = owl_variable_free_default;
564    var->set_fn(var, initval);
565    owl_variable_dict_add_variable(vd, var);
566  }
567}
568
569void owl_variable_dict_newvar_int(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
570  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_INT);
571  if(old) {
572    owl_variable_update(old, summ, desc);
573    old->ival_default = initval;
574  } else {
575    owl_variable * var = owl_variable_newvar(name, summ, desc);
576    var->type = OWL_VARIABLE_INT;
577    var->ival_default = initval;
578    var->validate_fn = owl_variable_int_validate_default;
579    var->set_fn = owl_variable_int_set_default;
580    var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
581    var->get_fn = owl_variable_get_default;
582    var->get_tostring_fn = owl_variable_int_get_tostring_default;
583    var->free_fn = owl_variable_free_default;
584    var->val = owl_malloc(sizeof(int));
585    var->set_fn(var, &initval);
586    owl_variable_dict_add_variable(vd, var);
587  }
588}
589
590void owl_variable_dict_newvar_bool(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
591  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_BOOL);
592  if(old) {
593    owl_variable_update(old, summ, desc);
594    old->ival_default = initval;
595  } else {
596    owl_variable * var = owl_variable_newvar(name, summ, desc);
597    var->type = OWL_VARIABLE_BOOL;
598    var->ival_default = initval;
599    var->validate_fn = owl_variable_bool_validate_default;
600    var->set_fn = owl_variable_bool_set_default;
601    var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
602    var->get_fn = owl_variable_get_default;
603    var->get_tostring_fn = owl_variable_bool_get_tostring_default;
604    var->free_fn = owl_variable_free_default;
605    var->val = owl_malloc(sizeof(int));
606    var->set_fn(var, &initval);
607    owl_variable_dict_add_variable(vd, var);
608  }
609}
610
611void owl_variable_dict_free(owl_vardict *d) {
612  owl_dict_free_all(d, (void(*)(void*))owl_variable_free);
613}
614
615/* free the list with owl_variable_dict_namelist_free */
616void owl_variable_dict_get_names(owl_vardict *d, owl_list *l) {
617  owl_dict_get_keys(d, l);
618}
619
620void owl_variable_dict_namelist_free(owl_list *l) {
621  owl_list_free_all(l, owl_free);
622}
623
624void owl_variable_free(owl_variable *v) {
625  if (v->free_fn) v->free_fn(v);
626  owl_free(v);
627}
628
629
630char *owl_variable_get_description(owl_variable *v) {
631  return v->description;
632}
633
634char *owl_variable_get_summary(owl_variable *v) {
635  return v->summary;
636}
637
638char *owl_variable_get_validsettings(owl_variable *v) {
639  if (v->validsettings) {
640    return v->validsettings;
641  } else {
642    return "";
643  }
644}
645
646/* functions for getting and setting variable values */
647
648/* returns 0 on success, prints a status msg if msg is true */
649int owl_variable_set_fromstring(owl_vardict *d, char *name, char *value, int msg, int requirebool) {
650  owl_variable *v;
651  char buff2[1024];
652  if (!name) return(-1);
653  v = owl_dict_find_element(d, name);
654  if (v == NULL) {
655    if (msg) owl_function_error("Unknown variable %s", name);
656    return -1;
657  }
658  if (!v->set_fromstring_fn) {
659    if (msg) owl_function_error("Variable %s is read-only", name);
660    return -1;   
661  }
662  if (requirebool && v->type!=OWL_VARIABLE_BOOL) {
663    if (msg) owl_function_error("Variable %s is not a boolean", name);
664    return -1;   
665  }
666  if (0 != v->set_fromstring_fn(v, value)) {
667    if (msg) owl_function_error("Unable to set %s (must be %s)", name, 
668                                  owl_variable_get_validsettings(v));
669    return -1;
670  }
671  if (msg && v->get_tostring_fn) {
672    v->get_tostring_fn(v, buff2, 1024, v->val);
673    owl_function_makemsg("%s = '%s'", name, buff2);
674  }   
675  return 0;
676}
677 
678int owl_variable_set_string(owl_vardict *d, char *name, char *newval) {
679  owl_variable *v;
680  if (!name) return(-1);
681  v = owl_dict_find_element(d, name);
682  if (v == NULL || !v->set_fn) return(-1);
683  if (v->type!=OWL_VARIABLE_STRING) return(-1);
684  return v->set_fn(v, (void*)newval);
685}
686 
687int owl_variable_set_int(owl_vardict *d, char *name, int newval) {
688  owl_variable *v;
689  if (!name) return(-1);
690  v = owl_dict_find_element(d, name);
691  if (v == NULL || !v->set_fn) return(-1);
692  if (v->type!=OWL_VARIABLE_INT && v->type!=OWL_VARIABLE_BOOL) return(-1);
693  return v->set_fn(v, &newval);
694}
695 
696int owl_variable_set_bool_on(owl_vardict *d, char *name) {
697  return owl_variable_set_int(d,name,1);
698}
699
700int owl_variable_set_bool_off(owl_vardict *d, char *name) {
701  return owl_variable_set_int(d,name,0);
702}
703
704int owl_variable_get_tostring(owl_vardict *d, char *name, char *buf, int bufsize) {
705  owl_variable *v;
706  if (!name) return(-1);
707  v = owl_dict_find_element(d, name);
708  if (v == NULL || !v->get_tostring_fn) return(-1);
709  return v->get_tostring_fn(v, buf, bufsize, v->val);
710}
711
712int owl_variable_get_default_tostring(owl_vardict *d, char *name, char *buf, int bufsize) {
713  owl_variable *v;
714  if (!name) return(-1);
715  v = owl_dict_find_element(d, name);
716  if (v == NULL || !v->get_tostring_fn) return(-1);
717  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
718    return v->get_tostring_fn(v, buf, bufsize, &(v->ival_default));
719  } else {
720    return v->get_tostring_fn(v, buf, bufsize, v->pval_default);
721  }
722}
723
724owl_variable *owl_variable_get_var(owl_vardict *d, char *name, int require_type) {
725  owl_variable *v;
726  if (!name) return(NULL);
727  v = owl_dict_find_element(d, name);
728  if (v == NULL || !v->get_fn || v->type != require_type) return(NULL);
729  return v;
730}
731
732/* returns a reference */
733void *owl_variable_get(owl_vardict *d, char *name, int require_type) {
734  owl_variable *v = owl_variable_get_var(d, name, require_type);
735  if(v == NULL) return NULL;
736  return v->get_fn(v);
737}
738
739/* returns a reference */
740char *owl_variable_get_string(owl_vardict *d, char *name) {
741  return (char*)owl_variable_get(d,name, OWL_VARIABLE_STRING);
742}
743
744/* returns a reference */
745void *owl_variable_get_other(owl_vardict *d, char *name) {
746  return (char*)owl_variable_get(d,name, OWL_VARIABLE_OTHER);
747}
748
749int owl_variable_get_int(owl_vardict *d, char *name) {
750  int *pi;
751  pi = (int*)owl_variable_get(d,name,OWL_VARIABLE_INT);
752  if (!pi) return(-1);
753  return(*pi);
754}
755
756int owl_variable_get_bool(owl_vardict *d, char *name) {
757  int *pi;
758  pi = (int*)owl_variable_get(d,name,OWL_VARIABLE_BOOL);
759  if (!pi) return(-1);
760  return(*pi);
761}
762
763void owl_variable_describe(owl_vardict *d, char *name, owl_fmtext *fm) {
764  char defaultbuf[50];
765  char buf[1024];
766  int buflen = 1023;
767  owl_variable *v;
768
769  if (!name
770      || (v = owl_dict_find_element(d, name)) == NULL 
771      || !v->get_fn) {
772    snprintf(buf, buflen, "     No such variable '%s'\n", name);     
773    owl_fmtext_append_normal(fm, buf);
774    return;
775  }
776  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
777    v->get_tostring_fn(v, defaultbuf, 50, &(v->ival_default));
778  } else {
779    v->get_tostring_fn(v, defaultbuf, 50, v->pval_default);
780  }
781  snprintf(buf, buflen, OWL_TABSTR "%-20s - %s (default: '%s')\n", 
782                  v->name, 
783                  owl_variable_get_summary(v), defaultbuf);
784  owl_fmtext_append_normal(fm, buf);
785}
786
787void owl_variable_get_help(owl_vardict *d, char *name, owl_fmtext *fm) {
788  char buff[1024];
789  int bufflen = 1023;
790  owl_variable *v;
791
792  if (!name
793      || (v = owl_dict_find_element(d, name)) == NULL 
794      || !v->get_fn) {
795    owl_fmtext_append_normal(fm, "No such variable...\n");
796    return;
797  }
798
799  owl_fmtext_append_bold(fm, "OWL VARIABLE\n\n");
800  owl_fmtext_append_normal(fm, OWL_TABSTR);
801  owl_fmtext_append_normal(fm, name);
802  owl_fmtext_append_normal(fm, " - ");
803  owl_fmtext_append_normal(fm, v->summary);
804  owl_fmtext_append_normal(fm, "\n\n");
805
806  owl_fmtext_append_normal(fm, "Current:        ");
807  owl_variable_get_tostring(d, name, buff, bufflen);
808  owl_fmtext_append_normal(fm, buff);
809  owl_fmtext_append_normal(fm, "\n\n");
810
811
812  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
813    v->get_tostring_fn(v, buff, bufflen, &(v->ival_default));
814  } else {
815    v->get_tostring_fn(v, buff, bufflen, v->pval_default);
816  }
817  owl_fmtext_append_normal(fm, "Default:        ");
818  owl_fmtext_append_normal(fm, buff);
819  owl_fmtext_append_normal(fm, "\n\n");
820
821  owl_fmtext_append_normal(fm, "Valid Settings: ");
822  owl_fmtext_append_normal(fm, owl_variable_get_validsettings(v));
823  owl_fmtext_append_normal(fm, "\n\n");
824
825  if (v->description && *v->description) {
826    owl_fmtext_append_normal(fm, "Description:\n");
827    owl_fmtext_append_normal(fm, owl_variable_get_description(v));
828    owl_fmtext_append_normal(fm, "\n\n");
829  }
830}
831
832
833
834
835/**************************************************************************/
836/*********************** GENERAL TYPE-SPECIFIC ****************************/
837/**************************************************************************/
838
839/* default common functions */
840
841void *owl_variable_get_default(owl_variable *v) {
842  return v->val;
843}
844
845void owl_variable_free_default(owl_variable *v) {
846  if (v->val) owl_free(v->val);
847}
848
849/* default functions for booleans */
850
851int owl_variable_bool_validate_default(owl_variable *v, void *newval) {
852  if (newval == NULL) return(0);
853  else if (*(int*)newval==1 || *(int*)newval==0) return(1);
854  else return (0);
855}
856
857int owl_variable_bool_set_default(owl_variable *v, void *newval) {
858  if (v->validate_fn) {
859    if (!v->validate_fn(v, newval)) return(-1);
860  }
861  *(int*)v->val = *(int*)newval;
862  return(0);
863}
864
865int owl_variable_bool_set_fromstring_default(owl_variable *v, char *newval) {
866  int i;
867  if (!strcmp(newval, "on")) i=1;
868  else if (!strcmp(newval, "off")) i=0;
869  else return(-1);
870  return (v->set_fn(v, &i));
871}
872
873int owl_variable_bool_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
874  if (val == NULL) {
875    snprintf(buf, bufsize, "<null>");
876    return -1;
877  } else if (*(int*)val == 0) {
878    snprintf(buf, bufsize, "off");
879    return 0;
880  } else if (*(int*)val == 1) {
881    snprintf(buf, bufsize, "on");
882    return 0;
883  } else {
884    snprintf(buf, bufsize, "<invalid>");
885    return -1;
886  }
887}
888
889/* default functions for integers */
890
891int owl_variable_int_validate_default(owl_variable *v, void *newval) {
892  if (newval == NULL) return(0);
893  else return (1);
894}
895
896int owl_variable_int_set_default(owl_variable *v, void *newval) {
897  if (v->validate_fn) {
898    if (!v->validate_fn(v, newval)) return(-1);
899  }
900  *(int*)v->val = *(int*)newval;
901  return(0);
902}
903
904int owl_variable_int_set_fromstring_default(owl_variable *v, char *newval) {
905  int i;
906  char *ep = "x";
907  i = strtol(newval, &ep, 10);
908  if (*ep || ep==newval) return(-1);
909  return (v->set_fn(v, &i));
910}
911
912int owl_variable_int_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
913  if (val == NULL) {
914    snprintf(buf, bufsize, "<null>");
915    return -1;
916  } else {
917    snprintf(buf, bufsize, "%d", *(int*)val);
918    return 0;
919  } 
920}
921
922/* default functions for enums (a variant of integers) */
923
924int owl_variable_enum_validate(owl_variable *v, void *newval) { 
925  char **enums;
926  int nenums, val;
927  if (newval == NULL) return(0);
928  enums = atokenize(v->validsettings, ",", &nenums);
929  if (enums == NULL) return(0);
930  atokenize_free(enums, nenums);
931  val = *(int*)newval;
932  if (val < 0 || val >= nenums) {
933    return(0);
934  }
935  return(1);
936}
937
938int owl_variable_enum_set_fromstring(owl_variable *v, char *newval) {
939  char **enums;
940  int nenums, i, val=-1;
941  if (newval == NULL) return(-1);
942  enums = atokenize(v->validsettings, ",", &nenums);
943  if (enums == NULL) return(-1);
944  for (i=0; i<nenums; i++) {
945    if (0==strcmp(newval, enums[i])) {
946      val = i;
947    }
948  }
949  atokenize_free(enums, nenums);
950  if (val == -1) return(-1);
951  return (v->set_fn(v, &val));
952}
953
954int owl_variable_enum_get_tostring(owl_variable *v, char* buf, int bufsize, void *val) {
955  char **enums;
956  int nenums, i;
957
958  if (val == NULL) {
959    snprintf(buf, bufsize, "<null>");
960    return -1;
961  }
962  enums = atokenize(v->validsettings, ",", &nenums);
963  i = *(int*)val;
964  if (i<0 || i>=nenums) {
965    snprintf(buf, bufsize, "<invalid:%d>",i);
966    atokenize_free(enums, nenums);
967    return(-1);
968  }
969  snprintf(buf, bufsize, "%s", enums[i]);
970  return 0;
971}
972
973/* default functions for stringeans */
974
975int owl_variable_string_validate_default(struct _owl_variable *v, void *newval) {
976  if (newval == NULL) return(0);
977  else return (1);
978}
979
980int owl_variable_string_set_default(owl_variable *v, void *newval) {
981  if (v->validate_fn) {
982    if (!v->validate_fn(v, newval)) return(-1);
983  }
984  if (v->val) owl_free(v->val);
985  v->val = owl_strdup(newval);
986  return(0);
987}
988
989int owl_variable_string_set_fromstring_default(owl_variable *v, char *newval) {
990  return (v->set_fn(v, newval));
991}
992
993int owl_variable_string_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
994  if (val == NULL) {
995    snprintf(buf, bufsize, "<null>");
996    return -1;
997  } else {
998    snprintf(buf, bufsize, "%s", (char*)val);
999    return 0;
1000  }
1001}
1002
1003
1004
1005/**************************************************************************/
1006/************************* REGRESSION TESTS *******************************/
1007/**************************************************************************/
1008
1009#ifdef OWL_INCLUDE_REG_TESTS
1010
1011#include "test.h"
1012
1013int owl_variable_regtest(void) {
1014  owl_vardict vd;
1015  int numfailed=0;
1016  char buf[1024];
1017  owl_variable * v;
1018
1019  in_regtest = 1;
1020
1021  printf("# BEGIN testing owl_variable\n");
1022  FAIL_UNLESS("setup", 0==owl_variable_dict_setup(&vd));
1023
1024  FAIL_UNLESS("get bool", 0==owl_variable_get_bool(&vd,"rxping"));
1025  FAIL_UNLESS("get bool (no such)", -1==owl_variable_get_bool(&vd,"mumble"));
1026  FAIL_UNLESS("get bool as string 1", 0==owl_variable_get_tostring(&vd,"rxping", buf, 1024));
1027  FAIL_UNLESS("get bool as string 2", 0==strcmp(buf,"off"));
1028  FAIL_UNLESS("set bool 1", 0==owl_variable_set_bool_on(&vd,"rxping"));
1029  FAIL_UNLESS("get bool 2", 1==owl_variable_get_bool(&vd,"rxping"));
1030  FAIL_UNLESS("set bool 3", 0==owl_variable_set_fromstring(&vd,"rxping","off",0,0));
1031  FAIL_UNLESS("get bool 4", 0==owl_variable_get_bool(&vd,"rxping"));
1032  FAIL_UNLESS("set bool 5", -1==owl_variable_set_fromstring(&vd,"rxping","xxx",0,0));
1033  FAIL_UNLESS("get bool 6", 0==owl_variable_get_bool(&vd,"rxping"));
1034
1035
1036  FAIL_UNLESS("get string", 0==strcmp("~/zlog/people", owl_variable_get_string(&vd,"logpath")));
1037  FAIL_UNLESS("set string 7", 0==owl_variable_set_string(&vd,"logpath","whee"));
1038  FAIL_UNLESS("get string", 0==strcmp("whee", owl_variable_get_string(&vd,"logpath")));
1039
1040  FAIL_UNLESS("get int", 8==owl_variable_get_int(&vd,"typewinsize"));
1041  FAIL_UNLESS("get int (no such)", -1==owl_variable_get_int(&vd,"mmble"));
1042  FAIL_UNLESS("get int as string 1", 0==owl_variable_get_tostring(&vd,"typewinsize", buf, 1024));
1043  FAIL_UNLESS("get int as string 2", 0==strcmp(buf,"8"));
1044  FAIL_UNLESS("set int 1", 0==owl_variable_set_int(&vd,"typewinsize",12));
1045  FAIL_UNLESS("get int 2", 12==owl_variable_get_int(&vd,"typewinsize"));
1046  FAIL_UNLESS("set int 1b", -1==owl_variable_set_int(&vd,"typewinsize",-3));
1047  FAIL_UNLESS("get int 2b", 12==owl_variable_get_int(&vd,"typewinsize"));
1048  FAIL_UNLESS("set int 3", 0==owl_variable_set_fromstring(&vd,"typewinsize","9",0,0));
1049  FAIL_UNLESS("get int 4", 9==owl_variable_get_int(&vd,"typewinsize"));
1050  FAIL_UNLESS("set int 5", -1==owl_variable_set_fromstring(&vd,"typewinsize","xxx",0,0));
1051  FAIL_UNLESS("set int 6", -1==owl_variable_set_fromstring(&vd,"typewinsize","",0,0));
1052  FAIL_UNLESS("get int 7", 9==owl_variable_get_int(&vd,"typewinsize"));
1053
1054  FAIL_UNLESS("get enum", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1055  FAIL_UNLESS("get enum as string 1", 0==owl_variable_get_tostring(&vd,"webbrowser", buf, 1024));
1056  FAIL_UNLESS("get enum as string 2", 0==strcmp(buf,"netscape"));
1057  FAIL_UNLESS("set enum 1", 0==owl_variable_set_int(&vd,"webbrowser",OWL_WEBBROWSER_GALEON));
1058  FAIL_UNLESS("get enum 2", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
1059  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",-3));
1060  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",209));
1061  FAIL_UNLESS("get enum 2b", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
1062  FAIL_UNLESS("set enum 3", 0==owl_variable_set_fromstring(&vd,"webbrowser","none",0,0));
1063  FAIL_UNLESS("get enum 4", OWL_WEBBROWSER_NONE==owl_variable_get_int(&vd,"webbrowser"));
1064  FAIL_UNLESS("set enum 5", 0==owl_variable_set_fromstring(&vd,"webbrowser","netscape",0,0));
1065  FAIL_UNLESS("get enum 6", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1066  FAIL_UNLESS("set enum 7", -1==owl_variable_set_fromstring(&vd,"webbrowser","xxx",0,0));
1067  FAIL_UNLESS("set enum 8", -1==owl_variable_set_fromstring(&vd,"webbrowser","",0,0));
1068  FAIL_UNLESS("set enum 9", -1==owl_variable_set_fromstring(&vd,"webbrowser","netscapey",0,0));
1069  FAIL_UNLESS("get enum 10", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1070
1071  owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
1072  FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(&vd, "stringvar", OWL_VARIABLE_STRING)));
1073  FAIL_UNLESS("get new string val", !strcmp("testval", owl_variable_get_string(&vd, "stringvar")));
1074  owl_variable_set_string(&vd, "stringvar", "new val");
1075  FAIL_UNLESS("update string val", !strcmp("new val", owl_variable_get_string(&vd, "stringvar")));
1076
1077  owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47);
1078  FAIL_UNLESS("get new int var", NULL != (v = owl_variable_get(&vd, "intvar", OWL_VARIABLE_INT)));
1079  FAIL_UNLESS("get new int val", 47 == owl_variable_get_int(&vd, "intvar"));
1080  owl_variable_set_int(&vd, "intvar", 17);
1081  FAIL_UNLESS("update bool val", 17 == owl_variable_get_int(&vd, "intvar"));
1082
1083  owl_variable_dict_newvar_bool(&vd, "boolvar", "", "", 1);
1084  FAIL_UNLESS("get new bool var", NULL != (v = owl_variable_get(&vd, "boolvar", OWL_VARIABLE_BOOL)));
1085  FAIL_UNLESS("get new bool val", owl_variable_get_bool(&vd, "boolvar"));
1086  owl_variable_set_bool_off(&vd, "boolvar");
1087  FAIL_UNLESS("update string val", !owl_variable_get_bool(&vd, "boolvar"));
1088
1089  owl_variable_dict_free(&vd);
1090
1091  /* if (numfailed) printf("*** WARNING: failures encountered with owl_variable\n"); */
1092  printf("# END testing owl_variable (%d failures)\n", numfailed);
1093  return(numfailed);
1094}
1095
1096
1097#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.