Browse Source

scheme: Some refactoring for error handling

Serj Kalichev 3 years ago
parent
commit
29d7fba718

+ 1 - 1
klish/iaction.h

@@ -8,7 +8,6 @@
 
 #include <faux/error.h>
 
-typedef struct kaction_s kaction_t;
 
 typedef struct iaction_s {
 	char *sym;
@@ -20,6 +19,7 @@ typedef struct iaction_s {
 	char *script;
 } iaction_t;
 
+
 C_DECL_BEGIN
 
 char *iaction_to_text(const iaction_t *iaction, int level);

+ 1 - 1
klish/ischeme/iaction.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/iaction.h>
 
 char *iaction_to_text(const iaction_t *iaction, int level)

+ 1 - 1
klish/ischeme/icommand.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/icommand.h>
 
 

+ 1 - 1
klish/ischeme/iparam.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/iparam.h>
 
 

+ 1 - 1
klish/ischeme/iplugin.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/iplugin.h>
 
 

+ 1 - 1
klish/ischeme/iptype.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/iptype.h>
 
 

+ 1 - 0
klish/ischeme/ischeme.c

@@ -4,6 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
+#include <klish/khelper.h>
 #include <klish/ischeme.h>
 
 

+ 1 - 1
klish/ischeme/iview.c

@@ -4,7 +4,7 @@
 #include <assert.h>
 
 #include <faux/str.h>
-#include <faux/conv.h>
+#include <klish/khelper.h>
 #include <klish/iview.h>
 
 

+ 5 - 17
klish/kaction.h

@@ -10,21 +10,10 @@
 #include <klish/iaction.h>
 
 
-typedef enum {
-	KACTION_ERROR_OK,
-	KACTION_ERROR_INTERNAL,
-	KACTION_ERROR_ALLOC,
-	KACTION_ERROR_ATTR_SYM,
-	KACTION_ERROR_ATTR_LOCK,
-	KACTION_ERROR_ATTR_INTERRUPT,
-	KACTION_ERROR_ATTR_INTERACTIVE,
-	KACTION_ERROR_ATTR_EXEC_ON,
-	KACTION_ERROR_ATTR_UPDATE_RETCODE,
-	KACTION_ERROR_ATTR_SCRIPT,
-} kaction_error_e;
-
+typedef struct kaction_s kaction_t;
 
 typedef enum {
+	KACTION_COND_NONE,
 	KACTION_COND_FAIL,
 	KACTION_COND_SUCCESS,
 	KACTION_COND_ALWAYS
@@ -33,10 +22,8 @@ typedef enum {
 
 C_DECL_BEGIN
 
-kaction_t *kaction_new(const iaction_t *info, kaction_error_e *error);
+kaction_t *kaction_new(void);
 void kaction_free(kaction_t *action);
-const char *kaction_strerror(kaction_error_e error);
-bool_t kaction_parse(kaction_t *action, const iaction_t *info, kaction_error_e *error);
 
 const char *kaction_sym_ref(const kaction_t *action);
 bool_t kaction_set_sym_ref(kaction_t *action, const char *sym_ref);
@@ -53,7 +40,8 @@ bool_t kaction_set_update_retcode(kaction_t *action, bool_t update_retcode);
 const char *kaction_script(const kaction_t *action);
 bool_t kaction_set_script(kaction_t *action, const char *script);
 
-kaction_t *kaction_from_iaction(iaction_t *iaction, faux_error_t *error_stack);
+bool_t kaction_parse(kaction_t *action, const iaction_t *info, faux_error_t *error);
+kaction_t *kaction_from_iaction(iaction_t *iaction, faux_error_t *error);
 
 C_DECL_END
 

+ 8 - 14
klish/kcommand.h

@@ -10,36 +10,30 @@
 #include <klish/kparam.h>
 #include <klish/kaction.h>
 
+
 typedef struct kcommand_s kcommand_t;
 
-typedef enum {
-	KCOMMAND_ERROR_OK,
-	KCOMMAND_ERROR_INTERNAL,
-	KCOMMAND_ERROR_ALLOC,
-	KCOMMAND_ERROR_ATTR_NAME,
-	KCOMMAND_ERROR_ATTR_HELP,
-} kcommand_error_e;
 
 C_DECL_BEGIN
 
-kcommand_t *kcommand_new(const icommand_t *info, kcommand_error_e *error);
+kcommand_t *kcommand_new(const char *name);
 void kcommand_free(kcommand_t *command);
-const char *kcommand_strerror(kcommand_error_e error);
-bool_t kcommand_parse(kcommand_t *command, const icommand_t *info,
-	kcommand_error_e *error);
 
 const char *kcommand_name(const kcommand_t *command);
-bool_t kcommand_set_name(kcommand_t *command, const char *name);
 const char *kcommand_help(const kcommand_t *command);
 bool_t kcommand_set_help(kcommand_t *command, const char *help);
 
 bool_t kcommand_add_param(kcommand_t *command, kparam_t *param);
 kparam_t *kcommand_find_param(const kcommand_t *command, const char *name);
+ssize_t kcommand_params_len(const kcommand_t *command);
 bool_t kcommand_add_action(kcommand_t *command, kaction_t *action);
+ssize_t kcommand_actions_len(const kcommand_t *command);
 
+bool_t kcommand_parse(kcommand_t *command, const icommand_t *info,
+	faux_error_t *error);
 bool_t kcommand_nested_from_icommand(kcommand_t *kcommand, icommand_t *icommand,
-	faux_error_t *error_stack);
-kcommand_t *kcommand_from_icommand(icommand_t *icommand, faux_error_t *error_stack);
+	faux_error_t *error);
+kcommand_t *kcommand_from_icommand(icommand_t *icommand, faux_error_t *error);
 
 C_DECL_END
 

+ 10 - 0
klish/khelper.h

@@ -126,6 +126,16 @@
 	return strcmp(f, k##nested##_##field(s)); \
 }
 
+#define _KNESTED_LEN(obj, nested) \
+	ssize_t k##obj##_##nested##s_len(const k##obj##_t *inst)
+#define KNESTED_LEN(obj, nested) \
+	_KNESTED_LEN(obj, nested) { \
+	assert(inst); \
+	if (!inst) \
+		return -1; \
+	return faux_list_len(inst->nested##s); \
+}
+
 
 C_DECL_BEGIN
 

+ 5 - 15
klish/kparam.h

@@ -9,27 +9,16 @@
 #include <faux/error.h>
 #include <klish/iparam.h>
 
-typedef struct kparam_s kparam_t;
 
-typedef enum {
-	KPARAM_ERROR_OK,
-	KPARAM_ERROR_INTERNAL,
-	KPARAM_ERROR_ALLOC,
-	KPARAM_ERROR_ATTR_NAME,
-	KPARAM_ERROR_ATTR_HELP,
-	KPARAM_ERROR_ATTR_PTYPE,
-} kparam_error_e;
+typedef struct kparam_s kparam_t;
 
 
 C_DECL_BEGIN
 
-kparam_t *kparam_new(const iparam_t *info, kparam_error_e *error);
+kparam_t *kparam_new(const char *name);
 void kparam_free(kparam_t *param);
-const char *kparam_strerror(kparam_error_e error);
-bool_t kparam_parse(kparam_t *param, const iparam_t *info, kparam_error_e *error);
 
 const char *kparam_name(const kparam_t *param);
-bool_t kparam_set_name(kparam_t *param, const char *name);
 const char *kparam_help(const kparam_t *param);
 bool_t kparam_set_help(kparam_t *param, const char *help);
 const char *kparam_ptype_ref(const kparam_t *param);
@@ -38,9 +27,10 @@ bool_t kparam_set_ptype_ref(kparam_t *param, const char *ptype_ref);
 bool_t kparam_add_param(kparam_t *param, kparam_t *nested_param);
 kparam_t *kparam_find_param(const kparam_t *param, const char *name);
 
+bool_t kparam_parse(kparam_t *param, const iparam_t *info, faux_error_t *error);
 bool_t kparam_nested_from_iparam(kparam_t *kparam, iparam_t *iparam,
-	faux_error_t *error_stack);
-kparam_t *kparam_from_iparam(iparam_t *iparam, faux_error_t *error_stack);
+	faux_error_t *error);
+kparam_t *kparam_from_iparam(iparam_t *iparam, faux_error_t *error);
 
 C_DECL_END
 

+ 3 - 0
klish/kscheme/Makefile.am

@@ -4,7 +4,10 @@ libklish_la_SOURCES += \
 	klish/kscheme/kplugin.c \
 	klish/kscheme/kptype.c \
 	klish/kscheme/kaction.c \
+	klish/kscheme/kaction_parse.c \
 	klish/kscheme/kparam.c \
+	klish/kscheme/kparam_parse.c \
 	klish/kscheme/kcommand.c \
+	klish/kscheme/kcommand_parse.c \
 	klish/kscheme/kview.c \
 	klish/kscheme/kscheme.c

+ 8 - 170
klish/kscheme/kaction.c

@@ -8,6 +8,7 @@
 #include <faux/list.h>
 #include <klish/khelper.h>
 #include <klish/kaction.h>
+#include <klish/ksym.h>
 
 
 struct kaction_s {
@@ -18,7 +19,7 @@ struct kaction_s {
 	kaction_cond_e exec_on;
 	bool_t update_retcode;
 	char *script;
-	//ksym_t *sym; // Symbol
+	ksym_t *sym; // Symbol
 };
 
 
@@ -52,8 +53,12 @@ KSET_BOOL(action, update_retcode);
 KGET_STR(action, script);
 KSET_STR(action, script);
 
+// Symbol
+KGET(action, ksym_t *, sym);
+KSET(action, ksym_t *, sym);
 
-static kaction_t *kaction_new_empty(void)
+
+kaction_t *kaction_new(void)
 {
 	kaction_t *action = NULL;
 
@@ -70,30 +75,7 @@ static kaction_t *kaction_new_empty(void)
 	action->exec_on = KACTION_COND_SUCCESS;
 	action->update_retcode = BOOL_TRUE;
 	action->script = NULL;
-
-	return action;
-}
-
-
-kaction_t *kaction_new(const iaction_t *info, kaction_error_e *error)
-{
-	kaction_t *action = NULL;
-
-	action = kaction_new_empty();
-	assert(action);
-	if (!action) {
-		if (error)
-			*error = KACTION_ERROR_ALLOC;
-		return NULL;
-	}
-
-	if (!info)
-		return action;
-
-	if (!kaction_parse(action, info, error)) {
-		kaction_free(action);
-		return NULL;
-	}
+	action->sym = NULL;
 
 	return action;
 }
@@ -110,147 +92,3 @@ void kaction_free(kaction_t *action)
 
 	faux_free(action);
 }
-
-
-const char *kaction_strerror(kaction_error_e error)
-{
-	const char *str = NULL;
-
-	switch (error) {
-	case KACTION_ERROR_OK:
-		str = "Ok";
-		break;
-	case KACTION_ERROR_INTERNAL:
-		str = "Internal error";
-		break;
-	case KACTION_ERROR_ALLOC:
-		str = "Memory allocation error";
-		break;
-	case KACTION_ERROR_ATTR_SYM:
-		str = "Illegal 'sym' attribute";
-		break;
-	case KACTION_ERROR_ATTR_LOCK:
-		str = "Illegal 'lock' attribute";
-		break;
-	case KACTION_ERROR_ATTR_INTERRUPT:
-		str = "Illegal 'interrupt' attribute";
-		break;
-	case KACTION_ERROR_ATTR_INTERACTIVE:
-		str = "Illegal 'interactive' attribute";
-		break;
-	case KACTION_ERROR_ATTR_UPDATE_RETCODE:
-		str = "Illegal 'update_retcode' attribute";
-		break;
-	case KACTION_ERROR_ATTR_SCRIPT:
-		str = "Illegal script";
-		break;
-	default:
-		str = "Unknown error";
-		break;
-	}
-
-	return str;
-}
-
-
-bool_t kaction_parse(kaction_t *action, const iaction_t *info, kaction_error_e *error)
-{
-	// Sym
-	if (!faux_str_is_empty(info->sym)) {
-		if (!kaction_set_sym_ref(action, info->sym)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_SYM;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Lock
-	if (!faux_str_is_empty(info->lock)) {
-		if (!kaction_set_lock(action, info->lock)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_LOCK;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Interrupt
-	if (!faux_str_is_empty(info->interrupt)) {
-		bool_t b = BOOL_FALSE;
-		if (!faux_conv_str2bool(info->interrupt, &b) ||
-			!kaction_set_interrupt(action, b)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_INTERRUPT;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Interactive
-	if (!faux_str_is_empty(info->interactive)) {
-		bool_t b = BOOL_FALSE;
-		if (!faux_conv_str2bool(info->interactive, &b) ||
-			!kaction_set_interactive(action, b)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_INTERACTIVE;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Exec_on
-	if (!faux_str_is_empty(info->exec_on)) {
-		kaction_cond_e c = KACTION_COND_SUCCESS;
-		if (faux_str_casecmp(info->exec_on, "fail"))
-			c = KACTION_COND_FAIL;
-		else if (faux_str_casecmp(info->exec_on, "success"))
-			c = KACTION_COND_SUCCESS;
-		else if (faux_str_casecmp(info->exec_on, "always"))
-			c = KACTION_COND_ALWAYS;
-		else {
-			if (error)
-				*error = KACTION_ERROR_ATTR_EXEC_ON;
-			return BOOL_FALSE;
-		}
-		if (!kaction_set_exec_on(action, c)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_EXEC_ON;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Update_retcode
-	if (!faux_str_is_empty(info->update_retcode)) {
-		bool_t b = BOOL_FALSE;
-		if (!faux_conv_str2bool(info->update_retcode, &b) ||
-			!kaction_set_update_retcode(action, b)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_UPDATE_RETCODE;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Script
-	if (!faux_str_is_empty(info->script)) {
-		if (!kaction_set_script(action, info->script)) {
-			if (error)
-				*error = KACTION_ERROR_ATTR_SCRIPT;
-			return BOOL_FALSE;
-		}
-	}
-
-	return BOOL_TRUE;
-}
-
-
-kaction_t *kaction_from_iaction(iaction_t *iaction, faux_error_t *error_stack)
-{
-	kaction_t *kaction = NULL;
-	kaction_error_e kaction_error = KACTION_ERROR_OK;
-
-	kaction = kaction_new(iaction, &kaction_error);
-	if (!kaction) {
-		faux_error_sprintf(error_stack, "ACTION : %s",
-			kaction_strerror(kaction_error));
-		return NULL;
-	}
-
-	return kaction;
-}

+ 107 - 0
klish/kscheme/kaction_parse.c

@@ -0,0 +1,107 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <faux/str.h>
+#include <faux/conv.h>
+#include <faux/list.h>
+#include <faux/error.h>
+#include <klish/khelper.h>
+#include <klish/kaction.h>
+
+#define TAG "ACTION"
+
+bool_t kaction_parse(kaction_t *action, const iaction_t *info, faux_error_t *error)
+{
+	bool_t retcode = BOOL_TRUE;
+
+	// Sym
+	if (!faux_str_is_empty(info->sym)) {
+		if (!kaction_set_sym_ref(action, info->sym)) {
+			faux_error_add(error, TAG": Illegal 'sym' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Lock
+	if (!faux_str_is_empty(info->lock)) {
+		if (!kaction_set_lock(action, info->lock)) {
+			faux_error_add(error, TAG": Illegal 'lock' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Interrupt
+	if (!faux_str_is_empty(info->interrupt)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->interrupt, &b) ||
+			!kaction_set_interrupt(action, b)) {
+			faux_error_add(error, TAG": Illegal 'interrupt' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Interactive
+	if (!faux_str_is_empty(info->interactive)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->interactive, &b) ||
+			!kaction_set_interactive(action, b)) {
+			faux_error_add(error, TAG": Illegal 'interactive' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Exec_on
+	if (!faux_str_is_empty(info->exec_on)) {
+		kaction_cond_e c = KACTION_COND_NONE;
+		if (faux_str_casecmp(info->exec_on, "fail"))
+			c = KACTION_COND_FAIL;
+		else if (faux_str_casecmp(info->exec_on, "success"))
+			c = KACTION_COND_SUCCESS;
+		else if (faux_str_casecmp(info->exec_on, "always"))
+			c = KACTION_COND_ALWAYS;
+		if ((KACTION_COND_NONE == c) || !kaction_set_exec_on(action, c)) {
+			faux_error_add(error, TAG": Illegal 'exec_on' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Update_retcode
+	if (!faux_str_is_empty(info->update_retcode)) {
+		bool_t b = BOOL_FALSE;
+		if (!faux_conv_str2bool(info->update_retcode, &b) ||
+			!kaction_set_update_retcode(action, b)) {
+			faux_error_add(error, TAG": Illegal 'update_retcode' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// Script
+	if (!faux_str_is_empty(info->script)) {
+		if (!kaction_set_script(action, info->script)) {
+			faux_error_add(error, TAG": Illegal 'script' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	return retcode;
+}
+
+
+kaction_t *kaction_from_iaction(iaction_t *iaction, faux_error_t *error)
+{
+	kaction_t *kaction = NULL;
+
+	kaction = kaction_new();
+	if (!kaction) {
+		faux_error_add(error, TAG": Can't create object");
+		return NULL;
+	}
+	if (!kaction_parse(kaction, iaction, error)) {
+		kaction_free(kaction);
+		return NULL;
+	}
+
+	return kaction;
+}

+ 7 - 186
klish/kscheme/kcommand.c

@@ -5,7 +5,6 @@
 
 #include <faux/str.h>
 #include <faux/list.h>
-#include <faux/error.h>
 #include <klish/khelper.h>
 #include <klish/kparam.h>
 #include <klish/kaction.h>
@@ -23,7 +22,6 @@ struct kcommand_s {
 
 // Name
 KGET_STR(command, name);
-KSET_STR_ONCE(command, name);
 
 // Help
 KGET_STR(command, help);
@@ -34,22 +32,27 @@ static KCMP_NESTED(command, param, name);
 static KCMP_NESTED_BY_KEY(command, param, name);
 KADD_NESTED(command, param);
 KFIND_NESTED(command, param);
+KNESTED_LEN(command, param);
 
 // ACTION list
 KADD_NESTED(command, action);
+KNESTED_LEN(command, action);
 
 
-static kcommand_t *kcommand_new_empty(void)
+kcommand_t *kcommand_new(const char *name)
 {
 	kcommand_t *command = NULL;
 
+	if (faux_str_is_empty(name))
+		return NULL;
+
 	command = faux_zmalloc(sizeof(*command));
 	assert(command);
 	if (!command)
 		return NULL;
 
 	// Initialize
-	command->name = NULL;
+	command->name = faux_str_dup(name);
 	command->help = NULL;
 
 	// PARAM list
@@ -67,30 +70,6 @@ static kcommand_t *kcommand_new_empty(void)
 }
 
 
-kcommand_t *kcommand_new(const icommand_t *info, kcommand_error_e *error)
-{
-	kcommand_t *command = NULL;
-
-	command = kcommand_new_empty();
-	assert(command);
-	if (!command) {
-		if (error)
-			*error = KCOMMAND_ERROR_ALLOC;
-		return NULL;
-	}
-
-	if (!info)
-		return command;
-
-	if (!kcommand_parse(command, info, error)) {
-		kcommand_free(command);
-		return NULL;
-	}
-
-	return command;
-}
-
-
 void kcommand_free(kcommand_t *command)
 {
 	if (!command)
@@ -103,161 +82,3 @@ void kcommand_free(kcommand_t *command)
 
 	faux_free(command);
 }
-
-
-const char *kcommand_strerror(kcommand_error_e error)
-{
-	const char *str = NULL;
-
-	switch (error) {
-	case KCOMMAND_ERROR_OK:
-		str = "Ok";
-		break;
-	case KCOMMAND_ERROR_INTERNAL:
-		str = "Internal error";
-		break;
-	case KCOMMAND_ERROR_ALLOC:
-		str = "Memory allocation error";
-		break;
-	case KCOMMAND_ERROR_ATTR_NAME:
-		str = "Illegal 'name' attribute";
-		break;
-	case KCOMMAND_ERROR_ATTR_HELP:
-		str = "Illegal 'help' attribute";
-		break;
-	default:
-		str = "Unknown error";
-		break;
-	}
-
-	return str;
-}
-
-
-bool_t kcommand_parse(kcommand_t *command, const icommand_t *info, kcommand_error_e *error)
-{
-	// Name [mandatory]
-	if (faux_str_is_empty(info->name)) {
-		if (error)
-			*error = KCOMMAND_ERROR_ATTR_NAME;
-		return BOOL_FALSE;
-	} else {
-		if (!kcommand_set_name(command, info->name)) {
-			if (error)
-				*error = KCOMMAND_ERROR_ATTR_NAME;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Help
-	if (!faux_str_is_empty(info->name)) {
-		if (!kcommand_set_help(command, info->help)) {
-			if (error)
-				*error = KCOMMAND_ERROR_ATTR_HELP;
-			return BOOL_FALSE;
-		}
-	}
-
-	return BOOL_TRUE;
-}
-
-
-bool_t kcommand_nested_from_icommand(kcommand_t *kcommand, icommand_t *icommand,
-	faux_error_t *error_stack)
-{
-	bool_t retval = BOOL_TRUE;
-
-	if (!kcommand || !icommand) {
-		faux_error_add(error_stack,
-			kcommand_strerror(KCOMMAND_ERROR_INTERNAL));
-		return BOOL_FALSE;
-	}
-
-
-	// PARAM list
-	if (icommand->params) {
-		iparam_t **p_iparam = NULL;
-		for (p_iparam = *icommand->params; *p_iparam; p_iparam++) {
-			kparam_t *kparam = NULL;
-			iparam_t *iparam = *p_iparam;
-
-			kparam = kparam_from_iparam(iparam, error_stack);
-			if (!kparam) {
-				retval = BOOL_FALSE;
-				continue;
-			}
-			if (!kcommand_add_param(kcommand, kparam)) {
-				// Search for PARAM duplicates
-				if (kcommand_find_param(kcommand,
-					kparam_name(kparam))) {
-					faux_error_sprintf(error_stack,
-						"COMMAND: "
-						"Can't add duplicate PARAM "
-						"\"%s\"",
-						kparam_name(kparam));
-				} else {
-					faux_error_sprintf(error_stack,
-						"COMMAND: "
-						"Can't add PARAM \"%s\"",
-						kparam_name(kparam));
-				}
-				kparam_free(kparam);
-				retval = BOOL_FALSE;
-				continue;
-			}
-		}
-	}
-
-	// ACTION list
-	if (icommand->actions) {
-		iaction_t **p_iaction = NULL;
-		for (p_iaction = *icommand->actions; *p_iaction; p_iaction++) {
-			kaction_t *kaction = NULL;
-			iaction_t *iaction = *p_iaction;
-
-			kaction = kaction_from_iaction(iaction, error_stack);
-			if (!kaction) {
-				retval = BOOL_FALSE;
-				continue;
-			}
-			if (!kcommand_add_action(kcommand, kaction)) {
-				faux_error_sprintf(error_stack, "COMMAND: "
-					"Can't add ACTION #%d",
-					faux_list_len(kcommand->actions) + 1);
-				kaction_free(kaction);
-				retval = BOOL_FALSE;
-				continue;
-			}
-		}
-	}
-
-	if (!retval)
-		faux_error_sprintf(error_stack,
-			"COMMAND \"%s\": Illegal nested elements",
-			kcommand_name(kcommand));
-
-	return retval;
-}
-
-
-kcommand_t *kcommand_from_icommand(icommand_t *icommand, faux_error_t *error_stack)
-{
-	kcommand_t *kcommand = NULL;
-	kcommand_error_e kcommand_error = KCOMMAND_ERROR_OK;
-
-	kcommand = kcommand_new(icommand, &kcommand_error);
-	if (!kcommand) {
-		faux_error_sprintf(error_stack, "COMMAND \"%s\": %s",
-			icommand->name ? icommand->name : "(null)",
-			kcommand_strerror(kcommand_error));
-		return NULL;
-	}
-
-	// Parse nested elements
-	if (!kcommand_nested_from_icommand(kcommand, icommand, error_stack)) {
-		kcommand_free(kcommand);
-		return NULL;
-	}
-
-	return kcommand;
-}

+ 136 - 0
klish/kscheme/kcommand_parse.c

@@ -0,0 +1,136 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <faux/str.h>
+#include <faux/list.h>
+#include <faux/error.h>
+#include <klish/khelper.h>
+#include <klish/icommand.h>
+#include <klish/kparam.h>
+#include <klish/kaction.h>
+#include <klish/kcommand.h>
+
+#define TAG "COMMAND"
+
+bool_t kcommand_parse(kcommand_t *command, const icommand_t *info,
+	faux_error_t *error)
+{
+	bool_t retcode = BOOL_TRUE;
+
+	// Help
+	if (!faux_str_is_empty(info->help)) {
+		if (!kcommand_set_help(command, info->help)) {
+			faux_error_add(error, TAG": Illegal 'help' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	return retcode;
+}
+
+
+bool_t kcommand_nested_from_icommand(kcommand_t *kcommand, icommand_t *icommand,
+	faux_error_t *error)
+{
+	bool_t retval = BOOL_TRUE;
+
+	if (!kcommand || !icommand) {
+		faux_error_add(error, TAG": Internal error");
+		return BOOL_FALSE;
+	}
+
+
+	// PARAM list
+	if (icommand->params) {
+		iparam_t **p_iparam = NULL;
+		for (p_iparam = *icommand->params; *p_iparam; p_iparam++) {
+			kparam_t *kparam = NULL;
+			iparam_t *iparam = *p_iparam;
+
+			kparam = kparam_from_iparam(iparam, error);
+			if (!kparam) {
+				retval = BOOL_FALSE;
+				continue;
+			}
+			if (!kcommand_add_param(kcommand, kparam)) {
+				// Search for PARAM duplicates
+				if (kcommand_find_param(kcommand,
+					kparam_name(kparam))) {
+					faux_error_sprintf(error,
+						TAG": Can't add duplicate PARAM "
+						"\"%s\"", kparam_name(kparam));
+				} else {
+					faux_error_sprintf(error,
+						TAG": Can't add PARAM \"%s\"",
+						kparam_name(kparam));
+				}
+				kparam_free(kparam);
+				retval = BOOL_FALSE;
+				continue;
+			}
+		}
+	}
+
+	// ACTION list
+	if (icommand->actions) {
+		iaction_t **p_iaction = NULL;
+		for (p_iaction = *icommand->actions; *p_iaction; p_iaction++) {
+			kaction_t *kaction = NULL;
+			iaction_t *iaction = *p_iaction;
+
+			kaction = kaction_from_iaction(iaction, error);
+			if (!kaction) {
+				retval = BOOL_FALSE;
+				continue;
+			}
+			if (!kcommand_add_action(kcommand, kaction)) {
+				faux_error_sprintf(error,
+					TAG": Can't add ACTION #%d",
+					kcommand_actions_len(kcommand) + 1);
+				kaction_free(kaction);
+				retval = BOOL_FALSE;
+				continue;
+			}
+		}
+	}
+
+	if (!retval)
+		faux_error_sprintf(error, TAG" \"%s\": Illegal nested elements",
+			kcommand_name(kcommand));
+
+	return retval;
+}
+
+
+kcommand_t *kcommand_from_icommand(icommand_t *icommand, faux_error_t *error)
+{
+	kcommand_t *kcommand = NULL;
+
+	// Name [mandatory]
+	if (faux_str_is_empty(icommand->name)) {
+		faux_error_add(error, TAG": Empty 'name' attribute");
+		return NULL;
+	}
+
+	kcommand = kcommand_new(icommand->name);
+	if (!kcommand) {
+		faux_error_sprintf(error, TAG" \"%s\": Can't create object",
+			icommand->name);
+		return NULL;
+	}
+
+	if (!kcommand_parse(kcommand, icommand, error)) {
+		kcommand_free(kcommand);
+		return NULL;
+	}
+
+	// Parse nested elements
+	if (!kcommand_nested_from_icommand(kcommand, icommand, error)) {
+		kcommand_free(kcommand);
+		return NULL;
+	}
+
+	return kcommand;
+}

+ 5 - 173
klish/kscheme/kparam.c

@@ -22,7 +22,6 @@ struct kparam_s {
 
 // Name
 KGET_STR(param, name);
-KSET_STR_ONCE(param, name);
 
 // Help
 KGET_STR(param, help);
@@ -43,17 +42,20 @@ KADD_NESTED(param, param);
 KFIND_NESTED(param, param);
 
 
-static kparam_t *kparam_new_empty(void)
+kparam_t *kparam_new(const char *name)
 {
 	kparam_t *param = NULL;
 
+	if (faux_str_is_empty(name))
+		return NULL;
+
 	param = faux_zmalloc(sizeof(*param));
 	assert(param);
 	if (!param)
 		return NULL;
 
 	// Initialize
-	param->name = NULL;
+	param->name = faux_str_dup(name);
 	param->help = NULL;
 	param->ptype_ref = NULL;
 	param->ptype = NULL;
@@ -67,30 +69,6 @@ static kparam_t *kparam_new_empty(void)
 }
 
 
-kparam_t *kparam_new(const iparam_t *info, kparam_error_e *error)
-{
-	kparam_t *param = NULL;
-
-	param = kparam_new_empty();
-	assert(param);
-	if (!param) {
-		if (error)
-			*error = KPARAM_ERROR_ALLOC;
-		return NULL;
-	}
-
-	if (!info)
-		return param;
-
-	if (!kparam_parse(param, info, error)) {
-		kparam_free(param);
-		return NULL;
-	}
-
-	return param;
-}
-
-
 void kparam_free(kparam_t *param)
 {
 	if (!param)
@@ -103,149 +81,3 @@ void kparam_free(kparam_t *param)
 
 	faux_free(param);
 }
-
-
-const char *kparam_strerror(kparam_error_e error)
-{
-	const char *str = NULL;
-
-	switch (error) {
-	case KPARAM_ERROR_OK:
-		str = "Ok";
-		break;
-	case KPARAM_ERROR_INTERNAL:
-		str = "Internal error";
-		break;
-	case KPARAM_ERROR_ALLOC:
-		str = "Memory allocation error";
-		break;
-	case KPARAM_ERROR_ATTR_NAME:
-		str = "Illegal 'name' attribute";
-		break;
-	case KPARAM_ERROR_ATTR_HELP:
-		str = "Illegal 'help' attribute";
-		break;
-	case KPARAM_ERROR_ATTR_PTYPE:
-		str = "Illegal 'ptype' attribute";
-		break;
-	default:
-		str = "Unknown error";
-		break;
-	}
-
-	return str;
-}
-
-
-bool_t kparam_parse(kparam_t *param, const iparam_t *info, kparam_error_e *error)
-{
-	// Name [mandatory]
-	if (faux_str_is_empty(info->name)) {
-		if (error)
-			*error = KPARAM_ERROR_ATTR_NAME;
-		return BOOL_FALSE;
-	} else {
-		if (!kparam_set_name(param, info->name)) {
-			if (error)
-				*error = KPARAM_ERROR_ATTR_NAME;
-			return BOOL_FALSE;
-		}
-	}
-
-	// Help
-	if (!faux_str_is_empty(info->name)) {
-		if (!kparam_set_help(param, info->help)) {
-			if (error)
-				*error = KPARAM_ERROR_ATTR_HELP;
-			return BOOL_FALSE;
-		}
-	}
-
-	// PTYPE reference
-	if (!faux_str_is_empty(info->ptype)) {
-		if (!kparam_set_ptype_ref(param, info->ptype)) {
-			if (error)
-				*error = KPARAM_ERROR_ATTR_PTYPE;
-			return BOOL_FALSE;
-		}
-	}
-
-	return BOOL_TRUE;
-}
-
-
-bool_t kparam_nested_from_iparam(kparam_t *kparam, iparam_t *iparam,
-	faux_error_t *error_stack)
-{
-	bool_t retval = BOOL_TRUE;
-
-	if (!kparam || !iparam) {
-		faux_error_add(error_stack,
-			kparam_strerror(KPARAM_ERROR_INTERNAL));
-		return BOOL_FALSE;
-	}
-
-	// Nested PARAM list
-	if (iparam->params) {
-		iparam_t **p_iparam = NULL;
-		for (p_iparam = *iparam->params; *p_iparam; p_iparam++) {
-			kparam_t *nkparam = NULL;
-			iparam_t *niparam = *p_iparam;
-
-			nkparam = kparam_from_iparam(niparam, error_stack);
-			if (!nkparam) {
-				retval = BOOL_FALSE;
-				continue;
-			}
-			if (!kparam_add_param(kparam, nkparam)) {
-				// Search for PARAM duplicates
-				if (kparam_find_param(kparam,
-					kparam_name(nkparam))) {
-					faux_error_sprintf(error_stack,
-						"PARAM: "
-						"Can't add duplicate PARAM "
-						"\"%s\"",
-						kparam_name(nkparam));
-				} else {
-					faux_error_sprintf(error_stack,
-						"PARAM: "
-						"Can't add PARAM \"%s\"",
-						kparam_name(nkparam));
-				}
-				kparam_free(nkparam);
-				retval = BOOL_FALSE;
-				continue;
-			}
-		}
-	}
-
-	if (!retval)
-		faux_error_sprintf(error_stack,
-			"PARAM \"%s\": Illegal nested elements",
-			kparam_name(kparam));
-
-	return retval;
-}
-
-
-kparam_t *kparam_from_iparam(iparam_t *iparam, faux_error_t *error_stack)
-{
-	kparam_t *kparam = NULL;
-	kparam_error_e kparam_error = KPARAM_ERROR_OK;
-
-	kparam = kparam_new(iparam, &kparam_error);
-	if (!kparam) {
-		faux_error_sprintf(error_stack, "PARAM \"%s\": %s",
-			iparam->name ? iparam->name : "(null)",
-			kparam_strerror(kparam_error));
-		return NULL;
-	}
-
-	// Parse nested elements
-	if (!kparam_nested_from_iparam(kparam, iparam, error_stack)) {
-		kparam_free(kparam);
-		return NULL;
-	}
-
-	return kparam;
-}

+ 117 - 0
klish/kscheme/kparam_parse.c

@@ -0,0 +1,117 @@
+#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/iparam.h>
+#include <klish/kptype.h>
+#include <klish/kparam.h>
+
+#define TAG "PARAM"
+
+bool_t kparam_parse(kparam_t *param, const iparam_t *info, faux_error_t *error)
+{
+	bool_t retcode = BOOL_TRUE;
+
+	// Help
+	if (!faux_str_is_empty(info->help)) {
+		if (!kparam_set_help(param, info->help)) {
+			faux_error_add(error, TAG": Illegal 'help' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	// PTYPE reference
+	if (!faux_str_is_empty(info->ptype)) {
+		if (!kparam_set_ptype_ref(param, info->ptype)) {
+			faux_error_add(error, TAG": Illegal 'ptype' attribute");
+			retcode = BOOL_FALSE;
+		}
+	}
+
+	return retcode;
+}
+
+
+bool_t kparam_nested_from_iparam(kparam_t *kparam, iparam_t *iparam,
+	faux_error_t *error)
+{
+	bool_t retval = BOOL_TRUE;
+
+	if (!kparam || !iparam) {
+		faux_error_add(error, TAG": Internal error");
+		return BOOL_FALSE;
+	}
+
+	// Nested PARAM list
+	if (iparam->params) {
+		iparam_t **p_iparam = NULL;
+		for (p_iparam = *iparam->params; *p_iparam; p_iparam++) {
+			kparam_t *nkparam = NULL;
+			iparam_t *niparam = *p_iparam;
+
+			nkparam = kparam_from_iparam(niparam, error);
+			if (!nkparam) {
+				retval = BOOL_FALSE;
+				continue;
+			}
+			if (!kparam_add_param(kparam, nkparam)) {
+				// Search for PARAM duplicates
+				if (kparam_find_param(kparam,
+					kparam_name(nkparam))) {
+					faux_error_sprintf(error,
+						TAG": Can't add duplicate PARAM "
+						"\"%s\"", kparam_name(nkparam));
+				} else {
+					faux_error_sprintf(error,
+						TAG": Can't add PARAM \"%s\"",
+						kparam_name(nkparam));
+				}
+				kparam_free(nkparam);
+				retval = BOOL_FALSE;
+				continue;
+			}
+		}
+	}
+
+	if (!retval)
+		faux_error_sprintf(error, TAG" \"%s\": Illegal nested elements",
+			kparam_name(kparam));
+
+	return retval;
+}
+
+
+kparam_t *kparam_from_iparam(iparam_t *iparam, faux_error_t *error)
+{
+	kparam_t *kparam = NULL;
+
+	// Name [mandatory]
+	if (faux_str_is_empty(iparam->name)) {
+		faux_error_add(error, TAG": Empty 'name' attribute");
+		return NULL;
+	}
+
+	kparam = kparam_new(iparam->name);
+	if (!kparam) {
+		faux_error_sprintf(error, TAG" \"%s\": Can't create object",
+			iparam->name);
+		return NULL;
+	}
+
+	if (!kparam_parse(kparam, iparam, error)) {
+		kparam_free(kparam);
+		return NULL;
+	}
+
+	// Parse nested elements
+	if (!kparam_nested_from_iparam(kparam, iparam, error)) {
+		kparam_free(kparam);
+		return NULL;
+	}
+
+	return kparam;
+}