source: variable.c @ 4cc0ee0b

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4cc0ee0b was 247cbc9, checked in by Geoffrey Thomas <geofft@mit.edu>, 17 years ago
Add the variable 'zsender' to customize the outgoing Zephyr username.
  • 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                 "   basic    - simple formatting\n"
276                 "   oneline  - one line per-message\n"
277                 "   perl     - legacy perl interface\n"
278                 "\nSEE ALSO: style, show styles, view -s <style>\n"
279                 ),
280
281
282  OWLVAR_INT(    "edit:maxfillcols" /* %OwlVarStub:edit_maxfillcols */, 70,
283                 "maximum number of columns for M-q to fill text to",
284                 "This specifies the maximum number of columns for M-q\n"
285                 "to fill text to.  If set to 0, ther will be no maximum\n"
286                 "limit.  In all cases, the current width of the screen\n"
287                 "will also be taken into account.  It will be used instead\n"
288                 "if it is narrower than the maximum, or if this\n"
289                 "is set to 0.\n" ),
290
291  OWLVAR_INT(    "edit:maxwrapcols" /* %OwlVarStub:edit_maxwrapcols */, 0,
292                 "maximum number of columns for line-wrapping",
293                 "This specifies the maximum number of columns for\n"
294                 "auto-line-wrapping.  If set to 0, ther will be no maximum\n"
295                 "limit.  In all cases, the current width of the screen\n"
296                 "will also be taken into account.  It will be used instead\n"
297                 "if it is narrower than the maximum, or if this\n"
298                 "is set to 0.\n\n"
299                 "It is recommended that outgoing messages be no wider\n"
300                 "than 60 columns, as a courtesy to recipients.\n"),
301
302  OWLVAR_INT( "aim_ignorelogin_timer" /* %OwlVarStub */, 15,
303              "number of seconds after AIM login to ignore login messages",
304              "This specifies the number of seconds to wait after an\n"
305              "AIM login before allowing the recipt of AIM login notifications.\n"
306              "By default this is set to 15.  If you would like to view login\n"
307              "notifications of buddies as soon as you login, set it to 0 instead."),
308
309             
310  OWLVAR_INT_FULL( "typewinsize" /* %OwlVarStub:typwin_lines */, 
311                   OWL_TYPWIN_SIZE,
312                  "number of lines in the typing window", 
313                   "This specifies the height of the window at the\n"
314                   "bottom of the screen where commands are entered\n"
315                   "and where messages are composed.\n",
316                   "int > 0",
317                   owl_variable_int_validate_gt0,
318                   owl_variable_typewinsize_set,
319                   NULL /* use default for get */
320                   ),
321
322  OWLVAR_ENUM( "scrollmode" /* %OwlVarStub */, OWL_SCROLLMODE_NORMAL,
323               "how to scroll up and down",
324               "This controls how the screen is scrolled as the\n"
325               "cursor moves between messages being displayed.\n"
326               "The following modes are supported:\n\n"
327               "   normal      - This is the owl default.  Scrolling happens\n"
328               "                 when it needs to, and an attempt is made to\n"
329               "                 keep the current message roughly near\n"
330               "                 the middle of the screen.\n"
331               "   top         - The current message will always be the\n"
332               "                 the top message displayed.\n"
333               "   neartop     - The current message will be one down\n"
334               "                 from the top message displayed,\n"
335               "                 where possible.\n"
336               "   center      - An attempt is made to keep the current\n"
337               "                 message near the center of the screen.\n"
338               "   paged       - The top message displayed only changes\n"
339               "                 when user moves the cursor to the top\n"
340               "                 or bottom of the screen.  When it moves,\n"
341               "                 the screen will be paged up or down and\n"
342               "                 the cursor will be near the top or\n"
343               "                 the bottom.\n"
344               "   pagedcenter - The top message displayed only changes\n"
345               "                 when user moves the cursor to the top\n"
346               "                 or bottom of the screen.  When it moves,\n"
347               "                 the screen will be paged up or down and\n"
348               "                 the cursor will be near the center.\n",
349               "normal,top,neartop,center,paged,pagedcenter" ),
350
351  OWLVAR_ENUM( "webbrowser" /* %OwlVarStub */, OWL_WEBBROWSER_NETSCAPE,
352               "web browser to use to launch URLs",
353               "When the 'w' key is pressed, this browser is used\n"
354               "to display the requested URL.\n",
355               "none,netscape,galeon,opera" ),
356
357
358  OWLVAR_BOOL( "_followlast" /* %OwlVarStub */, 0,
359               "enable automatic following of the last zephyr",
360               "If the cursor is at the last message, it will\n"
361               "continue to follow the last message if this is set.\n"
362               "Note that this is currently risky as you might accidentally\n"
363               "delete a message right as it came in.\n" ),
364
365  /* This MUST be last... */
366  { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL,
367    NULL, NULL, NULL, NULL, NULL, NULL }
368
369};
370
371/**************************************************************************/
372/*********************** SPECIFIC TO VARIABLES ****************************/
373/**************************************************************************/
374
375
376/* commonly useful */
377
378int owl_variable_int_validate_gt0(owl_variable *v, void *newval)
379{
380  if (newval == NULL) return(0);
381  else if (*(int*)newval < 1) return(0);
382  else return (1);
383}
384
385int owl_variable_int_validate_positive(owl_variable *v, void *newval)
386{
387  if (newval == NULL) return(0);
388  else if (*(int*)newval < 0) return(0);
389  else return (1);
390}
391
392/* typewinsize */
393int owl_variable_typewinsize_set(owl_variable *v, void *newval)
394{
395  int rv;
396  rv = owl_variable_int_set_default(v, newval);
397  if (0 == rv) owl_function_resize();
398  return(rv);
399}
400
401/* debug (cache value in g->debug) */
402int owl_variable_debug_set(owl_variable *v, void *newval)
403{
404  if (newval && (*(int*)newval == 1 || *(int*)newval == 0)) {
405    g.debug = *(int*)newval;
406  }
407  return owl_variable_bool_set_default(v, newval);
408}
409
410/* When 'aaway' is changed, need to notify the AIM server */
411int owl_variable_aaway_set(owl_variable *v, void *newval)
412{
413  if (newval) {
414    if (*(int*)newval == 1) {
415      owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
416    } else if (*(int*)newval == 0) {
417      owl_aim_set_awaymsg("");
418    }
419  }
420  return owl_variable_bool_set_default(v, newval);
421}
422
423int owl_variable_pseudologins_set(owl_variable *v, void *newval)
424{
425  if (newval) {
426    if (*(int*)newval == 1) {
427      owl_function_zephyr_buddy_check(0);
428    }
429  }
430  return owl_variable_bool_set_default(v, newval);
431}
432
433/* note that changing the value of this will clobber
434 * any user setting of this */
435int owl_variable_disable_ctrl_d_set(owl_variable *v, void *newval)
436{
437
438  if (in_regtest) return owl_variable_int_set_default(v, newval);
439
440  if (newval && !owl_context_is_startup(owl_global_get_context(&g))) {
441    if (*(int*)newval == 2) {
442      owl_function_command_norv("bindkey editmulti C-d command edit:delete-next-char");
443    } else if (*(int*)newval == 1) {
444      owl_function_command_norv("bindkey editmulti C-d command editmulti:done-or-delete");
445    } else {
446      owl_function_command_norv("bindkey editmulti C-d command editmulti:done");
447    }
448  } 
449  return owl_variable_int_set_default(v, newval); 
450}
451
452int owl_variable_tty_set(owl_variable *v, void *newval)
453{
454  owl_zephyr_set_locationinfo(owl_global_get_hostname(&g), newval);
455  return(owl_variable_string_set_default(v, newval));
456}
457
458
459/**************************************************************************/
460/****************************** GENERAL ***********************************/
461/**************************************************************************/
462
463int owl_variable_dict_setup(owl_vardict *vd) {
464  owl_variable *var, *cur;
465  if (owl_dict_create(vd)) return(-1);
466  for (var = variables_to_init; var->name != NULL; var++) {
467    cur = owl_malloc(sizeof(owl_variable));
468    memcpy(cur, var, sizeof(owl_variable));
469    switch (cur->type) {
470    case OWL_VARIABLE_OTHER:
471      cur->set_fn(cur, cur->pval_default);
472      break;
473    case OWL_VARIABLE_STRING:
474      if (!cur->validate_fn) 
475        cur->validate_fn = owl_variable_string_validate_default;
476      if (!cur->set_fn) 
477        cur->set_fn = owl_variable_string_set_default;
478      if (!cur->set_fromstring_fn) 
479        cur->set_fromstring_fn = owl_variable_string_set_fromstring_default;
480      if (!cur->get_fn) 
481        cur->get_fn = owl_variable_get_default;
482      if (!cur->get_tostring_fn) 
483        cur->get_tostring_fn = owl_variable_string_get_tostring_default;     
484      if (!cur->free_fn) 
485        cur->free_fn = owl_variable_free_default;
486      cur->set_fn(cur, cur->pval_default);
487      break;
488    case OWL_VARIABLE_BOOL:
489      if (!cur->validate_fn) 
490        cur->validate_fn = owl_variable_bool_validate_default;
491      if (!cur->set_fn) 
492        cur->set_fn = owl_variable_bool_set_default;
493      if (!cur->set_fromstring_fn) 
494        cur->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
495      if (!cur->get_fn) 
496        cur->get_fn = owl_variable_get_default;
497      if (!cur->get_tostring_fn) 
498        cur->get_tostring_fn = owl_variable_bool_get_tostring_default;     
499      if (!cur->free_fn) 
500        cur->free_fn = owl_variable_free_default;
501      cur->val = owl_malloc(sizeof(int));
502      cur->set_fn(cur, &cur->ival_default);
503      break;
504    case OWL_VARIABLE_INT:
505      if (!cur->validate_fn) 
506        cur->validate_fn = owl_variable_int_validate_default;
507      if (!cur->set_fn) 
508        cur->set_fn = owl_variable_int_set_default;
509      if (!cur->set_fromstring_fn) 
510        cur->set_fromstring_fn = owl_variable_int_set_fromstring_default;
511      if (!cur->get_fn) 
512        cur->get_fn = owl_variable_get_default;
513      if (!cur->get_tostring_fn) 
514        cur->get_tostring_fn = owl_variable_int_get_tostring_default;     
515      if (!cur->free_fn) 
516        cur->free_fn = owl_variable_free_default;
517      cur->val = owl_malloc(sizeof(int));
518      cur->set_fn(cur, &cur->ival_default);
519      break;
520    default:
521      fprintf(stderr, "owl_variable_setup: invalid variable type\n");
522      return(-2);
523    }
524    owl_dict_insert_element(vd, cur->name, (void*)cur, NULL);
525  }
526  return 0;
527}
528
529void owl_variable_dict_add_variable(owl_vardict * vardict,
530                                    owl_variable * var) {
531  owl_dict_insert_element(vardict, var->name, (void*)var, (void(*)(void*))owl_variable_free);
532}
533
534owl_variable * owl_variable_newvar(char *name, char *summary, char * description) {
535  owl_variable * var = (owl_variable*)owl_malloc(sizeof(owl_variable));
536  memset(var, 0, sizeof(owl_variable));
537  var->name = owl_strdup(name);
538  var->summary = owl_strdup(summary);
539  var->description = owl_strdup(description);
540  return var;
541}
542
543void owl_variable_update(owl_variable *var, char *summary, char *desc) {
544  if(var->summary) owl_free(var->summary);
545  var->summary = owl_strdup(summary);
546  if(var->description) owl_free(var->description);
547  var->description = owl_strdup(desc);
548}
549
550void owl_variable_dict_newvar_string(owl_vardict * vd, char *name, char *summ, char * desc, char * initval) {
551  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_STRING);
552  if(old) {
553    owl_variable_update(old, summ, desc);
554    if(old->pval_default) owl_free(old->pval_default);
555    old->pval_default = owl_strdup(initval);
556  } else {
557    owl_variable * var = owl_variable_newvar(name, summ, desc);
558    var->type = OWL_VARIABLE_STRING;
559    var->pval_default = owl_strdup(initval);
560    var->set_fn = owl_variable_string_set_default;
561    var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
562    var->get_fn = owl_variable_get_default;
563    var->get_tostring_fn = owl_variable_string_get_tostring_default;
564    var->free_fn = owl_variable_free_default;
565    var->set_fn(var, initval);
566    owl_variable_dict_add_variable(vd, var);
567  }
568}
569
570void owl_variable_dict_newvar_int(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
571  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_INT);
572  if(old) {
573    owl_variable_update(old, summ, desc);
574    old->ival_default = initval;
575  } else {
576    owl_variable * var = owl_variable_newvar(name, summ, desc);
577    var->type = OWL_VARIABLE_INT;
578    var->ival_default = initval;
579    var->validate_fn = owl_variable_int_validate_default;
580    var->set_fn = owl_variable_int_set_default;
581    var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
582    var->get_fn = owl_variable_get_default;
583    var->get_tostring_fn = owl_variable_int_get_tostring_default;
584    var->free_fn = owl_variable_free_default;
585    var->val = owl_malloc(sizeof(int));
586    var->set_fn(var, &initval);
587    owl_variable_dict_add_variable(vd, var);
588  }
589}
590
591void owl_variable_dict_newvar_bool(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
592  owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_BOOL);
593  if(old) {
594    owl_variable_update(old, summ, desc);
595    old->ival_default = initval;
596  } else {
597    owl_variable * var = owl_variable_newvar(name, summ, desc);
598    var->type = OWL_VARIABLE_BOOL;
599    var->ival_default = initval;
600    var->validate_fn = owl_variable_bool_validate_default;
601    var->set_fn = owl_variable_bool_set_default;
602    var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
603    var->get_fn = owl_variable_get_default;
604    var->get_tostring_fn = owl_variable_bool_get_tostring_default;
605    var->free_fn = owl_variable_free_default;
606    var->val = owl_malloc(sizeof(int));
607    var->set_fn(var, &initval);
608    owl_variable_dict_add_variable(vd, var);
609  }
610}
611
612void owl_variable_dict_free(owl_vardict *d) {
613  owl_dict_free_all(d, (void(*)(void*))owl_variable_free);
614}
615
616/* free the list with owl_variable_dict_namelist_free */
617void owl_variable_dict_get_names(owl_vardict *d, owl_list *l) {
618  owl_dict_get_keys(d, l);
619}
620
621void owl_variable_dict_namelist_free(owl_list *l) {
622  owl_list_free_all(l, owl_free);
623}
624
625void owl_variable_free(owl_variable *v) {
626  if (v->free_fn) v->free_fn(v);
627  owl_free(v);
628}
629
630
631char *owl_variable_get_description(owl_variable *v) {
632  return v->description;
633}
634
635char *owl_variable_get_summary(owl_variable *v) {
636  return v->summary;
637}
638
639char *owl_variable_get_validsettings(owl_variable *v) {
640  if (v->validsettings) {
641    return v->validsettings;
642  } else {
643    return "";
644  }
645}
646
647/* functions for getting and setting variable values */
648
649/* returns 0 on success, prints a status msg if msg is true */
650int owl_variable_set_fromstring(owl_vardict *d, char *name, char *value, int msg, int requirebool) {
651  owl_variable *v;
652  char buff2[1024];
653  if (!name) return(-1);
654  v = owl_dict_find_element(d, name);
655  if (v == NULL) {
656    if (msg) owl_function_error("Unknown variable %s", name);
657    return -1;
658  }
659  if (!v->set_fromstring_fn) {
660    if (msg) owl_function_error("Variable %s is read-only", name);
661    return -1;   
662  }
663  if (requirebool && v->type!=OWL_VARIABLE_BOOL) {
664    if (msg) owl_function_error("Variable %s is not a boolean", name);
665    return -1;   
666  }
667  if (0 != v->set_fromstring_fn(v, value)) {
668    if (msg) owl_function_error("Unable to set %s (must be %s)", name, 
669                                  owl_variable_get_validsettings(v));
670    return -1;
671  }
672  if (msg && v->get_tostring_fn) {
673    v->get_tostring_fn(v, buff2, 1024, v->val);
674    owl_function_makemsg("%s = '%s'", name, buff2);
675  }   
676  return 0;
677}
678 
679int owl_variable_set_string(owl_vardict *d, char *name, char *newval) {
680  owl_variable *v;
681  if (!name) return(-1);
682  v = owl_dict_find_element(d, name);
683  if (v == NULL || !v->set_fn) return(-1);
684  if (v->type!=OWL_VARIABLE_STRING) return(-1);
685  return v->set_fn(v, (void*)newval);
686}
687 
688int owl_variable_set_int(owl_vardict *d, char *name, int newval) {
689  owl_variable *v;
690  if (!name) return(-1);
691  v = owl_dict_find_element(d, name);
692  if (v == NULL || !v->set_fn) return(-1);
693  if (v->type!=OWL_VARIABLE_INT && v->type!=OWL_VARIABLE_BOOL) return(-1);
694  return v->set_fn(v, &newval);
695}
696 
697int owl_variable_set_bool_on(owl_vardict *d, char *name) {
698  return owl_variable_set_int(d,name,1);
699}
700
701int owl_variable_set_bool_off(owl_vardict *d, char *name) {
702  return owl_variable_set_int(d,name,0);
703}
704
705int owl_variable_get_tostring(owl_vardict *d, char *name, char *buf, int bufsize) {
706  owl_variable *v;
707  if (!name) return(-1);
708  v = owl_dict_find_element(d, name);
709  if (v == NULL || !v->get_tostring_fn) return(-1);
710  return v->get_tostring_fn(v, buf, bufsize, v->val);
711}
712
713int owl_variable_get_default_tostring(owl_vardict *d, char *name, char *buf, int bufsize) {
714  owl_variable *v;
715  if (!name) return(-1);
716  v = owl_dict_find_element(d, name);
717  if (v == NULL || !v->get_tostring_fn) return(-1);
718  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
719    return v->get_tostring_fn(v, buf, bufsize, &(v->ival_default));
720  } else {
721    return v->get_tostring_fn(v, buf, bufsize, v->pval_default);
722  }
723}
724
725owl_variable *owl_variable_get_var(owl_vardict *d, char *name, int require_type) {
726  owl_variable *v;
727  if (!name) return(NULL);
728  v = owl_dict_find_element(d, name);
729  if (v == NULL || !v->get_fn || v->type != require_type) return(NULL);
730  return v;
731}
732
733/* returns a reference */
734void *owl_variable_get(owl_vardict *d, char *name, int require_type) {
735  owl_variable *v = owl_variable_get_var(d, name, require_type);
736  if(v == NULL) return NULL;
737  return v->get_fn(v);
738}
739
740/* returns a reference */
741char *owl_variable_get_string(owl_vardict *d, char *name) {
742  return (char*)owl_variable_get(d,name, OWL_VARIABLE_STRING);
743}
744
745/* returns a reference */
746void *owl_variable_get_other(owl_vardict *d, char *name) {
747  return (char*)owl_variable_get(d,name, OWL_VARIABLE_OTHER);
748}
749
750int owl_variable_get_int(owl_vardict *d, char *name) {
751  int *pi;
752  pi = (int*)owl_variable_get(d,name,OWL_VARIABLE_INT);
753  if (!pi) return(-1);
754  return(*pi);
755}
756
757int owl_variable_get_bool(owl_vardict *d, char *name) {
758  int *pi;
759  pi = (int*)owl_variable_get(d,name,OWL_VARIABLE_BOOL);
760  if (!pi) return(-1);
761  return(*pi);
762}
763
764void owl_variable_describe(owl_vardict *d, char *name, owl_fmtext *fm) {
765  char defaultbuf[50];
766  char buf[1024];
767  int buflen = 1023;
768  owl_variable *v;
769
770  if (!name
771      || (v = owl_dict_find_element(d, name)) == NULL 
772      || !v->get_fn) {
773    snprintf(buf, buflen, "     No such variable '%s'\n", name);     
774    owl_fmtext_append_normal(fm, buf);
775    return;
776  }
777  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
778    v->get_tostring_fn(v, defaultbuf, 50, &(v->ival_default));
779  } else {
780    v->get_tostring_fn(v, defaultbuf, 50, v->pval_default);
781  }
782  snprintf(buf, buflen, OWL_TABSTR "%-20s - %s (default: '%s')\n", 
783                  v->name, 
784                  owl_variable_get_summary(v), defaultbuf);
785  owl_fmtext_append_normal(fm, buf);
786}
787
788void owl_variable_get_help(owl_vardict *d, char *name, owl_fmtext *fm) {
789  char buff[1024];
790  int bufflen = 1023;
791  owl_variable *v;
792
793  if (!name
794      || (v = owl_dict_find_element(d, name)) == NULL 
795      || !v->get_fn) {
796    owl_fmtext_append_normal(fm, "No such variable...\n");
797    return;
798  }
799
800  owl_fmtext_append_bold(fm, "OWL VARIABLE\n\n");
801  owl_fmtext_append_normal(fm, OWL_TABSTR);
802  owl_fmtext_append_normal(fm, name);
803  owl_fmtext_append_normal(fm, " - ");
804  owl_fmtext_append_normal(fm, v->summary);
805  owl_fmtext_append_normal(fm, "\n\n");
806
807  owl_fmtext_append_normal(fm, "Current:        ");
808  owl_variable_get_tostring(d, name, buff, bufflen);
809  owl_fmtext_append_normal(fm, buff);
810  owl_fmtext_append_normal(fm, "\n\n");
811
812
813  if (v->type == OWL_VARIABLE_INT || v->type == OWL_VARIABLE_BOOL) {
814    v->get_tostring_fn(v, buff, bufflen, &(v->ival_default));
815  } else {
816    v->get_tostring_fn(v, buff, bufflen, v->pval_default);
817  }
818  owl_fmtext_append_normal(fm, "Default:        ");
819  owl_fmtext_append_normal(fm, buff);
820  owl_fmtext_append_normal(fm, "\n\n");
821
822  owl_fmtext_append_normal(fm, "Valid Settings: ");
823  owl_fmtext_append_normal(fm, owl_variable_get_validsettings(v));
824  owl_fmtext_append_normal(fm, "\n\n");
825
826  if (v->description && *v->description) {
827    owl_fmtext_append_normal(fm, "Description:\n");
828    owl_fmtext_append_normal(fm, owl_variable_get_description(v));
829    owl_fmtext_append_normal(fm, "\n\n");
830  }
831}
832
833
834
835
836/**************************************************************************/
837/*********************** GENERAL TYPE-SPECIFIC ****************************/
838/**************************************************************************/
839
840/* default common functions */
841
842void *owl_variable_get_default(owl_variable *v) {
843  return v->val;
844}
845
846void owl_variable_free_default(owl_variable *v) {
847  if (v->val) owl_free(v->val);
848}
849
850/* default functions for booleans */
851
852int owl_variable_bool_validate_default(owl_variable *v, void *newval) {
853  if (newval == NULL) return(0);
854  else if (*(int*)newval==1 || *(int*)newval==0) return(1);
855  else return (0);
856}
857
858int owl_variable_bool_set_default(owl_variable *v, void *newval) {
859  if (v->validate_fn) {
860    if (!v->validate_fn(v, newval)) return(-1);
861  }
862  *(int*)v->val = *(int*)newval;
863  return(0);
864}
865
866int owl_variable_bool_set_fromstring_default(owl_variable *v, char *newval) {
867  int i;
868  if (!strcmp(newval, "on")) i=1;
869  else if (!strcmp(newval, "off")) i=0;
870  else return(-1);
871  return (v->set_fn(v, &i));
872}
873
874int owl_variable_bool_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
875  if (val == NULL) {
876    snprintf(buf, bufsize, "<null>");
877    return -1;
878  } else if (*(int*)val == 0) {
879    snprintf(buf, bufsize, "off");
880    return 0;
881  } else if (*(int*)val == 1) {
882    snprintf(buf, bufsize, "on");
883    return 0;
884  } else {
885    snprintf(buf, bufsize, "<invalid>");
886    return -1;
887  }
888}
889
890/* default functions for integers */
891
892int owl_variable_int_validate_default(owl_variable *v, void *newval) {
893  if (newval == NULL) return(0);
894  else return (1);
895}
896
897int owl_variable_int_set_default(owl_variable *v, void *newval) {
898  if (v->validate_fn) {
899    if (!v->validate_fn(v, newval)) return(-1);
900  }
901  *(int*)v->val = *(int*)newval;
902  return(0);
903}
904
905int owl_variable_int_set_fromstring_default(owl_variable *v, char *newval) {
906  int i;
907  char *ep = "x";
908  i = strtol(newval, &ep, 10);
909  if (*ep || ep==newval) return(-1);
910  return (v->set_fn(v, &i));
911}
912
913int owl_variable_int_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
914  if (val == NULL) {
915    snprintf(buf, bufsize, "<null>");
916    return -1;
917  } else {
918    snprintf(buf, bufsize, "%d", *(int*)val);
919    return 0;
920  } 
921}
922
923/* default functions for enums (a variant of integers) */
924
925int owl_variable_enum_validate(owl_variable *v, void *newval) { 
926  char **enums;
927  int nenums, val;
928  if (newval == NULL) return(0);
929  enums = atokenize(v->validsettings, ",", &nenums);
930  if (enums == NULL) return(0);
931  atokenize_free(enums, nenums);
932  val = *(int*)newval;
933  if (val < 0 || val >= nenums) {
934    return(0);
935  }
936  return(1);
937}
938
939int owl_variable_enum_set_fromstring(owl_variable *v, char *newval) {
940  char **enums;
941  int nenums, i, val=-1;
942  if (newval == NULL) return(-1);
943  enums = atokenize(v->validsettings, ",", &nenums);
944  if (enums == NULL) return(-1);
945  for (i=0; i<nenums; i++) {
946    if (0==strcmp(newval, enums[i])) {
947      val = i;
948    }
949  }
950  atokenize_free(enums, nenums);
951  if (val == -1) return(-1);
952  return (v->set_fn(v, &val));
953}
954
955int owl_variable_enum_get_tostring(owl_variable *v, char* buf, int bufsize, void *val) {
956  char **enums;
957  int nenums, i;
958
959  if (val == NULL) {
960    snprintf(buf, bufsize, "<null>");
961    return -1;
962  }
963  enums = atokenize(v->validsettings, ",", &nenums);
964  i = *(int*)val;
965  if (i<0 || i>=nenums) {
966    snprintf(buf, bufsize, "<invalid:%d>",i);
967    atokenize_free(enums, nenums);
968    return(-1);
969  }
970  snprintf(buf, bufsize, "%s", enums[i]);
971  return 0;
972}
973
974/* default functions for stringeans */
975
976int owl_variable_string_validate_default(struct _owl_variable *v, void *newval) {
977  if (newval == NULL) return(0);
978  else return (1);
979}
980
981int owl_variable_string_set_default(owl_variable *v, void *newval) {
982  if (v->validate_fn) {
983    if (!v->validate_fn(v, newval)) return(-1);
984  }
985  if (v->val) owl_free(v->val);
986  v->val = owl_strdup(newval);
987  return(0);
988}
989
990int owl_variable_string_set_fromstring_default(owl_variable *v, char *newval) {
991  return (v->set_fn(v, newval));
992}
993
994int owl_variable_string_get_tostring_default(owl_variable *v, char* buf, int bufsize, void *val) {
995  if (val == NULL) {
996    snprintf(buf, bufsize, "<null>");
997    return -1;
998  } else {
999    snprintf(buf, bufsize, "%s", (char*)val);
1000    return 0;
1001  }
1002}
1003
1004
1005
1006/**************************************************************************/
1007/************************* REGRESSION TESTS *******************************/
1008/**************************************************************************/
1009
1010#ifdef OWL_INCLUDE_REG_TESTS
1011
1012#include "test.h"
1013
1014int owl_variable_regtest(void) {
1015  owl_vardict vd;
1016  int numfailed=0;
1017  char buf[1024];
1018  owl_variable * v;
1019
1020  in_regtest = 1;
1021
1022  printf("# BEGIN testing owl_variable\n");
1023  FAIL_UNLESS("setup", 0==owl_variable_dict_setup(&vd));
1024
1025  FAIL_UNLESS("get bool", 0==owl_variable_get_bool(&vd,"rxping"));
1026  FAIL_UNLESS("get bool (no such)", -1==owl_variable_get_bool(&vd,"mumble"));
1027  FAIL_UNLESS("get bool as string 1", 0==owl_variable_get_tostring(&vd,"rxping", buf, 1024));
1028  FAIL_UNLESS("get bool as string 2", 0==strcmp(buf,"off"));
1029  FAIL_UNLESS("set bool 1", 0==owl_variable_set_bool_on(&vd,"rxping"));
1030  FAIL_UNLESS("get bool 2", 1==owl_variable_get_bool(&vd,"rxping"));
1031  FAIL_UNLESS("set bool 3", 0==owl_variable_set_fromstring(&vd,"rxping","off",0,0));
1032  FAIL_UNLESS("get bool 4", 0==owl_variable_get_bool(&vd,"rxping"));
1033  FAIL_UNLESS("set bool 5", -1==owl_variable_set_fromstring(&vd,"rxping","xxx",0,0));
1034  FAIL_UNLESS("get bool 6", 0==owl_variable_get_bool(&vd,"rxping"));
1035
1036
1037  FAIL_UNLESS("get string", 0==strcmp("~/zlog/people", owl_variable_get_string(&vd,"logpath")));
1038  FAIL_UNLESS("set string 7", 0==owl_variable_set_string(&vd,"logpath","whee"));
1039  FAIL_UNLESS("get string", 0==strcmp("whee", owl_variable_get_string(&vd,"logpath")));
1040
1041  FAIL_UNLESS("get int", 8==owl_variable_get_int(&vd,"typewinsize"));
1042  FAIL_UNLESS("get int (no such)", -1==owl_variable_get_int(&vd,"mmble"));
1043  FAIL_UNLESS("get int as string 1", 0==owl_variable_get_tostring(&vd,"typewinsize", buf, 1024));
1044  FAIL_UNLESS("get int as string 2", 0==strcmp(buf,"8"));
1045  FAIL_UNLESS("set int 1", 0==owl_variable_set_int(&vd,"typewinsize",12));
1046  FAIL_UNLESS("get int 2", 12==owl_variable_get_int(&vd,"typewinsize"));
1047  FAIL_UNLESS("set int 1b", -1==owl_variable_set_int(&vd,"typewinsize",-3));
1048  FAIL_UNLESS("get int 2b", 12==owl_variable_get_int(&vd,"typewinsize"));
1049  FAIL_UNLESS("set int 3", 0==owl_variable_set_fromstring(&vd,"typewinsize","9",0,0));
1050  FAIL_UNLESS("get int 4", 9==owl_variable_get_int(&vd,"typewinsize"));
1051  FAIL_UNLESS("set int 5", -1==owl_variable_set_fromstring(&vd,"typewinsize","xxx",0,0));
1052  FAIL_UNLESS("set int 6", -1==owl_variable_set_fromstring(&vd,"typewinsize","",0,0));
1053  FAIL_UNLESS("get int 7", 9==owl_variable_get_int(&vd,"typewinsize"));
1054
1055  FAIL_UNLESS("get enum", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1056  FAIL_UNLESS("get enum as string 1", 0==owl_variable_get_tostring(&vd,"webbrowser", buf, 1024));
1057  FAIL_UNLESS("get enum as string 2", 0==strcmp(buf,"netscape"));
1058  FAIL_UNLESS("set enum 1", 0==owl_variable_set_int(&vd,"webbrowser",OWL_WEBBROWSER_GALEON));
1059  FAIL_UNLESS("get enum 2", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
1060  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",-3));
1061  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",209));
1062  FAIL_UNLESS("get enum 2b", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
1063  FAIL_UNLESS("set enum 3", 0==owl_variable_set_fromstring(&vd,"webbrowser","none",0,0));
1064  FAIL_UNLESS("get enum 4", OWL_WEBBROWSER_NONE==owl_variable_get_int(&vd,"webbrowser"));
1065  FAIL_UNLESS("set enum 5", 0==owl_variable_set_fromstring(&vd,"webbrowser","netscape",0,0));
1066  FAIL_UNLESS("get enum 6", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1067  FAIL_UNLESS("set enum 7", -1==owl_variable_set_fromstring(&vd,"webbrowser","xxx",0,0));
1068  FAIL_UNLESS("set enum 8", -1==owl_variable_set_fromstring(&vd,"webbrowser","",0,0));
1069  FAIL_UNLESS("set enum 9", -1==owl_variable_set_fromstring(&vd,"webbrowser","netscapey",0,0));
1070  FAIL_UNLESS("get enum 10", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
1071
1072  owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
1073  FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(&vd, "stringvar", OWL_VARIABLE_STRING)));
1074  FAIL_UNLESS("get new string val", !strcmp("testval", owl_variable_get_string(&vd, "stringvar")));
1075  owl_variable_set_string(&vd, "stringvar", "new val");
1076  FAIL_UNLESS("update string val", !strcmp("new val", owl_variable_get_string(&vd, "stringvar")));
1077
1078  owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47);
1079  FAIL_UNLESS("get new int var", NULL != (v = owl_variable_get(&vd, "intvar", OWL_VARIABLE_INT)));
1080  FAIL_UNLESS("get new int val", 47 == owl_variable_get_int(&vd, "intvar"));
1081  owl_variable_set_int(&vd, "intvar", 17);
1082  FAIL_UNLESS("update bool val", 17 == owl_variable_get_int(&vd, "intvar"));
1083
1084  owl_variable_dict_newvar_bool(&vd, "boolvar", "", "", 1);
1085  FAIL_UNLESS("get new bool var", NULL != (v = owl_variable_get(&vd, "boolvar", OWL_VARIABLE_BOOL)));
1086  FAIL_UNLESS("get new bool val", owl_variable_get_bool(&vd, "boolvar"));
1087  owl_variable_set_bool_off(&vd, "boolvar");
1088  FAIL_UNLESS("update string val", !owl_variable_get_bool(&vd, "boolvar"));
1089
1090  owl_variable_dict_free(&vd);
1091
1092  /* if (numfailed) printf("*** WARNING: failures encountered with owl_variable\n"); */
1093  printf("# END testing owl_variable (%d failures)\n", numfailed);
1094  return(numfailed);
1095}
1096
1097
1098#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.