Browse Source

ptype as a entry's purpose. parse_for_local_exec()

Serj Kalichev 2 years ago
parent
commit
e339a4492a

+ 1 - 0
klish.xsd

@@ -155,6 +155,7 @@
 	<xs:simpleType name="entry_purpose_t">
 		<xs:restriction base="xs:string">
 			<xs:enumeration value="common"/>
+			<xs:enumeration value="ptype"/>
 			<xs:enumeration value="prompt"/>
 			<xs:enumeration value="cond"/>
 			<xs:enumeration value="completion"/>

+ 5 - 9
klish/ischeme/ientry.c

@@ -60,6 +60,8 @@ bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error)
 		kentry_purpose_e purpose = KENTRY_PURPOSE_NONE;
 		if (!faux_str_casecmp(info->purpose, "common"))
 			purpose = KENTRY_PURPOSE_COMMON;
+		else if (!faux_str_casecmp(info->purpose, "ptype"))
+			purpose = KENTRY_PURPOSE_PTYPE;
 		else if (!faux_str_casecmp(info->purpose, "prompt"))
 			purpose = KENTRY_PURPOSE_PROMPT;
 		else if (!faux_str_casecmp(info->purpose, "cond"))
@@ -92,14 +94,6 @@ bool_t ientry_parse(const ientry_t *info, kentry_t *entry, faux_error_t *error)
 		}
 	}
 
-	// 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)) {
@@ -319,6 +313,9 @@ char *ientry_deploy(const kentry_t *kentry, int level)
 		case KENTRY_PURPOSE_COMMON:
 			purpose = "common";
 			break;
+		case KENTRY_PURPOSE_PTYPE:
+			purpose = "ptype";
+			break;
 		case KENTRY_PURPOSE_PROMPT:
 			purpose = "prompt";
 			break;
@@ -345,7 +342,6 @@ char *ientry_deploy(const kentry_t *kentry, int level)
 		faux_str_free(num);
 		num = NULL;
 
-		attr2ctext(&str, "ptype", kentry_ptype_str(kentry), level + 1);
 		attr2ctext(&str, "value", kentry_value(kentry), level + 1);
 		attr2ctext(&str, "restore", faux_conv_bool2str(kentry_restore(kentry)), level + 1);
 		attr2ctext(&str, "order", faux_conv_bool2str(kentry_order(kentry)), level + 1);

+ 1 - 5
klish/kentry.h

@@ -26,6 +26,7 @@ typedef enum {
 typedef enum {
 	KENTRY_PURPOSE_NONE,
 	KENTRY_PURPOSE_COMMON, // Common entry like view/command/param
+	KENTRY_PURPOSE_PTYPE,
 	KENTRY_PURPOSE_PROMPT, // Prompt for view
 	KENTRY_PURPOSE_COND, // Conditional expression
 	KENTRY_PURPOSE_COMPLETION, // Engine to generate completions
@@ -69,11 +70,6 @@ bool_t kentry_set_min(kentry_t *entry, size_t min);
 // Max occurs
 size_t kentry_max(const kentry_t *entry);
 bool_t kentry_set_max(kentry_t *entry, size_t max);
-// Ptype
-const char *kentry_ptype_str(const kentry_t *entry);
-bool_t kentry_set_ptype_str(kentry_t *entry, const char *ptype_str);
-kentry_t *kentry_ptype(const kentry_t *entry);
-bool_t kentry_set_ptype(kentry_t *entry, kentry_t *ptype);
 // Ref
 const char *kentry_ref_str(const kentry_t *entry);
 bool_t kentry_set_ref_str(kentry_t *entry, const char *ref_str);

+ 0 - 15
klish/kscheme/kentry.c

@@ -20,8 +20,6 @@ struct kentry_s {
 	kentry_purpose_e purpose; // Special purpose of ENTRY
 	size_t min; // Min occurs of entry
 	size_t max; // Max occurs of entry
-	char *ptype_str; // Text reference to PTYPE
-	kentry_t *ptype; // Resolved entry's PTYPE
 	char *ref_str; // Text reference to aliased ENTRY
 	char *value; // Additional info
 	bool_t restore; // Should entry restore its depth while execution
@@ -67,13 +65,6 @@ KSET(entry, size_t, min);
 KGET(entry, size_t, max);
 KSET(entry, size_t, max);
 
-// PTYPE string (must be resolved later)
-KGET_STR(entry, ptype_str);
-KSET_STR(entry, ptype_str);
-// PTYPE (resolved)
-KGET(entry, kentry_t *, ptype);
-KSET(entry, kentry_t *, ptype);
-
 // Ref string (must be resolved later)
 KGET_STR(entry, ref_str);
 KSET_STR(entry, ref_str);
@@ -134,8 +125,6 @@ kentry_t *kentry_new(const char *name)
 	entry->purpose = KENTRY_PURPOSE_COMMON;
 	entry->min = 1;
 	entry->max = 1;
-	entry->ptype_str = NULL;
-	entry->ptype = NULL;
 	entry->ref_str = NULL;
 	entry->value = NULL;
 	entry->restore = BOOL_FALSE;
@@ -164,8 +153,6 @@ static void kentry_free_non_link(kentry_t *entry)
 	if (!entry)
 		return;
 
-	faux_str_free(entry->ptype_str);
-
 	faux_list_free(entry->entrys);
 	faux_list_free(entry->actions);
 }
@@ -222,8 +209,6 @@ bool_t kentry_link(kentry_t *dst, const kentry_t *src)
 	// purpose - orig
 	// min - orig
 	// max - orig
-	dst->ptype_str = src->ptype_str;
-	dst->ptype = src->ptype;
 	// ref_str - orig
 	// value - orig
 	// restore - orig

+ 0 - 12
klish/kscheme/kscheme.c

@@ -312,7 +312,6 @@ bool_t kscheme_prepare_entry(kscheme_t *scheme, kentry_t *entry,
 	bool_t retcode = BOOL_TRUE;
 	const char *ref = NULL;
 	kentry_t *ref_entry = NULL;
-	const char *ptype_str = NULL;
 
 	assert(scheme);
 	if (!scheme)
@@ -337,17 +336,6 @@ bool_t kscheme_prepare_entry(kscheme_t *scheme, kentry_t *entry,
 		}
 	}
 
-	// Resolve ptype's ENTRY
-	if ((ptype_str = kentry_ptype_str(entry))) {
-		ref_entry = kscheme_find_entry_by_path(scheme, ptype_str);
-		if (!ref_entry) {
-			faux_error_sprintf(error, "Can't find ENTRY \"%s\" for ptype",
-				ptype_str);
-			retcode = BOOL_FALSE;
-		}
-		kentry_set_ptype(entry, ref_entry);
-	}
-
 	// ACTIONs
 	if (!kscheme_prepare_action_list(scheme, entry, error))
 		retcode = BOOL_FALSE;

+ 3 - 3
klish/ksession.h

@@ -35,10 +35,10 @@ kpargv_t *ksession_parse_for_completion(ksession_t *session,
 	const char *raw_line);
 kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 	faux_error_t *error);
+kexec_t *ksession_parse_for_local_exec(kentry_t *entry);
 
-bool_t ksession_exec_locally(ksession_t *session, const char *line,
-	int *retcode, faux_error_t *error);
-
+bool_t ksession_exec_locally(ksession_t *session, kentry_t *entry,
+	int *retcode, const char **out);
 
 C_DECL_END
 

+ 20 - 21
klish/ksession/ksession.c

@@ -175,18 +175,21 @@ static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
 }
 
 
-bool_t ksession_exec_locally(ksession_t *session, const char *line,
-	int *retcode, faux_error_t *error)
+bool_t ksession_exec_locally(ksession_t *session, kentry_t *entry,
+	int *retcode, const char **out)
 {
 	kexec_t *exec = NULL;
 	faux_eloop_t *eloop = NULL;
+	faux_buf_t *buf = NULL;
+	char *cstr = NULL;
+	ssize_t len = 0;
 
-	assert(session);
-	if (!session)
+	assert(entry);
+	if (!entry)
 		return BOOL_FALSE;
 
 	// Parsing
-	exec = ksession_parse_for_exec(session, line, error);
+	exec = ksession_parse_for_local_exec(entry);
 	if (!exec)
 		return BOOL_FALSE;
 
@@ -223,23 +226,19 @@ bool_t ksession_exec_locally(ksession_t *session, const char *line,
 
 	kexec_retcode(exec, retcode);
 
-	// Debug only
-	{
-		faux_buf_t *buf = NULL;
-		printf("STDOUT:\n");
-		fflush(stdout);
-		ssize_t r = 0;
-		buf = kexec_bufout(exec);
-		do {
-			void *d = NULL;
-			ssize_t really_readed = 0;
-			r = faux_buf_dread_lock_easy(buf, &d);
-			if (r > 0) {
-				really_readed = write(STDOUT_FILENO, d, r);
-			}
-			faux_buf_dread_unlock_easy(buf, really_readed);
-		} while (r > 0);
+	if (!out) {
+		kexec_free(exec);
+		return BOOL_TRUE;
+	}
+	buf = kexec_bufout(exec);
+	if ((len = faux_buf_len(buf)) <= 0) {
+		kexec_free(exec);
+		return BOOL_TRUE;
 	}
+	cstr = faux_malloc(len + 1);
+	faux_buf_read(buf, cstr, len);
+	cstr[len] = '\0';
+	*out = cstr;
 
 	kexec_free(exec);
 

+ 69 - 6
klish/ksession/ksession_parse.c

@@ -41,7 +41,7 @@ static bool_t ksession_validate_arg(kentry_t *entry, const char *arg)
 
 
 static kpargv_status_e ksession_parse_arg(kentry_t *current_entry,
-	faux_argv_node_t **argv_iter, kpargv_t *pargv)
+	faux_argv_node_t **argv_iter, kpargv_t *pargv, bool_t entry_is_command)
 {
 	kentry_t *entry = current_entry;
 	kentry_mode_e mode = KENTRY_MODE_NONE;
@@ -62,9 +62,24 @@ static kpargv_status_e ksession_parse_arg(kentry_t *current_entry,
 
 	purpose = kpargv_purpose(pargv); // Purpose of parsing
 
+	// If we know the entry is a command then don't validate it. This
+	// behaviour is usefull for special purpose entries like PTYPEs, CONDs,
+	// etc. These entries are the starting point for parsing their args.
+	// We don't need to parse command itself. Command is predefined.
+	if (entry_is_command) {
+		kparg_t *parg = NULL;
+
+		// Command is an ENTRY with ACTIONs
+		if (kentry_actions_len(entry) <= 0)
+			return KPARSE_ILLEGAL;
+		parg = kparg_new(entry, NULL);
+		kpargv_add_pargs(pargv, parg);
+		kpargv_set_command(pargv, entry);
+		retcode = KPARSE_INPROGRESS;
+
 	// Is entry candidate to resolve current arg?
 	// Container can't be a candidate.
-	if (!kentry_container(entry)) {
+	} else if (!kentry_container(entry)) {
 		const char *current_arg = NULL;
 
 //printf("arg: %s, entry: %s\n", *argv_iter ? faux_argv_current(*argv_iter) : "<empty>",
@@ -137,7 +152,7 @@ static kpargv_status_e ksession_parse_arg(kentry_t *current_entry,
 			if (kentry_purpose(nested) != KENTRY_PURPOSE_COMMON)
 				continue;
 //printf("SWITCH arg: %s, entry %s\n", *argv_iter ? faux_argv_current(*argv_iter) : "<empty>", kentry_name(nested));
-			rc = ksession_parse_arg(nested, argv_iter, pargv);
+			rc = ksession_parse_arg(nested, argv_iter, pargv, BOOL_FALSE);
 //printf("%s\n", kpargv_status_decode(rc));
 			// If some arguments was consumed then we will not check
 			// next SWITCH's entries in any case.
@@ -171,7 +186,8 @@ static kpargv_status_e ksession_parse_arg(kentry_t *current_entry,
 			// (from 'min' to 'max' times)
 			for (num = 0; num < kentry_max(nested); num++) {
 //printf("SEQ arg: %s, entry %s\n", *argv_iter ? faux_argv_current(*argv_iter) : "<empty>", kentry_name(nested));
-				nrc = ksession_parse_arg(nested, argv_iter, pargv);
+				nrc = ksession_parse_arg(nested, argv_iter,
+					pargv, BOOL_FALSE);
 //printf("%s\n", kpargv_status_decode(nrc));
 				if (nrc != KPARSE_INPROGRESS)
 					break;
@@ -255,7 +271,8 @@ kpargv_t *ksession_parse_line(ksession_t *session, const faux_argv_t *argv,
 		if (kentry_purpose(current_entry) != KENTRY_PURPOSE_COMMON)
 			continue;
 		// Parsing
-		pstatus = ksession_parse_arg(current_entry, &argv_iter, pargv);
+		pstatus = ksession_parse_arg(current_entry, &argv_iter, pargv,
+			BOOL_FALSE);
 		if (pstatus != KPARSE_NOTFOUND)
 			break;
 		// NOTFOUND but some args were parsed.
@@ -458,7 +475,6 @@ kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 		pargv = ksession_parse_line(session, argv, KPURPOSE_EXEC);
 		// All components must be ready for execution
 		if (!pargv) {
-			kpargv_free(pargv);
 			faux_list_free(split);
 			return NULL;
 		}
@@ -494,3 +510,50 @@ kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
 
 	return exec;
 }
+
+
+kexec_t *ksession_parse_for_local_exec(kentry_t *entry)
+{
+	faux_argv_node_t *argv_iter = NULL;
+	kpargv_t *pargv = NULL;
+	kexec_t *exec = NULL;
+	faux_argv_t *argv = faux_argv_new();
+	kcontext_t *context = NULL;
+	kpargv_status_e pstatus = KPARSE_NONE;
+	const char *line = NULL; // TODO: Must be 'line' field of ENTRY
+
+	assert(entry);
+	if (!entry)
+		return NULL;
+
+	exec = kexec_new();
+	assert(exec);
+
+	argv = faux_argv_new();
+	assert(argv);
+	faux_argv_parse(argv, line);
+	argv_iter = faux_argv_iter(argv);
+
+	pargv = kpargv_new();
+	assert(pargv);
+	kpargv_set_continuable(pargv, faux_argv_is_continuable(argv));
+	kpargv_set_purpose(pargv, KPURPOSE_EXEC);
+
+	pstatus = ksession_parse_arg(entry, &argv_iter, pargv, BOOL_TRUE);
+	// Parsing problems
+	if ((pstatus != KPARSE_INPROGRESS) || (argv_iter != NULL)) {
+		kexec_free(exec);
+		faux_argv_free(argv);
+		kpargv_free(pargv);
+		return NULL;
+	}
+
+	context = kcontext_new(KCONTEXT_PLUGIN_ACTION);
+	assert(context);
+	kcontext_set_pargv(context, pargv);
+	kexec_add_contexts(exec, context);
+
+	faux_argv_free(argv);
+
+	return exec;
+}