forked from simonsj/fdupes-jody
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jody_sort.c
91 lines (77 loc) · 2.53 KB
/
jody_sort.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* Jody Bruchon's sorting code library
*
* Copyright (C) 2014-2017 by Jody Bruchon <jody@jodybruchon.com>
* Released under The MIT License
*/
#include <stdlib.h>
#include "jody_sort.h"
#define IS_NUM(a) (((a >= '0') && (a <= '9')) ? 1 : 0)
extern int numeric_sort(const char * restrict c1,
const char * restrict c2, int sort_direction)
{
int len1 = 0, len2 = 0;
int precompare = 0;
if (c1 == NULL || c2 == NULL) return -99;
/* Numerically correct sort */
while (*c1 != '\0' && *c2 != '\0') {
/* Reset string length counters */
len1 = 0; len2 = 0;
/* Skip all sequences of zeroes */
while (*c1 == '0') {
len1++;
c1++;
}
while (*c2 == '0') {
len2++;
c2++;
}
/* If both chars are numeric, do a numeric comparison */
if (IS_NUM(*c1) && IS_NUM(*c2)) {
precompare = 0;
/* Scan numbers and get preliminary results */
while (IS_NUM(*c1) && IS_NUM(*c2)) {
if (*c1 < *c2) precompare = -sort_direction;
if (*c1 > *c2) precompare = sort_direction;
len1++; len2++;
c1++; c2++;
/* Skip remaining digit pairs after any
* difference is found */
if (precompare != 0) {
while (IS_NUM(*c1) && IS_NUM(*c2)) {
len1++; len2++;
c1++; c2++;
}
break;
}
}
/* One numeric and one non-numeric means the
* numeric one is larger and sorts later */
if (IS_NUM(*c1) ^ IS_NUM(*c2)) {
if (IS_NUM(*c1)) return sort_direction;
else return -sort_direction;
}
/* If the last test fell through, numbers are
* of equal length. Use the precompare result
* as the result for this number comparison. */
if (precompare != 0) return precompare;
}
/* Do normal comparison */
if (*c1 == *c2 && *c1 != '\0' && *c2 != '\0') {
c1++; c2++;
len1++; len2++;
/* Put symbols and spaces after everything else */
} else if (*c2 < '.' && *c1 >= '.') return -sort_direction;
else if (*c1 < '.' && *c2 >= '.') return sort_direction;
/* Normal strcmp() style compare */
else if (*c1 > *c2) return sort_direction;
else return -sort_direction;
}
/* Longer strings generally sort later */
if (len1 < len2) return -sort_direction;
if (len1 > len2) return sort_direction;
/* Normal strcmp() style comparison */
if (*c1 == '\0' && *c2 != '\0') return -sort_direction;
if (*c1 != '\0' && *c2 == '\0') return sort_direction;
/* Fall through: the strings are equal */
return 0;
}