Logo Search packages:      
Sourcecode: halibut version File versions

bk_whlp.c

/*
 * Windows Help backend for Halibut
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>

#include "halibut.h"
#include "winhelp.h"

struct bk_whlp_state {
    WHLP 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.
 */
enum {
    FONT_NORMAL,
    FONT_EMPH,
    FONT_CODE,
    FONT_ITAL_CODE,
    FONT_BOLD_CODE,
    FONT_TITLE,
    FONT_TITLE_EMPH,
    FONT_TITLE_CODE,
    FONT_RULE
};

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,
                       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, void *unused) {
    WHLP h;
    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;

    IGNORE(unused);

    h = state.h = whlp_new();
    state.keywords = keywords;
    state.idx = idx;

    whlp_start_macro(h, "CB(\"btn_about\",\"&About\",\"About()\")");
    whlp_start_macro(h, "CB(\"btn_up\",\"&Up\",\"Contents()\")");
    whlp_start_macro(h, "BrowseButtons()");

    whlp_create_font(h, "Times New Roman", WHLP_FONTFAM_SERIF, 24,
                 0, 0, 0, 0);
    whlp_create_font(h, "Times New Roman", WHLP_FONTFAM_SERIF, 24,
                 WHLP_FONT_ITALIC, 0, 0, 0);
    whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24,
                 0, 0, 0, 0);
    whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24,
                 WHLP_FONT_ITALIC, 0, 0, 0);
    whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 24,
                 WHLP_FONT_BOLD, 0, 0, 0);
    whlp_create_font(h, "Arial", WHLP_FONTFAM_SERIF, 30,
                 WHLP_FONT_BOLD, 0, 0, 0);
    whlp_create_font(h, "Arial", WHLP_FONTFAM_SERIF, 30,
                 WHLP_FONT_BOLD|WHLP_FONT_ITALIC, 0, 0, 0);
    whlp_create_font(h, "Courier New", WHLP_FONTFAM_FIXED, 30,
                 WHLP_FONT_BOLD, 0, 0, 0);
    whlp_create_font(h, "Courier New", WHLP_FONTFAM_SANS, 18,
                 WHLP_FONT_STRIKEOUT, 0, 0, 0);

    conf = whlp_configure(sourceform);

    state.charset = conf.charset;

    /*
     * 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(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.
     */

    contents_topic = whlp_register_topic(h, "Top", NULL);
    whlp_primary_topic(h, contents_topic);
    for (p = sourceform; p; p = p->next) {
      if (p->type == para_Chapter ||
          p->type == para_Appendix ||
          p->type == para_UnnumberedChapter ||
          p->type == para_Heading ||
          p->type == para_Subsect) {

          rdstringc rs = { 0, 0, NULL };
          char *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, rs.text, errstr);
          }
          sfree(rs.text);
      }
    }

    /*
     * Loop over the index entries, preparing final text forms for
     * each one.
     */
    {
      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);

    /* ------------------------------------------------------------------
     * 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
     * goes into the system title slot.
     */
    {
      rdstringc rs = {0, 0, NULL};
      for (p = sourceform; p; p = p->next) {
          if (p->type == para_Title) {
            whlp_begin_para(h, WHLP_PARA_NONSCROLL);
            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) {
          whlp_title(h, rs.text);
          fprintf(state.cntfp, ":Title %s\r\n", rs.text);
          sfree(rs.text);
      }
      {
          rdstringc rs2 = {0,0,NULL};
          whlp_rdadds(&rs2, conf.titlepage, &conf, NULL);
          whlp_contents_write(&state, 1, rs2.text, contents_topic);
          sfree(rs2.text);
      }
    }

    /*
     * 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_rdaddwc(&rs, p->words, &conf, NULL);
      }
      if (rs.text) {
          whlp_copyright(h, rs.text);
          sfree(rs.text);
      }
    }

    lastsect = NULL;

    /* ------------------------------------------------------------------
     * Now we've done the contents page, we're ready to go through
     * and do the main manual text. Ooh.
     */
    nesting = 0;
    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_NoCite:
      case para_Title:
      break;

      case para_LcontPush:
      case para_QuotePush:
      nesting++;
      break;
      case para_LcontPop:
      case para_QuotePop:
      assert(nesting > 0);
      nesting--;
      break;

      /*
       * Chapter and section titles: start a new Help topic.
       */
      case para_Chapter:
      case para_Appendix:
      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;
          /*
           * Do a navigation menu for the previous section we
           * were in.
           */
          for (q = lastsect->child; q; q = q->sibling)
            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, &conf, &cstate);
            whlp_rdadds(&rs, conf.sectsuffix, &conf, &cstate);
          }
          whlp_rdaddwc(&rs, p->words, &conf, &cstate);
          whlp_rdadds(&rs, NULL, &conf, &cstate);

          if (p->parent == NULL)
            parent_topic = contents_topic;
          else
            parent_topic = (WHLP_TOPIC)p->parent->private_data;
          topicid = whlp_topic_id(parent_topic);
          macro = smalloc(100+strlen(topicid));
          sprintf(macro,
                "CBB(\"btn_up\",\"JI(`',`%s')\");EB(\"btn_up\")",
                topicid);
          whlp_begin_topic(h, new_topic,
                       rs.text ? rs.text : "",
                       macro, NULL);
          sfree(macro);

          {
            /*
             * Output the .cnt entry.
             * 
             * WinHelp has a bug involving having an internal
             * node followed by a leaf at the same level: the
             * leaf is output at the wrong level. We can mostly
             * work around this by modifying the leaf level
             * itself (see whlp_contents_write), but this
             * doesn't work for top-level sections since we
             * can't turn a level-1 leaf into a level-0 one. So
             * for top-level leaf sections (Bibliography
             * springs to mind), we output an internal node
             * containing only the leaf for that section.
             */
            int i;
            paragraph *q;

            /* Count up the level. */
            i = 1;
            for (q = p; q->parent; q = q->parent) i++;

            if (p->child || !p->parent) {
                /*
                 * If p has children then it needs to be a
                 * folder; if it has no parent then it needs to
                 * be a folder to work around the bug.
                 */
                whlp_contents_write(&state, i, rs.text, NULL);
                i++;
            }
            whlp_contents_write(&state, i, rs.text, new_topic);
          }

          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, &conf);
            whlp_set_font(h, FONT_TITLE);
            whlp_wtext(&state, conf.sectsuffix);
          }
          whlp_mkparagraph(&state, FONT_TITLE, p->words, FALSE, &conf);
          whlp_wtext(&state, NULL);
          whlp_end_para(h);

          lastsect = p;
      }
      break;

      case para_Rule:
      whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
      whlp_para_attr(h, WHLP_PARA_ALIGNMENT, WHLP_ALIGN_CENTRE);
      whlp_begin_para(h, WHLP_PARA_SCROLL);
      whlp_set_font(h, FONT_RULE);
      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
      state.cstate = charset_init_state;
      whlp_wtext(&state, EIGHTY);
      whlp_wtext(&state, NULL);
#undef TEN
#undef TWENTY
#undef FORTY
#undef EIGHTY
      whlp_end_para(h);
      break;

      case para_Normal:
      case para_Copyright:
      case para_DescribedThing:
      case para_Description:
      case para_BiblioCited:
      case para_Bullet:
      case para_NumberedList:
      whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);
      if (p->type == para_Bullet || p->type == para_NumberedList) {
          whlp_para_attr(h, WHLP_PARA_LEFTINDENT, 72*nesting + 72);
          whlp_para_attr(h, WHLP_PARA_FIRSTLINEINDENT, -36);
          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_wtext(&state, conf.bullet);
          } else {
            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,
                     72*nesting + (p->type==para_Description ? 72 : 0));
          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, &conf);
          whlp_wtext(&state, L" ");
      }

      whlp_mkparagraph(&state, FONT_NORMAL, p->words, FALSE, &conf);
      whlp_wtext(&state, NULL);
      whlp_end_para(h);
      break;

      case para_Code:
      /*
       * In a code paragraph, each individual word is a line. For
       * Help files, we will have to output this as a set of
       * paragraphs, all but the last of which don't set
       * SPACEBELOW.
       */
      {
          word *w;
          wchar_t *t, *e, *tmp;

          for (w = p->words; w; w = w->next) if (w->type == word_WeakCode) {
            t = w->text;
            if (w->next && w->next->type == word_Emph) {
                w = w->next;
                e = w->text;
            } else
                e = NULL;

            if (!w->next)
                whlp_para_attr(h, WHLP_PARA_SPACEBELOW, 12);

            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;

                for (n = 0; t[n] && e[n] && e[n] == ec; n++);
                if (ec == 'i')
                  whlp_set_font(h, FONT_ITAL_CODE);
                else if (ec == 'b')
                  whlp_set_font(h, FONT_BOLD_CODE);
                else
                  whlp_set_font(h, FONT_CODE);
                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_wtext(&state, t);
            whlp_wtext(&state, NULL);
            whlp_end_para(h);
          }
      }
      break;
    }

    fclose(state.cntfp);
    whlp_close(h, conf.filename);

    /*
     * Loop over the index entries, cleaning up our final text
     * forms.
     */
    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,
                        int level, char *text, WHLP_TOPIC topic) {
    /*
     * Horrifying bug in WinHelp. When dropping a section level or
     * more without using a folder-type entry, WinHelp accidentally
     * adds one to the section level. So we correct for that here.
     */
    if (state->cnt_last_level > level && topic)
      state->cnt_workaround = -1;
    else if (!topic)
      state->cnt_workaround = 0;
    state->cnt_last_level = level;

    fprintf(state->cntfp, "%d ", level + state->cnt_workaround);
    while (*text) {
      if (*text == '=')
          fputc('\\', state->cntfp);
      fputc(*text, state->cntfp);
      text++;
    }
    if (topic)
      fprintf(state->cntfp, "=%s", whlp_topic_id(topic));
    fputc('\n', state->cntfp);
}

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, conf);
      whlp_set_font(state->h, FONT_NORMAL);
      whlp_wtext(state, conf->sectsuffix);
    }
    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,
                       whlpconf *conf) {
    keyword *kwl;
    int deffont = font;
    int currfont = -1;
    int newfont;
    paragraph *xref_target = NULL;

    for (; text; text = text->next) switch (text->type) {
      case word_HyperLink:
      case word_HyperEnd:
      break;

      case word_IndexRef:
      if (subsidiary) break;         /* disabled in subsidiary bits */
      {
          indextag *tag = index_findtag(state->idx, text->text);
          int i;
          if (!tag)
            break;
          for (i = 0; i < tag->nrefs; i++)
            whlp_index_term(state->h, tag->refs[i]->backend_data,
                        state->curr_topic);
      }
      break;

      case word_UpperXref:
      case word_LowerXref:
      if (subsidiary) break;         /* disabled in subsidiary bits */
        kwl = kw_lookup(state->keywords, text->text);
        assert(xref_target == NULL);
        if (kwl) {
            if (kwl->para->type == para_NumberedList) {
                break;               /* don't xref to numbered list items */
            } else if (kwl->para->type == para_BiblioCited) {
                /*
                 * An xref to a bibliography item jumps to the section
                 * containing it.
                 */
                if (kwl->para->parent)
                    xref_target = kwl->para->parent;
                else
                    break;
            } else {
                xref_target = kwl->para;
            }
            whlp_start_hyperlink(state->h,
                                 (WHLP_TOPIC)xref_target->private_data);
        }
      break;

      case word_XrefEnd:
      if (subsidiary) break;         /* disabled in subsidiary bits */
      if (xref_target)
          whlp_end_hyperlink(state->h);
      xref_target = NULL;
      break;
      
      case word_Normal:
      case word_Emph:
      case word_Code:
      case word_WeakCode:
      case word_WhiteSpace:
      case word_EmphSpace:
      case word_CodeSpace:
      case word_WkCodeSpace:
      case word_Quote:
      case word_EmphQuote:
      case word_CodeQuote:
      case word_WkCodeQuote:
      if (towordstyle(text->type) == word_Emph)
          newfont = deffont + FONT_EMPH;
      else if (towordstyle(text->type) == word_Code ||
             towordstyle(text->type) == word_WeakCode)
          newfont = deffont + FONT_CODE;
      else
          newfont = deffont;
      if (newfont != currfont) {
          currfont = newfont;
          whlp_set_font(state->h, newfont);
      }
      if (removeattr(text->type) == word_Normal) {
          if (cvt_ok(conf->charset, text->text) || !text->alt)
            whlp_wtext(state, text->text);
          else
            whlp_mkparagraph(state, deffont, text->alt, FALSE, conf);
      } else if (removeattr(text->type) == word_WhiteSpace) {
          whlp_wtext(state, L" ");
      } else if (removeattr(text->type) == word_Quote) {
          whlp_wtext(state,
                   quoteaux(text->aux) == quote_Open ?
                   conf->lquote : conf->rquote);
      }
      break;
    }
}

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:
      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:
      case word_WhiteSpace:
      case word_EmphSpace:
      case word_CodeSpace:
      case word_WkCodeSpace:
      case word_Quote:
      case word_EmphQuote:
      case word_CodeQuote:
      case word_WkCodeQuote:
      assert(text->type != word_CodeQuote &&
             text->type != word_WkCodeQuote);
      if (removeattr(text->type) == word_Normal) {
          if (cvt_ok(conf->charset, text->text) || !text->alt)
            whlp_rdadds(rs, text->text, conf, state);
          else
            whlp_rdaddwc(rs, text->alt, conf, state);
      } else if (removeattr(text->type) == word_WhiteSpace) {
          whlp_rdadds(rs, L" ", conf, state);
      } else if (removeattr(text->type) == word_Quote) {
          whlp_rdadds(rs, quoteaux(text->aux) == quote_Open ?
                  conf->lquote : conf->rquote, conf, state);
      }
      break;
    }

    if (state == &ourstate)
      whlp_rdadds(rs, NULL, conf, state);
}

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);
      }
    }
}

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);
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index