X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/halibut/blobdiff_plain/d7482997dd1ca71b70df43c15dd5956f435a1a7e..5dd44dceca3dd3c1a4886dd6a7bdf05924e3447f:/misc.c diff --git a/misc.c b/misc.c index c4ac72f..6d5497b 100644 --- a/misc.c +++ b/misc.c @@ -41,6 +41,13 @@ void *stk_pop(stack s) { return NULL; } +void *stk_top(stack s) { + if (s->sp > 0) + return s->data[s->sp-1]; + else + return NULL; +} + /* * Small routines to amalgamate a string from an input source. */ @@ -55,7 +62,7 @@ void rdadd(rdstring *rs, wchar_t c) { rs->text[rs->pos++] = c; rs->text[rs->pos] = 0; } -void rdadds(rdstring *rs, wchar_t *p) { +void rdadds(rdstring *rs, wchar_t const *p) { int len = ustrlen(p); if (rs->pos >= rs->size - len) { rs->size = rs->pos + len + 128; @@ -77,7 +84,7 @@ void rdaddc(rdstringc *rs, char c) { rs->text[rs->pos++] = c; rs->text[rs->pos] = 0; } -void rdaddsc(rdstringc *rs, char *p) { +void rdaddsc(rdstringc *rs, char const *p) { int len = strlen(p); if (rs->pos >= rs->size - len) { rs->size = rs->pos + len + 128; @@ -91,7 +98,7 @@ char *rdtrimc(rdstringc *rs) { return rs->text; } -int compare_wordlists(word *a, word *b) { +static int compare_wordlists_literally(word *a, word *b) { int t; while (a && b) { if (a->type != b->type) @@ -106,7 +113,7 @@ int compare_wordlists(word *a, word *b) { if (c) return c; } - c = compare_wordlists(a->alt, b->alt); + c = compare_wordlists_literally(a->alt, b->alt); if (c) return c; a = a->next; @@ -135,6 +142,72 @@ int compare_wordlists(word *a, word *b) { return 0; } +int compare_wordlists(word *a, word *b) { + /* + * First we compare only the alphabetic content of the word + * lists, with case not a factor. If that comes out equal, + * _then_ we compare the word lists literally. + */ + struct { + word *w; + int i; + wchar_t c; + } pos[2]; + + pos[0].w = a; + pos[1].w = b; + pos[0].i = pos[1].i = 0; + + while (1) { + /* + * Find the next alphabetic character in each word list. + */ + int k; + + for (k = 0; k < 2; k++) { + /* + * Advance until we hit either an alphabetic character + * or the end of the word list. + */ + while (1) { + if (!pos[k].w) { + /* End of word list. */ + pos[k].c = 0; + break; + } else if (!pos[k].w->text || !pos[k].w->text[pos[k].i]) { + /* No characters remaining in this word; move on. */ + pos[k].w = pos[k].w->next; + pos[k].i = 0; + } else if (!uisalpha(pos[k].w->text[pos[k].i])) { + /* This character isn't alphabetic; move on. */ + pos[k].i++; + } else { + /* We have an alphabetic! Lowercase it and continue. */ + pos[k].c = utolower(pos[k].w->text[pos[k].i]); + break; + } + } + } + + if (pos[0].c < pos[1].c) + return -1; + else if (pos[0].c > pos[1].c) + return +1; + + if (!pos[0].c) + break; /* they're equal */ + + pos[0].i++; + pos[1].i++; + } + + /* + * If we reach here, the strings were alphabetically equal, so + * compare in more detail. + */ + return compare_wordlists_literally(a, b); +} + void mark_attr_ends(paragraph *sourceform) { paragraph *p; word *w, *wp;