summary refs log tree commit diff
path: root/bin/hilex
diff options
context:
space:
mode:
Diffstat (limited to 'bin/hilex')
-rw-r--r--bin/hilex/Makefile3
-rw-r--r--bin/hilex/ansi.c45
-rw-r--r--bin/hilex/hilex.c204
-rw-r--r--bin/hilex/hilex.h30
-rw-r--r--bin/hilex/html.c113
-rw-r--r--bin/hilex/irc.c60
6 files changed, 182 insertions, 273 deletions
diff --git a/bin/hilex/Makefile b/bin/hilex/Makefile
index c71738d6..e7972425 100644
--- a/bin/hilex/Makefile
+++ b/bin/hilex/Makefile
@@ -1,10 +1,7 @@
 CFLAGS += -std=c11 -Wall -Wextra -Wpedantic
 
-OBJS += ansi.o
 OBJS += c.o
 OBJS += hilex.o
-OBJS += html.o
-OBJS += irc.o
 OBJS += make.o
 OBJS += mdoc.o
 OBJS += text.o
diff --git a/bin/hilex/ansi.c b/bin/hilex/ansi.c
deleted file mode 100644
index 114d03a6..00000000
--- a/bin/hilex/ansi.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "hilex.h"
-
-static const char *SGR[ClassCap] = {
-	[Keyword]       = "37",
-	[Macro]         = "32",
-	[Comment]       = "34",
-	[String]        = "36",
-	[StringFormat]  = "36;1;96",
-	[Interpolation] = "33",
-};
-
-static void ansiFormat(const char *opts[], enum Class class, const char *text) {
-	(void)opts;
-	if (!SGR[class]) {
-		printf("%s", text);
-		return;
-	}
-	// Set color on each line for piping to less -R:
-	for (const char *nl; (nl = strchr(text, '\n')); text = &nl[1]) {
-		printf("\33[%sm%.*s\33[m\n", SGR[class], (int)(nl - text), text);
-	}
-	if (*text) printf("\33[%sm%s\33[m", SGR[class], text);
-}
-
-const struct Formatter FormatANSI = { .format = ansiFormat };
diff --git a/bin/hilex/hilex.c b/bin/hilex/hilex.c
index 1fa620e3..ccbfa8ad 100644
--- a/bin/hilex/hilex.c
+++ b/bin/hilex/hilex.c
@@ -15,6 +15,7 @@
  */
 
 #include <assert.h>
+#include <ctype.h>
 #include <err.h>
 #include <regex.h>
 #include <stdbool.h>
@@ -26,6 +27,14 @@
 
 #include "hilex.h"
 
+#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
+
+static const char *Class[] = {
+#define X(class) [class] = #class,
+	ENUM_CLASS
+#undef X
+};
+
 static const struct {
 	const struct Lexer *lexer;
 	const char *name;
@@ -58,41 +67,192 @@ static const struct Lexer *matchLexer(const char *name) {
 	return NULL;
 }
 
-static const struct {
-	const struct Formatter *formatter;
-	const char *name;
-} Formatters[] = {
-	{ &FormatANSI, "ansi" },
-	{ &FormatDebug, "debug" },
-	{ &FormatHTML, "html" },
-	{ &FormatIRC, "irc" },
+#define ENUM_OPTION \
+	X(Document, "document") \
+	X(Inline, "inline") \
+	X(Monospace, "monospace") \
+	X(Style, "style") \
+	X(Tab, "tab") \
+	X(Title, "title")
+
+enum Option {
+#define X(option, key) option,
+	ENUM_OPTION
+#undef X
+	OptionCap,
 };
 
-static const struct Formatter *parseFormatter(const char *name) {
-	for (size_t i = 0; i < ARRAY_LEN(Formatters); ++i) {
-		if (!strcmp(name, Formatters[i].name)) return Formatters[i].formatter;
-	}
-	errx(EX_USAGE, "unknown formatter %s", name);
-}
+typedef void Header(const char *opts[]);
+typedef void Format(const char *opts[], enum Class class, const char *text);
 
-static const char *ClassName[] = {
-#define X(class) [class] = #class,
-	ENUM_CLASS
-#undef X
+static const char *SGR[ClassCap] = {
+	[Keyword]       = "37",
+	[Macro]         = "32",
+	[Comment]       = "34",
+	[String]        = "36",
+	[StringFormat]  = "36;1;96",
+	[Interpolation] = "33",
 };
 
+static void ansiFormat(const char *opts[], enum Class class, const char *text) {
+	(void)opts;
+	if (!SGR[class]) {
+		printf("%s", text);
+		return;
+	}
+	// Set color on each line for piping to less -R:
+	for (const char *nl; (nl = strchr(text, '\n')); text = &nl[1]) {
+		printf("\33[%sm%.*s\33[m\n", SGR[class], (int)(nl - text), text);
+	}
+	if (*text) printf("\33[%sm%s\33[m", SGR[class], text);
+}
+
 static void
 debugFormat(const char *opts[], enum Class class, const char *text) {
 	if (class != Normal) {
-		printf("%s(", ClassName[class]);
-		FormatANSI.format(opts, class, text);
+		printf("%s(", Class[class]);
+		ansiFormat(opts, class, text);
 		printf(")");
 	} else {
 		printf("%s", text);
 	}
 }
 
-const struct Formatter FormatDebug = { .format = debugFormat };
+static const char *IRC[ClassCap] = {
+	[Keyword]       = "\00315",
+	[Macro]         = "\0033",
+	[Comment]       = "\0032",
+	[String]        = "\00310",
+	[StringFormat]  = "\00311",
+	[Interpolation] = "\0037",
+};
+
+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);
+		}
+	}
+}
+
+static void htmlEscape(const char *text) {
+	while (*text) {
+		switch (*text) {
+			break; case '"': text++; printf("&quot;");
+			break; case '&': text++; printf("&amp;");
+			break; case '<': text++; printf("&lt;");
+		}
+		size_t len = strcspn(text, "\"&<");
+		if (len) fwrite(text, len, 1, stdout);
+		text += len;
+	}
+}
+
+static const char *Styles[ClassCap] = {
+	[Keyword]       = "color: dimgray;",
+	[Macro]         = "color: green;",
+	[Comment]       = "color: navy;",
+	[String]        = "color: teal;",
+	[StringFormat]  = "color: teal; font-weight: bold;",
+	[Interpolation] = "color: olive;",
+};
+
+static void styleTabSize(const char *tab) {
+	printf("-moz-tab-size: ");
+	htmlEscape(tab);
+	printf("; tab-size: ");
+	htmlEscape(tab);
+	printf(";");
+}
+
+static void htmlHeader(const char *opts[]) {
+	if (!opts[Document]) goto body;
+
+	printf("<!DOCTYPE html>\n<title>");
+	if (opts[Title]) htmlEscape(opts[Title]);
+	printf("</title>\n");
+
+	if (opts[Style]) {
+		printf("<link rel=\"stylesheet\" href=\"");
+		htmlEscape(opts[Style]);
+		printf("\">\n");
+	} else if (!opts[Inline]) {
+		printf("<style>\n");
+		if (opts[Tab]) {
+			printf("pre.hilex { ");
+			styleTabSize(opts[Tab]);
+			printf(" }\n");
+		}
+		for (enum Class class = 0; class < ClassCap; ++class) {
+			if (!Styles[class]) continue;
+			printf(".hilex.%s { %s }\n", Class[class], Styles[class]);
+		}
+		printf("</style>\n");
+	}
+
+body:
+	if (opts[Inline] && opts[Tab]) {
+		printf("<pre class=\"hilex\" style=\"");
+		styleTabSize(opts[Tab]);
+		printf("\">");
+	} else {
+		printf("<pre class=\"hilex\">");
+	}
+}
+
+static void htmlFooter(const char *opts[]) {
+	printf("</pre>");
+	if (opts[Document]) printf("\n");
+}
+
+static void htmlFormat(const char *opts[], enum Class class, const char *text) {
+	if (class != Normal) {
+		if (opts[Inline]) {
+			printf("<span style=\"%s\">", Styles[class] ? Styles[class] : "");
+		} else {
+			printf("<span class=\"hilex %s\">", Class[class]);
+		}
+		htmlEscape(text);
+		printf("</span>");
+	} else {
+		htmlEscape(text);
+	}
+}
+
+static const struct Formatter {
+	const char *name;
+	Header *header;
+	Format *format;
+	Header *footer;
+} Formatters[] = {
+	{ "ansi", NULL, ansiFormat, NULL },
+	{ "debug", NULL, debugFormat, NULL },
+	{ "html", htmlHeader, htmlFormat, htmlFooter },
+	{ "irc", ircHeader, ircFormat, NULL },
+};
+
+static const struct Formatter *parseFormatter(const char *name) {
+	for (size_t i = 0; i < ARRAY_LEN(Formatters); ++i) {
+		if (!strcmp(name, Formatters[i].name)) return &Formatters[i];
+	}
+	errx(EX_USAGE, "unknown formatter %s", name);
+}
 
 static char *const OptionKeys[OptionCap + 1] = {
 #define X(option, key) [option] = key,
@@ -105,7 +265,7 @@ int main(int argc, char *argv[]) {
 	bool text = false;
 	const char *name = NULL;
 	const struct Lexer *lexer = NULL;
-	const struct Formatter *formatter = &FormatANSI;
+	const struct Formatter *formatter = &Formatters[0];
 	const char *opts[OptionCap] = {0};
 
 	for (int opt; 0 < (opt = getopt(argc, argv, "f:l:n:o:t"));) {
diff --git a/bin/hilex/hilex.h b/bin/hilex/hilex.h
index 88a71a51..5998e6a4 100644
--- a/bin/hilex/hilex.h
+++ b/bin/hilex/hilex.h
@@ -16,8 +16,6 @@
 
 #include <stdio.h>
 
-#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
-
 #define ENUM_CLASS \
 	X(None) \
 	X(Normal) \
@@ -50,31 +48,3 @@ extern const struct Lexer LexC;
 extern const struct Lexer LexMake;
 extern const struct Lexer LexMdoc;
 extern const struct Lexer LexText;
-
-#define ENUM_OPTION \
-	X(Document, "document") \
-	X(Inline, "inline") \
-	X(Monospace, "monospace") \
-	X(Style, "style") \
-	X(Tab, "tab") \
-	X(Title, "title")
-
-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 {
-	Header *header;
-	Format *format;
-	Header *footer;
-};
-
-extern const struct Formatter FormatANSI;
-extern const struct Formatter FormatDebug;
-extern const struct Formatter FormatHTML;
-extern const struct Formatter FormatIRC;
diff --git a/bin/hilex/html.c b/bin/hilex/html.c
deleted file mode 100644
index 59914d06..00000000
--- a/bin/hilex/html.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "hilex.h"
-
-static void htmlEscape(const char *text) {
-	while (*text) {
-		switch (*text) {
-			break; case '"': text++; printf("&quot;");
-			break; case '&': text++; printf("&amp;");
-			break; case '<': text++; printf("&lt;");
-		}
-		size_t len = strcspn(text, "\"&<");
-		if (len) fwrite(text, len, 1, stdout);
-		text += len;
-	}
-}
-
-static const char *Class[ClassCap] = {
-#define X(class) [class] = #class,
-	ENUM_CLASS
-#undef X
-};
-
-static const char *Styles[ClassCap] = {
-	[Keyword]       = "color: dimgray;",
-	[Macro]         = "color: green;",
-	[Comment]       = "color: navy;",
-	[String]        = "color: teal;",
-	[StringFormat]  = "color: teal; font-weight: bold;",
-	[Interpolation] = "color: olive;",
-};
-
-static void styleTabSize(const char *tab) {
-	printf("-moz-tab-size: ");
-	htmlEscape(tab);
-	printf("; tab-size: ");
-	htmlEscape(tab);
-	printf(";");
-}
-
-static void htmlHeader(const char *opts[]) {
-	if (!opts[Document]) goto body;
-
-	printf("<!DOCTYPE html>\n<title>");
-	if (opts[Title]) htmlEscape(opts[Title]);
-	printf("</title>\n");
-
-	if (opts[Style]) {
-		printf("<link rel=\"stylesheet\" href=\"");
-		htmlEscape(opts[Style]);
-		printf("\">\n");
-	} else if (!opts[Inline]) {
-		printf("<style>\n");
-		if (opts[Tab]) {
-			printf("pre.hilex { ");
-			styleTabSize(opts[Tab]);
-			printf(" }\n");
-		}
-		for (enum Class class = 0; class < ClassCap; ++class) {
-			if (!Styles[class]) continue;
-			printf(".hilex.%s { %s }\n", Class[class], Styles[class]);
-		}
-		printf("</style>\n");
-	}
-
-body:
-	if (opts[Inline] && opts[Tab]) {
-		printf("<pre class=\"hilex\" style=\"");
-		styleTabSize(opts[Tab]);
-		printf("\">");
-	} else {
-		printf("<pre class=\"hilex\">");
-	}
-}
-
-static void htmlFooter(const char *opts[]) {
-	printf("</pre>");
-	if (opts[Document]) printf("\n");
-}
-
-static void htmlFormat(const char *opts[], enum Class class, const char *text) {
-	if (class != Normal) {
-		if (opts[Inline]) {
-			printf("<span style=\"%s\">", Styles[class] ? Styles[class] : "");
-		} else {
-			printf("<span class=\"hilex %s\">", Class[class]);
-		}
-		htmlEscape(text);
-		printf("</span>");
-	} else {
-		htmlEscape(text);
-	}
-}
-
-const struct Formatter FormatHTML = { htmlHeader, htmlFormat, htmlFooter };
diff --git a/bin/hilex/irc.c b/bin/hilex/irc.c
deleted file mode 100644
index acc06fdf..00000000
--- a/bin/hilex/irc.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* 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]         = "\0033",
-	[Comment]       = "\0032",
-	[String]        = "\00310",
-	[StringFormat]  = "\00311",
-	[Interpolation] = "\0037",
-};
-
-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,
-};