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