From 35028f262a0a9fbf851d224a3e2719a8ecb1300e Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 09 Dec 2017 23:55:34 -0500 Subject: [PATCH] Handle indent/deindent --- include/util.h | 3 +++ src/main.c | 48 +++++++++++++++++++++++++++++++++++++++++------- src/util.c | 9 +++++++++ diff --git a/include/util.h b/include/util.h index c68405c4e0e44770f5e0f87a284a9c5f571a3266..8c8ad42accda29eea195729af3a7722bbd6ee174 100644 --- a/include/util.h +++ b/include/util.h @@ -7,10 +7,13 @@ struct parser { FILE *input, *output; int line, col; + int qhead; + uint32_t queue[32]; }; void parser_fatal(struct parser *parser, const char *err); uint32_t parser_getch(struct parser *parser); +void parser_pushch(struct parser *parser, uint32_t ch); int roff_macro(struct parser *p, char *cmd, ...); #endif diff --git a/src/main.c b/src/main.c index 504ff4ba1947daabd98b5adbd4bbf8cdf8521153..30433a5ea7482f17f88037db4d24d5c8c256e297 100644 --- a/src/main.c +++ b/src/main.c @@ -62,11 +62,19 @@ } static void parse_text(struct parser *p) { uint32_t ch; + int i = 0; while ((ch = parser_getch(p)) != UTF8_INVALID) { switch (ch) { case '\\': fprintf(p->output, "\\\\"); break; + case '.': + if (!i) { + // Escape . if it's the first character + fprintf(p->output, "\\&."); + break; + } + /* fallthrough */ default: utf8_fputch(p->output, ch); break; @@ -74,6 +82,7 @@ } if (ch == '\n') { break; } + ++i; } } @@ -108,9 +117,35 @@ } } } +static int parse_indent(struct parser *p) { + int i = 0; + uint32_t ch; + while ((ch = parser_getch(p)) == '\t') { + ++i; + } + parser_pushch(p, ch); + return i; +} + static void parse_document(struct parser *p) { uint32_t ch; - while ((ch = parser_getch(p)) != UTF8_INVALID) { + int indent = 0; + do { + int i = parse_indent(p); + if (i == indent - 1) { + roff_macro(p, "RE", NULL); + } else if (i == indent + 1) { + roff_macro(p, "RS", "4", NULL); + } else if (i != indent && ch == '\t') { + parser_fatal(p, "(De)indented by an amount greater than 1"); + } + indent = i; + + ch = parser_getch(p); + if (ch == UTF8_INVALID) { + break; + } + switch (ch) { case '#': parse_heading(p); @@ -118,16 +153,15 @@ break; case '\n': roff_macro(p, "P", NULL); break; + case ' ': + parser_fatal(p, "Tabs are required for indentation"); + break; default: - if (ch == '.') { - fprintf(p->output, "\\&."); - } else { - utf8_fputch(p->output, ch); - } + parser_pushch(p, ch); parse_text(p); break; } - } + } while (ch != UTF8_INVALID); } static void output_scdoc_preamble(struct parser *p) { diff --git a/src/util.c b/src/util.c index bb9df685fb4baf7e28ccc6e3c0a134abee0f7763..ff9bbcd2b34b9696e135b281de9a0aab0ee74be1 100644 --- a/src/util.c +++ b/src/util.c @@ -14,6 +14,9 @@ exit(1); } uint32_t parser_getch(struct parser *parser) { + if (parser->qhead) { + return parser->queue[--parser->qhead]; + } uint32_t ch = utf8_fgetch(parser->input); if (ch == '\n') { parser->col = 0; @@ -22,6 +25,12 @@ } else { ++parser->col; } return ch; +} + +void parser_pushch(struct parser *parser, uint32_t ch) { + if (ch != UTF8_INVALID) { + parser->queue[parser->qhead++] = ch; + } } int roff_macro(struct parser *p, char *cmd, ...) { -- 2.48.1