freetree234(macros);
}
+static void input_configure(input *in, paragraph *cfg) {
+ assert(cfg->type == para_Config);
+
+ if (!ustricmp(cfg->keyword, L"input-charset")) {
+ char *csname = utoa_dup(uadv(cfg->keyword));
+ in->charset = charset_from_localenc(csname);
+ sfree(csname);
+ }
+}
+
/*
* Can return EOF
*/
return c;
}
else if (in->currfp) {
- int c = getc(in->currfp);
- if (c == EOF) {
- fclose(in->currfp);
- in->currfp = NULL;
- }
- /* Track line numbers, for error reporting */
- if (pos)
- *pos = in->pos;
- if (in->reportcols) {
- switch (c) {
- case '\t':
- in->pos.col = 1 + (in->pos.col + TAB_STOP-1) % TAB_STOP;
- break;
- case '\n':
- in->pos.col = 1;
- in->pos.line++;
- break;
- default:
- in->pos.col++;
- break;
+ while (in->wcpos >= in->nwc) {
+
+ int c = getc(in->currfp);
+
+ if (c == EOF) {
+ fclose(in->currfp);
+ in->currfp = NULL;
+ return EOF;
+ }
+ /* Track line numbers, for error reporting */
+ if (pos)
+ *pos = in->pos;
+ if (in->reportcols) {
+ switch (c) {
+ case '\t':
+ in->pos.col = 1 + (in->pos.col + TAB_STOP-1) % TAB_STOP;
+ break;
+ case '\n':
+ in->pos.col = 1;
+ in->pos.line++;
+ break;
+ default:
+ in->pos.col++;
+ break;
+ }
+ } else {
+ in->pos.col = -1;
+ if (c == '\n')
+ in->pos.line++;
+ }
+
+ /*
+ * Do input character set translation, so that we return
+ * Unicode.
+ */
+ {
+ char buf[1];
+ char const *p;
+ int inlen;
+
+ buf[0] = (char)c;
+ p = buf;
+ inlen = 1;
+
+ in->nwc = charset_to_unicode(&p, &inlen,
+ in->wc, lenof(in->wc),
+ in->charset, &in->csstate,
+ NULL, 0);
+ assert(p == buf+1 && inlen == 0);
+
+ in->wcpos = 0;
}
- } else {
- in->pos.col = -1;
- if (c == '\n')
- in->pos.line++;
}
- /* FIXME: do input charmap translation. We should be returning
- * Unicode here. */
- return c;
+
+ return in->wc[in->wcpos++];
+
} else
return EOF;
}
c__invalid, /* invalid command */
c__comment, /* comment command (\#) */
c__escaped, /* escaped character */
+ c__nop, /* no-op */
c__nbsp, /* nonbreaking space */
c_A, /* appendix heading */
c_B, /* bibliography entry */
c_lcont, /* continuation para(s) for list item */
c_n, /* numbered list */
c_nocite, /* bibliography trickery */
- c_preamble, /* document preamble text */
+ c_preamble, /* (obsolete) preamble text */
c_q, /* quote marks */
+ c_quote, /* block-quoted paragraphs */
c_rule, /* horizontal rule */
c_title, /* document title */
c_u, /* aux field is char code */
static const struct { char const *name; int id; } keywords[] = {
{"#", c__comment}, /* comment command (\#) */
{"-", c__escaped}, /* nonbreaking hyphen */
+ {".", c__nop}, /* no-op */
{"A", c_A}, /* appendix heading */
{"B", c_B}, /* bibliography entry */
{"BR", c_BR}, /* bibliography rewrite */
{"lcont", c_lcont}, /* continuation para(s) for list item */
{"n", c_n}, /* numbered list */
{"nocite", c_nocite}, /* bibliography trickery */
- {"preamble", c_preamble}, /* document preamble text */
+ {"preamble", c_preamble}, /* (obsolete) preamble text */
{"q", c_q}, /* quote marks */
+ {"quote", c_quote}, /* block-quoted paragraphs */
{"rule", c_rule}, /* horizontal rule */
{"title", c_title}, /* document title */
{"versionid", c_versionid}, /* document RCS id */
} else if (c == '\\') { /* tok_cmd */
c = get(in, &cpos);
if (c == '-' || c == '\\' || c == '_' ||
- c == '#' || c == '{' || c == '}') {
+ c == '#' || c == '{' || c == '}' || c == '.') {
/* single-char command */
rdadd(&rs, c);
} else if (c == 'u') {
} type;
word **whptr; /* to restore from \u alternatives */
word **idximplicit; /* to restore from \u alternatives */
+ filepos fpos;
} *sitem;
stack parsestk;
struct crossparaitem {
- int type; /* currently c_lcont or -1 */
- int seen_lcont;
+ int type; /* currently c_lcont, c_quote or -1 */
+ int seen_lcont, seen_quote;
};
stack crossparastk;
word *indexword, *uword, *iword;
*/
dtor(t), t = get_token(in);
}
- if (t.type == tok_eop || t.type == tok_eof)
+ if (t.type == tok_eop || t.type == tok_eof ||
+ t.type == tok_rbrace) { /* might be } terminating \lcont */
+ if (t.type == tok_rbrace)
+ already = TRUE;
break;
- else if (t.type == tok_cmd && t.cmd == c_c)
+ } else if (t.type == tok_cmd && t.cmd == c_c) {
wtype = word_WeakCode;
- else if (t.type == tok_cmd && t.cmd == c_e &&
- wtype == word_WeakCode)
+ } else if (t.type == tok_cmd && t.cmd == c_e &&
+ wtype == word_WeakCode) {
wtype = word_Emph;
- else {
+ } else {
error(err_brokencodepara, &t.pos);
prev_para_type = par.type;
addpara(par, ret);
* finish them.
*/
if (t.type == tok_cmd &&
- t.cmd == c_lcont) {
+ (t.cmd == c_lcont || t.cmd == c_quote)) {
struct crossparaitem *sitem, *stop;
+ int cmd = t.cmd;
/*
* Expect, and swallow, an open brace.
}
/*
- * \lcont causes a continuation of a list item into
- * multiple paragraphs (which may in turn contain
- * nested lists, code paras etc). Hence, the previous
- * paragraph must be of a list type.
+ * Also expect, and swallow, any whitespace after that
+ * (a newline before a code paragraph wouldn't be
+ * surprising).
*/
- sitem = mknew(struct crossparaitem);
- stop = (struct crossparaitem *)stk_top(crossparastk);
- if (prev_para_type == para_Bullet ||
- prev_para_type == para_NumberedList ||
- prev_para_type == para_Description) {
- sitem->type = c_lcont;
- sitem->seen_lcont = 1;
- par.type = para_LcontPush;
- prev_para_type = par.type;
- addpara(par, ret);
+ do {
+ dtor(t), t = get_token(in);
+ } while (t.type == tok_white);
+ already = TRUE;
+
+ if (cmd == c_lcont) {
+ /*
+ * \lcont causes a continuation of a list item into
+ * multiple paragraphs (which may in turn contain
+ * nested lists, code paras etc). Hence, the previous
+ * paragraph must be of a list type.
+ */
+ sitem = mknew(struct crossparaitem);
+ stop = (struct crossparaitem *)stk_top(crossparastk);
+ if (stop)
+ *sitem = *stop;
+ else
+ sitem->seen_quote = sitem->seen_lcont = 0;
+
+ if (prev_para_type == para_Bullet ||
+ prev_para_type == para_NumberedList ||
+ prev_para_type == para_Description) {
+ sitem->type = c_lcont;
+ sitem->seen_lcont = 1;
+ par.type = para_LcontPush;
+ prev_para_type = par.type;
+ addpara(par, ret);
+ } else {
+ /*
+ * Push a null item on the cross-para stack so that
+ * when we see the corresponding closing brace we
+ * don't give a cascade error.
+ */
+ sitem->type = -1;
+ error(err_misplacedlcont, &t.pos);
+ }
} else {
/*
- * Push a null item on the cross-para stack so that
- * when we see the corresponding closing brace we
- * don't give a cascade error.
+ * \quote causes a group of paragraphs to be
+ * block-quoted (typically they will be indented a
+ * bit).
*/
- sitem->type = -1;
- sitem->seen_lcont = (stop ? stop->seen_lcont : 0);
- error(err_misplacedlcont, &t.pos);
+ sitem = mknew(struct crossparaitem);
+ stop = (struct crossparaitem *)stk_top(crossparastk);
+ if (stop)
+ *sitem = *stop;
+ else
+ sitem->seen_quote = sitem->seen_lcont = 0;
+ sitem->type = c_quote;
+ sitem->seen_quote = 1;
+ par.type = para_QuotePush;
+ prev_para_type = par.type;
+ addpara(par, ret);
}
stk_push(crossparastk, sitem);
continue;
prev_para_type = par.type;
addpara(par, ret);
break;
+ case c_quote:
+ par.type = para_QuotePop;
+ prev_para_type = par.type;
+ addpara(par, ret);
+ break;
}
sfree(sitem);
}
case c_define: is_macro = TRUE; needkw = 1; break;
/* For \nocite the keyword is _everything_ */
case c_nocite: needkw = 8; par.type = para_NoCite; break;
- case c_preamble: needkw = 32; par.type = para_Preamble; break;
+ case c_preamble: needkw = 32; par.type = para_Normal; break;
case c_rule: needkw = 16; par.type = para_Rule; break;
case c_title: needkw = 32; par.type = para_Title; break;
case c_versionid: needkw = 32; par.type = para_VersionID; break;
par.type == para_Appendix ||
par.type == para_UnnumberedChapter) {
struct crossparaitem *sitem = stk_top(crossparastk);
- if (sitem && sitem->seen_lcont) {
- error(err_sectmarkerinlcont, &t.pos);
+ if (sitem && (sitem->seen_lcont || sitem->seen_quote)) {
+ error(err_sectmarkerinblock,
+ &t.pos,
+ (sitem->seen_lcont ? "lcont" : "quote"));
}
}
already = TRUE;/* inhibit get_token at top of loop */
prev_para_type = par.type;
addpara(par, ret);
+
+ if (par.type == para_Config) {
+ input_configure(in, &par);
+ }
continue; /* next paragraph */
}
}
break;
}
+ if (t.type == tok_cmd && t.cmd == c__nop) {
+ dtor(t), t = get_token(in);
+ continue; /* do nothing! */
+ }
+
if (t.type == tok_cmd && t.cmd == c__escaped) {
t.type = tok_word; /* nice and simple */
t.aux = 0; /* even if `\-' - nonbreaking! */
/* Error recovery: push nop */
sitem = mknew(struct stack_item);
sitem->type = stack_nop;
+ sitem->fpos = t.pos;
stk_push(parsestk, sitem);
break;
case tok_rbrace:
}
if (sitem->type & stack_idx) {
indexword->text = ustrdup(indexstr.text);
- if (index_downcase)
+ if (index_downcase) {
+ word *w;
+
ustrlow(indexword->text);
+ ustrlow(indexstr.text);
+
+ for (w = idxwordlist; w; w = w->next)
+ if (w->text)
+ ustrlow(w->text);
+ }
indexing = FALSE;
rdadd(&indexstr, L'\0');
- index_merge(idx, FALSE, indexstr.text, idxwordlist);
+ index_merge(idx, FALSE, indexstr.text,
+ idxwordlist, &sitem->fpos);
sfree(indexstr.text);
}
if (sitem->type & stack_hyper) {
addword(wd, &idximplicit);
}
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_quote;
stk_push(parsestk, sitem);
}
* delimiting the text marked by the link.
*/
dtor(t), t = get_token(in);
+ sitem = mknew(struct stack_item);
+ sitem->fpos = wd.fpos;
+ sitem->type = stack_hyper;
+ /*
+ * Special cases: \W{}\i, \W{}\ii
+ */
+ if (t.type == tok_cmd &&
+ (t.cmd == c_i || t.cmd == c_ii)) {
+ if (indexing) {
+ error(err_nestedindex, &t.pos);
+ } else {
+ /* Add an index-reference word with no
+ * text as yet */
+ wd.type = word_IndexRef;
+ wd.text = NULL;
+ wd.alt = NULL;
+ wd.aux = 0;
+ wd.breaks = FALSE;
+ indexword = addword(wd, &whptr);
+ /* Set up a rdstring to read the
+ * index text */
+ indexstr = nullrs;
+ /* Flags so that we do the Right
+ * Things with text */
+ index_visible = (type != c_I);
+ index_downcase = (type == c_ii);
+ indexing = TRUE;
+ idxwordlist = NULL;
+ idximplicit = &idxwordlist;
+
+ sitem->type |= stack_idx;
+ }
+ dtor(t), t = get_token(in);
+ }
/*
* Special cases: \W{}\c, \W{}\e, \W{}\cw
*/
- sitem = mknew(struct stack_item);
- sitem->type = stack_hyper;
if (t.type == tok_cmd &&
(t.cmd == c_e || t.cmd == c_c || t.cmd == c_cw)) {
if (style != word_Normal)
/* Error recovery: eat lbrace, push nop. */
dtor(t), t = get_token(in);
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_nop;
stk_push(parsestk, sitem);
}
word_Emph);
spcstyle = tospacestyle(style);
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_style;
stk_push(parsestk, sitem);
}
/* Error recovery: eat lbrace, push nop. */
dtor(t), t = get_token(in);
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_nop;
stk_push(parsestk, sitem);
}
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_idx;
dtor(t), t = get_token(in);
/*
* paragraph.
*/
sitem = mknew(struct stack_item);
+ sitem->fpos = t.pos;
sitem->type = stack_ualt;
sitem->whptr = whptr;
sitem->idximplicit = idximplicit;
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;
read_file(&hptr, in, idx);
}
in->currindex++;