Hopefully readable now: indent -nut -kr -bl -bli0 -i2 *

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@2423 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
kichik 2003-04-04 14:43:36 +00:00
parent e1bc9f0971
commit 0e30afb5d9
16 changed files with 6231 additions and 5689 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -8,7 +8,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
#define NORETURN __attribute__((__noreturn__)) #define NORETURN __attribute__((__noreturn__))
#else #else
#define NORETURN /* nothing */ #define NORETURN /* nothing */
#endif #endif
#ifndef TRUE #ifndef TRUE
@ -44,27 +44,27 @@ typedef struct macrostack_Tag macrostack;
* column number, for reporting errors * column number, for reporting errors
*/ */
struct filepos_Tag { struct filepos_Tag {
char *filename; char *filename;
int line, col; int line, col;
}; };
/* /*
* Data structure to hold all the file names etc for input * Data structure to hold all the file names etc for input
*/ */
typedef struct pushback_Tag { typedef struct pushback_Tag {
int chr; int chr;
filepos pos; filepos pos;
} pushback; } pushback;
struct input_Tag { struct input_Tag {
char **filenames; /* complete list of input files */ char **filenames; /* complete list of input files */
int nfiles; /* how many in the list */ int nfiles; /* how many in the list */
FILE *currfp; /* the currently open one */ FILE *currfp; /* the currently open one */
int currindex; /* which one is that in the list */ int currindex; /* which one is that in the list */
pushback *pushback; /* pushed-back input characters */ pushback *pushback; /* pushed-back input characters */
int npushback, pushbacksize; int npushback, pushbacksize;
filepos pos; filepos pos;
int reportcols; /* report column numbers in errors */ int reportcols; /* report column numbers in errors */
macrostack *stack; /* macro expansions in force */ macrostack *stack; /* macro expansions in force */
}; };
/* /*
@ -72,95 +72,95 @@ struct input_Tag {
* list of paragraphs * list of paragraphs
*/ */
struct paragraph_Tag { struct paragraph_Tag {
paragraph *next; paragraph *next;
int type; int type;
wchar_t *keyword; /* for most special paragraphs */ wchar_t *keyword; /* for most special paragraphs */
word *words; /* list of words in paragraph */ word *words; /* list of words in paragraph */
int aux; /* number, in a numbered paragraph int aux; /* number, in a numbered paragraph
* or subsection level * or subsection level
*/ */
word *kwtext; /* chapter/section indication */ word *kwtext; /* chapter/section indication */
word *kwtext2; /* numeric-only form of kwtext */ word *kwtext2; /* numeric-only form of kwtext */
filepos fpos; filepos fpos;
paragraph *parent, *child, *sibling; /* for hierarchy navigation */ paragraph *parent, *child, *sibling; /* for hierarchy navigation */
void *private_data; /* for temp use in backends */ void *private_data; /* for temp use in backends */
}; };
enum { enum {
para_IM, /* index merge */ para_IM, /* index merge */
para_BR, /* bibliography rewrite */ para_BR, /* bibliography rewrite */
para_Rule, /* random horizontal rule */ para_Rule, /* random horizontal rule */
para_Chapter, para_Chapter,
para_Appendix, para_Appendix,
para_UnnumberedChapter, para_UnnumberedChapter,
para_Heading, para_Heading,
para_Subsect, para_Subsect,
para_Normal, para_Normal,
para_Biblio, /* causes no output unless turned ... */ para_Biblio, /* causes no output unless turned ... */
para_BiblioCited, /* ... into this paragraph type */ para_BiblioCited, /* ... into this paragraph type */
para_Bullet, para_Bullet,
para_NumberedList, para_NumberedList,
para_Code, para_Code,
para_Copyright, para_Copyright,
para_Preamble, para_Preamble,
para_NoCite, para_NoCite,
para_Title, para_Title,
para_VersionID, para_VersionID,
para_Config, /* configuration directive */ para_Config, /* configuration directive */
para_NotParaType /* placeholder value */ para_NotParaType /* placeholder value */
}; };
/* /*
* Data structure to hold an individual word * Data structure to hold an individual word
*/ */
struct word_Tag { struct word_Tag {
word *next, *alt; word *next, *alt;
int type; int type;
int aux; int aux;
int breaks; /* can a line break after it? */ int breaks; /* can a line break after it? */
wchar_t *text; wchar_t *text;
filepos fpos; filepos fpos;
}; };
enum { enum {
/* ORDERING CONSTRAINT: these normal-word types ... */ /* ORDERING CONSTRAINT: these normal-word types ... */
word_Normal, word_Normal,
word_Emph, word_Emph,
word_Code, /* monospaced; `quoted' in text */ word_Code, /* monospaced; `quoted' in text */
word_WeakCode, /* monospaced, normal in text */ word_WeakCode, /* monospaced, normal in text */
/* ... must be in the same order as these space types ... */ /* ... must be in the same order as these space types ... */
word_WhiteSpace, /* text is NULL or ignorable */ word_WhiteSpace, /* text is NULL or ignorable */
word_EmphSpace, /* WhiteSpace when emphasised */ word_EmphSpace, /* WhiteSpace when emphasised */
word_CodeSpace, /* WhiteSpace when code */ word_CodeSpace, /* WhiteSpace when code */
word_WkCodeSpace, /* WhiteSpace when weak code */ word_WkCodeSpace, /* WhiteSpace when weak code */
/* ... and must be in the same order as these quote types ... */ /* ... and must be in the same order as these quote types ... */
word_Quote, /* text is NULL or ignorable */ word_Quote, /* text is NULL or ignorable */
word_EmphQuote, /* Quote when emphasised */ word_EmphQuote, /* Quote when emphasised */
word_CodeQuote, /* (can't happen) */ word_CodeQuote, /* (can't happen) */
word_WkCodeQuote, /* (can't happen) */ word_WkCodeQuote, /* (can't happen) */
/* END ORDERING CONSTRAINT */ /* END ORDERING CONSTRAINT */
word_internal_endattrs, word_internal_endattrs,
word_UpperXref, /* \K */ word_UpperXref, /* \K */
word_LowerXref, /* \k */ word_LowerXref, /* \k */
word_XrefEnd, /* (invisible; no text) */ word_XrefEnd, /* (invisible; no text) */
word_IndexRef, /* (always an invisible one) */ word_IndexRef, /* (always an invisible one) */
word_HyperLink, /* (invisible) */ word_HyperLink, /* (invisible) */
word_HyperEnd, /* (also invisible; no text) */ word_HyperEnd, /* (also invisible; no text) */
word_FreeTextXref /* \R */ word_FreeTextXref /* \R */
}; };
/* aux values for attributed words */ /* aux values for attributed words */
enum { enum {
attr_Only = 0x0000, /* a lone word with the attribute */ attr_Only = 0x0000, /* a lone word with the attribute */
attr_First = 0x0001, /* the first of a series */ attr_First = 0x0001, /* the first of a series */
attr_Last = 0x0002, /* the last of a series */ attr_Last = 0x0002, /* the last of a series */
attr_Always = 0x0003, /* any other part of a series */ attr_Always = 0x0003, /* any other part of a series */
attr_mask = 0x0003, attr_mask = 0x0003,
}; };
/* aux values for quote-type words */ /* aux values for quote-type words */
enum { enum {
quote_Open = 0x0010, quote_Open = 0x0010,
quote_Close = 0x0020, quote_Close = 0x0020,
quote_mask = 0x0030, quote_mask = 0x0030,
}; };
#define isattr(x) ( ( (x) > word_Normal && (x) < word_WhiteSpace ) || \ #define isattr(x) ( ( (x) > word_Normal && (x) < word_WhiteSpace ) || \
( (x) > word_WhiteSpace && (x) < word_internal_endattrs ) ) ( (x) > word_WhiteSpace && (x) < word_internal_endattrs ) )
@ -179,36 +179,36 @@ enum {
void fatal(int code, ...) NORETURN; void fatal(int code, ...) NORETURN;
void error(int code, ...); void error(int code, ...);
enum { enum {
err_nomemory, /* out of memory */ err_nomemory, /* out of memory */
err_optnoarg, /* option `-%s' requires an argument */ err_optnoarg, /* option `-%s' requires an argument */
err_nosuchopt, /* unrecognised option `-%s' */ err_nosuchopt, /* unrecognised option `-%s' */
err_noinput, /* no input files */ err_noinput, /* no input files */
err_cantopen, /* unable to open input file `%s' */ err_cantopen, /* unable to open input file `%s' */
err_nodata, /* no data in input files */ err_nodata, /* no data in input files */
err_brokencodepara, /* line in codepara didn't begin `\c' */ err_brokencodepara, /* line in codepara didn't begin `\c' */
err_kwunclosed, /* expected `}' after keyword */ err_kwunclosed, /* expected `}' after keyword */
err_kwillegal, /* paragraph type expects no keyword */ err_kwillegal, /* paragraph type expects no keyword */
err_kwexpected, /* paragraph type expects a keyword */ err_kwexpected, /* paragraph type expects a keyword */
err_kwtoomany, /* paragraph type expects only 1 */ err_kwtoomany, /* paragraph type expects only 1 */
err_bodyillegal, /* paragraph type expects only kws! */ err_bodyillegal, /* paragraph type expects only kws! */
err_badparatype, /* invalid command at start of para */ err_badparatype, /* invalid command at start of para */
err_badmidcmd, /* invalid command in mid-para */ err_badmidcmd, /* invalid command in mid-para */
err_unexbrace, /* unexpected brace */ err_unexbrace, /* unexpected brace */
err_explbr, /* expected `{' after command */ err_explbr, /* expected `{' after command */
err_commenteof, /* EOF inside braced comment */ err_commenteof, /* EOF inside braced comment */
err_kwexprbr, /* expected `}' after cross-ref */ err_kwexprbr, /* expected `}' after cross-ref */
err_missingrbrace, /* unclosed braces at end of para */ err_missingrbrace, /* unclosed braces at end of para */
err_nestedstyles, /* unable to nest text styles */ err_nestedstyles, /* unable to nest text styles */
err_nestedindex, /* unable to nest `\i' thingys */ err_nestedindex, /* unable to nest `\i' thingys */
err_nosuchkw, /* unresolved cross-reference */ err_nosuchkw, /* unresolved cross-reference */
err_multiBR, /* multiple \BRs on same keyword */ err_multiBR, /* multiple \BRs on same keyword */
err_nosuchidxtag, /* \IM on unknown index tag (warning) */ err_nosuchidxtag, /* \IM on unknown index tag (warning) */
err_cantopenw, /* can't open output file for write */ err_cantopenw, /* can't open output file for write */
err_macroexists, /* this macro already exists */ err_macroexists, /* this macro already exists */
err_sectjump, /* jump a heading level, eg \C -> \S */ err_sectjump, /* jump a heading level, eg \C -> \S */
err_winhelp_ctxclash, /* WinHelp context ID hash clash */ err_winhelp_ctxclash, /* WinHelp context ID hash clash */
err_multikw, /* keyword clash in sections */ err_multikw, /* keyword clash in sections */
err_whatever /* random error of another type */ err_whatever /* random error of another type */
}; };
/* /*
@ -280,13 +280,13 @@ void *stk_pop(stack);
typedef struct tagRdstring rdstring; typedef struct tagRdstring rdstring;
struct tagRdstring { struct tagRdstring {
int pos, size; int pos, size;
wchar_t *text; wchar_t *text;
}; };
typedef struct tagRdstringc rdstringc; typedef struct tagRdstringc rdstringc;
struct tagRdstringc { struct tagRdstringc {
int pos, size; int pos, size;
char *text; char *text;
}; };
extern const rdstring empty_rdstring; extern const rdstring empty_rdstring;
extern const rdstringc empty_rdstringc; extern const rdstringc empty_rdstringc;
@ -303,10 +303,10 @@ void mark_attr_ends(paragraph * sourceform);
typedef struct tagWrappedLine wrappedline; typedef struct tagWrappedLine wrappedline;
struct tagWrappedLine { struct tagWrappedLine {
wrappedline *next; wrappedline *next;
word *begin, *end; /* first & last words of line */ word *begin, *end; /* first & last words of line */
int nspaces; /* number of whitespaces in line */ int nspaces; /* number of whitespaces in line */
int shortfall; /* how much shorter than max width */ int shortfall; /* how much shorter than max width */
}; };
wrappedline *wrap_para(word *, int, int, int (*)(word *)); wrappedline *wrap_para(word *, int, int, int (*)(word *));
void wrap_free(wrappedline *); void wrap_free(wrappedline *);
@ -320,18 +320,18 @@ paragraph *read_input(input * in, indexdata * idx);
* keywords.c * keywords.c
*/ */
struct keywordlist_Tag { struct keywordlist_Tag {
int nkeywords; int nkeywords;
int size; int size;
tree234 *keys; /* sorted by `key' field */ tree234 *keys; /* sorted by `key' field */
word **looseends; /* non-keyword list element numbers */ word **looseends; /* non-keyword list element numbers */
int nlooseends; int nlooseends;
int looseendssize; int looseendssize;
}; };
struct keyword_Tag { struct keyword_Tag {
wchar_t *key; /* the keyword itself */ wchar_t *key; /* the keyword itself */
word *text; /* "Chapter 2", "Appendix Q"... */ word *text; /* "Chapter 2", "Appendix Q"... */
/* (NB: filepos are not set) */ /* (NB: filepos are not set) */
paragraph *para; /* the paragraph referenced */ paragraph *para; /* the paragraph referenced */
}; };
keyword *kw_lookup(keywordlist *, wchar_t *); keyword *kw_lookup(keywordlist *, wchar_t *);
keywordlist *get_keywords(paragraph *); keywordlist *get_keywords(paragraph *);
@ -346,28 +346,28 @@ void subst_keywords(paragraph *, keywordlist *);
* Data structure to hold both sides of the index. * Data structure to hold both sides of the index.
*/ */
struct indexdata_Tag { struct indexdata_Tag {
tree234 *tags; /* holds type `indextag' */ tree234 *tags; /* holds type `indextag' */
tree234 *entries; /* holds type `indexentry' */ tree234 *entries; /* holds type `indexentry' */
}; };
/* /*
* Data structure to hold an index tag (LHS of index). * Data structure to hold an index tag (LHS of index).
*/ */
struct indextag_Tag { struct indextag_Tag {
wchar_t *name; wchar_t *name;
word *implicit_text; word *implicit_text;
word **explicit_texts; word **explicit_texts;
int nexplicit, explicit_size; int nexplicit, explicit_size;
int nrefs; int nrefs;
indexentry **refs; /* array of entries referenced by tag */ indexentry **refs; /* array of entries referenced by tag */
}; };
/* /*
* Data structure to hold an index entry (RHS of index). * Data structure to hold an index entry (RHS of index).
*/ */
struct indexentry_Tag { struct indexentry_Tag {
word *text; word *text;
void *backend_data; /* private to back end */ void *backend_data; /* private to back end */
}; };
indexdata *make_index(void); indexdata *make_index(void);

View file

@ -6,18 +6,18 @@
#include "halibut.h" #include "halibut.h"
static char *usagetext[] = { static char *usagetext[] = {
"halibut.exe file1 [file2 ...]", "halibut.exe file1 [file2 ...]",
NULL NULL
}; };
void usage(void) void usage(void)
{ {
char **p; char **p;
for (p = usagetext; *p; p++) for (p = usagetext; *p; p++)
puts(*p); puts(*p);
} }
void showversion(void) void showversion(void)
{ {
printf("Halibut, %s\n", version); printf("Halibut, %s\n", version);
} }

View file

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

File diff suppressed because it is too large Load diff

View file

@ -9,21 +9,21 @@
static int kwcmp(void *av, void *bv) static int kwcmp(void *av, void *bv)
{ {
const keyword *a = (const keyword *) av; const keyword *a = (const keyword *) av;
const keyword *b = (const keyword *) bv; const keyword *b = (const keyword *) bv;
return ustrcmp(a->key, b->key); return ustrcmp(a->key, b->key);
} }
static int kwfind(void *av, void *bv) static int kwfind(void *av, void *bv)
{ {
wchar_t *a = (wchar_t *) av; wchar_t *a = (wchar_t *) av;
const keyword *b = (const keyword *) bv; const keyword *b = (const keyword *) bv;
return ustrcmp(a, b->key); return ustrcmp(a, b->key);
} }
keyword *kw_lookup(keywordlist * kl, wchar_t * str) keyword *kw_lookup(keywordlist * kl, wchar_t * str)
{ {
return find234(kl->keys, str, kwfind); return find234(kl->keys, str, kwfind);
} }
/* /*
@ -34,126 +34,138 @@ keyword *kw_lookup(keywordlist * kl, wchar_t * str)
*/ */
keywordlist *get_keywords(paragraph * source) keywordlist *get_keywords(paragraph * source)
{ {
int errors = FALSE; int errors = FALSE;
keywordlist *kl = mknew(keywordlist); keywordlist *kl = mknew(keywordlist);
numberstate *n = number_init(); numberstate *n = number_init();
int prevpara = para_NotParaType; int prevpara = para_NotParaType;
number_cfg(n, source); number_cfg(n, source);
kl->size = 0; kl->size = 0;
kl->keys = newtree234(kwcmp); kl->keys = newtree234(kwcmp);
kl->nlooseends = kl->looseendssize = 0; kl->nlooseends = kl->looseendssize = 0;
kl->looseends = NULL; kl->looseends = NULL;
for (; source; source = source->next) { for (; source; source = source->next)
wchar_t *p, *q; {
p = q = source->keyword; wchar_t *p, *q;
p = q = source->keyword;
/* /*
* Look for the section type override (`example', * Look for the section type override (`example',
* `question' or whatever - to replace `chapter' or * `question' or whatever - to replace `chapter' or
* `section' on a per-section basis). * `section' on a per-section basis).
*/ */
if (q) { if (q)
q = uadv(q); /* point q at the word beyond */ {
if (!*q) q = uadv(q); /* point q at the word beyond */
q = NULL; 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); /*
* 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 (errors) { if (p && *p)
free_keywords(kl); {
return NULL; 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;
} }
}
return kl; number_free(n);
if (errors)
{
free_keywords(kl);
return NULL;
}
return kl;
} }
void free_keywords(keywordlist * kl) void free_keywords(keywordlist * kl)
{ {
keyword *kw; keyword *kw;
while (kl->nlooseends) while (kl->nlooseends)
free_word_list(kl->looseends[--kl->nlooseends]); free_word_list(kl->looseends[--kl->nlooseends]);
sfree(kl->looseends); sfree(kl->looseends);
while ((kw = index234(kl->keys, 0)) != NULL) { while ((kw = index234(kl->keys, 0)) != NULL)
delpos234(kl->keys, 0); {
free_word_list(kw->text); delpos234(kl->keys, 0);
sfree(kw); free_word_list(kw->text);
} sfree(kw);
freetree234(kl->keys); }
sfree(kl); freetree234(kl->keys);
sfree(kl);
} }
void subst_keywords(paragraph * source, keywordlist * kl) void subst_keywords(paragraph * source, keywordlist * kl)
{ {
for (; source; source = source->next) { for (; source; source = source->next)
word *ptr; {
for (ptr = source->words; ptr; ptr = ptr->next) { word *ptr;
if (ptr->type == word_UpperXref || ptr->type == word_LowerXref) { for (ptr = source->words; ptr; ptr = ptr->next)
keyword *kw; {
word **endptr, *close, *subst; if (ptr->type == word_UpperXref || ptr->type == word_LowerXref)
{
keyword *kw;
word **endptr, *close, *subst;
kw = kw_lookup(kl, ptr->text); kw = kw_lookup(kl, ptr->text);
if (!kw) { if (!kw)
error(err_nosuchkw, &ptr->fpos, ptr->text); {
subst = NULL; error(err_nosuchkw, &ptr->fpos, ptr->text);
} else subst = NULL;
subst = dup_word_list(kw->text); } else
subst = dup_word_list(kw->text);
if (subst && ptr->type == word_LowerXref && if (subst && ptr->type == word_LowerXref &&
kw->para->type != para_Biblio && kw->para->type != para_Biblio &&
kw->para->type != para_BiblioCited) kw->para->type != para_BiblioCited)
ustrlow(subst->text); ustrlow(subst->text);
close = mknew(word); close = mknew(word);
close->text = NULL; close->text = NULL;
close->alt = NULL; close->alt = NULL;
close->type = word_XrefEnd; close->type = word_XrefEnd;
close->fpos = ptr->fpos; close->fpos = ptr->fpos;
close->next = ptr->next; close->next = ptr->next;
ptr->next = subst; ptr->next = subst;
for (endptr = &ptr->next; *endptr; for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next)
endptr = &(*endptr)->next) (*endptr)->fpos = ptr->fpos;
(*endptr)->fpos = ptr->fpos;
*endptr = close; *endptr = close;
ptr = close; ptr = close;
} }
}
} }
}
} }

View file

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

View file

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

View file

@ -9,28 +9,30 @@
#ifdef LOGALLOC #ifdef LOGALLOC
#define LOGPARAMS char *file, int line, #define LOGPARAMS char *file, int line,
static FILE *logallocfp = NULL; static FILE *logallocfp = NULL;
static int logline = 2; /* off by 1: `null pointer is' */ static int logline = 2; /* off by 1: `null pointer is' */
static void loginc(void) static void loginc(void)
{ {
} }
static void logallocinit(void) static void logallocinit(void)
{ {
if (!logallocfp) { if (!logallocfp)
logallocfp = fopen("malloc.log", "w"); {
if (!logallocfp) { logallocfp = fopen("malloc.log", "w");
fprintf(stderr, "panic: unable to open malloc.log\n"); if (!logallocfp)
exit(10); {
} fprintf(stderr, "panic: unable to open malloc.log\n");
setvbuf(logallocfp, NULL, _IOLBF, BUFSIZ); exit(10);
fprintf(logallocfp, "null pointer is %p\n", NULL);
} }
setvbuf(logallocfp, NULL, _IOLBF, BUFSIZ);
fprintf(logallocfp, "null pointer is %p\n", NULL);
}
} }
static void logprintf(char *fmt, ...) static void logprintf(char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vfprintf(logallocfp, fmt, ap); vfprintf(logallocfp, fmt, ap);
va_end(ap); va_end(ap);
} }
#define LOGPRINT(x) ( logallocinit(), logprintf x ) #define LOGPRINT(x) ( logallocinit(), logprintf x )
@ -46,46 +48,49 @@ static void logprintf(char *fmt, ...)
* can do nothing except die when it's out of memory anyway. * can do nothing except die when it's out of memory anyway.
*/ */
void *(smalloc) (LOGPARAMS int size) { void *(smalloc) (LOGPARAMS int size) {
void *p; void *p;
LOGINC; LOGINC;
LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size)); LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size));
p = malloc(size); p = malloc(size);
if (!p) if (!p)
fatal(err_nomemory); fatal(err_nomemory);
LOGPRINT((" returns %p\n", p)); LOGPRINT((" returns %p\n", p));
return p; return p;
} }
/* /*
* sfree should guaranteeably deal gracefully with freeing NULL * sfree should guaranteeably deal gracefully with freeing NULL
*/ */
void (sfree) (LOGPARAMS void *p) { void (sfree) (LOGPARAMS void *p) {
if (p) { if (p)
LOGINC; {
LOGPRINT(("%s %d free(%p)\n", file, line, p)); LOGINC;
free(p); LOGPRINT(("%s %d free(%p)\n", file, line, p));
} free(p);
}
} }
/* /*
* srealloc should guaranteeably be able to realloc NULL * srealloc should guaranteeably be able to realloc NULL
*/ */
void *(srealloc) (LOGPARAMS void *p, int size) { void *(srealloc) (LOGPARAMS void *p, int size) {
void *q; void *q;
if (p) { if (p)
LOGINC; {
LOGPRINT(("%s %d realloc(%p,%ld)", file, line, p, (long) size)); LOGINC;
q = realloc(p, size); LOGPRINT(("%s %d realloc(%p,%ld)", file, line, p, (long) size));
LOGPRINT((" returns %p\n", q)); q = realloc(p, size);
} else { LOGPRINT((" returns %p\n", q));
LOGINC; } else
LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size)); {
q = malloc(size); LOGINC;
LOGPRINT((" returns %p\n", q)); LOGPRINT(("%s %d malloc(%ld)", file, line, (long) size));
} q = malloc(size);
if (!q) LOGPRINT((" returns %p\n", q));
fatal(err_nomemory); }
return q; if (!q)
fatal(err_nomemory);
return q;
} }
/* /*
@ -94,9 +99,9 @@ void *(srealloc) (LOGPARAMS void *p, int size) {
*/ */
char *dupstr(char *s) char *dupstr(char *s)
{ {
char *r = smalloc(1 + strlen(s)); char *r = smalloc(1 + strlen(s));
strcpy(r, s); strcpy(r, s);
return r; return r;
} }
/* /*
@ -104,22 +109,23 @@ char *dupstr(char *s)
*/ */
word *dup_word_list(word * w) word *dup_word_list(word * w)
{ {
word *head, **eptr = &head; word *head, **eptr = &head;
while (w) { while (w)
word *newwd = mknew(word); {
*newwd = *w; /* structure copy */ word *newwd = mknew(word);
newwd->text = ustrdup(w->text); *newwd = *w; /* structure copy */
if (w->alt) newwd->text = ustrdup(w->text);
newwd->alt = dup_word_list(w->alt); if (w->alt)
*eptr = newwd; newwd->alt = dup_word_list(w->alt);
newwd->next = NULL; *eptr = newwd;
eptr = &newwd->next; newwd->next = NULL;
eptr = &newwd->next;
w = w->next; w = w->next;
} }
return head; return head;
} }
/* /*
@ -127,15 +133,16 @@ word *dup_word_list(word * w)
*/ */
void free_word_list(word * w) void free_word_list(word * w)
{ {
word *t; word *t;
while (w) { while (w)
t = w; {
w = w->next; t = w;
sfree(t->text); w = w->next;
if (t->alt) sfree(t->text);
free_word_list(t->alt); if (t->alt)
sfree(t); free_word_list(t->alt);
} sfree(t);
}
} }
/* /*
@ -143,12 +150,13 @@ void free_word_list(word * w)
*/ */
void free_para_list(paragraph * p) void free_para_list(paragraph * p)
{ {
paragraph *t; paragraph *t;
while (p) { while (p)
t = p; {
p = p->next; t = p;
sfree(t->keyword); p = p->next;
free_word_list(t->words); sfree(t->keyword);
sfree(t); free_word_list(t->words);
} sfree(t);
}
} }

View file

@ -5,44 +5,45 @@
#include "halibut.h" #include "halibut.h"
struct stackTag { struct stackTag {
void **data; void **data;
int sp; int sp;
int size; int size;
}; };
stack stk_new(void) stack stk_new(void)
{ {
stack s; stack s;
s = mknew(struct stackTag); s = mknew(struct stackTag);
s->sp = 0; s->sp = 0;
s->size = 0; s->size = 0;
s->data = NULL; s->data = NULL;
return s; return s;
} }
void stk_free(stack s) void stk_free(stack s)
{ {
sfree(s->data); sfree(s->data);
sfree(s); sfree(s);
} }
void stk_push(stack s, void *item) void stk_push(stack s, void *item)
{ {
if (s->size <= s->sp) { if (s->size <= s->sp)
s->size = s->sp + 32; {
s->data = resize(s->data, s->size); s->size = s->sp + 32;
} s->data = resize(s->data, s->size);
s->data[s->sp++] = item; }
s->data[s->sp++] = item;
} }
void *stk_pop(stack s) void *stk_pop(stack s)
{ {
if (s->sp > 0) if (s->sp > 0)
return s->data[--s->sp]; return s->data[--s->sp];
else else
return NULL; return NULL;
} }
/* /*
@ -53,279 +54,304 @@ const rdstringc empty_rdstringc = { 0, 0, NULL };
void rdadd(rdstring * rs, wchar_t c) void rdadd(rdstring * rs, wchar_t c)
{ {
if (rs->pos >= rs->size - 1) { if (rs->pos >= rs->size - 1)
rs->size = rs->pos + 128; {
rs->text = resize(rs->text, rs->size); rs->size = rs->pos + 128;
} rs->text = resize(rs->text, rs->size);
rs->text[rs->pos++] = c; }
rs->text[rs->pos] = 0; rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
} }
void rdadds(rdstring * rs, wchar_t * p) void rdadds(rdstring * rs, wchar_t * p)
{ {
int len = ustrlen(p); int len = ustrlen(p);
if (rs->pos >= rs->size - len) { if (rs->pos >= rs->size - len)
rs->size = rs->pos + len + 128; {
rs->text = resize(rs->text, rs->size); rs->size = rs->pos + len + 128;
} rs->text = resize(rs->text, rs->size);
ustrcpy(rs->text + rs->pos, p); }
rs->pos += len; ustrcpy(rs->text + rs->pos, p);
rs->pos += len;
} }
wchar_t *rdtrim(rdstring * rs) wchar_t *rdtrim(rdstring * rs)
{ {
rs->text = resize(rs->text, rs->pos + 1); rs->text = resize(rs->text, rs->pos + 1);
return rs->text; return rs->text;
} }
void rdaddc(rdstringc * rs, char c) void rdaddc(rdstringc * rs, char c)
{ {
if (rs->pos >= rs->size - 1) { if (rs->pos >= rs->size - 1)
rs->size = rs->pos + 128; {
rs->text = resize(rs->text, rs->size); rs->size = rs->pos + 128;
} rs->text = resize(rs->text, rs->size);
rs->text[rs->pos++] = c; }
rs->text[rs->pos] = 0; rs->text[rs->pos++] = c;
rs->text[rs->pos] = 0;
} }
void rdaddsc(rdstringc * rs, char *p) void rdaddsc(rdstringc * rs, char *p)
{ {
int len = strlen(p); int len = strlen(p);
if (rs->pos >= rs->size - len) { if (rs->pos >= rs->size - len)
rs->size = rs->pos + len + 128; {
rs->text = resize(rs->text, rs->size); rs->size = rs->pos + len + 128;
} rs->text = resize(rs->text, rs->size);
strcpy(rs->text + rs->pos, p); }
rs->pos += len; strcpy(rs->text + rs->pos, p);
rs->pos += len;
} }
char *rdtrimc(rdstringc * rs) char *rdtrimc(rdstringc * rs)
{ {
rs->text = resize(rs->text, rs->pos + 1); rs->text = resize(rs->text, rs->pos + 1);
return rs->text; return rs->text;
} }
int compare_wordlists(word * a, word * b) int compare_wordlists(word * a, word * b)
{ {
int t; int t;
while (a && b) { while (a && b)
if (a->type != b->type) {
return (a->type < b->type ? -1 : +1); /* FIXME? */ if (a->type != b->type)
t = a->type; return (a->type < b->type ? -1 : +1); /* FIXME? */
if ((t != word_Normal && t != word_Code && t = a->type;
t != word_WeakCode && t != word_Emph) || a->alt || b->alt) { if ((t != word_Normal && t != word_Code &&
int c; t != word_WeakCode && t != word_Emph) || a->alt || b->alt)
if (a->text && b->text) { {
c = ustricmp(a->text, b->text); int c;
if (c) if (a->text && b->text)
return c; {
} c = ustricmp(a->text, b->text);
c = compare_wordlists(a->alt, b->alt); if (c)
if (c) return c;
return c; }
a = a->next; c = compare_wordlists(a->alt, b->alt);
b = b->next; if (c)
} else { return c;
wchar_t *ap = a->text, *bp = b->text; a = a->next;
while (*ap && *bp) { b = b->next;
wchar_t ac = utolower(*ap), bc = utolower(*bp); } else
if (ac != bc) {
return (ac < bc ? -1 : +1); wchar_t *ap = a->text, *bp = b->text;
if (!*++ap && a->next && a->next->type == t while (*ap && *bp)
&& !a->next->alt) {
a = a->next, ap = a->text; wchar_t ac = utolower(*ap), bc = utolower(*bp);
if (!*++bp && b->next && b->next->type == t if (ac != bc)
&& !b->next->alt) return (ac < bc ? -1 : +1);
b = b->next, bp = b->text; if (!*++ap && a->next && a->next->type == t && !a->next->alt)
} a = a->next, ap = a->text;
if (*ap || *bp) if (!*++bp && b->next && b->next->type == t && !b->next->alt)
return (*ap ? +1 : -1); b = b->next, bp = b->text;
a = a->next; }
b = b->next; if (*ap || *bp)
} return (*ap ? +1 : -1);
a = a->next;
b = b->next;
} }
}
if (a || b) if (a || b)
return (a ? +1 : -1); return (a ? +1 : -1);
else else
return 0; return 0;
} }
void mark_attr_ends(paragraph * sourceform) void mark_attr_ends(paragraph * sourceform)
{ {
paragraph *p; paragraph *p;
word *w, *wp; word *w, *wp;
for (p = sourceform; p; p = p->next) { for (p = sourceform; p; p = p->next)
wp = NULL; {
for (w = p->words; w; w = w->next) { wp = NULL;
if (isattr(w->type)) { for (w = p->words; w; w = w->next)
int before = (wp && isattr(wp->type) && {
sameattr(wp->type, w->type)); if (isattr(w->type))
int after = (w->next && isattr(w->next->type) && {
sameattr(w->next->type, w->type)); int before = (wp && isattr(wp->type) &&
w->aux |= (before ? sameattr(wp->type, w->type));
(after ? attr_Always : attr_Last) : int after = (w->next && isattr(w->next->type) &&
(after ? attr_First : attr_Only)); sameattr(w->next->type, w->type));
} w->aux |= (before ?
wp = w; (after ? attr_Always : attr_Last) :
} (after ? attr_First : attr_Only));
}
wp = w;
} }
}
} }
wrappedline *wrap_para(word * text, int width, int subsequentwidth, wrappedline *wrap_para(word * text, int width, int subsequentwidth,
int (*widthfn) (word *)) int (*widthfn) (word *))
{ {
wrappedline *head = NULL, **ptr = &head; wrappedline *head = NULL, **ptr = &head;
int nwords, wordsize; int nwords, wordsize;
struct wrapword { struct wrapword {
word *begin, *end; word *begin, *end;
int width; int width;
int spacewidth; int spacewidth;
int cost; int cost;
int nwords; int nwords;
} *wrapwords; } *wrapwords;
int i, j, n; 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;
/* /*
* Break the line up into wrappable components. * Count along the words to find nspaces and shortfall.
*/ */
nwords = wordsize = 0; w->nspaces = 0;
wrapwords = NULL; w->shortfall = width;
while (text) { for (j = 0; j < n; j++)
if (nwords >= wordsize) { {
wordsize = nwords + 64; w->shortfall -= wrapwords[i + j].width;
wrapwords = srealloc(wrapwords, wordsize * sizeof(*wrapwords)); if (j < n - 1 && wrapwords[i + j].spacewidth)
} {
wrapwords[nwords].width = 0; w->nspaces++;
wrapwords[nwords].begin = text; w->shortfall -= wrapwords[i + j].spacewidth;
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;
} }
i += n;
}
/* sfree(wrapwords);
* 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; return head;
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) void wrap_free(wrappedline * w)
{ {
while (w) { while (w)
wrappedline *t = w->next; {
sfree(w); wrappedline *t = w->next;
w = t; sfree(w);
} w = t;
}
} }

File diff suppressed because it is too large Load diff

View file

@ -126,13 +126,13 @@ void *index234(tree234 * t, int index);
* consume(p); * consume(p);
*/ */
enum { enum {
REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE
}; };
void *find234(tree234 * t, void *e, cmpfn234 cmp); void *find234(tree234 * t, void *e, cmpfn234 cmp);
void *findrel234(tree234 * t, void *e, cmpfn234 cmp, int relation); void *findrel234(tree234 * t, void *e, cmpfn234 cmp, int relation);
void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index); void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index);
void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation, void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp, int relation,
int *index); int *index);
/* /*
* Delete an element e in a 2-3-4 tree. Does not free the element, * Delete an element e in a 2-3-4 tree. Does not free the element,
@ -199,4 +199,4 @@ tree234 *join234r(tree234 * t1, tree234 * t2);
*/ */
tree234 *copytree234(tree234 * t, copyfn234 copyfn, void *copyfnstate); tree234 *copytree234(tree234 * t, copyfn234 copyfn, void *copyfnstate);
#endif /* TREE234_H */ #endif /* TREE234_H */

View file

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