scdoc2mdoc

A fork of scdoc to output mdoc(7)
git clone git://git.sgregoratto.me/scdoc2mdoc
Log | Files | Refs | README | LICENSE

commit 35028f262a0a9fbf851d224a3e2719a8ecb1300e
parent 9f74b6a0bf9794081b755274bbddd15deb6a10aa
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat,  9 Dec 2017 23:55:34 -0500

Handle indent/deindent

Diffstat:
Minclude/util.h | 3+++
Msrc/main.c | 48+++++++++++++++++++++++++++++++++++++++++-------
Msrc/util.c | 9+++++++++
3 files changed, 53 insertions(+), 7 deletions(-)

diff --git 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 @@ -62,11 +62,19 @@ static void parse_preamble(struct parser *p) { 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 @@ static void parse_text(struct parser *p) { if (ch == '\n') { break; } + ++i; } } @@ -108,9 +117,35 @@ static void parse_heading(struct parser *p) { } } +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 @@ static void parse_document(struct parser *p) { 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 @@ -14,6 +14,9 @@ void parser_fatal(struct parser *parser, const char *err) { } 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; @@ -24,6 +27,12 @@ uint32_t parser_getch(struct parser *parser) { 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, ...) { FILE *f = p->output; int l = fprintf(f, ".%s", cmd);