patch: sorting by version
Federico Di Gregorio <[email protected]>
| Newsgroups | gmane.comp.gnu.textutils.bugs |
|---|---|
| Message-ID | <1017843784.5585.162.camel@nenya> |
sorry if this is not the right mail address, but i didn't find any other apart from sort author private mail. lately i found myself in need of sorting a file on version numbers, like 1.0.1 or 1.12-27. i patched sort to use the same algorithm used by debian's dpkg and it worked for me. yes, i know that version number sorting is quite arbitrary but an half working algorithm is better than nothing. patch is attached. thank you very much for your time, federico -- Federico Di Gregorio Debian GNU/Linux Developer & Italian Press Contact [email protected] INIT.D Developer [email protected] Don't dream it. Be it. -- Dr. Frank'n'further
sort.c.diff
(text/plain, 2.9 KB)
80a81
> #define MAXVERSIONLENGTH 32
152a154
> int version; /* use dpkg-live version sorting */
177a180,183
> /* Translation table from ASCII values to collate values for the dpkg-like
> version sorting. */
> static int versiontab[256];
>
276a283
> -v compare according to dpkg-live version ordering\n\
499a507,514
> for (i=0; i<256; i++) versiontab[i] = 0;
> for (i='a'; i<='z'; i++) versiontab[i] = i;
> for (i='A'; i<='Z'; i++) versiontab[i] = i;
> versiontab['+'] = 256 + '+';
> versiontab['-'] = 256 + '-';
> versiontab['.'] = 256 + '.';
> versiontab[':'] = 256 + ':';
>
1083a1099,1162
> /* Compare strings A and B as dpkg-like versions */
>
> static char *
> _versioncompare_part (char *s, char *save, int max, int alpha)
> {
> int i;
>
> /* if *s is NUL, return NULL to signal end-of-string */
> if (!s || *s == '\0' || ISSPACE(*s)) return NULL;
>
> for (i=0; i<max ; i++) {
> if (*s && ((alpha && versiontab[(unsigned int)*s] > 0)
> || (!alpha && ISDIGIT(*s)))) {
> s++;
> }
> else {
> break;
> }
> }
> *save = *s;
> *s = '\0';
> return s;
> }
>
> static int
> versioncompare (register char *a, register char *b)
> {
> int res = 0, alpha = 0;
> char sa, sb, *pa, *pb;
>
> while (*a || *b) {
> pa = a; pb = b;
> a = _versioncompare_part(a, &sa, MAXVERSIONLENGTH, alpha);
> b = _versioncompare_part(b, &sb, MAXVERSIONLENGTH, alpha);
> if (a && b) {
> if (alpha) {
> while (*pa && *pb
> && versiontab[(unsigned int)*pa] > 0
> && versiontab[(unsigned int)*pb] > 0) {
> if (*pa != *pb) break;
> pa++; pb++;
> }
> res = versiontab[(unsigned int)*pb] - versiontab[(unsigned int)*pa];
> }
> else {
> res = atoi(pb) - atoi(pa);
> }
>
> }
> else if (a) res = -1;
> else if (b) res = 1;
> else res = 1000; /* very dirty trick */
>
> if (a) *a = sa;
> if (b) *b = sb;
>
> if (res != 0) return (res == 1000 ? 0 : -res);
>
> alpha = (alpha-1)*-1;
> }
>
> return -res;
> }
>
1151c1230
< if (key->numeric | key->general_numeric)
---
> if (key->numeric | key->general_numeric | key->version)
1167,1168c1246,1250
< diff = ((key->numeric ? numcompare : general_numcompare)
< (texta, textb));
---
> if (key->version)
> diff = versioncompare (texta, textb);
> else
> diff = ((key->numeric ? numcompare : general_numcompare)
> (texta, textb));
1874a1957,1959
> case 'v':
> key->version = 1;
> break;
1983a2069
> gkey.version = 0;
2242c2328
< && !key->skipeblanks && !key->month && !key->numeric
---
> && !key->skipeblanks && !key->month && !key->numeric && !key->version
2250a2337
> key->version = gkey.version;
2257c2344
< || gkey.general_numeric))
---
> || gkey.version || gkey.general_numeric))
signature.asc
(application/pgp-signature, 252 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: Per informazioni si veda http://www.gnupg.org iEYEABECAAYFAjyrEEcACgkQvcCgrgZGjetxtwCg0YRy0s8Vhrwr2IXDYeAs0BI7 gB0AoKCCrqnr4y5rmJvwCP19/1QHc4Sl =Odkr -----END PGP SIGNATURE-----