Esempio n. 1
0
void gen_citations(paragraph * source, keywordlist * kl)
{
  paragraph *para;
  int bibnum = 0;

  for (para = source; para; para = para->next)
  {
    word *ptr;

    /*
     * \BR and \nocite paragraphs get special processing here.
     */
    if (para->type == para_BR)
    {
      keyword *kw = kw_lookup(kl, para->keyword);
      if (!kw)
      {
        error(err_nosuchkw, &para->fpos, para->keyword);
      } else if (kw->text)
      {
        error(err_multiBR, &para->fpos, para->keyword);
      } else
      {
        kw->text = dup_word_list(para->words);
      }
    } else if (para->type == para_NoCite)
    {
      wchar_t *wp = para->keyword;
      while (*wp)
      {
        cite_biblio(kl, wp, para->fpos);
        wp = uadv(wp);
      }
    }

    /*
     * Scan for keyword references.
     */
    for (ptr = para->words; ptr; ptr = ptr->next)
    {
      if (ptr->type == word_UpperXref || ptr->type == word_LowerXref
          || ptr->type == word_FreeTextXref)
        cite_biblio(kl, ptr->text, ptr->fpos);
    }
  }

  /*
   * We're now almost done; all that remains is to scan through
   * the cited bibliography entries and invent default citation
   * texts for the ones that don't already have explicitly
   * provided \BR text.
   */
  for (para = source; para; para = para->next)
  {
    if (para->type == para_BiblioCited)
    {
      keyword *kw = kw_lookup(kl, para->keyword);
      assert(kw != NULL);
      if (!kw->text)
      {
        word *wd = smalloc(sizeof(word));
        wd->text = gentext(++bibnum);
        wd->type = word_Normal;
        wd->alt = NULL;
        wd->next = NULL;
        kw->text = wd;
      }
      para->kwtext = kw->text;
    }
  }
}
Esempio n. 2
0
static textconfig text_configure(paragraph *source) {
    textconfig ret;
    paragraph *p;
    int n;

    /*
     * Non-negotiables.
     */
    ret.bullet.next = NULL;
    ret.bullet.alt = NULL;
    ret.bullet.type = word_Normal;
    ret.atitle.just_numbers = FALSE;   /* ignored */
    ret.atitle.number_at_all = TRUE;   /* ignored */

    /*
     * Defaults.
     */
    ret.indent = 7;
    ret.indent_code = 2;
    ret.listindentbefore = 1;
    ret.listindentafter = 3;
    ret.width = 68;
    ret.atitle.align = CENTRE;
    ret.atitle.underline = L"\x2550\0=\0\0";
    ret.achapter.align = LEFT;
    ret.achapter.just_numbers = FALSE;
    ret.achapter.number_at_all = TRUE;
    ret.achapter.number_suffix = L": ";
    ret.achapter.underline = L"\x203E\0-\0\0";
    ret.nasect = 1;
    ret.asect = snewn(ret.nasect, alignstruct);
    ret.asect[0].align = LEFTPLUS;
    ret.asect[0].just_numbers = TRUE;
    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 = 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.startstrong = L"*\0*\0\0";
    ret.endstrong = uadv(ret.startstrong);
    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(*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].align = utoalign(q);
	    } else if (!ustricmp(p->keyword, L"text-section-underline")) {
		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].underline = q;
	    } else if (!ustricmp(p->keyword, L"text-section-numeric")) {
		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].just_numbers = utob(q);
	    } else if (!ustricmp(p->keyword, L"text-section-shownumber")) {
		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_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-strong")) {
		if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
		    ret.startstrong = uadv(p->keyword);
		    ret.endstrong = uadv(ret.startstrong);
		}
	    } 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 (*uadv(ret.endstrong) && *uadv(uadv(ret.endstrong)) &&
	   (!cvt_ok(ret.charset, ret.startstrong) ||
	    !cvt_ok(ret.charset, ret.endstrong))) {
	ret.startstrong = uadv(ret.endstrong);
	ret.endstrong = uadv(ret.startstrong);
    }

    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;
}
Esempio n. 3
0
/*
 * Add a \IM. `tags' points to a zero-terminated chain of
 * zero-terminated strings ("first\0second\0thirdandlast\0\0").
 * `text' points to a word list.
 *
 * Guarantee on calling sequence: all implicit merges are given
 * before the explicit ones.
 */
void index_merge(indexdata *idx, int is_explicit, wchar_t *tags, word *text,
		 filepos *fpos) {
    indextag *t, *existing;

    /*
     * For an implicit merge, we want to remove all emphasis,
     * because the chances are that the user didn't really want to
     * index the term as emphasised.
     */
    {
	word *w;

	for (w = text; w; w = w->next) {
	    if (w->type == word_Emph || w->type == word_Strong)
		w->type = word_Normal;
	    else if (w->type == word_EmphSpace || w->type == word_StrongSpace)
		w->type = word_WhiteSpace;
	    else if (w->type == word_EmphQuote || w->type == word_StrongQuote)
		w->type = word_Quote;
	}
    }

    /*
     * FIXME: want to warn on overlapping source sets.
     */
    for (; *tags; tags = uadv(tags)) {
	t = make_indextag();
	t->name = tags;
	existing = add234(idx->tags, t);
	if (existing == t) {
	    /*
	     * Duplicate this so we can free it independently.
	     */
	    t->name = ustrdup(tags);

	    /*
	     * Every tag has an implicit \IM. So if this tag
	     * doesn't exist and we're explicit, then we should
	     * warn (and drop it, since it won't be referenced).
	     */
	    if (is_explicit) {
		err_nosuchidxtag(fpos, tags);
		continue;
	    }

	    /*
	     * Otherwise, this is a new tag with an implicit \IM.
	     */
	    t->implicit_text = text;
	    t->implicit_fpos = *fpos;
	} else {
	    if (!is_explicit) {
 		/*
		 * An implicit \IM for a tag that's had an implicit
		 * \IM before. FIXME: we should check the text
		 * against the existing text and warn on
		 * differences. And check the tag for case match
		 * against the existing tag, likewise.
		 */

		/*
		 * Check the tag against its previous occurrence to
		 * see if the cases match.
		 */
		if (ustrcmp(t->name, existing->name)) {
		    err_indexcase(fpos, t->name,
			  &existing->implicit_fpos, existing->name);
		}

		sfree(t);
	    } else {
		/*
		 * An explicit \IM added to a valid tag. In
		 * particular, this removes the implicit \IM if
		 * present.
		 */
		sfree(t);
		t = existing;
		if (t->implicit_text) {
		    free_word_list(t->implicit_text);
		    t->implicit_text = NULL;
		}
		if (t->nexplicit >= t->explicit_size) {
		    t->explicit_size = t->nexplicit + 8;
		    t->explicit_texts = sresize(t->explicit_texts,
						t->explicit_size, word *);
		    t->explicit_fpos = sresize(t->explicit_fpos,
					       t->explicit_size, filepos);
		}
		t->explicit_texts[t->nexplicit] = text;
		t->explicit_fpos[t->nexplicit] = *fpos;
		t->nexplicit++;
	    }
	}
    }
Esempio n. 4
0
static infoconfig info_configure(paragraph *source) {
    infoconfig ret;
    paragraph *p;

    /*
     * Defaults.
     */
    ret.filename = dupstr("output.info");
    ret.maxfilesize = 64 << 10;
    ret.charset = CS_ASCII;
    ret.width = 70;
    ret.listindentbefore = 1;
    ret.listindentafter = 3;
    ret.indent_code = 2;
    ret.index_width = 40;
    ret.listsuffix = L".";
    ret.bullet = L"\x2022\0-\0\0";
    ret.rule = L"\x2500\0-\0\0";
    ret.startemph = L"_\0_\0\0";
    ret.endemph = uadv(ret.startemph);
    ret.lquote = L"\x2018\0\x2019\0`\0'\0\0";
    ret.rquote = uadv(ret.lquote);
    ret.sectsuffix = L": ";
    ret.underline = L"\x203E\0-\0\0";
    ret.index_text = L"Index";

    /*
     * Two-pass configuration so that we can pick up global config
     * (e.g. `quotes') before having it overridden by specific
     * config (`info-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);
		}
	    } else if (!ustricmp(p->keyword, L"index")) {
		ret.index_text = uadv(p->keyword);
	    }
	}
    }

    for (p = source; p; p = p->next) {
	if (p->type == para_Config) {
	    if (!ustricmp(p->keyword, L"info-filename")) {
		sfree(ret.filename);
		ret.filename = dupstr(adv(p->origkeyword));
	    } else if (!ustricmp(p->keyword, L"info-charset")) {
		ret.charset = charset_from_ustr(&p->fpos, uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-max-file-size")) {
		ret.maxfilesize = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-width")) {
		ret.width = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-indent-code")) {
		ret.indent_code = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-index-width")) {
		ret.index_width = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-list-indent")) {
		ret.listindentbefore = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-listitem-indent")) {
		ret.listindentafter = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"info-section-suffix")) {
		ret.sectsuffix = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"info-underline")) {
		ret.underline = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"info-bullet")) {
		ret.bullet = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"info-rule")) {
		ret.rule = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"info-list-suffix")) {
		ret.listsuffix = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"info-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"info-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.underline && *uadv(ret.underline) &&
	   !cvt_ok(ret.charset, ret.underline))
	ret.underline = uadv(ret.underline);

    while (*ret.bullet && *uadv(ret.bullet) &&
	   !cvt_ok(ret.charset, ret.bullet))
	ret.bullet = uadv(ret.bullet);

    while (*ret.rule && *uadv(ret.rule) &&
	   !cvt_ok(ret.charset, ret.rule))
	ret.rule = uadv(ret.rule);

    return ret;
}
Esempio n. 5
0
void info_backend(paragraph *sourceform, keywordlist *keywords,
		  indexdata *idx, void *unused) {
    paragraph *p;
    infoconfig conf;
    word *prefix, *body, *wp;
    word spaceword;
    wchar_t *prefixextra;
    int nesting, nestindent;
    int indentb, indenta;
    int filepos;
    int has_index;
    info_data intro_text = EMPTY_INFO_DATA;
    node *topnode, *currnode;
    word bullet;
    FILE *fp;

    IGNORE(unused);

    conf = info_configure(sourceform);

    /*
     * Go through and create a node for each section.
     */
    topnode = info_node_new("Top", conf.charset);
    currnode = topnode;
    for (p = sourceform; p; p = p->next) switch (p->type) {
	/*
	 * Chapter titles.
	 */
      case para_Chapter:
      case para_Appendix:
      case para_UnnumberedChapter:
      case para_Heading:
      case para_Subsect:
	{
	    node *newnode, *upnode;
	    char *nodename;

	    nodename = info_node_name_for_para(p, &conf);
	    newnode = info_node_new(nodename, conf.charset);
	    sfree(nodename);

	    p->private_data = newnode;

	    if (p->parent)
		upnode = (node *)p->parent->private_data;
	    else
		upnode = topnode;
	    assert(upnode);
	    newnode->up = upnode;

	    currnode->next = newnode;
	    newnode->prev = currnode;

	    currnode->listnext = newnode;
	    currnode = newnode;
	}
	break;
      default:
        p->private_data = NULL;
        break;
    }

    /*
     * Set up the display form of each index entry.
     */
    {
	int i;
	indexentry *entry;

	for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) {
	    info_idx *ii = snew(info_idx);
	    info_data id = EMPTY_INFO_DATA;

	    id.charset = conf.charset;

	    ii->nnodes = ii->nodesize = 0;
	    ii->nodes = NULL;

	    ii->length = info_rdaddwc(&id, entry->text, NULL, FALSE, &conf);

	    ii->text = id.output.text;

	    entry->backend_data = ii;
	}
    }

    /*
     * An Info file begins with a piece of introductory text which
     * is apparently never shown anywhere. This seems to me to be a
     * good place to put the copyright notice and the version IDs. 
     * Also, Info directory entries are expected to go here.
     */
    intro_text.charset = conf.charset;

    info_rdaddsc(&intro_text,
	    "This Info file generated by Halibut, ");
    info_rdaddsc(&intro_text, version);
    info_rdaddsc(&intro_text, "\n\n");

    for (p = sourceform; p; p = p->next)
	if (p->type == para_Config &&
	    !ustricmp(p->keyword, L"info-dir-entry")) {
	    wchar_t *section, *shortname, *longname, *kw;
	    char *s;

	    section = uadv(p->keyword);
	    shortname = *section ? uadv(section) : L"";
	    longname = *shortname ? uadv(shortname) : L"";
	    kw = *longname ? uadv(longname) : L"";

	    if (!*longname) {
		error(err_cfginsufarg, &p->fpos, p->origkeyword, 3);
		continue;
	    }

	    info_rdaddsc(&intro_text, "INFO-DIR-SECTION ");
	    info_rdadds(&intro_text, section);
	    info_rdaddsc(&intro_text, "\nSTART-INFO-DIR-ENTRY\n* ");
	    info_rdadds(&intro_text, shortname);
	    info_rdaddsc(&intro_text, ": (");
	    s = dupstr(conf.filename);
	    if (strlen(s) > 5 && !strcmp(s+strlen(s)-5, ".info"))
		s[strlen(s)-5] = '\0';
	    info_rdaddsc(&intro_text, s);
	    sfree(s);
	    info_rdaddsc(&intro_text, ")");
	    if (*kw) {
		keyword *kwl = kw_lookup(keywords, kw);
		if (kwl && kwl->para->private_data) {
		    node *n = (node *)kwl->para->private_data;
		    info_rdaddsc(&intro_text, n->name);
		}
	    }
	    info_rdaddsc(&intro_text, ".   ");
	    info_rdadds(&intro_text, longname);
	    info_rdaddsc(&intro_text, "\nEND-INFO-DIR-ENTRY\n\n");
	}

    for (p = sourceform; p; p = p->next)
	if (p->type == para_Copyright)
	    info_para(&intro_text, NULL, NULL, p->words, keywords,
		      0, 0, conf.width, &conf);

    for (p = sourceform; p; p = p->next)
	if (p->type == para_VersionID)
	    info_versionid(&intro_text, p->words, &conf);

    if (intro_text.output.text[intro_text.output.pos-1] != '\n')
	info_rdaddc(&intro_text, '\n');

    /* Do the title */
    for (p = sourceform; p; p = p->next)
	if (p->type == para_Title)
	    info_heading(&topnode->text, NULL, p->words, conf.width, &conf);

    nestindent = conf.listindentbefore + conf.listindentafter;
    nesting = 0;

    currnode = topnode;

    /* 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 >= 0);
	break;

	/*
	 * 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;

	/*
	 * Chapter titles.
	 */
      case para_Chapter:
      case para_Appendix:
      case para_UnnumberedChapter:
      case para_Heading:
      case para_Subsect:
	currnode = p->private_data;
	assert(currnode);
	assert(currnode->up);

	if (!currnode->up->started_menu) {
	    info_rdaddsc(&currnode->up->text, "* Menu:\n\n");
	    currnode->up->started_menu = TRUE;
	}
	info_menu_item(&currnode->up->text, currnode, p, &conf);

	has_index |= info_check_index(p->words, currnode, idx);
	info_heading(&currnode->text, p->kwtext, p->words, conf.width, &conf);
	nesting = 0;
	break;

      case para_Rule:
	info_rule(&currnode->text, 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:
	has_index |= info_check_index(p->words, currnode, idx);
	if (p->type == para_Bullet) {
	    bullet.next = NULL;
	    bullet.alt = NULL;
	    bullet.type = word_Normal;
	    bullet.text = conf.bullet;
	    prefix = &bullet;
	    prefixextra = NULL;
	    indentb = conf.listindentbefore;
	    indenta = conf.listindentafter;
	} else if (p->type == para_NumberedList) {
	    prefix = p->kwtext;
	    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 {
	    prefix = NULL;
	    prefixextra = NULL;
	    indentb = indenta = 0;
	}
	if (p->type == para_BiblioCited) {
	    body = dup_word_list(p->kwtext);
	    for (wp = body; wp->next; wp = wp->next);
	    wp->next = &spaceword;
	    spaceword.next = p->words;
	    spaceword.alt = NULL;
	    spaceword.type = word_WhiteSpace;
	    spaceword.text = NULL;
	} else {
	    wp = NULL;
	    body = p->words;
	}
	info_para(&currnode->text, prefix, prefixextra, body, keywords,
		  nesting + indentb, indenta,
		  conf.width - nesting - indentb - indenta, &conf);
	if (wp) {
	    wp->next = NULL;
	    free_word_list(body);
	}
	break;

      case para_Code:
	info_codepara(&currnode->text, p->words,
		      nesting + conf.indent_code,
		      conf.width - nesting - 2 * conf.indent_code);
	break;
    }

    /*
     * Create an index node if required.
     */
    if (has_index) {
	node *newnode;
	int i, j, k;
	indexentry *entry;
	char *nodename;

	nodename = info_node_name_for_text(conf.index_text, &conf);
	newnode = info_node_new(nodename, conf.charset);
	sfree(nodename);

	newnode->up = topnode;

	currnode->next = newnode;
	newnode->prev = currnode;
	currnode->listnext = newnode;

	k = info_rdadds(&newnode->text, conf.index_text);
	info_rdaddsc(&newnode->text, "\n");
	while (k > 0) {
	    info_rdadds(&newnode->text, conf.underline);
	    k -= ustrwid(conf.underline, conf.charset);
	}
	info_rdaddsc(&newnode->text, "\n\n");

	info_menu_item(&topnode->text, newnode, NULL, &conf);

	for (i = 0; (entry = index234(idx->entries, i)) != NULL; i++) {
	    info_idx *ii = (info_idx *)entry->backend_data;

	    for (j = 0; j < ii->nnodes; j++) {
		/*
		 * When we have multiple references for a single
		 * index term, we only display the actual term on
		 * the first line, to make it clear that the terms
		 * really are the same.
		 */
		if (j == 0)
		    info_rdaddsc(&newnode->text, ii->text);
		for (k = (j ? 0 : ii->length); k < conf.index_width-2; k++)
		    info_rdaddc(&newnode->text, ' ');
		info_rdaddsc(&newnode->text, "  *Note ");
		info_rdaddsc(&newnode->text, ii->nodes[j]->name);
		info_rdaddsc(&newnode->text, "::\n");
	    }
	}
    }

    /*
     * Finalise the text of each node, by adding the ^_ delimiter
     * and the node line at the top.
     */
    for (currnode = topnode; currnode; currnode = currnode->listnext) {
	char *origtext = currnode->text.output.text;
	currnode->text = empty_info_data;
	currnode->text.charset = conf.charset;
	info_rdaddsc(&currnode->text, "\037\nFile: ");
	info_rdaddsc(&currnode->text, conf.filename);
	info_rdaddsc(&currnode->text, ",  Node: ");
	info_rdaddsc(&currnode->text, currnode->name);
	if (currnode->prev) {
	    info_rdaddsc(&currnode->text, ",  Prev: ");
	    info_rdaddsc(&currnode->text, currnode->prev->name);
	}
	info_rdaddsc(&currnode->text, ",  Up: ");
	info_rdaddsc(&currnode->text, (currnode->up ?
				       currnode->up->name : "(dir)"));
	if (currnode->next) {
	    info_rdaddsc(&currnode->text, ",  Next: ");
	    info_rdaddsc(&currnode->text, currnode->next->name);
	}
	info_rdaddsc(&currnode->text, "\n\n");
	info_rdaddsc(&currnode->text, origtext);
	/*
	 * Just make _absolutely_ sure we end with a newline.
	 */
	if (currnode->text.output.text[currnode->text.output.pos-1] != '\n')
	    info_rdaddc(&currnode->text, '\n');

	sfree(origtext);
    }    

    /*
     * Compute the offsets for the tag table.
     */
    filepos = intro_text.output.pos;
    for (currnode = topnode; currnode; currnode = currnode->listnext) {
	currnode->pos = filepos;
	filepos += currnode->text.output.pos;
    }

    /*
     * Split into sub-files.
     */
    if (conf.maxfilesize > 0) {
	int currfilesize = intro_text.output.pos, currfilenum = 1;
	for (currnode = topnode; currnode; currnode = currnode->listnext) {
	    if (currfilesize > intro_text.output.pos &&
		currfilesize + currnode->text.output.pos > conf.maxfilesize) {
		currfilenum++;
		currfilesize = intro_text.output.pos;
	    }
	    currnode->filenum = currfilenum;
	    currfilesize += currnode->text.output.pos;
	}
    }

    /*
     * Write the primary output file.
     */
    fp = fopen(conf.filename, "w");
    if (!fp) {
	error(err_cantopenw, conf.filename);
	return;
    }
    fputs(intro_text.output.text, fp);
    if (conf.maxfilesize == 0) {
	for (currnode = topnode; currnode; currnode = currnode->listnext)
	    fputs(currnode->text.output.text, fp);
    } else {
	int filenum = 0;
	fprintf(fp, "\037\nIndirect:\n");
	for (currnode = topnode; currnode; currnode = currnode->listnext)
	    if (filenum != currnode->filenum) {
		filenum = currnode->filenum;
		fprintf(fp, "%s-%d: %d\n", conf.filename, filenum,
			currnode->pos);
	    }
    }
    fprintf(fp, "\037\nTag Table:\n");
    if (conf.maxfilesize > 0)
	fprintf(fp, "(Indirect)\n");
    for (currnode = topnode; currnode; currnode = currnode->listnext)
	fprintf(fp, "Node: %s\177%d\n", currnode->name, currnode->pos);
    fprintf(fp, "\037\nEnd Tag Table\n");
    fclose(fp);

    /*
     * Write the subfiles.
     */
    if (conf.maxfilesize > 0) {
	int filenum = 0;
	fp = NULL;

	for (currnode = topnode; currnode; currnode = currnode->listnext) {
	    if (filenum != currnode->filenum) {
		char *fname;

		filenum = currnode->filenum;

		if (fp)
		    fclose(fp);
		fname = snewn(strlen(conf.filename) + 40, char);
		sprintf(fname, "%s-%d", conf.filename, filenum);
		fp = fopen(fname, "w");
		if (!fp) {
		    error(err_cantopenw, fname);
		    return;
		}
		sfree(fname);
		fputs(intro_text.output.text, fp);
	    }
	    fputs(currnode->text.output.text, fp);
	}
Esempio n. 6
0
static manconfig man_configure(paragraph *source) {
    paragraph *p;
    manconfig ret;

    /*
     * Defaults.
     */
    ret.th = NULL;
    ret.headnumbers = FALSE;
    ret.mindepth = 0;
    ret.filename = dupstr("output.1");
    ret.charset = CS_ASCII;
    ret.bullet = L"\x2022\0o\0\0";
    ret.rule = L"\x2500\0-\0\0";
    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 (`man-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"man-identity")) {
		wchar_t *wp, *ep;

		wp = uadv(p->keyword);
		ep = wp;
		while (*ep)
		    ep = uadv(ep);
		sfree(ret.th);
		ret.th = snewn(ep - wp + 1, wchar_t);
		memcpy(ret.th, wp, (ep - wp + 1) * sizeof(wchar_t));
	    } else if (!ustricmp(p->keyword, L"man-charset")) {
		ret.charset = charset_from_ustr(&p->fpos, uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"man-headnumbers")) {
		ret.headnumbers = utob(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"man-mindepth")) {
		ret.mindepth = utoi(uadv(p->keyword));
	    } else if (!ustricmp(p->keyword, L"man-filename")) {
		sfree(ret.filename);
		ret.filename = dupstr(adv(p->origkeyword));
	    } else if (!ustricmp(p->keyword, L"man-bullet")) {
		ret.bullet = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"man-rule")) {
		ret.rule = uadv(p->keyword);
	    } else if (!ustricmp(p->keyword, L"man-quotes")) {
		if (*uadv(p->keyword) && *uadv(uadv(p->keyword))) {
		    ret.lquote = uadv(p->keyword);
		    ret.rquote = uadv(ret.lquote);
		}
	    }
	}