summary refs log tree commit diff
path: root/bin/hilex
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-12-28 23:48:24 -0500
committerJune McEnroe <june@causal.agency>2020-12-28 23:48:24 -0500
commit91bb43a64f479c1fe2dbb54500912049505875c1 (patch)
tree9c9ba5720b3dd45f9430c0b83b761b911ca8898d /bin/hilex
parentGenerate Tag tokens for mdoc headings (diff)
downloadsrc-91bb43a64f479c1fe2dbb54500912049505875c1.tar.gz
src-91bb43a64f479c1fe2dbb54500912049505875c1.zip
Add hilex IRC formatter
Diffstat (limited to '')
-rw-r--r--bin/hilex/Makefile1
-rw-r--r--bin/hilex/ansi.c4
-rw-r--r--bin/hilex/hilex.c26
-rw-r--r--bin/hilex/hilex.h11
-rw-r--r--bin/hilex/irc.c59
5 files changed, 95 insertions, 6 deletions
diff --git a/bin/hilex/Makefile b/bin/hilex/Makefile
index 3fd11069..aeaa36d4 100644
--- a/bin/hilex/Makefile
+++ b/bin/hilex/Makefile
@@ -3,6 +3,7 @@ CFLAGS += -std=c11 -Wall -Wextra -Wpedantic
 OBJS += ansi.o
 OBJS += c.o
 OBJS += hilex.o
+OBJS += irc.o
 OBJS += mdoc.o
 OBJS += text.o
 
diff --git a/bin/hilex/ansi.c b/bin/hilex/ansi.c
index 6a5600d4..6ef41f22 100644
--- a/bin/hilex/ansi.c
+++ b/bin/hilex/ansi.c
@@ -29,7 +29,7 @@ static const char *SGR[ClassCap] = {
 	[StringFormat] = "36;1;96",
 };
 
-static void format(const char *opts[], enum Class class, const char *text) {
+static void ansiFormat(const char *opts[], enum Class class, const char *text) {
 	(void)opts;
 	if (!SGR[class]) {
 		printf("%s", text);
@@ -42,4 +42,4 @@ static void format(const char *opts[], enum Class class, const char *text) {
 	if (*text) printf("\33[%sm%s\33[m", SGR[class], text);
 }
 
-const struct Formatter FormatANSI = { .format = format };
+const struct Formatter FormatANSI = { .format = ansiFormat };
diff --git a/bin/hilex/hilex.c b/bin/hilex/hilex.c
index aa8d4e05..089f85ee 100644
--- a/bin/hilex/hilex.c
+++ b/bin/hilex/hilex.c
@@ -63,6 +63,7 @@ static const struct {
 } Formatters[] = {
 	{ &FormatANSI, "ansi" },
 	{ &FormatDebug, "debug" },
+	{ &FormatIRC, "irc" },
 };
 
 static const struct Formatter *parseFormatter(const char *name) {
@@ -87,18 +88,35 @@ debugFormat(const char *opts[], enum Class class, const char *text) {
 
 const struct Formatter FormatDebug = { .format = debugFormat };
 
+static char *const OptionKeys[OptionCap + 1] = {
+#define X(option, key) [option] = key,
+	ENUM_OPTION
+#undef X
+	NULL,
+};
+
 int main(int argc, char *argv[]) {
 	bool text = false;
 	const char *name = NULL;
 	const struct Lexer *lexer = NULL;
 	const struct Formatter *formatter = &FormatANSI;
+	const char *opts[OptionCap] = {0};
 
-	for (int opt; 0 < (opt = getopt(argc, argv, "f:l:n:t"));) {
+	for (int opt; 0 < (opt = getopt(argc, argv, "f:l:n:o:t"));) {
 		switch (opt) {
 			break; case 'f': formatter = parseFormatter(optarg);
 			break; case 'l': lexer = parseLexer(optarg);
 			break; case 'n': name = optarg;
+			break; case 'o': {
+				while (*optarg) {
+					char *val;
+					int key = getsubopt(&optarg, OptionKeys, &val);
+					if (key < 0) errx(EX_USAGE, "no such option %s", val);
+					opts[key] = (val ? val : "");
+				}
+			}
 			break; case 't': text = true;
+			break; default:  return EX_USAGE;
 		}
 	}
 
@@ -122,10 +140,10 @@ int main(int argc, char *argv[]) {
 	if (!lexer) errx(EX_USAGE, "cannot infer lexer for %s", name);
 
 	*lexer->in = file;
-	if (formatter->header) formatter->header(NULL);
+	if (formatter->header) formatter->header(opts);
 	for (enum Class class; None != (class = lexer->lex());) {
 		assert(class < ClassCap);
-		formatter->format(NULL, class, *lexer->text);
+		formatter->format(opts, class, *lexer->text);
 	}
-	if (formatter->footer) formatter->footer(NULL);
+	if (formatter->footer) formatter->footer(opts);
 }
diff --git a/bin/hilex/hilex.h b/bin/hilex/hilex.h
index 7f51d53e..f0e49a78 100644
--- a/bin/hilex/hilex.h
+++ b/bin/hilex/hilex.h
@@ -50,6 +50,16 @@ extern const struct Lexer LexC;
 extern const struct Lexer LexMdoc;
 extern const struct Lexer LexText;
 
+#define ENUM_OPTION \
+	X(Monospace, "monospace")
+
+enum Option {
+#define X(option, key) option,
+	ENUM_OPTION
+#undef X
+	OptionCap,
+};
+
 typedef void Header(const char *opts[]);
 typedef void Format(const char *opts[], enum Class class, const char *text);
 struct Formatter {
@@ -60,3 +70,4 @@ struct Formatter {
 
 extern const struct Formatter FormatANSI;
 extern const struct Formatter FormatDebug;
+extern const struct Formatter FormatIRC;
diff --git a/bin/hilex/irc.c b/bin/hilex/irc.c
new file mode 100644
index 00000000..acad66e0
--- /dev/null
+++ b/bin/hilex/irc.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2020  C. McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hilex.h"
+
+static const char *IRC[ClassCap] = {
+	[Keyword] = "\00315",
+	[Macro] = "\00303",
+	[Comment] = "\00302",
+	[String] = "\00310",
+	[StringFormat] = "\00311",
+};
+
+static void ircHeader(const char *opts[]) {
+	if (opts[Monospace]) printf("\21");
+}
+
+static const char *stop(const char *text) {
+	return (*text == ',' || isdigit(*text) ? "\2\2" : "");
+}
+
+static void ircFormat(const char *opts[], enum Class class, const char *text) {
+	for (const char *nl; (nl = strchr(text, '\n')); text = &nl[1]) {
+		if (IRC[class]) printf("%s%s", IRC[class], stop(text));
+		printf("%.*s\n", (int)(nl - text), text);
+		if (opts[Monospace]) printf("\21");
+	}
+	if (*text) {
+		if (IRC[class]) {
+			printf("%s%s%s\17", IRC[class], stop(text), text);
+			if (opts[Monospace]) printf("\21");
+		} else {
+			printf("%s", text);
+		}
+	}
+}
+
+const struct Formatter FormatIRC = {
+	.header = ircHeader,
+	.format = ircFormat,
+};