Browse Source

ientry: Initial class

Serj Kalichev 2 years ago
parent
commit
fe8e03b0bd
4 changed files with 382 additions and 1 deletions
  1. 2 1
      klish/Makefile.am
  2. 40 0
      klish/ientry.h
  3. 6 0
      klish/ischeme.h
  4. 334 0
      klish/ischeme/ientry.c

+ 2 - 1
klish/Makefile.am

@@ -44,7 +44,8 @@ nobase_include_HEADERS += \
 	klish/iplugin.h \
 	klish/iaction.h \
 	klish/iptype.h \
-	klish/inspace.h
+	klish/inspace.h \
+	klish/ientry.h
 
 # Session
 nobase_include_HEADERS += \

+ 40 - 0
klish/ientry.h

@@ -0,0 +1,40 @@
+/** @file ientry.h
+ *
+ * @brief Klish scheme's "entry" entry
+ */
+
+#ifndef _klish_ientry_h
+#define _klish_ientry_h
+
+#include <faux/error.h>
+#include <klish/iaction.h>
+#include <klish/kentry.h>
+
+typedef struct ientry_s ientry_t;
+
+struct ientry_s {
+	char *name;
+	char *help;
+	char *container;
+	char *mode;
+	char *min;
+	char *max;
+	char *ptype;
+	char *ref;
+	char *value;
+	char *restore;
+	ientry_t * (*entrys)[]; // Nested entrys
+	iaction_t * (*actions)[];
+};
+
+C_DECL_BEGIN
+
+bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error);
+bool_t ientry_parse_nested(const ientry_t *ientry, kentry_t *kentry,
+	faux_error_t *error);
+kentry_t *ientry_load(const ientry_t *ientry, faux_error_t *error);
+char *ientry_deploy(const kentry_t *kentry, int level);
+
+C_DECL_END
+
+#endif // _klish_ientry_h

+ 6 - 0
klish/ischeme.h

@@ -11,6 +11,7 @@
 #include <klish/iplugin.h>
 #include <klish/iview.h>
 #include <klish/inspace.h>
+#include <klish/ientry.h>
 #include <klish/kscheme.h>
 
 #define VIEW_LIST .views = &(iview_t * []) {
@@ -41,9 +42,14 @@
 #define END_NSPACE_LIST NULL }
 #define NSPACE &(inspace_t)
 
+#define ENTRY_LIST .entrys = &(ientry_t * []) {
+#define END_ENTRY_LIST NULL }
+#define ENTRY &(ientry_t)
+
 
 typedef struct ischeme_s {
 	char *name;
+	ientry_t * (*entrys)[];
 	iplugin_t * (*plugins)[];
 	iptype_t * (*ptypes)[];
 	iview_t * (*views)[];

+ 334 - 0
klish/ischeme/ientry.c

@@ -0,0 +1,334 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <faux/str.h>
+#include <faux/list.h>
+#include <klish/khelper.h>
+#include <klish/ientry.h>
+#include <klish/kptype.h>
+#include <klish/kentry.h>
+
+#define TAG "ENTRY"
+
+
+bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error)
+{
+	bool_t retcode = BOOL_TRUE;
+
+	if (!info)
+		return BOOL_FALSE;
+	if (!entry)
+		return BOOL_FALSE;
+
+	// Help
+	if (!faux_str_is_empty(info->help)) {
+		if (!kentry_set_help(entry, info->help)) {
+			faux_error_add(error, TAG": Illegal 'help' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Container
+	if (!faux_str_is_empty(info->container)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->container, &b) ||
+			!kentry_set_container(entry, b)) {
+			faux_error_add(error, TAG": Illegal 'container' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Mode
+	if (!faux_str_is_empty(info->mode)) {
+		kentry_mode_e mode = KENTRY_MODE_NONE;
+		if (!faux_str_casecmp(info->mode, "sequence"))
+			mode = KENTRY_MODE_SEQUENCE;
+		else if (!faux_str_casecmp(info->mode, "switch"))
+			mode = KENTRY_MODE_SWITCH;
+		else if (!faux_str_casecmp(info->mode, "empty"))
+			mode = KENTRY_MODE_EMPTY;
+		if ((KENTRY_MODE_NONE == mode) || !kentry_set_mode(entry, mode)) {
+			faux_error_add(error, TAG": Illegal 'mode' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Min occurs
+	if (!faux_str_is_empty(info->min)) {
+		unsigned int i = 0;
+		if (!faux_conv_atoui(info->min, &i, 0) ||
+			!kentry_set_min(entry, (size_t)i)) {
+			faux_error_add(error, TAG": Illegal 'min' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Max occurs
+	if (!faux_str_is_empty(info->max)) {
+		unsigned int i = 0;
+		if (!faux_conv_atoui(info->max, &i, 0) ||
+			!kentry_set_max(entry, (size_t)i)) {
+			faux_error_add(error, TAG": Illegal 'max' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Ptype string
+	if (!faux_str_is_empty(info->ptype)) {
+		if (!kentry_set_ptype_str(entry, info->ptype)) {
+			faux_error_add(error, TAG": Illegal 'ptype' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Ref string
+	if (!faux_str_is_empty(info->ref)) {
+		if (!kentry_set_ref_str(entry, info->ref)) {
+			faux_error_add(error, TAG": Illegal 'ref' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Value
+	if (!faux_str_is_empty(info->value)) {
+		if (!kentry_set_value(entry, info->value)) {
+			faux_error_add(error, TAG": Illegal 'value' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Restore
+	if (!faux_str_is_empty(info->restore)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->restore, &b) ||
+			!kentry_set_restore(entry, b)) {
+			faux_error_add(error, TAG": Illegal 'restore' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	return retcode;
+}
+
+
+bool_t ientry_parse_nested(const ientry_t *ientry, kentry_t *kentry,
+	faux_error_t *error)
+{
+	bool_t retval = BOOL_TRUE;
+
+	if (!kentry || !ientry) {
+		faux_error_add(error, TAG": Internal error");
+		return BOOL_FALSE;
+	}
+
+	// ENTRY list
+	// ENTRYs can be duplicate. Duplicated ENTRY will add nested
+	// elements to existent ENTRY. Also it can overwrite ENTRY attributes.
+	// So there is no special rule which attribute value will be "on top".
+	// It's a random. Technically later ENTRYs will rewrite previous
+	// values.
+	if (ientry->entrys) {
+		ientry_t **p_ientry = NULL;
+		for (p_ientry = *ientry->entrys; *p_ientry; p_ientry++) {
+			kentry_t *nkentry = NULL;
+			ientry_t *nientry = *p_ientry;
+			const char *entry_name = nientry->name;
+
+			if (entry_name)
+				nkentry = kentry_find_entry(kentry, entry_name);
+
+			// ENTRY already exists
+			if (nkentry) {
+				if (!ientry_parse(nientry, nkentry, error)) {
+					retval = BOOL_FALSE;
+					continue;
+				}
+				if (!ientry_parse_nested(nientry, nkentry,
+					error)) {
+					retval = BOOL_FALSE;
+					continue;
+				}
+				continue;
+			}
+
+			// New ENTRY
+			nkentry = ientry_load(nientry, error);
+			if (!nkentry) {
+				retval = BOOL_FALSE;
+				continue;
+			}
+			kentry_set_parent(nkentry, kentry); // Set parent entry
+			if (!kentry_add_entry(kentry, nkentry)) {
+				faux_error_sprintf(error,
+					TAG": Can't add ENTRY \"%s\"",
+					kentry_name(nkentry));
+				kentry_free(nkentry);
+				retval = BOOL_FALSE;
+				continue;
+			}
+		}
+	}
+
+	// ACTION list
+	if (ientry->actions) {
+		iaction_t **p_iaction = NULL;
+		for (p_iaction = *ientry->actions; *p_iaction; p_iaction++) {
+			kaction_t *kaction = NULL;
+			iaction_t *iaction = *p_iaction;
+
+			kaction = iaction_load(iaction, error);
+			if (!kaction) {
+				retval = BOOL_FALSE;
+				continue;
+			}
+			if (!kentry_add_action(kentry, kaction)) {
+				faux_error_sprintf(error,
+					TAG": Can't add ACTION #%d",
+					kentry_actions_len(kentry) + 1);
+				kaction_free(kaction);
+				retval = BOOL_FALSE;
+				continue;
+			}
+		}
+	}
+
+	if (!retval)
+		faux_error_sprintf(error, TAG" \"%s\": Illegal nested elements",
+			kentry_name(kentry));
+
+	return retval;
+}
+
+
+kentry_t *ientry_load(const ientry_t *ientry, faux_error_t *error)
+{
+	kentry_t *kentry = NULL;
+
+	if (!ientry)
+		return NULL;
+
+	// Name [mandatory]
+	if (faux_str_is_empty(ientry->name)) {
+		faux_error_add(error, TAG": Empty 'name' attribute");
+		return NULL;
+	}
+
+	kentry = kentry_new(ientry->name);
+	if (!kentry) {
+		faux_error_sprintf(error, TAG" \"%s\": Can't create object",
+			ientry->name);
+		return NULL;
+	}
+
+	if (!ientry_parse(ientry, kentry, error)) {
+		kentry_free(kentry);
+		return NULL;
+	}
+
+	// Parse nested elements
+	if (!ientry_parse_nested(ientry, kentry, error)) {
+		kentry_free(kentry);
+		return NULL;
+	}
+
+	return kentry;
+}
+
+
+char *ientry_deploy(const kentry_t *kentry, int level)
+{
+	char *str = NULL;
+	char *tmp = NULL;
+	char *mode = NULL;
+	kentry_entrys_node_t *entrys_iter = NULL;
+	char *num = NULL;
+
+	tmp = faux_str_sprintf("%*cENTRY {\n", level, ' ');
+	faux_str_cat(&str, tmp);
+	faux_str_free(tmp);
+
+	attr2ctext(&str, "name", kentry_name(kentry), level + 1);
+	attr2ctext(&str, "help", kentry_help(kentry), level + 1);
+	attr2ctext(&str, "container", faux_conv_bool2str(kentry_container(kentry)), level + 1);
+
+	// Mode
+	switch (kentry_mode(kentry)) {
+	case KENTRY_MODE_SEQUENCE:
+		mode = "sequence";
+		break;
+	case KENTRY_MODE_SWITCH:
+		mode = "switch";
+		break;
+	case KENTRY_MODE_EMPTY:
+		mode = "empty";
+		break;
+	default:
+		mode = NULL;
+	}
+	attr2ctext(&str, "mode", mode, level + 1);
+
+	// Min occurs
+	num = faux_str_sprintf("%u", kentry_min(kentry));
+	attr2ctext(&str, "min", num, level + 1);
+	faux_str_free(num);
+	num = NULL;
+
+	// Max occurs
+	num = faux_str_sprintf("%u", kentry_max(kentry));
+	attr2ctext(&str, "max", num, level + 1);
+	faux_str_free(num);
+	num = NULL;
+
+	attr2ctext(&str, "ptype", kentry_ptype_str(kentry), level + 1);
+	attr2ctext(&str, "ref", kentry_ref_str(kentry), level + 1);
+	attr2ctext(&str, "value", kentry_value(kentry), level + 1);
+	attr2ctext(&str, "restore", faux_conv_bool2str(kentry_restore(kentry)), level + 1);
+
+	// ENTRY list
+	entrys_iter = kentry_entrys_iter(kentry);
+	if (entrys_iter) {
+		kentry_t *nentry = NULL;
+
+		tmp = faux_str_sprintf("\n%*cENTRY_LIST\n\n", level + 1, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+
+		while ((nentry = kentry_entrys_each(&entrys_iter))) {
+			tmp = ientry_deploy(nentry, level + 2);
+			faux_str_cat(&str, tmp);
+			faux_str_free(tmp);
+		}
+
+		tmp = faux_str_sprintf("%*cEND_ENTRY_LIST,\n", level + 1, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+	}
+
+	// ACTION list
+	actions_iter = kentry_actions_iter(kentry);
+	if (actions_iter) {
+		kaction_t *action = NULL;
+
+		tmp = faux_str_sprintf("\n%*cACTION_LIST\n\n", level + 1, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+
+		while ((action = kentry_actions_each(&actions_iter))) {
+			tmp = iaction_deploy(action, level + 2);
+			faux_str_cat(&str, tmp);
+			faux_str_free(tmp);
+		}
+
+		tmp = faux_str_sprintf("%*cEND_ACTION_LIST,\n", level + 1, ' ');
+		faux_str_cat(&str, tmp);
+		faux_str_free(tmp);
+	}
+
+	tmp = faux_str_sprintf("%*c},\n\n", level, ' ');
+	faux_str_cat(&str, tmp);
+	faux_str_free(tmp);
+
+	return str;
+}