/* -*- mode: c; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /********************************************************************* * Clustal Omega - Multiple sequence alignment * * Copyright (C) 2010 University College Dublin * * Clustal-Omega is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This file is part of Clustal-Omega. * ********************************************************************/ /* * RCS $Id: util.c 235 2011-04-13 14:13:19Z andreas $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "log.h" #include "util.h" /* struct for QSortAndTrackIndex and SortAndTrackIndexCmp[Asc|Desc] */ typedef struct { int piIndex; int piValue; } sortwithindex_t; /** * @brief Copy of squid's FileExists(). Copied here to make squid independent. */ int CheckIfFileExists(char *pcFilename) { FILE *prFile; if ((prFile = fopen(pcFilename, "r"))) { fclose(prFile); return TRUE; } return FALSE; } /* end of CheckIfFileExists */ /** * @brief Allocates memory (malloc) * * @param[in] bytes * bytes to allocated * @param[in] function * calling function name * @param[in] line * calling function line * * @return void pointer to the newly allocated memory * * @note use provided macro CKMALLOC() which automatically adds * function name and line number * */ void * CkMalloc(size_t bytes, const char *function, const int line) { void *ret; if(NULL == (ret = malloc(bytes * sizeof(char)))) { Log(&rLog, LOG_FATAL, "Out of memory (requested from %s:%d)\n", function, line); } return ret; } /*** end: ckmalloc ***/ /** * @brief Allocates memory (calloc). Memory will be * set to zero. * * @param[in] count * Allocate space for count objects * @param[in] size * Objects are of this size * @param[in] function * calling function name * @param[in] line * calling function line * * @return void pointer to the newly allocated and zeroed memory (calloc). * * @note use provided macro CKCALLOC() which automatically adds * function name and line number * * */ void * CkCalloc(size_t count, size_t size, const char *function, const int line) { void *ret; if(NULL == (ret = calloc(count, size))) { Log(&rLog, LOG_FATAL, "Out of memory (requested from %s:%d)\n", function, line); exit(EXIT_FAILURE); } return ret; } /*** end: CkCalloc ***/ /** * @brief Reallocates memory * * @param[in] ptr * Pointer to memory to be reallocated * @param[in] bytes * bytes to allocated * @param[in] function * calling function name * @param[in] line * calling function line * * @return void pointer to the newly allocated memory * * @note use provided macro CKREALLOC() which automatically adds * function name and line number * */ void * CkRealloc(void *ptr, size_t bytes, const char *function, const int line) { void *ret=NULL; if(NULL == (ret = realloc(ptr, bytes))) { Log(&rLog, LOG_FATAL, "FATAL: Out of memory (requested from %s:%d)\n", function, line); } return ret; } /*** end: ckrealloc ***/ /** * * @brief Frees memory * * @param[in] ptr * Pointer to memory to be freed * @param[in] function * calling function name * @param[in] line * calling function line * * @return void pointer to the now zeroed memory * * @note use provided macro CKFREE() * */ void * CkFree(void *ptr, const char *function, const int line) { if (ptr == NULL) { Log(&rLog, LOG_WARN, "Bad call to CkFree from %s:%d (pointer was NULL)\n", function, line); } else { free(ptr); ptr = NULL; } return ptr; } /*** end: CkFree ***/ /** * @brief safe version of strdup * * @param[in] src * String to copy from * * @return copy of string * * @note src is not allowed to be NULL. * */ char * CkStrdup(const char *src) { char *cp; assert(NULL!=src); /*cp = strdup(src); always makes trouble... */ cp = (char *) CKMALLOC(strlen(src) +1); strcpy(cp, src); return cp; } /*** end: CkStrdup ***/ /** * @brief Creates an int array of size len with len-1 random but unique * integers with values 0--len-1. This is "a modified version of * Fisher-Yates known as Durstenfeld-Fisher-Yates or * Knuth-Fisher-Yates". See * http://stackoverflow.com/questions/196017/unique-random-numbers-in-o1 * * @param[in] perm * The permutation array. Has to be preallocated * @param[out] len * Length of the permutation array * */ void PermutationArray(int **perm, const int len) { int max, i; assert(len>0); srand((unsigned int) time(0)); (*perm) = (int *) CKMALLOC(len * sizeof(int)); max = len-1; for (i=0; i=0) { int tmp, randno; /* randno = addrand((unsigned long) len); / returns 0--n-1 */ randno = (rand()%len); /* swap */ tmp = (*perm)[randno]; (*perm)[randno] = (*perm)[max]; (*perm)[max] = tmp; max--; } return; } /*** end: PermutationArray() ***/ /** * @brief Creates an array filled with random, but unique ints of * given range. Implementation of the Floyd algorithm. See * http://stackoverflow.com/questions/1608181/unique-random-numbers-in-an-integer-array-in-the-c-programming-language * Assuming M is the length of the desired array and N is the numeric * range: "This approach has the complexity of about O(M) (depends on * the search structure used), so it is better suitable when M << N. * This approach keeps track of already generated random numbers, so * it requires extra memory. However, the beauty of it is that it does * not make any of those horrendous "trial and error" iterations, * trying to find an unused random number. This algorithm is * guaranteed to generate one unique random number after each single * call to the random number generator." * * @warning This won't work if max_value<=array_len. Only use for * cases where array_len<piValue; const int ib = (const int) b_t->piValue; return ia - ib; } /*** end: SortAndTrackIndexCmpAsc ***/ /** * @brief Compare two sortwithindex_t pointers and return the * difference between the int value of the 2nd sortwithindex_t and the * 1st. Used for descending sort order in QSortWithIndexes() * * @see SortAndTrackIndexCmpDesc() and QSortAndTrackIndex() */ int SortAndTrackIndexCmpDesc(const void *a, const void *b) { const sortwithindex_t *a_t = (const sortwithindex_t *)a; const sortwithindex_t *b_t = (const sortwithindex_t *)b; const int ia = (const int) a_t->piValue; const int ib = (const int) b_t->piValue; return ib - ia; } /*** end: SortAndTrackIndexCmpDesc ***/ /** * @brief Sort a given int array in ascending or descending order, * while keeping track of the element order. * * @param[out] piSortedIndices * Will contain the indices of the sorted elements. Has to be preallocated. * @param[out] piArrayToSort * Array with values to sort. Will only be overwritten if * bOverwriteArrayToSort it true. * @param[in] iArrayLen * Number of elements in piArrayToSort. * @param[in] cOrder * Sort order. 'a' for ascending, 'd' for descending. * @param[in] bOverwriteArrayToSort * If false do not overwrite the array to sort. * */ void QSortAndTrackIndex(int *piSortedIndices, int *piArrayToSort, const int iArrayLen, const char cOrder, const bool bOverwriteArrayToSort) { int iCtr; /**< aux */ sortwithindex_t *prSort; assert(NULL!=piSortedIndices); assert(iArrayLen>0); assert(NULL!=piArrayToSort); assert('a'==cOrder || 'd'==cOrder); prSort = (sortwithindex_t *) CKMALLOC(iArrayLen * sizeof(sortwithindex_t)); for (iCtr=0; iCtr