/*  
 *  This file is part of abc2ps, 
 *  Copyright (C) 1996-2007  Michael Methfessel
 *  See file abc2ps.c for details.
 */

#include <sys/stat.h>
#include <ctype.h>
#include <sys/types.h>
#include <string.h>

#include "abc2ps.h"

#include "util.h"

/*  low-level utilities  */


/* --- strlpy source (BSD), include if needed --- */
size_t strlcpy(char *dst, const char *src, size_t siz)
{
  char *d = dst;
  const char *s = src;
  size_t n = siz;
  
  /* Copy as many bytes as will fit */
  if (n != 0) {
    while (--n != 0) {
      if ((*d++ = *s++) == '\0')
        break;
    }
  }
  
  /* Not enough room in dst, add NUL and traverse rest of src */
  if (n == 0) {
    if (siz != 0)
      *d = '\0';                /* NUL-terminate dst */
    while (*s++)
      ;
  }
  
  return(s - src - 1);        /* count does not include NUL */
}


/* ----- error warning ----- */
void wng (char msg[], char str[])
{
#if !ABC_LIBRARY
  printf ("+++ %s%s\n", msg, str);
#endif
}

/* ----- error exit ----- */
void rx (msg, str)
char msg[],str[];
{
  printf ("\n+++ %s%s\n", msg, str);
#if !ABC_LIBRARY
  exit (1);
#endif
}

void rx1 (char msg[], char c)
{
  printf ("\n+++ %s%c\n", msg, c);
#if !ABC_LIBRARY
  exit (1);
#endif
}

void rxi (msg, i)
char msg[];
int i;
{
  printf ("\n+++ %s%d\n", msg, i);
#if !ABC_LIBRARY
  exit (1);
#endif
}

/* ----- bug: print message for internal error and maybe stop -----  */
void bug (msg,fatal)
char msg[];
int fatal;
{
  printf ("\n\nThis cannot happen!");
  if (strlen(msg)>0) printf ("\nInternal error: %s.\n", msg);
#if !ABC_LIBRARY
  if (fatal) {
    printf ("Emergency stop.\n\n");
    exit (1);
  }
#endif
  else {
    printf ("Trying to continue...\n\n");
  }
}

/* ----- ranf(x1,x2): return random float between x1 and x2 --- */
#if ABC_LIBRARY
static int randomSeed = 1;        /* seed */

void resetRandom()
{
  randomSeed = 1;
}

float ranf(float x1, float x2)
{
  static int m=259200;   /* generator constants */
  static int a=421;
  static int c=54773;
  float r;
  
  randomSeed=(randomSeed*a+c)%m;
  r=x1+(x2-x1)*(double)randomSeed/(double)m;
  return r;
}
#else
float ranf(float x1, float x2)
{
  static int m=259200;   /* generator constants */
  static int a=421;
  static int c=54773;
  static int j=1;        /* seed */
  float r;
  
  j=(j*a+c)%m;
  r=x1+(x2-x1)*(double)j/(double)m;
  return r;
}
#endif


/* ----- getline ----- */
/*
* Added by jc:
* This routine reads a line from fp into  buf,  and  trims  away  any
* trailing  whitespace.   We  are  paranoid  about whether isspace(c)
* returns true for CR, so this routine should work even if the  input
* came from a DOS system.
*/
char * abcgetline (buf, len, fp)
     char* buf;
     int   len;
     FILE* fp;
{	
  char* rp;
  int   c, l;
#if ABC_INPUT_STRING
  int n = 0;
  while ( *abcInputString && *abcInputString != '\n' && n < len-1 )
    buf[n++] = *abcInputString++;
  if ( *abcInputString )
    abcInputString++;
  buf[n++] = 0;
  rp = buf;
  if ( rp ) {
#else
  if ((rp = fgets(buf,len,fp))) {
#endif
    l = strlen(buf);
    while ((l > 0) && (((c = buf[l-1]) && isspace(c)) || (c == '\r'))) 
      buf[--l] = 0;
  }
  return rp;
}


/* ----- strip: remove leading and trailing blanks ----- */
void strip (str1, str)
char str[], str1[];
{
  int l, i, i1, i2;
  l = strlen(str);

  i1 = 0;
  for (i=0; i<l; i++) {
    if ((str[i]!=' ') && (str[i]!='\n')) { 
      i1=i; 
      break; 
    }
  }
  
  i2 =  0;
  for (i=l-1; i>=0; i--) {
    if ((str[i]!=' ') && (str[i]!='\n')) { 
      i2 = i + 1; 
      break; 
    }
  }

  for (i=i1; i<i2; i++) str1[i-i1] = str[i];
  str1[i2-i1] = 0;

/*  printf (" l=%d i1=%d i2=%d <%s> <%s>\n", l, i1, i2, str, str1);*/

}


/* ----- nwords: count words in string ----- */
int nwords (str)      
char *str;
{
  int w,k;
  char *c;
  c=str;
  w=0;
  for(k=0;k<=50;k++) {
    while (*c==' ') c++;
    if (*c=='\0') break;
    w++;
    while ((*c!=' ') && (*c!='\0')) c++;
    if (*c=='\0') break;
  }
  return w;
}    



/* ----- getword: return n-th word from string ---- */
int getword (iw,str,str1)      
int iw;
char *str,*str1;
{
  int w,k;
  char *c,*cc;
  if (iw<0) { *str1='\0'; return 0;}
  c=str;
  w=0;
  for(k=0;k<=50;k++) {
    while (*c==' ') c++;
    if (*c=='\0') break;
    if (w==iw) {
      cc=str1;
      while ((*c!=' ')&&(*c!='\0')) { *cc=*c; c++; cc++; }
      *cc='\0';
      return 1;
    }
    w++;
    while ((*c!=' ') && (*c!='\0')) c++;
    if (*c=='\0') break;
  }
  *str1='\0';
  return 0;
}    


/* ----- abbrev: check for valid abbreviation ----- */
int abbrev (str,ab,nchar)
char str[],ab[];
int nchar;
{
  int i,nc;
  if (strlen(str) > strlen(ab)) return 0;
  nc=strlen(str);
  if (nc<nchar) nc=nchar;
  for (i=0;i<nc;i++) if (str[i] != ab[i]) return 0;
  return 1;
}

/* ----- strext: set extension on a file identifier ----- */
/*  force=1 forces change even if fid already has an extension */
/*  force=0 does not change the extension if there already is one */
void strext (fid1, fid, ext, force)
char fid[],ext[],fid1[];
int force;
{
  int i,l;
  char *p,*q;

  strcpy (fid1, fid);
  l=strlen(fid1);
  p=fid1;
  for (i=0;i<l;i++) 
    if (fid1[i]=='/') p=fid1+i;

  if (!force) {
    q=strchr(p,'.');
    if (q && (q!=fid1+strlen(fid1)-1)) return;
  }
  if (!strchr(p,'.')) strcat (fid1,".");
  q=strchr(p,'.'); 
  if (strlen(ext)>0) q++;
  *q = 0;
  strcat(fid1,ext);

}

/* ----- cutext: cut off extension on a file identifier ----- */
void cutext (fid)
char fid[];
{
  int i,l;

  l=strlen(fid);
  for (i=l-1; i>0; i--) {
    if (fid[i]=='.') {
      fid[i]='\0';
      break;
    }
  }

}

/* ----- getext: get extension on a file identifier ----- */
void getext (fid,ext)
char fid[],ext[];
{
  int i,l,k;
  
  l=strlen(fid);
  k=l-1;
  for (i=0;i<l;i++) 
    if (fid[i]=='.') k=i;
  
  for (i=k+1;i<l;i++)
    ext[i-k-1]=fid[i];
  ext[l-k-1]='\0';

}


/* ----- sscanu ----- */
float scan_u (str)
char str[];
{
  char unit[81];
  float a, b;
  
  strcpy(unit, "pt");
  sscanf(str, "%f%80s", &a, unit);
  
  if      (!strcmp(unit,"cm")) b = a*CM;
  else if (!strcmp(unit,"in")) b = a*IN;
  else if (!strcmp(unit,"pt")) b = a*PT;
#if ABC_LIBRARY
  else
    b = a*CM;
#else
  else {
    printf ("+++ Unknown unit \"%s\" in: %s\n",unit,str); 
    exit (3);
  }
#endif
  return b;
}

/* --- str_sel: check if k is selected by string str --- */
/* selection string example: 1,2,3-5,10-  */
int str_sel (char *str, int k)
{
  int a, b, n;
  char *s;

  if (*str == 0) return 0;
    
  s = str;

  while (*s) {
    if (!sscanf(s, "%d%n", &a, &n)) break;
    s += n;
    b = a;
    if (*s == '-') {
      s ++;
      if (*s == 0) 
        b=99;
      else {
        if (!sscanf(s, "%d%n", &b, &n)) break;
        s += n;
      }
    }
    if ((k >= a) && (k <= b)) return 1;
    if (*s == ',') s++;
    else break;
  }

  return 0;
  
}


/* ----- match ------- */
int match (char *str, char *pat)
{
  char *p, *s;
  p = pat;
  s = str; 

  if (strlen(pat) == 0) return 1;

  while (*p != 0) {

    if (*p == '*') {             /* found wildcard '*' in pattern */
      p++;
      while (*p == '*') p++;
      if (*p == 0) return 1;     /* trailing '*' matches all */
      for (;;) {                 /* find match to char after '*' */
        if (*s == 0) return 0;
        if ((*s == *p) || (*p == '+')) 
          if (match (s+1, p+1)) return 1;   /* ok if rest matches */
        s++;
      }
    }
    
    else {                       /* no wildcard -- char must match */   
      if (*s == 0) return 0;
      if ((*p != *s) && (*p != '+')) return 0;
      s++;
    }
    p++;
  }

  if (*s != 0) return 0;         /* pattern but not string exhausted */
  return 1;
}

/* ----- cmatch: string matching, choose whether case matters ------- */
int cmatch (char *str, char *pat, int respect_case)
{
  char *p, *s;
  p = pat;
  s = str; 

  if (strlen(pat) == 0) return 1;

  while (*p != 0) {

    if (*p == '*') {               /* found wildcard '*' in pattern */
      p++;
      while (*p == '*') p++;
      if (*p == 0) return 1;       /* trailing '*' matches all */
      for (;;) {                   /* find match to char after '*' */
        if (*s == 0) return 0;
        if ((*s == *p) || (*p == '+') || 
            (!respect_case && (tolower(*s)==tolower(*p))))
          if (cmatch (s+1, p+1, respect_case)) return 1;  /* ok, rest matches */
        s++;
      }
    }
    
    else {                         /* no wildcard -- char must match */   
      if (*s == 0) return 0;
      if ((*s != *p) && (*p != '+') &&
          !(!respect_case && (tolower(*s)==tolower(*p)))) return 0;
      s++;
    }
    p++;
  }

  if (*s != 0) return 0;           /* pattern but not string exhausted */
  return 1;
}

/* ----- isblankstr: check for blank string ---- */
int isblankstr (str)
char str[];
{
  int i;
  for (i=0;i<strlen(str);i++) if (str[i] != ' ') return 0;
  return 1;
}

/* ----- cap_str: capitalize a string ----- */
void cap_str(str)
char str[];
{
  char *c;
  for (c=str; *c!='\0'; c++)
	*c = toupper(*c);
}
    

/* ----- cwid ----- */
/*  These are char widths for Times-Roman */
float cwid(char c)
{
  float w;
  if      (c=='a') w=44.4;
  else if (c=='b') w=50.0;
  else if (c=='c') w=44.4;
  else if (c=='d') w=50.0;
  else if (c=='e') w=44.4;
  else if (c=='f') w=33.3;
  else if (c=='g') w=50.0;
  else if (c=='h') w=50.0;
  else if (c=='i') w=27.8;
  else if (c=='j') w=27.8;
  else if (c=='k') w=50.0;
  else if (c=='l') w=27.8;
  else if (c=='m') w=77.8;
  else if (c=='n') w=50.0;
  else if (c=='o') w=50.0;
  else if (c=='p') w=50.0;
  else if (c=='q') w=50.0;
  else if (c=='r') w=33.3;
  else if (c=='s') w=38.9;
  else if (c=='t') w=27.8;
  else if (c=='u') w=50.0;
  else if (c=='v') w=50.0;
  else if (c=='w') w=72.2;
  else if (c=='x') w=50.0;
  else if (c=='y') w=50.0;
  else if (c=='z') w=44.4;

  else if (c=='A') w=72.2;
  else if (c=='B') w=66.7;
  else if (c=='C') w=66.7;
  else if (c=='D') w=72.2;
  else if (c=='E') w=61.1;
  else if (c=='F') w=55.6;
  else if (c=='G') w=72.2;
  else if (c=='H') w=72.2;
  else if (c=='I') w=33.3;
  else if (c=='J') w=38.9;
  else if (c=='K') w=72.2;
  else if (c=='L') w=61.1;
  else if (c=='M') w=88.9;
  else if (c=='N') w=72.2;
  else if (c=='O') w=72.2;
  else if (c=='P') w=55.6;
  else if (c=='Q') w=72.2;
  else if (c=='R') w=66.7;
  else if (c=='S') w=55.6;
  else if (c=='T') w=61.1;
  else if (c=='U') w=72.2;
  else if (c=='V') w=72.2;
  else if (c=='W') w=94.4;
  else if (c=='X') w=72.2;
  else if (c=='Y') w=72.2;
  else if (c=='Z') w=61.1;

  else if (c=='0') w=50.0;
  else if (c=='1') w=50.0;
  else if (c=='2') w=50.0;
  else if (c=='3') w=50.0;
  else if (c=='4') w=50.0;
  else if (c=='5') w=50.0;
  else if (c=='6') w=50.0;
  else if (c=='7') w=50.0;
  else if (c=='8') w=50.0;
  else if (c=='9') w=50.0;

  else if (c=='~') w=54.1;
  else if (c=='!') w=33.3;
  else if (c=='@') w=92.1;
  else if (c=='#') w=50.0;
  else if (c=='$') w=50.0;
  else if (c=='%') w=83.3;
  else if (c=='^') w=46.9;
  else if (c=='&') w=77.8;
  else if (c=='*') w=50.0;
  else if (c=='(') w=33.3;
  else if (c==')') w=33.3;
/*|   else if (c=='-') w=33.3; |*/
  else if (c=='-') w=40.0;
  else if (c=='_') w=50.0;
  else if (c=='+') w=56.4;
  else if (c=='=') w=55.0;
  else if (c=='[') w=33.3;
  else if (c==']') w=33.3;
  else if (c=='{') w=48.0;
  else if (c=='}') w=48.0;
  else if (c=='|') w=20.0;
  else if (c==':') w=27.8;
  else if (c==';') w=27.8;
  else if (c=='.') w=27.8;
  else if (c==',') w=27.8;
  else if (c=='\\') w=27.8;
  else if (c=='\'') w=33.3;
  else if (c=='\"') w=40.8;
  else if (c=='<') w=56.4;
  else if (c=='>') w=56.4;
  else if (c=='?') w=44.4;
  else if (c=='/') w=27.8;
  else if (c=='`') w=33.3;
  else if (c==' ') w=25.0;
  else             w=50.0;
  return w/100.0;
}


/* ----- get_file_size ------- */
/* version using standard function stat */
#include <sys/stat.h>
int get_file_size (fname)
char fname[];
{
  int m,rc;
  struct stat statbuf; 
  rc = stat(fname,&statbuf); 
  if (rc == -1) {
    printf ("Unsuccessful call to stat for file %s\n", fname);
    return -1;
  } 
  m=statbuf.st_size; 
  return m;
} 

/* version which counts bytes by hand */
int get_file_size1 (fname)
char fname[];
{
  int m,i;
  FILE *fp;
  
  if ((fp = fopen (fname,"r")) == NULL) {
    printf ("Cannot open file to determine size: %s", fname);
    return -1;
  }

  m=0;
  i=getc(fp);
  while (i != EOF) {
    m++;
    i=getc(fp);
  } 
  fclose (fp);
  return m;
}

