summaryrefslogtreecommitdiffstats
path: root/epan/wslua/wslua_pref.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/wslua/wslua_pref.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/wslua/wslua_pref.c')
-rw-r--r--epan/wslua/wslua_pref.c567
1 files changed, 567 insertions, 0 deletions
diff --git a/epan/wslua/wslua_pref.c b/epan/wslua/wslua_pref.c
new file mode 100644
index 0000000..234170d
--- /dev/null
+++ b/epan/wslua/wslua_pref.c
@@ -0,0 +1,567 @@
+/*
+ * wslua_pref.c
+ *
+ * Wireshark's interface to the Lua Programming Language
+ *
+ * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
+ * (c) 2008, Balint Reczey <balint.reczey@ericsson.com>
+ * (c) 2011, Stig Bjorlykke <stig@bjorlykke.org>
+ * (c) 2014, Hadriel Kaplan <hadrielk@yahoo.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "wslua.h"
+
+/* WSLUA_CONTINUE_MODULE Proto */
+
+
+WSLUA_CLASS_DEFINE(Pref,NOP); /* A preference of a <<lua_class_Proto,`Proto`>>. */
+
+static range_t* get_range(lua_State *L, int idx_r, int idx_m);
+
+static enum_val_t* get_enum(lua_State *L, int idx)
+{
+ double seq;
+ const gchar *str1, *str2;
+ enum_val_t *ret, last = {NULL, NULL, -1};
+ GArray* es = g_array_new(TRUE,TRUE,sizeof(enum_val_t));
+
+ luaL_checktype(L, idx, LUA_TTABLE);
+ lua_pushnil(L); /* first key */
+
+ while (lua_next(L, idx)) {
+ enum_val_t e = {NULL, NULL, -1};
+
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnil(L);
+ lua_next(L, -2);
+ if (! lua_isstring(L,-1)) {
+ luaL_argerror(L,idx,"First value of an enum table must be string");
+ g_array_free(es,TRUE);
+ return NULL;
+ }
+ str1 = lua_tostring(L, -1);
+
+ lua_pop(L, 1);
+ lua_next(L, -2);
+ if (! lua_isstring(L,-1)) {
+ luaL_argerror(L,idx,"Second value of an enum table must be string");
+ g_array_free(es,TRUE);
+ return NULL;
+ }
+ str2 = lua_tostring(L, -1);
+
+ lua_pop(L, 1);
+ lua_next(L, -2);
+ if (! lua_isnumber(L,-1)) {
+ luaL_argerror(L,idx,"Third value of an enum table must be an integer");
+ g_array_free(es,TRUE);
+ return NULL;
+ }
+ seq = lua_tonumber(L, -1);
+
+ e.name = g_strdup(str1);
+ e.description = g_strdup(str2);
+ e.value = (guint32)seq;
+
+ g_array_append_val(es,e);
+
+ lua_pop(L, 3); /* removes 'value'; keeps 'key' for next iteration */
+ }
+
+ g_array_append_val(es,last);
+
+ ret = (enum_val_t*)(void*)g_array_free(es, FALSE);
+
+ return ret;
+}
+
+static int new_pref(lua_State* L, pref_type_t type) {
+ const gchar* label = luaL_optstring(L,1,NULL);
+ const gchar* descr = luaL_optstring(L,3,"");
+
+ Pref pref = g_new0(wslua_pref_t, 1);
+ pref->label = g_strdup(label);
+ pref->desc = g_strdup(descr);
+ pref->type = type;
+ pref->ref = LUA_NOREF;
+
+ switch(type) {
+ case PREF_BOOL: {
+ gboolean def = wslua_toboolean(L,2);
+ pref->value.b = def;
+ break;
+ }
+ case PREF_UINT: {
+ guint32 def = wslua_optgint32(L,2,0);
+ pref->value.u = def;
+ break;
+ }
+ case PREF_STRING: {
+ gchar* def = g_strdup(luaL_optstring(L,2,""));
+ /*
+ * prefs_register_string_preference() assumes that the
+ * variable for the preference points to a static
+ * string that is the initial (default) value of the
+ * preference. It makes a g_strdup()ed copy of that
+ * string, and assigns a pointer to that string to
+ * the variable.
+ *
+ * Our default string is *not* a static string, it's
+ * a g_strdup()ed copy of a string from Lua, so it would
+ * be leaked.
+ *
+ * We save it in info.default_s, as well as setting the
+ * initial value of the preference from it, so that we
+ * can free it after prefs_register_string_preference()
+ * returns.
+ *
+ * (Would that we were programming in a language where
+ * the details of memory management were handled by the
+ * compiler and language support....)
+ */
+ pref->value.s = def;
+ pref->info.default_s = def;
+ break;
+ }
+ case PREF_ENUM: {
+ guint32 def = wslua_optgint32(L,2,0);
+ enum_val_t *enum_val = get_enum(L,4);
+ gboolean radio = wslua_toboolean(L,5);
+ pref->value.e = def;
+ pref->info.enum_info.enumvals = enum_val;
+ pref->info.enum_info.radio_buttons = radio;
+ break;
+ }
+ case PREF_RANGE: {
+ range_t *range = get_range(L,2,4);
+ guint32 max = wslua_optgint32(L,4,0);
+ pref->value.r = range;
+ pref->info.max_value = max;
+ break;
+ }
+ case PREF_STATIC_TEXT: {
+ /* This is just a static text. */
+ break;
+ }
+ default:
+ ws_assert_not_reached();
+ break;
+
+ }
+
+ pushPref(L,pref);
+ return 1;
+}
+
+WSLUA_CONSTRUCTOR Pref_bool(lua_State* L) {
+ /*
+ Creates a boolean preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table.
+
+ ===== Example
+
+ [source,lua]
+ ----
+ -- create a Boolean preference named "bar" for Foo Protocol
+ -- (assuming Foo doesn't already have a preference named "bar")
+ proto_foo.prefs.bar = Pref.bool( "Bar", true, "Baz and all the rest" )
+ ----
+ */
+#define WSLUA_ARG_Pref_bool_LABEL 1 /* The Label (text in the right side of the
+ preference input) for this preference. */
+#define WSLUA_ARG_Pref_bool_DEFAULT 2 /* The default value for this preference. */
+#define WSLUA_ARG_Pref_bool_DESCR 3 /* A description of this preference. */
+ return new_pref(L,PREF_BOOL);
+}
+
+WSLUA_CONSTRUCTOR Pref_uint(lua_State* L) {
+ /* Creates an (unsigned) integer preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
+#define WSLUA_ARG_Pref_uint_LABEL 1 /* The Label (text in the right side of the
+ preference input) for this preference. */
+#define WSLUA_ARG_Pref_uint_DEFAULT 2 /* The default value for this preference. */
+#define WSLUA_ARG_Pref_uint_DESCR 3 /* A description of what this preference is. */
+ return new_pref(L,PREF_UINT);
+}
+
+WSLUA_CONSTRUCTOR Pref_string(lua_State* L) {
+ /* Creates a string preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
+#define WSLUA_ARG_Pref_string_LABEL 1 /* The Label (text in the right side of the
+ preference input) for this preference. */
+#define WSLUA_ARG_Pref_string_DEFAULT 2 /* The default value for this preference. */
+#define WSLUA_ARG_Pref_string_DESCR 3 /* A description of what this preference is. */
+ return new_pref(L,PREF_STRING);
+}
+
+WSLUA_CONSTRUCTOR Pref_enum(lua_State* L) {
+ /*
+ Creates an enum preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table.
+
+ ===== Example:
+
+ [source,lua]
+ ----
+ local OUTPUT_OFF = 0
+ local OUTPUT_DEBUG = 1
+ local OUTPUT_INFO = 2
+ local OUTPUT_WARN = 3
+ local OUTPUT_ERROR = 4
+
+ local output_tab = {
+ { 1, "Off" , OUTPUT_OFF },
+ { 2, "Debug" , OUTPUT_DEBUG },
+ { 3, "Information" , OUTPUT_INFO },
+ { 4, "Warning" , OUTPUT_WARN },
+ { 5, "Error" , OUTPUT_ERROR },
+ }
+
+ -- Create enum preference that shows as Combo Box under
+ -- Foo Protocol's preferences
+ proto_foo.prefs.outputlevel = Pref.enum(
+ "Output Level", -- label
+ OUTPUT_INFO, -- default value
+ "Verbosity of log output", -- description
+ output_tab, -- enum table
+ false -- show as combo box
+ )
+
+ -- Then, we can query the value of the selected preference.
+ -- This line prints "Output Level: 3" assuming the selected
+ -- output level is _INFO.
+ debug( "Output Level: " .. proto_foo.prefs.outputlevel )
+ ----
+ */
+#define WSLUA_ARG_Pref_enum_LABEL 1 /* The Label (text in the right side of the
+ preference input) for this preference. */
+#define WSLUA_ARG_Pref_enum_DEFAULT 2 /* The default value for this preference. */
+#define WSLUA_ARG_Pref_enum_DESCR 3 /* A description of what this preference is. */
+#define WSLUA_ARG_Pref_enum_ENUM 4 /* An enum Lua table. */
+#define WSLUA_ARG_Pref_enum_RADIO 5 /* Radio button (true) or Combobox (false). */
+ return new_pref(L,PREF_ENUM);
+}
+
+WSLUA_CONSTRUCTOR Pref_range(lua_State* L) {
+ /* Creates a range (numeric text entry) preference to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
+#define WSLUA_ARG_Pref_range_LABEL 1 /* The Label (text in the right side of the preference
+ input) for this preference. */
+#define WSLUA_ARG_Pref_range_DEFAULT 2 /* The default value for this preference, e.g., "53",
+ "10-30", or "10-30,53,55,100-120". */
+#define WSLUA_ARG_Pref_range_DESCR 3 /* A description of what this preference is. */
+#define WSLUA_ARG_Pref_range_MAX 4 /* The maximum value. */
+ return new_pref(L,PREF_RANGE);
+}
+
+WSLUA_CONSTRUCTOR Pref_statictext(lua_State* L) {
+ /* Creates a static text string to be added to a <<lua_class_attrib_proto_prefs,`Proto.prefs`>> Lua table. */
+#define WSLUA_ARG_Pref_statictext_LABEL 1 /* The static text. */
+#define WSLUA_ARG_Pref_statictext_DESCR 2 /* The static text description. */
+ return new_pref(L,PREF_STATIC_TEXT);
+}
+
+static range_t* get_range(lua_State *L, int idx_r, int idx_m)
+{
+ static range_t *ret = NULL;
+ const gchar *pattern = luaL_checkstring(L, idx_r);
+
+ switch (range_convert_str(wmem_epan_scope(), &ret, pattern, wslua_togint32(L, idx_m))) {
+ case CVT_NO_ERROR:
+ break;
+ case CVT_SYNTAX_ERROR:
+ WSLUA_ARG_ERROR(Pref_range,DEFAULT,"syntax error in default range");
+ return 0;
+ case CVT_NUMBER_TOO_BIG:
+ WSLUA_ARG_ERROR(Pref_range,DEFAULT,"value too large in default range");
+ return 0;
+ default:
+ WSLUA_ARG_ERROR(Pref_range,DEFAULT,"unknown error in default range");
+ return 0;
+ }
+
+ return ret;
+}
+
+/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
+static int Pref__gc(lua_State* L) {
+ Pref pref = toPref(L,1);
+
+ if (pref->ref != LUA_NOREF) {
+ // Did the user try to call __gc explicitly while it was registered to a
+ // protocol? Forbid that!
+ luaL_error(L, "Direct call to __gc is forbidden");
+ return 0;
+ }
+
+ g_free(pref->name);
+ g_free(pref->label);
+ g_free(pref->desc);
+ switch (pref->type) {
+ case PREF_STRING:
+ /*
+ * Free the initial string value; if it's not NULL, that
+ * means this is a never-registered preference, so the
+ * initial value hasn't been freed.
+ */
+ g_free(pref->info.default_s);
+ break;
+ case PREF_ENUM: {
+ /*
+ * Free the enum values allocated in get_enum().
+ */
+ const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
+ while (enum_valp->name) {
+ g_free((char *)enum_valp->name);
+ g_free((char *)enum_valp->description);
+ enum_valp++;
+ }
+ g_free((enum_val_t *)pref->info.enum_info.enumvals);
+ break;
+ }
+ default:
+ break;
+ }
+ g_free(pref);
+
+ return 0;
+}
+
+WSLUA_METHODS Pref_methods[] = {
+ WSLUA_CLASS_FNREG(Pref,bool),
+ WSLUA_CLASS_FNREG(Pref,uint),
+ WSLUA_CLASS_FNREG(Pref,string),
+ WSLUA_CLASS_FNREG(Pref,enum),
+ WSLUA_CLASS_FNREG(Pref,range),
+ WSLUA_CLASS_FNREG(Pref,statictext),
+ { NULL, NULL }
+};
+
+WSLUA_META Pref_meta[] = {
+ { NULL, NULL }
+};
+
+
+WSLUA_REGISTER Pref_register(lua_State* L) {
+ WSLUA_REGISTER_CLASS(Pref);
+ return 0;
+}
+
+WSLUA_CLASS_DEFINE(Prefs,NOP); /* The table of preferences of a protocol. */
+
+WSLUA_METAMETHOD Prefs__newindex(lua_State* L) {
+ /* Creates a new preference. */
+#define WSLUA_ARG_Prefs__newindex_NAME 2 /* The abbreviation of this preference. */
+#define WSLUA_ARG_Prefs__newindex_PREF 3 /* A valid but still unassigned Pref object. */
+
+ Pref prefs_p = checkPrefs(L,1);
+ const gchar* name = luaL_checkstring(L,WSLUA_ARG_Prefs__newindex_NAME);
+ Pref pref = checkPref(L,WSLUA_ARG_Prefs__newindex_PREF);
+ Pref p;
+ const gchar *c;
+
+ if (! prefs_p ) return 0;
+
+ if (! pref ) {
+ WSLUA_ARG_ERROR(Prefs__newindex,PREF,"must be a valid Pref");
+ return 0;
+ }
+
+ if (pref->name) {
+ WSLUA_ARG_ERROR(Prefs__newindex,NAME,"cannot change existing preference");
+ return 0;
+ }
+
+ if (pref->proto) {
+ WSLUA_ARG_ERROR(Prefs__newindex,PREF,"cannot be added to more than one protocol");
+ return 0;
+ }
+
+ p = prefs_p;
+
+ do {
+ if ( p->name && g_str_equal(p->name,name) ) {
+ luaL_error(L,"a preference named %s exists already",name);
+ return 0;
+ }
+ /*
+ * Make sure that only lower-case ASCII letters, numbers,
+ * underscores, and dots appear in the preference name.
+ */
+ for (c = name; *c != '\0'; c++) {
+ if (!g_ascii_islower(*c) && !g_ascii_isdigit(*c) && *c != '_' && *c != '.')
+ {
+ luaL_error(L,"illegal preference name \"%s\", only lower-case ASCII letters, "
+ "numbers, underscores and dots may be used", name);
+ return 0;
+ }
+ }
+
+ if ( ! p->next) {
+ // Keep a reference to the Pref to ensure it remains valid
+ // until the protocol is deregistered.
+ lua_pushvalue(L, WSLUA_ARG_Prefs__newindex_PREF);
+ pref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ p->next = pref;
+ pref->name = g_strdup(name);
+
+ if (!pref->label)
+ pref->label = g_strdup(name);
+
+ if (!prefs_p->proto->prefs_module) {
+ prefs_p->proto->prefs_module = prefs_register_protocol(prefs_p->proto->hfid,
+ wslua_prefs_changed);
+ }
+
+ switch(pref->type) {
+ case PREF_BOOL:
+ prefs_register_bool_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ &(pref->value.b));
+ break;
+ case PREF_UINT:
+ prefs_register_uint_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ 10,
+ &(pref->value.u));
+ break;
+ case PREF_STRING:
+ prefs_register_string_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ (const char **)(&(pref->value.s)));
+ /*
+ * We're finished with the initial string value; see
+ * the comment in new_pref().
+ */
+ g_free(pref->info.default_s);
+ pref->info.default_s = NULL;
+ break;
+ case PREF_ENUM:
+ prefs_register_enum_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ &(pref->value.e),
+ pref->info.enum_info.enumvals,
+ pref->info.enum_info.radio_buttons);
+ break;
+ case PREF_RANGE:
+ prefs_register_range_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ &(pref->value.r),
+ pref->info.max_value);
+ break;
+ case PREF_STATIC_TEXT:
+ prefs_register_static_text_preference(prefs_p->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc);
+ break;
+ default:
+ WSLUA_ERROR(Prefs__newindex,"Unknown Pref type");
+ break;
+ }
+
+ pref->proto = p->proto;
+
+ WSLUA_RETURN(0);
+ }
+ } while (( p = p->next ));
+
+ luaL_error(L,"this should not happen!");
+
+ WSLUA_RETURN(0);
+}
+
+WSLUA_METAMETHOD Prefs__index(lua_State* L) {
+ /*
+ Get the value of a preference setting.
+
+ ===== Example
+
+ [source,lua]
+ ----
+ -- print the value of Foo's preference named "bar"
+ debug( "bar = " .. proto_foo.prefs.bar )
+ ----
+ */
+#define WSLUA_ARG_Prefs__index_NAME 2 /* The abbreviation of this preference. */
+
+ Pref prefs_p = checkPrefs(L,1);
+ const gchar* name = luaL_checkstring(L,WSLUA_ARG_Prefs__index_NAME);
+
+ if (! prefs_p ) return 0;
+
+ if (!prefs_p->next) {
+ luaL_error(L,"No preference is registered yet");
+ return 0;
+ }
+
+ prefs_p = prefs_p->next;
+
+ do {
+ if ( g_str_equal(prefs_p->name,name) ) {
+ switch (prefs_p->type) {
+ case PREF_BOOL: lua_pushboolean(L, prefs_p->value.b); break;
+ case PREF_UINT: lua_pushnumber(L,(lua_Number)prefs_p->value.u); break;
+ case PREF_STRING: lua_pushstring(L,prefs_p->value.s); break;
+ case PREF_ENUM: lua_pushnumber(L,(lua_Number)prefs_p->value.e); break;
+ case PREF_RANGE:
+ {
+ char *push_str = range_convert_range(NULL, prefs_p->value.r);
+ lua_pushstring(L, push_str);
+ wmem_free(NULL, push_str);
+ }
+ break;
+ default: WSLUA_ERROR(Prefs__index,"Unknown Pref type"); return 0;
+ }
+ WSLUA_RETURN(1); /* The current value of the preference. */
+ }
+ } while (( prefs_p = prefs_p->next ));
+
+ WSLUA_ARG_ERROR(Prefs__index,NAME,"no preference named like this");
+ return 0;
+}
+
+/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
+static int Prefs__gc(lua_State* L _U_) {
+ /* do NOT free Prefs, it's a static part of Proto */
+ return 0;
+}
+
+WSLUA_META Prefs_meta[] = {
+ WSLUA_CLASS_MTREG(Prefs,newindex),
+ WSLUA_CLASS_MTREG(Prefs,index),
+ { NULL, NULL }
+};
+
+WSLUA_REGISTER Prefs_register(lua_State* L) {
+ WSLUA_REGISTER_META(Prefs);
+ return 0;
+}
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */