summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Tatham <anakin@pobox.com>1999-10-20 20:17:18 +0000
committerSimon Tatham <anakin@pobox.com>1999-10-20 20:17:18 +0000
commit8511f4ae900f48999617bc8384e9c327673e2196 (patch)
treed24d0a7d8cc217bf6d864157c3b08e05ed59868f
parente44f985bd4f796d4c4b11eb3555436dbaa2d163b (diff)
downloadhalibut-8511f4ae900f48999617bc8384e9c327673e2196.zip
halibut-8511f4ae900f48999617bc8384e9c327673e2196.tar.gz
halibut-8511f4ae900f48999617bc8384e9c327673e2196.tar.bz2
halibut-8511f4ae900f48999617bc8384e9c327673e2196.tar.xz
First backend! Text output now pretty much works.
[originally from svn r240]
-rw-r--r--Makefile1
-rw-r--r--biblio.c1
-rw-r--r--bk_text.c444
-rw-r--r--buttress.h45
-rw-r--r--contents.c10
-rw-r--r--error.c5
-rw-r--r--index.c20
-rw-r--r--input.c30
-rw-r--r--keywords.c6
-rw-r--r--main.c16
-rw-r--r--misc.c114
-rw-r--r--tree23.c2
12 files changed, 643 insertions, 51 deletions
diff --git a/Makefile b/Makefile
index d89b105..89843cc 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ SRC := ../
MODULES := main malloc ustring error help licence version misc tree23
MODULES += input keywords contents index style biblio
+MODULES += bk_text
OBJECTS := $(addsuffix .o,$(MODULES))
DEPS := $(addsuffix .d,$(MODULES))
diff --git a/biblio.c b/biblio.c
index 70e9411..ffff435 100644
--- a/biblio.c
+++ b/biblio.c
@@ -99,6 +99,7 @@ void gen_citations(paragraph *source, keywordlist *kl) {
wd->next = NULL;
kw->text = wd;
}
+ para->kwtext = kw->text;
}
}
}
diff --git a/bk_text.c b/bk_text.c
new file mode 100644
index 0000000..786c126
--- /dev/null
+++ b/bk_text.c
@@ -0,0 +1,444 @@
+/*
+ * text backend for Buttress
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "buttress.h"
+
+typedef enum { LEFT, CENTRE } alignment;
+
+typedef struct {
+ int indent;
+ int listindentbefore, listindentafter;
+ int width;
+ alignment titlealign, chapteralign;
+ wchar_t titleunderline, chapterunderline;
+ int include_version_id;
+ int indent_preambles;
+ word bullet;
+} textconfig;
+
+static int text_convert(wchar_t *, char **);
+
+static void text_title(FILE *, word *, word *, alignment, wchar_t, int, int);
+static void text_heading(FILE *, word *, word *, int, int);
+static void text_para(FILE *, word *, char *, word *, int, int, int);
+static void text_codepara(FILE *, word *, int, int);
+static void text_versionid(FILE *, word *);
+
+static textconfig text_configure(paragraph *sourceform) {
+ textconfig ret;
+
+ /*
+ * Non-negotiables.
+ */
+ ret.bullet.next = NULL;
+ ret.bullet.alt = NULL;
+ ret.bullet.type = word_Normal;
+
+ /*
+ * Defaults.
+ */
+ ret.indent = 7;
+ ret.listindentbefore = 1;
+ ret.listindentafter = 3;
+ ret.width = 68;
+ ret.titlealign = CENTRE;
+ ret.titleunderline = L'=';
+ ret.chapteralign = LEFT;
+ ret.chapterunderline = L'-';
+ ret.include_version_id = TRUE;
+ ret.indent_preambles = FALSE;
+ ret.bullet.text = ustrdup(L"-");
+
+ /*
+ * FIXME: must walk the source form gleaning configuration from
+ * \config paragraphs.
+ */
+ IGNORE(sourceform); /* for now */
+
+ return ret;
+}
+
+void text_backend(paragraph *sourceform, keywordlist *keywords, index *idx) {
+ paragraph *p;
+ textconfig conf;
+ word *prefix, *body, *wp;
+ word spaceword;
+ FILE *fp;
+ char *prefixextra;
+ int indentb, indenta;
+
+ IGNORE(keywords); /* we don't happen to need this */
+ IGNORE(idx); /* or this */
+
+ conf = text_configure(sourceform);
+
+ /*
+ * Determine the output file name, and open the output file
+ *
+ * FIXME: want configurable output file names here. For the
+ * moment, we'll just call it `output.txt'.
+ */
+ fp = fopen("output.txt", "w");
+ if (!fp) {
+ error(err_cantopenw, "output.txt");
+ return;
+ }
+
+ /* Do the title */
+ for (p = sourceform; p; p = p->next)
+ if (p->type == para_Title)
+ text_title(fp, NULL, p->words,
+ conf.titlealign, conf.titleunderline,
+ conf.indent, conf.width);
+
+ /* Do the preamble and copyright */
+ for (p = sourceform; p; p = p->next)
+ if (p->type == para_Preamble)
+ text_para(fp, NULL, NULL, p->words,
+ conf.indent_preambles ? conf.indent : 0, 0,
+ conf.width + (conf.indent_preambles ? 0 : conf.indent));
+ for (p = sourceform; p; p = p->next)
+ if (p->type == para_Copyright)
+ text_para(fp, NULL, NULL, p->words,
+ conf.indent_preambles ? conf.indent : 0, 0,
+ conf.width + (conf.indent_preambles ? 0 : conf.indent));
+
+ /* Do the main document */
+ for (p = sourceform; p; p = p->next) switch (p->type) {
+
+ /*
+ * Things we ignore because we've already processed them or
+ * aren't going to touch them in this pass.
+ */
+ case para_IM:
+ case para_BR:
+ case para_Biblio: /* only touch BiblioCited */
+ case para_VersionID:
+ case para_Copyright:
+ case para_Preamble:
+ case para_NoCite:
+ case para_Title:
+ break;
+
+ /*
+ * Chapter titles.
+ */
+ case para_Chapter:
+ case para_Appendix:
+ case para_UnnumberedChapter:
+ text_title(fp, p->kwtext, p->words,
+ conf.chapteralign, conf.chapterunderline,
+ conf.indent, conf.width);
+ break;
+
+ case para_Heading:
+ case para_Subsect:
+ text_heading(fp, p->kwtext2, p->words, conf.indent, conf.width);
+ break;
+
+ case para_Normal:
+ case para_BiblioCited: /* FIXME: put the citation on front */
+ case para_Bullet:
+ case para_NumberedList:
+ if (p->type == para_Bullet) {
+ prefix = &conf.bullet;
+ prefixextra = NULL;
+ indentb = conf.listindentbefore;
+ indenta = conf.listindentafter;
+ } else if (p->type == para_NumberedList) {
+ prefix = p->kwtext;
+ prefixextra = ".";
+ indentb = conf.listindentbefore;
+ indenta = conf.listindentafter;
+ } else {
+ prefix = NULL;
+ prefixextra = NULL;
+ indentb = indenta = 0;
+ }
+ if (p->type == para_BiblioCited) {
+ body = dup_word_list(p->kwtext);
+ for (wp = body; wp->next; wp = wp->next);
+ wp->next = &spaceword;
+ spaceword.next = p->words;
+ spaceword.alt = NULL;
+ spaceword.type = word_WhiteSpace;
+ spaceword.text = NULL;
+ } else {
+ wp = NULL;
+ body = p->words;
+ }
+ text_para(fp, prefix, prefixextra, body,
+ conf.indent + indentb, indenta, conf.width);
+ if (wp) {
+ wp->next = NULL;
+ free_word_list(body);
+ }
+ break;
+
+ case para_Code:
+ text_codepara(fp, p->words, conf.indent, conf.width);
+ break;
+ }
+
+ /* Do the version ID */
+ if (conf.include_version_id) {
+ for (p = sourceform; p; p = p->next)
+ if (p->type == para_VersionID)
+ text_versionid(fp, p->words);
+ }
+
+ /*
+ * Tidy up
+ */
+ fclose(fp);
+ sfree(conf.bullet.text);
+}
+
+/*
+ * Convert a wide string into a string of chars. If `result' is
+ * non-NULL, mallocs the resulting string and stores a pointer to
+ * it in `*result'. If `result' is NULL, merely checks whether all
+ * characters in the string are feasible for the output character
+ * set.
+ *
+ * Return is nonzero if all characters are OK. If not all
+ * characters are OK but `result' is non-NULL, a result _will_
+ * still be generated!
+ */
+static int text_convert(wchar_t *s, char **result) {
+ /*
+ * FIXME. Currently this is ISO8859-1 only.
+ */
+ int doing = (result != 0);
+ int ok = TRUE;
+ char *p = NULL;
+ int plen = 0, psize = 0;
+
+ for (; *s; s++) {
+ wchar_t c = *s;
+ char outc;
+
+ if ((c >= 32 && c <= 126) ||
+ (c >= 160 && c <= 255)) {
+ /* Char is OK. */
+ outc = (char)c;
+ } else {
+ /* Char is not OK. */
+ ok = FALSE;
+ outc = 0xBF; /* approximate the good old DEC `uh?' */
+ }
+ if (doing) {
+ if (plen >= psize) {
+ psize = plen + 256;
+ p = resize(p, psize);
+ }
+ p[plen++] = outc;
+ }
+ }
+ if (doing) {
+ p = resize(p, plen+1);
+ p[plen] = '\0';
+ *result = p;
+ }
+ return ok;
+}
+
+static void text_rdaddwc(rdstringc *rs, word *text, word *end) {
+ char *c;
+
+ for (; text && text != end; text = text->next) switch (text->type) {
+ case word_HyperLink:
+ case word_HyperEnd:
+ case word_UpperXref:
+ case word_LowerXref:
+ case word_XrefEnd:
+ case word_IndexRef:
+ break;
+
+ case word_Normal:
+ case word_Emph:
+ case word_Code:
+ case word_WeakCode:
+ if (text->type == word_Emph)
+ rdaddc(rs, '_'); /* FIXME: configurability */
+ else if (text->type == word_Code)
+ rdaddc(rs, '`'); /* FIXME: configurability */
+ if (text_convert(text->text, &c))
+ rdaddsc(rs, c);
+ else
+ text_rdaddwc(rs, text->alt, NULL);
+ sfree(c);
+ if (text->type == word_Emph)
+ rdaddc(rs, '_'); /* FIXME: configurability */
+ else if (text->type == word_Code)
+ rdaddc(rs, '\''); /* FIXME: configurability */
+ break;
+
+ case word_WhiteSpace:
+ rdaddc(rs, ' ');
+ break;
+ }
+}
+
+static int text_width(word *);
+
+static int text_width_list(word *text) {
+ int w = 0;
+ while (text) {
+ w += text_width(text);
+ text = text->next;
+ }
+ return w;
+}
+
+static int text_width(word *text) {
+ switch (text->type) {
+ case word_HyperLink:
+ case word_HyperEnd:
+ case word_UpperXref:
+ case word_LowerXref:
+ case word_XrefEnd:
+ case word_IndexRef:
+ return 0;
+
+ case word_Normal:
+ case word_Emph:
+ case word_Code:
+ case word_WeakCode:
+ return ((text->type == word_Emph || text->type == word_Code ? 2 : 0) +
+ (text_convert(text->text, NULL) ?
+ ustrlen(text->text) :
+ text_width_list(text->alt)));
+
+ case word_WhiteSpace:
+ return 1;
+ }
+ return 0; /* should never happen */
+}
+
+static void text_title(FILE *fp, word *prefix, word *text,
+ alignment align, wchar_t underline,
+ int indent, int width) {
+ rdstringc t = { 0, 0, NULL };
+ int margin, length;
+
+ if (prefix) {
+ text_rdaddwc(&t, prefix, NULL);
+ rdaddsc(&t, ": ");
+ }
+ text_rdaddwc(&t, text, NULL);
+
+ length = strlen(t.text);
+ if (align == CENTRE) {
+ margin = (indent + width - length)/2;
+ if (margin < 0) margin = 0;
+ } else
+ margin = 0;
+
+ fprintf(fp, "%*s%s\n", margin, "", t.text);
+ if (underline != L'\0') {
+ char *u, uc;
+ wchar_t uw[2];
+ uw[0] = underline; uw[1] = L'\0';
+ text_convert(uw, &u);
+ uc = u[0];
+ sfree(u);
+ fprintf(fp, "%*s", margin, "");
+ while (length--)
+ putc(uc, fp);
+ putc('\n', fp);
+ }
+ putc('\n', fp);
+
+ sfree(t.text);
+}
+
+static void text_heading(FILE *fp, word *prefix, word *text,
+ int indent, int width) {
+ rdstringc t = { 0, 0, NULL };
+ int margin;
+
+ if (prefix) {
+ text_rdaddwc(&t, prefix, NULL);
+ rdaddc(&t, ' ');
+ margin = strlen(t.text);
+ }
+ text_rdaddwc(&t, text, NULL);
+
+ margin = indent - margin;
+ if (margin < 0) margin = 0;
+
+ fprintf(fp, "%*s%s\n\n", margin, "", t.text);
+
+ if (strlen(t.text) > (size_t)width) {
+ /* FIXME: warn */
+ }
+
+ sfree(t.text);
+}
+
+static void text_para(FILE *fp, word *prefix, char *prefixextra, word *text,
+ int indent, int extraindent, int width) {
+ wrappedline *wrapping, *p;
+ rdstringc pfx = { 0, 0, NULL };
+ int e;
+ int firstlinewidth = width;
+
+ if (prefix) {
+ text_rdaddwc(&pfx, prefix, NULL);
+ if (prefixextra)
+ rdaddsc(&pfx, prefixextra);
+ fprintf(fp, "%*s%s", indent, "", pfx.text);
+ e = extraindent - strlen(pfx.text);
+ if (e < 0) {
+ e = 0;
+ firstlinewidth -= e;
+ if (firstlinewidth < 0) {
+ e = indent + extraindent;
+ firstlinewidth = width;
+ fprintf(fp, "\n");
+ }
+ }
+ sfree(pfx.text);
+ } else
+ e = indent + extraindent;
+
+ wrapping = wrap_para(text, firstlinewidth, width, text_width);
+ for (p = wrapping; p; p = p->next) {
+ rdstringc t = { 0, 0, NULL };
+ text_rdaddwc(&t, p->begin, p->end);
+ fprintf(fp, "%*s%s\n", e, "", t.text);
+ e = indent + extraindent;
+ sfree(t.text);
+ }
+ wrap_free(wrapping);
+ putc('\n', fp);
+}
+
+static void text_codepara(FILE *fp, word *text, int indent, int width) {
+ for (; text; text = text->next) if (text->type == word_WeakCode) {
+ char *c;
+ text_convert(text->text, &c);
+ if (strlen(c) > (size_t)width) {
+ /* FIXME: warn */
+ }
+ fprintf(fp, "%*s%s\n", indent, "", c);
+ sfree(c);
+ }
+
+ putc('\n', fp);
+}
+
+static void text_versionid(FILE *fp, word *text) {
+ rdstringc t = { 0, 0, NULL };
+
+ rdaddc(&t, '['); /* FIXME: configurability */
+ text_rdaddwc(&t, text, NULL);
+ rdaddc(&t, ']'); /* FIXME: configurability */
+
+ fprintf(fp, "%s\n\n", t.text);
+ sfree(t.text);
+}
diff --git a/buttress.h b/buttress.h
index 9bdfcfc..062bc37 100644
--- a/buttress.h
+++ b/buttress.h
@@ -16,6 +16,9 @@
#define FALSE 0
#endif
+/* For suppressing unused-parameter warnings */
+#define IGNORE(x) ( (x) = (x) )
+
/*
* Structure tags
*/
@@ -65,6 +68,7 @@ struct paragraph_Tag {
word *words; /* list of words in paragraph */
int aux; /* number, in a numbered paragraph */
word *kwtext; /* chapter/section indication */
+ word *kwtext2; /* numeric-only form of kwtext */
filepos fpos;
};
enum {
@@ -140,7 +144,8 @@ enum {
err_nestedindex, /* unable to nest `\i' thingys */
err_nosuchkw, /* unresolved cross-reference */
err_multiBR, /* multiple \BRs on same keyword */
- err_nosuchidxtag /* \IM on unknown index tag (warning) */
+ err_nosuchidxtag, /* \IM on unknown index tag (warning) */
+ err_cantopenw /* can't open output file for write */
};
/*
@@ -205,8 +210,36 @@ stack stk_new(void);
void stk_free(stack);
void stk_push(stack, void *);
void *stk_pop(stack);
+
+typedef struct tagRdstring rdstring;
+struct tagRdstring {
+ int pos, size;
+ wchar_t *text;
+};
+typedef struct tagRdstringc rdstringc;
+struct tagRdstringc {
+ int pos, size;
+ char *text;
+};
+void rdadd(rdstring *rs, wchar_t c);
+void rdadds(rdstring *rs, wchar_t *p);
+wchar_t *rdtrim(rdstring *rs);
+void rdaddc(rdstringc *rs, char c);
+void rdaddsc(rdstringc *rs, char *p);
+char *rdtrimc(rdstringc *rs);
+
int compare_wordlists(word *a, word *b);
+typedef struct tagWrappedLine wrappedline;
+struct tagWrappedLine {
+ wrappedline *next;
+ word *begin, *end; /* first & last words of line */
+ int nspaces; /* number of whitespaces in line */
+ int shortfall; /* how much shorter than max width */
+};
+wrappedline *wrap_para(word *, int, int, int (*)(word *));
+void wrap_free(wrappedline *);
+
/*
* input.c
*/
@@ -243,12 +276,13 @@ void cleanup_index(index *);
* takes responsibility for arg 2 */
void index_merge(index *, int is_explicit, wchar_t *, word *);
void build_index(index *);
+void index_debug(index *);
/*
* contents.c
*/
numberstate *number_init(void);
-word *number_mktext(numberstate *, int, int, int);
+word *number_mktext(numberstate *, int, int, int, word **);
void number_free(numberstate *);
/*
@@ -275,6 +309,11 @@ void freetree23(tree23 *);
void *add23(tree23 *, void *, int (*cmp)(void *, void *));
void *find23(tree23 *, void *, int (*cmp)(void *, void *));
void *first23(tree23 *, enum23 *);
-void *next23(tree23 *, enum23 *);
+void *next23(enum23 *);
+
+/*
+ * bk_text.c
+ */
+void text_backend(paragraph *, keywordlist *, index *);
#endif
diff --git a/contents.c b/contents.c
index 790c58f..494e987 100644
--- a/contents.c
+++ b/contents.c
@@ -89,8 +89,10 @@ static void doanumber(word ***wret, int num) {
dotext(wret, p);
}
-word *number_mktext(numberstate *state, int para, int aux, int prev) {
+word *number_mktext(numberstate *state, int para, int aux, int prev,
+ word **auxret) {
word *ret = NULL;
+ word **ret2 = &ret;
word **pret = &ret;
int i, level;
@@ -101,6 +103,7 @@ word *number_mktext(numberstate *state, int para, int aux, int prev) {
state->sectionlevels[i] = 0;
dotext(&pret, L"Chapter");
dospace(&pret);
+ ret2 = pret;
donumber(&pret, state->chapternum);
state->ischapter = 1;
break;
@@ -117,6 +120,7 @@ word *number_mktext(numberstate *state, int para, int aux, int prev) {
state->sectionlevels[i] = 0;
dotext(&pret, L"Section");
dospace(&pret);
+ ret2 = pret;
if (state->ischapter)
donumber(&pret, state->chapternum);
else
@@ -134,10 +138,12 @@ word *number_mktext(numberstate *state, int para, int aux, int prev) {
state->sectionlevels[i] = 0;
dotext(&pret, L"Appendix");
dospace(&pret);
+ ret2 = pret;
doanumber(&pret, state->appendixnum);
state->ischapter = 0;
break;
case para_NumberedList:
+ ret2 = pret;
if (prev != para_NumberedList)
state->listitem = 0;
state->listitem++;
@@ -145,5 +151,7 @@ word *number_mktext(numberstate *state, int para, int aux, int prev) {
break;
}
+ if (auxret)
+ *auxret = *ret2;
return ret;
}
diff --git a/error.c b/error.c
index 704ae03..b7eb0d5 100644
--- a/error.c
+++ b/error.c
@@ -142,6 +142,11 @@ static void do_error(int code, va_list ap) {
flags = 0;
/* FIXME: need to get a filepos to here somehow */
break;
+ case err_cantopenw:
+ sp = va_arg(ap, char *);
+ sprintf(error, "unable to open output file `%.200s'", sp);
+ flags = PREFIX;
+ break;
}
if (flags & PREFIX)
diff --git a/index.c b/index.c
index 3f629a0..4d7cfe9 100644
--- a/index.c
+++ b/index.c
@@ -128,12 +128,13 @@ void index_merge(index *idx, int is_explicit, wchar_t *tags, word *text) {
* entries.
*/
void build_index(index *i) {
- indextag *t, **ta;
+ indextag *t;
+ word **ta;
enum23 e;
int j;
for (t = (indextag *)first23(i->tags, &e); t;
- t = (indextag *)next23(i->tags, &e)) {
+ t = (indextag *)next23(&e)) {
if (t->implicit_text) {
t->nrefs = 1;
ta = &t->implicit_text;
@@ -156,10 +157,9 @@ void cleanup_index(index *i) {
indextag *t;
indexentry *ent;
enum23 e;
- int j;
for (t = (indextag *)first23(i->tags, &e); t;
- t = (indextag *)next23(i->tags, &e)) {
+ t = (indextag *)next23(&e)) {
sfree(t->name);
free_word_list(t->implicit_text);
sfree(t->explicit_texts);
@@ -168,30 +168,29 @@ void cleanup_index(index *i) {
}
freetree23(i->tags);
for (ent = (indexentry *)first23(i->entries, &e); ent;
- ent = (indexentry *)next23(i->entries, &e)) {
+ ent = (indexentry *)next23(&e)) {
sfree(ent);
}
freetree23(i->entries);
sfree(i);
}
+static void dbg_prtwordlist(int level, word *w);
+static void dbg_prtmerge(int is_explicit, wchar_t *tag, word *text);
+
void index_debug(index *i) {
indextag *t;
enum23 e;
int j;
for (t = (indextag *)first23(i->tags, &e); t;
- t = (indextag *)next23(i->tags, &e)) {
+ t = (indextag *)next23(&e)) {
if (t->implicit_text)
dbg_prtmerge(0, t->name, t->implicit_text);
for (j = 0; j < t->nexplicit; j++)
dbg_prtmerge(1, t->name, t->explicit_texts[j]);
}
}
-#define DEBUG
-
-#ifdef DEBUG
-static void dbg_prtwordlist(int level, word *w);
static void dbg_prtmerge(int is_explicit, wchar_t *tag, word *text) {
printf("\\IM: %splicit: \"", is_explicit ? "ex" : "im");
@@ -221,4 +220,3 @@ static void dbg_prtwordlist(int level, word *w) {
printf("\n");
}
}
-#endif
diff --git a/input.c b/input.c
index c5d0b5c..d5c4685 100644
--- a/input.c
+++ b/input.c
@@ -76,36 +76,6 @@ static int get(input *in) {
}
/*
- * Small routines to amalgamate a string from an input source.
- */
-typedef struct tagRdstring rdstring;
-struct tagRdstring {
- int pos, size;
- wchar_t *text;
-};
-static void rdadd(rdstring *rs, wchar_t c) {
- if (rs->pos >= rs->size-1) {
- rs->size = rs->pos + 128;
- rs->text = resize(rs->text, rs->size);
- }
- rs->text[rs->pos++] = c;
- rs->text[rs->pos] = 0;
-}
-static void rdadds(rdstring *rs, wchar_t *p) {
- int len = ustrlen(p);
- if (rs->pos >= rs->size - len) {
- rs->size = rs->pos + len + 128;
- rs->text = resize(rs->text, rs->size);
- }
- ustrcpy(rs->text + rs->pos, p);
- rs->pos += len;
-}
-static wchar_t *rdtrim(rdstring *rs) {
- rs->text = resize(rs->text, rs->pos + 1);
- return rs->text;
-}
-
-/*
* Lexical analysis of source files.
*/
typedef struct token_Tag token;
diff --git a/keywords.c b/keywords.c
index c446761..9019b55 100644
--- a/keywords.c
+++ b/keywords.c
@@ -100,7 +100,7 @@ keywordlist *get_keywords(paragraph *source) {
* Number the chapter / section / list-item / whatever.
*/
source->kwtext = number_mktext(n, source->type, source->aux,
- prevpara);
+ prevpara, &source->kwtext2);
prevpara = source->type;
if (source->keyword && *source->keyword) {
@@ -161,7 +161,9 @@ void subst_keywords(paragraph *source, keywordlist *kl) {
} else
subst = dup_word_list(kw->text);
- if (subst && ptr->type == word_LowerXref)
+ if (subst && ptr->type == word_LowerXref &&
+ kw->para->type != para_Biblio &&
+ kw->para->type != para_BiblioCited)
ustrlow(subst->text);
close = mknew(word);
diff --git a/main.c b/main.c
index 1fef5e4..34ce7d4 100644
--- a/main.c
+++ b/main.c
@@ -17,6 +17,7 @@ int main(int argc, char **argv) {
int nogo;
int errs;
int reportcols;
+ int debug;
/*
* Set up initial (default) parameters.
@@ -26,6 +27,7 @@ int main(int argc, char **argv) {
nfiles = 0;
nogo = errs = FALSE;
reportcols = 0;
+ debug = 0;
if (argc == 1) {
usage();
@@ -85,6 +87,7 @@ int main(int argc, char **argv) {
case 'V':
case 'L':
case 'P':
+ case 'd':
/*
* Option requiring no parameter.
*/
@@ -104,6 +107,9 @@ int main(int argc, char **argv) {
case 'P':
reportcols = 1;
break;
+ case 'd':
+ debug = TRUE;
+ break;
}
break;
case 'o':
@@ -193,10 +199,14 @@ int main(int argc, char **argv) {
index_merge(idx, TRUE, p->keyword, p->words);
build_index(idx);
- index_debug(idx);
- dbg_prtkws(keywords);
- dbg_prtsource(sourceform);
+ if (debug) {
+ index_debug(idx);
+ dbg_prtkws(keywords);
+ dbg_prtsource(sourceform);
+ }
+
+ text_backend(sourceform, keywords, idx);
free_para_list(sourceform);
free_keywords(keywords);
diff --git a/misc.c b/misc.c
index 3ead01c..3d512c6 100644
--- a/misc.c
+++ b/misc.c
@@ -41,6 +41,53 @@ void *stk_pop(stack s) {
return NULL;
}
+/*
+ * Small routines to amalgamate a string from an input source.
+ */
+void rdadd(rdstring *rs, wchar_t c) {
+ if (rs->pos >= rs->size-1) {
+ rs->size = rs->pos + 128;
+ rs->text = resize(rs->text, rs->size);
+ }
+ rs->text[rs->pos++] = c;
+ rs->text[rs->pos] = 0;
+}
+void rdadds(rdstring *rs, wchar_t *p) {
+ int len = ustrlen(p);
+ if (rs->pos >= rs->size - len) {
+ rs->size = rs->pos + len + 128;
+ rs->text = resize(rs->text, rs->size);
+ }
+ ustrcpy(rs->text + rs->pos, p);
+ rs->pos += len;
+}
+wchar_t *rdtrim(rdstring *rs) {
+ rs->text = resize(rs->text, rs->pos + 1);
+ return rs->text;
+}
+
+void rdaddc(rdstringc *rs, char c) {
+ if (rs->pos >= rs->size-1) {
+ rs->size = rs->pos + 128;
+ rs->text = resize(rs->text, rs->size);
+ }
+ rs->text[rs->pos++] = c;
+ rs->text[rs->pos] = 0;
+}
+void rdaddsc(rdstringc *rs, char *p) {
+ int len = strlen(p);
+ if (rs->pos >= rs->size - len) {
+ rs->size = rs->pos + len + 128;
+ rs->text = resize(rs->text, rs->size);
+ }
+ strcpy(rs->text + rs->pos, p);
+ rs->pos += len;
+}
+char *rdtrimc(rdstringc *rs) {
+ rs->text = resize(rs->text, rs->pos + 1);
+ return rs->text;
+}
+
int compare_wordlists(word *a, word *b) {
int t;
while (a && b) {
@@ -84,3 +131,70 @@ int compare_wordlists(word *a, word *b) {
else
return 0;
}
+
+wrappedline *wrap_para(word *text, int width, int subsequentwidth,
+ int (*widthfn)(word *)) {
+ wrappedline *head = NULL, **ptr = &head;
+ word *spc;
+ int nspc;
+ int thiswidth, lastgood;
+
+ while (text) {
+ wrappedline *w = mknew(wrappedline);
+ *ptr = w;
+ ptr = &w->next;
+ w->next = NULL;
+
+ w->begin = text;
+ spc = NULL;
+ nspc = 0;
+ thiswidth = lastgood = 0;
+ while (text) {
+ thiswidth += widthfn(text);
+ if (text->next && text->next->type == word_WhiteSpace) {
+ if (thiswidth > width)
+ break;
+ spc = text->next;
+ lastgood = thiswidth;
+ nspc++;
+ }
+ text = text->next;
+ }
+ /*
+ * We've exited this loop on one of three conditions. spc
+ * might be non-NULL and we've overflowed: we have broken
+ * the paragraph there. spc might be NULL and text might be
+ * NULL too: we've reached the end of the paragraph and
+ * should output the last line. Or text might be non-NULL
+ * and spc might be NULL: we've got an anomalously long
+ * line with no spaces we could have broken at. Output it
+ * anyway as the best we can do.
+ */
+ if (spc && thiswidth > width) {
+ w->end = spc;
+ text = spc->next;
+ w->nspaces = nspc-1;
+ w->shortfall = width - lastgood;
+ } else if (!text) {
+ w->end = NULL; /* no end marker needed */
+ w->nspaces = nspc;
+ w->shortfall = width - thiswidth;
+ } else {
+ w->end = text;
+ text = text->next;
+ w->nspaces = 0;
+ w->shortfall = width - thiswidth;
+ }
+ width = subsequentwidth;
+ }
+
+ return head;
+}
+
+void wrap_free(wrappedline *w) {
+ while (w) {
+ wrappedline *t = w->next;
+ sfree(w);
+ w = t;
+ }
+}
diff --git a/tree23.c b/tree23.c
index 4a0d60c..7089c29 100644
--- a/tree23.c
+++ b/tree23.c
@@ -238,7 +238,7 @@ void *first23(tree23 *t, enum23 *e) {
return n->elems[0];
}
-void *next23(tree23 *t, enum23 *e) {
+void *next23(enum23 *e) {
node23 *n = (node23 *)e->node;
int pos = e->posn;