NSIS/Docs/src/bin/halibut/misc.c
2021-09-14 22:42:37 +00:00

376 lines
8.1 KiB
C

/*
* misc.c: miscellaneous useful items
*/
#include <string.h>
#include <time.h>
#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;
}
}
unsigned long getutcunixtime()
{
#ifndef _WIN32
struct timespec ts;
ts.tv_sec = 0;
/* gettimeofday()? */
#if (_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 199309L)
if (0 == clock_gettime(CLOCK_REALTIME, &ts))
return ts.tv_sec;
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
if (timespec_get(&ts, TIME_UTC)) /* implementation defined epoch :( */
return ts.tv_sec;
#endif
#endif /*~ _WIN32 */
return (unsigned long) time(NULL);
}