Path: blob/devel/elmergrid/src/metis-5.1.0/GKlib/string.c
3206 views
/************************************************************************/1/*! \file23\brief Functions for manipulating strings.45Various functions for manipulating strings. Some of these functions6provide new functionality, whereas others are drop-in replacements7of standard functions (but with enhanced functionality).89\date Started 11/1/9910\author George11\version $Id: string.c 10711 2011-08-31 22:23:04Z karypis $12*/13/************************************************************************/1415#include <GKlib.h>16171819/************************************************************************/20/*! \brief Replaces certain characters in a string.2122This function takes a string and replaces all the characters in the23\c fromlist with the corresponding characters from the \c tolist.24That is, each occurence of <tt>fromlist[i]</tt> is replaced by25<tt>tolist[i]</tt>.26If the \c tolist is shorter than \c fromlist, then the corresponding27characters are deleted. The modifications on \c str are done in place.28It tries to provide a functionality similar to Perl's \b tr// function.2930\param str is the string whose characters will be replaced.31\param fromlist is the set of characters to be replaced.32\param tolist is the set of replacement characters .33\returns A pointer to \c str itself.34*/35/************************************************************************/36char *gk_strchr_replace(char *str, char *fromlist, char *tolist)37{38gk_idx_t i, j, k;39size_t len, fromlen, tolen;4041len = strlen(str);42fromlen = strlen(fromlist);43tolen = strlen(tolist);4445for (i=j=0; i<len; i++) {46for (k=0; k<fromlen; k++) {47if (str[i] == fromlist[k]) {48if (k < tolen)49str[j++] = tolist[k];50break;51}52}53if (k == fromlen)54str[j++] = str[i];55}56str[j] = '\0';5758return str;59}60616263/************************************************************************/64/*! \brief Regex-based search-and-replace function6566This function is a C implementation of Perl's <tt> s//</tt> regular-expression67based substitution function.6869\param str70is the input string on which the operation will be performed.71\param pattern72is the regular expression for the pattern to be matched for substitution.73\param replacement74is the replacement string, in which the possible captured pattern substrings75are referred to as $1, $2, ..., $9. The entire matched pattern is refered76to as $0.77\param options78is a string specified options for the substitution operation. Currently the79<tt>"i"</tt> (case insensitive) and <tt>"g"</tt> (global substitution) are80supported.81\param new_str82is a reference to a pointer that will store a pointer to the newly created83string that results from the substitutions. This string is allocated via84gk_malloc() and needs to be freed using gk_free(). The string is returned85even if no substitutions were performed.86\returns87If successful, it returns 1 + the number of substitutions that were performed.88Thus, if no substitutions were performed, the returned value will be 1.89Otherwise it returns 0. In case of error, a meaningful error message is90returned in <tt>newstr</tt>, which also needs to be freed afterwards.91*/92/************************************************************************/93int gk_strstr_replace(char *str, char *pattern, char *replacement, char *options,94char **new_str)95{96gk_idx_t i;97int j, rc, flags, global, nmatches;98size_t len, rlen, nlen, offset, noffset;99regex_t re;100regmatch_t matches[10];101102103/* Parse the options */104flags = REG_EXTENDED;105if (strchr(options, 'i') != NULL)106flags = flags | REG_ICASE;107global = (strchr(options, 'g') != NULL ? 1 : 0);108109110/* Compile the regex */111if ((rc = regcomp(&re, pattern, flags)) != 0) {112len = regerror(rc, &re, NULL, 0);113*new_str = gk_cmalloc(len, "gk_strstr_replace: new_str");114regerror(rc, &re, *new_str, len);115return 0;116}117118/* Prepare the output string */119len = strlen(str);120nlen = 2*len;121noffset = 0;122*new_str = gk_cmalloc(nlen+1, "gk_strstr_replace: new_str");123124125/* Get into the matching-replacing loop */126rlen = strlen(replacement);127offset = 0;128nmatches = 0;129do {130rc = regexec(&re, str+offset, 10, matches, 0);131132if (rc == REG_ESPACE) {133gk_free((void **)new_str, LTERM);134*new_str = gk_strdup("regexec ran out of memory.");135regfree(&re);136return 0;137}138else if (rc == REG_NOMATCH) {139if (nlen-noffset < len-offset) {140nlen += (len-offset) - (nlen-noffset);141*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");142}143strcpy(*new_str+noffset, str+offset);144noffset += (len-offset);145break;146}147else { /* A match was found! */148nmatches++;149150/* Copy the left unmatched portion of the string */151if (matches[0].rm_so > 0) {152if (nlen-noffset < matches[0].rm_so) {153nlen += matches[0].rm_so - (nlen-noffset);154*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");155}156strncpy(*new_str+noffset, str+offset, matches[0].rm_so);157noffset += matches[0].rm_so;158}159160/* Go and append the replacement string */161for (i=0; i<rlen; i++) {162switch (replacement[i]) {163case '\\':164if (i+1 < rlen) {165if (nlen-noffset < 1) {166nlen += nlen + 1;167*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");168}169*new_str[noffset++] = replacement[++i];170}171else {172gk_free((void **)new_str, LTERM);173*new_str = gk_strdup("Error in replacement string. Missing character following '\'.");174regfree(&re);175return 0;176}177break;178179case '$':180if (i+1 < rlen) {181j = (int)(replacement[++i] - '0');182if (j < 0 || j > 9) {183gk_free((void **)new_str, LTERM);184*new_str = gk_strdup("Error in captured subexpression specification.");185regfree(&re);186return 0;187}188189if (nlen-noffset < matches[j].rm_eo-matches[j].rm_so) {190nlen += nlen + (matches[j].rm_eo-matches[j].rm_so);191*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");192}193194strncpy(*new_str+noffset, str+offset+matches[j].rm_so, matches[j].rm_eo);195noffset += matches[j].rm_eo-matches[j].rm_so;196}197else {198gk_free((void **)new_str, LTERM);199*new_str = gk_strdup("Error in replacement string. Missing subexpression number folloing '$'.");200regfree(&re);201return 0;202}203break;204205default:206if (nlen-noffset < 1) {207nlen += nlen + 1;208*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");209}210(*new_str)[noffset++] = replacement[i];211}212}213214/* Update the offset of str for the next match */215offset += matches[0].rm_eo;216217if (!global) {218/* Copy the right portion of the string if no 'g' option */219if (nlen-noffset < len-offset) {220nlen += (len-offset) - (nlen-noffset);221*new_str = (char *)gk_realloc(*new_str, (nlen+1)*sizeof(char), "gk_strstr_replace: new_str");222}223strcpy(*new_str+noffset, str+offset);224noffset += (len-offset);225}226}227} while (global);228229(*new_str)[noffset] = '\0';230231regfree(&re);232return nmatches + 1;233234}235236237238/************************************************************************/239/*! \brief Prunes characters from the end of the string.240241This function removes any trailing characters that are included in the242\c rmlist. The trimming stops at the last character (i.e., first character243from the end) that is not in \c rmlist.244This function can be used to removed trailing spaces, newlines, etc.245This is a distructive operation as it modifies the string.246247\param str is the string that will be trimmed.248\param rmlist contains the set of characters that will be removed.249\returns A pointer to \c str itself.250\sa gk_strhprune()251*/252/*************************************************************************/253char *gk_strtprune(char *str, char *rmlist)254{255gk_idx_t i, j;256size_t len;257258len = strlen(rmlist);259260for (i=strlen(str)-1; i>=0; i--) {261for (j=0; j<len; j++) {262if (str[i] == rmlist[j])263break;264}265if (j == len)266break;267}268269str[i+1] = '\0';270271return str;272}273274275/************************************************************************/276/*! \brief Prunes characters from the beginning of the string.277278This function removes any starting characters that are included in the279\c rmlist. The trimming stops at the first character that is not in280\c rmlist.281This function can be used to removed leading spaces, tabs, etc.282This is a distructive operation as it modifies the string.283284\param str is the string that will be trimmed.285\param rmlist contains the set of characters that will be removed.286\returns A pointer to \c str itself.287\sa gk_strtprune()288*/289/*************************************************************************/290char *gk_strhprune(char *str, char *rmlist)291{292gk_idx_t i, j;293size_t len;294295len = strlen(rmlist);296297for (i=0; str[i]; i++) {298for (j=0; j<len; j++) {299if (str[i] == rmlist[j])300break;301}302if (j == len)303break;304}305306if (i>0) { /* If something needs to be removed */307for (j=0; str[i]; i++, j++)308str[j] = str[i];309str[j] = '\0';310}311312return str;313}314315316/************************************************************************/317/*! \brief Converts a string to upper case.318319This function converts a string to upper case. This operation modifies the320string itself.321322\param str is the string whose case will be changed.323\returns A pointer to \c str itself.324\sa gk_strtolower()325*/326/*************************************************************************/327char *gk_strtoupper(char *str)328{329int i;330331for (i=0; str[i]!='\0'; str[i]=toupper(str[i]), i++);332return str;333}334335336/************************************************************************/337/*! \brief Converts a string to lower case.338339This function converts a string to lower case. This operation modifies the340string itself.341342\param str is the string whose case will be changed.343\returns A pointer to \c str itself.344\sa gk_strtoupper()345*/346/*************************************************************************/347char *gk_strtolower(char *str)348{349int i;350351for (i=0; str[i]!='\0'; str[i]=tolower(str[i]), i++);352return str;353}354355356/************************************************************************/357/*! \brief Duplicates a string358359This function is a replacement for C's standard <em>strdup()</em> function.360The key differences between the two are that gk_strdup():361- uses the dynamic memory allocation routines of \e GKlib.362- it correctly handles NULL input strings.363364The string that is returned must be freed by gk_free().365366\param orgstr is the string that will be duplicated.367\returns A pointer to the newly created string.368\sa gk_free()369*/370/*************************************************************************/371char *gk_strdup(char *orgstr)372{373int len;374char *str=NULL;375376if (orgstr != NULL) {377len = strlen(orgstr)+1;378str = gk_malloc(len*sizeof(char), "gk_strdup: str");379strcpy(str, orgstr);380}381382return str;383}384385386/************************************************************************/387/*! \brief Case insensitive string comparison.388389This function compares two strings for equality by ignoring the case of the390strings.391392\warning This function is \b not equivalent to a case-insensitive393<em>strcmp()</em> function, as it does not return ordering394information.395396\todo Remove the above warning.397398\param s1 is the first string to be compared.399\param s2 is the second string to be compared.400\retval 1 if the strings are identical,401\retval 0 otherwise.402*/403/*************************************************************************/404int gk_strcasecmp(char *s1, char *s2)405{406int i=0;407408if (strlen(s1) != strlen(s2))409return 0;410411while (s1[i] != '\0') {412if (tolower(s1[i]) != tolower(s2[i]))413return 0;414i++;415}416417return 1;418}419420421/************************************************************************/422/*! \brief Compare two strings in revere order423424This function is similar to strcmp but it performs the comparison as425if the two strings were reversed.426427\param s1 is the first string to be compared.428\param s2 is the second string to be compared.429\retval -1, 0, 1, if the s1 < s2, s1 == s2, or s1 > s2.430*/431/*************************************************************************/432int gk_strrcmp(char *s1, char *s2)433{434int i1 = strlen(s1)-1;435int i2 = strlen(s2)-1;436437while ((i1 >= 0) && (i2 >= 0)) {438if (s1[i1] != s2[i2])439return (s1[i1] - s2[i2]);440i1--;441i2--;442}443444/* i1 == -1 and/or i2 == -1 */445446if (i1 < i2)447return -1;448if (i1 > i2)449return 1;450return 0;451}452453454455/************************************************************************/456/*! \brief Converts a time_t time into a string457458This function takes a time_t-specified time and returns a string-formated459representation of the corresponding time. The format of the string is460<em>mm/dd/yyyy hh:mm:ss</em>, in which the hours are in military time.461462\param time is the time to be converted.463\return It returns a pointer to a statically allocated string that is464over-written in successive calls of this function. If the465conversion failed, it returns NULL.466467*/468/*************************************************************************/469char *gk_time2str(time_t time)470{471static char datestr[128];472struct tm *tm;473474tm = localtime(&time);475476if (strftime(datestr, 128, "%m/%d/%Y %H:%M:%S", tm) == 0)477return NULL;478else479return datestr;480}481482483484#if !defined(WIN32) && !defined(__MINGW32__)485/************************************************************************/486/*! \brief Converts a date/time string into its equivalent time_t value487488This function takes date and/or time specification and converts it in489the equivalent time_t representation. The conversion is done using the490strptime() function. The format that gk_str2time() understands is491<em>mm/dd/yyyy hh:mm:ss</em>, in which the hours are in military time.492493\param str is the date/time string to be converted.494\return If the conversion was successful it returns the time, otherwise495it returns -1.496*/497/*************************************************************************/498time_t gk_str2time(char *str)499{500struct tm time;501time_t rtime;502503memset(&time, '\0', sizeof(time));504505if (strptime(str, "%m/%d/%Y %H:%M:%S", &time) == NULL)506return -1;507508rtime = mktime(&time);509return (rtime < 0 ? 0 : rtime);510}511#endif512513514/*************************************************************************515* This function returns the ID of a particular string based on the516* supplied StringMap array517**************************************************************************/518int gk_GetStringID(gk_StringMap_t *strmap, char *key)519{520int i;521522for (i=0; strmap[i].name; i++) {523if (gk_strcasecmp(key, strmap[i].name))524return strmap[i].id;525}526527return -1;528}529530531