removed text and help file backends; added some usage crap and removed the help command line optin(who needs that)

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@1542 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
rainwater 2002-11-01 21:52:36 +00:00
parent ef17957fff
commit 048c27836c
23 changed files with 7533 additions and 10037 deletions

Binary file not shown.

View file

@ -1,5 +1,7 @@
Halibut is copyright (c) 1999-2001 Simon Tatham and James Aylett. Halibut is copyright (c) 1999-2001 Simon Tatham and James Aylett.
Note: This version is modified by Robert Rainwater and Amir Szekely
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, (the "Software"), to deal in the Software without restriction,

View file

@ -5,43 +5,38 @@
#include <assert.h> #include <assert.h>
#include "halibut.h" #include "halibut.h"
static wchar_t * static wchar_t *gentext(int num)
gentext (int num)
{ {
wchar_t text[22]; wchar_t text[22];
wchar_t *p = text + sizeof (text); wchar_t *p = text + sizeof(text);
*--p = L'\0'; *--p = L'\0';
*--p = L']'; *--p = L']';
while (num != 0) while (num != 0) {
{ assert(p > text);
assert (p > text); *--p = L"0123456789"[num % 10];
*--p = L"0123456789"[num % 10]; num /= 10;
num /= 10;
} }
assert (p > text); assert(p > text);
*--p = L'['; *--p = L'[';
return ustrdup (p); return ustrdup(p);
} }
static void static void cite_biblio(keywordlist * kl, wchar_t * key, filepos fpos)
cite_biblio (keywordlist * kl, wchar_t * key, filepos fpos)
{ {
keyword *kw = kw_lookup (kl, key); keyword *kw = kw_lookup(kl, key);
if (!kw) if (!kw)
error (err_nosuchkw, &fpos, key); error(err_nosuchkw, &fpos, key);
else else {
{ /*
/* * We've found a \k reference. If it's a
* We've found a \k reference. If it's a * bibliography entry ...
* bibliography entry ... */
*/ if (kw->para->type == para_Biblio) {
if (kw->para->type == para_Biblio) /*
{ * ... then mark the paragraph as cited.
/* */
* ... then mark the paragraph as cited. kw->para->type = para_BiblioCited;
*/ }
kw->para->type = para_BiblioCited;
}
} }
} }
@ -51,77 +46,62 @@ cite_biblio (keywordlist * kl, wchar_t * key, filepos fpos)
* entries are actually cited (or \nocite-ed). * entries are actually cited (or \nocite-ed).
*/ */
void void gen_citations(paragraph * source, keywordlist * kl)
gen_citations (paragraph * source, keywordlist * kl)
{ {
paragraph *para; paragraph *para;
int bibnum = 0; int bibnum = 0;
for (para = source; para; para = para->next) for (para = source; para; para = para->next) {
{ word *ptr;
word *ptr;
/* /*
* \BR and \nocite paragraphs get special processing here. * \BR and \nocite paragraphs get special processing here.
*/ */
if (para->type == para_BR) if (para->type == para_BR) {
{ keyword *kw = kw_lookup(kl, para->keyword);
keyword *kw = kw_lookup (kl, para->keyword); if (!kw) {
if (!kw) error(err_nosuchkw, &para->fpos, para->keyword);
{ } else if (kw->text) {
error (err_nosuchkw, &para->fpos, para->keyword); error(err_multiBR, &para->fpos, para->keyword);
} } else {
else if (kw->text) kw->text = dup_word_list(para->words);
{ }
error (err_multiBR, &para->fpos, para->keyword); } else if (para->type == para_NoCite) {
} wchar_t *wp = para->keyword;
else while (*wp) {
{ cite_biblio(kl, wp, para->fpos);
kw->text = dup_word_list (para->words); wp = uadv(wp);
} }
} }
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. * Scan for keyword references.
*/ */
for (ptr = para->words; ptr; ptr = ptr->next) for (ptr = para->words; ptr; ptr = ptr->next) {
{ if (ptr->type == word_UpperXref || ptr->type == word_LowerXref)
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref) cite_biblio(kl, ptr->text, ptr->fpos);
cite_biblio (kl, ptr->text, ptr->fpos); }
}
} }
/* /*
* We're now almost done; all that remains is to scan through * We're now almost done; all that remains is to scan through
* the cited bibliography entries and invent default citation * the cited bibliography entries and invent default citation
* texts for the ones that don't already have explicitly * texts for the ones that don't already have explicitly
* provided \BR text. * provided \BR text.
*/ */
for (para = source; para; para = para->next) for (para = source; para; para = para->next) {
{ if (para->type == para_BiblioCited) {
if (para->type == para_BiblioCited) keyword *kw = kw_lookup(kl, para->keyword);
{ assert(kw != NULL);
keyword *kw = kw_lookup (kl, para->keyword); if (!kw->text) {
assert (kw != NULL); word *wd = smalloc(sizeof(word));
if (!kw->text) wd->text = gentext(++bibnum);
{ wd->type = word_Normal;
word *wd = smalloc (sizeof (word)); wd->alt = NULL;
wd->text = gentext (++bibnum); wd->next = NULL;
wd->type = word_Normal; kw->text = wd;
wd->alt = NULL; }
wd->next = NULL; para->kwtext = kw->text;
kw->text = wd; }
}
para->kwtext = kw->text;
}
} }
} }

View file

@ -1,751 +0,0 @@
/*
* text backend for Halibut
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "halibut.h"
typedef enum
{ LEFT, LEFTPLUS, CENTRE }
alignment;
typedef struct
{
alignment align;
int just_numbers;
wchar_t underline;
wchar_t *number_suffix;
}
alignstruct;
typedef struct
{
int indent, indent_code;
int listindentbefore, listindentafter;
int width;
alignstruct atitle, achapter, *asect;
int nasect;
int include_version_id;
int indent_preambles;
word bullet;
}
textconfig;
static int text_convert (wchar_t *, char **);
static void text_heading (FILE *, word *, word *, word *, alignstruct, int,
int);
static void text_rule (FILE *, int, int);
static void text_para (FILE *, word *, char *, word *, int, int, int);
static void text_codepara (FILE *, word *, int, int);
static void text_versionid (FILE *, word *);
static alignment
utoalign (wchar_t * p)
{
if (!ustricmp (p, L"centre") || !ustricmp (p, L"center"))
return CENTRE;
if (!ustricmp (p, L"leftplus"))
return LEFTPLUS;
return LEFT;
}
static textconfig
text_configure (paragraph * source)
{
textconfig ret;
/*
* Non-negotiables.
*/
ret.bullet.next = NULL;
ret.bullet.alt = NULL;
ret.bullet.type = word_Normal;
ret.atitle.just_numbers = FALSE; /* 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'=';
ret.achapter.align = LEFT;
ret.achapter.just_numbers = FALSE;
ret.achapter.number_suffix = ustrdup (L": ");
ret.achapter.underline = L'-';
ret.nasect = 1;
ret.asect = mknewa (alignstruct, ret.nasect);
ret.asect[0].align = LEFTPLUS;
ret.asect[0].just_numbers = TRUE;
ret.asect[0].number_suffix = ustrdup (L" ");
ret.asect[0].underline = L'\0';
ret.include_version_id = TRUE;
ret.indent_preambles = FALSE;
ret.bullet.text = ustrdup (L"-");
for (; source; source = source->next)
{
if (source->type == para_Config)
{
if (!ustricmp (source->keyword, L"text-indent"))
{
ret.indent = utoi (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-indent-code"))
{
ret.indent_code = utoi (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-width"))
{
ret.width = utoi (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-list-indent"))
{
ret.listindentbefore = utoi (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-listitem-indent"))
{
ret.listindentafter = utoi (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-chapter-align"))
{
ret.achapter.align = utoalign (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-chapter-underline"))
{
ret.achapter.underline = *uadv (source->keyword);
}
else if (!ustricmp (source->keyword, L"text-chapter-numeric"))
{
ret.achapter.just_numbers = utob (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-chapter-suffix"))
{
ret.achapter.number_suffix = ustrdup (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-section-align"))
{
wchar_t *p = uadv (source->keyword);
int n = 0;
if (uisdigit (*p))
{
n = utoi (p);
p = uadv (p);
}
if (n >= ret.nasect)
{
int i;
ret.asect = resize (ret.asect, n + 1);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect - 1];
ret.nasect = n + 1;
}
ret.asect[n].align = utoalign (p);
}
else if (!ustricmp (source->keyword, L"text-section-underline"))
{
wchar_t *p = uadv (source->keyword);
int n = 0;
if (uisdigit (*p))
{
n = utoi (p);
p = uadv (p);
}
if (n >= ret.nasect)
{
int i;
ret.asect = resize (ret.asect, n + 1);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect - 1];
ret.nasect = n + 1;
}
ret.asect[n].underline = *p;
}
else if (!ustricmp (source->keyword, L"text-section-numeric"))
{
wchar_t *p = uadv (source->keyword);
int n = 0;
if (uisdigit (*p))
{
n = utoi (p);
p = uadv (p);
}
if (n >= ret.nasect)
{
int i;
ret.asect = resize (ret.asect, n + 1);
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 (p);
}
else if (!ustricmp (source->keyword, L"text-section-suffix"))
{
wchar_t *p = uadv (source->keyword);
int n = 0;
if (uisdigit (*p))
{
n = utoi (p);
p = uadv (p);
}
if (n >= ret.nasect)
{
int i;
ret.asect = resize (ret.asect, n + 1);
for (i = ret.nasect; i <= n; i++)
ret.asect[i] = ret.asect[ret.nasect - 1];
ret.nasect = n + 1;
}
ret.asect[n].number_suffix = ustrdup (p);
}
else if (!ustricmp (source->keyword, L"text-title-align"))
{
ret.atitle.align = utoalign (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-title-underline"))
{
ret.atitle.underline = *uadv (source->keyword);
}
else if (!ustricmp (source->keyword, L"text-versionid"))
{
ret.include_version_id = utob (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-indent-preamble"))
{
ret.indent_preambles = utob (uadv (source->keyword));
}
else if (!ustricmp (source->keyword, L"text-bullet"))
{
ret.bullet.text = uadv (source->keyword);
}
}
}
return ret;
}
void
text_backend (paragraph * sourceform, keywordlist * keywords, indexdata * idx)
{
paragraph *p;
textconfig conf;
word *prefix, *body, *wp;
word spaceword;
FILE *fp;
char *prefixextra;
int indentb, indenta;
IGNORE (keywords); /* we don't happen to need this */
IGNORE (idx); /* or this */
conf = text_configure (sourceform);
/*
* Determine the output file name, and open the output file
*
* FIXME: want configurable output file names here. For the
* moment, we'll just call it `output.txt'.
*/
fp = fopen ("output.txt", "w");
if (!fp)
{
error (err_cantopenw, "output.txt");
return;
}
/* Do the title */
for (p = sourceform; p; p = p->next)
if (p->type == para_Title)
text_heading (fp, NULL, NULL, p->words,
conf.atitle, conf.indent, conf.width);
/* Do the preamble and copyright */
for (p = sourceform; p; p = p->next)
if (p->type == para_Preamble)
text_para (fp, NULL, NULL, p->words,
conf.indent_preambles ? conf.indent : 0, 0,
conf.width + (conf.indent_preambles ? 0 : conf.indent));
for (p = sourceform; p; p = p->next)
if (p->type == para_Copyright)
text_para (fp, NULL, NULL, p->words,
conf.indent_preambles ? conf.indent : 0, 0,
conf.width + (conf.indent_preambles ? 0 : conf.indent));
/* Do the main document */
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_Copyright:
case para_Preamble:
case para_NoCite:
case para_Title:
break;
/*
* Chapter titles.
*/
case para_Chapter:
case para_Appendix:
case para_UnnumberedChapter:
text_heading (fp, p->kwtext, p->kwtext2, p->words,
conf.achapter, conf.indent, conf.width);
break;
case para_Heading:
case para_Subsect:
text_heading (fp, p->kwtext, p->kwtext2, p->words,
conf.asect[p->aux >=
conf.nasect ? conf.nasect - 1 : p->aux],
conf.indent, conf.width);
break;
case para_Rule:
text_rule (fp, conf.indent, conf.width);
break;
case para_Normal:
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 = "."; /* FIXME: configurability */
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 (fp, prefix, prefixextra, body,
conf.indent + indentb, indenta,
conf.width - indentb - indenta);
if (wp)
{
wp->next = NULL;
free_word_list (body);
}
break;
case para_Code:
text_codepara (fp, p->words, conf.indent + conf.indent_code,
conf.width - 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 (fp, p->words);
}
/*
* Tidy up
*/
fclose (fp);
{
int i;
sfree (conf.achapter.number_suffix);
for (i = 0; i < conf.nasect; i++)
sfree (conf.asect[i].number_suffix);
sfree (conf.asect);
sfree (conf.bullet.text);
}
}
/*
* Convert a wide string into a string of chars. If `result' is
* non-NULL, mallocs the resulting string and stores a pointer to
* it in `*result'. If `result' is NULL, merely checks whether all
* characters in the string are feasible for the output character
* set.
*
* Return is nonzero if all characters are OK. If not all
* characters are OK but `result' is non-NULL, a result _will_
* still be generated!
*/
static int
text_convert (wchar_t * s, char **result)
{
/*
* FIXME. Currently this is ISO8859-1 only.
*/
int doing = (result != 0);
int ok = TRUE;
char *p = NULL;
int plen = 0, psize = 0;
for (; *s; s++)
{
wchar_t c = *s;
char outc;
if ((c >= 32 && c <= 126) || (c >= 160 && c <= 255))
{
/* Char is OK. */
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;
}
return ok;
}
static void
text_rdaddwc (rdstringc * rs, word * text, word * end)
{
char *c;
for (; text && text != end; 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 (towordstyle (text->type) == word_Emph &&
(attraux (text->aux) == attr_First ||
attraux (text->aux) == attr_Only))
rdaddc (rs, '_'); /* FIXME: configurability */
else if (towordstyle (text->type) == word_Code &&
(attraux (text->aux) == attr_First ||
attraux (text->aux) == attr_Only))
rdaddc (rs, '`'); /* FIXME: configurability */
if (removeattr (text->type) == word_Normal)
{
if (text_convert (text->text, &c))
rdaddsc (rs, c);
else
text_rdaddwc (rs, text->alt, NULL);
sfree (c);
}
else if (removeattr (text->type) == word_WhiteSpace)
{
rdaddc (rs, ' ');
}
else if (removeattr (text->type) == word_Quote)
{
rdaddc (rs, quoteaux (text->aux) == quote_Open ? '`' : '\'');
/* FIXME: configurability */
}
if (towordstyle (text->type) == word_Emph &&
(attraux (text->aux) == attr_Last ||
attraux (text->aux) == attr_Only))
rdaddc (rs, '_'); /* FIXME: configurability */
else if (towordstyle (text->type) == word_Code &&
(attraux (text->aux) == attr_Last ||
attraux (text->aux) == attr_Only))
rdaddc (rs, '\''); /* FIXME: configurability */
break;
}
}
static int text_width (word *);
static int
text_width_list (word * text)
{
int w = 0;
while (text)
{
w += text_width (text);
text = text->next;
}
return w;
}
static int
text_width (word * text)
{
switch (text->type)
{
case word_HyperLink:
case word_HyperEnd:
case word_UpperXref:
case word_LowerXref:
case word_XrefEnd:
case word_IndexRef:
return 0;
case word_Normal:
case word_Emph:
case word_Code:
case word_WeakCode:
return (((text->type == word_Emph ||
text->type == word_Code)
? (attraux (text->aux) == attr_Only ? 2 :
attraux (text->aux) == attr_Always ? 0 : 1)
: 0) +
(text_convert (text->text, NULL) ?
ustrlen (text->text) : text_width_list (text->alt)));
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);
return (((towordstyle (text->type) == word_Emph ||
towordstyle (text->type) == word_Code)
? (attraux (text->aux) == attr_Only ? 2 :
attraux (text->aux) == attr_Always ? 0 : 1) : 0) + 1);
}
return 0; /* should never happen */
}
static void
text_heading (FILE * fp, word * tprefix, word * nprefix, word * text,
alignstruct align, int indent, int width)
{
rdstringc t = { 0, 0, NULL };
int margin, length;
int firstlinewidth, wrapwidth;
wrappedline *wrapping, *p;
if (align.just_numbers && nprefix)
{
char *c;
text_rdaddwc (&t, nprefix, NULL);
if (text_convert (align.number_suffix, &c))
{
rdaddsc (&t, c);
sfree (c);
}
}
else if (!align.just_numbers && tprefix)
{
char *c;
text_rdaddwc (&t, tprefix, NULL);
if (text_convert (align.number_suffix, &c))
{
rdaddsc (&t, c);
sfree (c);
}
}
margin = length = (t.text ? strlen (t.text) : 0);
if (align.align == LEFTPLUS)
{
margin = indent - margin;
if (margin < 0)
margin = 0;
firstlinewidth = indent + width - margin - length;
wrapwidth = width;
}
else if (align.align == LEFT || align.align == CENTRE)
{
margin = 0;
firstlinewidth = indent + width - length;
wrapwidth = indent + width;
}
wrapping = wrap_para (text, firstlinewidth, wrapwidth, text_width);
for (p = wrapping; p; p = p->next)
{
text_rdaddwc (&t, p->begin, p->end);
length = (t.text ? strlen (t.text) : 0);
if (align.align == CENTRE)
{
margin = (indent + width - length) / 2;
if (margin < 0)
margin = 0;
}
fprintf (fp, "%*s%s\n", margin, "", t.text);
if (align.underline != L'\0')
{
char *u, uc;
wchar_t uw[2];
uw[0] = align.underline;
uw[1] = L'\0';
text_convert (uw, &u);
uc = u[0];
sfree (u);
fprintf (fp, "%*s", margin, "");
while (length--)
putc (uc, fp);
putc ('\n', fp);
}
if (align.align == LEFTPLUS)
margin = indent;
else
margin = 0;
sfree (t.text);
t = empty_rdstringc;
}
wrap_free (wrapping);
putc ('\n', fp);
sfree (t.text);
}
static void
text_rule (FILE * fp, int indent, int width)
{
while (indent--)
putc (' ', fp);
while (width--)
putc ('-', fp); /* FIXME: configurability! */
putc ('\n', fp);
putc ('\n', fp);
}
static void
text_para (FILE * fp, word * prefix, char *prefixextra, word * text,
int indent, int extraindent, int width)
{
wrappedline *wrapping, *p;
rdstringc pfx = { 0, 0, NULL };
int e;
int firstlinewidth = width;
if (prefix)
{
text_rdaddwc (&pfx, prefix, NULL);
if (prefixextra)
rdaddsc (&pfx, prefixextra);
fprintf (fp, "%*s%s", indent, "", pfx.text);
/* If the prefix is too long, shorten the first line to fit. */
e = extraindent - strlen (pfx.text);
if (e < 0)
{
firstlinewidth += e; /* this decreases it, since e < 0 */
if (firstlinewidth < 0)
{
e = indent + extraindent;
firstlinewidth = width;
fprintf (fp, "\n");
}
else
e = 0;
}
sfree (pfx.text);
}
else
e = indent + extraindent;
wrapping = wrap_para (text, firstlinewidth, width, text_width);
for (p = wrapping; p; p = p->next)
{
rdstringc t = { 0, 0, NULL };
text_rdaddwc (&t, p->begin, p->end);
fprintf (fp, "%*s%s\n", e, "", t.text);
e = indent + extraindent;
sfree (t.text);
}
wrap_free (wrapping);
putc ('\n', fp);
}
static void
text_codepara (FILE * fp, word * text, int indent, int width)
{
for (; text; text = text->next)
if (text->type == word_WeakCode)
{
char *c;
text_convert (text->text, &c);
if (strlen (c) > (size_t) width)
{
/* FIXME: warn */
}
fprintf (fp, "%*s%s\n", indent, "", c);
sfree (c);
}
putc ('\n', fp);
}
static void
text_versionid (FILE * fp, word * text)
{
rdstringc t = { 0, 0, NULL };
rdaddc (&t, '['); /* FIXME: configurability */
text_rdaddwc (&t, text, NULL);
rdaddc (&t, ']'); /* FIXME: configurability */
fprintf (fp, "%s\n", t.text);
sfree (t.text);
}

View file

@ -1,711 +0,0 @@
/*
* Windows Help backend for Halibut
*
* TODO:
* - allow user to specify section contexts.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "halibut.h"
#include "winhelp.h"
struct bk_whlp_state
{
WHLP h;
indexdata *idx;
keywordlist *keywords;
WHLP_TOPIC curr_topic;
FILE *cntfp;
int cnt_last_level, cnt_workaround;
};
/*
* Indexes of fonts in our standard font descriptor set.
*/
enum
{
FONT_NORMAL,
FONT_EMPH,
FONT_CODE,
FONT_TITLE,
FONT_TITLE_EMPH,
FONT_TITLE_CODE,
FONT_RULE
};
static void whlp_rdaddwc (rdstringc * rs, word * text);
static int whlp_convert (wchar_t * s, char **result, int hard_spaces);
static void whlp_mkparagraph (struct bk_whlp_state *state,
int font, word * text, int subsidiary);
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);
void
whlp_backend (paragraph * sourceform, keywordlist * keywords, indexdata * idx)
{
WHLP h;
char *filename, *cntname;
paragraph *p, *lastsect;
struct bk_whlp_state state;
WHLP_TOPIC contents_topic;
int i;
indexentry *ie;
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;
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, "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);
/*
* Loop over the source form finding out whether the user has
* specified particular help topic names for anything.
*/
for (p = sourceform; p; p = p->next)
{
p->private_data = NULL;
if (p->type == para_Config && p->parent)
{
if (!ustricmp (p->keyword, L"winhelp-topic"))
{
char *topicname;
whlp_convert (uadv (p->keyword), &topicname, 0);
/* Store the topic name in the private_data field of the
* containing section. */
p->parent->private_data = topicname;
}
}
}
/*
* 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)
{
char *topicid = p->private_data;
char *errstr;
p->private_data = whlp_register_topic (h, topicid, &errstr);
if (!p->private_data)
{
p->private_data = whlp_register_topic (h, NULL, NULL);
error (err_winhelp_ctxclash, &p->fpos, topicid, errstr);
}
sfree (topicid);
}
}
/*
* Loop over the index entries, preparing final text forms for
* each one.
*/
for (i = 0; (ie = index234 (idx->entries, i)) != NULL; i++)
{
rdstringc rs = { 0, 0, NULL };
whlp_rdaddwc (&rs, ie->text);
ie->backend_data = rs.text;
}
whlp_prepare (h);
/* ------------------------------------------------------------------
* Do the contents page, containing title, preamble and
* copyright.
*/
whlp_begin_topic (h, contents_topic, "Contents", "DB(\"btn_up\")", NULL);
/*
* 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);
whlp_mkparagraph (&state, FONT_TITLE, p->words, FALSE);
whlp_rdaddwc (&rs, p->words);
whlp_end_para (h);
}
}
if (rs.text)
{
whlp_title (h, rs.text);
fprintf (state.cntfp, ":Title %s\r\n", rs.text);
sfree (rs.text);
}
whlp_contents_write (&state, 1, "Title page", contents_topic);
/* FIXME: configurability in that string */
}
/*
* 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.
*/
{
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);
whlp_rdaddwc (&rs, p->words);
}
}
if (rs.text)
{
whlp_copyright (h, rs.text);
sfree (rs.text);
}
}
/*
* 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;
/* ------------------------------------------------------------------
* Now we've done the contents page, we're ready to go through
* and do the main manual text. Ooh.
*/
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_Copyright:
case para_Preamble:
case para_NoCite:
case para_Title:
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 (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);
}
{
rdstringc rs = { 0, 0, NULL };
WHLP_TOPIC new_topic, parent_topic;
char *macro, *topicid;
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);
rdaddsc (&rs, ": "); /* FIXME: configurability */
}
whlp_rdaddwc (&rs, p->words);
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);
if (p->kwtext)
{
whlp_mkparagraph (&state, FONT_TITLE, p->kwtext, FALSE);
whlp_set_font (h, FONT_TITLE);
whlp_text (h, ": "); /* FIXME: configurability */
}
whlp_mkparagraph (&state, FONT_TITLE, p->words, FALSE);
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);
#define TEN "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0"
#define TWENTY TEN TEN
#define FORTY TWENTY TWENTY
#define EIGHTY FORTY FORTY
whlp_text (h, EIGHTY);
#undef TEN
#undef TWENTY
#undef FORTY
#undef EIGHTY
whlp_end_para (h);
break;
case para_Normal:
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);
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);
if (p->type == para_Bullet)
{
whlp_text (h, "\x95");
}
else
{
whlp_mkparagraph (&state, FONT_NORMAL, p->kwtext, FALSE);
whlp_text (h, ".");
}
whlp_tab (h);
}
else
{
whlp_begin_para (h, WHLP_PARA_SCROLL);
}
if (p->type == para_BiblioCited)
{
whlp_mkparagraph (&state, FONT_NORMAL, p->kwtext, FALSE);
whlp_text (h, " ");
}
whlp_mkparagraph (&state, FONT_NORMAL, p->words, FALSE);
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;
char *c;
for (w = p->words; w; w = w->next)
{
if (!w->next)
whlp_para_attr (h, WHLP_PARA_SPACEBELOW, 12);
whlp_begin_para (h, WHLP_PARA_SCROLL);
whlp_set_font (h, FONT_CODE);
whlp_convert (w->text, &c, FALSE);
whlp_text (h, c);
sfree (c);
whlp_end_para (h);
}
}
break;
}
fclose (state.cntfp);
whlp_close (h, 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);
}
}
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)
{
whlp_begin_para (state->h, WHLP_PARA_NONSCROLL);
whlp_start_hyperlink (state->h, (WHLP_TOPIC) p->private_data);
if (p->kwtext)
{
whlp_mkparagraph (state, FONT_NORMAL, p->kwtext, TRUE);
whlp_set_font (state->h, FONT_NORMAL);
whlp_text (state->h, ": "); /* FIXME: configurability */
}
whlp_mkparagraph (state, FONT_NORMAL, p->words, TRUE);
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)
{
keyword *kwl;
int deffont = font;
int currfont = -1;
int newfont;
char *c;
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->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 (whlp_convert (text->text, &c, TRUE))
whlp_text (state->h, c);
else
whlp_mkparagraph (state, deffont, text->alt, FALSE);
sfree (c);
}
else if (removeattr (text->type) == word_WhiteSpace)
{
whlp_text (state->h, " ");
}
else if (removeattr (text->type) == word_Quote)
{
whlp_text (state->h,
quoteaux (text->aux) == quote_Open ? "\x91" : "\x92");
/* FIXME: configurability */
}
break;
}
}
static void
whlp_rdaddwc (rdstringc * rs, word * text)
{
char *c;
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 (whlp_convert (text->text, &c, FALSE))
rdaddsc (rs, c);
else
whlp_rdaddwc (rs, text->alt);
sfree (c);
}
else if (removeattr (text->type) == word_WhiteSpace)
{
rdaddc (rs, ' ');
}
else if (removeattr (text->type) == word_Quote)
{
rdaddc (rs, quoteaux (text->aux) == quote_Open ? '\x91' : '\x92');
/* FIXME: configurability */
}
break;
}
}
/*
* Convert a wide string into a string of chars. If `result' is
* non-NULL, mallocs the resulting string and stores a pointer to
* it in `*result'. If `result' is NULL, merely checks whether all
* characters in the string are feasible for the output character
* set.
*
* Return is nonzero if all characters are OK. If not all
* characters are OK but `result' is non-NULL, a result _will_
* still be generated!
*/
static int
whlp_convert (wchar_t * s, char **result, int hard_spaces)
{
/*
* FIXME. Currently this is ISO8859-1 only.
*/
int doing = (result != 0);
int ok = TRUE;
char *p = NULL;
int plen = 0, psize = 0;
for (; *s; s++)
{
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;
}
return ok;
}

File diff suppressed because it is too large Load diff

View file

@ -8,251 +8,224 @@
#include <limits.h> #include <limits.h>
#include "halibut.h" #include "halibut.h"
struct numberstate_Tag struct numberstate_Tag {
{ int chapternum;
int chapternum; int appendixnum;
int appendixnum; int ischapter;
int ischapter; int *sectionlevels;
int *sectionlevels; paragraph **currentsects;
paragraph **currentsects; paragraph *lastsect;
paragraph *lastsect; int oklevel;
int oklevel; int maxsectlevel;
int maxsectlevel; int listitem;
int listitem; wchar_t *chaptertext; /* the word for a chapter */
wchar_t *chaptertext; /* the word for a chapter */ wchar_t *sectiontext; /* the word for a section */
wchar_t *sectiontext; /* the word for a section */ wchar_t *apptext; /* the word for an appendix */
wchar_t *apptext; /* the word for an appendix */
}; };
numberstate * numberstate *number_init(void)
number_init (void)
{ {
numberstate *ret = mknew (numberstate); numberstate *ret = mknew(numberstate);
ret->chapternum = 0; ret->chapternum = 0;
ret->appendixnum = -1; ret->appendixnum = -1;
ret->ischapter = 1; ret->ischapter = 1;
ret->oklevel = -1; /* not even in a chapter yet */ ret->oklevel = -1; /* not even in a chapter yet */
ret->maxsectlevel = 32; ret->maxsectlevel = 32;
ret->sectionlevels = mknewa (int, ret->maxsectlevel); ret->sectionlevels = mknewa(int, ret->maxsectlevel);
ret->currentsects = mknewa (paragraph *, ret->maxsectlevel + 1); ret->currentsects = mknewa(paragraph *, ret->maxsectlevel + 1);
memset (ret->currentsects, 0, memset(ret->currentsects, 0,
(ret->maxsectlevel + 1) * sizeof (paragraph *)); (ret->maxsectlevel + 1) * sizeof(paragraph *));
ret->lastsect = NULL; ret->lastsect = NULL;
ret->listitem = -1; ret->listitem = -1;
return ret; return ret;
} }
void void number_free(numberstate * state)
number_free (numberstate * state)
{ {
sfree (state->sectionlevels); sfree(state->sectionlevels);
sfree (state->currentsects); sfree(state->currentsects);
sfree (state); sfree(state);
} }
static void static void dotext(word *** wret, wchar_t * text)
dotext (word *** wret, wchar_t * text)
{ {
word *mnewword = mknew (word); word *mnewword = mknew(word);
mnewword->text = ustrdup (text); mnewword->text = ustrdup(text);
mnewword->type = word_Normal; mnewword->type = word_Normal;
mnewword->alt = NULL; mnewword->alt = NULL;
mnewword->next = NULL; mnewword->next = NULL;
**wret = mnewword; **wret = mnewword;
*wret = &mnewword->next; *wret = &mnewword->next;
} }
static void static void dospace(word *** wret)
dospace (word *** wret)
{ {
word *mnewword = mknew (word); word *mnewword = mknew(word);
mnewword->text = NULL; mnewword->text = NULL;
mnewword->type = word_WhiteSpace; mnewword->type = word_WhiteSpace;
mnewword->alt = NULL; mnewword->alt = NULL;
mnewword->next = NULL; mnewword->next = NULL;
**wret = mnewword; **wret = mnewword;
*wret = &mnewword->next; *wret = &mnewword->next;
} }
static void static void donumber(word *** wret, int num)
donumber (word *** wret, int num)
{ {
wchar_t text[20]; wchar_t text[20];
wchar_t *p = text + sizeof (text); wchar_t *p = text + sizeof(text);
*--p = L'\0'; *--p = L'\0';
while (num != 0) while (num != 0) {
{ assert(p > text);
assert (p > text); *--p = L"0123456789"[num % 10];
*--p = L"0123456789"[num % 10]; num /= 10;
num /= 10;
} }
dotext (wret, p); dotext(wret, p);
} }
static void static void doanumber(word *** wret, int num)
doanumber (word *** wret, int num)
{ {
wchar_t text[20]; wchar_t text[20];
wchar_t *p; wchar_t *p;
int nletters, aton; int nletters, aton;
nletters = 1; nletters = 1;
aton = 25; aton = 25;
while (num > aton) while (num > aton) {
{ nletters++;
nletters++; num -= aton + 1;
num -= aton + 1; if (aton < INT_MAX / 26)
if (aton < INT_MAX / 26) aton = (aton + 1) * 26 - 1;
aton = (aton + 1) * 26 - 1; else
else aton = INT_MAX;
aton = INT_MAX;
} }
p = text + sizeof (text); p = text + sizeof(text);
*--p = L'\0'; *--p = L'\0';
while (nletters--) while (nletters--) {
{ assert(p > text);
assert (p > text); *--p = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num % 26];
*--p = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num % 26]; num /= 26;
num /= 26;
} }
dotext (wret, p); dotext(wret, p);
} }
void void number_cfg(numberstate * state, paragraph * source)
number_cfg (numberstate * state, paragraph * source)
{ {
/* /*
* Defaults * Defaults
*/ */
state->chaptertext = L"Chapter"; state->chaptertext = L"Chapter";
state->sectiontext = L"Section"; state->sectiontext = L"Section";
state->apptext = L"Appendix"; state->apptext = L"Appendix";
for (; source; source = source->next) for (; source; source = source->next) {
{ if (source->type == para_Config) {
if (source->type == para_Config) if (!ustricmp(source->keyword, L"chapter")) {
{ state->chaptertext = uadv(source->keyword);
if (!ustricmp (source->keyword, L"chapter")) } else if (!ustricmp(source->keyword, L"section")) {
{ state->sectiontext = uadv(source->keyword);
state->chaptertext = uadv (source->keyword); } else if (!ustricmp(source->keyword, L"appendix")) {
} state->apptext = uadv(source->keyword);
else if (!ustricmp (source->keyword, L"section")) }
{ }
state->sectiontext = uadv (source->keyword);
}
else if (!ustricmp (source->keyword, L"appendix"))
{
state->apptext = uadv (source->keyword);
}
}
} }
} }
word * word *number_mktext(numberstate * state, paragraph * p, wchar_t * category,
number_mktext (numberstate * state, paragraph * p, wchar_t * category, int prev, int *errflag)
int prev, int *errflag)
{ {
word *ret = NULL; word *ret = NULL;
word **ret2 = &ret; word **ret2 = &ret;
word **pret = &ret; word **pret = &ret;
int i, level; int i, level;
level = -2; /* default for non-section-heading */ level = -2; /* default for non-section-heading */
switch (p->type) switch (p->type) {
{
case para_Chapter: case para_Chapter:
state->chapternum++; state->chapternum++;
for (i = 0; i < state->maxsectlevel; i++) for (i = 0; i < state->maxsectlevel; i++)
state->sectionlevels[i] = 0; state->sectionlevels[i] = 0;
dotext (&pret, category ? category : state->chaptertext); dotext(&pret, category ? category : state->chaptertext);
dospace (&pret); dospace(&pret);
ret2 = pret; ret2 = pret;
donumber (&pret, state->chapternum); donumber(&pret, state->chapternum);
state->ischapter = 1; state->ischapter = 1;
state->oklevel = 0; state->oklevel = 0;
level = -1; level = -1;
break; break;
case para_Heading: case para_Heading:
case para_Subsect: case para_Subsect:
level = (p->type == para_Heading ? 0 : p->aux); level = (p->type == para_Heading ? 0 : p->aux);
if (level > state->oklevel) if (level > state->oklevel) {
{ error(err_sectjump, &p->fpos);
error (err_sectjump, &p->fpos); *errflag = TRUE;
*errflag = TRUE; ret = NULL;
ret = NULL; break;
break; }
} state->oklevel = level + 1;
state->oklevel = level + 1; if (state->maxsectlevel <= level) {
if (state->maxsectlevel <= level) state->maxsectlevel = level + 32;
{ state->sectionlevels = resize(state->sectionlevels,
state->maxsectlevel = level + 32; state->maxsectlevel);
state->sectionlevels = resize (state->sectionlevels, }
state->maxsectlevel); state->sectionlevels[level]++;
} for (i = level + 1; i < state->maxsectlevel; i++)
state->sectionlevels[level]++; state->sectionlevels[i] = 0;
for (i = level + 1; i < state->maxsectlevel; i++) dotext(&pret, category ? category : state->sectiontext);
state->sectionlevels[i] = 0; dospace(&pret);
dotext (&pret, category ? category : state->sectiontext); ret2 = pret;
dospace (&pret); if (state->ischapter)
ret2 = pret; donumber(&pret, state->chapternum);
if (state->ischapter) else
donumber (&pret, state->chapternum); doanumber(&pret, state->appendixnum);
else for (i = 0; i <= level; i++) {
doanumber (&pret, state->appendixnum); dotext(&pret, L".");
for (i = 0; i <= level; i++) if (state->sectionlevels[i] == 0)
{ state->sectionlevels[i] = 1;
dotext (&pret, L"."); donumber(&pret, state->sectionlevels[i]);
if (state->sectionlevels[i] == 0) }
state->sectionlevels[i] = 1; break;
donumber (&pret, state->sectionlevels[i]);
}
break;
case para_Appendix: case para_Appendix:
state->appendixnum++; state->appendixnum++;
for (i = 0; i < state->maxsectlevel; i++) for (i = 0; i < state->maxsectlevel; i++)
state->sectionlevels[i] = 0; state->sectionlevels[i] = 0;
dotext (&pret, category ? category : state->apptext); dotext(&pret, category ? category : state->apptext);
dospace (&pret); dospace(&pret);
ret2 = pret; ret2 = pret;
doanumber (&pret, state->appendixnum); doanumber(&pret, state->appendixnum);
state->ischapter = 0; state->ischapter = 0;
state->oklevel = 0; state->oklevel = 0;
level = -1; level = -1;
break; break;
case para_UnnumberedChapter: case para_UnnumberedChapter:
level = -1; level = -1;
break; break;
case para_NumberedList: case para_NumberedList:
ret2 = pret; ret2 = pret;
if (prev != para_NumberedList) if (prev != para_NumberedList)
state->listitem = 0; state->listitem = 0;
state->listitem++; state->listitem++;
donumber (&pret, state->listitem); donumber(&pret, state->listitem);
break; break;
} }
/* /*
* Now set up parent, child and sibling links. * Now set up parent, child and sibling links.
*/ */
p->parent = p->child = p->sibling = NULL; p->parent = p->child = p->sibling = NULL;
if (level != -2) if (level != -2) {
{ if (state->currentsects[level + 1])
if (state->currentsects[level + 1]) state->currentsects[level + 1]->sibling = p;
state->currentsects[level + 1]->sibling = p; if (level >= 0 && state->currentsects[level]) {
if (level >= 0 && state->currentsects[level]) p->parent = state->currentsects[level];
{ if (!state->currentsects[level]->child)
p->parent = state->currentsects[level]; state->currentsects[level]->child = p;
if (!state->currentsects[level]->child) }
state->currentsects[level]->child = p; state->currentsects[level + 1] = state->lastsect = p;
} for (i = level + 2; i < state->maxsectlevel + 1; i++)
state->currentsects[level + 1] = state->lastsect = p; state->currentsects[i] = NULL;
for (i = level + 2; i < state->maxsectlevel + 1; i++) } else {
state->currentsects[i] = NULL; p->parent = state->lastsect;
}
else
{
p->parent = state->lastsect;
} }
p->kwtext2 = *ret2; p->kwtext2 = *ret2;
return ret; return ret;
} }

View file

@ -10,218 +10,217 @@
/* /*
* Error flags * Error flags
*/ */
#define PREFIX 0x0001 /* give `halibut:' prefix */ #define PREFIX 0x0001 /* give `halibut:' prefix */
#define FILEPOS 0x0002 /* give file position prefix */ #define FILEPOS 0x0002 /* give file position prefix */
static void static void do_error(int code, va_list ap)
do_error (int code, va_list ap)
{ {
char error[1024]; char error[1024];
char auxbuf[256]; char auxbuf[256];
char *sp, *sp2; char *sp, *sp2;
wchar_t *wsp; wchar_t *wsp;
filepos fpos, fpos2; filepos fpos, fpos2;
int flags; int flags;
switch (code) switch (code) {
{ case err_nomemory: /* no arguments */
case err_nomemory: /* no arguments */ sprintf(error, "out of memory");
sprintf (error, "out of memory"); flags = PREFIX;
flags = PREFIX; break;
break;
case err_optnoarg: case err_optnoarg:
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
sprintf (error, "option `-%.200s' requires an argument", sp); sprintf(error, "option `-%.200s' requires an argument", sp);
flags = PREFIX; flags = PREFIX;
break; break;
case err_nosuchopt: case err_nosuchopt:
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
sprintf (error, "unrecognised option `-%.200s'", sp); sprintf(error, "unrecognised option `-%.200s'", sp);
flags = PREFIX; flags = PREFIX;
break; break;
case err_noinput: /* no arguments */ case err_noinput: /* no arguments */
sprintf (error, "no input files"); sprintf(error, "no input files");
flags = PREFIX; flags = PREFIX;
break; break;
case err_cantopen: case err_cantopen:
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
sprintf (error, "unable to open input file `%.200s'", sp); sprintf(error, "unable to open input file `%.200s'", sp);
flags = PREFIX; flags = PREFIX;
break; break;
case err_nodata: /* no arguments */ case err_nodata: /* no arguments */
sprintf (error, "no data in input files"); sprintf(error, "no data in input files");
flags = PREFIX; flags = PREFIX;
break; break;
case err_brokencodepara: case err_brokencodepara:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "every line of a code paragraph should begin `\\c'"); sprintf(error,
flags = FILEPOS; "every line of a code paragraph should begin `\\c'");
break; flags = FILEPOS;
break;
case err_kwunclosed: case err_kwunclosed:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected `}' after paragraph keyword"); sprintf(error, "expected `}' after paragraph keyword");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_kwexpected: case err_kwexpected:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected a paragraph keyword"); sprintf(error, "expected a paragraph keyword");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_kwillegal: case err_kwillegal:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected no paragraph keyword"); sprintf(error, "expected no paragraph keyword");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_kwtoomany: case err_kwtoomany:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected only one paragraph keyword"); sprintf(error, "expected only one paragraph keyword");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_bodyillegal: case err_bodyillegal:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected no text after paragraph keyword"); sprintf(error, "expected no text after paragraph keyword");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_badparatype: case err_badparatype:
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "command `%.200s' unrecognised at start of" sprintf(error, "command `%.200s' unrecognised at start of"
" paragraph", sp); " paragraph", sp);
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_badmidcmd: case err_badmidcmd:
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "command `%.200s' unexpected in mid-paragraph", sp); sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp);
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_unexbrace: case err_unexbrace:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "brace character unexpected in mid-paragraph"); sprintf(error, "brace character unexpected in mid-paragraph");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_explbr: case err_explbr:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected `{' after command"); sprintf(error, "expected `{' after command");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_commenteof: case err_commenteof:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "end of file unexpected inside `\\#{...}' comment"); sprintf(error, "end of file unexpected inside `\\#{...}' comment");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_kwexprbr: case err_kwexprbr:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected `}' after cross-reference"); sprintf(error, "expected `}' after cross-reference");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_missingrbrace: case err_missingrbrace:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "unclosed braces at end of paragraph"); sprintf(error, "unclosed braces at end of paragraph");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_nestedstyles: case err_nestedstyles:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "unable to nest text styles"); sprintf(error, "unable to nest text styles");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_nestedindex: case err_nestedindex:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "unable to nest index markings"); sprintf(error, "unable to nest index markings");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_nosuchkw: case err_nosuchkw:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
sprintf (error, "unable to resolve cross-reference to `%.200s'", sp); sprintf(error, "unable to resolve cross-reference to `%.200s'",
flags = FILEPOS; sp);
break; flags = FILEPOS;
break;
case err_multiBR: case err_multiBR:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
sprintf (error, "multiple `\\BR' entries given for `%.200s'", sp); sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp);
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_nosuchidxtag: case err_nosuchidxtag:
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
sprintf (error, "`\\IM' on unknown index tag `%.200s'", sp); sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp);
flags = 0; flags = 0;
/* FIXME: need to get a filepos to here somehow */ /* FIXME: need to get a filepos to here somehow */
break; break;
case err_cantopenw: case err_cantopenw:
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
sprintf (error, "unable to open output file `%.200s'", sp); sprintf(error, "unable to open output file `%.200s'", sp);
flags = PREFIX; flags = PREFIX;
break; break;
case err_macroexists: case err_macroexists:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
sprintf (error, "macro `%.200s' already defined", sp); sprintf(error, "macro `%.200s' already defined", sp);
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_sectjump: case err_sectjump:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sprintf (error, "expected higher heading levels before this one"); sprintf(error, "expected higher heading levels before this one");
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_winhelp_ctxclash: case err_winhelp_ctxclash:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
sp2 = va_arg (ap, char *); sp2 = va_arg(ap, char *);
sprintf (error, "Windows Help context id `%.200s' clashes with " sprintf(error, "Windows Help context id `%.200s' clashes with "
"previously defined `%.200s'", sp, sp2); "previously defined `%.200s'", sp, sp2);
flags = FILEPOS; flags = FILEPOS;
break; break;
case err_multikw: case err_multikw:
fpos = *va_arg (ap, filepos *); fpos = *va_arg(ap, filepos *);
fpos2 = *va_arg (ap, filepos *); fpos2 = *va_arg(ap, filepos *);
wsp = va_arg (ap, wchar_t *); wsp = va_arg(ap, wchar_t *);
sp = ustrtoa (wsp, auxbuf, sizeof (auxbuf)); sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf));
sprintf (error, "paragraph keyword `%.200s' already defined at ", sp); sprintf(error, "paragraph keyword `%.200s' already defined at ",
sprintf (error + strlen (error), "%s:%d", fpos2.filename, fpos2.line); sp);
flags = FILEPOS; sprintf(error + strlen(error), "%s:%d", fpos2.filename,
break; fpos2.line);
flags = FILEPOS;
break;
case err_whatever: case err_whatever:
sp = va_arg (ap, char *); sp = va_arg(ap, char *);
vsprintf (error, sp, ap); vsprintf(error, sp, ap);
flags = PREFIX; flags = PREFIX;
break; break;
} }
if (flags & PREFIX) if (flags & PREFIX)
fputs ("halibut: ", stderr); fputs("halibut: ", stderr);
if (flags & FILEPOS) if (flags & FILEPOS) {
{ fprintf(stderr, "%s:%d:", fpos.filename, fpos.line);
fprintf (stderr, "%s:%d:", fpos.filename, fpos.line); if (fpos.col > 0)
if (fpos.col > 0) fprintf(stderr, "%d:", fpos.col);
fprintf (stderr, "%d:", fpos.col); fputc(' ', stderr);
fputc (' ', stderr);
} }
fputs (error, stderr); fputs(error, stderr);
fputc ('\n', stderr); fputc('\n', stderr);
} }
void void fatal(int code, ...)
fatal (int code, ...)
{ {
va_list ap; va_list ap;
va_start (ap, code); va_start(ap, code);
do_error (code, ap); do_error(code, ap);
va_end (ap); va_end(ap);
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void void error(int code, ...)
error (int code, ...)
{ {
va_list ap; va_list ap;
va_start (ap, code); va_start(ap, code);
do_error (code, ap); do_error(code, ap);
va_end (ap); va_end(ap);
} }

View file

@ -8,7 +8,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
#define NORETURN __attribute__((__noreturn__)) #define NORETURN __attribute__((__noreturn__))
#else #else
#define NORETURN /* nothing */ #define NORETURN /* nothing */
#endif #endif
#ifndef TRUE #ifndef TRUE
@ -43,133 +43,123 @@ typedef struct macrostack_Tag macrostack;
* Data structure to hold a file name and index, a line and a * Data structure to hold a file name and index, a line and a
* column number, for reporting errors * column number, for reporting errors
*/ */
struct filepos_Tag struct filepos_Tag {
{ char *filename;
char *filename; int line, col;
int line, col;
}; };
/* /*
* Data structure to hold all the file names etc for input * Data structure to hold all the file names etc for input
*/ */
typedef struct pushback_Tag typedef struct pushback_Tag {
{ int chr;
int chr; filepos pos;
filepos pos; } pushback;
} struct input_Tag {
pushback; char **filenames; /* complete list of input files */
struct input_Tag int nfiles; /* how many in the list */
{ FILE *currfp; /* the currently open one */
char **filenames; /* complete list of input files */ int currindex; /* which one is that in the list */
int nfiles; /* how many in the list */ pushback *pushback; /* pushed-back input characters */
FILE *currfp; /* the currently open one */ int npushback, pushbacksize;
int currindex; /* which one is that in the list */ filepos pos;
pushback *pushback; /* pushed-back input characters */ int reportcols; /* report column numbers in errors */
int npushback, pushbacksize; macrostack *stack; /* macro expansions in force */
filepos pos;
int reportcols; /* report column numbers in errors */
macrostack *stack; /* macro expansions in force */
}; };
/* /*
* Data structure to hold the input form of the source, ie a linked * Data structure to hold the input form of the source, ie a linked
* list of paragraphs * list of paragraphs
*/ */
struct paragraph_Tag struct paragraph_Tag {
{ paragraph *next;
paragraph *next; int type;
int type; wchar_t *keyword; /* for most special paragraphs */
wchar_t *keyword; /* for most special paragraphs */ word *words; /* list of words in paragraph */
word *words; /* list of words in paragraph */ int aux; /* number, in a numbered paragraph
int aux; /* number, in a numbered paragraph * or subsection level
* or subsection level */
*/ word *kwtext; /* chapter/section indication */
word *kwtext; /* chapter/section indication */ word *kwtext2; /* numeric-only form of kwtext */
word *kwtext2; /* numeric-only form of kwtext */ filepos fpos;
filepos fpos;
paragraph *parent, *child, *sibling; /* for hierarchy navigation */ paragraph *parent, *child, *sibling; /* for hierarchy navigation */
void *private_data; /* for temp use in backends */ void *private_data; /* for temp use in backends */
}; };
enum enum {
{ para_IM, /* index merge */
para_IM, /* index merge */ para_BR, /* bibliography rewrite */
para_BR, /* bibliography rewrite */ para_Rule, /* random horizontal rule */
para_Rule, /* random horizontal rule */ para_Chapter,
para_Chapter, para_Appendix,
para_Appendix, para_UnnumberedChapter,
para_UnnumberedChapter, para_Heading,
para_Heading, para_Subsect,
para_Subsect, para_Normal,
para_Normal, para_Biblio, /* causes no output unless turned ... */
para_Biblio, /* causes no output unless turned ... */ para_BiblioCited, /* ... into this paragraph type */
para_BiblioCited, /* ... into this paragraph type */ para_Bullet,
para_Bullet, para_NumberedList,
para_NumberedList, para_Code,
para_Code, para_Copyright,
para_Copyright, para_Preamble,
para_Preamble, para_NoCite,
para_NoCite, para_Title,
para_Title, para_VersionID,
para_VersionID, para_Config, /* configuration directive */
para_Config, /* configuration directive */ para_NotParaType /* placeholder value */
para_NotParaType /* placeholder value */
}; };
/* /*
* Data structure to hold an individual word * Data structure to hold an individual word
*/ */
struct word_Tag struct word_Tag {
{ word *next, *alt;
word *next, *alt; int type;
int type; int aux;
int aux; int breaks; /* can a line break after it? */
int breaks; /* can a line break after it? */ wchar_t *text;
wchar_t *text; filepos fpos;
filepos fpos;
}; };
enum enum {
{ /* ORDERING CONSTRAINT: these normal-word types ... */
/* ORDERING CONSTRAINT: these normal-word types ... */ word_Normal,
word_Normal, word_Emph,
word_Emph, word_Code, /* monospaced; `quoted' in text */
word_Code, /* monospaced; `quoted' in text */ word_WeakCode, /* monospaced, normal in text */
word_WeakCode, /* monospaced, normal in text */ /* ... must be in the same order as these space types ... */
/* ... must be in the same order as these space types ... */ word_WhiteSpace, /* text is NULL or ignorable */
word_WhiteSpace, /* text is NULL or ignorable */ word_EmphSpace, /* WhiteSpace when emphasised */
word_EmphSpace, /* WhiteSpace when emphasised */ word_CodeSpace, /* WhiteSpace when code */
word_CodeSpace, /* WhiteSpace when code */ word_WkCodeSpace, /* WhiteSpace when weak code */
word_WkCodeSpace, /* WhiteSpace when weak code */ /* ... and must be in the same order as these quote types ... */
/* ... and must be in the same order as these quote types ... */ word_Quote, /* text is NULL or ignorable */
word_Quote, /* text is NULL or ignorable */ word_EmphQuote, /* Quote when emphasised */
word_EmphQuote, /* Quote when emphasised */ word_CodeQuote, /* (can't happen) */
word_CodeQuote, /* (can't happen) */ word_WkCodeQuote, /* (can't happen) */
word_WkCodeQuote, /* (can't happen) */ /* END ORDERING CONSTRAINT */
/* END ORDERING CONSTRAINT */ word_internal_endattrs,
word_internal_endattrs, word_UpperXref, /* \K */
word_UpperXref, /* \K */ word_LowerXref, /* \k */
word_LowerXref, /* \k */ word_XrefEnd, /* (invisible; no text) */
word_XrefEnd, /* (invisible; no text) */ word_IndexRef, /* (always an invisible one) */
word_IndexRef, /* (always an invisible one) */ word_HyperLink, /* (invisible) */
word_HyperLink, /* (invisible) */ word_HyperEnd /* (also invisible; no text) */
word_HyperEnd /* (also invisible; no text) */
}; };
/* aux values for attributed words */ /* aux values for attributed words */
enum enum {
{ attr_Only = 0x0000, /* a lone word with the attribute */
attr_Only = 0x0000, /* a lone word with the attribute */ attr_First = 0x0001, /* the first of a series */
attr_First = 0x0001, /* the first of a series */ attr_Last = 0x0002, /* the last of a series */
attr_Last = 0x0002, /* the last of a series */ attr_Always = 0x0003, /* any other part of a series */
attr_Always = 0x0003, /* any other part of a series */ attr_mask = 0x0003,
attr_mask = 0x0003,
}; };
/* aux values for quote-type words */ /* aux values for quote-type words */
enum enum {
{ quote_Open = 0x0010,
quote_Open = 0x0010, quote_Close = 0x0020,
quote_Close = 0x0020, quote_mask = 0x0030,
quote_mask = 0x0030,
}; };
#define isattr(x) ( ( (x) > word_Normal && (x) < word_WhiteSpace ) || \ #define isattr(x) ( ( (x) > word_Normal && (x) < word_WhiteSpace ) || \
( (x) > word_WhiteSpace && (x) < word_internal_endattrs ) ) ( (x) > word_WhiteSpace && (x) < word_internal_endattrs ) )
@ -185,63 +175,60 @@ enum
/* /*
* error.c * error.c
*/ */
void void fatal(int code, ...) NORETURN;
fatal (int code, ...) void error(int code, ...);
NORETURN; enum {
void error (int code, ...); err_nomemory, /* out of memory */
enum err_optnoarg, /* option `-%s' requires an argument */
{ err_nosuchopt, /* unrecognised option `-%s' */
err_nomemory, /* out of memory */ err_noinput, /* no input files */
err_optnoarg, /* option `-%s' requires an argument */ err_cantopen, /* unable to open input file `%s' */
err_nosuchopt, /* unrecognised option `-%s' */ err_nodata, /* no data in input files */
err_noinput, /* no input files */ err_brokencodepara, /* line in codepara didn't begin `\c' */
err_cantopen, /* unable to open input file `%s' */ err_kwunclosed, /* expected `}' after keyword */
err_nodata, /* no data in input files */ err_kwillegal, /* paragraph type expects no keyword */
err_brokencodepara, /* line in codepara didn't begin `\c' */ err_kwexpected, /* paragraph type expects a keyword */
err_kwunclosed, /* expected `}' after keyword */ err_kwtoomany, /* paragraph type expects only 1 */
err_kwillegal, /* paragraph type expects no keyword */ err_bodyillegal, /* paragraph type expects only kws! */
err_kwexpected, /* paragraph type expects a keyword */ err_badparatype, /* invalid command at start of para */
err_kwtoomany, /* paragraph type expects only 1 */ err_badmidcmd, /* invalid command in mid-para */
err_bodyillegal, /* paragraph type expects only kws! */ err_unexbrace, /* unexpected brace */
err_badparatype, /* invalid command at start of para */ err_explbr, /* expected `{' after command */
err_badmidcmd, /* invalid command in mid-para */ err_commenteof, /* EOF inside braced comment */
err_unexbrace, /* unexpected brace */ err_kwexprbr, /* expected `}' after cross-ref */
err_explbr, /* expected `{' after command */ err_missingrbrace, /* unclosed braces at end of para */
err_commenteof, /* EOF inside braced comment */ err_nestedstyles, /* unable to nest text styles */
err_kwexprbr, /* expected `}' after cross-ref */ err_nestedindex, /* unable to nest `\i' thingys */
err_missingrbrace, /* unclosed braces at end of para */ err_nosuchkw, /* unresolved cross-reference */
err_nestedstyles, /* unable to nest text styles */ err_multiBR, /* multiple \BRs on same keyword */
err_nestedindex, /* unable to nest `\i' thingys */ err_nosuchidxtag, /* \IM on unknown index tag (warning) */
err_nosuchkw, /* unresolved cross-reference */ err_cantopenw, /* can't open output file for write */
err_multiBR, /* multiple \BRs on same keyword */ err_macroexists, /* this macro already exists */
err_nosuchidxtag, /* \IM on unknown index tag (warning) */ err_sectjump, /* jump a heading level, eg \C -> \S */
err_cantopenw, /* can't open output file for write */ err_winhelp_ctxclash, /* WinHelp context ID hash clash */
err_macroexists, /* this macro already exists */ err_multikw, /* keyword clash in sections */
err_sectjump, /* jump a heading level, eg \C -> \S */ err_whatever /* random error of another type */
err_winhelp_ctxclash, /* WinHelp context ID hash clash */ };
err_multikw, /* keyword clash in sections */
err_whatever /* random error of another type */
};
/* /*
* malloc.c * malloc.c
*/ */
#ifdef LOGALLOC #ifdef LOGALLOC
void *smalloc (char *file, int line, int size); void *smalloc(char *file, int line, int size);
void *srealloc (char *file, int line, void *p, int size); void *srealloc(char *file, int line, void *p, int size);
void sfree (char *file, int line, void *p); void sfree(char *file, int line, void *p);
#define smalloc(x) smalloc(__FILE__, __LINE__, x) #define smalloc(x) smalloc(__FILE__, __LINE__, x)
#define srealloc(x, y) srealloc(__FILE__, __LINE__, x, y) #define srealloc(x, y) srealloc(__FILE__, __LINE__, x, y)
#define sfree(x) sfree(__FILE__, __LINE__, x) #define sfree(x) sfree(__FILE__, __LINE__, x)
#else #else
void *smalloc (int size); void *smalloc(int size);
void *srealloc (void *p, int size); void *srealloc(void *p, int size);
void sfree (void *p); void sfree(void *p);
#endif #endif
void free_word_list (word * w); void free_word_list(word * w);
void free_para_list (paragraph * p); void free_para_list(paragraph * p);
word *dup_word_list (word * w); word *dup_word_list(word * w);
char *dupstr (char *s); char *dupstr(char *s);
#define mknew(type) ( (type *) smalloc (sizeof (type)) ) #define mknew(type) ( (type *) smalloc (sizeof (type)) )
#define mknewa(type, number) ( (type *) smalloc ((number) * sizeof (type)) ) #define mknewa(type, number) ( (type *) smalloc ((number) * sizeof (type)) )
@ -251,110 +238,104 @@ fatal (int code, ...)
/* /*
* ustring.c * ustring.c
*/ */
wchar_t *ustrdup (wchar_t * s); wchar_t *ustrdup(wchar_t * s);
char *ustrtoa (wchar_t * s, char *outbuf, int size); char *ustrtoa(wchar_t * s, char *outbuf, int size);
int ustrlen (wchar_t * s); int ustrlen(wchar_t * s);
wchar_t *uadv (wchar_t * s); wchar_t *uadv(wchar_t * s);
wchar_t *ustrcpy (wchar_t * dest, wchar_t * source); wchar_t *ustrcpy(wchar_t * dest, wchar_t * source);
wchar_t utolower (wchar_t); wchar_t utolower(wchar_t);
int ustrcmp (wchar_t * lhs, wchar_t * rhs); int ustrcmp(wchar_t * lhs, wchar_t * rhs);
int ustricmp (wchar_t * lhs, wchar_t * rhs); int ustricmp(wchar_t * lhs, wchar_t * rhs);
int utoi (wchar_t *); int utoi(wchar_t *);
int utob (wchar_t *); int utob(wchar_t *);
int uisdigit (wchar_t); int uisdigit(wchar_t);
wchar_t *ustrlow (wchar_t * s); wchar_t *ustrlow(wchar_t * s);
wchar_t *ustrftime (wchar_t * fmt, struct tm *timespec); wchar_t *ustrftime(wchar_t * fmt, struct tm *timespec);
/* /*
* help.c * help.c
*/ */
void help (void); void usage(void);
void usage (void); void showversion(void);
void showversion (void);
/* /*
* licence.c * licence.c
*/ */
void licence (void); void licence(void);
/* /*
* version.c * version.c
*/ */
const char *const version; const char *const version;
/* /*
* misc.c * misc.c
*/ */
typedef struct stackTag *stack; typedef struct stackTag *stack;
stack stk_new (void); stack stk_new(void);
void stk_free (stack); void stk_free(stack);
void stk_push (stack, void *); void stk_push(stack, void *);
void *stk_pop (stack); void *stk_pop(stack);
typedef struct tagRdstring rdstring; typedef struct tagRdstring rdstring;
struct tagRdstring struct tagRdstring {
{ int pos, size;
int pos, size; wchar_t *text;
wchar_t *text; };
}; typedef struct tagRdstringc rdstringc;
typedef struct tagRdstringc rdstringc; struct tagRdstringc {
struct tagRdstringc int pos, size;
{ char *text;
int pos, size; };
char *text; extern const rdstring empty_rdstring;
}; extern const rdstringc empty_rdstringc;
extern const rdstring empty_rdstring; void rdadd(rdstring * rs, wchar_t c);
extern const rdstringc empty_rdstringc; void rdadds(rdstring * rs, wchar_t * p);
void rdadd (rdstring * rs, wchar_t c); wchar_t *rdtrim(rdstring * rs);
void rdadds (rdstring * rs, wchar_t * p); void rdaddc(rdstringc * rs, char c);
wchar_t *rdtrim (rdstring * rs); void rdaddsc(rdstringc * rs, char *p);
void rdaddc (rdstringc * rs, char c); char *rdtrimc(rdstringc * rs);
void rdaddsc (rdstringc * rs, char *p);
char *rdtrimc (rdstringc * rs);
int compare_wordlists (word * a, word * b); int compare_wordlists(word * a, word * b);
void mark_attr_ends (paragraph * sourceform); void mark_attr_ends(paragraph * sourceform);
typedef struct tagWrappedLine wrappedline; typedef struct tagWrappedLine wrappedline;
struct tagWrappedLine struct tagWrappedLine {
{ wrappedline *next;
wrappedline *next; word *begin, *end; /* first & last words of line */
word *begin, *end; /* first & last words of line */ int nspaces; /* number of whitespaces in line */
int nspaces; /* number of whitespaces in line */ int shortfall; /* how much shorter than max width */
int shortfall; /* how much shorter than max width */ };
}; wrappedline *wrap_para(word *, int, int, int (*)(word *));
wrappedline *wrap_para (word *, int, int, int (*)(word *)); void wrap_free(wrappedline *);
void wrap_free (wrappedline *);
/* /*
* input.c * input.c
*/ */
paragraph *read_input (input * in, indexdata * idx); paragraph *read_input(input * in, indexdata * idx);
/* /*
* keywords.c * keywords.c
*/ */
struct keywordlist_Tag struct keywordlist_Tag {
{ int nkeywords;
int nkeywords; int size;
int size; tree234 *keys; /* sorted by `key' field */
tree234 *keys; /* sorted by `key' field */ word **looseends; /* non-keyword list element numbers */
word **looseends; /* non-keyword list element numbers */ int nlooseends;
int nlooseends; int looseendssize;
int looseendssize; };
}; struct keyword_Tag {
struct keyword_Tag wchar_t *key; /* the keyword itself */
{ word *text; /* "Chapter 2", "Appendix Q"... */
wchar_t *key; /* the keyword itself */ /* (NB: filepos are not set) */
word *text; /* "Chapter 2", "Appendix Q"... */ paragraph *para; /* the paragraph referenced */
/* (NB: filepos are not set) */ };
paragraph *para; /* the paragraph referenced */ keyword *kw_lookup(keywordlist *, wchar_t *);
}; keywordlist *get_keywords(paragraph *);
keyword *kw_lookup (keywordlist *, wchar_t *); void free_keywords(keywordlist *);
keywordlist *get_keywords (paragraph *); void subst_keywords(paragraph *, keywordlist *);
void free_keywords (keywordlist *);
void subst_keywords (paragraph *, keywordlist *);
/* /*
* index.c * index.c
@ -363,76 +344,62 @@ fatal (int code, ...)
/* /*
* Data structure to hold both sides of the index. * Data structure to hold both sides of the index.
*/ */
struct indexdata_Tag struct indexdata_Tag {
{ tree234 *tags; /* holds type `indextag' */
tree234 *tags; /* holds type `indextag' */ tree234 *entries; /* holds type `indexentry' */
tree234 *entries; /* holds type `indexentry' */ };
};
/* /*
* Data structure to hold an index tag (LHS of index). * Data structure to hold an index tag (LHS of index).
*/ */
struct indextag_Tag struct indextag_Tag {
{ wchar_t *name;
wchar_t *name; word *implicit_text;
word *implicit_text; word **explicit_texts;
word **explicit_texts; int nexplicit, explicit_size;
int nexplicit, explicit_size; int nrefs;
int nrefs; indexentry **refs; /* array of entries referenced by tag */
indexentry **refs; /* array of entries referenced by tag */ };
};
/* /*
* Data structure to hold an index entry (RHS of index). * Data structure to hold an index entry (RHS of index).
*/ */
struct indexentry_Tag struct indexentry_Tag {
{ word *text;
word *text; void *backend_data; /* private to back end */
void *backend_data; /* private to back end */ };
};
indexdata *make_index (void); indexdata *make_index(void);
void cleanup_index (indexdata *); void cleanup_index(indexdata *);
/* index_merge takes responsibility for freeing arg 3 iff implicit; never /* index_merge takes responsibility for freeing arg 3 iff implicit; never
* takes responsibility for arg 2 */ * takes responsibility for arg 2 */
void index_merge (indexdata *, int is_explicit, wchar_t *, word *); void index_merge(indexdata *, int is_explicit, wchar_t *, word *);
void build_index (indexdata *); void build_index(indexdata *);
void index_debug (indexdata *); void index_debug(indexdata *);
indextag *index_findtag (indexdata * idx, wchar_t * name); indextag *index_findtag(indexdata * idx, wchar_t * name);
/* /*
* contents.c * contents.c
*/ */
numberstate *number_init (void); numberstate *number_init(void);
void number_cfg (numberstate *, paragraph *); void number_cfg(numberstate *, paragraph *);
word *number_mktext (numberstate *, paragraph *, wchar_t *, int, int *); word *number_mktext(numberstate *, paragraph *, wchar_t *, int, int *);
void number_free (numberstate *); void number_free(numberstate *);
/* /*
* biblio.c * biblio.c
*/ */
void gen_citations (paragraph *, keywordlist *); void gen_citations(paragraph *, keywordlist *);
/* /*
* style.c * style.c
*/ */
struct userstyle_Tag struct userstyle_Tag {
{ };
};
/*
* bk_text.c
*/
void text_backend (paragraph *, keywordlist *, indexdata *);
/* /*
* bk_xhtml.c * bk_xhtml.c
*/ */
void xhtml_backend (paragraph *, keywordlist *, indexdata *); void xhtml_backend(paragraph *, keywordlist *, indexdata *);
/*
* bk_whlp.c
*/
void whlp_backend (paragraph *, keywordlist *, indexdata *);
#endif #endif

View file

@ -5,34 +5,19 @@
#include <stdio.h> #include <stdio.h>
#include "halibut.h" #include "halibut.h"
static char *helptext[] = {
"FIXME: help text goes here",
NULL
};
static char *usagetext[] = { static char *usagetext[] = {
"FIXME: usage text goes here", "halibut.exe file1 [file2 ...]",
NULL NULL
}; };
void void usage(void)
help (void)
{ {
char **p; char **p;
for (p = helptext; *p; p++) for (p = usagetext; *p; p++)
puts (*p); puts(*p);
} }
void void showversion(void)
usage (void)
{ {
char **p; printf("Halibut, %s\n", version);
for (p = usagetext; *p; p++)
puts (*p);
}
void
showversion (void)
{
printf ("Halibut, %s\n", version);
} }

View file

@ -6,59 +6,53 @@
#include <stdlib.h> #include <stdlib.h>
#include "halibut.h" #include "halibut.h"
static int compare_tags (void *av, void *bv); static int compare_tags(void *av, void *bv);
static int compare_entries (void *av, void *bv); static int compare_entries(void *av, void *bv);
indexdata * indexdata *make_index(void)
make_index (void)
{ {
indexdata *ret = mknew (indexdata); indexdata *ret = mknew(indexdata);
ret->tags = newtree234 (compare_tags); ret->tags = newtree234(compare_tags);
ret->entries = newtree234 (compare_entries); ret->entries = newtree234(compare_entries);
return ret; return ret;
} }
static indextag * static indextag *make_indextag(void)
make_indextag (void)
{ {
indextag *ret = mknew (indextag); indextag *ret = mknew(indextag);
ret->name = NULL; ret->name = NULL;
ret->implicit_text = NULL; ret->implicit_text = NULL;
ret->explicit_texts = NULL; ret->explicit_texts = NULL;
ret->nexplicit = ret->explicit_size = ret->nrefs = 0; ret->nexplicit = ret->explicit_size = ret->nrefs = 0;
ret->refs = NULL; ret->refs = NULL;
return ret; return ret;
} }
static int static int compare_tags(void *av, void *bv)
compare_tags (void *av, void *bv)
{ {
indextag *a = (indextag *) av, *b = (indextag *) bv; indextag *a = (indextag *) av, *b = (indextag *) bv;
return ustricmp (a->name, b->name); return ustricmp(a->name, b->name);
} }
static int static int compare_to_find_tag(void *av, void *bv)
compare_to_find_tag (void *av, void *bv)
{ {
wchar_t *a = (wchar_t *) av; wchar_t *a = (wchar_t *) av;
indextag *b = (indextag *) bv; indextag *b = (indextag *) bv;
return ustricmp (a, b->name); return ustricmp(a, b->name);
} }
static int static int compare_entries(void *av, void *bv)
compare_entries (void *av, void *bv)
{ {
indexentry *a = (indexentry *) av, *b = (indexentry *) bv; indexentry *a = (indexentry *) av, *b = (indexentry *) bv;
return compare_wordlists (a->text, b->text); return compare_wordlists(a->text, b->text);
} }
/* /*
* Back-end utility: find the indextag with a given name. * Back-end utility: find the indextag with a given name.
*/ */
indextag * indextag *index_findtag(indexdata * idx, wchar_t * name)
index_findtag (indexdata * idx, wchar_t * name)
{ {
return find234 (idx->tags, name, compare_to_find_tag); return find234(idx->tags, name, compare_to_find_tag);
} }
/* /*
@ -70,76 +64,66 @@ index_findtag (indexdata * idx, wchar_t * name)
* before the explicit ones. * before the explicit ones.
*/ */
void void
index_merge (indexdata * idx, int is_explicit, wchar_t * tags, word * text) index_merge(indexdata * idx, int is_explicit, wchar_t * tags, word * text)
{ {
indextag *t, *existing; indextag *t, *existing;
/* /*
* FIXME: want to warn on overlapping source sets. * FIXME: want to warn on overlapping source sets.
*/ */
for (; *tags; tags = uadv (tags)) for (; *tags; tags = uadv(tags)) {
{ t = make_indextag();
t = make_indextag (); t->name = tags;
t->name = tags; existing = add234(idx->tags, t);
existing = add234 (idx->tags, t); if (existing == t) {
if (existing == t) /*
{ * Duplicate this so we can free it independently.
/* */
* Duplicate this so we can free it independently. t->name = ustrdup(tags);
*/
t->name = ustrdup (tags);
/* /*
* Every tag has an implicit \IM. So if this tag * Every tag has an implicit \IM. So if this tag
* doesn't exist and we're explicit, then we should * doesn't exist and we're explicit, then we should
* warn (and drop it, since it won't be referenced). * warn (and drop it, since it won't be referenced).
*/ */
if (is_explicit) if (is_explicit) {
{ error(err_nosuchidxtag, tags);
error (err_nosuchidxtag, tags); continue;
continue; }
}
/* /*
* Otherwise, this is a new tag with an implicit \IM. * Otherwise, this is a new tag with an implicit \IM.
*/ */
t->implicit_text = text; t->implicit_text = text;
} } else {
else sfree(t);
{ t = existing;
sfree (t); if (!is_explicit) {
t = existing; /*
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
* An implicit \IM for a tag that's had an implicit * differences. And check the tag for case match
* \IM before. FIXME: we should check the text * against the existing tag, likewise.
* against the existing text and warn on */
* differences. And check the tag for case match } else {
* against the existing tag, likewise. /*
*/ * An explicit \IM added to a valid tag. In
} * particular, this removes the implicit \IM if
else * present.
{ */
/* if (t->implicit_text) {
* An explicit \IM added to a valid tag. In free_word_list(t->implicit_text);
* particular, this removes the implicit \IM if t->implicit_text = NULL;
* present. }
*/ if (t->nexplicit >= t->explicit_size) {
if (t->implicit_text) t->explicit_size = t->nexplicit + 8;
{ t->explicit_texts = resize(t->explicit_texts,
free_word_list (t->implicit_text); t->explicit_size);
t->implicit_text = NULL; }
} t->explicit_texts[t->nexplicit++] = text;
if (t->nexplicit >= t->explicit_size) }
{ }
t->explicit_size = t->nexplicit + 8;
t->explicit_texts = resize (t->explicit_texts,
t->explicit_size);
}
t->explicit_texts[t->nexplicit++] = text;
}
}
} }
} }
@ -150,129 +134,112 @@ index_merge (indexdata * idx, int is_explicit, wchar_t * tags, word * text)
* entries in the original 2-3 tree with pointers to the RHS * entries in the original 2-3 tree with pointers to the RHS
* entries. * entries.
*/ */
void void build_index(indexdata * i)
build_index (indexdata * i)
{ {
indextag *t; indextag *t;
word **ta; word **ta;
int ti; int ti;
int j; int j;
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++) for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
{ if (t->implicit_text) {
if (t->implicit_text) t->nrefs = 1;
{ ta = &t->implicit_text;
t->nrefs = 1; } else {
ta = &t->implicit_text; t->nrefs = t->nexplicit;
} ta = t->explicit_texts;
else }
{ if (t->nrefs) {
t->nrefs = t->nexplicit; t->refs = mknewa(indexentry *, t->nrefs);
ta = t->explicit_texts; for (j = 0; j < t->nrefs; j++) {
} indexentry *ent = mknew(indexentry);
if (t->nrefs) ent->text = *ta++;
{ t->refs[j] = add234(i->entries, ent);
t->refs = mknewa (indexentry *, t->nrefs); if (t->refs[j] != ent) /* duplicate */
for (j = 0; j < t->nrefs; j++) sfree(ent);
{ }
indexentry *ent = mknew (indexentry); }
ent->text = *ta++;
t->refs[j] = add234 (i->entries, ent);
if (t->refs[j] != ent) /* duplicate */
sfree (ent);
}
}
} }
} }
void void cleanup_index(indexdata * i)
cleanup_index (indexdata * i)
{ {
indextag *t; indextag *t;
indexentry *ent; indexentry *ent;
int ti; int ti;
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++) for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
{ sfree(t->name);
sfree (t->name); free_word_list(t->implicit_text);
free_word_list (t->implicit_text); sfree(t->explicit_texts);
sfree (t->explicit_texts); sfree(t->refs);
sfree (t->refs); sfree(t);
sfree (t);
} }
freetree234 (i->tags); freetree234(i->tags);
for (ti = 0; (ent = (indexentry *) index234 (i->entries, ti)) != NULL; ti++) for (ti = 0; (ent = (indexentry *) index234(i->entries, ti)) != NULL;
{ ti++) {
sfree (ent); sfree(ent);
} }
freetree234 (i->entries); freetree234(i->entries);
sfree (i); sfree(i);
} }
static void dbg_prtwordlist (int level, word * w); static void dbg_prtwordlist(int level, word * w);
static void dbg_prtmerge (int is_explicit, wchar_t * tag, word * text); static void dbg_prtmerge(int is_explicit, wchar_t * tag, word * text);
void void index_debug(indexdata * i)
index_debug (indexdata * i)
{ {
indextag *t; indextag *t;
indexentry *y; indexentry *y;
int ti; int ti;
int j; int j;
printf ("\nINDEX TAGS\n==========\n\n"); printf("\nINDEX TAGS\n==========\n\n");
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++) for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
{ printf("\n");
printf ("\n"); if (t->implicit_text)
if (t->implicit_text) dbg_prtmerge(0, t->name, t->implicit_text);
dbg_prtmerge (0, t->name, t->implicit_text); for (j = 0; j < t->nexplicit; j++)
for (j = 0; j < t->nexplicit; j++) dbg_prtmerge(1, t->name, t->explicit_texts[j]);
dbg_prtmerge (1, t->name, t->explicit_texts[j]);
} }
printf ("\nINDEX ENTRIES\n=============\n\n"); printf("\nINDEX ENTRIES\n=============\n\n");
for (ti = 0; (y = (indexentry *) index234 (i->entries, ti)) != NULL; ti++) for (ti = 0; (y = (indexentry *) index234(i->entries, ti)) != NULL;
{ ti++) {
printf ("\n"); printf("\n");
printf ("{\n"); printf("{\n");
dbg_prtwordlist (1, y->text); dbg_prtwordlist(1, y->text);
printf ("}\n"); printf("}\n");
} }
} }
static void static void dbg_prtmerge(int is_explicit, wchar_t * tag, word * text)
dbg_prtmerge (int is_explicit, wchar_t * tag, word * text)
{ {
printf ("\\IM: %splicit: \"", is_explicit ? "ex" : "im"); printf("\\IM: %splicit: \"", is_explicit ? "ex" : "im");
for (; *tag; tag++) for (; *tag; tag++)
putchar (*tag); putchar(*tag);
printf ("\" {\n"); printf("\" {\n");
dbg_prtwordlist (1, text); dbg_prtwordlist(1, text);
printf ("}\n"); printf("}\n");
} }
static void static void dbg_prtwordlist(int level, word * w)
dbg_prtwordlist (int level, word * w)
{ {
for (; w; w = w->next) for (; w; w = w->next) {
{ wchar_t *wp;
wchar_t *wp; printf("%*sword %d ", level * 4, "", w->type);
printf ("%*sword %d ", level * 4, "", w->type); if (w->text) {
if (w->text) printf("\"");
{ for (wp = w->text; *wp; wp++)
printf ("\""); putchar(*wp);
for (wp = w->text; *wp; wp++) printf("\"");
putchar (*wp); } else
printf ("\""); printf("(no text)");
} if (w->alt) {
else printf(" alt = {\n");
printf ("(no text)"); dbg_prtwordlist(level + 1, w->alt);
if (w->alt) printf("%*s}", level * 4, "");
{ }
printf (" alt = {\n"); printf("\n");
dbg_prtwordlist (level + 1, w->alt);
printf ("%*s}", level * 4, "");
}
printf ("\n");
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -7,26 +7,23 @@
#include <assert.h> #include <assert.h>
#include "halibut.h" #include "halibut.h"
static int static int kwcmp(void *av, void *bv)
kwcmp (void *av, void *bv)
{ {
const keyword *a = (const keyword *) av; const keyword *a = (const keyword *) av;
const keyword *b = (const keyword *) bv; const keyword *b = (const keyword *) bv;
return ustrcmp (a->key, b->key); return ustrcmp(a->key, b->key);
} }
static int static int kwfind(void *av, void *bv)
kwfind (void *av, void *bv)
{ {
wchar_t *a = (wchar_t *) av; wchar_t *a = (wchar_t *) av;
const keyword *b = (const keyword *) bv; const keyword *b = (const keyword *) bv;
return ustrcmp (a, b->key); return ustrcmp(a, b->key);
} }
keyword * keyword *kw_lookup(keywordlist * kl, wchar_t * str)
kw_lookup (keywordlist * kl, wchar_t * str)
{ {
return find234 (kl->keys, str, kwfind); return find234(kl->keys, str, kwfind);
} }
/* /*
@ -35,145 +32,128 @@ kw_lookup (keywordlist * kl, wchar_t * str)
* collation, last at the top (so that we can Heapsort them when we * collation, last at the top (so that we can Heapsort them when we
* finish). * finish).
*/ */
keywordlist * keywordlist *get_keywords(paragraph * source)
get_keywords (paragraph * source)
{ {
int errors = FALSE; int errors = FALSE;
keywordlist *kl = mknew (keywordlist); keywordlist *kl = mknew(keywordlist);
numberstate *n = number_init (); numberstate *n = number_init();
int prevpara = para_NotParaType; int prevpara = para_NotParaType;
number_cfg (n, source); number_cfg(n, source);
kl->size = 0; kl->size = 0;
kl->keys = newtree234 (kwcmp); kl->keys = newtree234(kwcmp);
kl->nlooseends = kl->looseendssize = 0; kl->nlooseends = kl->looseendssize = 0;
kl->looseends = NULL; kl->looseends = NULL;
for (; source; source = source->next) for (; source; source = source->next) {
{ wchar_t *p, *q;
wchar_t *p, *q; p = q = source->keyword;
p = q = source->keyword;
/* /*
* Look for the section type override (`example', * Look for the section type override (`example',
* `question' or whatever - to replace `chapter' or * `question' or whatever - to replace `chapter' or
* `section' on a per-section basis). * `section' on a per-section basis).
*/ */
if (q) if (q) {
{ q = uadv(q); /* point q at the word beyond */
q = uadv (q); /* point q at the word beyond */ if (!*q)
if (!*q) q = NULL;
q = NULL; }
}
/* /*
* Number the chapter / section / list-item / whatever. * Number the chapter / section / list-item / whatever.
* This also sets up the `parent', `child' and `sibling' * This also sets up the `parent', `child' and `sibling'
* links. * links.
*/ */
source->kwtext = number_mktext (n, source, q, prevpara, &errors); source->kwtext = number_mktext(n, source, q, prevpara, &errors);
prevpara = source->type; prevpara = source->type;
if (p && *p) if (p && *p) {
{ if (source->kwtext || source->type == para_Biblio) {
if (source->kwtext || source->type == para_Biblio) keyword *kw, *ret;
{
keyword *kw, *ret;
kw = mknew (keyword); kw = mknew(keyword);
kw->key = p; kw->key = p;
kw->text = source->kwtext; kw->text = source->kwtext;
kw->para = source; kw->para = source;
ret = add234 (kl->keys, kw); ret = add234(kl->keys, kw);
if (ret != kw) if (ret != kw) {
{ error(err_multikw, &source->fpos, &ret->para->fpos, p);
error (err_multikw, &source->fpos, &ret->para->fpos, p); sfree(kw);
sfree (kw); /* FIXME: what happens to kw->text? Does it leak? */
/* FIXME: what happens to kw->text? Does it leak? */ }
} }
} } else {
} if (kl->nlooseends >= kl->looseendssize) {
else kl->looseendssize = kl->nlooseends + 32;
{ kl->looseends = resize(kl->looseends, kl->looseendssize);
if (kl->nlooseends >= kl->looseendssize) }
{ kl->looseends[kl->nlooseends++] = source->kwtext;
kl->looseendssize = kl->nlooseends + 32; }
kl->looseends = resize (kl->looseends, kl->looseendssize);
}
kl->looseends[kl->nlooseends++] = source->kwtext;
}
} }
number_free (n); number_free(n);
if (errors) if (errors) {
{ free_keywords(kl);
free_keywords (kl); return NULL;
return NULL;
} }
return kl; return kl;
} }
void void free_keywords(keywordlist * kl)
free_keywords (keywordlist * kl)
{ {
keyword *kw; keyword *kw;
while (kl->nlooseends) while (kl->nlooseends)
free_word_list (kl->looseends[--kl->nlooseends]); free_word_list(kl->looseends[--kl->nlooseends]);
sfree (kl->looseends); sfree(kl->looseends);
while ((kw = index234 (kl->keys, 0)) != NULL) while ((kw = index234(kl->keys, 0)) != NULL) {
{ delpos234(kl->keys, 0);
delpos234 (kl->keys, 0); free_word_list(kw->text);
free_word_list (kw->text); sfree(kw);
sfree (kw);
} }
freetree234 (kl->keys); freetree234(kl->keys);
sfree (kl); sfree(kl);
} }
void void subst_keywords(paragraph * source, keywordlist * kl)
subst_keywords (paragraph * source, keywordlist * kl)
{ {
for (; source; source = source->next) for (; source; source = source->next) {
{ word *ptr;
word *ptr; for (ptr = source->words; ptr; ptr = ptr->next) {
for (ptr = source->words; ptr; ptr = ptr->next) if (ptr->type == word_UpperXref || ptr->type == word_LowerXref) {
{ keyword *kw;
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref) word **endptr, *close, *subst;
{
keyword *kw;
word **endptr, *close, *subst;
kw = kw_lookup (kl, ptr->text); kw = kw_lookup(kl, ptr->text);
if (!kw) if (!kw) {
{ error(err_nosuchkw, &ptr->fpos, ptr->text);
error (err_nosuchkw, &ptr->fpos, ptr->text); subst = NULL;
subst = NULL; } else
} subst = dup_word_list(kw->text);
else
subst = dup_word_list (kw->text);
if (subst && ptr->type == word_LowerXref && if (subst && ptr->type == word_LowerXref &&
kw->para->type != para_Biblio && kw->para->type != para_Biblio &&
kw->para->type != para_BiblioCited) kw->para->type != para_BiblioCited)
ustrlow (subst->text); ustrlow(subst->text);
close = mknew (word); close = mknew(word);
close->text = NULL; close->text = NULL;
close->alt = NULL; close->alt = NULL;
close->type = word_XrefEnd; close->type = word_XrefEnd;
close->fpos = ptr->fpos; close->fpos = ptr->fpos;
close->next = ptr->next; close->next = ptr->next;
ptr->next = subst; ptr->next = subst;
for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next) for (endptr = &ptr->next; *endptr;
(*endptr)->fpos = ptr->fpos; endptr = &(*endptr)->next)
(*endptr)->fpos = ptr->fpos;
*endptr = close; *endptr = close;
ptr = close; ptr = close;
} }
} }
} }
} }

View file

@ -5,14 +5,13 @@
#include <stdio.h> #include <stdio.h>
static char *licencetext[] = { static char *licencetext[] = {
"FIXME: licence text goes here", "FIXME: licence text goes here",
NULL NULL
}; };
void void licence(void)
licence (void)
{ {
char **p; char **p;
for (p = licencetext; *p; p++) for (p = licencetext; *p; p++)
puts (*p); puts(*p);
} }

View file

@ -6,338 +6,289 @@
#include <stdlib.h> #include <stdlib.h>
#include "halibut.h" #include "halibut.h"
static void dbg_prtsource (paragraph * sourceform); static void dbg_prtsource(paragraph * sourceform);
static void dbg_prtwordlist (int level, word * w); static void dbg_prtwordlist(int level, word * w);
static void dbg_prtkws (keywordlist * kws); static void dbg_prtkws(keywordlist * kws);
int int main(int argc, char **argv)
main (int argc, char **argv)
{ {
char **infiles; char **infiles;
char *outfile; char *outfile;
int nfiles; int nfiles;
int nogo; int nogo;
int errs; int errs;
int reportcols; int reportcols;
int debug; int debug;
/* /*
* Set up initial (default) parameters. * Set up initial (default) parameters.
*/ */
infiles = mknewa (char *, argc); infiles = mknewa(char *, argc);
outfile = NULL; outfile = NULL;
nfiles = 0; nfiles = 0;
nogo = errs = FALSE; nogo = errs = FALSE;
reportcols = 0; reportcols = 0;
debug = 0; debug = 0;
if (argc == 1) if (argc == 1) {
{ usage();
usage (); exit(EXIT_SUCCESS);
exit (EXIT_SUCCESS);
} }
/* /*
* Parse command line arguments. * Parse command line arguments.
*/ */
while (--argc) while (--argc) {
{ char *p = *++argv;
char *p = *++argv; if (*p == '-') {
if (*p == '-') /*
{ * An option.
/* */
* An option. while (p && *++p) {
*/ char c = *p;
while (p && *++p) switch (c) {
{ case '-':
char c = *p; /*
switch (c) * Long option.
{ */
case '-': {
/* char *opt, *val;
* Long option. opt = p++; /* opt will have _one_ leading - */
*/ while (*p && *p != '=')
{ p++; /* find end of option */
char *opt, *val; if (*p == '=') {
opt = p++; /* opt will have _one_ leading - */ *p++ = '\0';
while (*p && *p != '=') val = p;
p++; /* find end of option */ } else
if (*p == '=') val = NULL;
{ if (!strcmp(opt, "-version")) {
*p++ = '\0'; showversion();
val = p; nogo = TRUE;
} } else if (!strcmp(opt, "-licence") ||
else !strcmp(opt, "-license")) {
val = NULL; licence();
if (!strcmp (opt, "-help")) nogo = TRUE;
{ } else if (!strcmp(opt, "-output")) {
help (); if (!val)
nogo = TRUE; errs = TRUE, error(err_optnoarg, opt);
} else
else if (!strcmp (opt, "-version")) outfile = val;
{ } else if (!strcmp(opt, "-precise")) {
showversion (); reportcols = 1;
nogo = TRUE; } else {
} errs = TRUE, error(err_nosuchopt, opt);
else if (!strcmp (opt, "-licence") || }
!strcmp (opt, "-license")) }
{ p = NULL;
licence (); break;
nogo = TRUE; case 'V':
} case 'L':
else if (!strcmp (opt, "-output")) case 'P':
{ case 'd':
if (!val) /*
errs = TRUE, error (err_optnoarg, opt); * Option requiring no parameter.
else */
outfile = val; switch (c) {
} case 'V':
else if (!strcmp (opt, "-precise")) showversion();
{ nogo = TRUE;
reportcols = 1; break;
} case 'L':
else licence();
{ nogo = TRUE;
errs = TRUE, error (err_nosuchopt, opt); break;
} case 'P':
} reportcols = 1;
p = NULL; break;
break; case 'd':
case 'h': debug = TRUE;
case 'V': break;
case 'L': }
case 'P': break;
case 'd': case 'o':
/* /*
* Option requiring no parameter. * Option requiring parameter.
*/ */
switch (c) p++;
{ if (!*p && argc > 1)
case 'h': --argc, p = *++argv;
help (); else if (!*p) {
nogo = TRUE; char opt[2];
break; opt[0] = c;
case 'V': opt[1] = '\0';
showversion (); errs = TRUE, error(err_optnoarg, opt);
nogo = TRUE; }
break; /*
case 'L': * Now c is the option and p is the parameter.
licence (); */
nogo = TRUE; switch (c) {
break; case 'o':
case 'P': outfile = p;
reportcols = 1; break;
break; }
case 'd': p = NULL; /* prevent continued processing */
debug = TRUE; break;
break; default:
} /*
break; * Unrecognised option.
case 'o': */
/* {
* Option requiring parameter. char opt[2];
*/ opt[0] = c;
p++; opt[1] = '\0';
if (!*p && argc > 1) errs = TRUE, error(err_nosuchopt, opt);
--argc, p = *++argv; }
else if (!*p) }
{ }
char opt[2]; } else {
opt[0] = c; /*
opt[1] = '\0'; * A non-option argument.
errs = TRUE, error (err_optnoarg, opt); */
} infiles[nfiles++] = p;
/* }
* Now c is the option and p is the parameter.
*/
switch (c)
{
case 'o':
outfile = p;
break;
}
p = NULL; /* prevent continued processing */
break;
default:
/*
* Unrecognised option.
*/
{
char opt[2];
opt[0] = c;
opt[1] = '\0';
errs = TRUE, error (err_nosuchopt, opt);
}
}
}
}
else
{
/*
* A non-option argument.
*/
infiles[nfiles++] = p;
}
} }
if (errs) if (errs)
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
if (nogo) if (nogo)
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
/* /*
* Do the work. * Do the work.
*/ */
if (nfiles == 0) if (nfiles == 0) {
{ error(err_noinput);
error (err_noinput); usage();
usage (); exit(EXIT_FAILURE);
exit (EXIT_FAILURE);
} }
{ {
input in; input in;
paragraph *sourceform, *p; paragraph *sourceform, *p;
indexdata *idx; indexdata *idx;
keywordlist *keywords; keywordlist *keywords;
in.filenames = infiles; in.filenames = infiles;
in.nfiles = nfiles; in.nfiles = nfiles;
in.currfp = NULL; in.currfp = NULL;
in.currindex = 0; in.currindex = 0;
in.npushback = in.pushbacksize = 0; in.npushback = in.pushbacksize = 0;
in.pushback = NULL; in.pushback = NULL;
in.reportcols = reportcols; in.reportcols = reportcols;
in.stack = NULL; in.stack = NULL;
idx = make_index (); idx = make_index();
sourceform = read_input (&in, idx); sourceform = read_input(&in, idx);
if (!sourceform) if (!sourceform)
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
sfree (in.pushback); sfree(in.pushback);
mark_attr_ends (sourceform); mark_attr_ends(sourceform);
sfree (infiles); sfree(infiles);
keywords = get_keywords (sourceform); keywords = get_keywords(sourceform);
if (!keywords) if (!keywords)
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
gen_citations (sourceform, keywords); gen_citations(sourceform, keywords);
subst_keywords (sourceform, keywords); subst_keywords(sourceform, keywords);
for (p = sourceform; p; p = p->next) for (p = sourceform; p; p = p->next)
if (p->type == para_IM) if (p->type == para_IM)
index_merge (idx, TRUE, p->keyword, p->words); index_merge(idx, TRUE, p->keyword, p->words);
build_index (idx); build_index(idx);
if (debug) if (debug) {
{ index_debug(idx);
index_debug (idx); dbg_prtkws(keywords);
dbg_prtkws (keywords); dbg_prtsource(sourceform);
dbg_prtsource (sourceform); }
}
text_backend (sourceform, keywords, idx); xhtml_backend(sourceform, keywords, idx);
xhtml_backend (sourceform, keywords, idx);
whlp_backend (sourceform, keywords, idx);
free_para_list (sourceform); free_para_list(sourceform);
free_keywords (keywords); free_keywords(keywords);
cleanup_index (idx); cleanup_index(idx);
} }
return 0; return 0;
} }
static void static void dbg_prtsource(paragraph * sourceform)
dbg_prtsource (paragraph * sourceform)
{ {
/* /*
* Output source form in debugging format. * Output source form in debugging format.
*/ */
paragraph *p; paragraph *p;
for (p = sourceform; p; p = p->next) for (p = sourceform; p; p = p->next) {
{ wchar_t *wp;
wchar_t *wp; printf("para %d ", p->type);
printf ("para %d ", p->type); if (p->keyword) {
if (p->keyword) wp = p->keyword;
{ while (*wp) {
wp = p->keyword; putchar('\"');
while (*wp) for (; *wp; wp++)
{ putchar(*wp);
putchar ('\"'); putchar('\"');
for (; *wp; wp++) if (*++wp)
putchar (*wp); printf(", ");
putchar ('\"'); }
if (*++wp) } else
printf (", "); printf("(no keyword)");
} printf(" {\n");
} dbg_prtwordlist(1, p->words);
else printf("}\n");
printf ("(no keyword)");
printf (" {\n");
dbg_prtwordlist (1, p->words);
printf ("}\n");
} }
} }
static void static void dbg_prtkws(keywordlist * kws)
dbg_prtkws (keywordlist * kws)
{ {
/* /*
* Output keywords in debugging format. * Output keywords in debugging format.
*/ */
int i; int i;
keyword *kw; keyword *kw;
for (i = 0; (kw = index234 (kws->keys, i)) != NULL; i++) for (i = 0; (kw = index234(kws->keys, i)) != NULL; i++) {
{ wchar_t *wp;
wchar_t *wp; printf("keyword ");
printf ("keyword "); wp = kw->key;
wp = kw->key; while (*wp) {
while (*wp) putchar('\"');
{ for (; *wp; wp++)
putchar ('\"'); putchar(*wp);
for (; *wp; wp++) putchar('\"');
putchar (*wp); if (*++wp)
putchar ('\"'); printf(", ");
if (*++wp) }
printf (", "); printf(" {\n");
} dbg_prtwordlist(1, kw->text);
printf (" {\n"); printf("}\n");
dbg_prtwordlist (1, kw->text);
printf ("}\n");
} }
} }
static void static void dbg_prtwordlist(int level, word * w)
dbg_prtwordlist (int level, word * w)
{ {
for (; w; w = w->next) for (; w; w = w->next) {
{ wchar_t *wp;
wchar_t *wp; printf("%*sword %d ", level * 4, "", w->type);
printf ("%*sword %d ", level * 4, "", w->type); if (w->text) {
if (w->text) printf("\"");
{ for (wp = w->text; *wp; wp++)
printf ("\""); putchar(*wp);
for (wp = w->text; *wp; wp++) printf("\"");
putchar (*wp); } else
printf ("\""); printf("(no text)");
} if (w->alt) {
else printf(" alt = {\n");
printf ("(no text)"); dbg_prtwordlist(level + 1, w->alt);
if (w->alt) printf("%*s}", level * 4, "");
{ }
printf (" alt = {\n"); printf("\n");
dbg_prtwordlist (level + 1, w->alt);
printf ("%*s}", level * 4, "");
}
printf ("\n");
} }
} }

View file

@ -1,16 +1,11 @@
OBJS = biblio.o bk_text.o bk_whlp.o bk_xhtml.o contents.o error.o help.o index.o input.o keywords.o licence.o main.o malloc.o misc.o style.o tree234.o ustring.o version.o winhelp.o OBJS = biblio.o bk_xhtml.o contents.o error.o help.o index.o input.o keywords.o licence.o main.o malloc.o misc.o style.o tree234.o ustring.o version.o winhelp.o
LIBS = LIBS =
# -- Programs -- CC = gcc
MAKE = make RM = del
CC = gcc DEFINES = -DVERSION="\"1.0 (NSIS Custom Build)\""
RM = del CFLAGS = -Wall -W $(DEFINES)
LFLAGS = -s
# -- Compilers and linker flags --
DEFINES =
CFLAGS = -Wall -W $(DEFINES)
LFLAGS = -s
all : halibut all : halibut

View file

@ -9,33 +9,28 @@
#ifdef LOGALLOC #ifdef LOGALLOC
#define LOGPARAMS char *file, int line, #define LOGPARAMS char *file, int line,
static FILE *logallocfp = NULL; static FILE *logallocfp = NULL;
static int logline = 2; /* off by 1: `null pointer is' */ static int logline = 2; /* off by 1: `null pointer is' */
static void static void loginc(void)
loginc (void)
{ {
} }
static void static void logallocinit(void)
logallocinit (void)
{ {
if (!logallocfp) if (!logallocfp) {
{ logallocfp = fopen("malloc.log", "w");
logallocfp = fopen ("malloc.log", "w"); if (!logallocfp) {
if (!logallocfp) fprintf(stderr, "panic: unable to open malloc.log\n");
{ exit(10);
fprintf (stderr, "panic: unable to open malloc.log\n"); }
exit (10); setvbuf(logallocfp, NULL, _IOLBF, BUFSIZ);
} fprintf(logallocfp, "null pointer is %p\n", NULL);
setvbuf (logallocfp, NULL, _IOLBF, BUFSIZ);
fprintf (logallocfp, "null pointer is %p\n", NULL);
} }
} }
static void static void logprintf(char *fmt, ...)
logprintf (char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start (ap, fmt); va_start(ap, fmt);
vfprintf (logallocfp, fmt, ap); vfprintf(logallocfp, fmt, ap);
va_end (ap); va_end(ap);
} }
#define LOGPRINT(x) ( logallocinit(), logprintf x ) #define LOGPRINT(x) ( logallocinit(), logprintf x )
@ -50,124 +45,110 @@ logprintf (char *fmt, ...)
* smalloc should guarantee to return a useful pointer - Halibut * smalloc should guarantee to return a useful pointer - Halibut
* can do nothing except die when it's out of memory anyway. * can do nothing except die when it's out of memory anyway.
*/ */
void *(smalloc) (LOGPARAMS int size) void *(smalloc) (LOGPARAMS int size) {
{ void *p;
void *p; LOGINC;
LOGINC; LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size));
LOGPRINT (("%s %d malloc(%ld)", file, line, (long) size)); p = malloc(size);
p = malloc (size); if (!p)
if (!p) fatal(err_nomemory);
fatal (err_nomemory); LOGPRINT((" returns %p\n", p));
LOGPRINT ((" returns %p\n", p)); return p;
return p;
} }
/* /*
* sfree should guaranteeably deal gracefully with freeing NULL * sfree should guaranteeably deal gracefully with freeing NULL
*/ */
void (sfree) (LOGPARAMS void *p) void (sfree) (LOGPARAMS void *p) {
{ if (p) {
if (p) LOGINC;
{ LOGPRINT(("%s %d free(%p)\n", file, line, p));
LOGINC; free(p);
LOGPRINT (("%s %d free(%p)\n", file, line, p));
free (p);
} }
} }
/* /*
* srealloc should guaranteeably be able to realloc NULL * srealloc should guaranteeably be able to realloc NULL
*/ */
void *(srealloc) (LOGPARAMS void *p, int size) void *(srealloc) (LOGPARAMS void *p, int size) {
{ void *q;
void *q; if (p) {
if (p) LOGINC;
{ LOGPRINT(("%s %d realloc(%p,%ld)", file, line, p, (long) size));
LOGINC; q = realloc(p, size);
LOGPRINT (("%s %d realloc(%p,%ld)", file, line, p, (long) size)); LOGPRINT((" returns %p\n", q));
q = realloc (p, size); } else {
LOGPRINT ((" returns %p\n", q)); LOGINC;
LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size));
q = malloc(size);
LOGPRINT((" returns %p\n", q));
} }
else if (!q)
{ fatal(err_nomemory);
LOGINC; return q;
LOGPRINT (("%s %d malloc(%ld)", file, line, (long) size));
q = malloc (size);
LOGPRINT ((" returns %p\n", q));
}
if (!q)
fatal (err_nomemory);
return q;
} }
/* /*
* dupstr is like strdup, but with the never-return-NULL property * dupstr is like strdup, but with the never-return-NULL property
* of smalloc (and also reliably defined in all environments :-) * of smalloc (and also reliably defined in all environments :-)
*/ */
char * char *dupstr(char *s)
dupstr (char *s)
{ {
char *r = smalloc (1 + strlen (s)); char *r = smalloc(1 + strlen(s));
strcpy (r, s); strcpy(r, s);
return r; return r;
} }
/* /*
* Duplicate a linked list of words * Duplicate a linked list of words
*/ */
word * word *dup_word_list(word * w)
dup_word_list (word * w)
{ {
word *head, **eptr = &head; word *head, **eptr = &head;
while (w) while (w) {
{ word *newwd = mknew(word);
word *newwd = mknew (word); *newwd = *w; /* structure copy */
*newwd = *w; /* structure copy */ newwd->text = ustrdup(w->text);
newwd->text = ustrdup (w->text); if (w->alt)
if (w->alt) newwd->alt = dup_word_list(w->alt);
newwd->alt = dup_word_list (w->alt); *eptr = newwd;
*eptr = newwd; newwd->next = NULL;
newwd->next = NULL; eptr = &newwd->next;
eptr = &newwd->next;
w = w->next; w = w->next;
} }
return head; return head;
} }
/* /*
* Free a linked list of words * Free a linked list of words
*/ */
void void free_word_list(word * w)
free_word_list (word * w)
{ {
word *t; word *t;
while (w) while (w) {
{ t = w;
t = w; w = w->next;
w = w->next; sfree(t->text);
sfree (t->text); if (t->alt)
if (t->alt) free_word_list(t->alt);
free_word_list (t->alt); sfree(t);
sfree (t);
} }
} }
/* /*
* Free a linked list of paragraphs * Free a linked list of paragraphs
*/ */
void void free_para_list(paragraph * p)
free_para_list (paragraph * p)
{ {
paragraph *t; paragraph *t;
while (p) while (p) {
{ t = p;
t = p; p = p->next;
p = p->next; sfree(t->keyword);
sfree (t->keyword); free_word_list(t->words);
free_word_list (t->words); sfree(t);
sfree (t);
} }
} }

View file

@ -4,51 +4,45 @@
#include "halibut.h" #include "halibut.h"
struct stackTag struct stackTag {
{ void **data;
void **data; int sp;
int sp; int size;
int size;
}; };
stack stack stk_new(void)
stk_new (void)
{ {
stack s; stack s;
s = mknew (struct stackTag); s = mknew(struct stackTag);
s->sp = 0; s->sp = 0;
s->size = 0; s->size = 0;
s->data = NULL; s->data = NULL;
return s; return s;
} }
void void stk_free(stack s)
stk_free (stack s)
{ {
sfree (s->data); sfree(s->data);
sfree (s); sfree(s);
} }
void void stk_push(stack s, void *item)
stk_push (stack s, void *item)
{ {
if (s->size <= s->sp) if (s->size <= s->sp) {
{ s->size = s->sp + 32;
s->size = s->sp + 32; s->data = resize(s->data, s->size);
s->data = resize (s->data, s->size);
} }
s->data[s->sp++] = item; s->data[s->sp++] = item;
} }
void * void *stk_pop(stack s)
stk_pop (stack s)
{ {
if (s->sp > 0) if (s->sp > 0)
return s->data[--s->sp]; return s->data[--s->sp];
else else
return NULL; return NULL;
} }
/* /*
@ -57,321 +51,281 @@ stk_pop (stack s)
const rdstring empty_rdstring = { 0, 0, NULL }; const rdstring empty_rdstring = { 0, 0, NULL };
const rdstringc empty_rdstringc = { 0, 0, NULL }; const rdstringc empty_rdstringc = { 0, 0, NULL };
void void rdadd(rdstring * rs, wchar_t c)
rdadd (rdstring * rs, wchar_t c)
{ {
if (rs->pos >= rs->size - 1) if (rs->pos >= rs->size - 1) {
{ rs->size = rs->pos + 128;
rs->size = rs->pos + 128; rs->text = resize(rs->text, rs->size);
rs->text = resize (rs->text, rs->size);
} }
rs->text[rs->pos++] = c; rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0; rs->text[rs->pos] = 0;
} }
void void rdadds(rdstring * rs, wchar_t * p)
rdadds (rdstring * rs, wchar_t * p)
{ {
int len = ustrlen (p); int len = ustrlen(p);
if (rs->pos >= rs->size - len) if (rs->pos >= rs->size - len) {
{ rs->size = rs->pos + len + 128;
rs->size = rs->pos + len + 128; rs->text = resize(rs->text, rs->size);
rs->text = resize (rs->text, rs->size);
} }
ustrcpy (rs->text + rs->pos, p); ustrcpy(rs->text + rs->pos, p);
rs->pos += len; rs->pos += len;
} }
wchar_t * wchar_t *rdtrim(rdstring * rs)
rdtrim (rdstring * rs)
{ {
rs->text = resize (rs->text, rs->pos + 1); rs->text = resize(rs->text, rs->pos + 1);
return rs->text; return rs->text;
} }
void void rdaddc(rdstringc * rs, char c)
rdaddc (rdstringc * rs, char c)
{ {
if (rs->pos >= rs->size - 1) if (rs->pos >= rs->size - 1) {
{ rs->size = rs->pos + 128;
rs->size = rs->pos + 128; rs->text = resize(rs->text, rs->size);
rs->text = resize (rs->text, rs->size);
} }
rs->text[rs->pos++] = c; rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0; rs->text[rs->pos] = 0;
} }
void void rdaddsc(rdstringc * rs, char *p)
rdaddsc (rdstringc * rs, char *p)
{ {
int len = strlen (p); int len = strlen(p);
if (rs->pos >= rs->size - len) if (rs->pos >= rs->size - len) {
{ rs->size = rs->pos + len + 128;
rs->size = rs->pos + len + 128; rs->text = resize(rs->text, rs->size);
rs->text = resize (rs->text, rs->size);
} }
strcpy (rs->text + rs->pos, p); strcpy(rs->text + rs->pos, p);
rs->pos += len; rs->pos += len;
} }
char * char *rdtrimc(rdstringc * rs)
rdtrimc (rdstringc * rs)
{ {
rs->text = resize (rs->text, rs->pos + 1); rs->text = resize(rs->text, rs->pos + 1);
return rs->text; return rs->text;
} }
int int compare_wordlists(word * a, word * b)
compare_wordlists (word * a, word * b)
{ {
int t; int t;
while (a && b) while (a && b) {
{ if (a->type != b->type)
if (a->type != b->type) return (a->type < b->type ? -1 : +1); /* FIXME? */
return (a->type < b->type ? -1 : +1); /* FIXME? */ t = a->type;
t = a->type; if ((t != word_Normal && t != word_Code &&
if ((t != word_Normal && t != word_Code && t != word_WeakCode && t != word_Emph) || a->alt || b->alt) {
t != word_WeakCode && t != word_Emph) || a->alt || b->alt) int c;
{ if (a->text && b->text) {
int c; c = ustricmp(a->text, b->text);
if (a->text && b->text) if (c)
{ return c;
c = ustricmp (a->text, b->text); }
if (c) c = compare_wordlists(a->alt, b->alt);
return c; if (c)
} return c;
c = compare_wordlists (a->alt, b->alt); a = a->next;
if (c) b = b->next;
return c; } else {
a = a->next; wchar_t *ap = a->text, *bp = b->text;
b = b->next; while (*ap && *bp) {
} wchar_t ac = utolower(*ap), bc = utolower(*bp);
else if (ac != bc)
{ return (ac < bc ? -1 : +1);
wchar_t *ap = a->text, *bp = b->text; if (!*++ap && a->next && a->next->type == t
while (*ap && *bp) && !a->next->alt)
{ a = a->next, ap = a->text;
wchar_t ac = utolower (*ap), bc = utolower (*bp); if (!*++bp && b->next && b->next->type == t
if (ac != bc) && !b->next->alt)
return (ac < bc ? -1 : +1); b = b->next, bp = b->text;
if (!*++ap && a->next && a->next->type == t && !a->next->alt) }
a = a->next, ap = a->text; if (*ap || *bp)
if (!*++bp && b->next && b->next->type == t && !b->next->alt) return (*ap ? +1 : -1);
b = b->next, bp = b->text; a = a->next;
} b = b->next;
if (*ap || *bp) }
return (*ap ? +1 : -1);
a = a->next;
b = b->next;
}
} }
if (a || b) if (a || b)
return (a ? +1 : -1); return (a ? +1 : -1);
else else
return 0; return 0;
} }
void void mark_attr_ends(paragraph * sourceform)
mark_attr_ends (paragraph * sourceform)
{ {
paragraph *p; paragraph *p;
word *w, *wp; word *w, *wp;
for (p = sourceform; p; p = p->next) for (p = sourceform; p; p = p->next) {
{ wp = NULL;
wp = NULL; for (w = p->words; w; w = w->next) {
for (w = p->words; w; w = w->next) if (isattr(w->type)) {
{ int before = (wp && isattr(wp->type) &&
if (isattr (w->type)) sameattr(wp->type, w->type));
{ int after = (w->next && isattr(w->next->type) &&
int before = (wp && isattr (wp->type) && sameattr(w->next->type, w->type));
sameattr (wp->type, w->type)); w->aux |= (before ?
int after = (w->next && isattr (w->next->type) && (after ? attr_Always : attr_Last) :
sameattr (w->next->type, w->type)); (after ? attr_First : attr_Only));
w->aux |= (before ? }
(after ? attr_Always : attr_Last) : wp = w;
(after ? attr_First : attr_Only)); }
}
wp = w;
}
} }
} }
wrappedline * wrappedline *wrap_para(word * text, int width, int subsequentwidth,
wrap_para (word * text, int width, int subsequentwidth, int (*widthfn) (word *))
int (*widthfn) (word *))
{ {
wrappedline *head = NULL, **ptr = &head; wrappedline *head = NULL, **ptr = &head;
int nwords, wordsize; int nwords, wordsize;
struct wrapword struct wrapword {
{ word *begin, *end;
word *begin, *end; int width;
int width; int spacewidth;
int spacewidth; int cost;
int cost; int nwords;
int nwords; } *wrapwords;
} int i, j, n;
*wrapwords;
int i, j, n;
/* /*
* Break the line up into wrappable components. * Break the line up into wrappable components.
*/ */
nwords = wordsize = 0; nwords = wordsize = 0;
wrapwords = NULL; wrapwords = NULL;
while (text) while (text) {
{ if (nwords >= wordsize) {
if (nwords >= wordsize) wordsize = nwords + 64;
{ wrapwords = srealloc(wrapwords, wordsize * sizeof(*wrapwords));
wordsize = nwords + 64; }
wrapwords = srealloc (wrapwords, wordsize * sizeof (*wrapwords)); wrapwords[nwords].width = 0;
} wrapwords[nwords].begin = text;
wrapwords[nwords].width = 0; while (text) {
wrapwords[nwords].begin = text; wrapwords[nwords].width += widthfn(text);
while (text) wrapwords[nwords].end = text->next;
{ if (text->next && (text->next->type == word_WhiteSpace ||
wrapwords[nwords].width += widthfn (text); text->next->type == word_EmphSpace ||
wrapwords[nwords].end = text->next; text->breaks))
if (text->next && (text->next->type == word_WhiteSpace || break;
text->next->type == word_EmphSpace || text = text->next;
text->breaks)) }
break; if (text && text->next && (text->next->type == word_WhiteSpace ||
text = text->next; text->next->type == word_EmphSpace)) {
} wrapwords[nwords].spacewidth = widthfn(text->next);
if (text && text->next && (text->next->type == word_WhiteSpace || text = text->next;
text->next->type == word_EmphSpace)) } else {
{ wrapwords[nwords].spacewidth = 0;
wrapwords[nwords].spacewidth = widthfn (text->next); }
text = text->next; nwords++;
} if (text)
else text = text->next;
{
wrapwords[nwords].spacewidth = 0;
}
nwords++;
if (text)
text = text->next;
} }
/* /*
* Perform the dynamic wrapping algorithm: work backwards from * Perform the dynamic wrapping algorithm: work backwards from
* nwords-1, determining the optimal wrapping for each terminal * nwords-1, determining the optimal wrapping for each terminal
* subsequence of the paragraph. * subsequence of the paragraph.
*/ */
for (i = nwords; i--;) for (i = nwords; i--;) {
{ int best = -1;
int best = -1; int bestcost = 0;
int bestcost = 0; int cost;
int cost; int linelen = 0, spacewidth = 0;
int linelen = 0, spacewidth = 0; int seenspace;
int seenspace; int thiswidth = (i == 0 ? width : subsequentwidth);
int thiswidth = (i == 0 ? width : subsequentwidth);
j = 0; j = 0;
seenspace = 0; seenspace = 0;
while (i + j < nwords) while (i + j < nwords) {
{ /*
/* * See what happens if we put j+1 words on this line.
* See what happens if we put j+1 words on this line. */
*/ if (spacewidth)
if (spacewidth) seenspace = 1;
seenspace = 1; linelen += spacewidth + wrapwords[i + j].width;
linelen += spacewidth + wrapwords[i + j].width; spacewidth = wrapwords[i + j].spacewidth;
spacewidth = wrapwords[i + j].spacewidth; j++;
j++; if (linelen > thiswidth) {
if (linelen > thiswidth) /*
{ * If we're over the width limit, abandon ship,
/* * _unless_ there is no best-effort yet (which will
* If we're over the width limit, abandon ship, * only happen if the first word is too long all by
* _unless_ there is no best-effort yet (which will * itself).
* only happen if the first word is too long all by */
* itself). if (best > 0)
*/ break;
if (best > 0) }
break; if (i + j == nwords) {
} /*
if (i + j == nwords) * Special case: if we're at the very end of the
{ * paragraph, we don't score penalty points for the
/* * white space left on the line.
* Special case: if we're at the very end of the */
* paragraph, we don't score penalty points for the cost = 0;
* white space left on the line. } else {
*/ cost = (thiswidth - linelen) * (thiswidth - linelen);
cost = 0; cost += wrapwords[i + j].cost;
} }
else /*
{ * We compare bestcost >= cost, not bestcost > cost,
cost = (thiswidth - linelen) * (thiswidth - linelen); * because in cases where the costs are identical we
cost += wrapwords[i + j].cost; * want to try to look like the greedy algorithm,
} * because readers are likely to have spent a lot of
/* * time looking at greedy-wrapped paragraphs and
* We compare bestcost >= cost, not bestcost > cost, * there's no point violating the Principle of Least
* because in cases where the costs are identical we * Surprise if it doesn't actually gain anything.
* want to try to look like the greedy algorithm, */
* because readers are likely to have spent a lot of if (best < 0 || bestcost >= cost) {
* time looking at greedy-wrapped paragraphs and bestcost = cost;
* there's no point violating the Principle of Least best = j;
* Surprise if it doesn't actually gain anything. }
*/ }
if (best < 0 || bestcost >= cost) /*
{ * Now we know the optimal answer for this terminal
bestcost = cost; * subsequence, so put it in wrapwords.
best = j; */
} wrapwords[i].cost = bestcost;
} wrapwords[i].nwords = best;
/*
* Now we know the optimal answer for this terminal
* subsequence, so put it in wrapwords.
*/
wrapwords[i].cost = bestcost;
wrapwords[i].nwords = best;
} }
/* /*
* We've wrapped the paragraph. Now build the output * We've wrapped the paragraph. Now build the output
* `wrappedline' list. * `wrappedline' list.
*/ */
i = 0; i = 0;
while (i < nwords) while (i < nwords) {
{ wrappedline *w = mknew(wrappedline);
wrappedline *w = mknew (wrappedline); *ptr = w;
*ptr = w; ptr = &w->next;
ptr = &w->next; w->next = NULL;
w->next = NULL;
n = wrapwords[i].nwords; n = wrapwords[i].nwords;
w->begin = wrapwords[i].begin; w->begin = wrapwords[i].begin;
w->end = wrapwords[i + n - 1].end; w->end = wrapwords[i + n - 1].end;
/* /*
* Count along the words to find nspaces and shortfall. * Count along the words to find nspaces and shortfall.
*/ */
w->nspaces = 0; w->nspaces = 0;
w->shortfall = width; w->shortfall = width;
for (j = 0; j < n; j++) for (j = 0; j < n; j++) {
{ w->shortfall -= wrapwords[i + j].width;
w->shortfall -= wrapwords[i + j].width; if (j < n - 1 && wrapwords[i + j].spacewidth) {
if (j < n - 1 && wrapwords[i + j].spacewidth) w->nspaces++;
{ w->shortfall -= wrapwords[i + j].spacewidth;
w->nspaces++; }
w->shortfall -= wrapwords[i + j].spacewidth; }
} i += n;
}
i += n;
} }
sfree (wrapwords); sfree(wrapwords);
return head; return head;
} }
void void wrap_free(wrappedline * w)
wrap_free (wrappedline * w)
{ {
while (w) while (w) {
{ wrappedline *t = w->next;
wrappedline *t = w->next; sfree(w);
sfree (w); w = t;
w = t;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -42,18 +42,18 @@ typedef void *(*copyfn234) (void *state, void *element);
* lookups by key will fail: you can only look things up by numeric * lookups by key will fail: you can only look things up by numeric
* index, and you have to use addpos234() and delpos234(). * index, and you have to use addpos234() and delpos234().
*/ */
tree234 *newtree234 (cmpfn234 cmp); tree234 *newtree234(cmpfn234 cmp);
/* /*
* Free a 2-3-4 tree (not including freeing the elements). * Free a 2-3-4 tree (not including freeing the elements).
*/ */
void freetree234 (tree234 * t); void freetree234(tree234 * t);
/* /*
* Add an element e to a sorted 2-3-4 tree t. Returns e on success, * Add an element e to a sorted 2-3-4 tree t. Returns e on success,
* or if an existing element compares equal, returns that. * or if an existing element compares equal, returns that.
*/ */
void *add234 (tree234 * t, void *e); void *add234(tree234 * t, void *e);
/* /*
* Add an element e to an unsorted 2-3-4 tree t. Returns e on * Add an element e to an unsorted 2-3-4 tree t. Returns e on
@ -63,7 +63,7 @@ void *add234 (tree234 * t, void *e);
* Index range can be from 0 to the tree's current element count, * Index range can be from 0 to the tree's current element count,
* inclusive. * inclusive.
*/ */
void *addpos234 (tree234 * t, void *e, int index); void *addpos234(tree234 * t, void *e, int index);
/* /*
* Look up the element at a given numeric index in a 2-3-4 tree. * Look up the element at a given numeric index in a 2-3-4 tree.
@ -83,7 +83,7 @@ void *addpos234 (tree234 * t, void *e, int index);
* consume(p); * consume(p);
* } * }
*/ */
void *index234 (tree234 * t, int index); void *index234(tree234 * t, int index);
/* /*
* Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not
@ -125,15 +125,14 @@ void *index234 (tree234 * t, int index);
* for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;) * for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;)
* consume(p); * consume(p);
*/ */
enum enum {
{ REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE
REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE
}; };
void *find234 (tree234 * t, void *e, cmpfn234 cmp); void *find234(tree234 * t, void *e, cmpfn234 cmp);
void *findrel234 (tree234 * t, void *e, cmpfn234 cmp, int relation); void *findrel234(tree234 * t, void *e, cmpfn234 cmp, int relation);
void *findpos234 (tree234 * t, void *e, cmpfn234 cmp, int *index); void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index);
void *findrelpos234 (tree234 * t, void *e, cmpfn234 cmp, int relation, void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation,
int *index); int *index);
/* /*
* Delete an element e in a 2-3-4 tree. Does not free the element, * Delete an element e in a 2-3-4 tree. Does not free the element,
@ -152,13 +151,13 @@ void *findrelpos234 (tree234 * t, void *e, cmpfn234 cmp, int relation,
* is out of range (delpos234) or the element is already not in the * is out of range (delpos234) or the element is already not in the
* tree (del234) then they return NULL. * tree (del234) then they return NULL.
*/ */
void *del234 (tree234 * t, void *e); void *del234(tree234 * t, void *e);
void *delpos234 (tree234 * t, int index); void *delpos234(tree234 * t, int index);
/* /*
* Return the total element count of a tree234. * Return the total element count of a tree234.
*/ */
int count234 (tree234 * t); int count234(tree234 * t);
/* /*
* Split a tree234 into two valid tree234s. * Split a tree234 into two valid tree234s.
@ -173,8 +172,8 @@ int count234 (tree234 * t);
* in the tree that satisfy the relation are returned; the * in the tree that satisfy the relation are returned; the
* remainder are left. * remainder are left.
*/ */
tree234 *splitpos234 (tree234 * t, int index, int before); tree234 *splitpos234(tree234 * t, int index, int before);
tree234 *split234 (tree234 * t, void *e, cmpfn234 cmp, int rel); tree234 *split234(tree234 * t, void *e, cmpfn234 cmp, int rel);
/* /*
* Join two tree234s together into a single one. * Join two tree234s together into a single one.
@ -188,8 +187,8 @@ tree234 *split234 (tree234 * t, void *e, cmpfn234 cmp, int rel);
* The tree returned is t1 (join234) or t2 (join234r), if the * The tree returned is t1 (join234) or t2 (join234r), if the
* operation is successful. * operation is successful.
*/ */
tree234 *join234 (tree234 * t1, tree234 * t2); tree234 *join234(tree234 * t1, tree234 * t2);
tree234 *join234r (tree234 * t1, tree234 * t2); tree234 *join234r(tree234 * t1, tree234 * t2);
/* /*
* Make a complete copy of a tree234. Element pointers will be * Make a complete copy of a tree234. Element pointers will be
@ -198,6 +197,6 @@ tree234 *join234r (tree234 * t1, tree234 * t2);
* first is private state and the second is the element. A simple * first is private state and the second is the element. A simple
* copy routine probably won't need private state.) * copy routine probably won't need private state.)
*/ */
tree234 *copytree234 (tree234 * t, copyfn234 copyfn, void *copyfnstate); tree234 *copytree234(tree234 * t, copyfn234 copyfn, void *copyfnstate);
#endif /* TREE234_H */ #endif /* TREE234_H */

View file

@ -6,211 +6,187 @@
#include <time.h> #include <time.h>
#include "halibut.h" #include "halibut.h"
wchar_t * wchar_t *ustrdup(wchar_t * s)
ustrdup (wchar_t * s)
{ {
wchar_t *r; wchar_t *r;
if (s) if (s) {
{ r = mknewa(wchar_t, 1 + ustrlen(s));
r = mknewa (wchar_t, 1 + ustrlen (s)); ustrcpy(r, s);
ustrcpy (r, s); } else {
r = mknew(wchar_t);
*r = 0;
} }
else return r;
{ }
r = mknew (wchar_t);
*r = 0; char *ustrtoa(wchar_t * s, char *outbuf, int size)
{
char *p;
if (!s) {
*outbuf = '\0';
return outbuf;
} }
return r; for (p = outbuf; *s && p < outbuf + size; p++, s++)
*p = *s;
if (p < outbuf + size)
*p = '\0';
else
outbuf[size - 1] = '\0';
return outbuf;
} }
char * int ustrlen(wchar_t * s)
ustrtoa (wchar_t * s, char *outbuf, int size)
{ {
char *p; int len = 0;
if (!s) while (*s++)
{ len++;
*outbuf = '\0'; return len;
return outbuf; }
wchar_t *uadv(wchar_t * s)
{
return s + 1 + ustrlen(s);
}
wchar_t *ustrcpy(wchar_t * dest, wchar_t * source)
{
wchar_t *ret = dest;
do {
*dest++ = *source;
} }
for (p = outbuf; *s && p < outbuf + size; p++, s++) while (*source++);
*p = *s; return ret;
if (p < outbuf + size)
*p = '\0';
else
outbuf[size - 1] = '\0';
return outbuf;
} }
int int ustrcmp(wchar_t * lhs, wchar_t * rhs)
ustrlen (wchar_t * s)
{ {
int len = 0; if (!lhs && !rhs)
while (*s++) return 0;
len++; if (!lhs)
return len; return -1;
} if (!rhs)
return +1;
wchar_t * while (*lhs && *rhs && *lhs == *rhs)
uadv (wchar_t * s) lhs++, rhs++;
{ if (*lhs < *rhs)
return s + 1 + ustrlen (s); return -1;
} else if (*lhs > *rhs)
return 1;
wchar_t *
ustrcpy (wchar_t * dest, wchar_t * source)
{
wchar_t *ret = dest;
do
{
*dest++ = *source;
}
while (*source++);
return ret;
}
int
ustrcmp (wchar_t * lhs, wchar_t * rhs)
{
if (!lhs && !rhs)
return 0; return 0;
if (!lhs)
return -1;
if (!rhs)
return +1;
while (*lhs && *rhs && *lhs == *rhs)
lhs++, rhs++;
if (*lhs < *rhs)
return -1;
else if (*lhs > *rhs)
return 1;
return 0;
} }
wchar_t wchar_t utolower(wchar_t c)
utolower (wchar_t c)
{ {
if (c == L'\0') if (c == L'\0')
return c; /* this property needed by ustricmp */ return c; /* this property needed by ustricmp */
/* FIXME: this doesn't even come close */ /* FIXME: this doesn't even come close */
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
c += 'a' - 'A'; c += 'a' - 'A';
return c; return c;
} }
int int ustricmp(wchar_t * lhs, wchar_t * rhs)
ustricmp (wchar_t * lhs, wchar_t * rhs)
{ {
wchar_t lc, rc; wchar_t lc, rc;
while ((lc = utolower (*lhs)) == (rc = utolower (*rhs)) && lc && rc) while ((lc = utolower(*lhs)) == (rc = utolower(*rhs)) && lc && rc)
lhs++, rhs++; lhs++, rhs++;
if (!lc && !rc) if (!lc && !rc)
return 0; return 0;
if (lc < rc) if (lc < rc)
return -1; return -1;
else else
return 1; return 1;
} }
wchar_t * wchar_t *ustrlow(wchar_t * s)
ustrlow (wchar_t * s)
{ {
wchar_t *p = s; wchar_t *p = s;
while (*p) while (*p) {
{ *p = utolower(*p);
*p = utolower (*p); p++;
p++;
} }
return s; return s;
} }
int int utoi(wchar_t * s)
utoi (wchar_t * s)
{ {
int sign = +1; int sign = +1;
int n; int n;
if (*s == L'-') if (*s == L'-') {
{ s++;
s++; sign = -1;
sign = -1;
} }
n = 0; n = 0;
while (*s && *s >= L'0' && *s <= L'9') while (*s && *s >= L'0' && *s <= L'9') {
{ n *= 10;
n *= 10; n += (*s - '0');
n += (*s - '0'); s++;
s++;
} }
return n; return n;
} }
int int utob(wchar_t * s)
utob (wchar_t * s)
{ {
if (!ustricmp (s, L"yes") || !ustricmp (s, L"y") || if (!ustricmp(s, L"yes") || !ustricmp(s, L"y") ||
!ustricmp (s, L"true") || !ustricmp (s, L"t")) !ustricmp(s, L"true") || !ustricmp(s, L"t"))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
int int uisdigit(wchar_t c)
uisdigit (wchar_t c)
{ {
return c >= L'0' && c <= L'9'; return c >= L'0' && c <= L'9';
} }
#define USTRFTIME_DELTA 128 #define USTRFTIME_DELTA 128
wchar_t * wchar_t *ustrftime(wchar_t * wfmt, struct tm * timespec)
ustrftime (wchar_t * wfmt, struct tm * timespec)
{ {
void *blk = NULL; void *blk = NULL;
wchar_t *wblk, *wp; wchar_t *wblk, *wp;
char *fmt, *text, *p; char *fmt, *text, *p;
size_t size = 0; size_t size = 0;
size_t len; size_t len;
/* /*
* strftime has the entertaining property that it returns 0 * strftime has the entertaining property that it returns 0
* _either_ on out-of-space _or_ on successful generation of * _either_ on out-of-space _or_ on successful generation of
* the empty string. Hence we must ensure our format can never * the empty string. Hence we must ensure our format can never
* generate the empty string. Somebody throw a custard pie at * generate the empty string. Somebody throw a custard pie at
* whoever was responsible for that. Please? * whoever was responsible for that. Please?
*/ */
if (wfmt) if (wfmt) {
{ len = ustrlen(wfmt);
len = ustrlen (wfmt); fmt = mknewa(char, 2 + len);
fmt = mknewa (char, 2 + len); ustrtoa(wfmt, fmt + 1, len + 1);
ustrtoa (wfmt, fmt + 1, len + 1); fmt[0] = ' ';
fmt[0] = ' '; } else
} fmt = " %c";
else
fmt = " %c";
while (1) while (1) {
{ size += USTRFTIME_DELTA;
size += USTRFTIME_DELTA; blk = resize((char *) blk, size);
blk = resize ((char *) blk, size); len = strftime((char *) blk, size - 1, fmt, timespec);
len = strftime ((char *) blk, size - 1, fmt, timespec); if (len > 0)
if (len > 0) break;
break;
} }
/* Note: +1 for the terminating 0, -1 for the initial space in fmt */ /* Note: +1 for the terminating 0, -1 for the initial space in fmt */
wblk = resize ((wchar_t *) blk, len); wblk = resize((wchar_t *) blk, len);
text = mknewa (char, len); text = mknewa(char, len);
strftime (text, len, fmt + 1, timespec); strftime(text, len, fmt + 1, timespec);
/* /*
* We operate in the C locale, so this all ought to be kosher * We operate in the C locale, so this all ought to be kosher
* ASCII. If we ever move outside ASCII machines, we may need * ASCII. If we ever move outside ASCII machines, we may need
* to make this more portable... * to make this more portable...
*/ */
for (wp = wblk, p = text; *p; p++, wp++) for (wp = wblk, p = text; *p; p++, wp++)
*wp = *p; *wp = *p;
*wp = 0; *wp = 0;
if (wfmt) if (wfmt)
sfree (fmt); sfree(fmt);
sfree (text); sfree(text);
return wblk; return wblk;
} }

File diff suppressed because it is too large Load diff

View file

@ -9,25 +9,25 @@ typedef struct WHLP_TOPIC_tag *WHLP_TOPIC;
/* /*
* Initialise a new WHlp context and begin accumulating data in it. * Initialise a new WHlp context and begin accumulating data in it.
*/ */
WHLP whlp_new (void); WHLP whlp_new(void);
/* /*
* Close a WHlp context and write out the help file it has created. * Close a WHlp context and write out the help file it has created.
*/ */
void whlp_close (WHLP h, char *filename); void whlp_close(WHLP h, char *filename);
/* /*
* Abandon and free a WHlp context without writing out anything. * Abandon and free a WHlp context without writing out anything.
*/ */
void whlp_abandon (WHLP h); void whlp_abandon(WHLP h);
/* /*
* Specify the title and copyright notice of a help file. Also * Specify the title and copyright notice of a help file. Also
* specify Help macros to be run on loading. * specify Help macros to be run on loading.
*/ */
void whlp_title (WHLP h, char *title); void whlp_title(WHLP h, char *title);
void whlp_copyright (WHLP h, char *copyright); void whlp_copyright(WHLP h, char *copyright);
void whlp_start_macro (WHLP h, char *macro); void whlp_start_macro(WHLP h, char *macro);
/* /*
* Register a help topic. Irritatingly, due to weird phase-order * Register a help topic. Irritatingly, due to weird phase-order
@ -53,13 +53,13 @@ void whlp_start_macro (WHLP h, char *macro);
* On success (i.e. in any circumstance other than a hash clash), a * On success (i.e. in any circumstance other than a hash clash), a
* valid WHLP_TOPIC is returned for later use. * valid WHLP_TOPIC is returned for later use.
*/ */
WHLP_TOPIC whlp_register_topic (WHLP h, char *context_name, char **clash); WHLP_TOPIC whlp_register_topic(WHLP h, char *context_name, char **clash);
/* /*
* Link two topics together in a browse sequence. Automatically * Link two topics together in a browse sequence. Automatically
* takes care of the forward and reverse links. * takes care of the forward and reverse links.
*/ */
void whlp_browse_link (WHLP h, WHLP_TOPIC before, WHLP_TOPIC after); void whlp_browse_link(WHLP h, WHLP_TOPIC before, WHLP_TOPIC after);
/* /*
* After calling whlp_register_topic for all topics, you should * After calling whlp_register_topic for all topics, you should
@ -67,12 +67,12 @@ void whlp_browse_link (WHLP h, WHLP_TOPIC before, WHLP_TOPIC after);
* context names for all anonymous topics. Then you can start * context names for all anonymous topics. Then you can start
* writing actual text. * writing actual text.
*/ */
void whlp_prepare (WHLP h); void whlp_prepare(WHLP h);
/* /*
* Create a link from an index term to a topic. * Create a link from an index term to a topic.
*/ */
void whlp_index_term (WHLP h, char *index, WHLP_TOPIC topic); void whlp_index_term(WHLP h, char *index, WHLP_TOPIC topic);
/* /*
* Call this if you need the id of a topic and you don't already * Call this if you need the id of a topic and you don't already
@ -85,13 +85,13 @@ void whlp_index_term (WHLP h, char *index, WHLP_TOPIC topic);
* *
* Do not call this before calling whlp_prepare(). * Do not call this before calling whlp_prepare().
*/ */
char *whlp_topic_id (WHLP_TOPIC topic); char *whlp_topic_id(WHLP_TOPIC topic);
/* /*
* Call this to specify which help topic will be the first one * Call this to specify which help topic will be the first one
* displayed when the help file is loaded. * displayed when the help file is loaded.
*/ */
void whlp_primary_topic (WHLP h, WHLP_TOPIC topic); void whlp_primary_topic(WHLP h, WHLP_TOPIC topic);
/* /*
* Call this when about to begin writing out the text for a topic. * Call this when about to begin writing out the text for a topic.
@ -101,7 +101,7 @@ void whlp_primary_topic (WHLP h, WHLP_TOPIC topic);
* *
* whlp_begin_topic(helpfile, mytopic, "Title", NULL); * whlp_begin_topic(helpfile, mytopic, "Title", NULL);
*/ */
void whlp_begin_topic (WHLP h, WHLP_TOPIC topic, char *title, ...); void whlp_begin_topic(WHLP h, WHLP_TOPIC topic, char *title, ...);
/* /*
* Call this to set up a font descriptor. You supply the font name, * Call this to set up a font descriptor. You supply the font name,
@ -118,25 +118,23 @@ void whlp_begin_topic (WHLP h, WHLP_TOPIC topic, char *title, ...);
* descriptor you create, but you could work this out just as * descriptor you create, but you could work this out just as
* easily yourself by counting. * easily yourself by counting.
*/ */
enum enum {
{ WHLP_FONT_BOLD = 1,
WHLP_FONT_BOLD = 1, WHLP_FONT_ITALIC = 2,
WHLP_FONT_ITALIC = 2, WHLP_FONT_UNDERLINE = 4,
WHLP_FONT_UNDERLINE = 4, WHLP_FONT_STRIKEOUT = 8,
WHLP_FONT_STRIKEOUT = 8, WHLP_FONT_DOUBLEUND = 16,
WHLP_FONT_DOUBLEUND = 16, WHLP_FONT_SMALLCAPS = 32
WHLP_FONT_SMALLCAPS = 32
}; };
enum enum {
{ WHLP_FONTFAM_FIXED = 1,
WHLP_FONTFAM_FIXED = 1, WHLP_FONTFAM_SERIF = 2,
WHLP_FONTFAM_SERIF = 2, WHLP_FONTFAM_SANS = 3,
WHLP_FONTFAM_SANS = 3, WHLP_FONTFAM_SCRIPT = 4,
WHLP_FONTFAM_SCRIPT = 4, WHLP_FONTFAM_DECOR = 5
WHLP_FONTFAM_DECOR = 5
}; };
int whlp_create_font (WHLP h, char *font, int family, int halfpoints, int whlp_create_font(WHLP h, char *font, int family, int halfpoints,
int rendition, int r, int g, int b); int rendition, int r, int g, int b);
/* /*
* Routines to output paragraphs and actual text (at last). * Routines to output paragraphs and actual text (at last).
@ -148,26 +146,23 @@ int whlp_create_font (WHLP h, char *font, int family, int halfpoints,
* whole paragraph, and finally call whlp_end_para() to finish it * whole paragraph, and finally call whlp_end_para() to finish it
* off. * off.
*/ */
enum enum {
{ WHLP_PARA_SPACEABOVE = 1, WHLP_PARA_SPACEBELOW, WHLP_PARA_SPACELINES,
WHLP_PARA_SPACEABOVE = 1, WHLP_PARA_SPACEBELOW, WHLP_PARA_SPACELINES, WHLP_PARA_LEFTINDENT, WHLP_PARA_RIGHTINDENT, WHLP_PARA_FIRSTLINEINDENT,
WHLP_PARA_LEFTINDENT, WHLP_PARA_RIGHTINDENT, WHLP_PARA_FIRSTLINEINDENT, WHLP_PARA_ALIGNMENT
WHLP_PARA_ALIGNMENT
}; };
enum enum {
{ WHLP_ALIGN_LEFT, WHLP_ALIGN_RIGHT, WHLP_ALIGN_CENTRE
WHLP_ALIGN_LEFT, WHLP_ALIGN_RIGHT, WHLP_ALIGN_CENTRE
}; };
enum enum {
{ WHLP_PARA_SCROLL, WHLP_PARA_NONSCROLL
WHLP_PARA_SCROLL, WHLP_PARA_NONSCROLL
}; };
void whlp_para_attr (WHLP h, int attr_id, int attr_param); void whlp_para_attr(WHLP h, int attr_id, int attr_param);
void whlp_set_tabstop (WHLP h, int tabstop, int alignment); void whlp_set_tabstop(WHLP h, int tabstop, int alignment);
void whlp_begin_para (WHLP h, int para_type); void whlp_begin_para(WHLP h, int para_type);
void whlp_end_para (WHLP h); void whlp_end_para(WHLP h);
void whlp_set_font (WHLP h, int font_id); void whlp_set_font(WHLP h, int font_id);
void whlp_text (WHLP h, char *text); void whlp_text(WHLP h, char *text);
void whlp_start_hyperlink (WHLP h, WHLP_TOPIC target); void whlp_start_hyperlink(WHLP h, WHLP_TOPIC target);
void whlp_end_hyperlink (WHLP h); void whlp_end_hyperlink(WHLP h);
void whlp_tab (WHLP h); void whlp_tab(WHLP h);