mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-19 08:25:21 +01:00
Qt/QML edition
This commit is contained in:
commit
d7b361ba44
2168 changed files with 721948 additions and 0 deletions
649
dependencies/libarchive-3.4.2/libarchive/archive_util.c
vendored
Normal file
649
dependencies/libarchive-3.4.2/libarchive/archive_util.c
vendored
Normal file
|
@ -0,0 +1,649 @@
|
|||
/*-
|
||||
* Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
#ifdef HAVE_ZLIB_H
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_LZMA_H
|
||||
#include <lzma.h>
|
||||
#endif
|
||||
#ifdef HAVE_BZLIB_H
|
||||
#include <bzlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_LZ4_H
|
||||
#include <lz4.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_random_private.h"
|
||||
#include "archive_string.h"
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
static int archive_utility_string_sort_helper(char **, unsigned int);
|
||||
|
||||
/* Generic initialization of 'struct archive' objects. */
|
||||
int
|
||||
__archive_clean(struct archive *a)
|
||||
{
|
||||
archive_string_conversion_free(a);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
int
|
||||
archive_version_number(void)
|
||||
{
|
||||
return (ARCHIVE_VERSION_NUMBER);
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_version_string(void)
|
||||
{
|
||||
return (ARCHIVE_VERSION_STRING);
|
||||
}
|
||||
|
||||
int
|
||||
archive_errno(struct archive *a)
|
||||
{
|
||||
return (a->archive_error_number);
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_error_string(struct archive *a)
|
||||
{
|
||||
|
||||
if (a->error != NULL && *a->error != '\0')
|
||||
return (a->error);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
archive_file_count(struct archive *a)
|
||||
{
|
||||
return (a->file_count);
|
||||
}
|
||||
|
||||
int
|
||||
archive_format(struct archive *a)
|
||||
{
|
||||
return (a->archive_format);
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_format_name(struct archive *a)
|
||||
{
|
||||
return (a->archive_format_name);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
archive_compression(struct archive *a)
|
||||
{
|
||||
return archive_filter_code(a, 0);
|
||||
}
|
||||
|
||||
const char *
|
||||
archive_compression_name(struct archive *a)
|
||||
{
|
||||
return archive_filter_name(a, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a count of the number of compressed bytes processed.
|
||||
*/
|
||||
la_int64_t
|
||||
archive_position_compressed(struct archive *a)
|
||||
{
|
||||
return archive_filter_bytes(a, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a count of the number of uncompressed bytes processed.
|
||||
*/
|
||||
la_int64_t
|
||||
archive_position_uncompressed(struct archive *a)
|
||||
{
|
||||
return archive_filter_bytes(a, 0);
|
||||
}
|
||||
|
||||
void
|
||||
archive_clear_error(struct archive *a)
|
||||
{
|
||||
archive_string_empty(&a->error_string);
|
||||
a->error = NULL;
|
||||
a->archive_error_number = 0;
|
||||
}
|
||||
|
||||
void
|
||||
archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
a->archive_error_number = error_number;
|
||||
if (fmt == NULL) {
|
||||
a->error = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
archive_string_empty(&(a->error_string));
|
||||
va_start(ap, fmt);
|
||||
archive_string_vsprintf(&(a->error_string), fmt, ap);
|
||||
va_end(ap);
|
||||
a->error = a->error_string.s;
|
||||
}
|
||||
|
||||
void
|
||||
archive_copy_error(struct archive *dest, struct archive *src)
|
||||
{
|
||||
dest->archive_error_number = src->archive_error_number;
|
||||
|
||||
archive_string_copy(&dest->error_string, &src->error_string);
|
||||
dest->error = dest->error_string.s;
|
||||
}
|
||||
|
||||
void
|
||||
__archive_errx(int retvalue, const char *msg)
|
||||
{
|
||||
static const char msg1[] = "Fatal Internal Error in libarchive: ";
|
||||
size_t s;
|
||||
|
||||
s = write(2, msg1, strlen(msg1));
|
||||
(void)s; /* UNUSED */
|
||||
s = write(2, msg, strlen(msg));
|
||||
(void)s; /* UNUSED */
|
||||
s = write(2, "\n", 1);
|
||||
(void)s; /* UNUSED */
|
||||
exit(retvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a temporary file
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
/*
|
||||
* Do not use Windows tmpfile() function.
|
||||
* It will make a temporary file under the root directory
|
||||
* and it'll cause permission error if a user who is
|
||||
* non-Administrator creates temporary files.
|
||||
* Also Windows version of mktemp family including _mktemp_s
|
||||
* are not secure.
|
||||
*/
|
||||
static int
|
||||
__archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
{
|
||||
static const wchar_t prefix[] = L"libarchive_";
|
||||
static const wchar_t suffix[] = L"XXXXXXXXXX";
|
||||
static const wchar_t num[] = {
|
||||
L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
|
||||
L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
|
||||
L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
|
||||
L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
|
||||
L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
|
||||
L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
|
||||
L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
|
||||
L'u', L'v', L'w', L'x', L'y', L'z'
|
||||
};
|
||||
HCRYPTPROV hProv;
|
||||
struct archive_wstring temp_name;
|
||||
wchar_t *ws;
|
||||
DWORD attr;
|
||||
wchar_t *xp, *ep;
|
||||
int fd;
|
||||
|
||||
hProv = (HCRYPTPROV)NULL;
|
||||
fd = -1;
|
||||
ws = NULL;
|
||||
|
||||
if (template == NULL) {
|
||||
archive_string_init(&temp_name);
|
||||
|
||||
/* Get a temporary directory. */
|
||||
if (tmpdir == NULL) {
|
||||
size_t l;
|
||||
wchar_t *tmp;
|
||||
|
||||
l = GetTempPathW(0, NULL);
|
||||
if (l == 0) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
tmp = malloc(l*sizeof(wchar_t));
|
||||
if (tmp == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
GetTempPathW((DWORD)l, tmp);
|
||||
archive_wstrcpy(&temp_name, tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
|
||||
strlen(tmpdir)) < 0)
|
||||
goto exit_tmpfile;
|
||||
if (temp_name.s[temp_name.length-1] != L'/')
|
||||
archive_wstrappend_wchar(&temp_name, L'/');
|
||||
}
|
||||
|
||||
/* Check if temp_name is a directory. */
|
||||
attr = GetFileAttributesW(temp_name.s);
|
||||
if (attr == (DWORD)-1) {
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
ws = __la_win_permissive_name_w(temp_name.s);
|
||||
if (ws == NULL) {
|
||||
errno = EINVAL;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
attr = GetFileAttributesW(ws);
|
||||
if (attr == (DWORD)-1) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
}
|
||||
if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
errno = ENOTDIR;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a temporary file.
|
||||
*/
|
||||
archive_wstrcat(&temp_name, prefix);
|
||||
archive_wstrcat(&temp_name, suffix);
|
||||
ep = temp_name.s + archive_strlen(&temp_name);
|
||||
xp = ep - wcslen(suffix);
|
||||
template = temp_name.s;
|
||||
} else {
|
||||
xp = wcschr(template, L'X');
|
||||
if (xp == NULL) /* No X, programming error */
|
||||
abort();
|
||||
for (ep = xp; *ep == L'X'; ep++)
|
||||
continue;
|
||||
if (*ep) /* X followed by non X, programming error */
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
wchar_t *p;
|
||||
HANDLE h;
|
||||
|
||||
/* Generate a random file name through CryptGenRandom(). */
|
||||
p = xp;
|
||||
if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
|
||||
(BYTE*)p)) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
for (; p < ep; p++)
|
||||
*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
|
||||
|
||||
free(ws);
|
||||
ws = __la_win_permissive_name_w(template);
|
||||
if (ws == NULL) {
|
||||
errno = EINVAL;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
if (template == temp_name.s) {
|
||||
attr = FILE_ATTRIBUTE_TEMPORARY |
|
||||
FILE_FLAG_DELETE_ON_CLOSE;
|
||||
} else {
|
||||
/* mkstemp */
|
||||
attr = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
h = CreateFileW(ws,
|
||||
GENERIC_READ | GENERIC_WRITE | DELETE,
|
||||
0,/* Not share */
|
||||
NULL,
|
||||
CREATE_NEW,/* Create a new file only */
|
||||
attr,
|
||||
NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
/* The same file already exists. retry with
|
||||
* a new filename. */
|
||||
if (GetLastError() == ERROR_FILE_EXISTS)
|
||||
continue;
|
||||
/* Otherwise, fail creation temporary file. */
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
|
||||
if (fd == -1) {
|
||||
CloseHandle(h);
|
||||
goto exit_tmpfile;
|
||||
} else
|
||||
break;/* success! */
|
||||
}
|
||||
exit_tmpfile:
|
||||
if (hProv != (HCRYPTPROV)NULL)
|
||||
CryptReleaseContext(hProv, 0);
|
||||
free(ws);
|
||||
if (template == temp_name.s)
|
||||
archive_wstring_free(&temp_name);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
int
|
||||
__archive_mktemp(const char *tmpdir)
|
||||
{
|
||||
return __archive_mktempx(tmpdir, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
__archive_mkstemp(wchar_t *template)
|
||||
{
|
||||
return __archive_mktempx(NULL, template);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
get_tempdir(struct archive_string *temppath)
|
||||
{
|
||||
const char *tmp;
|
||||
|
||||
tmp = getenv("TMPDIR");
|
||||
if (tmp == NULL)
|
||||
#ifdef _PATH_TMP
|
||||
tmp = _PATH_TMP;
|
||||
#else
|
||||
tmp = "/tmp";
|
||||
#endif
|
||||
archive_strcpy(temppath, tmp);
|
||||
if (temppath->s[temppath->length-1] != '/')
|
||||
archive_strappend_char(temppath, '/');
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#if defined(HAVE_MKSTEMP)
|
||||
|
||||
/*
|
||||
* We can use mkstemp().
|
||||
*/
|
||||
|
||||
int
|
||||
__archive_mktemp(const char *tmpdir)
|
||||
{
|
||||
struct archive_string temp_name;
|
||||
int fd = -1;
|
||||
|
||||
archive_string_init(&temp_name);
|
||||
if (tmpdir == NULL) {
|
||||
if (get_tempdir(&temp_name) != ARCHIVE_OK)
|
||||
goto exit_tmpfile;
|
||||
} else {
|
||||
archive_strcpy(&temp_name, tmpdir);
|
||||
if (temp_name.s[temp_name.length-1] != '/')
|
||||
archive_strappend_char(&temp_name, '/');
|
||||
}
|
||||
archive_strcat(&temp_name, "libarchive_XXXXXX");
|
||||
fd = mkstemp(temp_name.s);
|
||||
if (fd < 0)
|
||||
goto exit_tmpfile;
|
||||
__archive_ensure_cloexec_flag(fd);
|
||||
unlink(temp_name.s);
|
||||
exit_tmpfile:
|
||||
archive_string_free(&temp_name);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
int
|
||||
__archive_mkstemp(char *template)
|
||||
{
|
||||
int fd = -1;
|
||||
fd = mkstemp(template);
|
||||
if (fd >= 0)
|
||||
__archive_ensure_cloexec_flag(fd);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
#else /* !HAVE_MKSTEMP */
|
||||
|
||||
/*
|
||||
* We use a private routine.
|
||||
*/
|
||||
|
||||
static int
|
||||
__archive_mktempx(const char *tmpdir, char *template)
|
||||
{
|
||||
static const char num[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z'
|
||||
};
|
||||
struct archive_string temp_name;
|
||||
struct stat st;
|
||||
int fd;
|
||||
char *tp, *ep;
|
||||
|
||||
fd = -1;
|
||||
if (template == NULL) {
|
||||
archive_string_init(&temp_name);
|
||||
if (tmpdir == NULL) {
|
||||
if (get_tempdir(&temp_name) != ARCHIVE_OK)
|
||||
goto exit_tmpfile;
|
||||
} else
|
||||
archive_strcpy(&temp_name, tmpdir);
|
||||
if (temp_name.s[temp_name.length-1] == '/') {
|
||||
temp_name.s[temp_name.length-1] = '\0';
|
||||
temp_name.length --;
|
||||
}
|
||||
if (la_stat(temp_name.s, &st) < 0)
|
||||
goto exit_tmpfile;
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
archive_strcat(&temp_name, "/libarchive_");
|
||||
tp = temp_name.s + archive_strlen(&temp_name);
|
||||
archive_strcat(&temp_name, "XXXXXXXXXX");
|
||||
ep = temp_name.s + archive_strlen(&temp_name);
|
||||
template = temp_name.s;
|
||||
} else {
|
||||
tp = strchr(template, 'X');
|
||||
if (tp == NULL) /* No X, programming error */
|
||||
abort();
|
||||
for (ep = tp; *ep == 'X'; ep++)
|
||||
continue;
|
||||
if (*ep) /* X followed by non X, programming error */
|
||||
abort();
|
||||
}
|
||||
|
||||
do {
|
||||
char *p;
|
||||
|
||||
p = tp;
|
||||
archive_random(p, ep - p);
|
||||
while (p < ep) {
|
||||
int d = *((unsigned char *)p) % sizeof(num);
|
||||
*p++ = num[d];
|
||||
}
|
||||
fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
|
||||
0600);
|
||||
} while (fd < 0 && errno == EEXIST);
|
||||
if (fd < 0)
|
||||
goto exit_tmpfile;
|
||||
__archive_ensure_cloexec_flag(fd);
|
||||
if (template == temp_name.s)
|
||||
unlink(temp_name.s);
|
||||
exit_tmpfile:
|
||||
if (template == temp_name.s)
|
||||
archive_string_free(&temp_name);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
int
|
||||
__archive_mktemp(const char *tmpdir)
|
||||
{
|
||||
return __archive_mktempx(tmpdir, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
__archive_mkstemp(char *template)
|
||||
{
|
||||
return __archive_mktempx(NULL, template);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_MKSTEMP */
|
||||
#endif /* !_WIN32 || __CYGWIN__ */
|
||||
|
||||
/*
|
||||
* Set FD_CLOEXEC flag to a file descriptor if it is not set.
|
||||
* We have to set the flag if the platform does not provide O_CLOEXEC
|
||||
* or F_DUPFD_CLOEXEC flags.
|
||||
*
|
||||
* Note: This function is absolutely called after creating a new file
|
||||
* descriptor even if the platform seemingly provides O_CLOEXEC or
|
||||
* F_DUPFD_CLOEXEC macros because it is possible that the platform
|
||||
* merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
|
||||
*/
|
||||
void
|
||||
__archive_ensure_cloexec_flag(int fd)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
(void)fd; /* UNUSED */
|
||||
#else
|
||||
int flags;
|
||||
|
||||
if (fd >= 0) {
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags != -1 && (flags & FD_CLOEXEC) == 0)
|
||||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to sort a group of strings using quicksort.
|
||||
*/
|
||||
static int
|
||||
archive_utility_string_sort_helper(char **strings, unsigned int n)
|
||||
{
|
||||
unsigned int i, lesser_count, greater_count;
|
||||
char **lesser, **greater, **tmp, *pivot;
|
||||
int retval1, retval2;
|
||||
|
||||
/* A list of 0 or 1 elements is already sorted */
|
||||
if (n <= 1)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
lesser_count = greater_count = 0;
|
||||
lesser = greater = NULL;
|
||||
pivot = strings[0];
|
||||
for (i = 1; i < n; i++)
|
||||
{
|
||||
if (strcmp(strings[i], pivot) < 0)
|
||||
{
|
||||
lesser_count++;
|
||||
tmp = (char **)realloc(lesser,
|
||||
lesser_count * sizeof(char *));
|
||||
if (!tmp) {
|
||||
free(greater);
|
||||
free(lesser);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
lesser = tmp;
|
||||
lesser[lesser_count - 1] = strings[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
greater_count++;
|
||||
tmp = (char **)realloc(greater,
|
||||
greater_count * sizeof(char *));
|
||||
if (!tmp) {
|
||||
free(greater);
|
||||
free(lesser);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
greater = tmp;
|
||||
greater[greater_count - 1] = strings[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* quicksort(lesser) */
|
||||
retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
|
||||
for (i = 0; i < lesser_count; i++)
|
||||
strings[i] = lesser[i];
|
||||
free(lesser);
|
||||
|
||||
/* pivot */
|
||||
strings[lesser_count] = pivot;
|
||||
|
||||
/* quicksort(greater) */
|
||||
retval2 = archive_utility_string_sort_helper(greater, greater_count);
|
||||
for (i = 0; i < greater_count; i++)
|
||||
strings[lesser_count + 1 + i] = greater[i];
|
||||
free(greater);
|
||||
|
||||
return (retval1 < retval2) ? retval1 : retval2;
|
||||
}
|
||||
|
||||
int
|
||||
archive_utility_string_sort(char **strings)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
while (strings[size] != NULL)
|
||||
size++;
|
||||
return archive_utility_string_sort_helper(strings, size);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue