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.
Note: This version is modified by Robert Rainwater and Amir Szekely
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,

View file

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

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

View file

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

View file

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

View file

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

View file

@ -6,59 +6,53 @@
#include <stdlib.h>
#include "halibut.h"
static int compare_tags (void *av, void *bv);
static int compare_entries (void *av, void *bv);
static int compare_tags(void *av, void *bv);
static int compare_entries(void *av, void *bv);
indexdata *
make_index (void)
indexdata *make_index(void)
{
indexdata *ret = mknew (indexdata);
ret->tags = newtree234 (compare_tags);
ret->entries = newtree234 (compare_entries);
return ret;
indexdata *ret = mknew(indexdata);
ret->tags = newtree234(compare_tags);
ret->entries = newtree234(compare_entries);
return ret;
}
static indextag *
make_indextag (void)
static indextag *make_indextag(void)
{
indextag *ret = mknew (indextag);
ret->name = NULL;
ret->implicit_text = NULL;
ret->explicit_texts = NULL;
ret->nexplicit = ret->explicit_size = ret->nrefs = 0;
ret->refs = NULL;
return ret;
indextag *ret = mknew(indextag);
ret->name = NULL;
ret->implicit_text = NULL;
ret->explicit_texts = NULL;
ret->nexplicit = ret->explicit_size = ret->nrefs = 0;
ret->refs = NULL;
return ret;
}
static int
compare_tags (void *av, void *bv)
static int compare_tags(void *av, void *bv)
{
indextag *a = (indextag *) av, *b = (indextag *) bv;
return ustricmp (a->name, b->name);
indextag *a = (indextag *) av, *b = (indextag *) bv;
return ustricmp(a->name, b->name);
}
static int
compare_to_find_tag (void *av, void *bv)
static int compare_to_find_tag(void *av, void *bv)
{
wchar_t *a = (wchar_t *) av;
indextag *b = (indextag *) bv;
return ustricmp (a, b->name);
wchar_t *a = (wchar_t *) av;
indextag *b = (indextag *) bv;
return ustricmp(a, b->name);
}
static int
compare_entries (void *av, void *bv)
static int compare_entries(void *av, void *bv)
{
indexentry *a = (indexentry *) av, *b = (indexentry *) bv;
return compare_wordlists (a->text, b->text);
indexentry *a = (indexentry *) av, *b = (indexentry *) bv;
return compare_wordlists(a->text, b->text);
}
/*
* Back-end utility: find the indextag with a given name.
*/
indextag *
index_findtag (indexdata * idx, wchar_t * name)
indextag *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.
*/
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.
*/
for (; *tags; tags = uadv (tags))
{
t = make_indextag ();
t->name = tags;
existing = add234 (idx->tags, t);
if (existing == t)
{
/*
* Duplicate this so we can free it independently.
*/
t->name = ustrdup (tags);
/*
* FIXME: want to warn on overlapping source sets.
*/
for (; *tags; tags = uadv(tags)) {
t = make_indextag();
t->name = tags;
existing = add234(idx->tags, t);
if (existing == t) {
/*
* Duplicate this so we can free it independently.
*/
t->name = ustrdup(tags);
/*
* Every tag has an implicit \IM. So if this tag
* doesn't exist and we're explicit, then we should
* warn (and drop it, since it won't be referenced).
*/
if (is_explicit)
{
error (err_nosuchidxtag, tags);
continue;
}
/*
* Every tag has an implicit \IM. So if this tag
* doesn't exist and we're explicit, then we should
* warn (and drop it, since it won't be referenced).
*/
if (is_explicit) {
error(err_nosuchidxtag, tags);
continue;
}
/*
* Otherwise, this is a new tag with an implicit \IM.
*/
t->implicit_text = text;
}
else
{
sfree (t);
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
* differences. And check the tag for case match
* against the existing tag, likewise.
*/
}
else
{
/*
* An explicit \IM added to a valid tag. In
* particular, this removes the implicit \IM if
* present.
*/
if (t->implicit_text)
{
free_word_list (t->implicit_text);
t->implicit_text = NULL;
}
if (t->nexplicit >= t->explicit_size)
{
t->explicit_size = t->nexplicit + 8;
t->explicit_texts = resize (t->explicit_texts,
t->explicit_size);
}
t->explicit_texts[t->nexplicit++] = text;
}
}
/*
* Otherwise, this is a new tag with an implicit \IM.
*/
t->implicit_text = text;
} else {
sfree(t);
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
* differences. And check the tag for case match
* against the existing tag, likewise.
*/
} else {
/*
* An explicit \IM added to a valid tag. In
* particular, this removes the implicit \IM if
* present.
*/
if (t->implicit_text) {
free_word_list(t->implicit_text);
t->implicit_text = NULL;
}
if (t->nexplicit >= t->explicit_size) {
t->explicit_size = t->nexplicit + 8;
t->explicit_texts = 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.
*/
void
build_index (indexdata * i)
void build_index(indexdata * i)
{
indextag *t;
word **ta;
int ti;
int j;
indextag *t;
word **ta;
int ti;
int j;
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++)
{
if (t->implicit_text)
{
t->nrefs = 1;
ta = &t->implicit_text;
}
else
{
t->nrefs = t->nexplicit;
ta = t->explicit_texts;
}
if (t->nrefs)
{
t->refs = mknewa (indexentry *, t->nrefs);
for (j = 0; j < t->nrefs; j++)
{
indexentry *ent = mknew (indexentry);
ent->text = *ta++;
t->refs[j] = add234 (i->entries, ent);
if (t->refs[j] != ent) /* duplicate */
sfree (ent);
}
}
for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
if (t->implicit_text) {
t->nrefs = 1;
ta = &t->implicit_text;
} else {
t->nrefs = t->nexplicit;
ta = t->explicit_texts;
}
if (t->nrefs) {
t->refs = mknewa(indexentry *, t->nrefs);
for (j = 0; j < t->nrefs; j++) {
indexentry *ent = mknew(indexentry);
ent->text = *ta++;
t->refs[j] = add234(i->entries, ent);
if (t->refs[j] != ent) /* duplicate */
sfree(ent);
}
}
}
}
void
cleanup_index (indexdata * i)
void cleanup_index(indexdata * i)
{
indextag *t;
indexentry *ent;
int ti;
indextag *t;
indexentry *ent;
int ti;
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++)
{
sfree (t->name);
free_word_list (t->implicit_text);
sfree (t->explicit_texts);
sfree (t->refs);
sfree (t);
for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
sfree(t->name);
free_word_list(t->implicit_text);
sfree(t->explicit_texts);
sfree(t->refs);
sfree(t);
}
freetree234 (i->tags);
for (ti = 0; (ent = (indexentry *) index234 (i->entries, ti)) != NULL; ti++)
{
sfree (ent);
freetree234(i->tags);
for (ti = 0; (ent = (indexentry *) index234(i->entries, ti)) != NULL;
ti++) {
sfree(ent);
}
freetree234 (i->entries);
sfree (i);
freetree234(i->entries);
sfree(i);
}
static void dbg_prtwordlist (int level, word * w);
static void dbg_prtmerge (int is_explicit, wchar_t * tag, word * text);
static void dbg_prtwordlist(int level, word * w);
static void dbg_prtmerge(int is_explicit, wchar_t * tag, word * text);
void
index_debug (indexdata * i)
void index_debug(indexdata * i)
{
indextag *t;
indexentry *y;
int ti;
int j;
indextag *t;
indexentry *y;
int ti;
int j;
printf ("\nINDEX TAGS\n==========\n\n");
for (ti = 0; (t = (indextag *) index234 (i->tags, ti)) != NULL; ti++)
{
printf ("\n");
if (t->implicit_text)
dbg_prtmerge (0, t->name, t->implicit_text);
for (j = 0; j < t->nexplicit; j++)
dbg_prtmerge (1, t->name, t->explicit_texts[j]);
printf("\nINDEX TAGS\n==========\n\n");
for (ti = 0; (t = (indextag *) index234(i->tags, ti)) != NULL; ti++) {
printf("\n");
if (t->implicit_text)
dbg_prtmerge(0, t->name, t->implicit_text);
for (j = 0; j < t->nexplicit; j++)
dbg_prtmerge(1, t->name, t->explicit_texts[j]);
}
printf ("\nINDEX ENTRIES\n=============\n\n");
for (ti = 0; (y = (indexentry *) index234 (i->entries, ti)) != NULL; ti++)
{
printf ("\n");
printf ("{\n");
dbg_prtwordlist (1, y->text);
printf ("}\n");
printf("\nINDEX ENTRIES\n=============\n\n");
for (ti = 0; (y = (indexentry *) index234(i->entries, ti)) != NULL;
ti++) {
printf("\n");
printf("{\n");
dbg_prtwordlist(1, y->text);
printf("}\n");
}
}
static void
dbg_prtmerge (int is_explicit, wchar_t * tag, word * text)
static void dbg_prtmerge(int is_explicit, wchar_t * tag, word * text)
{
printf ("\\IM: %splicit: \"", is_explicit ? "ex" : "im");
for (; *tag; tag++)
putchar (*tag);
printf ("\" {\n");
dbg_prtwordlist (1, text);
printf ("}\n");
printf("\\IM: %splicit: \"", is_explicit ? "ex" : "im");
for (; *tag; tag++)
putchar(*tag);
printf("\" {\n");
dbg_prtwordlist(1, text);
printf("}\n");
}
static void
dbg_prtwordlist (int level, word * w)
static void dbg_prtwordlist(int level, word * w)
{
for (; w; w = w->next)
{
wchar_t *wp;
printf ("%*sword %d ", level * 4, "", w->type);
if (w->text)
{
printf ("\"");
for (wp = w->text; *wp; wp++)
putchar (*wp);
printf ("\"");
}
else
printf ("(no text)");
if (w->alt)
{
printf (" alt = {\n");
dbg_prtwordlist (level + 1, w->alt);
printf ("%*s}", level * 4, "");
}
printf ("\n");
for (; w; w = w->next) {
wchar_t *wp;
printf("%*sword %d ", level * 4, "", w->type);
if (w->text) {
printf("\"");
for (wp = w->text; *wp; wp++)
putchar(*wp);
printf("\"");
} else
printf("(no text)");
if (w->alt) {
printf(" alt = {\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 "halibut.h"
static int
kwcmp (void *av, void *bv)
static int kwcmp(void *av, void *bv)
{
const keyword *a = (const keyword *) av;
const keyword *b = (const keyword *) bv;
return ustrcmp (a->key, b->key);
const keyword *a = (const keyword *) av;
const keyword *b = (const keyword *) bv;
return ustrcmp(a->key, b->key);
}
static int
kwfind (void *av, void *bv)
static int kwfind(void *av, void *bv)
{
wchar_t *a = (wchar_t *) av;
const keyword *b = (const keyword *) bv;
return ustrcmp (a, b->key);
wchar_t *a = (wchar_t *) av;
const keyword *b = (const keyword *) bv;
return ustrcmp(a, b->key);
}
keyword *
kw_lookup (keywordlist * kl, wchar_t * str)
keyword *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
* finish).
*/
keywordlist *
get_keywords (paragraph * source)
keywordlist *get_keywords(paragraph * source)
{
int errors = FALSE;
keywordlist *kl = mknew (keywordlist);
numberstate *n = number_init ();
int prevpara = para_NotParaType;
int errors = FALSE;
keywordlist *kl = mknew(keywordlist);
numberstate *n = number_init();
int prevpara = para_NotParaType;
number_cfg (n, source);
number_cfg(n, source);
kl->size = 0;
kl->keys = newtree234 (kwcmp);
kl->nlooseends = kl->looseendssize = 0;
kl->looseends = NULL;
for (; source; source = source->next)
{
wchar_t *p, *q;
p = q = source->keyword;
kl->size = 0;
kl->keys = newtree234(kwcmp);
kl->nlooseends = kl->looseendssize = 0;
kl->looseends = NULL;
for (; source; source = source->next) {
wchar_t *p, *q;
p = q = source->keyword;
/*
* Look for the section type override (`example',
* `question' or whatever - to replace `chapter' or
* `section' on a per-section basis).
*/
if (q)
{
q = uadv (q); /* point q at the word beyond */
if (!*q)
q = NULL;
}
/*
* Look for the section type override (`example',
* `question' or whatever - to replace `chapter' or
* `section' on a per-section basis).
*/
if (q) {
q = uadv(q); /* point q at the word beyond */
if (!*q)
q = NULL;
}
/*
* Number the chapter / section / list-item / whatever.
* This also sets up the `parent', `child' and `sibling'
* links.
*/
source->kwtext = number_mktext (n, source, q, prevpara, &errors);
prevpara = source->type;
/*
* Number the chapter / section / list-item / whatever.
* This also sets up the `parent', `child' and `sibling'
* links.
*/
source->kwtext = number_mktext(n, source, q, prevpara, &errors);
prevpara = source->type;
if (p && *p)
{
if (source->kwtext || source->type == para_Biblio)
{
keyword *kw, *ret;
if (p && *p) {
if (source->kwtext || source->type == para_Biblio) {
keyword *kw, *ret;
kw = mknew (keyword);
kw->key = p;
kw->text = source->kwtext;
kw->para = source;
ret = add234 (kl->keys, kw);
if (ret != kw)
{
error (err_multikw, &source->fpos, &ret->para->fpos, p);
sfree (kw);
/* FIXME: what happens to kw->text? Does it leak? */
}
}
}
else
{
if (kl->nlooseends >= kl->looseendssize)
{
kl->looseendssize = kl->nlooseends + 32;
kl->looseends = resize (kl->looseends, kl->looseendssize);
}
kl->looseends[kl->nlooseends++] = source->kwtext;
}
kw = mknew(keyword);
kw->key = p;
kw->text = source->kwtext;
kw->para = source;
ret = add234(kl->keys, kw);
if (ret != kw) {
error(err_multikw, &source->fpos, &ret->para->fpos, p);
sfree(kw);
/* FIXME: what happens to kw->text? Does it leak? */
}
}
} else {
if (kl->nlooseends >= kl->looseendssize) {
kl->looseendssize = kl->nlooseends + 32;
kl->looseends = resize(kl->looseends, kl->looseendssize);
}
kl->looseends[kl->nlooseends++] = source->kwtext;
}
}
number_free (n);
number_free(n);
if (errors)
{
free_keywords (kl);
return NULL;
if (errors) {
free_keywords(kl);
return NULL;
}
return kl;
return kl;
}
void
free_keywords (keywordlist * kl)
void free_keywords(keywordlist * kl)
{
keyword *kw;
while (kl->nlooseends)
free_word_list (kl->looseends[--kl->nlooseends]);
sfree (kl->looseends);
while ((kw = index234 (kl->keys, 0)) != NULL)
{
delpos234 (kl->keys, 0);
free_word_list (kw->text);
sfree (kw);
keyword *kw;
while (kl->nlooseends)
free_word_list(kl->looseends[--kl->nlooseends]);
sfree(kl->looseends);
while ((kw = index234(kl->keys, 0)) != NULL) {
delpos234(kl->keys, 0);
free_word_list(kw->text);
sfree(kw);
}
freetree234 (kl->keys);
sfree (kl);
freetree234(kl->keys);
sfree(kl);
}
void
subst_keywords (paragraph * source, keywordlist * kl)
void subst_keywords(paragraph * source, keywordlist * kl)
{
for (; source; source = source->next)
{
word *ptr;
for (ptr = source->words; ptr; ptr = ptr->next)
{
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref)
{
keyword *kw;
word **endptr, *close, *subst;
for (; source; source = source->next) {
word *ptr;
for (ptr = source->words; ptr; ptr = ptr->next) {
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref) {
keyword *kw;
word **endptr, *close, *subst;
kw = kw_lookup (kl, ptr->text);
if (!kw)
{
error (err_nosuchkw, &ptr->fpos, ptr->text);
subst = NULL;
}
else
subst = dup_word_list (kw->text);
kw = kw_lookup(kl, ptr->text);
if (!kw) {
error(err_nosuchkw, &ptr->fpos, ptr->text);
subst = NULL;
} else
subst = dup_word_list(kw->text);
if (subst && ptr->type == word_LowerXref &&
kw->para->type != para_Biblio &&
kw->para->type != para_BiblioCited)
ustrlow (subst->text);
if (subst && ptr->type == word_LowerXref &&
kw->para->type != para_Biblio &&
kw->para->type != para_BiblioCited)
ustrlow(subst->text);
close = mknew (word);
close->text = NULL;
close->alt = NULL;
close->type = word_XrefEnd;
close->fpos = ptr->fpos;
close = mknew(word);
close->text = NULL;
close->alt = NULL;
close->type = word_XrefEnd;
close->fpos = ptr->fpos;
close->next = ptr->next;
ptr->next = subst;
close->next = ptr->next;
ptr->next = subst;
for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next)
(*endptr)->fpos = ptr->fpos;
for (endptr = &ptr->next; *endptr;
endptr = &(*endptr)->next)
(*endptr)->fpos = ptr->fpos;
*endptr = close;
ptr = close;
}
}
*endptr = close;
ptr = close;
}
}
}
}

View file

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

View file

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

View file

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

View file

@ -4,51 +4,45 @@
#include "halibut.h"
struct stackTag
{
void **data;
int sp;
int size;
struct stackTag {
void **data;
int sp;
int size;
};
stack
stk_new (void)
stack stk_new(void)
{
stack s;
stack s;
s = mknew (struct stackTag);
s->sp = 0;
s->size = 0;
s->data = NULL;
s = mknew(struct stackTag);
s->sp = 0;
s->size = 0;
s->data = NULL;
return s;
return s;
}
void
stk_free (stack s)
void stk_free(stack s)
{
sfree (s->data);
sfree (s);
sfree(s->data);
sfree(s);
}
void
stk_push (stack s, void *item)
void stk_push(stack s, void *item)
{
if (s->size <= s->sp)
{
s->size = s->sp + 32;
s->data = resize (s->data, s->size);
if (s->size <= s->sp) {
s->size = s->sp + 32;
s->data = resize(s->data, s->size);
}
s->data[s->sp++] = item;
s->data[s->sp++] = item;
}
void *
stk_pop (stack s)
void *stk_pop(stack s)
{
if (s->sp > 0)
return s->data[--s->sp];
else
return NULL;
if (s->sp > 0)
return s->data[--s->sp];
else
return NULL;
}
/*
@ -57,321 +51,281 @@ stk_pop (stack s)
const rdstring empty_rdstring = { 0, 0, NULL };
const rdstringc empty_rdstringc = { 0, 0, NULL };
void
rdadd (rdstring * rs, wchar_t c)
void rdadd(rdstring * rs, wchar_t c)
{
if (rs->pos >= rs->size - 1)
{
rs->size = rs->pos + 128;
rs->text = resize (rs->text, rs->size);
if (rs->pos >= rs->size - 1) {
rs->size = rs->pos + 128;
rs->text = resize(rs->text, rs->size);
}
rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
}
void
rdadds (rdstring * rs, wchar_t * p)
void rdadds(rdstring * rs, wchar_t * p)
{
int len = ustrlen (p);
if (rs->pos >= rs->size - len)
{
rs->size = rs->pos + len + 128;
rs->text = resize (rs->text, rs->size);
int len = ustrlen(p);
if (rs->pos >= rs->size - len) {
rs->size = rs->pos + len + 128;
rs->text = resize(rs->text, rs->size);
}
ustrcpy (rs->text + rs->pos, p);
rs->pos += len;
ustrcpy(rs->text + rs->pos, p);
rs->pos += len;
}
wchar_t *
rdtrim (rdstring * rs)
wchar_t *rdtrim(rdstring * rs)
{
rs->text = resize (rs->text, rs->pos + 1);
return rs->text;
rs->text = resize(rs->text, rs->pos + 1);
return rs->text;
}
void
rdaddc (rdstringc * rs, char c)
void rdaddc(rdstringc * rs, char c)
{
if (rs->pos >= rs->size - 1)
{
rs->size = rs->pos + 128;
rs->text = resize (rs->text, rs->size);
if (rs->pos >= rs->size - 1) {
rs->size = rs->pos + 128;
rs->text = resize(rs->text, rs->size);
}
rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
}
void
rdaddsc (rdstringc * rs, char *p)
void rdaddsc(rdstringc * rs, char *p)
{
int len = strlen (p);
if (rs->pos >= rs->size - len)
{
rs->size = rs->pos + len + 128;
rs->text = resize (rs->text, rs->size);
int len = strlen(p);
if (rs->pos >= rs->size - len) {
rs->size = rs->pos + len + 128;
rs->text = resize(rs->text, rs->size);
}
strcpy (rs->text + rs->pos, p);
rs->pos += len;
strcpy(rs->text + rs->pos, p);
rs->pos += len;
}
char *
rdtrimc (rdstringc * rs)
char *rdtrimc(rdstringc * rs)
{
rs->text = resize (rs->text, rs->pos + 1);
return rs->text;
rs->text = resize(rs->text, rs->pos + 1);
return rs->text;
}
int
compare_wordlists (word * a, word * b)
int compare_wordlists(word * a, word * b)
{
int t;
while (a && b)
{
if (a->type != b->type)
return (a->type < b->type ? -1 : +1); /* FIXME? */
t = a->type;
if ((t != word_Normal && t != word_Code &&
t != word_WeakCode && t != word_Emph) || a->alt || b->alt)
{
int c;
if (a->text && b->text)
{
c = ustricmp (a->text, b->text);
if (c)
return c;
}
c = compare_wordlists (a->alt, b->alt);
if (c)
return c;
a = a->next;
b = b->next;
}
else
{
wchar_t *ap = a->text, *bp = b->text;
while (*ap && *bp)
{
wchar_t ac = utolower (*ap), bc = utolower (*bp);
if (ac != bc)
return (ac < bc ? -1 : +1);
if (!*++ap && a->next && a->next->type == t && !a->next->alt)
a = a->next, ap = a->text;
if (!*++bp && b->next && b->next->type == t && !b->next->alt)
b = b->next, bp = b->text;
}
if (*ap || *bp)
return (*ap ? +1 : -1);
a = a->next;
b = b->next;
}
int t;
while (a && b) {
if (a->type != b->type)
return (a->type < b->type ? -1 : +1); /* FIXME? */
t = a->type;
if ((t != word_Normal && t != word_Code &&
t != word_WeakCode && t != word_Emph) || a->alt || b->alt) {
int c;
if (a->text && b->text) {
c = ustricmp(a->text, b->text);
if (c)
return c;
}
c = compare_wordlists(a->alt, b->alt);
if (c)
return c;
a = a->next;
b = b->next;
} else {
wchar_t *ap = a->text, *bp = b->text;
while (*ap && *bp) {
wchar_t ac = utolower(*ap), bc = utolower(*bp);
if (ac != bc)
return (ac < bc ? -1 : +1);
if (!*++ap && a->next && a->next->type == t
&& !a->next->alt)
a = a->next, ap = a->text;
if (!*++bp && b->next && b->next->type == t
&& !b->next->alt)
b = b->next, bp = b->text;
}
if (*ap || *bp)
return (*ap ? +1 : -1);
a = a->next;
b = b->next;
}
}
if (a || b)
return (a ? +1 : -1);
else
return 0;
if (a || b)
return (a ? +1 : -1);
else
return 0;
}
void
mark_attr_ends (paragraph * sourceform)
void mark_attr_ends(paragraph * sourceform)
{
paragraph *p;
word *w, *wp;
for (p = sourceform; p; p = p->next)
{
wp = NULL;
for (w = p->words; w; w = w->next)
{
if (isattr (w->type))
{
int before = (wp && isattr (wp->type) &&
sameattr (wp->type, w->type));
int after = (w->next && isattr (w->next->type) &&
sameattr (w->next->type, w->type));
w->aux |= (before ?
(after ? attr_Always : attr_Last) :
(after ? attr_First : attr_Only));
}
wp = w;
}
paragraph *p;
word *w, *wp;
for (p = sourceform; p; p = p->next) {
wp = NULL;
for (w = p->words; w; w = w->next) {
if (isattr(w->type)) {
int before = (wp && isattr(wp->type) &&
sameattr(wp->type, w->type));
int after = (w->next && isattr(w->next->type) &&
sameattr(w->next->type, w->type));
w->aux |= (before ?
(after ? attr_Always : attr_Last) :
(after ? attr_First : attr_Only));
}
wp = w;
}
}
}
wrappedline *
wrap_para (word * text, int width, int subsequentwidth,
int (*widthfn) (word *))
wrappedline *wrap_para(word * text, int width, int subsequentwidth,
int (*widthfn) (word *))
{
wrappedline *head = NULL, **ptr = &head;
int nwords, wordsize;
struct wrapword
{
word *begin, *end;
int width;
int spacewidth;
int cost;
int nwords;
}
*wrapwords;
int i, j, n;
wrappedline *head = NULL, **ptr = &head;
int nwords, wordsize;
struct wrapword {
word *begin, *end;
int width;
int spacewidth;
int cost;
int nwords;
} *wrapwords;
int i, j, n;
/*
* Break the line up into wrappable components.
*/
nwords = wordsize = 0;
wrapwords = NULL;
while (text)
{
if (nwords >= wordsize)
{
wordsize = nwords + 64;
wrapwords = srealloc (wrapwords, wordsize * sizeof (*wrapwords));
}
wrapwords[nwords].width = 0;
wrapwords[nwords].begin = text;
while (text)
{
wrapwords[nwords].width += widthfn (text);
wrapwords[nwords].end = text->next;
if (text->next && (text->next->type == word_WhiteSpace ||
text->next->type == word_EmphSpace ||
text->breaks))
break;
text = text->next;
}
if (text && text->next && (text->next->type == word_WhiteSpace ||
text->next->type == word_EmphSpace))
{
wrapwords[nwords].spacewidth = widthfn (text->next);
text = text->next;
}
else
{
wrapwords[nwords].spacewidth = 0;
}
nwords++;
if (text)
text = text->next;
/*
* Break the line up into wrappable components.
*/
nwords = wordsize = 0;
wrapwords = NULL;
while (text) {
if (nwords >= wordsize) {
wordsize = nwords + 64;
wrapwords = srealloc(wrapwords, wordsize * sizeof(*wrapwords));
}
wrapwords[nwords].width = 0;
wrapwords[nwords].begin = text;
while (text) {
wrapwords[nwords].width += widthfn(text);
wrapwords[nwords].end = text->next;
if (text->next && (text->next->type == word_WhiteSpace ||
text->next->type == word_EmphSpace ||
text->breaks))
break;
text = text->next;
}
if (text && text->next && (text->next->type == word_WhiteSpace ||
text->next->type == word_EmphSpace)) {
wrapwords[nwords].spacewidth = widthfn(text->next);
text = text->next;
} else {
wrapwords[nwords].spacewidth = 0;
}
nwords++;
if (text)
text = text->next;
}
/*
* Perform the dynamic wrapping algorithm: work backwards from
* nwords-1, determining the optimal wrapping for each terminal
* subsequence of the paragraph.
*/
for (i = nwords; i--;)
{
int best = -1;
int bestcost = 0;
int cost;
int linelen = 0, spacewidth = 0;
int seenspace;
int thiswidth = (i == 0 ? width : subsequentwidth);
/*
* Perform the dynamic wrapping algorithm: work backwards from
* nwords-1, determining the optimal wrapping for each terminal
* subsequence of the paragraph.
*/
for (i = nwords; i--;) {
int best = -1;
int bestcost = 0;
int cost;
int linelen = 0, spacewidth = 0;
int seenspace;
int thiswidth = (i == 0 ? width : subsequentwidth);
j = 0;
seenspace = 0;
while (i + j < nwords)
{
/*
* See what happens if we put j+1 words on this line.
*/
if (spacewidth)
seenspace = 1;
linelen += spacewidth + wrapwords[i + j].width;
spacewidth = wrapwords[i + j].spacewidth;
j++;
if (linelen > thiswidth)
{
/*
* If we're over the width limit, abandon ship,
* _unless_ there is no best-effort yet (which will
* only happen if the first word is too long all by
* itself).
*/
if (best > 0)
break;
}
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.
*/
cost = 0;
}
else
{
cost = (thiswidth - linelen) * (thiswidth - linelen);
cost += wrapwords[i + j].cost;
}
/*
* We compare bestcost >= cost, not bestcost > cost,
* because in cases where the costs are identical we
* 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
* there's no point violating the Principle of Least
* Surprise if it doesn't actually gain anything.
*/
if (best < 0 || bestcost >= cost)
{
bestcost = cost;
best = j;
}
}
/*
* Now we know the optimal answer for this terminal
* subsequence, so put it in wrapwords.
*/
wrapwords[i].cost = bestcost;
wrapwords[i].nwords = best;
j = 0;
seenspace = 0;
while (i + j < nwords) {
/*
* See what happens if we put j+1 words on this line.
*/
if (spacewidth)
seenspace = 1;
linelen += spacewidth + wrapwords[i + j].width;
spacewidth = wrapwords[i + j].spacewidth;
j++;
if (linelen > thiswidth) {
/*
* If we're over the width limit, abandon ship,
* _unless_ there is no best-effort yet (which will
* only happen if the first word is too long all by
* itself).
*/
if (best > 0)
break;
}
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.
*/
cost = 0;
} else {
cost = (thiswidth - linelen) * (thiswidth - linelen);
cost += wrapwords[i + j].cost;
}
/*
* We compare bestcost >= cost, not bestcost > cost,
* because in cases where the costs are identical we
* 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
* there's no point violating the Principle of Least
* Surprise if it doesn't actually gain anything.
*/
if (best < 0 || bestcost >= cost) {
bestcost = cost;
best = j;
}
}
/*
* 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
* `wrappedline' list.
*/
i = 0;
while (i < nwords)
{
wrappedline *w = mknew (wrappedline);
*ptr = w;
ptr = &w->next;
w->next = NULL;
/*
* We've wrapped the paragraph. Now build the output
* `wrappedline' list.
*/
i = 0;
while (i < nwords) {
wrappedline *w = mknew(wrappedline);
*ptr = w;
ptr = &w->next;
w->next = NULL;
n = wrapwords[i].nwords;
w->begin = wrapwords[i].begin;
w->end = wrapwords[i + n - 1].end;
n = wrapwords[i].nwords;
w->begin = wrapwords[i].begin;
w->end = wrapwords[i + n - 1].end;
/*
* Count along the words to find nspaces and shortfall.
*/
w->nspaces = 0;
w->shortfall = width;
for (j = 0; j < n; j++)
{
w->shortfall -= wrapwords[i + j].width;
if (j < n - 1 && wrapwords[i + j].spacewidth)
{
w->nspaces++;
w->shortfall -= wrapwords[i + j].spacewidth;
}
}
i += n;
/*
* Count along the words to find nspaces and shortfall.
*/
w->nspaces = 0;
w->shortfall = width;
for (j = 0; j < n; j++) {
w->shortfall -= wrapwords[i + j].width;
if (j < n - 1 && wrapwords[i + j].spacewidth) {
w->nspaces++;
w->shortfall -= wrapwords[i + j].spacewidth;
}
}
i += n;
}
sfree (wrapwords);
sfree(wrapwords);
return head;
return head;
}
void
wrap_free (wrappedline * w)
void wrap_free(wrappedline * w)
{
while (w)
{
wrappedline *t = w->next;
sfree (w);
w = t;
while (w) {
wrappedline *t = w->next;
sfree(w);
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
* 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).
*/
void freetree234 (tree234 * t);
void freetree234(tree234 * t);
/*
* 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.
*/
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
@ -63,7 +63,7 @@ void *add234 (tree234 * t, void *e);
* Index range can be from 0 to the tree's current element count,
* 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.
@ -83,7 +83,7 @@ void *addpos234 (tree234 * t, void *e, int index);
* 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
@ -125,15 +125,14 @@ void *index234 (tree234 * t, int index);
* for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;)
* consume(p);
*/
enum
{
REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE
enum {
REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE
};
void *find234 (tree234 * t, void *e, cmpfn234 cmp);
void *findrel234 (tree234 * t, void *e, cmpfn234 cmp, int relation);
void *findpos234 (tree234 * t, void *e, cmpfn234 cmp, int *index);
void *findrelpos234 (tree234 * t, void *e, cmpfn234 cmp, int relation,
int *index);
void *find234(tree234 * t, void *e, cmpfn234 cmp);
void *findrel234(tree234 * t, void *e, cmpfn234 cmp, int relation);
void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index);
void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation,
int *index);
/*
* 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
* tree (del234) then they return NULL.
*/
void *del234 (tree234 * t, void *e);
void *delpos234 (tree234 * t, int index);
void *del234(tree234 * t, void *e);
void *delpos234(tree234 * t, int index);
/*
* Return the total element count of a tree234.
*/
int count234 (tree234 * t);
int count234(tree234 * t);
/*
* 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
* remainder are left.
*/
tree234 *splitpos234 (tree234 * t, int index, int before);
tree234 *split234 (tree234 * t, void *e, cmpfn234 cmp, int rel);
tree234 *splitpos234(tree234 * t, int index, int before);
tree234 *split234(tree234 * t, void *e, cmpfn234 cmp, int rel);
/*
* 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
* operation is successful.
*/
tree234 *join234 (tree234 * t1, tree234 * t2);
tree234 *join234r (tree234 * t1, tree234 * t2);
tree234 *join234(tree234 * t1, tree234 * t2);
tree234 *join234r(tree234 * t1, tree234 * t2);
/*
* 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
* 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 "halibut.h"
wchar_t *
ustrdup (wchar_t * s)
wchar_t *ustrdup(wchar_t * s)
{
wchar_t *r;
if (s)
{
r = mknewa (wchar_t, 1 + ustrlen (s));
ustrcpy (r, s);
wchar_t *r;
if (s) {
r = mknewa(wchar_t, 1 + ustrlen(s));
ustrcpy(r, s);
} else {
r = mknew(wchar_t);
*r = 0;
}
else
{
r = mknew (wchar_t);
*r = 0;
return r;
}
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 *
ustrtoa (wchar_t * s, char *outbuf, int size)
int ustrlen(wchar_t * s)
{
char *p;
if (!s)
{
*outbuf = '\0';
return outbuf;
int len = 0;
while (*s++)
len++;
return len;
}
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++)
*p = *s;
if (p < outbuf + size)
*p = '\0';
else
outbuf[size - 1] = '\0';
return outbuf;
while (*source++);
return ret;
}
int
ustrlen (wchar_t * s)
int ustrcmp(wchar_t * lhs, wchar_t * rhs)
{
int len = 0;
while (*s++)
len++;
return len;
}
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;
}
while (*source++);
return ret;
}
int
ustrcmp (wchar_t * lhs, wchar_t * rhs)
{
if (!lhs && !rhs)
if (!lhs && !rhs)
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;
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
utolower (wchar_t c)
wchar_t utolower(wchar_t c)
{
if (c == L'\0')
return c; /* this property needed by ustricmp */
/* FIXME: this doesn't even come close */
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
return c;
if (c == L'\0')
return c; /* this property needed by ustricmp */
/* FIXME: this doesn't even come close */
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
return c;
}
int
ustricmp (wchar_t * lhs, wchar_t * rhs)
int ustricmp(wchar_t * lhs, wchar_t * rhs)
{
wchar_t lc, rc;
while ((lc = utolower (*lhs)) == (rc = utolower (*rhs)) && lc && rc)
lhs++, rhs++;
if (!lc && !rc)
return 0;
if (lc < rc)
return -1;
else
return 1;
wchar_t lc, rc;
while ((lc = utolower(*lhs)) == (rc = utolower(*rhs)) && lc && rc)
lhs++, rhs++;
if (!lc && !rc)
return 0;
if (lc < rc)
return -1;
else
return 1;
}
wchar_t *
ustrlow (wchar_t * s)
wchar_t *ustrlow(wchar_t * s)
{
wchar_t *p = s;
while (*p)
{
*p = utolower (*p);
p++;
wchar_t *p = s;
while (*p) {
*p = utolower(*p);
p++;
}
return s;
return s;
}
int
utoi (wchar_t * s)
int utoi(wchar_t * s)
{
int sign = +1;
int n;
int sign = +1;
int n;
if (*s == L'-')
{
s++;
sign = -1;
if (*s == L'-') {
s++;
sign = -1;
}
n = 0;
while (*s && *s >= L'0' && *s <= L'9')
{
n *= 10;
n += (*s - '0');
s++;
n = 0;
while (*s && *s >= L'0' && *s <= L'9') {
n *= 10;
n += (*s - '0');
s++;
}
return n;
return n;
}
int
utob (wchar_t * s)
int utob(wchar_t * s)
{
if (!ustricmp (s, L"yes") || !ustricmp (s, L"y") ||
!ustricmp (s, L"true") || !ustricmp (s, L"t"))
return TRUE;
return FALSE;
if (!ustricmp(s, L"yes") || !ustricmp(s, L"y") ||
!ustricmp(s, L"true") || !ustricmp(s, L"t"))
return TRUE;
return FALSE;
}
int
uisdigit (wchar_t c)
int uisdigit(wchar_t c)
{
return c >= L'0' && c <= L'9';
return c >= L'0' && c <= L'9';
}
#define USTRFTIME_DELTA 128
wchar_t *
ustrftime (wchar_t * wfmt, struct tm * timespec)
wchar_t *ustrftime(wchar_t * wfmt, struct tm * timespec)
{
void *blk = NULL;
wchar_t *wblk, *wp;
char *fmt, *text, *p;
size_t size = 0;
size_t len;
void *blk = NULL;
wchar_t *wblk, *wp;
char *fmt, *text, *p;
size_t size = 0;
size_t len;
/*
* strftime has the entertaining property that it returns 0
* _either_ on out-of-space _or_ on successful generation of
* the empty string. Hence we must ensure our format can never
* generate the empty string. Somebody throw a custard pie at
* whoever was responsible for that. Please?
*/
if (wfmt)
{
len = ustrlen (wfmt);
fmt = mknewa (char, 2 + len);
ustrtoa (wfmt, fmt + 1, len + 1);
fmt[0] = ' ';
}
else
fmt = " %c";
/*
* strftime has the entertaining property that it returns 0
* _either_ on out-of-space _or_ on successful generation of
* the empty string. Hence we must ensure our format can never
* generate the empty string. Somebody throw a custard pie at
* whoever was responsible for that. Please?
*/
if (wfmt) {
len = ustrlen(wfmt);
fmt = mknewa(char, 2 + len);
ustrtoa(wfmt, fmt + 1, len + 1);
fmt[0] = ' ';
} else
fmt = " %c";
while (1)
{
size += USTRFTIME_DELTA;
blk = resize ((char *) blk, size);
len = strftime ((char *) blk, size - 1, fmt, timespec);
if (len > 0)
break;
while (1) {
size += USTRFTIME_DELTA;
blk = resize((char *) blk, size);
len = strftime((char *) blk, size - 1, fmt, timespec);
if (len > 0)
break;
}
/* Note: +1 for the terminating 0, -1 for the initial space in fmt */
wblk = resize ((wchar_t *) blk, len);
text = mknewa (char, len);
strftime (text, len, fmt + 1, timespec);
/*
* We operate in the C locale, so this all ought to be kosher
* ASCII. If we ever move outside ASCII machines, we may need
* to make this more portable...
*/
for (wp = wblk, p = text; *p; p++, wp++)
*wp = *p;
*wp = 0;
if (wfmt)
sfree (fmt);
sfree (text);
return wblk;
/* Note: +1 for the terminating 0, -1 for the initial space in fmt */
wblk = resize((wchar_t *) blk, len);
text = mknewa(char, len);
strftime(text, len, fmt + 1, timespec);
/*
* We operate in the C locale, so this all ought to be kosher
* ASCII. If we ever move outside ASCII machines, we may need
* to make this more portable...
*/
for (wp = wblk, p = text; *p; p++, wp++)
*wp = *p;
*wp = 0;
if (wfmt)
sfree(fmt);
sfree(text);
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.
*/
WHLP whlp_new (void);
WHLP whlp_new(void);
/*
* 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.
*/
void whlp_abandon (WHLP h);
void whlp_abandon(WHLP h);
/*
* Specify the title and copyright notice of a help file. Also
* specify Help macros to be run on loading.
*/
void whlp_title (WHLP h, char *title);
void whlp_copyright (WHLP h, char *copyright);
void whlp_start_macro (WHLP h, char *macro);
void whlp_title(WHLP h, char *title);
void whlp_copyright(WHLP h, char *copyright);
void whlp_start_macro(WHLP h, char *macro);
/*
* 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
* 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
* 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
@ -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
* writing actual text.
*/
void whlp_prepare (WHLP h);
void whlp_prepare(WHLP h);
/*
* 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
@ -85,13 +85,13 @@ void whlp_index_term (WHLP h, char *index, WHLP_TOPIC topic);
*
* 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
* 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.
@ -101,7 +101,7 @@ void whlp_primary_topic (WHLP h, WHLP_TOPIC topic);
*
* 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,
@ -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
* easily yourself by counting.
*/
enum
{
WHLP_FONT_BOLD = 1,
WHLP_FONT_ITALIC = 2,
WHLP_FONT_UNDERLINE = 4,
WHLP_FONT_STRIKEOUT = 8,
WHLP_FONT_DOUBLEUND = 16,
WHLP_FONT_SMALLCAPS = 32
enum {
WHLP_FONT_BOLD = 1,
WHLP_FONT_ITALIC = 2,
WHLP_FONT_UNDERLINE = 4,
WHLP_FONT_STRIKEOUT = 8,
WHLP_FONT_DOUBLEUND = 16,
WHLP_FONT_SMALLCAPS = 32
};
enum
{
WHLP_FONTFAM_FIXED = 1,
WHLP_FONTFAM_SERIF = 2,
WHLP_FONTFAM_SANS = 3,
WHLP_FONTFAM_SCRIPT = 4,
WHLP_FONTFAM_DECOR = 5
enum {
WHLP_FONTFAM_FIXED = 1,
WHLP_FONTFAM_SERIF = 2,
WHLP_FONTFAM_SANS = 3,
WHLP_FONTFAM_SCRIPT = 4,
WHLP_FONTFAM_DECOR = 5
};
int whlp_create_font (WHLP h, char *font, int family, int halfpoints,
int rendition, int r, int g, int b);
int whlp_create_font(WHLP h, char *font, int family, int halfpoints,
int rendition, int r, int g, int b);
/*
* 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
* off.
*/
enum
{
WHLP_PARA_SPACEABOVE = 1, WHLP_PARA_SPACEBELOW, WHLP_PARA_SPACELINES,
WHLP_PARA_LEFTINDENT, WHLP_PARA_RIGHTINDENT, WHLP_PARA_FIRSTLINEINDENT,
WHLP_PARA_ALIGNMENT
enum {
WHLP_PARA_SPACEABOVE = 1, WHLP_PARA_SPACEBELOW, WHLP_PARA_SPACELINES,
WHLP_PARA_LEFTINDENT, WHLP_PARA_RIGHTINDENT, WHLP_PARA_FIRSTLINEINDENT,
WHLP_PARA_ALIGNMENT
};
enum
{
WHLP_ALIGN_LEFT, WHLP_ALIGN_RIGHT, WHLP_ALIGN_CENTRE
enum {
WHLP_ALIGN_LEFT, WHLP_ALIGN_RIGHT, WHLP_ALIGN_CENTRE
};
enum
{
WHLP_PARA_SCROLL, WHLP_PARA_NONSCROLL
enum {
WHLP_PARA_SCROLL, WHLP_PARA_NONSCROLL
};
void whlp_para_attr (WHLP h, int attr_id, int attr_param);
void whlp_set_tabstop (WHLP h, int tabstop, int alignment);
void whlp_begin_para (WHLP h, int para_type);
void whlp_end_para (WHLP h);
void whlp_set_font (WHLP h, int font_id);
void whlp_text (WHLP h, char *text);
void whlp_start_hyperlink (WHLP h, WHLP_TOPIC target);
void whlp_end_hyperlink (WHLP h);
void whlp_tab (WHLP h);
void whlp_para_attr(WHLP h, int attr_id, int attr_param);
void whlp_set_tabstop(WHLP h, int tabstop, int alignment);
void whlp_begin_para(WHLP h, int para_type);
void whlp_end_para(WHLP h);
void whlp_set_font(WHLP h, int font_id);
void whlp_text(WHLP h, char *text);
void whlp_start_hyperlink(WHLP h, WHLP_TOPIC target);
void whlp_end_hyperlink(WHLP h);
void whlp_tab(WHLP h);