Gallery can now list photos ... names sorted using quicksort.
This commit is contained in:
parent
80feccdd87
commit
d02b825fba
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
.PHONY: clean
|
||||
OBJS=obj/main.o obj/util.o obj/galleries.o obj/varray.o
|
||||
OBJS=obj/main.o obj/util.o obj/galleries.o obj/gallery.o obj/varray.o
|
||||
|
||||
gallery.cgi: $(OBJS)
|
||||
$(CC) -o $@ $(OBJS)
|
||||
|
@ -17,6 +17,7 @@ struct gallery_info {
|
||||
char* gallery_name; /* Directory name for gallery */
|
||||
char* gallery_title; /* Title of gallery */
|
||||
char* gallery_desc; /* Description of gallery */
|
||||
char* gallery_dir; /* Filesystem path of gallery */
|
||||
};
|
||||
|
||||
/* Two helper functions create, (deep) copy and destroy these structures */
|
||||
@ -28,6 +29,7 @@ struct gallery_info {
|
||||
* struct is malloc()'d for use and returned.
|
||||
*/
|
||||
struct gallery_info* create_gallery_info(
|
||||
const char* dir,
|
||||
const char* name,
|
||||
const char* title,
|
||||
const char* desc,
|
||||
|
43
include/gallery.h
Normal file
43
include/gallery.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _GALLERY_H
|
||||
#define _GALLERY_H
|
||||
|
||||
#include <varray.h>
|
||||
#include <galleries.h>
|
||||
|
||||
/* The following file describes structs that pertain to a specific gallery. */
|
||||
|
||||
/* Gallery Contents structure. The following file wraps up a gallery_info
|
||||
* file along with a listing of all photos in the gallery, stored as a string
|
||||
* array.
|
||||
*
|
||||
* Note that in this structure, the info pointer is neigher copied nor freed.
|
||||
*/
|
||||
struct gallery_contents {
|
||||
struct gallery_info* info;
|
||||
struct static_string_array* photos;
|
||||
};
|
||||
|
||||
/* Get the contents of a gallery. This takes an existing gallery_info struct,
|
||||
* opens the directory, then grabs the names of all supported photo types.
|
||||
*
|
||||
* A pre-allocated struct may be supplied for storage, otherwise a new one will
|
||||
* be created (pass NULL as the argument).
|
||||
*
|
||||
* Returns a brand new gallery_contents struct, or NULL if creation failed.
|
||||
*/
|
||||
struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
|
||||
struct gallery_contents* dest );
|
||||
|
||||
/* Destroy a gallery_contents struct. The fields_only member tells this
|
||||
* function that the gallery_contents struct, just its contents.
|
||||
*/
|
||||
void destroy_gallery_contents( struct gallery_contents* gc, int fields_only );
|
||||
|
||||
/* Duplicate a gallery_contents struct. A pre-allocated struct may be supplied.
|
||||
*
|
||||
* This does a deep copy of the structure, returning it, or NULL if it failed.
|
||||
*/
|
||||
struct gallery_contents* copy_gallery_contents( struct gallery_contents* gc,
|
||||
struct gallery_contents* dest );
|
||||
|
||||
#endif
|
@ -109,4 +109,26 @@ struct txtinfo_chain* read_txtinfo_chain( const char* file );
|
||||
|
||||
/* Write out a txtinfo_chain object. Returns 0 on success, errno on failure. */
|
||||
int write_txtinfo_chain( const char* file, struct txtinfo_chain* chain );
|
||||
|
||||
/* Duplicate a structure in memory.
|
||||
* This calls malloc to allocate a region of the specified size,
|
||||
* then does a memcpy from the supplied address.
|
||||
*
|
||||
* Returns the copy on success, or NULL on failure.
|
||||
*/
|
||||
void* memdup( void* ptr, size_t length );
|
||||
|
||||
/* Sort a generic array
|
||||
*
|
||||
* This does an in-place sort of the objects contained in the array.
|
||||
* Since there's no way of knowing how to sort the objects, a function
|
||||
* for doing this must be supplied as a pointer.
|
||||
*
|
||||
* str_sort_array does the above sort with strings, setting case_insensitive
|
||||
* will cause the sorting algorithm to ignore the case.
|
||||
*/
|
||||
void sort_str_array( char** array, size_t length, int case_insensitive );
|
||||
void sort_array( char** array, size_t length,
|
||||
int (*compare)( const void*, const void* ) );
|
||||
|
||||
#endif
|
||||
|
@ -75,6 +75,14 @@ struct vararray* create_vararray( struct vararray* dest, size_t obj_size,
|
||||
*/
|
||||
void destroy_vararray( struct vararray* dest );
|
||||
|
||||
/* Copy a vararray
|
||||
*
|
||||
* This does a deep copy of the entire contents in the array.
|
||||
*
|
||||
* Returns the copy on success, or NULL on failure
|
||||
*/
|
||||
struct vararray* copy_vararray( struct vararray* src );
|
||||
|
||||
/* Fetch a node value. There's one function for each type.
|
||||
*
|
||||
* They are provided to allow easy fetching of simple types without needing to
|
||||
@ -380,8 +388,9 @@ CREATE_STATIC_ARRAY_STRUCT( static_string_array, char*, string );
|
||||
|
||||
/* The following are for all the simple types in use. Note that the
|
||||
* size parameter is omitted. They all match the generic type array
|
||||
* (static_simple_array), and may be casted as such when freeing.
|
||||
* (static_simple_array), which is used when duplicating the arrays.
|
||||
*/
|
||||
struct static_simple_array { size_t length; void* value; };
|
||||
struct static_char_array { size_t length; char* value; };
|
||||
struct static_uchar_array { size_t length; unsigned char* value; };
|
||||
struct static_short_array { size_t length; short* value; };
|
||||
@ -400,38 +409,38 @@ struct static_double_array { size_t length; double* value; };
|
||||
*
|
||||
* They return the vararray created, or NULL on failure.
|
||||
*/
|
||||
struct vararray* import_obj_array( struct static_obj_array* sa );
|
||||
struct vararray* import_string_array( struct static_string_array* sa );
|
||||
struct vararray* import_char_array( struct static_char_array* sa );
|
||||
struct vararray* import_uchar_array( struct static_uchar_array* sa );
|
||||
struct vararray* import_short_array( struct static_short_array* sa );
|
||||
struct vararray* import_ushort_array( struct static_ushort_array* sa );
|
||||
struct vararray* import_int_array( struct static_int_array* sa );
|
||||
struct vararray* import_uint_array( struct static_uint_array* sa );
|
||||
struct vararray* import_long_array( struct static_long_array* sa );
|
||||
struct vararray* import_ulong_array( struct static_ulong_array* sa );
|
||||
struct vararray* import_llong_array( struct static_llong_array* sa );
|
||||
struct vararray* import_ullong_array( struct static_ullong_array* sa );
|
||||
struct vararray* import_float_array( struct static_float_array* sa );
|
||||
struct vararray* import_double_array( struct static_double_array* sa );
|
||||
struct vararray* import_obj_array( struct static_obj_array* sa );
|
||||
struct vararray* import_string_array( struct static_string_array* sa );
|
||||
struct vararray* import_char_array( struct static_char_array* sa );
|
||||
struct vararray* import_uchar_array( struct static_uchar_array* sa );
|
||||
struct vararray* import_short_array( struct static_short_array* sa );
|
||||
struct vararray* import_ushort_array( struct static_ushort_array* sa );
|
||||
struct vararray* import_int_array( struct static_int_array* sa );
|
||||
struct vararray* import_uint_array( struct static_uint_array* sa );
|
||||
struct vararray* import_long_array( struct static_long_array* sa );
|
||||
struct vararray* import_ulong_array( struct static_ulong_array* sa );
|
||||
struct vararray* import_llong_array( struct static_llong_array* sa );
|
||||
struct vararray* import_ullong_array( struct static_ullong_array* sa );
|
||||
struct vararray* import_float_array( struct static_float_array* sa );
|
||||
struct vararray* import_double_array( struct static_double_array* sa );
|
||||
|
||||
/* Export functions. These take a variable array and output a plain static
|
||||
* C array of the specified type, or NULL if this can't be achieved.
|
||||
*/
|
||||
struct static_obj_array* export_obj_array( struct vararray* va );
|
||||
struct static_string_array* export_string_array( struct vararray* va );
|
||||
struct static_char_array* export_char_array( struct vararray* va );
|
||||
struct static_uchar_array* export_uchar_array( struct vararray* va );
|
||||
struct static_short_array* export_short_array( struct vararray* va );
|
||||
struct static_ushort_array* export_ushort_array( struct vararray* va );
|
||||
struct static_int_array* export_int_array( struct vararray* va );
|
||||
struct static_uint_array* export_uint_array( struct vararray* va );
|
||||
struct static_long_array* export_long_array( struct vararray* va );
|
||||
struct static_ulong_array* export_ulong_array( struct vararray* va );
|
||||
struct static_llong_array* export_llong_array( struct vararray* va );
|
||||
struct static_ullong_array* export_ullong_array( struct vararray* va );
|
||||
struct static_float_array* export_float_array( struct vararray* va );
|
||||
struct static_double_array* export_double_array( struct vararray* va );
|
||||
struct static_obj_array* export_obj_array( struct vararray* va );
|
||||
struct static_string_array* export_string_array( struct vararray* va);
|
||||
struct static_char_array* export_char_array( struct vararray* va );
|
||||
struct static_uchar_array* export_uchar_array( struct vararray* va );
|
||||
struct static_short_array* export_short_array( struct vararray* va );
|
||||
struct static_ushort_array* export_ushort_array( struct vararray* va);
|
||||
struct static_int_array* export_int_array( struct vararray* va );
|
||||
struct static_uint_array* export_uint_array( struct vararray* va );
|
||||
struct static_long_array* export_long_array( struct vararray* va );
|
||||
struct static_ulong_array* export_ulong_array( struct vararray* va );
|
||||
struct static_llong_array* export_llong_array( struct vararray* va );
|
||||
struct static_ullong_array* export_ullong_array( struct vararray* va);
|
||||
struct static_float_array* export_float_array( struct vararray* va );
|
||||
struct static_double_array* export_double_array( struct vararray* va);
|
||||
|
||||
/* Free a static array. The following can be used to free any
|
||||
* statically-allocated array. Macros are provided to free the above static
|
||||
@ -451,7 +460,7 @@ void destroy_array( void* container, size_t length,
|
||||
* object, in the case of static_obj_array)
|
||||
*/
|
||||
#define destroy_obj_array( array, ptr_member ) \
|
||||
destroy_array( array, array->length, array->member, 1 )
|
||||
destroy_array( array, array->length, array->ptr_member, 1 )
|
||||
|
||||
/* Free an array of strings. */
|
||||
#define destroy_string_array( array ) \
|
||||
@ -461,4 +470,25 @@ void destroy_array( void* container, size_t length,
|
||||
#define destroy_simple_array( array ) \
|
||||
destroy_array( array, array->length, array->value, 0 )
|
||||
|
||||
/* Duplicate a static array. The following will make a deep copy of any
|
||||
* statically-allocated array in one of the above structs.
|
||||
*
|
||||
* For convenience, a macro is provided that casts your array to the
|
||||
* right type for use. You should use this, rather than calling the
|
||||
* function directly. The macro assumes at least one element is present
|
||||
* in the array.
|
||||
*
|
||||
* Returns the copy on success, NULL on failure.
|
||||
*/
|
||||
struct static_simple_array* duplicate_simple_array_impl(
|
||||
struct static_simple_array* src, size_t data_size );
|
||||
#define duplicate_static_array( array, type ) \
|
||||
(type*)duplicate_simple_array_impl( \
|
||||
(struct static_simple_array*)array, \
|
||||
sizeof( array->value[0] ) )
|
||||
|
||||
struct static_obj_array* duplicate_obj_array_impl(
|
||||
struct static_obj_array* src );
|
||||
#define duplicate_static_obj_array( array, type ) \
|
||||
(type*)duplicate_obj_array_impl( (struct static_obj_array*)array )
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
* struct is malloc()'d for use and returned.
|
||||
*/
|
||||
struct gallery_info* create_gallery_info(
|
||||
const char* dir,
|
||||
const char* name,
|
||||
const char* title,
|
||||
const char* desc,
|
||||
@ -38,16 +39,19 @@ struct gallery_info* create_gallery_info(
|
||||
/* If we're still here, then allocation succeeded:
|
||||
* copy in the strings
|
||||
*/
|
||||
dest->gallery_dir = strdup(dir);
|
||||
dest->gallery_name = strdup(name);
|
||||
dest->gallery_title= strdup(title);
|
||||
dest->gallery_desc = strdup(desc);
|
||||
|
||||
/* Check none of them are null */
|
||||
if ( (dest->gallery_name == NULL) ||
|
||||
if ( (dest->gallery_dir == NULL) ||
|
||||
(dest->gallery_name == NULL) ||
|
||||
(dest->gallery_title == NULL) ||
|
||||
(dest->gallery_desc == NULL) ) {
|
||||
dprintf("create_gallery_info: name at %p, title at %p, desc at %p -> bailout!\n",
|
||||
dest->gallery_name, dest->gallery_title, dest->gallery_desc);
|
||||
if ( dest->gallery_dir != NULL ) free( dest->gallery_dir );
|
||||
if ( dest->gallery_name != NULL ) free( dest->gallery_name );
|
||||
if ( dest->gallery_title != NULL ) free( dest->gallery_title );
|
||||
if ( dest->gallery_desc != NULL ) free( dest->gallery_desc );
|
||||
@ -62,7 +66,8 @@ struct gallery_info* create_gallery_info(
|
||||
struct gallery_info* copy_gallery_info( struct gallery_info* info,
|
||||
struct gallery_info* dest ) {
|
||||
dprintf("copy_gallery_info: copying %p to %p\n", info, dest );
|
||||
return create_gallery_info( info->gallery_name,
|
||||
return create_gallery_info( info->gallery_dir,
|
||||
info->gallery_name,
|
||||
info->gallery_title,
|
||||
info->gallery_desc,
|
||||
dest );
|
||||
@ -77,6 +82,7 @@ void destroy_gallery_info( struct gallery_info* info, int fields_only ) {
|
||||
free( info->gallery_name );
|
||||
free( info->gallery_title );
|
||||
free( info->gallery_desc );
|
||||
free( info->gallery_dir );
|
||||
if ( !fields_only ) free( info );
|
||||
}
|
||||
|
||||
@ -124,7 +130,7 @@ struct gallery_info* read_gallery( const char* dir, struct gallery_info* dest )
|
||||
dprintf( "read_gallery: name=%s\n", name );
|
||||
|
||||
/* Create the object */
|
||||
dest = create_gallery_info( name, title, desc, dest );
|
||||
dest = create_gallery_info( dir, name, title, desc, dest );
|
||||
|
||||
/* Free our copy of the data and return */
|
||||
free( name );
|
||||
|
125
src/gallery.c
Normal file
125
src/gallery.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include <gallery.h>
|
||||
#include <dprintf.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <util.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/* Get the contents of a gallery. This takes an existing gallery_info struct,
|
||||
* opens the directory, then grabs the names of all supported photo types.
|
||||
*
|
||||
* A pre-allocated struct may be supplied for storage, otherwise a new one will
|
||||
* be created (pass NULL as the argument).
|
||||
*
|
||||
* Returns a brand new gallery_contents struct, or NULL if creation failed.
|
||||
*/
|
||||
struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
|
||||
struct gallery_contents* dest ){
|
||||
int free_struct = 1;
|
||||
if ( gallery == NULL ) return NULL;
|
||||
|
||||
if ( dest == NULL )
|
||||
dest = (struct gallery_contents*)
|
||||
calloc( 1, sizeof( struct gallery_contents ) );
|
||||
else free_struct = 0;
|
||||
if ( dest == NULL ) return NULL;
|
||||
|
||||
dprintf("read_gallery_contents: reading gallery info from gallery %s storing in %p\n", gallery->gallery_name, dest);
|
||||
|
||||
dest->info = gallery;
|
||||
struct vararray* list = create_vararray( NULL, 0, NULL, NULL );
|
||||
if ( list == NULL ) {
|
||||
dputs("read_gallery_contents: failed to allocate vararray\n");
|
||||
if ( free_struct ) free( dest );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Open the directory up */
|
||||
DIR* dir = opendir( gallery->gallery_dir );
|
||||
if ( dir == NULL ) {
|
||||
dprintf("read_gallery_contents: failed to opendir(\"%s\")\n", gallery->gallery_dir);
|
||||
if ( free_struct ) free( dest );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dirent* de = readdir( dir );
|
||||
while ( de != NULL ) {
|
||||
/* Look for files that end in:
|
||||
* .jpg, .jpeg, .gif, .png, .tif, .tiff
|
||||
*
|
||||
* Ultimately, I should just probe using magic bytes, but
|
||||
* this'll do for now.
|
||||
*/
|
||||
char* file_ext = rindex( de->d_name, '.' );
|
||||
if ( ( file_ext != NULL ) &&
|
||||
( (strcasecmp( file_ext, ".jpg" ) == 0) ||
|
||||
(strcasecmp( file_ext, ".jpeg" ) == 0) ||
|
||||
(strcasecmp( file_ext, ".gif" ) == 0) ||
|
||||
(strcasecmp( file_ext, ".png" ) == 0) ||
|
||||
(strcasecmp( file_ext, ".tif" ) == 0) ||
|
||||
(strcasecmp( file_ext, ".tiff" ) == 0) ) )
|
||||
push_vararray_string( list, de->d_name );
|
||||
|
||||
de = readdir( dir );
|
||||
}
|
||||
closedir( dir );
|
||||
|
||||
/* We now should have a list of files in list...
|
||||
* convert this to a static array, then dispense with the original
|
||||
* variable array.
|
||||
*/
|
||||
dest->photos = export_string_array( list );
|
||||
destroy_vararray( list );
|
||||
|
||||
/* Check for success... if not, free everything and return NULL */
|
||||
if ( dest->photos == NULL ) {
|
||||
dputs("read_gallery_contents: failed to list files\n");
|
||||
if ( free_struct ) free( dest );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Do a sort of the filenames */
|
||||
if ( dest->photos->length > 1 )
|
||||
sort_str_array( dest->photos->string, dest->photos->length, 1 );
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Destroy a gallery_contents struct. The fields_only member tells this
|
||||
* function that the gallery_contents struct, just its contents.
|
||||
*/
|
||||
void destroy_gallery_contents( struct gallery_contents* gc, int fields_only ) {
|
||||
destroy_string_array( gc->photos );
|
||||
free( gc );
|
||||
}
|
||||
|
||||
/* Duplicate a gallery_contents struct. A pre-allocated struct may be supplied.
|
||||
*
|
||||
* This does a deep copy of the structure, returning it, or NULL if it failed.
|
||||
*/
|
||||
struct gallery_contents* copy_gallery_contents( struct gallery_contents* gc,
|
||||
struct gallery_contents* dest ) {
|
||||
int free_struct = 1;
|
||||
if ( dest == NULL ) {
|
||||
dest = (struct gallery_contents*)
|
||||
memdup( (void*)gc,
|
||||
sizeof( struct gallery_contents ) );
|
||||
if ( dest == NULL ) return NULL;
|
||||
} else {
|
||||
free_struct = 0;
|
||||
memcpy( (void*)dest, (void*)gc,
|
||||
sizeof( struct gallery_contents ) );
|
||||
}
|
||||
|
||||
/* That's duplicated the main container... now the photo list */
|
||||
dest->photos = duplicate_static_obj_array( gc->photos,
|
||||
struct static_string_array );
|
||||
if ( dest->photos == NULL ) {
|
||||
if ( free_struct ) free( dest );
|
||||
return NULL;
|
||||
}
|
||||
return dest;
|
||||
}
|
13
src/main.c
13
src/main.c
@ -5,6 +5,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <dprintf.h>
|
||||
#include <errno.h>
|
||||
#include <gallery.h>
|
||||
|
||||
/* Entry point into entire webapp */
|
||||
int main( int argc, char** argv ) {
|
||||
@ -108,7 +109,17 @@ void gallery_handler( struct gallery_info* gallery,
|
||||
struct vararray* path_info ) {
|
||||
printf("Content-Type: text/plain\n\nTODO: gallery handler\n");
|
||||
printf("Name: %s\nTitle: %s\nDescription: %s\n",
|
||||
gallery->gallery_name, gallery->gallery_title, gallery->gallery_desc );
|
||||
gallery->gallery_name,
|
||||
gallery->gallery_title,
|
||||
gallery->gallery_desc );
|
||||
|
||||
/* Read the photo list */
|
||||
struct gallery_contents* contents =
|
||||
read_gallery_contents( gallery, NULL );
|
||||
|
||||
size_t i;
|
||||
for( i = 0; i < contents->photos->length; i++ )
|
||||
puts( contents->photos->string[i] );
|
||||
}
|
||||
|
||||
/* Action pages handler */
|
||||
|
90
src/util.c
90
src/util.c
@ -375,3 +375,93 @@ int write_txtinfo_chain( const char* file, struct txtinfo_chain* chain ) {
|
||||
fclose( fp );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Duplicate a structure in memory.
|
||||
* This calls malloc to allocate a region of the specified size,
|
||||
* then does a memcpy from the supplied address.
|
||||
*
|
||||
* Returns the copy on success, or NULL on failure.
|
||||
*/
|
||||
void* memdup( void* ptr, size_t length ) {
|
||||
void* out = malloc( length );
|
||||
if ( out != NULL ) memcpy( out, ptr, length );
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Sort an array of strings
|
||||
*
|
||||
* This does an in-place sort of the strings contained in the array.
|
||||
* Setting the case_insensitive argument non-zero causes the case to be ignored
|
||||
* when sorting.
|
||||
*
|
||||
* The implementation is based on pseudocode from
|
||||
* http://en.wikipedia.org/wiki/Quick_sort#Version_with_in-place_partition
|
||||
*/
|
||||
inline size_t quicksort_part( void** array, size_t left,
|
||||
size_t right, size_t pivot,
|
||||
int (*compare)( const void*, const void* ) ) {
|
||||
|
||||
void* pivot_value = array[ pivot ];
|
||||
dprintf( "quicksort_part: array at %p, between %d and %d, pivot %d\n",
|
||||
array, left, right, pivot );
|
||||
|
||||
/* swap array[pivotIndex] and array[right] // Move pivot to end */
|
||||
array[ pivot ] = array[ right ];
|
||||
array[ right ] = pivot_value;
|
||||
|
||||
size_t store_index = left;
|
||||
void* store_val;
|
||||
|
||||
size_t i;
|
||||
for( i = left; i < right; i++ ) {
|
||||
dprintf( "quicksort_part: at %d, string at %p\n",
|
||||
i, &array[i] );
|
||||
/* if array[i] <= pivotValue */
|
||||
if ( compare( array[i], pivot_value ) <= 0 ) {
|
||||
/* swap array[i] and array[storeIndex] */
|
||||
store_val = array[ store_index ];
|
||||
array[ store_index ] = array[ i ];
|
||||
array[ i ] = store_val;
|
||||
|
||||
store_index++;
|
||||
}
|
||||
}
|
||||
/* // Move pivot to its final place
|
||||
* swap array[storeIndex] and array[right]
|
||||
*/
|
||||
store_val = array[ store_index ];
|
||||
array[ store_index ] = array[ right ];
|
||||
array[ right ] = store_val;
|
||||
|
||||
return store_index;
|
||||
}
|
||||
|
||||
inline void quicksort_main( void** array, size_t left, size_t right,
|
||||
int (*compare)( const void*, const void* ) ) {
|
||||
if ( right > left ) {
|
||||
size_t pivot_index =
|
||||
quicksort_part( array, left, right, left, compare );
|
||||
quicksort_main( array, left, pivot_index-1, compare );
|
||||
quicksort_main( array, pivot_index+1, right, compare );
|
||||
}
|
||||
}
|
||||
|
||||
inline int void_strcmp( const void* a, const void* b ) {
|
||||
return strcmp( (char*)a, (char*)b );
|
||||
}
|
||||
|
||||
inline int void_strcasecmp( const void* a, const void* b ) {
|
||||
return strcasecmp( (char*)a, (char*)b );
|
||||
}
|
||||
|
||||
void sort_array( char** array, size_t length,
|
||||
int (*compare)( const void*, const void* ) ) {
|
||||
quicksort_main( array, 0, length-1, compare );
|
||||
}
|
||||
|
||||
void sort_str_array( char** array, size_t length, int case_insensitive ) {
|
||||
if ( case_insensitive )
|
||||
quicksort_main( (void**)array, 0, length-1, &void_strcasecmp );
|
||||
else
|
||||
quicksort_main( (void**)array, 0, length-1, &void_strcmp );
|
||||
}
|
||||
|
135
src/varray.c
135
src/varray.c
@ -1,6 +1,7 @@
|
||||
#include <varray.h>
|
||||
#include <stdlib.h>
|
||||
#include <dprintf.h>
|
||||
#include <util.h>
|
||||
/*
|
||||
* Variable array implementation. The following implements a linked-list
|
||||
* allowing for easy dynamic array manipulation.
|
||||
@ -10,11 +11,12 @@
|
||||
* for efficient indexing once the content is settled.
|
||||
*/
|
||||
|
||||
/* Helper: Shallow-copy function for objects */
|
||||
void* object_shallow_copy( void* orig, size_t size ) {
|
||||
void* out = malloc( size );
|
||||
if ( out != NULL ) memcpy( out, orig, size );
|
||||
return out;
|
||||
/* Special strdup. This is used for string arrays, since the strings can be
|
||||
* variable length. strdup takes one argument, so we make a wrapper to ignore
|
||||
* the object size (which should be zero).
|
||||
*/
|
||||
void* va_strdup( void* orig, size_t size ) {
|
||||
return (void*)strdup( (char*)orig );
|
||||
}
|
||||
|
||||
/* Create a new vararray
|
||||
@ -42,11 +44,16 @@ struct vararray* create_vararray( struct vararray* dest, size_t obj_size,
|
||||
dest->head = NULL;
|
||||
dest->tail = NULL;
|
||||
if ( copy_func == NULL )
|
||||
dest->copy_func = &object_shallow_copy;
|
||||
if ( obj_size > 0 ) /* Object container */
|
||||
dest->copy_func = &memdup; /* see util.h
|
||||
* and util.c
|
||||
*/
|
||||
else
|
||||
dest->copy_func = &va_strdup;
|
||||
else
|
||||
dest->copy_func = copy_func;
|
||||
if ( destroy_func == NULL )
|
||||
dest->destroy_func = &free;
|
||||
dest->destroy_func = &free; /* standard C library */
|
||||
else
|
||||
dest->destroy_func = destroy_func;
|
||||
}
|
||||
@ -82,6 +89,61 @@ void destroy_vararray( struct vararray* dest ) {
|
||||
dprintf("destroy_vararray: array at %p and all contents freed\n", dest);
|
||||
}
|
||||
|
||||
/* Copy a vararray
|
||||
*
|
||||
* This does a deep copy of the entire contents in the array.
|
||||
*
|
||||
* Returns the copy on success, or NULL on failure
|
||||
*/
|
||||
struct vararray* copy_vararray( struct vararray* src ) {
|
||||
if ( src == NULL ) return NULL;
|
||||
|
||||
/* Start by doing a shallow copy of the struct. */
|
||||
struct vararray* dest = (struct vararray*)
|
||||
memdup( (void*)src, sizeof( struct vararray ) );
|
||||
if ( dest == NULL ) return NULL;
|
||||
|
||||
/* Unlink the original chain from the copy */
|
||||
dest->head = NULL;
|
||||
dest->tail = NULL;
|
||||
|
||||
/* Okay, now start at the head, and duplicate each node. */
|
||||
struct vararray_node* s_node = src->head;
|
||||
struct vararray_node* d_node = dest->head;
|
||||
while( s_node != NULL ) {
|
||||
/* Copy the node */
|
||||
struct vararray_node* copy = (struct vararray_node*)
|
||||
memdup((void*)s_node, sizeof( struct vararray_node ));
|
||||
if ( copy == NULL ) {
|
||||
/* Node copy failed */
|
||||
destroy_vararray( dest );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copy the node contents if needed */
|
||||
if ( copy->using_ptr )
|
||||
copy->data.as_ptr = (*src->copy_func)
|
||||
(copy->data.as_ptr, src->data_size);
|
||||
|
||||
/* Link it in */
|
||||
copy->prev = d_node;
|
||||
if ( d_node == NULL )
|
||||
dest->head = copy;
|
||||
else
|
||||
d_node->next = copy;
|
||||
|
||||
/* Move on */
|
||||
s_node = s_node->next;
|
||||
d_node = copy;
|
||||
}
|
||||
|
||||
/* Now at the end of the chain... we can link the tail */
|
||||
dest->tail = d_node;
|
||||
|
||||
/* Linking should be complete... return the new array */
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Helper function: Locate a node by index. 'end' specifies from which
|
||||
* end to begin the count, zero for the start (head), non-sero for
|
||||
* the end (tail).
|
||||
@ -538,6 +600,7 @@ struct static_obj_array* export_obj_array( struct vararray* va ) {
|
||||
sa->length = va->length;
|
||||
sa->copy_func = va->copy_func;
|
||||
sa->destroy_func = va->destroy_func;
|
||||
sa->obj_size = va->data_size;
|
||||
|
||||
struct vararray_node* node = va->head;
|
||||
void** destptr = sa->object;
|
||||
@ -567,6 +630,7 @@ struct static_string_array* export_string_array( struct vararray* va ) {
|
||||
sa->length = va->length;
|
||||
sa->copy_func = va->copy_func;
|
||||
sa->destroy_func = va->destroy_func;
|
||||
sa->obj_size = 0;
|
||||
|
||||
struct vararray_node* node = va->head;
|
||||
size_t index = 0;
|
||||
@ -639,3 +703,60 @@ void destroy_array( void* container, size_t length,
|
||||
free( elements );
|
||||
}
|
||||
}
|
||||
|
||||
/* Duplicate a static array. The following will make a deep copy of any
|
||||
* statically-allocated array in one of the above structs.
|
||||
*
|
||||
* Returns the copy on success, NULL on failure.
|
||||
*/
|
||||
struct static_simple_array* duplicate_simple_array_impl(
|
||||
struct static_simple_array* src, size_t data_size ) {
|
||||
if ( src == NULL ) return NULL;
|
||||
|
||||
/* Duplicate the array container */
|
||||
struct static_simple_array* copy = (struct static_simple_array*)
|
||||
memdup( (void*)src, sizeof( struct static_simple_array ) );
|
||||
if ( copy == NULL ) return NULL;
|
||||
|
||||
/* Now, duplicate the data */
|
||||
copy->value = memdup( src->value, data_size*src->length );
|
||||
if ( copy->value == NULL ) {
|
||||
free( copy );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
struct static_obj_array* duplicate_obj_array_impl(
|
||||
struct static_obj_array* src ) {
|
||||
|
||||
if ( src == NULL ) return NULL;
|
||||
|
||||
/* Duplicate the array container */
|
||||
struct static_obj_array* copy = (struct static_obj_array*)
|
||||
memdup( (void*)src, sizeof( struct static_obj_array ) );
|
||||
if ( copy == NULL ) return NULL;
|
||||
|
||||
/* Allocate the array itself */
|
||||
copy->object = (void**)calloc( src->length, sizeof(void*) );
|
||||
if ( copy->object == NULL ) {
|
||||
free( copy );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now, duplicate the data */
|
||||
size_t i;
|
||||
for( i=0; i<src->length; i++) {
|
||||
copy->object[i] = (*src->copy_func)( src->object[i],
|
||||
src->obj_size );
|
||||
if ( copy->object[i] == NULL ) {
|
||||
copy->length = i;
|
||||
destroy_obj_array( copy, object );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user