#ifndef _UTIL_H #define _UTIL_H #include #include #include /* Various utility functions for the gallery */ /* Memory management functions. * * These wrappers around malloc/calloc, realloc and free internally * monitor the usage of memory chunks. It keeps track of all allocated * pointers, allowing for garbage collection to occur at the end when * all pointers should be unused. * * For performance, these can be disabled at compile time. Their prime focus is * for development... to track where allocations are being made. It shouldn't * be necessary in production -- if it is, there's a memory leakage bug. */ #ifdef MEMALLOC_TRACK /* Memory allocation tracking enabled */ void* gcmalloc( size_t size ); void* gccalloc( size_t nmemb, size_t size ); void* gcrealloc( void* ptr, size_t size ); void gcfree( void* ptr ); void gcfreeall(); char* gcstrdup( const char* str ); char* gcreport(); /* The pointers are tracked in this linked list */ struct mem_chunk { void* ptr; size_t size; struct mem_chunk* prev; struct mem_chunk* next; }; static struct mem_chunk* gc_head = NULL; static struct mem_chunk* gc_tail = NULL; static size_t gc_count = 0; #else /* Memory allocation tracking disabled */ #define gcmalloc( size ) malloc( size ) #define gccalloc( size, num ) calloc( size, num ) #define gcrealloc( ptr, size ) realloc( ptr, size ) #define gcfree( ptr ) free( ptr ) #define gcstrdup( size ) strdup( size ) #endif /* Sanitise a given name. Names may only contain alpha-numeric * characters, hyphens, underscores and full stop characters. * * This function sanitises in-place, invalid characters get replaced with * underscores. */ void sanitise_name( char* name ); /* Cross-compatibility hack */ #ifndef PATHSEP # ifdef WIN32 # define PATHSEP "\\" # else # define PATHSEP "/" # endif #endif /* Concatenate one string onto the end of the other. * * This function does a realloc of the first string to make room for the second, * returning the pointer to the concatenated string. * * This is different to strcat, which does not re-allocate memory or make room * in any way. */ char* str_concat( char* dest, const char* src ); /* Like above, but add a single character */ char* str_concatc( char* dest, const char c ); /* Construct a path from given directory names. * fmt is a list of types and sizes interpreted as follows: * s Insert a string at this point. * i Insert a signed integer at this point. * u Insert an unsigned integer at this point. * x Insert a hexadecimal integer at this point * o Insert an octal integer at this point * f Insert a floating-point/double at this point. * / Insert the path separator string at this point. * \ Insert the next character verbatim * * Whitespace is ignored, so you can add spaces for readability. Digits * are interpreted as the width of the field in characters. Anything else * is passed through verbatim. * * Whitespace can be passed through by escaping it however. * * For float/double fields, a decimal point followed by digits indicates * the number of decimal digits to include. * * Example: * "s/s ? s=6.2f & s=u & s=u" might yield * "humour/funnypic.jpg?rotation=000.00&width=600&height=400" */ char* construct_path( const char* format, ...); /* construct_path field widths are limited to the following number of * characters... */ #define CONSTRUCT_PATH_FIELD_WIDTH 64 /* Obtain the CGI filesystem directory */ const char* get_cgidir(); /* Obtain the CGI directory URI */ const char* get_cgiuri(); /* Local versions of dirname and basename. These allocate and return copies of * the strings passed to them. */ char* get_basename( const char* path ); char* get_dirname( const char* path ); /* Substitute the extension on a filename. * * This function does a string substitution on the filename given to it, and * returns it. Returns NULL if it can't allocate a buffer. */ char* substitute_ext( const char* filename, const char* new_ext ); /* Parse a text file. The text files in this system have the format: * "\t\n" * * Multiple lines with the same variable are concatenated together. * * The content of these files is stored in a chained struct like the one below. */ struct txtinfo_chain { char* field_name; char* field_val; struct txtinfo_chain* next; }; /* Create a txtinfo_chain object */ struct txtinfo_chain* create_txtinfo_chain( const char* name, const char* val ); /* Destroy a txtinfo_chain object. This destroys all linked objects! */ void destroy_txtinfo_chain( struct txtinfo_chain* chain ); /* Locate a field in a field chain. Return NULL if it isn't present. */ struct txtinfo_chain* find_txtinfo_chain( struct txtinfo_chain* chain, const char* name ); /* Return the value for a given field name. This returns a copy of the string. */ char* get_txtinfo_chain_val( struct txtinfo_chain* chain, const char *name ); /* Read a file into a txtinfo_chain object. Returns NULL on failure. */ 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( void** array, size_t length, int (*compare)( const void*, const void* ) ); #endif