Logo Search packages:      
Sourcecode: halibut version File versions

keywords.c

/*
 * keywords.c: keep track of all cross-reference keywords
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "halibut.h"

static int kwcmp(void *av, void *bv)
{
    const keyword *a = (const keyword *)av;
    const keyword *b = (const keyword *)bv;
    return ustrcmp(a->key, b->key);
}

static int kwfind(void *av, void *bv)
{
    wchar_t *a = (wchar_t *)av;
    const keyword *b = (const keyword *)bv;
    return ustrcmp(a, b->key);
}

keyword *kw_lookup(keywordlist *kl, wchar_t *str) {
    return find234(kl->keys, str, kwfind);
}

/*
 * This function reads through source form and collects the
 * keywords. They get collected in a heap, sorted by Unicode
 * collation, last at the top (so that we can Heapsort them when we
 * finish).
 */
keywordlist *get_keywords(paragraph *source) {
    int errors = FALSE;
    keywordlist *kl = snew(keywordlist);
    numberstate *n = number_init();
    int prevpara = para_NotParaType;

    number_cfg(n, source);

    kl->size = 0;
    kl->keys = newtree234(kwcmp);
    kl->nlooseends = kl->looseendssize = 0;
    kl->looseends = NULL;
    for (; source; source = source->next) {
      wchar_t *p, *q;
      p = q = source->keyword;

      /*
       * Look for the section type override (`example',
       * `question' or whatever - to replace `chapter' or
       * `section' on a per-section basis).
       */
      if (q) {
          q = uadv(q);         /* point q at the word beyond */
          if (!*q) q = NULL;
      }
      
      /*
       * Number the chapter / section / list-item / whatever.
       * This also sets up the `parent', `child' and `sibling'
       * links.
       */
      source->kwtext = number_mktext(n, source, q, &prevpara, &errors);

      if (p && *p) {
          if (source->kwtext || source->type == para_Biblio) {
            keyword *kw, *ret;

            kw = snew(keyword);
            kw->key = p;
            kw->text = source->kwtext;
            kw->para = source;
            ret = add234(kl->keys, kw);
            if (ret != kw) {
                error(err_multikw, &source->fpos, &ret->para->fpos, p);
                sfree(kw);
                /* FIXME: what happens to kw->text? Does it leak? */
            }
          }
      } else {
          if (kl->nlooseends >= kl->looseendssize) {
            kl->looseendssize = kl->nlooseends + 32;
            kl->looseends = sresize(kl->looseends, kl->looseendssize,
                              word *);
          }
          kl->looseends[kl->nlooseends++] = source->kwtext;
      }
    }

    number_free(n);

    if (errors) {
      free_keywords(kl);
      return NULL;
    }

    return kl;
}

void free_keywords(keywordlist *kl) {
    keyword *kw;
    while (kl->nlooseends)
      free_word_list(kl->looseends[--kl->nlooseends]);
    sfree(kl->looseends);
    while ( (kw = index234(kl->keys, 0)) != NULL) {
        delpos234(kl->keys, 0);
      free_word_list(kw->text);
      sfree(kw);
    }
    freetree234(kl->keys);
    sfree(kl);
}

void subst_keywords(paragraph *source, keywordlist *kl) {
    for (; source; source = source->next) {
      word *ptr;
      for (ptr = source->words; ptr; ptr = ptr->next) {
          if (ptr->type == word_UpperXref ||
            ptr->type == word_LowerXref) {
            keyword *kw;
            word **endptr, *close, *subst;

            kw = kw_lookup(kl, ptr->text);
            if (!kw) {
                error(err_nosuchkw, &ptr->fpos, ptr->text);
                subst = NULL;
            } else
                subst = dup_word_list(kw->text);

            if (subst && ptr->type == word_LowerXref &&
                kw->para->type != para_Biblio &&
                kw->para->type != para_BiblioCited)
                ustrlow(subst->text);

            close = snew(word);
            close->text = NULL;
            close->alt = NULL;
            close->type = word_XrefEnd;
            close->fpos = ptr->fpos;

            close->next = ptr->next;
            ptr->next = subst;

            for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next)
                (*endptr)->fpos = ptr->fpos;

            *endptr = close;
            ptr = close;
          }
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index