2 * Copyright 2009, Dana Burkart
3 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
4 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de
5 * Copyright 2010, Rene Gollent (anevilyak@gmail.com)
6 * Distributed under the terms of the MIT License.
10 #include <NaturalCompare.h>
16 #include <StorageDefs.h>
17 #include <SupportDefs.h>
23 // #pragma mark - Natural sorting
26 struct natural_chunk
{
33 char buffer
[B_FILE_NAME_LENGTH
];
39 FetchNaturalChunk(natural_chunk
& chunk
, const char* source
)
41 if (chunk
.type
== natural_chunk::ASCII
) {
44 while (!isdigit(source
[pos
]) && !isspace(source
[pos
])
45 && source
[pos
] != '\0') {
48 strlcpy(chunk
.buffer
, source
, pos
+ 1);
53 // Skip leading zeros and whitespace characters
55 while (source
[0] == '0' || isspace(source
[0])) {
60 // Number chunk (stop at next white space)
62 while (isdigit(source
[pos
])) {
66 strlcpy(chunk
.buffer
, source
, pos
+ 1);
69 // Skip trailing whitespace as well
70 while (isspace(source
[pos
])) {
79 //! Compares two strings naturally, as opposed to lexicographically
81 NaturalCompare(const char* stringA
, const char* stringB
)
84 return stringB
== NULL
? 0 : -1;
95 // Determine type of next chunks in each string based on first char
96 if (stringA
[indexA
] == '\0')
97 a
.type
= natural_chunk::END
;
98 else if (isdigit(stringA
[indexA
]) || isspace(stringA
[indexA
]))
99 a
.type
= natural_chunk::NUMBER
;
101 a
.type
= natural_chunk::ASCII
;
103 if (stringB
[indexB
] == '\0')
104 b
.type
= natural_chunk::END
;
105 else if (isdigit(stringB
[indexB
]) || isspace(stringB
[indexB
]))
106 b
.type
= natural_chunk::NUMBER
;
108 b
.type
= natural_chunk::ASCII
;
110 // Check if we reached the end of either string
111 if (a
.type
== natural_chunk::END
)
112 return b
.type
== natural_chunk::END
? 0 : -1;
113 if (b
.type
== natural_chunk::END
)
116 if (a
.type
!= b
.type
) {
117 // Different chunk types, just compare the remaining strings
118 return strcasecmp(&stringA
[indexA
], &stringB
[indexB
]);
121 // Fetch the next chunks
122 indexA
+= FetchNaturalChunk(a
, &stringA
[indexA
]);
123 indexB
+= FetchNaturalChunk(b
, &stringB
[indexB
]);
125 // Compare the two chunks based on their type
126 if (a
.type
== natural_chunk::ASCII
) {
128 int result
= strcasecmp(a
.buffer
, b
.buffer
);
132 // Number chunks - they are compared as strings to allow an
133 // almost arbitrary number of digits.
134 if (a
.length
> b
.length
)
136 if (a
.length
< b
.length
)
139 int result
= strcmp(a
.buffer
, b
.buffer
);
144 // The chunks were equal, proceed with the next chunk
151 } // namespace BPrivate