* TODO:
*
* - configurable choice of how to allocate node names
- * - escape, warn or simply remove commas and colons in node
- * names; also test colons in index terms.
- * - might be helpful to diagnose duplicate node names too!
+ * - might be helpful to diagnose duplicate node names!
* - test everything in info(1), and probably jed too
*
* Later:
for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) {
info_idx *ii = mknew(info_idx);
rdstringc rs = { 0, 0, NULL };
+ char *p, *q;
ii->nnodes = ii->nodesize = 0;
ii->nodes = NULL;
info_rdaddwc(&rs, entry->text, NULL, FALSE);
+
/*
- * FIXME: splatter colons.
+ * We cannot have colons in index terms, since they
+ * disrupt the structure of the index menu. Remove any
+ * that we find, with a warning.
*/
+ p = q = rs.text;
+ while (*p) {
+ if (*p == ':') {
+ error(err_infoindexcolon, &entry->fpos);
+ } else {
+ *q++ = *p;
+ }
+ p++;
+ }
+
ii->text = rs.text;
entry->backend_data = ii;
return n;
}
-static char *info_node_name(paragraph *p)
+static char *info_node_name(paragraph *par)
{
rdstringc rsc = { 0, 0, NULL };
- info_rdaddwc(&rsc, p->kwtext ? p->kwtext : p->words, NULL, FALSE);
+ char *p, *q;
+ info_rdaddwc(&rsc, par->kwtext ? par->kwtext : par->words, NULL, FALSE);
+
+ /*
+ * We cannot have commas or colons in a node name. Remove any
+ * that we find, with a warning.
+ */
+ p = q = rsc.text;
+ while (*p) {
+ if (*p == ':' || *p == ',') {
+ error(err_infonodechar, &par->fpos, *p);
+ } else {
+ *q++ = *p;
+ }
+ p++;
+ }
+ *p = '\0';
+
return rsc.text;
}
static void do_error(int code, va_list ap) {
char error[1024];
char auxbuf[256];
+ char c;
char *sp, *sp2;
wchar_t *wsp;
filepos fpos, fpos2;
" parameters");
flags = FILEPOS;
break;
+ case err_infoindexcolon:
+ fpos = *va_arg(ap, filepos *);
+ sprintf(error, "info output format does not support colons in"
+ " index terms; removing");
+ flags = FILEPOS;
+ break;
+ case err_infonodechar:
+ fpos = *va_arg(ap, filepos *);
+ c = (char)va_arg(ap, int);
+ sprintf(error, "info output format does not support '%c' in"
+ " node names; removing", c);
+ flags = FILEPOS;
+ break;
case err_whatever:
sp = va_arg(ap, char *);
vsprintf(error, sp, ap);
err_misplacedlcont, /* \lcont not after a list item */
err_sectmarkerinblock, /* section marker appeared in block */
err_infodirentry, /* \cfg{info-dir-entry} missing param */
+ err_infoindexcolon, /* colon in index term in info */
+ err_infonodechar, /* colon/comma in node name in info */
err_whatever /* random error of another type */
};
struct indextag_Tag {
wchar_t *name;
word *implicit_text;
+ filepos implicit_fpos;
word **explicit_texts;
+ filepos *explicit_fpos;
int nexplicit, explicit_size;
int nrefs;
indexentry **refs; /* array of entries referenced by tag */
struct indexentry_Tag {
word *text;
void *backend_data; /* private to back end */
+ filepos fpos;
};
indexdata *make_index(void);
void cleanup_index(indexdata *);
/* index_merge takes responsibility for freeing arg 3 iff implicit; never
* takes responsibility for arg 2 */
-void index_merge(indexdata *, int is_explicit, wchar_t *, word *);
+void index_merge(indexdata *, int is_explicit, wchar_t *, word *, filepos *);
void build_index(indexdata *);
void index_debug(indexdata *);
indextag *index_findtag(indexdata *idx, wchar_t *name);
ret->name = NULL;
ret->implicit_text = NULL;
ret->explicit_texts = NULL;
+ ret->explicit_fpos = NULL;
ret->nexplicit = ret->explicit_size = ret->nrefs = 0;
ret->refs = NULL;
return ret;
* Guarantee on calling sequence: all implicit merges are given
* before the explicit ones.
*/
-void index_merge(indexdata *idx, int is_explicit, wchar_t *tags, word *text) {
+void index_merge(indexdata *idx, int is_explicit, wchar_t *tags, word *text,
+ filepos *fpos) {
indextag *t, *existing;
/*
* Otherwise, this is a new tag with an implicit \IM.
*/
t->implicit_text = text;
+ t->implicit_fpos = *fpos;
} else {
sfree(t);
t = existing;
t->explicit_size = t->nexplicit + 8;
t->explicit_texts = resize(t->explicit_texts,
t->explicit_size);
+ t->explicit_fpos = resize(t->explicit_fpos,
+ t->explicit_size);
}
- t->explicit_texts[t->nexplicit++] = text;
+ t->explicit_texts[t->nexplicit] = text;
+ t->explicit_fpos[t->nexplicit] = *fpos;
+ t->nexplicit++;
}
}
}
void build_index(indexdata *i) {
indextag *t;
word **ta;
+ filepos *fa;
int ti;
int j;
if (t->implicit_text) {
t->nrefs = 1;
ta = &t->implicit_text;
+ fa = &t->implicit_fpos;
} else {
t->nrefs = t->nexplicit;
ta = t->explicit_texts;
+ fa = t->explicit_fpos;
}
if (t->nrefs) {
t->refs = mknewa(indexentry *, t->nrefs);
for (j = 0; j < t->nrefs; j++) {
indexentry *ent = mknew(indexentry);
ent->text = *ta++;
+ ent->fpos = *fa++;
t->refs[j] = add234(i->entries, ent);
if (t->refs[j] != ent) /* duplicate */
sfree(ent);
} type;
word **whptr; /* to restore from \u alternatives */
word **idximplicit; /* to restore from \u alternatives */
+ filepos fpos;
} *sitem;
stack parsestk;
struct crossparaitem {
/* 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:
}
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);
}
* Special cases: \W{}\c, \W{}\e, \W{}\cw
*/
sitem = mknew(struct stack_item);
+ sitem->fpos = wd.fpos;
sitem->type = stack_hyper;
if (t.type == tok_cmd &&
(t.cmd == c_e || t.cmd == c_c || t.cmd == c_cw)) {
/* 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;
\IM{nonexist3} Logical impossibilities
+Fingly \i{eep}.
+
+\IM{eep} Thing: with a colon
+
+Flongly \i{eep:sping}.
+
\define{macro} macro definition
\define{macro} same macro again
Unclosed brace: \c{foo.
+\U Spong, wimble: flomp.
+
Comment to EOF: \#{ and here we go.
for (p = sourceform; p; p = p->next)
if (p->type == para_IM)
- index_merge(idx, TRUE, p->keyword, p->words);
+ index_merge(idx, TRUE, p->keyword, p->words, &p->fpos);
build_index(idx);