#include "zsh.mdh"
#include "sort.pro"
static int sortdir;
static int sortnumeric;
static int
eltpcmp(const void *a, const void *b)
{
const SortElt ae = *(const SortElt *)a;
const SortElt be = *(const SortElt *)b;
const char *as = ae->cmp, *bs = be->cmp;
const char *ao = as;
int cmp;
if (ae->len != -1 || be->len != -1) {
const char *cmpa, *cmpb;
const char *laststarta = as;
int len;
if (ae->len != -1) {
len = ae->len;
if (be->len != -1 && len > be->len)
len = be->len;
}
else
len = be->len;
for (cmpa = as, cmpb = bs; *cmpa == *cmpb && len--; cmpa++, cmpb++) {
if (!*cmpa) {
if (ae->len == -1 || be->len == -1)
break;
laststarta = cmpa + 1;
}
}
if (*cmpa == *cmpb && ae->len != be->len) {
if (ae->len != -1) {
if (be->len != -1) {
return (ae->len - be->len) * sortdir;
} else {
return sortdir;
}
} else {
return - sortdir;
}
}
bs += (laststarta - as);
as += (laststarta - as);
}
#ifdef HAVE_STRCOLL
cmp = strcoll(as, bs);
#endif
if (sortnumeric) {
for (; *as == *bs && *as; as++, bs++);
#ifndef HAVE_STRCOLL
cmp = (int)STOUC(*as) - (int)STOUC(*bs);
#endif
if (idigit(*as) || idigit(*bs)) {
for (; as > ao && idigit(as[-1]); as--, bs--);
if (idigit(*as) && idigit(*bs)) {
while (*as == '0')
as++;
while (*bs == '0')
bs++;
for (; idigit(*as) && *as == *bs; as++, bs++);
if (idigit(*as) || idigit(*bs)) {
cmp = (int)STOUC(*as) - (int)STOUC(*bs);
while (idigit(*as) && idigit(*bs))
as++, bs++;
if (idigit(*as) && !idigit(*bs))
return sortdir;
if (idigit(*bs) && !idigit(*as))
return -sortdir;
}
}
}
}
#ifndef HAVE_STRCOLL
else
cmp = strcmp(as, bs);
#endif
return sortdir * cmp;
}
mod_export int
zstrcmp(const char *as, const char *bs, int sortflags)
{
struct sortelt ae, be, *aeptr, *beptr;
int oldsortdir = sortdir, oldsortnumeric = sortnumeric, ret;
ae.cmp = as;
be.cmp = bs;
ae.len = -1;
be.len = -1;
aeptr = &ae;
beptr = &be;
sortdir = 1;
sortnumeric = (sortflags & SORTIT_NUMERICALLY) ? 1 : 0;
ret = eltpcmp(&aeptr, &beptr);
sortnumeric = oldsortnumeric;
sortdir = oldsortdir;
return ret;
}
mod_export void
strmetasort(char **array, int sortwhat, int *unmetalenp)
{
char **arrptr;
SortElt *sortptrarr, *sortptrarrptr;
SortElt sortarr, sortarrptr;
int oldsortdir, oldsortnumeric, nsort;
nsort = arrlen(array);
if (nsort < 2)
return;
pushheap();
sortptrarr = (SortElt *) zhalloc(nsort * sizeof(SortElt));
sortarr = (SortElt) zhalloc(nsort * sizeof(struct sortelt));
for (arrptr = array, sortptrarrptr = sortptrarr, sortarrptr = sortarr;
*arrptr; arrptr++, sortptrarrptr++, sortarrptr++) {
char *metaptr;
int needlen, needalloc;
*sortptrarrptr = sortarrptr;
sortarrptr->orig = *arrptr;
if (unmetalenp) {
int count = unmetalenp[arrptr-array];
sortarrptr->origlen = count;
for (metaptr = *arrptr; *metaptr != '\0' && count--; metaptr++)
;
needlen = (count != 0);
} else {
needlen = 0;
for (metaptr = *arrptr; *metaptr && *metaptr != Meta;
metaptr++);
}
if ((needalloc = (sortwhat &
(SORTIT_IGNORING_CASE|SORTIT_IGNORING_BACKSLASHES)))
|| *metaptr == Meta) {
char *s, *t, *src = *arrptr, *dst;
int len;
sortarrptr->cmp = dst =
(char *)zhalloc(((sortwhat & SORTIT_IGNORING_CASE)?2:1)*strlen(src)+1);
if (unmetalenp) {
len = unmetalenp[arrptr-array];
} else if (*metaptr != '\0') {
char *t = dst + (metaptr - src);
if (metaptr != src)
memcpy(dst, src, metaptr - src);
while ((*t = *metaptr++)) {
if (*t++ == Meta) {
if ((t[-1] = *metaptr++ ^ 32) == '\0')
needlen = 1;
}
}
len = t - dst;
src = dst;
} else {
len = metaptr - src;
}
if (sortwhat & SORTIT_IGNORING_CASE) {
char *send = src + len;
#ifdef MULTIBYTE_SUPPORT
if (isset(MULTIBYTE)) {
mbstate_t mbsin, mbsout;
int clen;
wchar_t wc;
memset(&mbsin, 0, sizeof(mbstate_t));
memset(&mbsout, 0, sizeof(mbstate_t));
for (s = src, t = dst; s < send; ) {
clen = mbrtowc(&wc, s, send-s, &mbsin);
if (clen < 0) {
while (s < send)
*t++ = tulower(*s++);
break;
}
if (clen == 0) {
*t++ = '\0';
s++;
continue;
}
s += clen;
wc = towlower(wc);
clen = wcrtomb(t, wc, &mbsout);
t += clen;
DPUTS(clen < 0, "Bad conversion when lowering case");
}
*t = '\0';
len = t - dst;
} else
#endif
for (s = src, t = dst; s < send; )
*t++ = tulower(*s++);
src = dst;
}
if (sortwhat & SORTIT_IGNORING_BACKSLASHES) {
char *end = src + len + 1;
for (s = src, t = dst; s < end; ) {
if (*s == '\\') {
s++;
len--;
}
*t++ = *s++;
}
}
sortarrptr->len = needlen ? len : -1;
} else {
sortarrptr->cmp = *arrptr;
sortarrptr->len = needlen ? unmetalenp[arrptr-array] : -1;
}
}
oldsortdir = sortdir;
oldsortnumeric = sortnumeric;
sortdir = (sortwhat & SORTIT_BACKWARDS) ? -1 : 1;
sortnumeric = (sortwhat & SORTIT_NUMERICALLY) ? 1 : 0;
qsort(sortptrarr, nsort, sizeof(SortElt *), eltpcmp);
sortnumeric = oldsortnumeric;
sortdir = oldsortdir;
for (arrptr = array, sortptrarrptr = sortptrarr; nsort--; ) {
if (unmetalenp)
unmetalenp[arrptr-array] = (*sortptrarrptr)->origlen;
*arrptr++ = (*sortptrarrptr++)->orig;
}
popheap();
}