/* Copyright (C) 2009 Kevin W. Hamlen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * The latest version of this program can be obtained from * http://songs.sourceforge.net. */ #ifdef HAVE_CONFIG_H # include "config.h" #else # include "vsconfig.h" #endif #ifdef HAVE_STDLIB_H # include #endif #include "chars.h" #include "songidx.h" #include "fileio.h" /* skipesc() * Walk past any LaTeX macros or braces until we reach the next "real" character. */ void skipesc(p) const WCHAR **p; { for (;;) { if (**p == wc_backslash) { ++(*p); if (wc_isalpha(**p)) while (wc_isalpha(**p)) ++(*p); else if (**p) ++(*p); while (wc_isspace(**p)) ++(*p); } else if (**p == wc_lbrace) { ++(*p); while (wc_isspace(**p)) ++(*p); } else if (**p == wc_rbrace) ++(*p); else break; } } /* songcmp(,) * Return a negative number if is less than , a positive number if * is greater than , and 0 if and are equal. The ordering is first * by title, then by index. This function is suitable for use with qsort(). */ int songcmp(s1,s2) const void *s1; const void *s2; { static WCHAR buf1[MAXLINELEN+1], *bp1; static WCHAR buf2[MAXLINELEN+1], *bp2; const WCHAR *t1 = (*((const SONGENTRY **) s1))->title; const WCHAR *t2 = (*((const SONGENTRY **) s2))->title; int diff; for (;;) { skipesc(&t1); while(*t1 && !wc_isalpha(*t1) && !wc_isdigit(*t1)) { ++t1; skipesc(&t1); } skipesc(&t2); while(*t2 && !wc_isalpha(*t2) && !wc_isdigit(*t2)) { ++t2; skipesc(&t2); } if ((*t1==wc_null) || (*t2==wc_null)) { if ((*t1==wc_null) && (*t2==wc_null)) break; return (t1!=wc_null) ? 1 : -1; } if (wc_isdigit(*t1) || wc_isdigit(*t2)) { long n1, n2; WCHAR *p1, *p2; if (!wc_isdigit(*t1)) return 1; if (!wc_isdigit(*t2)) return -1; n1 = ws_strtol(t1, &p1, 10); t1 = p1; n2 = ws_strtol(t2, &p2, 10); t2 = p2; if (n1 == n2) continue; return n1-n2; } for (bp1=buf1; wc_isalpha(*t1); skipesc(&t1)) *bp1++=wc_tolower(*t1++); for (bp2=buf2; wc_isalpha(*t2); skipesc(&t2)) *bp2++=wc_tolower(*t2++); *bp1 = *bp2 = wc_null; if ((diff = ws_coll(buf1,buf2)) != 0) return diff; } if (((*((const SONGENTRY **) s1))->title[0] == wc_asterisk) && ((*((const SONGENTRY **) s2))->title[0] != wc_asterisk)) return 1; if (((*((const SONGENTRY **) s1))->title[0] != wc_asterisk) && ((*((const SONGENTRY **) s2))->title[0] == wc_asterisk)) return -1; return (*((const SONGENTRY **) s1))->idx - (*((const SONGENTRY **) s2))->idx; }