commit 35028f262a0a9fbf851d224a3e2719a8ecb1300e
parent 9f74b6a0bf9794081b755274bbddd15deb6a10aa
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 9 Dec 2017 23:55:34 -0500
Handle indent/deindent
Diffstat:
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);