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