mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-23 03:39:39 +00:00
Added natural sorting for filenames.
This commit is contained in:
parent
6c2c40caab
commit
4a31ac8100
@ -100,6 +100,7 @@ add_executable(VitaShell
|
|||||||
minizip/zip.c
|
minizip/zip.c
|
||||||
minizip/ioapi.c
|
minizip/ioapi.c
|
||||||
bm.c
|
bm.c
|
||||||
|
strnatcmp.c
|
||||||
audio/vita_audio.c
|
audio/vita_audio.c
|
||||||
audio/player.c
|
audio/player.c
|
||||||
audio/id3.c
|
audio/id3.c
|
||||||
|
@ -102,6 +102,8 @@ The english language file is provided in **'VitaShellCustomization.rar'** and av
|
|||||||
### Changelog 1.79 ###
|
### Changelog 1.79 ###
|
||||||
- Added support for multi volume rar archives.
|
- Added support for multi volume rar archives.
|
||||||
- Added support for password encrypted zip archives.
|
- Added support for password encrypted zip archives.
|
||||||
|
- Added support for file property in archives, now it can show size and contains.
|
||||||
|
- Added natural sorting for filenames.
|
||||||
- Fixed bug where size of files in archives over 2GB where shown as 16EB.
|
- Fixed bug where size of files in archives over 2GB where shown as 16EB.
|
||||||
|
|
||||||
### Changelog 1.78 ###
|
### Changelog 1.78 ###
|
||||||
|
22
archive.c
22
archive.c
@ -555,7 +555,7 @@ int fileListGetArchiveEntries(FileList *list, const char *path, int sort) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files) {
|
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path)) {
|
||||||
SceIoStat stat;
|
SceIoStat stat;
|
||||||
memset(&stat, 0, sizeof(SceIoStat));
|
memset(&stat, 0, sizeof(SceIoStat));
|
||||||
|
|
||||||
@ -571,15 +571,18 @@ int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint
|
|||||||
FileListEntry *entry = list.head->next; // Ignore ..
|
FileListEntry *entry = list.head->next; // Ignore ..
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < list.length - 1; i++) {
|
for (i = 0; i < list.length - 1; i++, entry = entry->next) {
|
||||||
char *new_path = malloc(strlen(path) + strlen(entry->name) + 2);
|
char *new_path = malloc(strlen(path) + strlen(entry->name) + 2);
|
||||||
snprintf(new_path, MAX_PATH_LENGTH - 1, "%s%s", path, entry->name);
|
snprintf(new_path, MAX_PATH_LENGTH - 1, "%s%s", path, entry->name);
|
||||||
|
|
||||||
getArchivePathInfo(new_path, size, folders, files);
|
if (handler && handler(new_path)) {
|
||||||
|
free(new_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
getArchivePathInfo(new_path, size, folders, files, handler);
|
||||||
|
|
||||||
free(new_path);
|
free(new_path);
|
||||||
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folders)
|
if (folders)
|
||||||
@ -587,6 +590,9 @@ int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint
|
|||||||
|
|
||||||
fileListEmpty(&list);
|
fileListEmpty(&list);
|
||||||
} else {
|
} else {
|
||||||
|
if (handler && handler(path))
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
(*size) += stat.st_size;
|
(*size) += stat.st_size;
|
||||||
|
|
||||||
@ -632,7 +638,7 @@ int extractArchivePath(const char *src, const char *dst, FileProcessParam *param
|
|||||||
FileListEntry *entry = list.head->next; // Ignore ..
|
FileListEntry *entry = list.head->next; // Ignore ..
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < list.length - 1; i++) {
|
for (i = 0; i < list.length - 1; i++, entry = entry->next) {
|
||||||
char *src_path = malloc(strlen(src) + strlen(entry->name) + 2);
|
char *src_path = malloc(strlen(src) + strlen(entry->name) + 2);
|
||||||
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", src, entry->name);
|
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", src, entry->name);
|
||||||
|
|
||||||
@ -648,8 +654,6 @@ int extractArchivePath(const char *src, const char *dst, FileProcessParam *param
|
|||||||
fileListEmpty(&list);
|
fileListEmpty(&list);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileListEmpty(&list);
|
fileListEmpty(&list);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
int fileListGetArchiveEntries(FileList *list, const char *path, int sort);
|
int fileListGetArchiveEntries(FileList *list, const char *path, int sort);
|
||||||
|
|
||||||
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files);
|
int getArchivePathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path));
|
||||||
int extractArchivePath(const char *src, const char *dst, FileProcessParam *param);
|
int extractArchivePath(const char *src, const char *dst, FileProcessParam *param);
|
||||||
|
|
||||||
int archiveFileGetstat(const char *file, SceIoStat *stat);
|
int archiveFileGetstat(const char *file, SceIoStat *stat);
|
||||||
|
30
file.c
30
file.c
@ -22,6 +22,7 @@
|
|||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
static char *devices[] = {
|
static char *devices[] = {
|
||||||
"gro0:",
|
"gro0:",
|
||||||
@ -747,17 +748,20 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
|||||||
FileListEntry *p = list->head;
|
FileListEntry *p = list->head;
|
||||||
FileListEntry *previous = NULL;
|
FileListEntry *previous = NULL;
|
||||||
|
|
||||||
|
char entry_name[MAX_NAME_LENGTH];
|
||||||
|
strcpy(entry_name, entry->name);
|
||||||
|
removeEndSlash(entry_name);
|
||||||
|
|
||||||
while (p) {
|
while (p) {
|
||||||
// Get the minimum length without /
|
char p_name[MAX_NAME_LENGTH];
|
||||||
int len = MIN(entry->name_length, p->name_length);
|
strcpy(p_name, p->name);
|
||||||
if (entry->name[len - 1] == '/' || p->name[len - 1] == '/')
|
removeEndSlash(p_name);
|
||||||
len--;
|
|
||||||
|
|
||||||
// '..' is always at first
|
// '..' is always at first
|
||||||
if (strcmp(entry->name, "..") == 0)
|
if (strcmp(entry_name, "..") == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (strcmp(p->name, "..") == 0) {
|
if (strcmp(p_name, "..") == 0) {
|
||||||
previous = p;
|
previous = p;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
continue;
|
continue;
|
||||||
@ -777,16 +781,14 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
|||||||
if (sort == SORT_BY_NAME) {
|
if (sort == SORT_BY_NAME) {
|
||||||
// Sort by name within the same type
|
// Sort by name within the same type
|
||||||
if (entry->is_folder == p->is_folder) {
|
if (entry->is_folder == p->is_folder) {
|
||||||
int diff = strncasecmp(entry->name, p->name, len);
|
if (strnatcasecmp(entry_name, p_name) < 0) {
|
||||||
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sort == SORT_BY_SIZE) {
|
} else if (sort == SORT_BY_SIZE) {
|
||||||
// Sort by name for folders
|
// Sort by name for folders
|
||||||
if (entry->is_folder && p->is_folder) {
|
if (entry->is_folder && p->is_folder) {
|
||||||
int diff = strncasecmp(entry->name, p->name, len);
|
if (strnatcasecmp(entry_name, p_name) < 0) {
|
||||||
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (!entry->is_folder && !p->is_folder) {
|
} else if (!entry->is_folder && !p->is_folder) {
|
||||||
@ -796,8 +798,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
|||||||
|
|
||||||
// Sort by name for files with the same size
|
// Sort by name for files with the same size
|
||||||
if (entry->size == p->size) {
|
if (entry->size == p->size) {
|
||||||
int diff = strncasecmp(entry->name, p->name, len);
|
if (strnatcasecmp(entry_name, p_name) < 0) {
|
||||||
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,8 +815,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
|||||||
|
|
||||||
// Sort by name for files and folders with the same date
|
// Sort by name for files and folders with the same date
|
||||||
if (entry_tick.tick == p_tick.tick) {
|
if (entry_tick.tick == p_tick.tick) {
|
||||||
int diff = strncasecmp(entry->name, p->name, len);
|
if (strnatcasecmp(entry_name, p_name) < 0) {
|
||||||
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ int copy_thread(SceSize args_size, CopyArguments *args) {
|
|||||||
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", args->copy_list->path, copy_entry->name);
|
snprintf(src_path, MAX_PATH_LENGTH - 1, "%s%s", args->copy_list->path, copy_entry->name);
|
||||||
|
|
||||||
if (args->copy_mode == COPY_MODE_EXTRACT) {
|
if (args->copy_mode == COPY_MODE_EXTRACT) {
|
||||||
getArchivePathInfo(src_path, &size, &folders, &files);
|
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
|
||||||
} else {
|
} else {
|
||||||
getPathInfo(src_path, &size, &folders, &files, NULL);
|
getPathInfo(src_path, &size, &folders, &files, NULL);
|
||||||
}
|
}
|
||||||
|
@ -139,10 +139,10 @@ int update_extract_thread(SceSize args, void *argp) {
|
|||||||
// Get archive path info
|
// Get archive path info
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
uint32_t folders = 0, files = 0;
|
uint32_t folders = 0, files = 0;
|
||||||
getArchivePathInfo(src_path, &size, &folders, &files);
|
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
|
||||||
|
|
||||||
// Update thread
|
// Update thread
|
||||||
thid = createStartUpdateThread(size + folders*DIRECTORY_SIZE, 1);
|
thid = createStartUpdateThread(size + folders * DIRECTORY_SIZE, 1);
|
||||||
|
|
||||||
// Extract process
|
// Extract process
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
|
@ -429,7 +429,7 @@ int install_thread(SceSize args_size, InstallArguments *args) {
|
|||||||
// Get archive path info
|
// Get archive path info
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
uint32_t folders = 0, files = 0;
|
uint32_t folders = 0, files = 0;
|
||||||
getArchivePathInfo(src_path, &size, &folders, &files);
|
getArchivePathInfo(src_path, &size, &folders, &files, NULL);
|
||||||
|
|
||||||
// Check memory card free space
|
// Check memory card free space
|
||||||
if (checkMemoryCardFreeSpace(PACKAGE_DIR, size))
|
if (checkMemoryCardFreeSpace(PACKAGE_DIR, size))
|
||||||
|
@ -110,7 +110,11 @@ static int info_thread(SceSize args_size, InfoArguments *args) {
|
|||||||
uint32_t folders = 0, files = 0;
|
uint32_t folders = 0, files = 0;
|
||||||
|
|
||||||
info_done = 0;
|
info_done = 0;
|
||||||
getPathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
|
if (isInArchive()) {
|
||||||
|
getArchivePathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
|
||||||
|
} else {
|
||||||
|
getPathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
|
||||||
|
}
|
||||||
info_done = 1;
|
info_done = 1;
|
||||||
|
|
||||||
if (folders > 0)
|
if (folders > 0)
|
||||||
@ -265,23 +269,18 @@ int initPropertyDialog(char *path, FileListEntry *entry) {
|
|||||||
|
|
||||||
// Size & contains
|
// Size & contains
|
||||||
if (entry->is_folder) {
|
if (entry->is_folder) {
|
||||||
if (isInArchive()) {
|
strcpy(property_size, "...");
|
||||||
property_entries[PROPERTY_ENTRY_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
strcpy(property_contains, "...");
|
||||||
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
||||||
} else {
|
|
||||||
strcpy(property_size, "...");
|
|
||||||
strcpy(property_contains, "...");
|
|
||||||
|
|
||||||
// Info thread
|
// Info thread
|
||||||
InfoArguments info_args;
|
InfoArguments info_args;
|
||||||
info_args.path = path;
|
info_args.path = path;
|
||||||
|
|
||||||
info_thid = sceKernelCreateThread("info_thread", (SceKernelThreadEntry)info_thread, 0x10000100, 0x100000, 0, 0, NULL);
|
info_thid = sceKernelCreateThread("info_thread", (SceKernelThreadEntry)info_thread, 0x10000100, 0x100000, 0, 0, NULL);
|
||||||
if (info_thid >= 0)
|
if (info_thid >= 0)
|
||||||
sceKernelStartThread(info_thid, sizeof(InfoArguments), &info_args);
|
sceKernelStartThread(info_thid, sizeof(InfoArguments), &info_args);
|
||||||
|
|
||||||
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_VISIBLE;
|
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_VISIBLE;
|
||||||
}
|
|
||||||
|
|
||||||
// property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
// property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
||||||
} else {
|
} else {
|
||||||
|
178
strnatcmp.c
Normal file
178
strnatcmp.c
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* partial change history:
|
||||||
|
*
|
||||||
|
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||||
|
*
|
||||||
|
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||||
|
* value must be that of an unsigned int, even on platforms that have
|
||||||
|
* negative chars in their default char type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* These are defined as macros to make it easier to adapt this code to
|
||||||
|
* different characters types or comparison functions. */
|
||||||
|
static inline int
|
||||||
|
nat_isdigit(nat_char a)
|
||||||
|
{
|
||||||
|
return isdigit((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
nat_isspace(nat_char a)
|
||||||
|
{
|
||||||
|
return isspace((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline nat_char
|
||||||
|
nat_toupper(nat_char a)
|
||||||
|
{
|
||||||
|
return toupper((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_right(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
int bias = 0;
|
||||||
|
|
||||||
|
/* The longest run of digits wins. That aside, the greatest
|
||||||
|
value wins, but we can't know that it will until we've scanned
|
||||||
|
both numbers to know that they have the same magnitude, so we
|
||||||
|
remember it in BIAS. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return bias;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = -1;
|
||||||
|
} else if (*a > *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = +1;
|
||||||
|
} else if (!*a && !*b)
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_left(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
/* Compare two left-aligned numbers: the first to have a
|
||||||
|
different value wins. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return 0;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
else if (*a > *b)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
|
||||||
|
{
|
||||||
|
int ai, bi;
|
||||||
|
nat_char ca, cb;
|
||||||
|
int fractional, result;
|
||||||
|
|
||||||
|
assert(a && b);
|
||||||
|
ai = bi = 0;
|
||||||
|
while (1) {
|
||||||
|
ca = a[ai]; cb = b[bi];
|
||||||
|
|
||||||
|
/* skip over leading spaces or zeros */
|
||||||
|
while (nat_isspace(ca))
|
||||||
|
ca = a[++ai];
|
||||||
|
|
||||||
|
while (nat_isspace(cb))
|
||||||
|
cb = b[++bi];
|
||||||
|
|
||||||
|
/* process run of digits */
|
||||||
|
if (nat_isdigit(ca) && nat_isdigit(cb)) {
|
||||||
|
fractional = (ca == '0' || cb == '0');
|
||||||
|
|
||||||
|
if (fractional) {
|
||||||
|
if ((result = compare_left(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if ((result = compare_right(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ca && !cb) {
|
||||||
|
/* The strings compare the same. Perhaps the caller
|
||||||
|
will want to call strcmp to break the tie. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fold_case) {
|
||||||
|
ca = nat_toupper(ca);
|
||||||
|
cb = nat_toupper(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca < cb)
|
||||||
|
return -1;
|
||||||
|
else if (ca > cb)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
++ai; ++bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compare, recognizing numeric string and ignoring case. */
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 1);
|
||||||
|
}
|
31
strnatcmp.h
Normal file
31
strnatcmp.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* CUSTOMIZATION SECTION
|
||||||
|
*
|
||||||
|
* You can change this typedef, but must then also change the inline
|
||||||
|
* functions in strnatcmp.c */
|
||||||
|
typedef char nat_char;
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b);
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b);
|
Loading…
Reference in New Issue
Block a user