#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/times.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>


#define MAXSTR 10000
#define MAXFF 50

#include "strsubs.h" 
#include "vsubs.h" 

extern int errno ;


int oldsplitup(char *strin, char**spt, int maxpt) 
/**
 retained in case there are compatibility problems 
*/
{
 char *s1, *s2, *sx ;
 char *str ;
 int i, len, num ;

 len = strlen(strin) ;
 if (len==0) return 0 ;  
 ZALLOC(str, 2*len, char) ; 
 num = 0 ; 
 sx = strin ;
 for (i=0; i<maxpt; i++)  {
  s1 = fnwhite(sx) ;
  if (s1==NULL) { 
   break ;
  }
  s2 = fwhite(s1) ;
  if (s2==NULL) {
   s2 = s1+strlen(s1) ;
  }
  s2-- ;  /* now points at last character of next word */
  len = s2-s1+1 ;
  strncpy(str,s1,len) ;
  str[len] = '\0' ;
  spt[num] = strdup(str) ;
  ++num ;
  sx = s2+1 ;
 }
 freestring(&str) ;
 return num ;
}

void freeup (char *strpt[],int numpt)
/** free up array of strings */
{
    int i ;
    for (i=numpt-1; i>=0; i--)  {
      if (strpt[i] != NULL) freestring(&strpt[i]) ;
    }
}

int first_word(char *string, char *xword, char *xrest)

/*  first_word(string, *word, *rest)

        Break the string into the first word and the rest.  Both word and
rest begin with non-white space, unless rest is null.
        Return:
                0 means string is all white
                1 means word is non-white, but rest is white
                2 means word and rest are non-white
 
        If string and rest coincide, string will be overwritten
 
*/
{
   char *spt, x ;
   char *ss = NULL, *sx ;
   int l1,l2 ;

   ss = strdup(string) ;
   if (ss==NULL)  {
    printf("strdup fails\n") ;
    printf("%s\n",string) ;
    fatalx("first_word... strdup fails\n") ;
   }
   fflush(stdout) ;
   spt = ss ;
   xword[0]=xrest[0] = '\0' ;
   if ((spt = fnwhite(ss)) == NULL) {
     free(ss) ;
     return 0 ;
   }
    sx = fwhite(spt) ;
    if (sx==NULL) {
     strcpy(xword,spt) ;
     free (ss) ;
     return 1 ;
    }
    l1 = sx-spt ;
    l2 = strlen(sx) - 1 ;
    *sx = '\0' ;
    strcpy(xword,spt) ;
    if (l2 <= 0) {
     free(ss) ;
     return 1 ;
    }

    sx = fnwhite(sx+1) ;
    if (sx==NULL) { 
     free (ss) ;
     return 1 ;
    }
    strcpy(xrest,sx) ;  
    free (ss) ;
    return 2 ;
}

char *fnwhite (char * ss) 
/* return first non white space */
{
  char *x ;
  if (ss==NULL) fatalx("fnwhite: logic bug\n") ;
  for (x= ss; *x != '\0'; ++x)  {
   if (!isspace(*x)) return x ;
  }
  return NULL ;
}

char *ftab (char *ss) 
/* return first tab  */
{
  char *x ;
  int n ;
  for (x= ss; *x != '\0'; ++x)  {
   if (*x == CTAB) return x ;
  }
  return NULL ;
}
 
char *fwhite (char * ss) 
/* return first white space */
{
  char *x ;
  int n ;
  for (x= ss; *x != '\0'; ++x)  {
   if (isspace(*x)) return x ;
  }
  return NULL ;
}
 
static char Estr[MAXSTR];

void fatalx( char *fmt, ...) 
{	va_list args;

	va_start( args, fmt);
	vsprintf( Estr, fmt, args);
	va_end( args);
        fflush(stdout) ;

        fprintf(stderr,"fatalx:\n%s",Estr) ;
        fflush(stderr) ;
        abort() ;
}
int NPisnumber (char c) 
/**
 returns 1 if - + or digit 
*/
{
  if (isdigit(c)) return 1 ;
  if (c=='+') return 1 ;
  if (c=='-') return 1 ;

  return 0 ;
}
int isnumword (char *str) 
{

  int i, len, numpt ;
  char c ;
  len = strlen(str) ;
 
  numpt = 0 ;
  for (i=0; i<len; i++) {
   c = str[i] ; 

   if ((c == '.') && (numpt==0) ) {
    ++numpt ;
    continue ;
   }

   if (!NPisnumber(c)) return NO ;
   if (!isdigit(c) && (i>0) ) return NO ;
  }
  return YES ;

}

long seednum() 
{
   long a, b, c, d ;
   struct tms tbuff ;

   a = (long) getpid() ;
   b = (long) getuid() ;
   d = times(&tbuff) ;

   c = d ^ ((a + b) << 15) ;


   return c ;

}
int splitupwxbuff(char *strin, char **spt, int maxpt, char *bigbuff, int bigbufflen)  
// splits by white space; No zero length strings
{
  char *sx, *sy ;   
  int num, len, k, klo ;
  int empty = YES ;

  len = strlen(strin) ; 
  if (len>=bigbufflen) fatalx("(splitupwxbuff) overflow\n%s", strin) ;
  strcpy(bigbuff, strin) ;    
  num = 0 ;
  for (k=0; k<len; ++k) { 
   if (!isspace(bigbuff[k])) {
     empty = NO ;
     klo = k ;  
     sx = bigbuff + k ;
     break ;
   }
  }
  if (empty) return 0 ;
  for (k=klo; k<len; ++k) { 
   if (isspace(strin[k])) { 
    bigbuff[k] = CNULL; 
    if (num>=maxpt) break ;
    spt[num] = sx ;      
    if (strlen(sx) > 0) ++num ;
    sx  = bigbuff+k+1 ;
   }
  }
   if (num>=maxpt) return num ;
   spt[num] = sx ;
   if (strlen(sx) > 0) ++num ;
   return num ;
}
int splitupxbuff(char *strin, char **spt, int maxpt, char splitc, char *bigbuff, int bigbufflen)  
{
  char *sx, *sy ;   
  int num, len, k, klo ;
  int empty = YES ;

  len = strlen(strin) ; 
  if (len>=bigbufflen) fatalx("(splitupxbuff) overflow \n%s\n", strin) ;
  strcpy(bigbuff, strin) ;    
  num = 0 ;
  for (k=0; k<len; ++k) { 
   if (strin[k] != splitc) { 
     empty = NO ;
     klo = k ;
     sx = bigbuff + k ; 
     break ;
   }
  }
  if (empty) return 0 ;
  for (k=klo; k<len; ++k) { 
   if (strin[k] == splitc) { 
    bigbuff[k] = CNULL; 
    if (num>=maxpt) fatalx("overflow\n") ;
    spt[num] = sx ;      
    sx  = bigbuff+k+1 ;
    ++num ;
   }
  }
   if (num>=maxpt) fatalx("overflow\n") ;
   spt[num] = sx ;
   ++num ;
   return num ;
}

int splitup(char *strin, char **spt, int maxpt)  
{
  char *bigb, **qpt ;  
  int num, len, k ;

  if (strin==NULL) return 0 ;
  len = strlen(strin) ; 
  ZALLOC(bigb, len+1, char) ;
  ZALLOC(qpt, maxpt, char *) ; 
  num = splitupwxbuff(strin, qpt, maxpt, bigb, len+1) ; 
  for (k=0; k<num; ++k) { 
   spt[k] = strdup(qpt[k]) ; 
  }
  free(bigb) ;
  free(qpt) ;
  return num;
}
int splitupx(char *strin, char **spt, int maxpt, char splitc)  
{
  char *bigb, **qpt ;  
  int num, len, k ;

  if (strin==NULL) return 0 ;
  len = strlen(strin) ; 
  ZALLOC(bigb, len+1, char) ;
  ZALLOC(qpt, maxpt, char *) ; 
  num = splitupxbuff(strin, qpt, maxpt, splitc, bigb, len+1) ; 
  for (k=0; k<num; ++k) { 
   spt[k] = strdup(qpt[k]) ; 
  }
  free(bigb) ;
  free(qpt) ;
  return num;
}

int split1 (char *strin,  char *strpt[], char splitc)
/*
take a string and break it into 2 substrings separated by splitc ;
numpt is number of words returned  (1 or 2) 
*/
{
  char rest[MAXSTR],str[MAXSTR],ww[MAXSTR]  ;
  int  len, i, l ;

  strncpy(str,strin,MAXSTR) ; 
  len = strlen(strin) ;
  for (i=0; i<len; i++) {
   if (str[i] == splitc) {
    l = i ;
    strncpy(ww, str, l) ;  
    ww[l] = '\0' ;
    strpt[0] = strdup(ww) ;
    l = len-(i+1) ;
    if (l<=0) return 1 ;
    strncpy(rest,str+i+1,l) ;
    rest[l] = '\0' ;
    strpt[1] = strdup(rest) ;
    return 2 ;
   }
  }
  strpt[0] = strdup(strin) ;
  strpt[1] = NULL ;
  return 1 ;
}

void printbl(int n) 
{
  int i ;
  for (i=0; i<n; i++) {
   printf(" ") ;
  }
}

void printnl() 
{
   printf("\n") ;
}

void striptrail(char *sss, char c) 
/** 
 strip out trailing characters 
 c will usually be ' '
*/
{
   int len, i ;
   len = strlen(sss) ;
   for (i=len-1; i>=0; --i) {  
    if (sss[i] != c) return ;
    sss[i] = '\0' ;
   }
}

void catx(char *sxout, char **spt, int n) 
{
     int i  ;
     sxout[0] = CNULL ; 

     for (i=0; i<n; i++) {
      strcat(sxout,spt[i]) ;
     }


}

void catxx(char *sxout, char **spt, int n) 
/** 
 like catx but with space between items 
*/
{
     int i  ;
     sxout[0] = CNULL ; 

     for (i=0; i<n; i++) {
      strcat(sxout,spt[i]) ;
      if (i<(n-1)) strcat(sxout, " ") ;
     }
}
void catxc(char *sxout, char **spt, int n, char c) 
/** 
 like catx but with char c between items 
*/
{
     int i  ;
     char cc[2] ; 

     sxout[0] = CNULL ; 

     cc[0] = c ; 
     cc[1] = CNULL ;

     for (i=0; i<n; i++) {
      strcat(sxout,spt[i]) ;
      if (i<(n-1)) strcat(sxout, cc) ;
     }
}

void makedfn(char *dirname, char *fname, char *outname, int maxstr) 
/** makes full path name.    
  If fname starts with '/' or dirname = NULL we 
  so nothing. 
  outname MUST be allocated of length at least maxstr 
*/
{
    char *ss ;
    int len ;
 
    if ((dirname==NULL) || (fname[0]=='/')) {  
/* if fname starts with / we assume absolute pathname */
     len = strlen(fname) ;  
     if (len>=maxstr) fatalx("(makedfn) maxstr too short\n") ;
     strcpy(outname, fname) ;
     return ;
    }
    len = strlen(dirname) + strlen(fname)+1 ;  
    if (len>=maxstr) fatalx("(makedfn) maxstr too short\n") ;

    ss = outname ;
    strcpy(ss,dirname) ;
    ss = ss+strlen(dirname) ;  
    ss[0] = '/' ;
    ++ss ;
    strcpy(ss,fname) ;
}

int substringx (char **ap, char *inx, char *outx, int niter)
/** 
 *ap is original string 
 all occurrences of inx are substituted with outx 
 can loop so be careful !!  

 NB.  ap must be on heap.  Fixed allocation not supported 
*/
{
   char *a, *pt ;
   char *str ;
   int len, off, x ;

   if (niter>50) fatalx("bad string replacement\n %s\n", *ap) ;

   a = *ap ;
   len = strlen(a) + strlen(inx) + strlen(outx) + 1 ;
   pt = strstr(a, inx) ;
   if (pt == NULL) { 
    return 0 ;
   }
   ZALLOC(str, len, char) ;
   off = pt - a ;
   strncpy(str,a,off) ;            
   strcpy(str+off, outx) ;
   x = strlen(outx) ; 
   pt += strlen(inx) ;
   strcpy(str+off+x, pt) ;
   
   freestring(&a) ;
   *ap = strdup(str) ;
   free(str) ;
   return (1 + substringx(ap, inx, outx, niter+1)) ;
}

int substring (char **ap, char *inx, char *outx)
/** 
 *ap is original string 
 all occurrences of inx are substituted with outx 
 can loop so be careful !!  
 

 NB.  ap must be on heap.  Fixed allocation not supported 
*/
{
   return (substringx(ap, inx, outx, 0)) ;
}



int numcols(char *name)
// number of cols 
{
  FILE *fff ;
  char line[MAXSTR] ;
  char *spt[MAXSTR] ;
  char *sx ;
  int nsplit, num=0 ;

  if (name == NULL) fatalx("(numlines)  no name")  ;
  openit(name, &fff, "r") ;
  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, MAXFF) ; 
   if (nsplit==0) continue ;
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   freeup(spt, nsplit) ;
   fclose(fff) ;
   return nsplit ;
  }
}

int numlines(char *name)
// number of lines   no comments or blanks
{
  FILE *fff ;
  char line[MAXSTR] ;
  char *spt[MAXSTR] ;
  char *sx ;
  int nsplit, num=0 ;

  num = 0; 
  if (name == NULL) fatalx("(numlines)  no name")  ;
  openit(name, &fff, "r") ;
  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, MAXFF) ; 
   if (nsplit==0) continue ;
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   ++num ;
   freeup(spt, nsplit) ;
  }
  fclose(fff) ;
  return num ;
}

int ftest(char *sss) 
// can we open file for reading
{
 FILE *fdummy ;

 fdummy = fopen(sss, "r")  ; 

 if (fdummy == NULL) return NO ;
 fclose(fdummy) ;
 return YES ;
}

void openit(char *name, FILE **fff, char *type)  
{
  char *ss ;  
  if (name==NULL) fatalx("\n(openit) null name\n") ;
  *fff = fopen(name,type) ;
  if (*fff==NULL) {
   ss = strerror(errno) ;
   printf("bad open %s\n", name) ; 
// system("lsof | fgrep np29") ;
   fatalx("can't open file %s of type %s\n error info: %s\n",name,type,ss) ;
  }
}

int 
getxx(double **xx, int maxrow, int numcol, char *fname)
{

  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff ;
  FILE *fff ;
  int nbad = 0 ; 

  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  maxff = MAX(MAXFF, numcol) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (nsplit<numcol) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    xx[i][num]  = atof(spt[i]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}

double clocktime()
{
  double xtime ;
  double y ;

  xtime = (double) clock() ;
  y =  xtime / (double) CLOCKS_PER_SEC ;
  return y ;
}
int
indxstring(char **namelist, int len, char *strid)  
// look for string in list.  Was called indxindex
{
     int k ; 
     for (k=0; k< len; k++) {  
      if (namelist[k] == NULL) continue ; 
      if (strcmp(namelist[k], strid) == 0) return k ;
     }
     return -1 ;
}
int
indxstringr(char **namelist, int len, char *strid)  
// look for string in list.  Searches array in reverse ;
{
     int k ; 
     for (k=len-1; k >=0 ; k--) {  
      if (namelist[k] == NULL) continue ; 
      if (strcmp(namelist[k], strid) == 0) return k ;
     }
     return -1 ;
}

int 
getnameslohi(char ****pnames, int maxrow, int numcol, char *fname, int lo, int hi)
{

// count is base 1
  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff, numcolp, lcount=0 ;
  FILE *fff ;
  int nbad = 0 ; 
  char ***names ;

  names = *pnames ;
  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  numcolp = numcol + 1 ;
  maxff = MAX(MAXFF, numcolp) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (nsplit<numcol) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   ++lcount ; 
   if ((lcount<lo) || (lcount>hi)) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    names[i][num] = strdup(spt[i]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}

int 
getnames(char ****pnames, int maxrow, int numcol, char *fname)
{

  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff, numcolp ;
  FILE *fff ;
  int nbad = 0 ; 
  char ***names ;

  names = *pnames ;
  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  numcolp = numcol + 1 ;
  maxff = MAX(MAXFF, numcolp) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (nsplit<numcol) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    names[i][num] = strdup(spt[i]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}

int 
getxxnames(char ***pnames, double **xx, int maxrow, int numcol, char *fname)
{

  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff, numcolp ;
  FILE *fff ;
  int nbad = 0 ; 
  char **names = NULL ;

  if (pnames != NULL) names = *pnames ;
  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  numcolp = numcol + 1 ;
  maxff = MAX(MAXFF, numcolp) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (names != NULL) names[num] = strdup(sx) ;
   if (nsplit<numcolp) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    xx[i][num]  = atof(spt[i+1]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}

int 
getxxnamesf(char ***pnames, double **xx, int maxrow, int numcol, FILE *fff)
/** 
like getxxnames but file already open 
*/
{

#define MAXFF  50

  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff, numcolp ;
  int nbad = 0 ; 
  char **names ;

  if (pnames != NULL) names = *pnames ;

  numcolp = numcol + 1 ;
  maxff = MAX(MAXFF, numcolp) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (names != NULL) names[num] = strdup(sx) ;
   if (nsplit<numcolp) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    xx[i][num]  = atof(spt[i+1]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  return num ;
}


int 
getss(char **ss, char *fname)
/** 
 get list of names 
*/
{

  char line[MAXSTR] ;
  char qqq[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff ;
  FILE *fff ;


  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  maxff = MAXFF  ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   if (nsplit<1) { 
     continue ;
   }
   ss[num] = strdup(spt[0]) ;
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}
char revchar(char c) {
 char cc ;
     
 cc = toupper(c) ;
 if (cc=='A') return 'T' ;
 if (cc=='C') return 'G' ;
 if (cc=='G') return 'C' ;
 if (cc=='T') return 'A' ;

 return c ; 
}

void crevcomp(char *sout, char *sin)  
{
   char *sss, c, cout ; 
   int len ;
   int i, j, t; 
  
   len = strlen(sin) ;
   ZALLOC(sss, len+1, char) ;
   sss[len] = CNULL ;

   for (i=0; i<len; ++i) { 
    j = len-i-1 ;
    c = sin[i] ;
    t = base2num(c) ;
    if (t<0) { 
     sss[j] = c ;
     continue ;
    }
    cout = num2base(3-t) ;
    if (islower(c)) cout = tolower(cout) ;
    sss[j] = cout ;
   }
   strcpy(sout, sss) ;
   free(sss) ;
}

char *int_string(int a, int len, int base)
{
  static char ss[100] ;
  int t = a, k, i ;
  char *binary = "01" ;

  ss[len] = CNULL ;
  for (i=0; i<len; i++) {
   k = t % base  ;
   ss[len-i-1] = '0' + k ;   
   t = t/base ;
  }
  return ss ;
// fragile
}
char *binary_string(int a, int len)
{
  static char ss[100] ;
  int t = a, k, i ;
  char *binary = "01" ;

  ss[len] = CNULL ;
  for (i=0; i<len; i++) {
   k = t % 2 ;
   ss[len-i-1] = binary[k] ;
   t = t/2 ;
  }
  return ss ;
// fragile
}

char num2iub(int num) {  

  char *iubstring = "ACGTMRWSYKVHDBX" ;
  char c ;

  c = '?' ;
  if (num<0) return c ;
  if (num>14) return c ;

  return iubstring[num] ;

}

int iub2num(char c) { 

 char *iubstring = "ACGTMRWSYKVHDBX" ;
 int t ; 
 char *sx ; 

 sx = strchr(iubstring, c)  ; 
 if (sx == NULL) return -1 ;
 return sx - iubstring ;

}

char num2base (int num) 
{

  char *bases ="ACGT", c ;
  c = '?' ;
  if (num<0) return c ;
  if (num>3) return c ;
  return bases[num] ;

}
int base2num(char c)

{
    char cc ; 

    cc = toupper(c) ;

    switch (cc)  {
     case 'A':  return 0;
      break ;
     case 'C':  return 1;
      break ;
     case 'G':  return 2;
      break ;
     case 'T':  return 3;
      break ;
     default:  return -1 ;
    }
}

int string_binary(char *sx)
{
   int *aa, len, i, t ;
   char c ;

   len = strlen(sx) ;
   ZALLOC(aa, len, int) ;

   for (i=0; i<len; i++) {

    c = sx[i] ;
    if (c == '0') continue ;
    if (c != '1') fatalx("bad string: %s\n", sx) ;
    aa[i] = 1;
   }
   t = kodeitb(aa, len, 2) ;
   free(aa) ;
   return t ;

}
void freestring(char **ss)  
/* note extra indirection */
{
  if (*ss == NULL) return ; 
  free(*ss) ; 
  *ss = NULL ;
}

void copystrings(char **sa, char **sb, int n) 
{
  int i ; 
  for (i=0; i<n; ++i) {  
   sb[i] = strdup(sa[i]) ;
  }
}

void printstringsw(char **ss, int n, int slen, int width) 
{
  int k, kmod ;
  char fmt[10], s1[5] ;

  sprintf(s1, "%ds", slen) ;
  strcpy (fmt, "%") ;
  strcat(fmt, s1) ;

  for (k=0; k<n; ++k) {
   if (ss[k] != NULL) printf(fmt, ss[k]) ;
   else printf(fmt, "NULL") ; 
   kmod = (k+1) % width ;
   if ((kmod == 0) && (k < (n-1))) {
    printnl() ;
   }
  }
  printnl() ;
}

void printstrings(char **ss, int n) 

{
  int k ;

  for (k=0; k<n; ++k) {
   if (ss[k] != NULL) printf("%s", ss[k]) ;
   else printf("%s", "NULL") ; 
   printnl() ;
  }
}

int ridfile(char *fname)
{
  int t ;

  chmod(fname, 0777) ;
  t = unlink(fname) ;
  return t ;
}

char compbase(char x) 
// upper case !!
// return complement
{
 if (x=='A') return 'T' ;
 if (x=='C') return 'G' ;
 if (x=='G') return 'C' ;
 if (x=='T') return 'A' ;

 return x ;

}
void mkupper(char *sx)
{
  int len, k ;
     
  len = strlen(sx) ;
  for (k=0; k<len; ++k) { 
   sx[k] = toupper(sx[k]) ;
  }
}

void mklower(char *sx)
{
  int len, k ;
     
  len = strlen(sx) ;
  for (k=0; k<len; ++k) { 
   sx[k] = tolower(sx[k]) ;
  }
}


char *strstrx(char *s1, char *s2) 
// like strstr but case insensitive
// see also strcasestr
{
 char *ss1, *ss2, *spt  ;

 ss1 = strdup(s1) ;
 ss2 = strdup(s2) ;


 mkupper(ss1) ;
 mkupper(ss2) ;

 spt = strstr(ss1, ss2) ;
 if (spt != NULL) {
   spt = s1 + (spt - ss1) ;
 }

 freestring(&ss1) ;
 freestring(&ss2) ;

 return spt ;

}


int 
getjjnames(char ***pnames, int **jj, int maxrow, int numcol, char *fname)
{

  char line[MAXSTR] ;
  char *spt[MAXFF] ;
  char *sx ;
  int nsplit, i, j, num=0, maxff, numcolp ;
  FILE *fff ;
  int nbad = 0 ; 
  char **names ;

  names = *pnames ;
  if (fname == NULL) fff = stdin ; 
  else {
   openit(fname, &fff, "r") ;
  }
  numcolp = numcol + 1 ;
  maxff = MAX(MAXFF, numcolp) ; 

  while (fgets(line, MAXSTR, fff) != NULL)  {
   nsplit = splitup(line, spt, maxff) ; 
   if (nsplit == 0) { 
    freeup(spt, nsplit) ;
    continue ;
   }
   sx = spt[0] ;
   if (sx[0] == '#') {
    freeup(spt, nsplit) ;
    continue ;
   }
   names[num] = strdup(sx) ;
   if (nsplit<numcolp) { 
     ++nbad ;
     if (nbad<10) printf("+++ bad line: nsplit: %d numcol: %d\n%s\n", nsplit, numcol, line) ;
     continue ;
   }
   if (num>=maxrow) fatalx("too much data\n") ;
   for (i=0; i<numcol; i++)  {
    jj[i][num]  = atoi(spt[i+1]) ;
   }
   freeup(spt, nsplit) ;
   ++num ;
  }
  if (fname != NULL) fclose(fff) ;
  return num ;
}
int isiub(char iub) 
{
 char ss[5] ;
 int t ;

 t = iubdekode(ss, iub) ;  
 if (t==0) return NO ;
 return YES ; 

}

int isiub2(char iub) 
{
// base or het iub should be upper case
 char ss[5] ;
 int t ;

 t = iubdekode(ss, iub) ;  
 if (t==1) return YES ;
 if (t==2) return YES ;
 return NO ; 

}

int iubdekode(char *aa, char iub) 
// a should be 5 long 
{ 

  char a[5] ;  

  switch (iub)  { 

   case 'A':  
    strcpy(a,"A") ;
    break ;
   case 'C':  
    strcpy(a,"C") ;
    break ;
   case 'G':  
    strcpy(a,"G") ;
    break ;
   case 'T':  
    strcpy(a,"T") ;
    break ;
   case 'M':  
    strcpy(a,"AC") ;
    break ;
   case 'R':  
    strcpy(a,"AG") ;
    break ;
   case 'W':  
    strcpy(a,"AT") ;
    break ;
   case 'S':  
    strcpy(a,"CG") ;
    break ;
   case 'Y':  
    strcpy(a,"CT") ;
    break ;
   case 'K':  
    strcpy(a,"GT") ;
    break ;
   case 'V':  
    strcpy(a,"ACG") ;
    break ;
   case 'H':  
    strcpy(a,"ACT") ;
    break ;
   case 'D':  
    strcpy(a,"AGT") ;
    break ;
   case 'B':  
    strcpy(a,"CGT") ;
    break ;
   case 'X':  
    strcpy(a,"ACGT") ;
    break ;
   case 'N':  
    strcpy(a,"ACGT") ;
    break ;
   
   default:  
    a[0] = CNULL ;
  }
  if (aa != NULL) strcpy(aa, a) ;
  return strlen(a) ;
} 
int iubcbases(char  *cbases, char iub)
// crack iub into 2 bases (which may agree) 
// return number of bases (1 or 2) or -1. 
{

  char uu[5] ;
  int nuu ;

  nuu = iubdekode(uu, iub) ;
  if (nuu<1) return -1 ;
  if (nuu>2) return -1 ;
  if (nuu==1) uu[1] = uu[0] ;

  cbases[0]  = uu[0] ;
  cbases[1]  = uu[1] ;

  return nuu ;

}

int ishet(char c) 
{
 char aa[5] ; 
 int n ; 

 n = iubdekode(aa, c) ; 
 if (n==2) return YES ; 
 return NO ;
}

char *lastff(char *sss) 

{
  char *sx ; 
  sx = strrchr(sss, '/') ;
  if (sx == NULL) return sss ;
  return sx+1 ;
}

int char2int(char cc) 
{

  int x ; 
  x = (int) (cc - '0') ;
  return x ;

}
char int2char(int x) 
{

  char c ; 
  c = (char) ('0' + x) ;
}

void chomp(char *cc)
{
 int len ;
 len = strlen(cc) ;

 if (len==0) return ;
 if (cc[len-1] == CNL) cc[len-1] = CNULL ;

}

int numcmatch(char *cc, int len, char c) 
{
  int k, t = 0 ;

  for (k=0; k<len; ++k) {
   if (cc[k] == c) ++t ;
  }

  return t ;

}

int numcnomatch(char *cc, int len, char c) 
{
  int k, t = 0 ;

  for (k=0; k<len; ++k) {
   if (cc[k] != c) ++t ;
  }

  return t ;

}

