mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
parameters (which is by default linked in with libunix.a),
regular expressions can no longer prompt dos.library requesters
to appear. However, to be on the safe side, if you are expecting
to pass regular expressions on the command line, do not use
the wildcard expansion code such as by overriding the library
symbols with dummy functions such as are used in the file
"stdlib_wildcard_expand.c".
- Added a new variable '__open_locale' which can be used to
restrict all library functions to use the "C" language locale
rather than the current system locale settings. In addition
to that, two new functions __locale_exit() and __locale_init()
can be used to close and (re-)open the system locale at a
later time.
- Local ("static") functions are now identified by the STATIC
qualifier. This was done in preparation for changes that will
deal with global and local data and the issue of thread safety.
git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@14839 87f5fb63-7c3d-0410-a384-fd976d0f7a62
292 lines
8.2 KiB
C
292 lines
8.2 KiB
C
/*
|
|
* $Id: stdlib_qsort.c,v 1.5 2005-02-25 10:14:21 obarthel Exp $
|
|
*
|
|
* :ts=4
|
|
*
|
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
|
* Copyright (c) 2002-2005 by Olaf Barthel <olsen@sourcery.han.de>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
|
* may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
|
*/
|
|
|
|
#ifndef _STDLIB_NULL_POINTER_CHECK_H
|
|
#include "stdlib_null_pointer_check.h"
|
|
#endif /* _STDLIB_NULL_POINTER_CHECK_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifndef _STDLIB_HEADERS_H
|
|
#include "stdlib_headers.h"
|
|
#endif /* _STDLIB_HEADERS_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
/******************************************************************
|
|
* qsort.c -- Non-Recursive ANSI Quicksort function *
|
|
* *
|
|
* Public domain by Raymond Gardner, Englewood CO February 1991 *
|
|
* *
|
|
* Usage: *
|
|
* qsort(base, nbr_elements, width_bytes, compare_function); *
|
|
* void *base; *
|
|
* size_t nbr_elements, width_bytes; *
|
|
* int (*compare_function)(const void *, const void *); *
|
|
* *
|
|
* Sorts an array starting at base, of length nbr_elements, each *
|
|
* element of size width_bytes, ordered via compare_function, *
|
|
* which is called as (*compare_function)(ptr_to_element1, *
|
|
* ptr_to_element2) and returns < 0 if element1 < element2, *
|
|
* 0 if element1 = element2, > 0 if element1 > element2. *
|
|
* Most refinements are due to R. Sedgewick. See "Implementing *
|
|
* Quicksort Programs", Comm. ACM, Oct. 1978, and Corrigendum, *
|
|
* Comm. ACM, June 1979. *
|
|
******************************************************************/
|
|
|
|
/******************************************************************/
|
|
|
|
#define SWAP(a, b, size) (swap((char *)(a), (char *)(b), size))
|
|
#define COMPARE(a, b) ((*comp)((const void *)(a), (const void *)(b)))
|
|
|
|
/******************************************************************/
|
|
|
|
/* subfiles of THRESHOLD or fewer elements will
|
|
be sorted by a simple insertion sort
|
|
Note! THRESHOLD must be at least 3 */
|
|
#define THRESHOLD 7
|
|
|
|
/******************************************************************/
|
|
|
|
/* For an 68030 and beyond the alignment does not matter and you can skip the
|
|
second half of the test (everything beyond the 'nbytes >= sizeof(long)'). */
|
|
#if defined(M68020)
|
|
#define IS_WORD_ALIGNED(a,b) (1)
|
|
#else
|
|
#define IS_WORD_ALIGNED(a,b) (((((unsigned long)(a)) | ((unsigned long)(b))) & 1) == 0)
|
|
#endif /* M68020 */
|
|
|
|
/******************************************************************/
|
|
|
|
/* swap nbytes between a and b */
|
|
INLINE STATIC void
|
|
swap(char * a, char * b, size_t nbytes)
|
|
{
|
|
char temp;
|
|
|
|
assert( a != NULL && b != NULL && nbytes > 0 );
|
|
|
|
/* This is an attempt to use 'long' sized swapping, if possible. */
|
|
if(nbytes >= sizeof(long) && IS_WORD_ALIGNED(a,b))
|
|
{
|
|
long *_a = (long *)a;
|
|
long *_b = (long *)b;
|
|
long _temp;
|
|
|
|
do
|
|
{
|
|
_temp = (*_a);
|
|
(*_a++) = (*_b);
|
|
(*_b++) = _temp;
|
|
|
|
nbytes -= sizeof(long);
|
|
}
|
|
while(nbytes >= sizeof(long));
|
|
|
|
if(nbytes > 0)
|
|
{
|
|
a = (char *)_a;
|
|
b = (char *)_b;
|
|
|
|
do
|
|
{
|
|
temp = (*a);
|
|
(*a++) = (*b);
|
|
(*b++) = temp;
|
|
}
|
|
while(--nbytes > 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
temp = (*a);
|
|
(*a++) = (*b);
|
|
(*b++) = temp;
|
|
}
|
|
while(--nbytes > 0);
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
void
|
|
qsort(void * base, size_t count, size_t size, int (*comp)(const void * element1, const void * element2))
|
|
{
|
|
ENTER();
|
|
|
|
SHOWPOINTER(base);
|
|
SHOWVALUE(count);
|
|
SHOWVALUE(size);
|
|
SHOWPOINTER(comp);
|
|
|
|
assert( (int)count >= 0 && (int)size >= 0 );
|
|
|
|
if(count > 1 && size > 0)
|
|
{
|
|
char *stack[32 * 2], **sp; /* stack and stack pointer */
|
|
char *i, *j, *limit; /* scan and limit pointers */
|
|
char *base_pointer; /* base pointer as (char *) */
|
|
size_t threshold; /* size of THRESHOLD elements in bytes */
|
|
|
|
assert( base != NULL && comp != NULL );
|
|
|
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
|
{
|
|
if(base == NULL || comp == NULL)
|
|
{
|
|
SHOWMSG("invalid parameters");
|
|
|
|
__set_errno(EFAULT);
|
|
goto out;
|
|
}
|
|
}
|
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
|
|
|
/* set up (char *) base_pointer pointer */
|
|
base_pointer = (char *)base;
|
|
|
|
/* init threshold */
|
|
threshold = THRESHOLD * size; /* ZZZ problematic if (THRESHOLD * size) > 0xffffffff */
|
|
|
|
/* init stack pointer */
|
|
sp = stack;
|
|
|
|
/* pointer past end of array */
|
|
limit = base_pointer + count * size; /* ZZZ problematic if (count * size) > 0xffffffff or (base_pointer + count * size) > 0xffffffff */
|
|
|
|
/* repeat until break... */
|
|
while(TRUE)
|
|
{
|
|
/* if more than THRESHOLD elements */
|
|
if((size_t)(limit - base_pointer) > threshold)
|
|
{
|
|
/* swap base_pointer with middle */
|
|
SWAP((((limit - base_pointer) / size) / 2) * size + base_pointer, base_pointer, size);
|
|
|
|
/* i scans left to right */
|
|
i = base_pointer + size;
|
|
|
|
/* j scans right to left */
|
|
j = limit - size;
|
|
|
|
/* Sedgewick's three-element sort sets things up so that
|
|
(*i) <= (*base_pointer) <= (*j); (*base_pointer) is
|
|
pivot element */
|
|
if(COMPARE(i, j) > 0)
|
|
SWAP(i, j, size);
|
|
|
|
if(COMPARE(base_pointer, j) > 0)
|
|
SWAP(base_pointer, j, size);
|
|
|
|
if(COMPARE(i, base_pointer) > 0)
|
|
SWAP(i, base_pointer, size);
|
|
|
|
/* loop until break */
|
|
while(TRUE)
|
|
{
|
|
/* move i right until (*i) >= pivot */
|
|
do
|
|
i += size;
|
|
while(COMPARE(i, base_pointer) < 0);
|
|
|
|
/* move j left until (*j) <= pivot */
|
|
do
|
|
j -= size;
|
|
while(COMPARE(j, base_pointer) > 0);
|
|
|
|
/* break loop if pointers crossed */
|
|
if(i > j)
|
|
break;
|
|
|
|
/* else swap elements, keep scanning */
|
|
SWAP(i, j, size);
|
|
}
|
|
|
|
/* move pivot into correct place */
|
|
SWAP(base_pointer, j, size);
|
|
|
|
/* if left subfile larger */
|
|
if(j - base_pointer > limit - i)
|
|
{
|
|
/* stack left subfile base_pointer and limit */
|
|
sp[0] = base_pointer;
|
|
sp[1] = j;
|
|
|
|
/* sort the right subfile */
|
|
base_pointer = i;
|
|
}
|
|
else /* else right subfile larger */
|
|
{
|
|
/* stack right subfile base_pointer and limit */
|
|
sp[0] = i;
|
|
sp[1] = limit;
|
|
|
|
/* sort the left subfile */
|
|
limit = j;
|
|
}
|
|
|
|
/* increment stack pointer */
|
|
sp += 2;
|
|
}
|
|
else /* else subfile is small, use insertion sort */
|
|
{
|
|
for(j = base_pointer, i = j + size; i < limit; j = i, i += size)
|
|
{
|
|
for( ; COMPARE(j, j + size) > 0; j -= size )
|
|
{
|
|
SWAP(j, j + size, size);
|
|
if(j == base_pointer)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if any entries on stack pop the base_pointer and limit,
|
|
else the stack is empty and we're done */
|
|
if(sp == stack)
|
|
break;
|
|
|
|
sp -= 2;
|
|
|
|
base_pointer = sp[0];
|
|
limit = sp[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
|
|
LEAVE();
|
|
}
|