diff cmd.c @ 27:722a45b4028b

Add define command for defining macros Macros are parsed when they are defined with the D command and can subsequently be used as arguments for other commands. Handle out of memory errors directly in tok.c.
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Mon, 25 Sep 2017 21:21:25 +0200
parents 1b89066d992c
children e3db02d7f1f4
line wrap: on
line diff
--- a/cmd.c	Thu Sep 21 09:45:59 2017 +0200
+++ b/cmd.c	Mon Sep 25 21:21:25 2017 +0200
@@ -37,10 +37,12 @@
 
 #include "cmd.h"
 #include "io.h"
+#include "macro.h"
 #include "pager.h"
 #include "proc.h"
 #include "pw.h"
 #include "pwfile.h"
+#include "tok.h"
 #include "util.h"
 
 #define	TIME_FORMAT	"%Y-%m-%dT%TZ"
@@ -82,6 +84,7 @@
 	CHARCLASS_GRAPH
 };
 
+static enum cmd_return	cmd_define(struct pwm_ctx *, int, char *[]);
 static enum cmd_return	cmd_status(struct pwm_ctx *, int, char *[]);
 static enum cmd_return	cmd_info(struct pwm_ctx *, int, char *[]);
 static enum cmd_return	cmd_list(struct pwm_ctx *, int, char *[]);
@@ -152,6 +155,7 @@
 };
 
 static struct cmd cmds[] = {
+    { "D", "define", "define name=value", "Define a macro", cmd_define },
     { "t", "status", "status", "Redisplay an error message of the previous "
     "command and unsaved changes", cmd_status },
     { "i", "info", "info", "Show metadata information about the current file",
@@ -217,6 +221,66 @@
 }
 
 static enum cmd_return
+cmd_define(struct pwm_ctx *ctx, int argc, char *argv[])
+{
+	int		retval = CMD_ERR;
+	const char	*value;
+	char		*name = NULL;
+	size_t		tokenc = 0;
+	union tok	**tokenv = NULL;
+	struct macro_entry *macro_entry;
+
+	if (argc != 2) {
+		return (CMD_USAGE);
+	}
+
+	/* split into name and value */
+	value = strchr(argv[1], '=');
+	if (value == NULL) {
+		pwm_err(ctx, "bad macro definition \"%s\"", argv[1]);
+		goto out;
+	}
+	xasprintf(&name, "%.*s", value - argv[1], argv[1]);
+	value++;
+
+	/* tokenize macro value */
+	switch (tok_tokenize(value, &tokenc, &tokenv)) {
+	case TOK_ERR_UNTERMINATED_QUOTE:
+		pwm_err(ctx, "unterminated quote in macro");
+		goto out;
+	case TOK_ERR_TRAILING_BACKSLASH:
+		pwm_err(ctx, "trailing backslash in macro");
+		goto out;
+	case TOK_ERR_INVALID_MACRO_NAME:
+		pwm_err(ctx, "invalid macro name referenced in macro");
+		goto out;
+	}
+
+	/* parse macro definition */
+	switch (macro_parse(name, tokenc, tokenv, ctx->macro_head,
+	    &macro_entry)) {
+	case MACRO_ERR_INVALID_NAME:
+		pwm_err(ctx, "invalid macro name \"%s\"", name);
+		goto out;
+	case MACRO_ERR_UNDEFINED_MACRO:
+		pwm_err(ctx, "macro definition references undefined macro");
+		goto out;
+	case MACRO_ERR_RECURSIVE:
+		pwm_err(ctx, "macro definition must not be recursive");
+		goto out;
+	}
+
+	macro_add(ctx->macro_head, macro_entry);
+	retval = CMD_OK;
+
+out:
+	tok_free(tokenv);
+	free(name);
+
+	return (retval);
+}
+
+static enum cmd_return
 cmd_status(struct pwm_ctx *ctx, int argc, char *argv[])
 {
 	if (argc != 1) {