Example #1
0
/*
 * Duplicate a linked list of words
 */
word *dup_word_list(word *w) {
    word *head = NULL, **eptr = &head;

    while (w) {
	word *newwd = snew(word);
	*newwd = *w;		       /* structure copy */
	newwd->text = ustrdup(w->text);
	if (w->alt)
	    newwd->alt = dup_word_list(w->alt);
	*eptr = newwd;
	newwd->next = NULL;
	eptr = &newwd->next;

	w = w->next;
    }

    return head;
}
Example #2
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;
    }
  }
}
Example #3
0
void text_backend(paragraph *sourceform, keywordlist *keywords,
		  indexdata *idx, void *unused) {
    paragraph *p;
    textconfig conf;
    word *prefix, *body, *wp;
    word spaceword;
    textfile tf;
    wchar_t *prefixextra;
    int nesting, nestbase, nestindent;
    int indentb, indenta;

    IGNORE(unused);
    IGNORE(keywords);		       /* we don't happen to need this */
    IGNORE(idx);		       /* or this */

    conf = text_configure(sourceform);

    /*
     * Open the output file.
     */
    if (!strcmp(conf.filename, "-"))
	tf.fp = stdout;
    else
	tf.fp = fopen(conf.filename, "w");
    if (!tf.fp) {
	err_cantopenw(conf.filename);
	return;
    }
    tf.charset = conf.charset;
    tf.state = charset_init_state;

    /* Do the title */
    for (p = sourceform; p; p = p->next)
	if (p->type == para_Title)
	    text_heading(&tf, NULL, NULL, p->words,
			 conf.atitle, conf.indent, conf.width, &conf);

    nestindent = conf.listindentbefore + conf.listindentafter;
    nestbase = (conf.indent_preambles ? 0 : -conf.indent);
    nesting = nestbase;

    /* 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 >= nestbase);
	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:
	text_heading(&tf, p->kwtext, p->kwtext2, p->words,
		     conf.achapter, conf.indent, conf.width, &conf);
	nesting = 0;
	break;

      case para_Heading:
      case para_Subsect:
	text_heading(&tf, p->kwtext, p->kwtext2, p->words,
		     conf.asect[p->aux>=conf.nasect ? conf.nasect-1 : p->aux],
		     conf.indent, conf.width, &conf);
	break;

      case para_Rule:
	text_rule(&tf, conf.indent + 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:
	if (p->type == para_Bullet) {
	    prefix = &conf.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;
	}
	text_para(&tf, prefix, prefixextra, body,
		  conf.indent + nesting + indentb, indenta,
		  conf.width - nesting - indentb - indenta, &conf);
	if (wp) {
	    wp->next = NULL;
	    free_word_list(body);
	}
	break;

      case para_Code:
	text_codepara(&tf, p->words,
		      conf.indent + nesting + conf.indent_code,
		      conf.width - nesting - 2 * conf.indent_code);
	break;
    }

    /* Do the version ID */
    if (conf.include_version_id) {
	for (p = sourceform; p; p = p->next)
	    if (p->type == para_VersionID)
 		text_versionid(&tf, p->words, &conf);
    }

    /*
     * Tidy up
     */
    text_output(&tf, NULL);	       /* end charset conversion */
    if (tf.fp != stdout)
	fclose(tf.fp);
    sfree(conf.asect);
    sfree(conf.filename);
}
Example #4
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 = •
	    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);
	}