X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/halibut/blobdiff_plain/41848b3e209f21729cbfe29aaa47d4c061aed94e..26c8c119efd44804c7b27f8637c69eda63f0c189:/input.c diff --git a/input.c b/input.c index a616ac9..1410022 100644 --- a/input.c +++ b/input.c @@ -119,7 +119,8 @@ static int get(input *in, filepos *pos, rdstringc *rsc) { int c = getc(in->currfp); if (c == EOF) { - fclose(in->currfp); + if (in->wantclose) + fclose(in->currfp); in->currfp = NULL; return EOF; } @@ -426,6 +427,7 @@ token get_token(input *in) { c == '#' || c == '{' || c == '}' || c == '.') { /* single-char command */ rdadd(&rs, c); + prevpos = rsc.pos; } else if (c == 'u') { int len = 0; do { @@ -609,7 +611,7 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, stack_style = 2, /* \e, \c, \cw */ stack_idx = 4, /* \I, \i, \ii */ stack_hyper = 8, /* \W */ - stack_quote = 16, /* \q */ + stack_quote = 16 /* \q */ } type; word **whptr; /* to restore from \u alternatives */ word **idximplicit; /* to restore from \u alternatives */ @@ -834,8 +836,10 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, needkw = 4; break; case c__comment: - if (isbrace(in)) + if (isbrace(in)) { + needkw = -1; break; /* `\#{': isn't a comment para */ + } do { dtor(t), t = get_token(in); } while (t.type != tok_eop && t.type != tok_eof); @@ -902,7 +906,21 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, /* Get keywords. */ dtor(t), t = get_token(in); fp = t.pos; - while (t.type == tok_lbrace) { + while (t.type == tok_lbrace || + (t.type == tok_white && (needkw & 24))) { + /* + * In paragraph types which can't accept any + * body text (such as \cfg), we are lenient + * about whitespace between keywords. This is + * important for \cfg in particular since it + * can often have many keywords which are long + * pieces of text, so it's useful to permit the + * user to wrap the line between them. + */ + if (t.type == tok_white) { + dtor(t), t = get_token(in); /* eat the space */ + continue; + } /* This is a keyword. */ nkeys++; /* FIXME: there will be bugs if anyone specifies an @@ -960,7 +978,8 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, rdadd(¯otext, L'\n'); rdadds(¯otext, t.text); dtor(t), t = get_token(in); - if (t.type == tok_eop) break; + if (t.type == tok_eop || t.type == tok_eof) + break; } macrodef(macros, rs.text, macrotext.text, fp); continue; /* next paragraph */ @@ -1528,7 +1547,17 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, } stk_free(parsestk); prev_para_type = par.type; - addpara(par, ret); + /* + * Before we add the paragraph to the output list, we + * should check that there was any text in it at all; there + * might not be if (for example) the paragraph contained + * nothing but an unrecognised command sequence, and if we + * put an empty paragraph on the list it may confuse the + * back ends later on. + */ + if (par.words) { + addpara(par, ret); + } if (t.type == tok_eof) already = TRUE; } @@ -1550,22 +1579,80 @@ static void read_file(paragraph ***ret, input *in, indexdata *idx, stk_free(crossparastk); } +struct { + char const *magic; + size_t nmagic; + int binary; + void (*reader)(input *); +} magics[] = { + { "%!FontType1-", 12, FALSE, &read_pfa_file }, + { "%!PS-AdobeFont-", 15, FALSE, &read_pfa_file }, + { "\x80\x01", 2, TRUE, &read_pfb_file }, + { "StartFontMetrics", 16, FALSE, &read_afm_file }, + { "\x00\x01\x00\x00", 4, TRUE, &read_sfnt_file }, + { "true", 4, TRUE, &read_sfnt_file }, +}; + paragraph *read_input(input *in, indexdata *idx) { paragraph *head = NULL; paragraph **hptr = &head; tree234 *macros; + char mag[16]; + size_t len, i; + int binary; + void (*reader)(input *); macros = newtree234(macrocmp); while (in->currindex < in->nfiles) { - in->currfp = fopen(in->filenames[in->currindex], "r"); + setpos(in, in->filenames[in->currindex]); + in->charset = in->defcharset; + in->csstate = charset_init_state; + in->wcpos = in->nwc = 0; + in->pushback_chars = NULL; + + if (!in->filenames[in->currindex]) { + in->currfp = stdin; + in->wantclose = FALSE; /* don't fclose stdin */ + /* + * When reading standard input, we always expect to see + * an actual Halibut file and not any of the unusual + * input types like fonts. + */ + reader = NULL; + } else { + /* + * Open the file in binary mode to look for magic + * numbers. We'll switch to text mode if we find we're + * looking at a text file type. + */ + in->currfp = fopen(in->filenames[in->currindex], "rb"); + binary = FALSE; /* default to Halibut source, which is text */ + if (in->currfp) { + in->wantclose = TRUE; + reader = NULL; + len = fread(mag, 1, sizeof(mag), in->currfp); + for (i = 0; i < lenof(magics); i++) { + if (len >= magics[i].nmagic && + memcmp(mag, magics[i].magic, magics[i].nmagic) == 0) { + reader = magics[i].reader; + binary = magics[i].binary; + break; + } + } + rewind(in->currfp); + } + if (!binary) { + fclose(in->currfp); + in->currfp = fopen(in->filenames[in->currindex], "r"); + } + } if (in->currfp) { - setpos(in, in->filenames[in->currindex]); - in->charset = in->defcharset; - in->csstate = charset_init_state; - in->wcpos = in->nwc = 0; - in->pushback_chars = NULL; - read_file(&hptr, in, idx, macros); + if (reader == NULL) { + read_file(&hptr, in, idx, macros); + } else { + (*reader)(in); + } } in->currindex++; }