colcomp.c revision 1.1 1 1.1 christos /* COLLATE COMPARE, COMPARES DIGITS NUMERICALLY AND OTHERS IN ASCII */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright 2001, 2015, Harlan Stenn. Used by NTP with permission.
5 1.1 christos *
6 1.1 christos * Author: Harlan Stenn <harlan (at) pfcs.com>
7 1.1 christos *
8 1.1 christos * Copying and distribution of this file, with or without modification,
9 1.1 christos * are permitted in any medium without royalty provided the copyright
10 1.1 christos * notice and this notice are preserved. This file is offered as-is,
11 1.1 christos * without any warranty.
12 1.1 christos */
13 1.1 christos
14 1.1 christos /*
15 1.1 christos * Expected collate order for numeric "pieces" is:
16 1.1 christos * 0 - 9 followed by
17 1.1 christos * 00 - 99 followed by
18 1.1 christos * 000 - 999 followed by
19 1.1 christos * ...
20 1.1 christos */
21 1.1 christos
22 1.1 christos #include <ctype.h>
23 1.1 christos
24 1.1 christos /*
25 1.1 christos * Older versions of isdigit() require the argument be isascii()
26 1.1 christos */
27 1.1 christos
28 1.1 christos #if 0
29 1.1 christos # define MyIsDigit(x) \
30 1.1 christos (isascii ((unsigned char) (x)) && isdigit ((unsigned char) (x)))
31 1.1 christos #else
32 1.1 christos # define MyIsDigit(x) isdigit ((unsigned char) (x))
33 1.1 christos #endif
34 1.1 christos
35 1.1 christos
36 1.1 christos int
37 1.1 christos colcomp (s1, s2)
38 1.1 christos register char *s1;
39 1.1 christos register char *s2;
40 1.1 christos {
41 1.1 christos int hilo = 0; /* comparison value */
42 1.1 christos
43 1.1 christos while (*s1 && *s2)
44 1.1 christos {
45 1.1 christos if ( MyIsDigit(*s1)
46 1.1 christos && MyIsDigit(*s2))
47 1.1 christos {
48 1.1 christos hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0;
49 1.1 christos ++s1;
50 1.1 christos ++s2;
51 1.1 christos while (MyIsDigit(*s1)
52 1.1 christos && MyIsDigit(*s2))
53 1.1 christos {
54 1.1 christos if (!hilo)
55 1.1 christos hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0;
56 1.1 christos ++s1;
57 1.1 christos ++s2;
58 1.1 christos }
59 1.1 christos if (MyIsDigit(*s1))
60 1.1 christos hilo = 1; /* s2 is first */
61 1.1 christos if (MyIsDigit(*s2))
62 1.1 christos hilo = -1; /* s1 is first */
63 1.1 christos if (hilo)
64 1.1 christos break;
65 1.1 christos continue;
66 1.1 christos }
67 1.1 christos if (MyIsDigit(*s1))
68 1.1 christos {
69 1.1 christos hilo = -1; /* s1 must come first */
70 1.1 christos break;
71 1.1 christos }
72 1.1 christos if (MyIsDigit(*s2))
73 1.1 christos {
74 1.1 christos hilo = 1; /* s2 must come first */
75 1.1 christos break;
76 1.1 christos }
77 1.1 christos hilo = (*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0;
78 1.1 christos if (hilo)
79 1.1 christos break;
80 1.1 christos ++s1;
81 1.1 christos ++s2;
82 1.1 christos }
83 1.1 christos if (*s1 && *s2)
84 1.1 christos return (hilo);
85 1.1 christos if (hilo)
86 1.1 christos return (hilo);
87 1.1 christos return ((*s1 < *s2) ? -1 : (*s1 > *s2) ? 1 : 0);
88 1.1 christos }
89 1.1 christos
90 1.1 christos #ifdef TEST
91 1.1 christos
92 1.1 christos #include <stdlib.h>
93 1.1 christos
94 1.1 christos static int qcmp( const void *fi1,
95 1.1 christos const void *fi2)
96 1.1 christos {
97 1.1 christos return colcomp(*(char**)fi1, *(char**)fi2);
98 1.1 christos }
99 1.1 christos
100 1.1 christos int main( int argc, char *argv[], char *environ[]) {
101 1.1 christos void *base;
102 1.1 christos size_t nmemb = 0;
103 1.1 christos size_t size = sizeof(char *);
104 1.1 christos char *ca[] = {
105 1.1 christos "999", "0", "10", "1", "01", "100", "010", "99", "00", "001", "099", "9"
106 1.1 christos };
107 1.1 christos char **cp;
108 1.1 christos int i;
109 1.1 christos
110 1.1 christos if (argc > 1) {
111 1.1 christos /* Sort use-provided list */
112 1.1 christos } else {
113 1.1 christos base = (void *) ca;
114 1.1 christos nmemb = sizeof ca / size;
115 1.1 christos }
116 1.1 christos printf("argc is <%d>, nmemb = <%d>\n", argc, nmemb);
117 1.1 christos
118 1.1 christos printf("Before:\n");
119 1.1 christos cp = (char **)base;
120 1.1 christos for (i = 0; i < nmemb; ++i) {
121 1.1 christos printf("%s\n", *cp++);
122 1.1 christos }
123 1.1 christos
124 1.1 christos qsort((void *)base, nmemb, size, qcmp);
125 1.1 christos
126 1.1 christos printf("After:\n");
127 1.1 christos cp = (char **)base;
128 1.1 christos for (i = 0; i < nmemb; ++i) {
129 1.1 christos printf("%s\n", *cp++);
130 1.1 christos }
131 1.1 christos
132 1.1 christos exit(0);
133 1.1 christos }
134 1.1 christos
135 1.1 christos #endif
136