1290001Sglebius/* COLLATE COMPARE, COMPARES DIGITS NUMERICALLY AND OTHERS IN ASCII */ 2290001Sglebius 3290001Sglebius/* 4290001Sglebius * Copyright 2001, 2015, Harlan Stenn. Used by NTP with permission. 5290001Sglebius * 6290001Sglebius * Author: Harlan Stenn <harlan@pfcs.com> 7290001Sglebius * 8290001Sglebius * Copying and distribution of this file, with or without modification, 9290001Sglebius * are permitted in any medium without royalty provided the copyright 10290001Sglebius * notice and this notice are preserved. This file is offered as-is, 11290001Sglebius * without any warranty. 12290001Sglebius */ 13290001Sglebius 14290001Sglebius/* 15290001Sglebius * Expected collate order for numeric "pieces" is: 16290001Sglebius * 0 - 9 followed by 17290001Sglebius * 00 - 99 followed by 18290001Sglebius * 000 - 999 followed by 19290001Sglebius * ... 20290001Sglebius */ 21290001Sglebius 22290001Sglebius#include <ctype.h> 23290001Sglebius 24290001Sglebius/* 25290001Sglebius * Older versions of isdigit() require the argument be isascii() 26290001Sglebius */ 27290001Sglebius 28290001Sglebius#if 0 29290001Sglebius# define MyIsDigit(x) \ 30290001Sglebius (isascii ((unsigned char) (x)) && isdigit ((unsigned char) (x))) 31290001Sglebius#else 32290001Sglebius# define MyIsDigit(x) isdigit ((unsigned char) (x)) 33290001Sglebius#endif 34290001Sglebius 35290001Sglebius 36290001Sglebiusint 37290001Sglebiuscolcomp (s1, s2) 38290001Sglebius register char *s1; 39290001Sglebius register char *s2; 40290001Sglebius{ 41290001Sglebius int hilo = 0; /* comparison value */ 42290001Sglebius 43290001Sglebius while (*s1 && *s2) 44290001Sglebius { 45290001Sglebius if ( MyIsDigit(*s1) 46290001Sglebius && MyIsDigit(*s2)) 47290001Sglebius { 48290001Sglebius hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0; 49290001Sglebius ++s1; 50290001Sglebius ++s2; 51290001Sglebius while (MyIsDigit(*s1) 52290001Sglebius && MyIsDigit(*s2)) 53290001Sglebius { 54290001Sglebius if (!hilo) 55290001Sglebius hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0; 56290001Sglebius ++s1; 57290001Sglebius ++s2; 58290001Sglebius } 59290001Sglebius if (MyIsDigit(*s1)) 60290001Sglebius hilo = 1; /* s2 is first */ 61290001Sglebius if (MyIsDigit(*s2)) 62290001Sglebius hilo = -1; /* s1 is first */ 63290001Sglebius if (hilo) 64290001Sglebius break; 65290001Sglebius continue; 66290001Sglebius } 67290001Sglebius if (MyIsDigit(*s1)) 68290001Sglebius { 69290001Sglebius hilo = -1; /* s1 must come first */ 70290001Sglebius break; 71290001Sglebius } 72290001Sglebius if (MyIsDigit(*s2)) 73290001Sglebius { 74290001Sglebius hilo = 1; /* s2 must come first */ 75290001Sglebius break; 76290001Sglebius } 77290001Sglebius hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0; 78290001Sglebius if (hilo) 79290001Sglebius break; 80290001Sglebius ++s1; 81290001Sglebius ++s2; 82290001Sglebius } 83290001Sglebius if (*s1 && *s2) 84290001Sglebius return (hilo); 85290001Sglebius if (hilo) 86290001Sglebius return (hilo); 87290001Sglebius return ((*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0); 88290001Sglebius} 89290001Sglebius 90290001Sglebius#ifdef TEST 91290001Sglebius 92290001Sglebius#include <stdlib.h> 93290001Sglebius 94290001Sglebiusstatic int qcmp( const void *fi1, 95290001Sglebius const void *fi2) 96290001Sglebius{ 97290001Sglebius return colcomp(*(char**)fi1, *(char**)fi2); 98290001Sglebius} 99290001Sglebius 100290001Sglebiusint main( int argc, char *argv[], char *environ[]) { 101290001Sglebius void *base; 102290001Sglebius size_t nmemb = 0; 103290001Sglebius size_t size = sizeof(char *); 104290001Sglebius char *ca[] = { 105290001Sglebius "999", "0", "10", "1", "01", "100", "010", "99", "00", "001", "099", "9" 106290001Sglebius }; 107290001Sglebius char **cp; 108290001Sglebius int i; 109290001Sglebius 110290001Sglebius if (argc > 1) { 111290001Sglebius /* Sort use-provided list */ 112290001Sglebius } else { 113290001Sglebius base = (void *) ca; 114290001Sglebius nmemb = sizeof ca / size; 115290001Sglebius } 116290001Sglebius printf("argc is <%d>, nmemb = <%d>\n", argc, nmemb); 117290001Sglebius 118290001Sglebius printf("Before:\n"); 119290001Sglebius cp = (char **)base; 120290001Sglebius for (i = 0; i < nmemb; ++i) { 121290001Sglebius printf("%s\n", *cp++); 122290001Sglebius } 123290001Sglebius 124290001Sglebius qsort((void *)base, nmemb, size, qcmp); 125290001Sglebius 126290001Sglebius printf("After:\n"); 127290001Sglebius cp = (char **)base; 128290001Sglebius for (i = 0; i < nmemb; ++i) { 129290001Sglebius printf("%s\n", *cp++); 130290001Sglebius } 131290001Sglebius 132290001Sglebius exit(0); 133290001Sglebius} 134290001Sglebius 135290001Sglebius#endif 136