strverscmp.c raw

   1  #define _GNU_SOURCE
   2  #include <ctype.h>
   3  #include <string.h>
   4  
   5  int strverscmp(const char *l0, const char *r0)
   6  {
   7  	const unsigned char *l = (const void *)l0;
   8  	const unsigned char *r = (const void *)r0;
   9  	size_t i, dp, j;
  10  	int z = 1;
  11  
  12  	/* Find maximal matching prefix and track its maximal digit
  13  	 * suffix and whether those digits are all zeros. */
  14  	for (dp=i=0; l[i]==r[i]; i++) {
  15  		int c = l[i];
  16  		if (!c) return 0;
  17  		if (!isdigit(c)) dp=i+1, z=1;
  18  		else if (c!='0') z=0;
  19  	}
  20  
  21  	if (l[dp]!='0' && r[dp]!='0') {
  22  		/* If we're not looking at a digit sequence that began
  23  		 * with a zero, longest digit string is greater. */
  24  		for (j=i; isdigit(l[j]); j++)
  25  			if (!isdigit(r[j])) return 1;
  26  		if (isdigit(r[j])) return -1;
  27  	} else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) {
  28  		/* Otherwise, if common prefix of digit sequence is
  29  		 * all zeros, digits order less than non-digits. */
  30  		return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0');
  31  	}
  32  
  33  	return l[i] - r[i];
  34  }
  35