/*
* Windows Help backend for Halibut
- *
- * TODO:
- * - allow user to specify section contexts.
*/
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <assert.h>
#include "halibut.h"
indexdata *idx;
keywordlist *keywords;
WHLP_TOPIC curr_topic;
+ int charset;
+ charset_state cstate;
FILE *cntfp;
int cnt_last_level, cnt_workaround;
};
+typedef struct {
+ int charset;
+ wchar_t *bullet, *lquote, *rquote, *titlepage, *sectsuffix, *listsuffix;
+ char *filename;
+} whlpconf;
+
/*
* Indexes of fonts in our standard font descriptor set.
*/
FONT_RULE
};
-static void whlp_rdaddwc(rdstringc *rs, word *text);
-static int whlp_convert(wchar_t *s, int maxlen,
- char **result, int hard_spaces);
+static void whlp_rdaddwc(rdstringc *rs, word *text, whlpconf *conf,
+ charset_state *state);
+static void whlp_rdadds(rdstringc *rs, const wchar_t *text, whlpconf *conf,
+ charset_state *state);
static void whlp_mkparagraph(struct bk_whlp_state *state,
- int font, word *text, int subsidiary);
-static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p);
+ int font, word *text, int subsidiary,
+ whlpconf *conf);
+static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p,
+ whlpconf *conf);
static void whlp_contents_write(struct bk_whlp_state *state,
int level, char *text, WHLP_TOPIC topic);
+static void whlp_wtext(struct bk_whlp_state *state, const wchar_t *text);
+paragraph *whlp_config_filename(char *filename)
+{
+ return cmdline_cfg_simple("winhelp-filename", filename, NULL);
+}
+
+static whlpconf whlp_configure(paragraph *source) {
+ paragraph *p;
+ whlpconf ret;
+
+ /*
+ * Defaults.
+ */
+ ret.charset = CS_CP1252;
+ ret.bullet = L"\x2022\0-\0\0";
+ ret.lquote = L"\x2018\0\x2019\0\"\0\"\0\0";
+ ret.rquote = uadv(ret.lquote);
+ ret.filename = dupstr("output.hlp");
+ ret.titlepage = L"Title page";
+ ret.sectsuffix = L": ";
+ ret.listsuffix = L".";
+
+ /*
+ * Two-pass configuration so that we can pick up global config
+ * (e.g. `quotes') before having it overridden by specific
+ * config (`win-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) {
+ p->private_data = NULL;
+ if (p->type == para_Config) {
+ /*
+ * In principle we should support a `winhelp-charset'
+ * here. We don't, because my WinHelp output code
+ * doesn't know how to change character set. Once I
+ * find out, I'll support it.
+ */
+ if (p->parent && !ustricmp(p->keyword, L"winhelp-topic")) {
+ /* Store the topic name in the private_data field of the
+ * containing section. */
+ p->parent->private_data = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"winhelp-filename")) {
+ sfree(ret.filename);
+ ret.filename = dupstr(adv(p->origkeyword));
+ } else if (!ustricmp(p->keyword, L"winhelp-bullet")) {
+ ret.bullet = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"winhelp-section-suffix")) {
+ ret.sectsuffix = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"winhelp-list-suffix")) {
+ ret.listsuffix = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"winhelp-contents-titlepage")) {
+ ret.titlepage = uadv(p->keyword);
+ } else if (!ustricmp(p->keyword, L"winhelp-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 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 (*ret.bullet && *uadv(ret.bullet) &&
+ !cvt_ok(ret.charset, ret.bullet))
+ ret.bullet = uadv(ret.bullet);
+
+ return ret;
+}
+
void whlp_backend(paragraph *sourceform, keywordlist *keywords,
- indexdata *idx) {
+ indexdata *idx, void *unused) {
WHLP h;
- char *filename, *cntname;
+ char *cntname;
paragraph *p, *lastsect;
struct bk_whlp_state state;
WHLP_TOPIC contents_topic;
int i;
int nesting;
indexentry *ie;
+ int done_contents_topic = FALSE;
+ whlpconf conf;
- filename = "output.hlp"; /* FIXME: configurability */
- cntname = "output.cnt"; /* corresponding contents file */
-
- state.cntfp = fopen(cntname, "wb");
- state.cnt_last_level = -1; state.cnt_workaround = 0;
+ IGNORE(unused);
h = state.h = whlp_new();
state.keywords = keywords;
whlp_create_font(h, "Courier New", WHLP_FONTFAM_SANS, 18,
WHLP_FONT_STRIKEOUT, 0, 0, 0);
+ conf = whlp_configure(sourceform);
+
+ state.charset = conf.charset;
+
/*
- * Loop over the source form finding out whether the user has
- * specified particular help topic names for anything.
+ * Ensure the output file name has a .hlp extension. This is
+ * required since we must create the .cnt file in parallel with
+ * it.
*/
- for (p = sourceform; p; p = p->next) {
- p->private_data = NULL;
- if (p->type == para_Config && p->parent) {
- if (!ustricmp(p->keyword, L"winhelp-topic")) {
- char *topicname;
- whlp_convert(uadv(p->keyword), 0, &topicname, 0);
- /* Store the topic name in the private_data field of the
- * containing section. */
- p->parent->private_data = topicname;
- }
+ {
+ int len = strlen(conf.filename);
+ if (len < 4 || conf.filename[len-4] != '.' ||
+ tolower(conf.filename[len-3] != 'h') ||
+ tolower(conf.filename[len-2] != 'l') ||
+ tolower(conf.filename[len-1] != 'p')) {
+ char *newf;
+ newf = snewn(len + 5, char);
+ sprintf(newf, "%s.hlp", conf.filename);
+ sfree(conf.filename);
+ conf.filename = newf;
+ len = strlen(newf);
}
+ cntname = snewn(len+1, char);
+ sprintf(cntname, "%.*s.cnt", len-4, conf.filename);
}
+ state.cntfp = fopen(cntname, "wb");
+ state.cnt_last_level = -1; state.cnt_workaround = 0;
+
/*
* Loop over the source form registering WHLP_TOPICs for
* everything.
p->type == para_UnnumberedChapter ||
p->type == para_Heading ||
p->type == para_Subsect) {
- char *topicid = p->private_data;
+
+ rdstringc rs = { 0, 0, NULL };
char *errstr;
- p->private_data = whlp_register_topic(h, topicid, &errstr);
+ whlp_rdadds(&rs, (wchar_t *)p->private_data, &conf, NULL);
+
+ p->private_data = whlp_register_topic(h, rs.text, &errstr);
if (!p->private_data) {
p->private_data = whlp_register_topic(h, NULL, NULL);
- error(err_winhelp_ctxclash, &p->fpos, topicid, errstr);
+ error(err_winhelp_ctxclash, &p->fpos, rs.text, errstr);
}
- sfree(topicid);
+ sfree(rs.text);
}
}
* Loop over the index entries, preparing final text forms for
* each one.
*/
- for (i = 0; (ie = index234(idx->entries, i)) != NULL; i++) {
- rdstringc rs = {0, 0, NULL};
- whlp_rdaddwc(&rs, ie->text);
- ie->backend_data = rs.text;
+ {
+ indexentry *ie_prev = NULL;
+ int nspaces = 1;
+
+ for (i = 0; (ie = index234(idx->entries, i)) != NULL; i++) {
+ rdstringc rs = {0, 0, NULL};
+ charset_state state = CHARSET_INIT_STATE;
+ whlp_rdaddwc(&rs, ie->text, &conf, &state);
+
+ if (ie_prev) {
+ /*
+ * It appears that Windows Help's index mechanism
+ * is inherently case-insensitive. Therefore, if two
+ * adjacent index terms compare equal apart from
+ * case, I'm going to append nonbreaking spaces to
+ * the end of the second one so that Windows will
+ * treat them as distinct.
+ *
+ * This is nasty because we're depending on our
+ * case-insensitive comparison having the same
+ * semantics as the Windows one :-/ but I see no
+ * alternative.
+ */
+ wchar_t *a, *b;
+
+ a = ufroma_dup((char *)ie_prev->backend_data, conf.charset);
+ b = ufroma_dup(rs.text, conf.charset);
+ if (!ustricmp(a, b)) {
+ int j;
+ for (j = 0; j < nspaces; j++)
+ whlp_rdadds(&rs, L"\xA0", &conf, &state);
+ /*
+ * Add one to nspaces, so that if another term
+ * appears which is equivalent to the previous
+ * two it'll acquire one more space.
+ */
+ nspaces++;
+ } else
+ nspaces = 1;
+ sfree(a);
+ sfree(b);
+ }
+
+ whlp_rdadds(&rs, NULL, &conf, &state);
+
+ ie->backend_data = rs.text;
+
+ /*
+ * Only move ie_prev on if nspaces==1 (since when we
+ * have three or more adjacent terms differing only in
+ * case, we will want to compare with the _first_ of
+ * them because that won't have had any extra spaces
+ * added on which will foul up the comparison).
+ */
+ if (nspaces == 1)
+ ie_prev = ie;
+ }
}
whlp_prepare(h);
/* ------------------------------------------------------------------
- * Do the contents page, containing title, preamble and
- * copyright.
+ * Begin the contents page.
*/
whlp_begin_topic(h, contents_topic, "Contents", "DB(\"btn_up\")", NULL);
+ state.curr_topic = contents_topic;
/*
* The manual title goes in the non-scroll region, and also
for (p = sourceform; p; p = p->next) {
if (p->type == para_Title) {
whlp_begin_para(h, WHLP_PARA_NONSCROLL);
- whlp_mkparagraph(&state, FONT_TITLE, p->words, FALSE);
- whlp_rdaddwc(&rs, p->words);
+ state.cstate = charset_init_state;
+ whlp_mkparagraph(&state, FONT_TITLE, p->words, FALSE, &conf);
+ whlp_wtext(&state, NULL);
whlp_end_para(h);
+ whlp_rdaddwc(&rs, p->words, &conf, NULL);
}
}
if (rs.text) {
fprintf(state.cntfp, ":Title %s\r\n", rs.text);
sfree(rs.text);
}
- whlp_contents_write(&state, 1, "Title page", contents_topic);
- /* FIXME: configurability in that string */
- }
-
- /*
- * Next comes the preamble, which just goes into the ordinary
- * scrolling region.
- */
- for (p = sourceform; p; p = p->next) {
- if (p->type == para_Preamble) {
- whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
- whlp_begin_para(h, WHLP_PARA_SCROLL);
- whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE);
- whlp_end_para(h);
+ {
+ rdstringc rs2 = {0,0,NULL};
+ whlp_rdadds(&rs2, conf.titlepage, &conf, NULL);
+ whlp_contents_write(&state, 1, rs2.text, contents_topic);
+ sfree(rs2.text);
}
}
/*
- * The copyright goes to two places, again: into the contents
- * page and also into the system section.
+ * Put the copyright into the system section.
*/
{
rdstringc rs = {0, 0, NULL};
for (p = sourceform; p; p = p->next) {
- if (p->type == para_Copyright) {
- whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
- whlp_begin_para(h, WHLP_PARA_SCROLL);
- whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE);
- whlp_end_para(h);
- whlp_rdaddwc(&rs, p->words);
- }
+ if (p->type == para_Copyright)
+ whlp_rdaddwc(&rs, p->words, &conf, NULL);
}
if (rs.text) {
whlp_copyright(h, rs.text);
}
}
- /*
- * Now do the primary navigation menu.
- */
- for (p = sourceform; p; p = p->next) {
- if (p->type == para_Chapter ||
- p->type == para_Appendix ||
- p->type == para_UnnumberedChapter)
- whlp_navmenu(&state, p);
- }
-
- state.curr_topic = contents_topic;
lastsect = NULL;
/* ------------------------------------------------------------------
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_LcontPush:
+ case para_QuotePush:
nesting++;
break;
case para_LcontPop:
+ case para_QuotePop:
assert(nesting > 0);
nesting--;
break;
case para_UnnumberedChapter:
case para_Heading:
case para_Subsect:
+
+ if (!done_contents_topic) {
+ paragraph *p;
+
+ /*
+ * If this is the first section title we've seen, then
+ * we're currently still in the contents topic. We
+ * should therefore finish up the contents page by
+ * writing a nav menu.
+ */
+ for (p = sourceform; p; p = p->next) {
+ if (p->type == para_Chapter ||
+ p->type == para_Appendix ||
+ p->type == para_UnnumberedChapter)
+ whlp_navmenu(&state, p, &conf);
+ }
+
+ done_contents_topic = TRUE;
+ }
+
if (lastsect && lastsect->child) {
paragraph *q;
/*
* were in.
*/
for (q = lastsect->child; q; q = q->sibling)
- whlp_navmenu(&state, q);
+ whlp_navmenu(&state, q, &conf);
}
{
rdstringc rs = {0, 0, NULL};
WHLP_TOPIC new_topic, parent_topic;
char *macro, *topicid;
+ charset_state cstate = CHARSET_INIT_STATE;
new_topic = p->private_data;
whlp_browse_link(h, state.curr_topic, new_topic);
state.curr_topic = new_topic;
if (p->kwtext) {
- whlp_rdaddwc(&rs, p->kwtext);
- rdaddsc(&rs, ": "); /* FIXME: configurability */
+ whlp_rdaddwc(&rs, p->kwtext, &conf, &cstate);
+ whlp_rdadds(&rs, conf.sectsuffix, &conf, &cstate);
}
- whlp_rdaddwc(&rs, p->words);
+ whlp_rdaddwc(&rs, p->words, &conf, &cstate);
+ whlp_rdadds(&rs, NULL, &conf, &cstate);
+
if (p->parent == NULL)
parent_topic = contents_topic;
else
sfree(rs.text);
whlp_begin_para(h, WHLP_PARA_NONSCROLL);
+ state.cstate = charset_init_state;
if (p->kwtext) {
- whlp_mkparagraph(&state, FONT_TITLE, p->kwtext, FALSE);
+ whlp_mkparagraph(&state, FONT_TITLE, p->kwtext, FALSE, &conf);
whlp_set_font(h, FONT_TITLE);
- whlp_text(h, ": "); /* FIXME: configurability */
+ whlp_wtext(&state, conf.sectsuffix);
}
- whlp_mkparagraph(&state, FONT_TITLE, p->words, FALSE);
+ whlp_mkparagraph(&state, FONT_TITLE, p->words, FALSE, &conf);
+ whlp_wtext(&state, NULL);
whlp_end_para(h);
lastsect = p;
whlp_para_attr(h, WHLP_PARA_ALIGNMENT, WHLP_ALIGN_CENTRE);
whlp_begin_para(h, WHLP_PARA_SCROLL);
whlp_set_font(h, FONT_RULE);
-#define TEN "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0"
+ state.cstate = charset_init_state;
+#define TEN L"\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0"
#define TWENTY TEN TEN
#define FORTY TWENTY TWENTY
#define EIGHTY FORTY FORTY
- whlp_text(h, EIGHTY);
+ state.cstate = charset_init_state;
+ whlp_wtext(&state, EIGHTY);
+ whlp_wtext(&state, NULL);
#undef TEN
#undef TWENTY
#undef FORTY
break;
case para_Normal:
+ case para_Copyright:
case para_DescribedThing:
case para_Description:
case para_BiblioCited:
whlp_set_tabstop(h, 72, WHLP_ALIGN_LEFT);
whlp_begin_para(h, WHLP_PARA_SCROLL);
whlp_set_font(h, FONT_NORMAL);
+ state.cstate = charset_init_state;
if (p->type == para_Bullet) {
- whlp_text(h, "\x95");
+ whlp_wtext(&state, conf.bullet);
} else {
- whlp_mkparagraph(&state, FONT_NORMAL, p->kwtext, FALSE);
- whlp_text(h, ".");
+ whlp_mkparagraph(&state, FONT_NORMAL, p->kwtext, FALSE, &conf);
+ whlp_wtext(&state, conf.listsuffix);
}
+ whlp_wtext(&state, NULL);
whlp_tab(h);
} else {
whlp_para_attr(h, WHLP_PARA_LEFTINDENT,
whlp_begin_para(h, WHLP_PARA_SCROLL);
}
+ state.cstate = charset_init_state;
+
if (p->type == para_BiblioCited) {
- whlp_mkparagraph(&state, FONT_NORMAL, p->kwtext, FALSE);
- whlp_text(h, " ");
+ whlp_mkparagraph(&state, FONT_NORMAL, p->kwtext, FALSE, &conf);
+ whlp_wtext(&state, L" ");
}
- whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE);
+ whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE, &conf);
+ whlp_wtext(&state, NULL);
whlp_end_para(h);
break;
*/
{
word *w;
- wchar_t *t, *e;
- char *c;
+ wchar_t *t, *e, *tmp;
for (w = p->words; w; w = w->next) if (w->type == word_WeakCode) {
t = w->text;
whlp_para_attr(h, WHLP_PARA_LEFTINDENT, 72*nesting);
whlp_begin_para(h, WHLP_PARA_SCROLL);
+ state.cstate = charset_init_state;
while (e && *e && *t) {
int n;
int ec = *e;
whlp_set_font(h, FONT_BOLD_CODE);
else
whlp_set_font(h, FONT_CODE);
- whlp_convert(t, n, &c, FALSE);
- whlp_text(h, c);
- sfree(c);
+ tmp = snewn(n+1, wchar_t);
+ ustrncpy(tmp, t, n);
+ tmp[n] = L'\0';
+ whlp_wtext(&state, tmp);
+ whlp_wtext(&state, NULL);
+ state.cstate = charset_init_state;
+ sfree(tmp);
t += n;
e += n;
}
whlp_set_font(h, FONT_CODE);
- whlp_convert(t, 0, &c, FALSE);
- whlp_text(h, c);
- sfree(c);
+ whlp_wtext(&state, t);
+ whlp_wtext(&state, NULL);
whlp_end_para(h);
}
}
}
fclose(state.cntfp);
- whlp_close(h, filename);
+ whlp_close(h, conf.filename);
/*
* Loop over the index entries, cleaning up our final text
for (i = 0; (ie = index234(idx->entries, i)) != NULL; i++) {
sfree(ie->backend_data);
}
+
+ sfree(conf.filename);
+ sfree(cntname);
}
static void whlp_contents_write(struct bk_whlp_state *state,
fputc('\n', state->cntfp);
}
-static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p) {
- whlp_begin_para(state->h, WHLP_PARA_NONSCROLL);
+static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p,
+ whlpconf *conf) {
+ whlp_begin_para(state->h, WHLP_PARA_SCROLL);
whlp_start_hyperlink(state->h, (WHLP_TOPIC)p->private_data);
+ state->cstate = charset_init_state;
if (p->kwtext) {
- whlp_mkparagraph(state, FONT_NORMAL, p->kwtext, TRUE);
+ whlp_mkparagraph(state, FONT_NORMAL, p->kwtext, TRUE, conf);
whlp_set_font(state->h, FONT_NORMAL);
- whlp_text(state->h, ": "); /* FIXME: configurability */
+ whlp_wtext(state, conf->sectsuffix);
}
- whlp_mkparagraph(state, FONT_NORMAL, p->words, TRUE);
+ whlp_mkparagraph(state, FONT_NORMAL, p->words, TRUE, conf);
+ whlp_wtext(state, NULL);
whlp_end_hyperlink(state->h);
whlp_end_para(state->h);
}
static void whlp_mkparagraph(struct bk_whlp_state *state,
- int font, word *text, int subsidiary) {
+ int font, word *text, int subsidiary,
+ whlpconf *conf) {
keyword *kwl;
int deffont = font;
int currfont = -1;
int newfont;
- char *c;
paragraph *xref_target = NULL;
for (; text; text = text->next) switch (text->type) {
whlp_set_font(state->h, newfont);
}
if (removeattr(text->type) == word_Normal) {
- if (whlp_convert(text->text, 0, &c, TRUE))
- whlp_text(state->h, c);
+ if (cvt_ok(conf->charset, text->text) || !text->alt)
+ whlp_wtext(state, text->text);
else
- whlp_mkparagraph(state, deffont, text->alt, FALSE);
- sfree(c);
+ whlp_mkparagraph(state, deffont, text->alt, FALSE, conf);
} else if (removeattr(text->type) == word_WhiteSpace) {
- whlp_text(state->h, " ");
+ whlp_wtext(state, L" ");
} else if (removeattr(text->type) == word_Quote) {
- whlp_text(state->h,
- quoteaux(text->aux) == quote_Open ? "\x91" : "\x92");
- /* FIXME: configurability */
+ whlp_wtext(state,
+ quoteaux(text->aux) == quote_Open ?
+ conf->lquote : conf->rquote);
}
break;
}
}
-static void whlp_rdaddwc(rdstringc *rs, word *text) {
- char *c;
+static void whlp_rdaddwc(rdstringc *rs, word *text, whlpconf *conf,
+ charset_state *state) {
+ charset_state ourstate = CHARSET_INIT_STATE;
+
+ if (!state)
+ state = &ourstate;
for (; text; text = text->next) switch (text->type) {
case word_HyperLink:
assert(text->type != word_CodeQuote &&
text->type != word_WkCodeQuote);
if (removeattr(text->type) == word_Normal) {
- if (whlp_convert(text->text, 0, &c, FALSE))
- rdaddsc(rs, c);
+ if (cvt_ok(conf->charset, text->text) || !text->alt)
+ whlp_rdadds(rs, text->text, conf, state);
else
- whlp_rdaddwc(rs, text->alt);
- sfree(c);
+ whlp_rdaddwc(rs, text->alt, conf, state);
} else if (removeattr(text->type) == word_WhiteSpace) {
- rdaddc(rs, ' ');
+ whlp_rdadds(rs, L" ", conf, state);
} else if (removeattr(text->type) == word_Quote) {
- rdaddc(rs, quoteaux(text->aux) == quote_Open ? '\x91' : '\x92');
- /* FIXME: configurability */
+ whlp_rdadds(rs, quoteaux(text->aux) == quote_Open ?
+ conf->lquote : conf->rquote, conf, state);
}
break;
}
+
+ if (state == &ourstate)
+ whlp_rdadds(rs, NULL, conf, state);
}
-/*
- * 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 whlp_convert(wchar_t *s, int maxlen,
- char **result, int hard_spaces) {
- /*
- * FIXME. Currently this is ISO8859-1 only.
- */
- int doing = (result != 0);
- int ok = TRUE;
- char *p = NULL;
- int plen = 0, psize = 0;
-
- if (maxlen <= 0)
- maxlen = -1;
-
- for (; *s && maxlen != 0; s++, maxlen--) {
- wchar_t c = *s;
- char outc;
-
- if ((c >= 32 && c <= 126) ||
- (c >= 160 && c <= 255)) {
- /* Char is OK. */
- if (c == 32 && hard_spaces)
- outc = '\240';
- else
- 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 whlp_rdadds(rdstringc *rs, const wchar_t *text, whlpconf *conf,
+ charset_state *state)
+{
+ charset_state ourstate = CHARSET_INIT_STATE;
+ int textlen = text ? ustrlen(text) : 0;
+ char outbuf[256];
+ int ret;
+
+ if (!state)
+ state = &ourstate;
+
+ while (textlen > 0 &&
+ (ret = charset_from_unicode(&text, &textlen, outbuf,
+ lenof(outbuf)-1,
+ conf->charset, state, NULL)) > 0) {
+ outbuf[ret] = '\0';
+ rdaddsc(rs, outbuf);
+ }
+
+ if (text == NULL || state == &ourstate) {
+ if ((ret = charset_from_unicode(NULL, 0, outbuf, lenof(outbuf)-1,
+ conf->charset, state, NULL)) > 0) {
+ outbuf[ret] = '\0';
+ rdaddsc(rs, outbuf);
}
}
- if (doing) {
- p = resize(p, plen+1);
- p[plen] = '\0';
- *result = p;
+}
+
+static void whlp_wtext(struct bk_whlp_state *state, const wchar_t *text)
+{
+ int textlen = text ? ustrlen(text) : 0;
+ char outbuf[256];
+ int ret;
+
+ while (textlen > 0 &&
+ (ret = charset_from_unicode(&text, &textlen, outbuf,
+ lenof(outbuf)-1,
+ state->charset, &state->cstate,
+ NULL)) > 0) {
+ outbuf[ret] = '\0';
+ whlp_text(state->h, outbuf);
+ }
+
+ if (text == NULL) {
+ if ((ret = charset_from_unicode(NULL, 0, outbuf, lenof(outbuf)-1,
+ state->charset, &state->cstate,
+ NULL)) > 0) {
+ outbuf[ret] = '\0';
+ whlp_text(state->h, outbuf);
+ }
}
- return ok;
}