X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/halibut/blobdiff_plain/2614b01da5f5c65d7a80aeef0f65d41fb554fedf..3e030063e831da0af7bdb8d12f2f25a5224ba0be:/bk_whlp.c diff --git a/bk_whlp.c b/bk_whlp.c index 91b07c1..d11fd22 100644 --- a/bk_whlp.c +++ b/bk_whlp.c @@ -1,12 +1,10 @@ /* * Windows Help backend for Halibut - * - * TODO: - * - allow user to specify section contexts. */ #include #include +#include #include #include "halibut.h" @@ -45,8 +43,13 @@ static void whlp_navmenu(struct bk_whlp_state *state, paragraph *p); static void whlp_contents_write(struct bk_whlp_state *state, int level, char *text, WHLP_TOPIC topic); +paragraph *whlp_config_filename(char *filename) +{ + return cmdline_cfg_simple("winhelp-filename", filename, NULL); +} + void whlp_backend(paragraph *sourceform, keywordlist *keywords, - indexdata *idx) { + indexdata *idx, void *unused) { WHLP h; char *filename, *cntname; paragraph *p, *lastsect; @@ -55,12 +58,9 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, int i; int nesting; indexentry *ie; + int done_contents_topic = FALSE; - 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; @@ -91,8 +91,10 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, /* * Loop over the source form finding out whether the user has - * specified particular help topic names for anything. + * specified particular help topic names for anything. Also + * pick out the output file name at this stage. */ + filename = dupstr("output.hlp"); for (p = sourceform; p; p = p->next) { p->private_data = NULL; if (p->type == para_Config && p->parent) { @@ -102,11 +104,39 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, /* Store the topic name in the private_data field of the * containing section. */ p->parent->private_data = topicname; + } else if (!ustricmp(p->keyword, L"winhelp-filename")) { + sfree(filename); + filename = dupstr(adv(p->origkeyword)); } } } /* + * Ensure the output file name has a .hlp extension. This is + * required since we must create the .cnt file in parallel with + * it. + */ + { + int len = strlen(filename); + if (len < 4 || filename[len-4] != '.' || + tolower(filename[len-3] != 'h') || + tolower(filename[len-2] != 'l') || + tolower(filename[len-1] != 'p')) { + char *newf; + newf = mknewa(char, len + 5); + sprintf(newf, "%s.hlp", filename); + sfree(filename); + filename = newf; + len = strlen(newf); + } + cntname = mknewa(char, len+1); + sprintf(cntname, "%.*s.cnt", len-4, 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. */ @@ -144,8 +174,7 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, 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); @@ -174,32 +203,13 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, } /* - * 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); - } - } - - /* - * 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); + if (p->type == para_Copyright) whlp_rdaddwc(&rs, p->words); - } } if (rs.text) { whlp_copyright(h, rs.text); @@ -207,17 +217,6 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, } } - /* - * 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; /* ------------------------------------------------------------------ @@ -234,8 +233,6 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, 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; @@ -258,6 +255,28 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, 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); + } + + state.curr_topic = contents_topic; + + done_contents_topic = TRUE; + } + if (lastsect && lastsect->child) { paragraph *q; /* @@ -362,6 +381,7 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, break; case para_Normal: + case para_Copyright: case para_DescribedThing: case para_Description: case para_BiblioCited: @@ -458,6 +478,9 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, for (i = 0; (ie = index234(idx->entries, i)) != NULL; i++) { sfree(ie->backend_data); } + + sfree(filename); + sfree(cntname); } static void whlp_contents_write(struct bk_whlp_state *state, @@ -582,7 +605,7 @@ static void whlp_mkparagraph(struct bk_whlp_state *state, whlp_set_font(state->h, newfont); } if (removeattr(text->type) == word_Normal) { - if (whlp_convert(text->text, 0, &c, TRUE)) + if (whlp_convert(text->text, 0, &c, TRUE) || !text->alt) whlp_text(state->h, c); else whlp_mkparagraph(state, deffont, text->alt, FALSE); @@ -625,7 +648,7 @@ static void whlp_rdaddwc(rdstringc *rs, word *text) { assert(text->type != word_CodeQuote && text->type != word_WkCodeQuote); if (removeattr(text->type) == word_Normal) { - if (whlp_convert(text->text, 0, &c, FALSE)) + if (whlp_convert(text->text, 0, &c, FALSE) || !text->alt) rdaddsc(rs, c); else whlp_rdaddwc(rs, text->alt); @@ -653,45 +676,49 @@ static void whlp_rdaddwc(rdstringc *rs, word *text) { */ static int whlp_convert(wchar_t *s, int maxlen, char **result, int hard_spaces) { + wchar_t *s2; + char *ret; + int ok; + /* - * FIXME. Currently this is ISO8859-1 only. + * Enforce maxlen. */ - 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; - } - } - if (doing) { - p = resize(p, plen+1); - p[plen] = '\0'; - *result = p; + if (maxlen > 0 && ustrlen(s) > maxlen) { + s2 = mknewa(wchar_t, maxlen+1); + memcpy(s2, s, maxlen * sizeof(wchar_t)); + s2[maxlen] = L'\0'; + s = s2; + } else + s2 = NULL; + + /* + * We currently only support Win1252 in Windows Help files, + * because I don't know how to fiddle the character set + * designation in the |SYSTEM file to indicate anything else. + */ + + ret = utoa_careful_dup(s, CS_CP1252); + if (!ret) { + ok = FALSE; + ret = utoa_dup(s, CS_CP1252); + } else + ok = TRUE; + + /* + * Enforce hard_spaces. + */ + if (hard_spaces) { + char *p; + + for (p = ret; *p; p++) + if (*p == ' ') + *p = '\240'; } + + if (s2) + sfree(s2); + + *result = ret; + return ok; }