Browse Source

scheme: Add plugin's scheme element

Serj Kalichev 3 years ago
parent
commit
15963672a0

+ 18 - 0
bin/klishd/sch.c

@@ -1,5 +1,23 @@
 ischeme_t sch = {
 
+ PLUGIN_LIST
+
+  PLUGIN {
+   .name = "plugin1",
+   .alias = "alias1",
+   .file = "file1",
+   .global = "true",
+  },
+
+  PLUGIN {
+   .name = "plugin2",
+   .alias = "alias2",
+   .file = "file2",
+   .global = "false",
+  },
+
+ END_PLUGIN_LIST,
+
  PTYPE_LIST
 
   PTYPE {

+ 4 - 1
klish/Makefile.am

@@ -12,7 +12,10 @@ nobase_include_HEADERS += \
 	klish/kscheme.h \
 	klish/kview.h \
 	klish/kcommand.h \
-	klish/kparam.h
+	klish/kparam.h \
+	klish/kplugin.h \
+	klish/kaction.h \
+	klish/kptype.h
 
 noinst_HEADERS += \
 	klish/khelper.h

+ 60 - 0
klish/kplugin.h

@@ -0,0 +1,60 @@
+/** @file kplugin.h
+ *
+ * @brief Klish scheme's "plugin" entry
+ */
+
+#ifndef _klish_kplugin_h
+#define _klish_kplugin_h
+
+#include <faux/error.h>
+
+typedef struct kplugin_s kplugin_t;
+
+typedef struct iplugin_s {
+	char *name;
+	char *alias;
+	char *file;
+	char *global;
+	char *script;
+} iplugin_t;
+
+
+typedef enum {
+	KPLUGIN_ERROR_OK,
+	KPLUGIN_ERROR_INTERNAL,
+	KPLUGIN_ERROR_ALLOC,
+	KPLUGIN_ERROR_ATTR_NAME,
+	KPLUGIN_ERROR_ATTR_ALIAS,
+	KPLUGIN_ERROR_ATTR_FILE,
+	KPLUGIN_ERROR_ATTR_GLOBAL,
+	KPLUGIN_ERROR_SCRIPT,
+} kplugin_error_e;
+
+
+C_DECL_BEGIN
+
+// iplugin_t
+char *iplugin_to_text(const iplugin_t *iplugin, int level);
+
+// kplugin_t
+void kplugin_free(kplugin_t *plugin);
+bool_t kplugin_parse(kplugin_t *plugin, const iplugin_t *info, kplugin_error_e *error);
+kplugin_t *kplugin_new(const iplugin_t *info, kplugin_error_e *error);
+const char *kplugin_strerror(kplugin_error_e error);
+
+const char *kplugin_name(const kplugin_t *plugin);
+bool_t kplugin_set_name(kplugin_t *plugin, const char *name);
+const char *kplugin_alias(const kplugin_t *plugin);
+bool_t kplugin_set_alias(kplugin_t *plugin, const char *alias);
+const char *kplugin_file(const kplugin_t *plugin);
+bool_t kplugin_set_file(kplugin_t *plugin, const char *file);
+bool_t kplugin_global(const kplugin_t *plugin);
+bool_t kplugin_set_global(kplugin_t *plugin, bool_t global);
+const char *kplugin_script(const kplugin_t *plugin);
+bool_t kplugin_set_script(kplugin_t *plugin, const char *script);
+
+kplugin_t *kplugin_from_iplugin(iplugin_t *iplugin, faux_error_t *error_stack);
+
+C_DECL_END
+
+#endif // _klish_kplugin_h

+ 8 - 0
klish/kscheme.h

@@ -9,6 +9,7 @@
 #include <faux/error.h>
 
 #include <klish/kptype.h>
+#include <klish/kplugin.h>
 #include <klish/kaction.h>
 #include <klish/kparam.h>
 #include <klish/kcommand.h>
@@ -35,11 +36,16 @@
 #define END_ACTION_LIST NULL }
 #define ACTION &(iaction_t)
 
+#define PLUGIN_LIST .plugins = &(iplugin_t * []) {
+#define END_PLUGIN_LIST NULL }
+#define PLUGIN &(iplugin_t)
+
 
 typedef struct kscheme_s kscheme_t;
 
 typedef struct ischeme_s {
 	char *name;
+	iplugin_t * (*plugins)[];
 	iptype_t * (*ptypes)[];
 	iview_t * (*views)[];
 } ischeme_t;
@@ -66,6 +72,8 @@ bool_t kscheme_add_view(kscheme_t *scheme, kview_t *view);
 kview_t *kscheme_find_view(const kscheme_t *scheme, const char *name);
 bool_t kscheme_add_ptype(kscheme_t *scheme, kptype_t *ptype);
 kptype_t *kscheme_find_ptype(const kscheme_t *scheme, const char *name);
+bool_t kscheme_add_plugin(kscheme_t *scheme, kplugin_t *plugin);
+kplugin_t *kscheme_find_plugin(const kscheme_t *scheme, const char *name);
 
 bool_t kscheme_nested_from_ischeme(kscheme_t *kscheme, ischeme_t *ischeme,
 	faux_error_t *error_stack);

+ 3 - 1
klish/kscheme/Makefile.am

@@ -1,5 +1,6 @@
 libklish_la_SOURCES += \
 	klish/kscheme/khelper.c \
+	klish/kscheme/kplugin.c \
 	klish/kscheme/kptype.c \
 	klish/kscheme/kaction.c \
 	klish/kscheme/kparam.c \
@@ -11,4 +12,5 @@ libklish_la_SOURCES += \
 	klish/kscheme/iaction.c \
 	klish/kscheme/iview.c \
 	klish/kscheme/icommand.c \
-	klish/kscheme/iparam.c
+	klish/kscheme/iparam.c \
+	klish/kscheme/iplugin.c

+ 31 - 0
klish/kscheme/iplugin.c

@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <faux/str.h>
+#include <faux/conv.h>
+#include <klish/khelper.h>
+#include <klish/kplugin.h>
+
+
+char *iplugin_to_text(const iplugin_t *iplugin, int level)
+{
+	char *str = NULL;
+	char *tmp = NULL;
+
+	tmp = faux_str_sprintf("%*cPLUGIN {\n", level, ' ');
+	faux_str_cat(&str, tmp);
+	faux_str_free(tmp);
+
+	attr2ctext(&str, "name", iplugin->name, level + 1);
+	attr2ctext(&str, "alias", iplugin->alias, level + 1);
+	attr2ctext(&str, "file", iplugin->file, level + 1);
+	attr2ctext(&str, "global", iplugin->global, level + 1);
+
+	tmp = faux_str_sprintf("%*c},\n\n", level, ' ');
+	faux_str_cat(&str, tmp);
+	faux_str_free(tmp);
+
+	return str;
+}

+ 21 - 0
klish/kscheme/ischeme.c

@@ -19,6 +19,27 @@ char *ischeme_to_text(const ischeme_t *ischeme, int level)
 	faux_str_cat(&str, tmp);
 	faux_str_free(tmp);
 
+	// PLUGIN list
+	if (ischeme->plugins) {
+		iplugin_t **p_iplugin = NULL;
+
+		tmp = faux_str_sprintf("\n%*cPLUGIN_LIST\n\n", level, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+
+		for (p_iplugin = *ischeme->plugins; *p_iplugin; p_iplugin++) {
+			iplugin_t *iplugin = *p_iplugin;
+
+			tmp = iplugin_to_text(iplugin, level + 2);
+			faux_str_cat(&str, tmp);
+			faux_str_free(tmp);
+		}
+
+		tmp = faux_str_sprintf("%*cEND_PLUGIN_LIST,\n", level + 1, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+	}
+
 	// PTYPE list
 	if (ischeme->ptypes) {
 		iptype_t **p_iptype = NULL;

+ 213 - 0
klish/kscheme/kplugin.c

@@ -0,0 +1,213 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <faux/str.h>
+#include <faux/list.h>
+#include <faux/conv.h>
+#include <faux/error.h>
+#include <klish/khelper.h>
+#include <klish/kplugin.h>
+
+
+struct kplugin_s {
+	char *name;
+	char *alias;
+	char *file;
+	bool_t global;
+	char *script;
+};
+
+
+// Simple methods
+
+// Name
+KGET_STR(plugin, name);
+KSET_STR_ONCE(plugin, name);
+
+// Alias
+KGET_STR(plugin, alias);
+KSET_STR(plugin, alias);
+
+// Alias
+KGET_STR(plugin, file);
+KSET_STR(plugin, file);
+
+// Global
+KGET_BOOL(plugin, global);
+KSET_BOOL(plugin, global);
+
+// Script
+KGET_STR(plugin, script);
+KSET_STR(plugin, script);
+
+
+static kplugin_t *kplugin_new_empty(void)
+{
+	kplugin_t *plugin = NULL;
+
+	plugin = faux_zmalloc(sizeof(*plugin));
+	assert(plugin);
+	if (!plugin)
+		return NULL;
+
+	// Initialize
+	plugin->name = NULL;
+	plugin->alias = NULL;
+	plugin->file = NULL;
+	plugin->global = BOOL_FALSE;
+	plugin->script = NULL;
+
+	return plugin;
+}
+
+
+kplugin_t *kplugin_new(const iplugin_t *info, kplugin_error_e *error)
+{
+	kplugin_t *plugin = NULL;
+
+	plugin = kplugin_new_empty();
+	assert(plugin);
+	if (!plugin) {
+		if (error)
+			*error = KPLUGIN_ERROR_ALLOC;
+		return NULL;
+	}
+
+	if (!info)
+		return plugin;
+
+	if (!kplugin_parse(plugin, info, error)) {
+		kplugin_free(plugin);
+		return NULL;
+	}
+
+	return plugin;
+}
+
+
+void kplugin_free(kplugin_t *plugin)
+{
+	if (!plugin)
+		return;
+
+	faux_str_free(plugin->name);
+	faux_str_free(plugin->alias);
+	faux_str_free(plugin->file);
+	faux_str_free(plugin->script);
+
+	faux_free(plugin);
+}
+
+
+const char *kplugin_strerror(kplugin_error_e error)
+{
+	const char *str = NULL;
+
+	switch (error) {
+	case KPLUGIN_ERROR_OK:
+		str = "Ok";
+		break;
+	case KPLUGIN_ERROR_INTERNAL:
+		str = "Internal error";
+		break;
+	case KPLUGIN_ERROR_ALLOC:
+		str = "Memory allocation error";
+		break;
+	case KPLUGIN_ERROR_ATTR_NAME:
+		str = "Illegal 'name' attribute";
+		break;
+	case KPLUGIN_ERROR_ATTR_ALIAS:
+		str = "Illegal 'alias' attribute";
+		break;
+	case KPLUGIN_ERROR_ATTR_FILE:
+		str = "Illegal 'file' attribute";
+		break;
+	case KPLUGIN_ERROR_ATTR_GLOBAL:
+		str = "Illegal 'global' attribute";
+		break;
+	case KPLUGIN_ERROR_SCRIPT:
+		str = "Illegal script";
+		break;
+	default:
+		str = "Unknown error";
+		break;
+	}
+
+	return str;
+}
+
+
+bool_t kplugin_parse(kplugin_t *plugin, const iplugin_t *info, kplugin_error_e *error)
+{
+	// Name [mandatory]
+	if (faux_str_is_empty(info->name)) {
+		if (error)
+			*error = KPLUGIN_ERROR_ATTR_NAME;
+		return BOOL_FALSE;
+	} else {
+		if (!kplugin_set_name(plugin, info->name)) {
+			if (error)
+				*error = KPLUGIN_ERROR_ATTR_NAME;
+			return BOOL_FALSE;
+		}
+	}
+
+	// Alias
+	if (!faux_str_is_empty(info->alias)) {
+		if (!kplugin_set_alias(plugin, info->alias)) {
+			if (error)
+				*error = KPLUGIN_ERROR_ATTR_ALIAS;
+			return BOOL_FALSE;
+		}
+	}
+
+	// File
+	if (!faux_str_is_empty(info->file)) {
+		if (!kplugin_set_file(plugin, info->file)) {
+			if (error)
+				*error = KPLUGIN_ERROR_ATTR_FILE;
+			return BOOL_FALSE;
+		}
+	}
+
+	// Global
+	if (!faux_str_is_empty(info->global)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->global, &b) ||
+			!kplugin_set_global(plugin, b)) {
+			if (error)
+				*error = KPLUGIN_ERROR_ATTR_GLOBAL;
+			return BOOL_FALSE;
+		}
+	}
+
+	// Script
+	if (!faux_str_is_empty(info->script)) {
+		if (!kplugin_set_script(plugin, info->script)) {
+			if (error)
+				*error = KPLUGIN_ERROR_SCRIPT;
+			return BOOL_FALSE;
+		}
+	}
+
+	return BOOL_TRUE;
+}
+
+
+kplugin_t *kplugin_from_iplugin(iplugin_t *iplugin, faux_error_t *error_stack)
+{
+	kplugin_t *kplugin = NULL;
+	kplugin_error_e kplugin_error = KPLUGIN_ERROR_OK;
+
+	kplugin = kplugin_new(iplugin, &kplugin_error);
+	if (!kplugin) {
+		faux_error_sprintf(error_stack, "PLUGIN \"%s\": %s",
+			iplugin->name ? iplugin->name : "(null)",
+			kplugin_strerror(kplugin_error));
+		return NULL;
+	}
+
+	return kplugin;
+}

+ 48 - 0
klish/kscheme/kscheme.c

@@ -6,18 +6,26 @@
 #include <faux/str.h>
 #include <faux/list.h>
 #include <klish/khelper.h>
+#include <klish/kplugin.h>
 #include <klish/kptype.h>
 #include <klish/kview.h>
 #include <klish/kscheme.h>
 
 
 struct kscheme_s {
+	faux_list_t *plugins;
 	faux_list_t *ptypes;
 	faux_list_t *views;
 };
 
 // Simple methods
 
+// PLUGIN list
+KCMP_NESTED(scheme, plugin, name);
+KCMP_NESTED_BY_KEY(scheme, plugin, name);
+KADD_NESTED(scheme, plugin);
+KFIND_NESTED(scheme, plugin);
+
 // PTYPE list
 KCMP_NESTED(scheme, ptype, name);
 KCMP_NESTED_BY_KEY(scheme, ptype, name);
@@ -43,6 +51,12 @@ kscheme_t *kscheme_new(kscheme_error_e *error)
 		return NULL;
 	}
 
+	// PLUGIN list
+	scheme->plugins = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
+		kscheme_plugin_compare, kscheme_plugin_kcompare,
+		(void (*)(void *))kplugin_free);
+	assert(scheme->plugins);
+
 	// PTYPE list
 	scheme->ptypes = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
 		kscheme_ptype_compare, kscheme_ptype_kcompare,
@@ -64,6 +78,7 @@ void kscheme_free(kscheme_t *scheme)
 	if (!scheme)
 		return;
 
+	faux_list_free(scheme->plugins);
 	faux_list_free(scheme->ptypes);
 	faux_list_free(scheme->views);
 	faux_free(scheme);
@@ -104,6 +119,39 @@ bool_t kscheme_nested_from_ischeme(kscheme_t *kscheme, ischeme_t *ischeme,
 		return BOOL_FALSE;
 	}
 
+	// PLUGIN list
+	if (ischeme->plugins) {
+		iplugin_t **p_iplugin = NULL;
+		for (p_iplugin = *ischeme->plugins; *p_iplugin; p_iplugin++) {
+			kplugin_t *kplugin = NULL;
+			iplugin_t *iplugin = *p_iplugin;
+
+			kplugin = kplugin_from_iplugin(iplugin, error_stack);
+			if (!kplugin) {
+				retval = BOOL_FALSE; // Don't stop
+				continue;
+			}
+			if (!kscheme_add_plugin(kscheme, kplugin)) {
+				// Search for PLUGIN duplicates
+				if (kscheme_find_plugin(kscheme,
+					kplugin_name(kplugin))) {
+					faux_error_sprintf(error_stack,
+						"SCHEME: "
+						"Can't add duplicate PLUGIN "
+						"\"%s\"",
+						kplugin_name(kplugin));
+				} else {
+					faux_error_sprintf(error_stack,
+						"SCHEME: "
+						"Can't add PLUGIN \"%s\"",
+						kplugin_name(kplugin));
+				}
+				kplugin_free(kplugin);
+				retval = BOOL_FALSE;
+			}
+		}
+	}
+
 	// PTYPE list
 	if (ischeme->ptypes) {
 		iptype_t **p_iptype = NULL;