typedef enum { LEFT, LEFTPLUS, CENTRE } alignment;
typedef struct {
alignment align;
- int just_numbers;
- wchar_t underline;
+ int number_at_all, just_numbers;
+ wchar_t *underline;
wchar_t *number_suffix;
} alignstruct;
int nasect;
int include_version_id;
int indent_preambles;
+ int charset;
word bullet;
+ wchar_t *lquote, *rquote, *rule;
+ char *filename;
+ wchar_t *listsuffix, *startemph, *endemph;
} textconfig;
-static int text_convert(wchar_t *, char **);
+typedef struct {
+ FILE *fp;
+ int charset;
+ charset_state state;
+} textfile;
+
+static void text_heading(textfile *, word *, word *, word *, alignstruct,
+ int, int, textconfig *);
+static void text_rule(textfile *, int, int, textconfig *);
+static void text_para(textfile *, word *, wchar_t *, word *, int, int, int,
+ textconfig *);
+static void text_codepara(textfile *, word *, int, int);
+static void text_versionid(textfile *, word *, textconfig *);
-static void text_heading(FILE *, word *, word *, word *, alignstruct, int,int);
-static void text_rule(FILE *, 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 void text_output(textfile *, const wchar_t *);
+static void text_output_many(textfile *, int, wchar_t);
static alignment utoalign(wchar_t *p) {
if (!ustricmp(p, L"centre") || !ustricmp(p, L"center"))
static textconfig text_configure(paragraph *source) {
textconfig ret;
+ paragraph *p;
+ int n;
/*
* Non-negotiables.
ret.bullet.alt = NULL;
ret.bullet.type = word_Normal;
ret.atitle.just_numbers = FALSE; /* ignored */
+ ret.atitle.number_at_all = TRUE; /* ignored */
/*
* Defaults.
ret.listindentafter = 3;
ret.width = 68;
ret.atitle.align = CENTRE;
- ret.atitle.underline = L'=';
+ ret.atitle.underline = L"\x2550\0=\0\0";
ret.achapter.align = LEFT;
ret.achapter.just_numbers = FALSE;
- ret.achapter.number_suffix = ustrdup(L": ");
- ret.achapter.underline = L'-';
+ ret.achapter.number_at_all = TRUE;
+ ret.achapter.number_suffix = L": ";
+ ret.achapter.underline = L"\x203E\0-\0\0";
ret.nasect = 1;
- ret.asect = mknewa(alignstruct, ret.nasect);
+ ret.asect = snewn(ret.nasect, alignstruct);
ret.asect[0].align = LEFTPLUS;
ret.asect[0].just_numbers = TRUE;
- ret.asect[0].number_suffix = ustrdup(L" ");
- ret.asect[0].underline = L'\0';
+ ret.asect[0].number_at_all = TRUE;
+ ret.asect[0].number_suffix = L" ";
+ ret.asect[0].underline = L"\0";
ret.include_version_id = TRUE;
ret.indent_preambles = FALSE;
- ret.bullet.text = ustrdup(L"-");
-
- for (; source; source = source->next) {
- if (source->type == para_Config) {
- if (!ustricmp(source->keyword, L"text-indent")) {
- ret.indent = utoi(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-indent-code")) {
- ret.indent_code = utoi(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-width")) {
- ret.width = utoi(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-list-indent")) {
- ret.listindentbefore = utoi(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-listitem-indent")) {
- ret.listindentafter = utoi(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-chapter-align")) {
- ret.achapter.align = utoalign(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-chapter-underline")) {
- ret.achapter.underline = *uadv(source->keyword);
- } else if (!ustricmp(source->keyword, L"text-chapter-numeric")) {
- ret.achapter.just_numbers = utob(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-chapter-suffix")) {
- ret.achapter.number_suffix = uadv(source->keyword);
- } else if (!ustricmp(source->keyword, L"text-section-align")) {
- wchar_t *p = uadv(source->keyword);
+ ret.bullet.text = L"\x2022\0-\0\0";
+ ret.rule = L"\x2500\0-\0\0";
+ ret.filename = dupstr("output.txt");
+ ret.startemph = L"_\0_\0\0";
+ ret.endemph = uadv(ret.startemph);
+ ret.listsuffix = L".";
+ ret.charset = CS_ASCII;
+ /*
+ * Default quote characters are Unicode matched single quotes,
+ * falling back to the TeXlike `'.
+ */
+ ret.lquote = L"\x2018\0\x2019\0`\0'\0\0";
+ ret.rquote = uadv(ret.lquote);
+
+ /*
+ * Two-pass configuration so that we can pick up global config
+ * (e.g. `quotes') before having it overridden by specific
+ * config (`text-quotes'), irrespective of the order in which
+ * they occur.
+ */
+ for (p = source; p; p = p->next) {
+ if (p->type == para_Config) {
+ if (!ustricmp(p->keyword, L"quotes")) {
+ if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
+ ret.lquote = uadv(p->keyword);
+ ret.rquote = uadv(ret.lquote);
+ }
+ }
+ }
+ }
+
+ for (p = source; p; p = p->next) {
+ if (p->type == para_Config) {
+ if (!ustricmp(p->keyword, L"text-indent")) {
+ ret.indent = utoi(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-charset")) {
+ ret.charset = charset_from_ustr(&p->fpos, uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-filename")) {
+ sfree(ret.filename);
+ ret.filename = dupstr(adv(p->origkeyword));
+ } else if (!ustricmp(p->keyword, L"text-indent-code")) {
+ ret.indent_code = utoi(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-width")) {
+ ret.width = utoi(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-list-indent")) {
+ ret.listindentbefore = utoi(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-listitem-indent")) {
+ ret.listindentafter = utoi(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-chapter-align")) {
+ ret.achapter.align = utoalign(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-chapter-underline")) {
+ ret.achapter.underline = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-chapter-numeric")) {
+ ret.achapter.just_numbers = utob(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-chapter-shownumber")) {
+ ret.achapter.number_at_all = utob(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-chapter-suffix")) {
+ ret.achapter.number_suffix = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-section-align")) {
+ wchar_t *q = uadv(p->keyword);
int n = 0;
- if (uisdigit(*p)) {
- n = utoi(p);
- p = uadv(p);
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
}
if (n >= ret.nasect) {
int i;
- ret.asect = resize(ret.asect, n+1);
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect-1];
ret.nasect = n+1;
}
- ret.asect[n].align = utoalign(p);
- } else if (!ustricmp(source->keyword, L"text-section-underline")) {
- wchar_t *p = uadv(source->keyword);
+ ret.asect[n].align = utoalign(q);
+ } else if (!ustricmp(p->keyword, L"text-section-underline")) {
+ wchar_t *q = uadv(p->keyword);
int n = 0;
- if (uisdigit(*p)) {
- n = utoi(p);
- p = uadv(p);
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
}
if (n >= ret.nasect) {
int i;
- ret.asect = resize(ret.asect, n+1);
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect-1];
ret.nasect = n+1;
}
- ret.asect[n].underline = *p;
- } else if (!ustricmp(source->keyword, L"text-section-numeric")) {
- wchar_t *p = uadv(source->keyword);
+ ret.asect[n].underline = q;
+ } else if (!ustricmp(p->keyword, L"text-section-numeric")) {
+ wchar_t *q = uadv(p->keyword);
int n = 0;
- if (uisdigit(*p)) {
- n = utoi(p);
- p = uadv(p);
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
}
if (n >= ret.nasect) {
int i;
- ret.asect = resize(ret.asect, n+1);
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect-1];
ret.nasect = n+1;
}
- ret.asect[n].just_numbers = utob(p);
- } else if (!ustricmp(source->keyword, L"text-section-suffix")) {
- wchar_t *p = uadv(source->keyword);
+ ret.asect[n].just_numbers = utob(q);
+ } else if (!ustricmp(p->keyword, L"text-section-shownumber")) {
+ wchar_t *q = uadv(p->keyword);
int n = 0;
- if (uisdigit(*p)) {
- n = utoi(p);
- p = uadv(p);
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
}
if (n >= ret.nasect) {
int i;
- ret.asect = resize(ret.asect, n+1);
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect-1];
ret.nasect = n+1;
}
- ret.asect[n].number_suffix = p;
- } else if (!ustricmp(source->keyword, L"text-title-align")) {
- ret.atitle.align = utoalign(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-title-underline")) {
- ret.atitle.underline = *uadv(source->keyword);
- } else if (!ustricmp(source->keyword, L"text-versionid")) {
- ret.include_version_id = utob(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-indent-preamble")) {
- ret.indent_preambles = utob(uadv(source->keyword));
- } else if (!ustricmp(source->keyword, L"text-bullet")) {
- ret.bullet.text = uadv(source->keyword);
+ ret.asect[n].number_at_all = utob(q);
+ } else if (!ustricmp(p->keyword, L"text-section-suffix")) {
+ wchar_t *q = uadv(p->keyword);
+ int n = 0;
+ if (uisdigit(*q)) {
+ n = utoi(q);
+ q = uadv(q);
+ }
+ if (n >= ret.nasect) {
+ int i;
+ ret.asect = sresize(ret.asect, n+1, alignstruct);
+ for (i = ret.nasect; i <= n; i++) {
+ ret.asect[i] = ret.asect[ret.nasect-1];
+ }
+ ret.nasect = n+1;
+ }
+ ret.asect[n].number_suffix = q;
+ } else if (!ustricmp(p->keyword, L"text-title-align")) {
+ ret.atitle.align = utoalign(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-title-underline")) {
+ ret.atitle.underline = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-versionid")) {
+ ret.include_version_id = utob(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-indent-preamble")) {
+ ret.indent_preambles = utob(uadv(p->keyword));
+ } else if (!ustricmp(p->keyword, L"text-bullet")) {
+ ret.bullet.text = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-rule")) {
+ ret.rule = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-list-suffix")) {
+ ret.listsuffix = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"text-emphasis")) {
+ if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
+ ret.startemph = uadv(p->keyword);
+ ret.endemph = uadv(ret.startemph);
+ }
+ } else if (!ustricmp(p->keyword, L"text-quotes")) {
+ if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
+ ret.lquote = uadv(p->keyword);
+ ret.rquote = uadv(ret.lquote);
+ }
}
}
}
+ /*
+ * Now process fallbacks on quote characters, underlines, the
+ * rule character, the emphasis characters, and bullets.
+ */
+ while (*uadv(ret.rquote) && *uadv(uadv(ret.rquote)) &&
+ (!cvt_ok(ret.charset, ret.lquote) ||
+ !cvt_ok(ret.charset, ret.rquote))) {
+ ret.lquote = uadv(ret.rquote);
+ ret.rquote = uadv(ret.lquote);
+ }
+
+ while (*uadv(ret.endemph) && *uadv(uadv(ret.endemph)) &&
+ (!cvt_ok(ret.charset, ret.startemph) ||
+ !cvt_ok(ret.charset, ret.endemph))) {
+ ret.startemph = uadv(ret.endemph);
+ ret.endemph = uadv(ret.startemph);
+ }
+
+ while (*ret.atitle.underline && *uadv(ret.atitle.underline) &&
+ !cvt_ok(ret.charset, ret.atitle.underline))
+ ret.atitle.underline = uadv(ret.atitle.underline);
+
+ while (*ret.achapter.underline && *uadv(ret.achapter.underline) &&
+ !cvt_ok(ret.charset, ret.achapter.underline))
+ ret.achapter.underline = uadv(ret.achapter.underline);
+
+ for (n = 0; n < ret.nasect; n++) {
+ while (*ret.asect[n].underline && *uadv(ret.asect[n].underline) &&
+ !cvt_ok(ret.charset, ret.asect[n].underline))
+ ret.asect[n].underline = uadv(ret.asect[n].underline);
+ }
+
+ while (*ret.bullet.text && *uadv(ret.bullet.text) &&
+ !cvt_ok(ret.charset, ret.bullet.text))
+ ret.bullet.text = uadv(ret.bullet.text);
+
+ while (*ret.rule && *uadv(ret.rule) &&
+ !cvt_ok(ret.charset, ret.rule))
+ ret.rule = uadv(ret.rule);
+
return ret;
}
+paragraph *text_config_filename(char *filename)
+{
+ return cmdline_cfg_simple("text-filename", filename, NULL);
+}
+
void text_backend(paragraph *sourceform, keywordlist *keywords,
- indexdata *idx) {
+ indexdata *idx, void *unused) {
paragraph *p;
textconfig conf;
word *prefix, *body, *wp;
word spaceword;
- FILE *fp;
- char *prefixextra;
+ textfile tf;
+ wchar_t *prefixextra;
+ int nesting, nestbase, nestindent;
int indentb, indenta;
+ IGNORE(unused);
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'.
+ * Open the output file.
*/
- fp = fopen("output.txt", "w");
- if (!fp) {
- error(err_cantopenw, "output.txt");
+ tf.fp = fopen(conf.filename, "w");
+ if (!tf.fp) {
+ error(err_cantopenw, conf.filename);
return;
}
+ tf.charset = conf.charset;
+ tf.state = charset_init_state;
/* Do the title */
for (p = sourceform; p; p = p->next)
if (p->type == para_Title)
- text_heading(fp, NULL, NULL, p->words,
- conf.atitle, conf.indent, conf.width);
+ text_heading(&tf, NULL, NULL, p->words,
+ conf.atitle, conf.indent, conf.width, &conf);
- /* 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));
+ nestindent = conf.listindentbefore + conf.listindentafter;
+ nestbase = (conf.indent_preambles ? 0 : -conf.indent);
+ nesting = nestbase;
/* Do the main document */
for (p = sourceform; p; p = p->next) switch (p->type) {
+ case para_QuotePush:
+ nesting += 2;
+ break;
+ case para_QuotePop:
+ nesting -= 2;
+ assert(nesting >= 0);
+ break;
+
+ case para_LcontPush:
+ nesting += nestindent;
+ break;
+ case para_LcontPop:
+ nesting -= nestindent;
+ assert(nesting >= nestbase);
+ break;
+
/*
* Things we ignore because we've already processed them or
* aren't going to touch them in this pass.
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;
case para_Chapter:
case para_Appendix:
case para_UnnumberedChapter:
- text_heading(fp, p->kwtext, p->kwtext2, p->words,
- conf.achapter, conf.indent, conf.width);
+ text_heading(&tf, p->kwtext, p->kwtext2, p->words,
+ conf.achapter, conf.indent, conf.width, &conf);
+ nesting = 0;
break;
case para_Heading:
case para_Subsect:
- text_heading(fp, p->kwtext, p->kwtext2, p->words,
+ text_heading(&tf, p->kwtext, p->kwtext2, p->words,
conf.asect[p->aux>=conf.nasect ? conf.nasect-1 : p->aux],
- conf.indent, conf.width);
+ conf.indent, conf.width, &conf);
break;
case para_Rule:
- text_rule(fp, conf.indent, conf.width);
+ text_rule(&tf, conf.indent + nesting, conf.width - nesting, &conf);
break;
case para_Normal:
+ case para_Copyright:
+ case para_DescribedThing:
+ case para_Description:
case para_BiblioCited:
case para_Bullet:
case para_NumberedList:
indenta = conf.listindentafter;
} else if (p->type == para_NumberedList) {
prefix = p->kwtext;
- prefixextra = "."; /* FIXME: configurability */
+ prefixextra = conf.listsuffix;
+ indentb = conf.listindentbefore;
+ indenta = conf.listindentafter;
+ } else if (p->type == para_Description) {
+ prefix = NULL;
+ prefixextra = NULL;
indentb = conf.listindentbefore;
indenta = conf.listindentafter;
} else {
wp = NULL;
body = p->words;
}
- text_para(fp, prefix, prefixextra, body,
- conf.indent + indentb, indenta,
- conf.width - indentb - indenta);
+ text_para(&tf, prefix, prefixextra, body,
+ conf.indent + nesting + indentb, indenta,
+ conf.width - nesting - indentb - indenta, &conf);
if (wp) {
wp->next = NULL;
free_word_list(body);
break;
case para_Code:
- text_codepara(fp, p->words, conf.indent + conf.indent_code, conf.width - 2 * conf.indent_code);
+ text_codepara(&tf, p->words,
+ conf.indent + nesting + conf.indent_code,
+ conf.width - nesting - 2 * conf.indent_code);
break;
}
if (conf.include_version_id) {
for (p = sourceform; p; p = p->next)
if (p->type == para_VersionID)
- text_versionid(fp, p->words);
+ text_versionid(&tf, p->words, &conf);
}
/*
* Tidy up
*/
- fclose(fp);
- {
- int i;
- sfree(conf.achapter.number_suffix);
- for (i = 0; i < conf.nasect; i++)
- sfree(conf.asect[i].number_suffix);
- sfree(conf.asect);
- sfree(conf.bullet.text);
- }
+ text_output(&tf, NULL); /* end charset conversion */
+ fclose(tf.fp);
+ sfree(conf.asect);
+ sfree(conf.filename);
}
-/*
- * 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;
- }
+static void text_output(textfile *tf, const wchar_t *s)
+{
+ char buf[256];
+ int ret, len;
+ const wchar_t **sp;
+
+ if (!s) {
+ sp = NULL;
+ len = 1;
+ } else {
+ sp = &s;
+ len = ustrlen(s);
}
- if (doing) {
- p = resize(p, plen+1);
- p[plen] = '\0';
- *result = p;
+
+ while (len > 0) {
+ ret = charset_from_unicode(sp, &len, buf, lenof(buf),
+ tf->charset, &tf->state, NULL);
+ if (!sp)
+ len = 0;
+ fwrite(buf, 1, ret, tf->fp);
}
- return ok;
}
-static void text_rdaddwc(rdstringc *rs, word *text, word *end) {
- char *c;
+static void text_output_many(textfile *tf, int n, wchar_t c)
+{
+ wchar_t s[2];
+ s[0] = c;
+ s[1] = L'\0';
+ while (n--)
+ text_output(tf, s);
+}
+static void text_rdaddw(rdstring *rs, word *text, word *end, textconfig *cfg) {
for (; text && text != end; text = text->next) switch (text->type) {
case word_HyperLink:
case word_HyperEnd:
if (towordstyle(text->type) == word_Emph &&
(attraux(text->aux) == attr_First ||
attraux(text->aux) == attr_Only))
- rdaddc(rs, '_'); /* FIXME: configurability */
+ rdadds(rs, cfg->startemph);
else if (towordstyle(text->type) == word_Code &&
(attraux(text->aux) == attr_First ||
attraux(text->aux) == attr_Only))
- rdaddc(rs, '`'); /* FIXME: configurability */
+ rdadds(rs, cfg->lquote);
if (removeattr(text->type) == word_Normal) {
- if (text_convert(text->text, &c))
- rdaddsc(rs, c);
+ if (cvt_ok(cfg->charset, text->text) || !text->alt)
+ rdadds(rs, text->text);
else
- text_rdaddwc(rs, text->alt, NULL);
- sfree(c);
+ text_rdaddw(rs, text->alt, NULL, cfg);
} else if (removeattr(text->type) == word_WhiteSpace) {
- rdaddc(rs, ' ');
+ rdadd(rs, L' ');
} else if (removeattr(text->type) == word_Quote) {
- rdaddc(rs, quoteaux(text->aux) == quote_Open ? '`' : '\'');
- /* FIXME: configurability */
+ rdadds(rs, quoteaux(text->aux) == quote_Open ?
+ cfg->lquote : cfg->rquote);
}
if (towordstyle(text->type) == word_Emph &&
(attraux(text->aux) == attr_Last ||
attraux(text->aux) == attr_Only))
- rdaddc(rs, '_'); /* FIXME: configurability */
+ rdadds(rs, cfg->endemph);
else if (towordstyle(text->type) == word_Code &&
(attraux(text->aux) == attr_Last ||
attraux(text->aux) == attr_Only))
- rdaddc(rs, '\''); /* FIXME: configurability */
+ rdadds(rs, cfg->rquote);
break;
}
}
-static int text_width(word *);
+static int text_width(void *, word *);
-static int text_width_list(word *text) {
+static int text_width_list(void *ctx, word *text) {
int w = 0;
while (text) {
- w += text_width(text);
+ w += text_width(ctx, text);
text = text->next;
}
return w;
}
-static int text_width(word *text) {
+static int text_width(void *ctx, word *text) {
+ textconfig *cfg = (textconfig *)ctx;
+ int wid;
+ int attr;
+
switch (text->type) {
case word_HyperLink:
case word_HyperEnd:
case word_XrefEnd:
case word_IndexRef:
return 0;
+ }
+
+ assert(text->type < word_internal_endattrs);
+
+ wid = 0;
+ attr = towordstyle(text->type);
+ if (attr == word_Emph || attr == word_Code) {
+ if (attraux(text->aux) == attr_Only ||
+ attraux(text->aux) == attr_First)
+ wid += ustrwid(attr == word_Emph ? cfg->startemph : cfg->lquote,
+ cfg->charset);
+ }
+ if (attr == word_Emph || attr == word_Code) {
+ if (attraux(text->aux) == attr_Only ||
+ attraux(text->aux) == attr_Last)
+ wid += ustrwid(attr == word_Emph ? cfg->startemph : cfg->lquote,
+ cfg->charset);
+ }
+ switch (text->type) {
case word_Normal:
case word_Emph:
case word_Code:
case word_WeakCode:
- return (((text->type == word_Emph ||
- text->type == word_Code)
- ? (attraux(text->aux) == attr_Only ? 2 :
- attraux(text->aux) == attr_Always ? 0 : 1)
- : 0) +
- (text_convert(text->text, NULL) ?
- ustrlen(text->text) :
- text_width_list(text->alt)));
+ if (cvt_ok(cfg->charset, text->text) || !text->alt)
+ wid += ustrwid(text->text, cfg->charset);
+ else
+ wid += text_width_list(ctx, text->alt);
+ return wid;
case word_WhiteSpace:
case word_EmphSpace:
case word_WkCodeQuote:
assert(text->type != word_CodeQuote &&
text->type != word_WkCodeQuote);
- return (((towordstyle(text->type) == word_Emph ||
- towordstyle(text->type) == word_Code)
- ? (attraux(text->aux) == attr_Only ? 2 :
- attraux(text->aux) == attr_Always ? 0 : 1)
- : 0) + 1);
+ if (removeattr(text->type) == word_Quote) {
+ if (quoteaux(text->aux) == quote_Open)
+ wid += ustrwid(cfg->lquote, cfg->charset);
+ else
+ wid += ustrwid(cfg->rquote, cfg->charset);
+ } else
+ wid++; /* space */
}
- return 0; /* should never happen */
+
+ return wid;
}
-static void text_heading(FILE *fp, word *tprefix, word *nprefix, word *text,
- alignstruct align, int indent, int width) {
- rdstringc t = { 0, 0, NULL };
+static void text_heading(textfile *tf, word *tprefix, word *nprefix,
+ word *text, alignstruct align,
+ int indent, int width, textconfig *cfg) {
+ rdstring t = { 0, 0, NULL };
int margin, length;
int firstlinewidth, wrapwidth;
wrappedline *wrapping, *p;
- if (align.just_numbers && nprefix) {
- char *c;
- text_rdaddwc(&t, nprefix, NULL);
- if (text_convert(align.number_suffix, &c)) {
- rdaddsc(&t, c);
- sfree(c);
- }
- } else if (!align.just_numbers && tprefix) {
- char *c;
- text_rdaddwc(&t, tprefix, NULL);
- if (text_convert(align.number_suffix, &c)) {
- rdaddsc(&t, c);
- sfree(c);
+ if (align.number_at_all) {
+ if (align.just_numbers && nprefix) {
+ text_rdaddw(&t, nprefix, NULL, cfg);
+ rdadds(&t, align.number_suffix);
+ } else if (!align.just_numbers && tprefix) {
+ text_rdaddw(&t, tprefix, NULL, cfg);
+ rdadds(&t, align.number_suffix);
}
}
- margin = length = (t.text ? strlen(t.text) : 0);
+ margin = length = ustrwid(t.text ? t.text : L"", cfg->charset);
if (align.align == LEFTPLUS) {
margin = indent - margin;
wrapwidth = indent + width;
}
- wrapping = wrap_para(text, firstlinewidth, wrapwidth, text_width);
+ wrapping = wrap_para(text, firstlinewidth, wrapwidth,
+ text_width, cfg, 0);
for (p = wrapping; p; p = p->next) {
- text_rdaddwc(&t, p->begin, p->end);
- length = (t.text ? strlen(t.text) : 0);
+ text_rdaddw(&t, p->begin, p->end, cfg);
+ length = ustrwid(t.text ? t.text : L"", cfg->charset);
if (align.align == CENTRE) {
margin = (indent + width - length)/2;
if (margin < 0) margin = 0;
}
- fprintf(fp, "%*s%s\n", margin, "", t.text);
- if (align.underline != L'\0') {
- char *u, uc;
- wchar_t uw[2];
- uw[0] = align.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);
+ text_output_many(tf, margin, L' ');
+ text_output(tf, t.text);
+ text_output(tf, L"\n");
+ if (*align.underline) {
+ text_output_many(tf, margin, L' ');
+ while (length > 0) {
+ text_output(tf, align.underline);
+ length -= ustrwid(align.underline, cfg->charset);
+ }
+ text_output(tf, L"\n");
}
if (align.align == LEFTPLUS)
margin = indent;
else
margin = 0;
sfree(t.text);
- t = empty_rdstringc;
+ t = empty_rdstring;
}
wrap_free(wrapping);
- putc('\n', fp);
+ text_output(tf, L"\n");
sfree(t.text);
}
-static void text_rule(FILE *fp, int indent, int width) {
- while (indent--) putc(' ', fp);
- while (width--) putc('-', fp); /* FIXME: configurability! */
- putc('\n', fp);
- putc('\n', fp);
+static void text_rule(textfile *tf, int indent, int width, textconfig *cfg) {
+ text_output_many(tf, indent, L' ');
+ while (width > 0) {
+ text_output(tf, cfg->rule);
+ width -= ustrwid(cfg->rule, cfg->charset);
+ }
+ text_output_many(tf, 2, L'\n');
}
-static void text_para(FILE *fp, word *prefix, char *prefixextra, word *text,
- int indent, int extraindent, int width) {
+static void text_para(textfile *tf, word *prefix, wchar_t *prefixextra,
+ word *text, int indent, int extraindent, int width,
+ textconfig *cfg) {
wrappedline *wrapping, *p;
- rdstringc pfx = { 0, 0, NULL };
+ rdstring pfx = { 0, 0, NULL };
int e;
int firstlinewidth = width;
if (prefix) {
- text_rdaddwc(&pfx, prefix, NULL);
+ text_rdaddw(&pfx, prefix, NULL, cfg);
if (prefixextra)
- rdaddsc(&pfx, prefixextra);
- fprintf(fp, "%*s%s", indent, "", pfx.text);
+ rdadds(&pfx, prefixextra);
+ text_output_many(tf, indent, L' ');
+ text_output(tf, pfx.text);
/* If the prefix is too long, shorten the first line to fit. */
- e = extraindent - strlen(pfx.text);
+ e = extraindent - ustrwid(pfx.text ? pfx.text : L"", cfg->charset);
if (e < 0) {
firstlinewidth += e; /* this decreases it, since e < 0 */
if (firstlinewidth < 0) {
e = indent + extraindent;
firstlinewidth = width;
- fprintf(fp, "\n");
+ text_output(tf, L"\n");
} else
e = 0;
}
} else
e = indent + extraindent;
- wrapping = wrap_para(text, firstlinewidth, width, text_width);
+ wrapping = wrap_para(text, firstlinewidth, width,
+ text_width, cfg, 0);
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);
+ rdstring t = { 0, 0, NULL };
+ text_rdaddw(&t, p->begin, p->end, cfg);
+ text_output_many(tf, e, L' ');
+ text_output(tf, t.text);
+ text_output(tf, L"\n");
e = indent + extraindent;
sfree(t.text);
}
wrap_free(wrapping);
- putc('\n', fp);
+ text_output(tf, L"\n");
}
-static void text_codepara(FILE *fp, word *text, int indent, int width) {
+static void text_codepara(textfile *tf, 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);
+ int wid = ustrwid(text->text, tf->charset);
+ if (wid > width)
+ error(err_text_codeline, &text->fpos, wid, width);
+ text_output_many(tf, indent, L' ');
+ text_output(tf, text->text);
+ text_output(tf, L"\n");
}
- putc('\n', fp);
+ text_output(tf, L"\n");
}
-static void text_versionid(FILE *fp, word *text) {
- rdstringc t = { 0, 0, NULL };
+static void text_versionid(textfile *tf, word *text, textconfig *cfg) {
+ rdstring t = { 0, 0, NULL };
- rdaddc(&t, '['); /* FIXME: configurability */
- text_rdaddwc(&t, text, NULL);
- rdaddc(&t, ']'); /* FIXME: configurability */
+ rdadd(&t, L'[');
+ text_rdaddw(&t, text, NULL, cfg);
+ rdadd(&t, L']');
+ rdadd(&t, L'\n');
- fprintf(fp, "%s\n", t.text);
+ text_output(tf, t.text);
sfree(t.text);
}