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