diff libcommon/dispatch.c @ 14:b7ee2e85686b

command dispatch and scripting factored out into libcommon
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Mar 2021 07:34:35 +0000
parents simtool/dispatch.c@ddd767f6e15b
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcommon/dispatch.c	Sun Mar 14 07:34:35 2021 +0000
@@ -0,0 +1,149 @@
+/*
+ * This module implements common command dispatch for our SIM tools.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "cmdtab.h"
+
+extern struct cmdtab cmdtab[];
+
+static FILE *
+handle_output_redir(str)
+	char *str;
+{
+	char *cp, *fn;
+	FILE *outf;
+
+	for (cp = str; isspace(*cp); cp++)
+		;
+	if (!*cp || *cp == '#') {
+		fprintf(stderr, "error: no filename after '>'\n");
+		return(0);
+	}
+	for (fn = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#') {
+		fprintf(stderr, "error: invalid syntax after '>'\n");
+		return(0);
+	}
+	outf = fopen(fn, "w");
+	if (!outf)
+		perror(fn);
+	return outf;
+}
+
+simtool_dispatch_cmd(cmd, is_script)
+	char *cmd;
+{
+	char *argv[20];
+	char *cp, **ap;
+	struct cmdtab *tp;
+	FILE *outf;
+	int rc;
+
+	for (cp = cmd; isspace(*cp); cp++)
+		;
+	if (!*cp || *cp == '#')
+		return(0);
+	if (is_script)
+		printf("Script command: %s\n", cp);
+	if (*cp == '!')
+		return system(cp + 1);
+	argv[0] = cp;
+	while (*cp && !isspace(*cp))
+		cp++;
+	if (*cp)
+		*cp++ = '\0';
+	for (tp = cmdtab; tp->cmd; tp++)
+		if (!strcmp(tp->cmd, argv[0]))
+			break;
+	if (!tp->func) {
+		fprintf(stderr, "error: no such command\n");
+		return(-1);
+	}
+	for (ap = argv + 1; ; ) {
+		while (isspace(*cp))
+			cp++;
+		if (!*cp || *cp == '#' || *cp == '>')
+			break;
+		if (ap - argv - 1 >= tp->maxargs) {
+			fprintf(stderr, "error: too many arguments\n");
+			return(-1);
+		}
+		if (*cp == '"') {
+			*ap++ = ++cp;
+			for (;;) {
+				if (!*cp) {
+unterm_qstring:				fprintf(stderr,
+					"error: unterminated quoted string\n");
+					return(-1);
+				}
+				if (*cp == '"')
+					break;
+				if (*cp++ == '\\') {
+					if (!*cp)
+						goto unterm_qstring;
+					cp++;
+				}
+			}
+			*cp++ = '\0';
+		} else {
+			*ap++ = cp;
+			while (*cp && !isspace(*cp))
+				cp++;
+			if (*cp)
+				*cp++ = '\0';
+		}
+	}
+	if (ap - argv - 1 < tp->minargs) {
+		fprintf(stderr, "error: too few arguments\n");
+		return(-1);
+	}
+	*ap = 0;
+	if (*cp == '>') {
+		if (!tp->allow_redir) {
+			fprintf(stderr,
+			"error: command does not support output redirection\n");
+			return(-1);
+		}
+		outf = handle_output_redir(cp + 1);
+		if (!outf)
+			return(-1);
+	} else
+		outf = stdout;
+	rc = tp->func(ap - argv, argv, outf);
+	if (outf != stdout)
+		fclose(outf);
+	return rc;
+}
+
+dispatch_ready_argv(argc, argv)
+	char **argv;
+{
+	struct cmdtab *tp;
+
+	for (tp = cmdtab; tp->cmd; tp++)
+		if (!strcmp(tp->cmd, argv[0]))
+			break;
+	if (!tp->func) {
+		fprintf(stderr, "error: no such command\n");
+		return(-1);
+	}
+	if (argc - 1 > tp->maxargs) {
+		fprintf(stderr, "error: too many arguments\n");
+		return(-1);
+	}
+	if (argc - 1 < tp->minargs) {
+		fprintf(stderr, "error: too few arguments\n");
+		return(-1);
+	}
+	return tp->func(argc, argv, stdout);
+}