update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / epan / wslua / wslua_pref.c
blob52b3706a907a70dbc1c723c7d807044c7552c7cd
1 /*
2 * wslua_pref.c
4 * Wireshark's interface to the Lua Programming Language
6 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
7 * (c) 2008, Balint Reczey <balint.reczey@ericsson.com>
8 * (c) 2011, Stig Bjorlykke <stig@bjorlykke.org>
9 * (c) 2014, Hadriel Kaplan <hadrielk@yahoo.com>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include "config.h"
20 #include "wslua.h"
22 /* WSLUA_CONTINUE_MODULE Proto */
25 WSLUA_CLASS_DEFINE(Pref,NOP); /* A preference of a <<lua_class_Proto,`Proto`>>. */
27 static range_t* get_range(lua_State *L, int idx_r, int idx_m);
29 static enum_val_t* get_enum(lua_State *L, int idx)
31 double seq;
32 const char *str1, *str2;
33 enum_val_t *ret, last = {NULL, NULL, -1};
34 GArray* es = g_array_new(true,true,sizeof(enum_val_t));
36 luaL_checktype(L, idx, LUA_TTABLE);
37 lua_pushnil(L); /* first key */
39 while (lua_next(L, idx)) {
40 enum_val_t e = {NULL, NULL, -1};
42 luaL_checktype(L, -1, LUA_TTABLE);
43 lua_pushnil(L);
44 lua_next(L, -2);
45 if (! lua_isstring(L,-1)) {
46 luaL_argerror(L,idx,"First value of an enum table must be string");
47 g_array_free(es,true);
48 return NULL;
50 str1 = lua_tostring(L, -1);
52 lua_pop(L, 1);
53 lua_next(L, -2);
54 if (! lua_isstring(L,-1)) {
55 luaL_argerror(L,idx,"Second value of an enum table must be string");
56 g_array_free(es,true);
57 return NULL;
59 str2 = lua_tostring(L, -1);
61 lua_pop(L, 1);
62 lua_next(L, -2);
63 if (! lua_isnumber(L,-1)) {
64 luaL_argerror(L,idx,"Third value of an enum table must be an integer");
65 g_array_free(es,true);
66 return NULL;
68 seq = lua_tonumber(L, -1);
70 e.name = g_strdup(str1);
71 e.description = g_strdup(str2);
72 e.value = (uint32_t)seq;
74 g_array_append_val(es,e);
76 lua_pop(L, 3); /* removes 'value'; keeps 'key' for next iteration */
79 g_array_append_val(es,last);
81 ret = (enum_val_t*)(void*)g_array_free(es, false);
83 return ret;
86 static int new_pref(lua_State* L, pref_type_t type) {
87 const char* label = luaL_optstring(L,1,NULL);
88 const char* descr = luaL_optstring(L,3,"");
90 Pref pref = g_new0(wslua_pref_t, 1);
91 pref->label = g_strdup(label);
92 pref->desc = g_strdup(descr);
93 pref->type = type;
94 pref->ref = LUA_NOREF;
96 switch(type) {
97 case PREF_BOOL: {
98 bool def = wslua_toboolean(L,2);
99 pref->value.b = def;
100 break;
102 case PREF_UINT: {
103 uint32_t def = wslua_optint32(L,2,0);
104 pref->value.u = def;
105 break;
107 case PREF_STRING: {
108 char* def = g_strdup(luaL_optstring(L,2,""));
110 * prefs_register_string_preference() assumes that the
111 * variable for the preference points to a static
112 * string that is the initial (default) value of the
113 * preference. It makes a g_strdup()ed copy of that
114 * string, and assigns a pointer to that string to
115 * the variable.
117 * Our default string is *not* a static string, it's
118 * a g_strdup()ed copy of a string from Lua, so it would
119 * be leaked.
121 * We save it in info.default_s, as well as setting the
122 * initial value of the preference from it, so that we
123 * can free it after prefs_register_string_preference()
124 * returns.
126 * (Would that we were programming in a language where
127 * the details of memory management were handled by the
128 * compiler and language support....)
130 pref->value.s = def;
131 pref->info.default_s = def;
132 break;
134 case PREF_ENUM: {
135 uint32_t def = wslua_optint32(L,2,0);
136 enum_val_t *enum_val = get_enum(L,4);
137 bool radio = wslua_toboolean(L,5);
138 pref->value.e = def;
139 pref->info.enum_info.enumvals = enum_val;
140 pref->info.enum_info.radio_buttons = radio;
141 break;
143 case PREF_RANGE: {
144 range_t *range = get_range(L,2,4);
145 uint32_t max = wslua_optint32(L,4,0);
146 pref->value.r = range;
147 pref->info.max_value = max;
148 break;
150 case PREF_STATIC_TEXT: {
151 /* This is just a static text. */
152 break;
154 default:
155 ws_assert_not_reached();
156 break;
160 pushPref(L,pref);
161 return 1;
164 WSLUA_CONSTRUCTOR Pref_bool(lua_State* L) {
166 Creates a boolean preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table.
168 ===== Example
170 [source,lua]
171 ----
172 -- create a Boolean preference named "bar" for Foo Protocol
173 -- (assuming Foo doesn't already have a preference named "bar")
174 proto_foo.prefs.bar = Pref.bool( "Bar", true, "Baz and all the rest" )
175 ----
177 #define WSLUA_ARG_Pref_bool_LABEL 1 /* The Label (text in the right side of the
178 preference input) for this preference. */
179 #define WSLUA_ARG_Pref_bool_DEFAULT 2 /* The default value for this preference. */
180 #define WSLUA_ARG_Pref_bool_DESCRIPTION 3 /* A description of this preference. */
181 return new_pref(L,PREF_BOOL);
184 WSLUA_CONSTRUCTOR Pref_uint(lua_State* L) {
185 /* Creates an (unsigned) integer preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
186 #define WSLUA_ARG_Pref_uint_LABEL 1 /* The Label (text in the right side of the
187 preference input) for this preference. */
188 #define WSLUA_ARG_Pref_uint_DEFAULT 2 /* The default value for this preference. */
189 #define WSLUA_ARG_Pref_uint_DESCRIPTION 3 /* A description of what this preference is. */
190 return new_pref(L,PREF_UINT);
193 WSLUA_CONSTRUCTOR Pref_string(lua_State* L) {
194 /* Creates a string preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
195 #define WSLUA_ARG_Pref_string_LABEL 1 /* The Label (text in the right side of the
196 preference input) for this preference. */
197 #define WSLUA_ARG_Pref_string_DEFAULT 2 /* The default value for this preference. */
198 #define WSLUA_ARG_Pref_string_DESCRIPTION 3 /* A description of what this preference is. */
199 return new_pref(L,PREF_STRING);
202 WSLUA_CONSTRUCTOR Pref_enum(lua_State* L) {
204 Creates an enum preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table.
206 ===== Example:
208 [source,lua]
209 ----
210 local OUTPUT_OFF = 0
211 local OUTPUT_DEBUG = 1
212 local OUTPUT_INFO = 2
213 local OUTPUT_WARN = 3
214 local OUTPUT_ERROR = 4
216 local output_tab = {
217 { 1, "Off" , OUTPUT_OFF },
218 { 2, "Debug" , OUTPUT_DEBUG },
219 { 3, "Information" , OUTPUT_INFO },
220 { 4, "Warning" , OUTPUT_WARN },
221 { 5, "Error" , OUTPUT_ERROR },
224 -- Create enum preference that shows as Combo Box under
225 -- Foo Protocol's preferences
226 proto_foo.prefs.outputlevel = Pref.enum(
227 "Output Level", -- label
228 OUTPUT_INFO, -- default value
229 "Verbosity of log output", -- description
230 output_tab, -- enum table
231 false -- show as combo box
234 -- Then, we can query the value of the selected preference.
235 -- This line prints "Output Level: 3" assuming the selected
236 -- output level is _INFO.
237 debug( "Output Level: " .. proto_foo.prefs.outputlevel )
238 ----
240 #define WSLUA_ARG_Pref_enum_LABEL 1 /* The Label (text in the right side of the
241 preference input) for this preference. */
242 #define WSLUA_ARG_Pref_enum_DEFAULT 2 /* The default value for this preference. */
243 #define WSLUA_ARG_Pref_enum_DESCRIPTION 3 /* A description of what this preference is. */
244 #define WSLUA_ARG_Pref_enum_ENUM 4 /* An enum Lua table. */
245 #define WSLUA_ARG_Pref_enum_RADIO 5 /* Radio button (true) or Combobox (false). */
246 return new_pref(L,PREF_ENUM);
249 WSLUA_CONSTRUCTOR Pref_range(lua_State* L) {
250 /* Creates a range (numeric text entry) preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
251 #define WSLUA_ARG_Pref_range_LABEL 1 /* The Label (text in the right side of the preference
252 input) for this preference. */
253 #define WSLUA_ARG_Pref_range_DEFAULT 2 /* The default value for this preference, e.g., "53",
254 "10-30", or "10-30,53,55,100-120". */
255 #define WSLUA_ARG_Pref_range_DESCRIPTION 3 /* A description of what this preference is. */
256 #define WSLUA_ARG_Pref_range_MAX 4 /* The maximum value. */
257 return new_pref(L,PREF_RANGE);
260 WSLUA_CONSTRUCTOR Pref_statictext(lua_State* L) {
261 /* Creates a static text string to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
262 #define WSLUA_ARG_Pref_statictext_LABEL 1 /* The static text. */
263 #define WSLUA_ARG_Pref_statictext_DESCRIPTION 2 /* The static text description. */
264 return new_pref(L,PREF_STATIC_TEXT);
267 static range_t* get_range(lua_State *L, int idx_r, int idx_m)
269 static range_t *ret = NULL;
270 const char *pattern = luaL_checkstring(L, idx_r);
272 switch (range_convert_str(wmem_epan_scope(), &ret, pattern, wslua_toint32(L, idx_m))) {
273 case CVT_NO_ERROR:
274 break;
275 case CVT_SYNTAX_ERROR:
276 WSLUA_ARG_ERROR(Pref_range,DEFAULT,"syntax error in default range");
277 return 0;
278 case CVT_NUMBER_TOO_BIG:
279 WSLUA_ARG_ERROR(Pref_range,DEFAULT,"value too large in default range");
280 return 0;
281 default:
282 WSLUA_ARG_ERROR(Pref_range,DEFAULT,"unknown error in default range");
283 return 0;
286 return ret;
289 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
290 static int Pref__gc(lua_State* L) {
291 Pref pref = toPref(L,1);
293 if (pref->ref != LUA_NOREF) {
294 // Did the user try to call __gc explicitly while it was registered to a
295 // protocol? Forbid that!
296 luaL_error(L, "Direct call to __gc is forbidden");
297 return 0;
300 g_free(pref->name);
301 g_free(pref->label);
302 g_free(pref->desc);
303 switch (pref->type) {
304 case PREF_STRING:
306 * Free the initial string value; if it's not NULL, that
307 * means this is a never-registered preference, so the
308 * initial value hasn't been freed.
310 g_free(pref->info.default_s);
311 break;
312 case PREF_ENUM: {
314 * Free the enum values allocated in get_enum().
316 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
317 while (enum_valp->name) {
318 g_free((char *)enum_valp->name);
319 g_free((char *)enum_valp->description);
320 enum_valp++;
322 g_free((enum_val_t *)pref->info.enum_info.enumvals);
323 break;
325 default:
326 break;
328 g_free(pref);
330 return 0;
333 WSLUA_METHODS Pref_methods[] = {
334 WSLUA_CLASS_FNREG(Pref,bool),
335 WSLUA_CLASS_FNREG(Pref,uint),
336 WSLUA_CLASS_FNREG(Pref,string),
337 WSLUA_CLASS_FNREG(Pref,enum),
338 WSLUA_CLASS_FNREG(Pref,range),
339 WSLUA_CLASS_FNREG(Pref,statictext),
340 { NULL, NULL }
343 WSLUA_META Pref_meta[] = {
344 { NULL, NULL }
348 WSLUA_REGISTER Pref_register(lua_State* L) {
349 WSLUA_REGISTER_CLASS(Pref);
350 return 0;
353 WSLUA_CLASS_DEFINE(Prefs,NOP); /* The table of preferences of a protocol. */
355 WSLUA_METAMETHOD Prefs__newindex(lua_State* L) {
356 /* Creates a new preference. */
357 #define WSLUA_ARG_Prefs__newindex_NAME 2 /* The abbreviation of this preference. */
358 #define WSLUA_ARG_Prefs__newindex_PREF 3 /* A valid but still unassigned Pref object. */
360 Pref prefs_p = checkPrefs(L,1);
361 const char* name = luaL_checkstring(L,WSLUA_ARG_Prefs__newindex_NAME);
362 Pref pref = checkPref(L,WSLUA_ARG_Prefs__newindex_PREF);
363 Pref p;
364 const char *c;
366 if (! prefs_p ) return 0;
368 if (! pref ) {
369 WSLUA_ARG_ERROR(Prefs__newindex,PREF,"must be a valid Pref");
370 return 0;
373 if (pref->name) {
374 WSLUA_ARG_ERROR(Prefs__newindex,NAME,"cannot change existing preference");
375 return 0;
378 if (pref->proto) {
379 WSLUA_ARG_ERROR(Prefs__newindex,PREF,"cannot be added to more than one protocol");
380 return 0;
383 p = prefs_p;
385 do {
386 if ( p->name && g_str_equal(p->name,name) ) {
387 luaL_error(L,"a preference named %s exists already",name);
388 return 0;
391 * Make sure that only lower-case ASCII letters, numbers,
392 * underscores, and dots appear in the preference name.
394 for (c = name; *c != '\0'; c++) {
395 if (!g_ascii_islower(*c) && !g_ascii_isdigit(*c) && *c != '_' && *c != '.')
397 luaL_error(L,"illegal preference name \"%s\", only lower-case ASCII letters, "
398 "numbers, underscores and dots may be used", name);
399 return 0;
403 if ( ! p->next) {
404 // Keep a reference to the Pref to ensure it remains valid
405 // until the protocol is deregistered.
406 lua_pushvalue(L, WSLUA_ARG_Prefs__newindex_PREF);
407 pref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
409 p->next = pref;
410 pref->name = g_strdup(name);
412 if (!pref->label)
413 pref->label = g_strdup(name);
415 if (!prefs_p->proto->prefs_module) {
416 prefs_p->proto->prefs_module = prefs_register_protocol(prefs_p->proto->hfid,
417 wslua_prefs_changed);
420 switch(pref->type) {
421 case PREF_BOOL:
422 prefs_register_bool_preference(prefs_p->proto->prefs_module,
423 pref->name,
424 pref->label,
425 pref->desc,
426 &(pref->value.b));
427 break;
428 case PREF_UINT:
429 prefs_register_uint_preference(prefs_p->proto->prefs_module,
430 pref->name,
431 pref->label,
432 pref->desc,
434 &(pref->value.u));
435 break;
436 case PREF_STRING:
437 prefs_register_string_preference(prefs_p->proto->prefs_module,
438 pref->name,
439 pref->label,
440 pref->desc,
441 (const char **)(&(pref->value.s)));
443 * We're finished with the initial string value; see
444 * the comment in new_pref().
446 g_free(pref->info.default_s);
447 pref->info.default_s = NULL;
448 break;
449 case PREF_ENUM:
450 prefs_register_enum_preference(prefs_p->proto->prefs_module,
451 pref->name,
452 pref->label,
453 pref->desc,
454 &(pref->value.e),
455 pref->info.enum_info.enumvals,
456 pref->info.enum_info.radio_buttons);
457 break;
458 case PREF_RANGE:
459 prefs_register_range_preference(prefs_p->proto->prefs_module,
460 pref->name,
461 pref->label,
462 pref->desc,
463 &(pref->value.r),
464 pref->info.max_value);
465 break;
466 case PREF_STATIC_TEXT:
467 prefs_register_static_text_preference(prefs_p->proto->prefs_module,
468 pref->name,
469 pref->label,
470 pref->desc);
471 break;
472 default:
473 WSLUA_ERROR(Prefs__newindex,"Unknown Pref type");
474 break;
477 pref->proto = p->proto;
479 WSLUA_RETURN(0);
481 } while (( p = p->next ));
483 luaL_error(L,"this should not happen!");
485 WSLUA_RETURN(0);
488 WSLUA_METAMETHOD Prefs__index(lua_State* L) {
490 Get the value of a preference setting.
492 ===== Example
494 [source,lua]
495 ----
496 -- print the value of Foo's preference named "bar"
497 debug( "bar = " .. proto_foo.prefs.bar )
498 ----
500 #define WSLUA_ARG_Prefs__index_NAME 2 /* The abbreviation of this preference. */
502 Pref prefs_p = checkPrefs(L,1);
503 const char* name = luaL_checkstring(L,WSLUA_ARG_Prefs__index_NAME);
505 if (! prefs_p ) return 0;
507 if (!prefs_p->next) {
508 luaL_error(L,"No preference is registered yet");
509 return 0;
512 prefs_p = prefs_p->next;
514 do {
515 if ( g_str_equal(prefs_p->name,name) ) {
516 switch (prefs_p->type) {
517 case PREF_BOOL: lua_pushboolean(L, prefs_p->value.b); break;
518 case PREF_UINT: lua_pushinteger(L,(lua_Integer)prefs_p->value.u); break;
519 case PREF_STRING: lua_pushstring(L,prefs_p->value.s); break;
520 case PREF_ENUM: lua_pushinteger(L,(lua_Integer)prefs_p->value.e); break;
521 case PREF_RANGE:
523 char *push_str = range_convert_range(NULL, prefs_p->value.r);
524 lua_pushstring(L, push_str);
525 wmem_free(NULL, push_str);
527 break;
528 default: WSLUA_ERROR(Prefs__index,"Unknown Pref type"); return 0;
530 WSLUA_RETURN(1); /* The current value of the preference. */
532 } while (( prefs_p = prefs_p->next ));
534 WSLUA_ARG_ERROR(Prefs__index,NAME,"no preference named like this");
535 return 0;
538 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
539 static int Prefs__gc(lua_State* L _U_) {
540 /* do NOT free Prefs, it's a static part of Proto */
541 return 0;
544 WSLUA_META Prefs_meta[] = {
545 WSLUA_CLASS_MTREG(Prefs,newindex),
546 WSLUA_CLASS_MTREG(Prefs,index),
547 { NULL, NULL }
550 WSLUA_REGISTER Prefs_register(lua_State* L) {
551 WSLUA_REGISTER_META(Prefs);
552 return 0;
557 * Editor modelines - https://www.wireshark.org/tools/modelines.html
559 * Local variables:
560 * c-basic-offset: 4
561 * tab-width: 8
562 * indent-tabs-mode: nil
563 * End:
565 * vi: set shiftwidth=4 tabstop=8 expandtab:
566 * :indentSize=4:tabSize=8:noTabs=true: