Hacked up halibut source code
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@1534 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
8204a7298a
commit
b23696e64c
24 changed files with 12849 additions and 0 deletions
21
Docs/src/bin/halibut/LICENCE
Normal file
21
Docs/src/bin/halibut/LICENCE
Normal file
|
@ -0,0 +1,21 @@
|
|||
Halibut is copyright (c) 1999-2001 Simon Tatham and James Aylett.
|
||||
|
||||
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,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
127
Docs/src/bin/halibut/biblio.c
Normal file
127
Docs/src/bin/halibut/biblio.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* biblio.c: process the bibliography
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "halibut.h"
|
||||
|
||||
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;
|
||||
}
|
||||
assert (p > text);
|
||||
*--p = L'[';
|
||||
return ustrdup (p);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a pass through the source form, generating citation formats
|
||||
* for bibliography entries and also marking which bibliography
|
||||
* entries are actually cited (or \nocite-ed).
|
||||
*/
|
||||
|
||||
void
|
||||
gen_citations (paragraph * source, keywordlist * kl)
|
||||
{
|
||||
paragraph *para;
|
||||
int bibnum = 0;
|
||||
|
||||
for (para = source; para; para = para->next)
|
||||
{
|
||||
word *ptr;
|
||||
|
||||
/*
|
||||
* \BR and \nocite paragraphs get special processing here.
|
||||
*/
|
||||
if (para->type == para_BR)
|
||||
{
|
||||
keyword *kw = kw_lookup (kl, para->keyword);
|
||||
if (!kw)
|
||||
{
|
||||
error (err_nosuchkw, ¶->fpos, para->keyword);
|
||||
}
|
||||
else if (kw->text)
|
||||
{
|
||||
error (err_multiBR, ¶->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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
751
Docs/src/bin/halibut/bk_text.c
Normal file
751
Docs/src/bin/halibut/bk_text.c
Normal file
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
711
Docs/src/bin/halibut/bk_whlp.c
Normal file
711
Docs/src/bin/halibut/bk_whlp.c
Normal file
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
1933
Docs/src/bin/halibut/bk_xhtml.c
Normal file
1933
Docs/src/bin/halibut/bk_xhtml.c
Normal file
File diff suppressed because it is too large
Load diff
258
Docs/src/bin/halibut/contents.c
Normal file
258
Docs/src/bin/halibut/contents.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* contents.c: build a table of contents
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#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 */
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
number_free (numberstate * state)
|
||||
{
|
||||
sfree (state->sectionlevels);
|
||||
sfree (state->currentsects);
|
||||
sfree (state);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
dotext (wret, p);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
p = text + sizeof (text);
|
||||
*--p = L'\0';
|
||||
while (nletters--)
|
||||
{
|
||||
assert (p > text);
|
||||
*--p = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num % 26];
|
||||
num /= 26;
|
||||
}
|
||||
dotext (wret, p);
|
||||
}
|
||||
|
||||
void
|
||||
number_cfg (numberstate * state, paragraph * source)
|
||||
{
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case para_UnnumberedChapter:
|
||||
level = -1;
|
||||
break;
|
||||
case para_NumberedList:
|
||||
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;
|
||||
}
|
||||
|
||||
p->kwtext2 = *ret2;
|
||||
return ret;
|
||||
}
|
227
Docs/src/bin/halibut/error.c
Normal file
227
Docs/src/bin/halibut/error.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* error.c: Halibut error handling
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "halibut.h"
|
||||
|
||||
/*
|
||||
* Error flags
|
||||
*/
|
||||
#define PREFIX 0x0001 /* give `halibut:' prefix */
|
||||
#define FILEPOS 0x0002 /* give file position prefix */
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case err_brokencodepara:
|
||||
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;
|
||||
case err_kwexpected:
|
||||
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;
|
||||
case err_kwtoomany:
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case err_unexbrace:
|
||||
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;
|
||||
case err_commenteof:
|
||||
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;
|
||||
case err_missingrbrace:
|
||||
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;
|
||||
case err_nestedindex:
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case err_cantopenw:
|
||||
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;
|
||||
case err_sectjump:
|
||||
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;
|
||||
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;
|
||||
case err_whatever:
|
||||
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);
|
||||
}
|
||||
fputs (error, stderr);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
|
||||
void
|
||||
fatal (int code, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, code);
|
||||
do_error (code, ap);
|
||||
va_end (ap);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
error (int code, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, code);
|
||||
do_error (code, ap);
|
||||
va_end (ap);
|
||||
}
|
438
Docs/src/bin/halibut/halibut.h
Normal file
438
Docs/src/bin/halibut/halibut.h
Normal file
|
@ -0,0 +1,438 @@
|
|||
#ifndef HALIBUT_HALIBUT_H
|
||||
#define HALIBUT_HALIBUT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#else
|
||||
#define NORETURN /* nothing */
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* For suppressing unused-parameter warnings */
|
||||
#define IGNORE(x) ( (x) = (x) )
|
||||
|
||||
#include "tree234.h"
|
||||
|
||||
/*
|
||||
* Structure tags
|
||||
*/
|
||||
typedef struct input_Tag input;
|
||||
typedef struct filepos_Tag filepos;
|
||||
typedef struct paragraph_Tag paragraph;
|
||||
typedef struct word_Tag word;
|
||||
typedef struct keywordlist_Tag keywordlist;
|
||||
typedef struct keyword_Tag keyword;
|
||||
typedef struct userstyle_Tag userstyle;
|
||||
typedef struct numberstate_Tag numberstate;
|
||||
typedef struct indexdata_Tag indexdata;
|
||||
typedef struct indextag_Tag indextag;
|
||||
typedef struct indexentry_Tag indexentry;
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
paragraph *parent, *child, *sibling; /* for hierarchy navigation */
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
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,
|
||||
};
|
||||
/* aux values for quote-type words */
|
||||
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 ) )
|
||||
#define sameattr(x,y) ( (((x)-(y)) & 3) == 0 )
|
||||
#define towordstyle(x) ( word_Normal + ((x) & 3) )
|
||||
#define tospacestyle(x) ( word_WhiteSpace + ((x) & 3) )
|
||||
#define toquotestyle(x) ( word_Quote + ((x) & 3) )
|
||||
#define removeattr(x) ( word_Normal + ((x) &~ 3) )
|
||||
|
||||
#define attraux(x) ( (x) & attr_mask )
|
||||
#define quoteaux(x) ( (x) & quote_mask )
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
#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);
|
||||
#endif
|
||||
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)) )
|
||||
#define resize(array, len) ( srealloc ((array), (len) * sizeof (*(array))) )
|
||||
#define lenof(array) ( sizeof(array) / sizeof(*(array)) )
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* help.c
|
||||
*/
|
||||
void help (void);
|
||||
void usage (void);
|
||||
void showversion (void);
|
||||
|
||||
/*
|
||||
* licence.c
|
||||
*/
|
||||
void licence (void);
|
||||
|
||||
/*
|
||||
* version.c
|
||||
*/
|
||||
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 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);
|
||||
|
||||
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 *);
|
||||
|
||||
/*
|
||||
* input.c
|
||||
*/
|
||||
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 *);
|
||||
|
||||
/*
|
||||
* index.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Data structure to hold both sides of the index.
|
||||
*/
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data structure to hold an index entry (RHS of index).
|
||||
*/
|
||||
struct indexentry_Tag
|
||||
{
|
||||
word *text;
|
||||
void *backend_data; /* private to back end */
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* contents.c
|
||||
*/
|
||||
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 *);
|
||||
|
||||
/*
|
||||
* style.c
|
||||
*/
|
||||
struct userstyle_Tag
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
* bk_text.c
|
||||
*/
|
||||
void text_backend (paragraph *, keywordlist *, indexdata *);
|
||||
|
||||
/*
|
||||
* bk_xhtml.c
|
||||
*/
|
||||
void xhtml_backend (paragraph *, keywordlist *, indexdata *);
|
||||
|
||||
/*
|
||||
* bk_whlp.c
|
||||
*/
|
||||
void whlp_backend (paragraph *, keywordlist *, indexdata *);
|
||||
|
||||
#endif
|
38
Docs/src/bin/halibut/help.c
Normal file
38
Docs/src/bin/halibut/help.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* help.c: usage instructions
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "halibut.h"
|
||||
|
||||
static char *helptext[] = {
|
||||
"FIXME: help text goes here",
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *usagetext[] = {
|
||||
"FIXME: usage text goes here",
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
help (void)
|
||||
{
|
||||
char **p;
|
||||
for (p = helptext; *p; p++)
|
||||
puts (*p);
|
||||
}
|
||||
|
||||
void
|
||||
usage (void)
|
||||
{
|
||||
char **p;
|
||||
for (p = usagetext; *p; p++)
|
||||
puts (*p);
|
||||
}
|
||||
|
||||
void
|
||||
showversion (void)
|
||||
{
|
||||
printf ("Halibut, %s\n", version);
|
||||
}
|
278
Docs/src/bin/halibut/index.c
Normal file
278
Docs/src/bin/halibut/index.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* index.c: create and collate index data structures
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "halibut.h"
|
||||
|
||||
static int compare_tags (void *av, void *bv);
|
||||
static int compare_entries (void *av, void *bv);
|
||||
|
||||
indexdata *
|
||||
make_index (void)
|
||||
{
|
||||
indexdata *ret = mknew (indexdata);
|
||||
ret->tags = newtree234 (compare_tags);
|
||||
ret->entries = newtree234 (compare_entries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_tags (void *av, void *bv)
|
||||
{
|
||||
indextag *a = (indextag *) av, *b = (indextag *) bv;
|
||||
return ustricmp (a->name, b->name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_entries (void *av, void *bv)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return find234 (idx->tags, name, compare_to_find_tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a \IM. `tags' points to a zero-terminated chain of
|
||||
* zero-terminated strings ("first\0second\0thirdandlast\0\0").
|
||||
* `text' points to a word list.
|
||||
*
|
||||
* Guarantee on calling sequence: all implicit merges are given
|
||||
* before the explicit ones.
|
||||
*/
|
||||
void
|
||||
index_merge (indexdata * idx, int is_explicit, wchar_t * tags, word * text)
|
||||
{
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the final-form index. We now have every tag, with every
|
||||
* \IM, set up in a 2-3 tree indexed by tag. We now want to collate
|
||||
* the RHSes of the \IMs, and sort by final form, and decorate the
|
||||
* entries in the original 2-3 tree with pointers to the RHS
|
||||
* entries.
|
||||
*/
|
||||
void
|
||||
build_index (indexdata * i)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_index (indexdata * i)
|
||||
{
|
||||
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);
|
||||
}
|
||||
freetree234 (i->tags);
|
||||
for (ti = 0; (ent = (indexentry *) index234 (i->entries, ti)) != NULL; ti++)
|
||||
{
|
||||
sfree (ent);
|
||||
}
|
||||
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);
|
||||
|
||||
void
|
||||
index_debug (indexdata * i)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
1516
Docs/src/bin/halibut/input.c
Normal file
1516
Docs/src/bin/halibut/input.c
Normal file
File diff suppressed because it is too large
Load diff
179
Docs/src/bin/halibut/keywords.c
Normal file
179
Docs/src/bin/halibut/keywords.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* keywords.c: keep track of all cross-reference keywords
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "halibut.h"
|
||||
|
||||
static int
|
||||
kwcmp (void *av, void *bv)
|
||||
{
|
||||
const keyword *a = (const keyword *) av;
|
||||
const keyword *b = (const keyword *) bv;
|
||||
return ustrcmp (a->key, b->key);
|
||||
}
|
||||
|
||||
static int
|
||||
kwfind (void *av, void *bv)
|
||||
{
|
||||
wchar_t *a = (wchar_t *) av;
|
||||
const keyword *b = (const keyword *) bv;
|
||||
return ustrcmp (a, b->key);
|
||||
}
|
||||
|
||||
keyword *
|
||||
kw_lookup (keywordlist * kl, wchar_t * str)
|
||||
{
|
||||
return find234 (kl->keys, str, kwfind);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads through source form and collects the
|
||||
* keywords. They get collected in a heap, sorted by Unicode
|
||||
* collation, last at the top (so that we can Heapsort them when we
|
||||
* finish).
|
||||
*/
|
||||
keywordlist *
|
||||
get_keywords (paragraph * source)
|
||||
{
|
||||
int errors = FALSE;
|
||||
keywordlist *kl = mknew (keywordlist);
|
||||
numberstate *n = number_init ();
|
||||
int prevpara = para_NotParaType;
|
||||
|
||||
number_cfg (n, source);
|
||||
|
||||
kl->size = 0;
|
||||
kl->keys = newtree234 (kwcmp);
|
||||
kl->nlooseends = kl->looseendssize = 0;
|
||||
kl->looseends = NULL;
|
||||
for (; source; source = source->next)
|
||||
{
|
||||
wchar_t *p, *q;
|
||||
p = q = source->keyword;
|
||||
|
||||
/*
|
||||
* Look for the section type override (`example',
|
||||
* `question' or whatever - to replace `chapter' or
|
||||
* `section' on a per-section basis).
|
||||
*/
|
||||
if (q)
|
||||
{
|
||||
q = uadv (q); /* point q at the word beyond */
|
||||
if (!*q)
|
||||
q = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Number the chapter / section / list-item / whatever.
|
||||
* This also sets up the `parent', `child' and `sibling'
|
||||
* links.
|
||||
*/
|
||||
source->kwtext = number_mktext (n, source, q, prevpara, &errors);
|
||||
prevpara = source->type;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
number_free (n);
|
||||
|
||||
if (errors)
|
||||
{
|
||||
free_keywords (kl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return kl;
|
||||
}
|
||||
|
||||
void
|
||||
free_keywords (keywordlist * kl)
|
||||
{
|
||||
keyword *kw;
|
||||
while (kl->nlooseends)
|
||||
free_word_list (kl->looseends[--kl->nlooseends]);
|
||||
sfree (kl->looseends);
|
||||
while ((kw = index234 (kl->keys, 0)) != NULL)
|
||||
{
|
||||
delpos234 (kl->keys, 0);
|
||||
free_word_list (kw->text);
|
||||
sfree (kw);
|
||||
}
|
||||
freetree234 (kl->keys);
|
||||
sfree (kl);
|
||||
}
|
||||
|
||||
void
|
||||
subst_keywords (paragraph * source, keywordlist * kl)
|
||||
{
|
||||
for (; source; source = source->next)
|
||||
{
|
||||
word *ptr;
|
||||
for (ptr = source->words; ptr; ptr = ptr->next)
|
||||
{
|
||||
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref)
|
||||
{
|
||||
keyword *kw;
|
||||
word **endptr, *close, *subst;
|
||||
|
||||
kw = kw_lookup (kl, ptr->text);
|
||||
if (!kw)
|
||||
{
|
||||
error (err_nosuchkw, &ptr->fpos, ptr->text);
|
||||
subst = NULL;
|
||||
}
|
||||
else
|
||||
subst = dup_word_list (kw->text);
|
||||
|
||||
if (subst && ptr->type == word_LowerXref &&
|
||||
kw->para->type != para_Biblio &&
|
||||
kw->para->type != para_BiblioCited)
|
||||
ustrlow (subst->text);
|
||||
|
||||
close = mknew (word);
|
||||
close->text = NULL;
|
||||
close->alt = NULL;
|
||||
close->type = word_XrefEnd;
|
||||
close->fpos = ptr->fpos;
|
||||
|
||||
close->next = ptr->next;
|
||||
ptr->next = subst;
|
||||
|
||||
for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next)
|
||||
(*endptr)->fpos = ptr->fpos;
|
||||
|
||||
*endptr = close;
|
||||
ptr = close;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
Docs/src/bin/halibut/licence.c
Normal file
18
Docs/src/bin/halibut/licence.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* licence.c: licence text
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static char *licencetext[] = {
|
||||
"FIXME: licence text goes here",
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
licence (void)
|
||||
{
|
||||
char **p;
|
||||
for (p = licencetext; *p; p++)
|
||||
puts (*p);
|
||||
}
|
343
Docs/src/bin/halibut/main.c
Normal file
343
Docs/src/bin/halibut/main.c
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* main.c: command line parsing and top level
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (errs)
|
||||
exit (EXIT_FAILURE);
|
||||
if (nogo)
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
/*
|
||||
* Do the work.
|
||||
*/
|
||||
if (nfiles == 0)
|
||||
{
|
||||
error (err_noinput);
|
||||
usage ();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
{
|
||||
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;
|
||||
|
||||
idx = make_index ();
|
||||
|
||||
sourceform = read_input (&in, idx);
|
||||
if (!sourceform)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
sfree (in.pushback);
|
||||
|
||||
mark_attr_ends (sourceform);
|
||||
|
||||
sfree (infiles);
|
||||
|
||||
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);
|
||||
|
||||
build_index (idx);
|
||||
|
||||
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);
|
||||
|
||||
free_para_list (sourceform);
|
||||
free_keywords (keywords);
|
||||
cleanup_index (idx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbg_prtsource (paragraph * sourceform)
|
||||
{
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbg_prtkws (keywordlist * kws)
|
||||
{
|
||||
/*
|
||||
* Output keywords in debugging format.
|
||||
*/
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
22
Docs/src/bin/halibut/makefile
Normal file
22
Docs/src/bin/halibut/makefile
Normal file
|
@ -0,0 +1,22 @@
|
|||
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
|
||||
LIBS =
|
||||
|
||||
# -- Programs --
|
||||
MAKE = make
|
||||
CC = gcc
|
||||
RM = del
|
||||
|
||||
# -- Compilers and linker flags --
|
||||
DEFINES =
|
||||
CFLAGS = -Wall -W $(DEFINES)
|
||||
LFLAGS = -s
|
||||
|
||||
|
||||
all : halibut
|
||||
|
||||
halibut : $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LFLAGS) -o ..\halibut.exe $(OBJS) $(LIBS)
|
||||
|
||||
clean ::
|
||||
$(RM) *.o
|
||||
$(RM) ..\halibut.exe
|
173
Docs/src/bin/halibut/malloc.c
Normal file
173
Docs/src/bin/halibut/malloc.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* malloc.c: safe wrappers around malloc, realloc, free, strdup
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "halibut.h"
|
||||
|
||||
#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 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);
|
||||
}
|
||||
}
|
||||
static void
|
||||
logprintf (char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
vfprintf (logallocfp, fmt, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
#define LOGPRINT(x) ( logallocinit(), logprintf x )
|
||||
#define LOGINC do { loginc(); logline++; } while (0)
|
||||
#else
|
||||
#define LOGPARAMS
|
||||
#define LOGPRINT(x)
|
||||
#define LOGINC ((void)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *r = smalloc (1 + strlen (s));
|
||||
strcpy (r, s);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a linked list of words
|
||||
*/
|
||||
word *
|
||||
dup_word_list (word * w)
|
||||
{
|
||||
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;
|
||||
|
||||
w = w->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a linked list of words
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a linked list of paragraphs
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
377
Docs/src/bin/halibut/misc.c
Normal file
377
Docs/src/bin/halibut/misc.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* misc.c: miscellaneous useful items
|
||||
*/
|
||||
|
||||
#include "halibut.h"
|
||||
|
||||
struct stackTag
|
||||
{
|
||||
void **data;
|
||||
int sp;
|
||||
int size;
|
||||
};
|
||||
|
||||
stack
|
||||
stk_new (void)
|
||||
{
|
||||
stack s;
|
||||
|
||||
s = mknew (struct stackTag);
|
||||
s->sp = 0;
|
||||
s->size = 0;
|
||||
s->data = NULL;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
stk_free (stack s)
|
||||
{
|
||||
sfree (s->data);
|
||||
sfree (s);
|
||||
}
|
||||
|
||||
void
|
||||
stk_push (stack s, void *item)
|
||||
{
|
||||
if (s->size <= s->sp)
|
||||
{
|
||||
s->size = s->sp + 32;
|
||||
s->data = resize (s->data, s->size);
|
||||
}
|
||||
s->data[s->sp++] = item;
|
||||
}
|
||||
|
||||
void *
|
||||
stk_pop (stack s)
|
||||
{
|
||||
if (s->sp > 0)
|
||||
return s->data[--s->sp];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Small routines to amalgamate a string from an input source.
|
||||
*/
|
||||
const rdstring empty_rdstring = { 0, 0, NULL };
|
||||
const rdstringc empty_rdstringc = { 0, 0, NULL };
|
||||
|
||||
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);
|
||||
}
|
||||
rs->text[rs->pos++] = c;
|
||||
rs->text[rs->pos] = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
ustrcpy (rs->text + rs->pos, p);
|
||||
rs->pos += len;
|
||||
}
|
||||
|
||||
wchar_t *
|
||||
rdtrim (rdstring * rs)
|
||||
{
|
||||
rs->text = resize (rs->text, rs->pos + 1);
|
||||
return rs->text;
|
||||
}
|
||||
|
||||
void
|
||||
rdaddc (rdstringc * rs, char c)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
strcpy (rs->text + rs->pos, p);
|
||||
rs->pos += len;
|
||||
}
|
||||
|
||||
char *
|
||||
rdtrimc (rdstringc * rs)
|
||||
{
|
||||
rs->text = resize (rs->text, rs->pos + 1);
|
||||
return rs->text;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (a || b)
|
||||
return (a ? +1 : -1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sfree (wrapwords);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void
|
||||
wrap_free (wrappedline * w)
|
||||
{
|
||||
while (w)
|
||||
{
|
||||
wrappedline *t = w->next;
|
||||
sfree (w);
|
||||
w = t;
|
||||
}
|
||||
}
|
7
Docs/src/bin/halibut/style.c
Normal file
7
Docs/src/bin/halibut/style.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* style.c: load and keep track of user style preferences
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "halibut.h"
|
2555
Docs/src/bin/halibut/tree234.c
Normal file
2555
Docs/src/bin/halibut/tree234.c
Normal file
File diff suppressed because it is too large
Load diff
203
Docs/src/bin/halibut/tree234.h
Normal file
203
Docs/src/bin/halibut/tree234.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* tree234.h: header defining functions in tree234.c.
|
||||
*
|
||||
* This file is copyright 1999-2001 Simon Tatham.
|
||||
*
|
||||
* 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, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef TREE234_H
|
||||
#define TREE234_H
|
||||
|
||||
/*
|
||||
* This typedef is opaque outside tree234.c itself.
|
||||
*/
|
||||
typedef struct tree234_Tag tree234;
|
||||
|
||||
typedef int (*cmpfn234) (void *, void *);
|
||||
|
||||
typedef void *(*copyfn234) (void *state, void *element);
|
||||
|
||||
/*
|
||||
* Create a 2-3-4 tree. If `cmp' is NULL, the tree is unsorted, and
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Free a 2-3-4 tree (not including freeing the elements).
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Add an element e to an unsorted 2-3-4 tree t. Returns e on
|
||||
* success, NULL on failure. (Failure should only occur if the
|
||||
* index is out of range or the tree is sorted.)
|
||||
*
|
||||
* Index range can be from 0 to the tree's current element count,
|
||||
* inclusive.
|
||||
*/
|
||||
void *addpos234 (tree234 * t, void *e, int index);
|
||||
|
||||
/*
|
||||
* Look up the element at a given numeric index in a 2-3-4 tree.
|
||||
* Returns NULL if the index is out of range.
|
||||
*
|
||||
* One obvious use for this function is in iterating over the whole
|
||||
* of a tree (sorted or unsorted):
|
||||
*
|
||||
* for (i = 0; (p = index234(tree, i)) != NULL; i++) consume(p);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* int maxcount = count234(tree);
|
||||
* for (i = 0; i < maxcount; i++) {
|
||||
* p = index234(tree, i);
|
||||
* assert(p != NULL);
|
||||
* consume(p);
|
||||
* }
|
||||
*/
|
||||
void *index234 (tree234 * t, int index);
|
||||
|
||||
/*
|
||||
* Find an element e in a sorted 2-3-4 tree t. Returns NULL if not
|
||||
* found. e is always passed as the first argument to cmp, so cmp
|
||||
* can be an asymmetric function if desired. cmp can also be passed
|
||||
* as NULL, in which case the compare function from the tree proper
|
||||
* will be used.
|
||||
*
|
||||
* Three of these functions are special cases of findrelpos234. The
|
||||
* non-`pos' variants lack the `index' parameter: if the parameter
|
||||
* is present and non-NULL, it must point to an integer variable
|
||||
* which will be filled with the numeric index of the returned
|
||||
* element.
|
||||
*
|
||||
* The non-`rel' variants lack the `relation' parameter. This
|
||||
* parameter allows you to specify what relation the element you
|
||||
* provide has to the element you're looking for. This parameter
|
||||
* can be:
|
||||
*
|
||||
* REL234_EQ - find only an element that compares equal to e
|
||||
* REL234_LT - find the greatest element that compares < e
|
||||
* REL234_LE - find the greatest element that compares <= e
|
||||
* REL234_GT - find the smallest element that compares > e
|
||||
* REL234_GE - find the smallest element that compares >= e
|
||||
*
|
||||
* Non-`rel' variants assume REL234_EQ.
|
||||
*
|
||||
* If `rel' is REL234_GT or REL234_LT, the `e' parameter may be
|
||||
* NULL. In this case, REL234_GT will return the smallest element
|
||||
* in the tree, and REL234_LT will return the greatest. This gives
|
||||
* an alternative means of iterating over a sorted tree, instead of
|
||||
* using index234:
|
||||
*
|
||||
* // to loop forwards
|
||||
* for (p = NULL; (p = findrel234(tree, p, NULL, REL234_GT)) != NULL ;)
|
||||
* consume(p);
|
||||
*
|
||||
* // to loop backwards
|
||||
* for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;)
|
||||
* consume(p);
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Delete an element e in a 2-3-4 tree. Does not free the element,
|
||||
* merely removes all links to it from the tree nodes.
|
||||
*
|
||||
* delpos234 deletes the element at a particular tree index: it
|
||||
* works on both sorted and unsorted trees.
|
||||
*
|
||||
* del234 deletes the element passed to it, so it only works on
|
||||
* sorted trees. (It's equivalent to using findpos234 to determine
|
||||
* the index of an element, and then passing that index to
|
||||
* delpos234.)
|
||||
*
|
||||
* Both functions return a pointer to the element they delete, for
|
||||
* the user to free or pass on elsewhere or whatever. If the index
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Return the total element count of a tree234.
|
||||
*/
|
||||
int count234 (tree234 * t);
|
||||
|
||||
/*
|
||||
* Split a tree234 into two valid tree234s.
|
||||
*
|
||||
* splitpos234 splits at a given index. If `before' is TRUE, the
|
||||
* items at and after that index are left in t and the ones before
|
||||
* are returned; if `before' is FALSE, the items before that index
|
||||
* are left in t and the rest are returned.
|
||||
*
|
||||
* split234 splits at a given key. You can pass any of the
|
||||
* relations used with findrel234, except for REL234_EQ. The items
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Join two tree234s together into a single one.
|
||||
*
|
||||
* All the elements in t1 are placed to the left of all the
|
||||
* elements in t2. If the trees are sorted, there will be a test to
|
||||
* ensure that this satisfies the ordering criterion, and NULL will
|
||||
* be returned otherwise. If the trees are unsorted, there is no
|
||||
* restriction on the use of join234.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Make a complete copy of a tree234. Element pointers will be
|
||||
* reused unless copyfn is non-NULL, in which case it will be used
|
||||
* to copy each element. (copyfn takes two `void *' parameters; the
|
||||
* 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);
|
||||
|
||||
#endif /* TREE234_H */
|
216
Docs/src/bin/halibut/ustring.c
Normal file
216
Docs/src/bin/halibut/ustring.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* ustring.c: Unicode string routines
|
||||
*/
|
||||
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#include "halibut.h"
|
||||
|
||||
wchar_t *
|
||||
ustrdup (wchar_t * s)
|
||||
{
|
||||
wchar_t *r;
|
||||
if (s)
|
||||
{
|
||||
r = mknewa (wchar_t, 1 + ustrlen (s));
|
||||
ustrcpy (r, s);
|
||||
}
|
||||
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;
|
||||
}
|
||||
for (p = outbuf; *s && p < outbuf + size; p++, s++)
|
||||
*p = *s;
|
||||
if (p < outbuf + size)
|
||||
*p = '\0';
|
||||
else
|
||||
outbuf[size - 1] = '\0';
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
int
|
||||
ustrlen (wchar_t * s)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 *p = s;
|
||||
while (*p)
|
||||
{
|
||||
*p = utolower (*p);
|
||||
p++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
utoi (wchar_t * s)
|
||||
{
|
||||
int sign = +1;
|
||||
int n;
|
||||
|
||||
if (*s == L'-')
|
||||
{
|
||||
s++;
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (*s && *s >= L'0' && *s <= L'9')
|
||||
{
|
||||
n *= 10;
|
||||
n += (*s - '0');
|
||||
s++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
uisdigit (wchar_t c)
|
||||
{
|
||||
return c >= L'0' && c <= L'9';
|
||||
}
|
||||
|
||||
#define USTRFTIME_DELTA 128
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
13
Docs/src/bin/halibut/version.c
Normal file
13
Docs/src/bin/halibut/version.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* version.c: version string
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef VERSION
|
||||
#define VER "anonymous build (" __DATE__ " " __TIME__ ")"
|
||||
#else
|
||||
#define VER "version " VERSION
|
||||
#endif
|
||||
|
||||
const char *const version = VER;
|
2272
Docs/src/bin/halibut/winhelp.c
Normal file
2272
Docs/src/bin/halibut/winhelp.c
Normal file
File diff suppressed because it is too large
Load diff
173
Docs/src/bin/halibut/winhelp.h
Normal file
173
Docs/src/bin/halibut/winhelp.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* winhelp.h header file for winhelp.c
|
||||
*/
|
||||
|
||||
typedef struct WHLP_tag *WHLP;
|
||||
|
||||
typedef struct WHLP_TOPIC_tag *WHLP_TOPIC;
|
||||
|
||||
/*
|
||||
* Initialise a new WHlp context and begin accumulating data in it.
|
||||
*/
|
||||
WHLP whlp_new (void);
|
||||
|
||||
/*
|
||||
* Close a WHlp context and write out the help file it has created.
|
||||
*/
|
||||
void whlp_close (WHLP h, char *filename);
|
||||
|
||||
/*
|
||||
* Abandon and free a WHlp context without writing out anything.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Register a help topic. Irritatingly, due to weird phase-order
|
||||
* issues with the whole file format, you have to register all your
|
||||
* topics _before_ actually outputting your text. This seems likely
|
||||
* to require two passes over the source document.
|
||||
*
|
||||
* If you want to specify a particular context string (for
|
||||
* reference from other programs, to provide context-sensitive
|
||||
* help), you can supply it here. Otherwise, just pass NULL and a
|
||||
* nondescript one will be allocated automatically.
|
||||
*
|
||||
* If you specify two context strings which clash under the Windows
|
||||
* help file hash algorithm, this function will return NULL and
|
||||
* provide a pointer to the other context string that this one
|
||||
* clashed with, and you must tell your user to fix the clash.
|
||||
* Sadly this is the only way to do it; despite HLP files having a
|
||||
* perfectly good method of mapping arbitrary strings to things,
|
||||
* they didn't see fit to use that method for help contexts, so
|
||||
* instead they hash the context names and expect the hashes to be
|
||||
* unique. Sigh.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* After calling whlp_register_topic for all topics, you should
|
||||
* call this, which will sort out all loose ends and allocate
|
||||
* context names for all anonymous topics. Then you can start
|
||||
* writing actual text.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Call this if you need the id of a topic and you don't already
|
||||
* know it (for example, if whlp_prepare has allocated it
|
||||
* anonymously for you). You might need this, for example, in
|
||||
* creating macros for button-bar bindings.
|
||||
*
|
||||
* The string returned will be freed when the WHLP context is
|
||||
* closed. You should not free it yourself.
|
||||
*
|
||||
* Do not call this before calling whlp_prepare().
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Call this when about to begin writing out the text for a topic.
|
||||
*
|
||||
* Any additional arguments are Help macros, terminated with a
|
||||
* NULL. So the minimum call sequence is
|
||||
*
|
||||
* whlp_begin_topic(helpfile, mytopic, "Title", NULL);
|
||||
*/
|
||||
void whlp_begin_topic (WHLP h, WHLP_TOPIC topic, char *title, ...);
|
||||
|
||||
/*
|
||||
* Call this to set up a font descriptor. You supply the font name,
|
||||
* the font size (in half-points), the graphic rendition flags
|
||||
* (bold, italic etc), and the general font family (for Windows to
|
||||
* select a fallback font if yours is unavailable). You can also
|
||||
* specify a foreground colour for the text (but unfortunately not
|
||||
* a background).
|
||||
*
|
||||
* Font descriptors are identified in whlp_set_font() by small
|
||||
* integers, which are allocated from 0 upwards in the order you
|
||||
* call whlp_create_font(). For your convenience,
|
||||
* whlp_create_font() returns the integer allocated to each font
|
||||
* 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_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);
|
||||
|
||||
/*
|
||||
* Routines to output paragraphs and actual text (at last).
|
||||
*
|
||||
* You should start by calling whlp_para_attr() to set any
|
||||
* paragraph attributes that differ from the standard settings.
|
||||
* Next call whlp_begin_para() to start the paragraph. Then call
|
||||
* the various in-paragraph functions until you have output the
|
||||
* 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_ALIGN_LEFT, WHLP_ALIGN_RIGHT, WHLP_ALIGN_CENTRE
|
||||
};
|
||||
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);
|
Loading…
Add table
Add a link
Reference in a new issue