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-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.