Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
Parse section headings
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "string.h"
#include "unicode.h"
#include "util.h"
char date[256];
static int parse_section(struct parser *p) {
str_t *section = str_create();
uint32_t ch;
while ((ch = parser_getch(p)) != UTF8_INVALID) {
if (isdigit(ch)) {
assert(str_append_ch(section, ch) != -1);
} else if (ch == ')') {
if (!section->str) {
break;
}
int sec = strtol(section->str, NULL, 10);
if (sec < 1 || sec > 9) {
parser_fatal(p, "Expected section between 1 and 9");
break;
}
str_free(section);
return sec;
} else {
parser_fatal(p, "Expected digit or )");
break;
}
};
parser_fatal(p, "Expected manual section");
return -1;
}
static void parse_preamble(struct parser *p) {
str_t *name = str_create();
int section = -1;
uint32_t ch;
do {
ch = parser_getch(p);
while ((ch = parser_getch(p)) != UTF8_INVALID) {
if (isalnum(ch)) {
assert(str_append_ch(name, ch) != -1);
} else if (ch == '(') {
section = parse_section(p);
} else if (ch == '\n') {
if (name->len == 0) {
parser_fatal(p, "Expected preamble");
}
if (section == -1) {
parser_fatal(p, "Expected manual section");
}
char sec[2] = { '0' + section, 0 };
roff_macro(p, "TH", name->str, sec, date, NULL);
break;
}
} while (ch != UTF8_INVALID);
}
str_free(name); }
static void output_preamble(struct parser *p) {
static void parse_text(struct parser *p) {
uint32_t ch;
while ((ch = parser_getch(p)) != UTF8_INVALID) {
switch (ch) {
case '\\':
fprintf(p->output, "\\\\");
break;
default:
utf8_fputch(p->output, ch);
break;
}
if (ch == '\n') {
break;
}
}
}
static void parse_heading(struct parser *p) {
uint32_t ch;
int level = 1;
while ((ch = parser_getch(p)) != UTF8_INVALID) {
if (ch == '#') {
++level;
} else if (ch == ' ') {
break;
} else {
parser_fatal(p, "Invalid start of heading (probably needs a space)");
}
}
switch (level) {
case 1:
fprintf(p->output, ".SH ");
break;
case 2:
fprintf(p->output, ".SS ");
break;
default:
parser_fatal(p, "Only headings up to two levels deep are permitted");
break;
}
while ((ch = parser_getch(p)) != UTF8_INVALID) {
utf8_fputch(p->output, ch);
if (ch == '\n') {
break;
}
}
}
static void parse_document(struct parser *p) {
uint32_t ch;
while ((ch = parser_getch(p)) != UTF8_INVALID) {
switch (ch) {
case '#':
parse_heading(p);
break;
case '\n':
roff_macro(p, "P", NULL);
break;
default:
if (ch == '.') {
fprintf(p->output, "\\&.");
} else {
utf8_fputch(p->output, ch);
}
parse_text(p);
break;
}
}
}
static void output_scdoc_preamble(struct parser *p) {
// TODO: Add version here
fprintf(p->output, ".\\\" Generated by scdoc\n");
fprintf(p->output, ".\\\" Fix weird qutation marks:\n");
fprintf(p->output, ".\\\" http://bugs.debian.org/507673\n");
fprintf(p->output, ".\\\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html\n");
fprintf(p->output, ".ie \\n(.g .ds Aq \\(aq\n");
fprintf(p->output, ".el .ds Aq '\n");
fprintf(p->output, ".\\\" Disable hyphenation:\n");
roff_macro(p, "nh", NULL);
fprintf(p->output, ".\\\" Generated content:\n");
}
int main(int argc, char **argv) {
if (argc > 1) {
fprintf(stderr, "Usage: scdoc < input.scd > output.roff");
return 1;
}
time_t now;
time(&now);
struct tm *now_tm = localtime(&now);
strftime(date, sizeof(date), "%F", now_tm);
struct parser p = {
.input = stdin,
.output = stdout,
.line = 1,
.col = 1
};
output_preamble(&p);
output_scdoc_preamble(&p);
parse_preamble(&p);
parse_document(&p);
return 0; }