~sircmpwn/scdoc

35028f262a0a9fbf851d224a3e2719a8ecb1300e — Drew DeVault 3 years ago 9f74b6a
Handle indent/deindent
3 files changed, 53 insertions(+), 7 deletions(-)

M include/util.h
M src/main.c
M src/util.c
M include/util.h => include/util.h +3 -0
@@ 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

M src/main.c => src/main.c +41 -7
@@ 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) {

M src/util.c => src/util.c +9 -0
@@ 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);