From c382aaa0828072d208e8bb768c58ae5d0b9eb310 Mon Sep 17 00:00:00 2001 From: June McEnroe Date: Mon, 28 Dec 2020 23:48:24 -0500 Subject: Add hilex IRC formatter --- bin/hilex/Makefile | 1 + bin/hilex/ansi.c | 4 ++-- bin/hilex/hilex.c | 26 ++++++++++++++++++++---- bin/hilex/hilex.h | 11 ++++++++++ bin/hilex/irc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 bin/hilex/irc.c 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 4b8e1b69..fa88fd37 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 6e308249..b90efab1 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 442094c8..e997b881 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..c760fc26 --- /dev/null +++ b/bin/hilex/irc.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2020 June McEnroe + * + * 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 . + */ + +#include +#include +#include +#include + +#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, +}; -- cgit 1.4.1