source: variable.c @ af16ad3

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