packages feed

ViennaRNA-bindings-0.233.1.1: C/ViennaRNA/string_utils.c

/*
                               string_utils.c

                 c  Ivo L Hofacker and Walter Fontana
                          Vienna RNA package
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdarg.h>

#include "ViennaRNA/utils.h"
#include "ViennaRNA/string_utils.h"

/*
#################################
# PRIVATE FUNCTION DECLARATIONS #
#################################
*/

/*
#################################
# BEGIN OF FUNCTION DEFINITIONS #
#################################
*/

#ifndef HAVE_STRDUP
char *strdup(const char *s) {
  char *dup;

  dup = vrna_alloc(strlen(s)+1);
  strcpy(dup, s);
  return(dup);
}
#endif

PUBLIC char *
vrna_strdup_printf(const char *format, ...){

  char *result;
  va_list argp;

  va_start(argp, format);
  result = vrna_strdup_vprintf(format, argp);
  va_end(argp); /* Each va_start() or va_copy() needs a va_end() */

  return result;
}

PUBLIC char *
vrna_strdup_vprintf(const char *format, va_list argp){

  char    *result;
  int     r;

  result  = NULL;

#ifndef HAVE_VASPRINTF
  int     count;
  va_list copy;
  va_copy(copy, argp);

  r = -1;

  /* retrieve the number of characters that the string requires */
#ifdef _WIN32
  /*
    vsnprintf() in Windows is not ANSI compliant, although it's
    "...included for compliance to the ANSI standard"
    Thus, we use _vscprintf() that explicitly counts characters
  */
  count = _vscprintf(format, argp);
#else
  count = vsnprintf(NULL, 0, format, argp);
#endif

  if((count >= 0) && (count < INT_MAX)){
    char *buf = (char *)vrna_alloc(sizeof(char) * (count + 1));
    if(buf == NULL)
      r = -1;
    else if((r = vsnprintf(buf, count + 1, format, copy)) < 0)
      free(buf);
    else
      result = buf;
  }

  va_end(copy);  /* Each va_start() or va_copy() needs a va_end() */
#else
  /* the default is to use vasprintf() if available */
  r = vasprintf(&result, format, argp);
#endif

  /* check for any memory allocation error indicated by r == -1 */
  if(r == -1){
    vrna_message_warning("vrna_strdup_printf: memory allocation failure!");
    result = NULL;
  }

  return result;
}


PUBLIC int
vrna_strcat_printf(char **dest, const char *format, ...){

  int r;
  va_list argp;

  va_start(argp, format);
  r = vrna_strcat_vprintf(dest, format, argp);
  va_end(argp); /* Each va_start() or va_copy() needs a va_end() */

  return r;
}


PUBLIC int
vrna_strcat_vprintf(char **dest, const char *format, va_list args){

  char    *buf;
  int     r, l1, l2;
  size_t  old_count, new_count;

  if((!dest) || (!format))
    return -1;

  va_list copy;
  va_copy(copy, args);

  r         = -1;
  buf       = *dest;
  old_count = (buf) ? strlen(buf) : 0;

  /* retrieve the number of characters that the string requires */
#ifdef _WIN32
  /*
    vsnprintf() in Windows is not ANSI compliant, although it's
    "...included for compliance to the ANSI standard"
    Thus, we use _vscprintf() that explicitly counts characters
  */
  new_count = _vscprintf(format, args);
#else
  new_count = vsnprintf(NULL, 0, format, args);
#endif

  /* determine longer and shorter part of new string for INT overflow protection */
  if(old_count > new_count){
    l1 = old_count;
    l2 = new_count;
  } else {
    l1 = new_count;
    l2 = old_count;
  }

  if((new_count > 0) && (l1 < SIZE_MAX) && ((SIZE_MAX - l1) > l2)){
    buf = (char *)vrna_realloc(buf, sizeof(char) * (old_count + new_count + 1));
    if(buf == NULL)
      r = -1;
    else if((r = vsnprintf(buf + old_count, new_count + 1, format, copy)) < 0)
      free(buf);
    else {
      *dest = buf;
      r = old_count + new_count;
    }
  } else if(new_count == 0){
    /* we do not treat empty format string as error */
    r = (int)old_count;
  }

  va_end(copy);  /* Each va_start() or va_copy() needs a va_end() */

  /* check for any memory allocation error indicated by r == -1 */
  if(r == -1){
    vrna_message_warning("vrna_strcat_printf: memory allocation failure!");
    *dest = NULL;
  }

  return r;
}


PUBLIC char *
vrna_random_string(int l, const char symbols[]){

  char *r;
  int   i, rn, base;

  base = (int) strlen(symbols);
  r = (char *) vrna_alloc(sizeof(char)*(l+1));

  for (i = 0; i < l; i++) {
    rn = (int) (vrna_urn()*base);  /* [0, base-1] */
    r[i] = symbols[rn];
  }
  r[l] = '\0';
  return r;
}

/*-----------------------------------------------------------------*/

PUBLIC int
vrna_hamming_distance(const char *s1,
                      const char *s2){

  int h=0;

  for (; *s1 && *s2; s1++, s2++)
    if (*s1 != *s2) h++;
  return h;
}

PUBLIC int
vrna_hamming_distance_bound(const char *s1,
                            const char *s2,
                            int boundary){

  int h=0;

  for (; *s1 && *s2 && boundary; s1++, s2++, boundary--)
    if (*s1 != *s2) h++;
  return h;
}

PUBLIC  void
vrna_seq_toRNA(char *sequence){

  unsigned int i;
  if(sequence){
    for(i = 0; sequence[i]; i++){
      if(sequence[i] == 'T') sequence[i] = 'U';
      if(sequence[i] == 't') sequence[i] = 'u';
    }
  }
}

PUBLIC void
vrna_seq_toupper(char *sequence){

  unsigned int i;
  if(sequence){
    for(i=0;sequence[i];i++)
      sequence[i] = toupper(sequence[i]);
  }
}

PUBLIC char *
vrna_cut_point_insert(const char *string,
                      int cp){

  char *ctmp;
  int len;

  if(cp > 0){
    len = strlen(string);
    ctmp = (char *)vrna_alloc((len+2) * sizeof(char));
    /* first sequence */
    (void) strncpy(ctmp, string, cp-1);
    /* spacer */
    ctmp[cp-1] = '&';
    /* second sequence */
    (void) strcat(ctmp, string+cp-1);
  } else {
    ctmp = strdup(string);
  }
  return ctmp;
}

PUBLIC char *
vrna_cut_point_remove(const char *string,
                      int *cp){

  char *pos, *copy = NULL;

  *cp = -1;

  if(string){
    copy = (char *) vrna_alloc(strlen(string)+1);
    (void) sscanf(string, "%s", copy);
    pos = strchr(copy, '&');
    if (pos) {
      *cp = (int)(pos - copy) + 1;
      if (*cp >= strlen(copy)) *cp = -1;
      if (strchr(pos+1, '&')) vrna_message_error("more than one cut-point in input");
      for (;*pos;pos++) *pos = *(pos+1); /* splice out the & */
    }
  }

  return copy;
}

#ifdef  VRNA_BACKWARD_COMPAT

/*###########################################*/
/*# deprecated functions below              #*/
/*###########################################*/

PUBLIC void
str_uppercase(char *sequence){

  vrna_seq_toupper(sequence);
}

PUBLIC void
str_DNA2RNA(char *sequence){

  vrna_seq_toRNA(sequence);
}

PUBLIC char *
random_string(int l, const char symbols[]){

  return vrna_random_string(l, symbols);
}

PUBLIC int
hamming(const char *s1,
        const char *s2){

  return vrna_hamming_distance(s1, s2);
}

PUBLIC int
hamming_bound(const char *s1,
              const char *s2,
              int boundary){

  return vrna_hamming_distance_bound(s1, s2, boundary);
}

#endif