/*  
 *  This file is part of abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *  See file abc2ps.c for details.
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "abc2ps.h" 
#include <sys/stat.h>
#ifdef _MSVC
#include <process.h>
#endif

/*  low-level utilities  */

/* case insensitive compare for unix */
#ifndef _MSVC
int stricmp(const char *p1, const char *p2) {
	if (!(p1 || p2)) return 0;
	if (!p1 && p2) return 1;
	if (p1 && !p2) return -1;
	while (*p1 && *p2) {
		if (tolower(*p2) < tolower(*p1)) {
			return -1;
		} else if (tolower(*p2) > tolower(*p1)) {
			return 1;
		}
		p1++;
		p2++;
	}
	/* one or both strings has run out */
	if (!(*p1 || *p2)) {
		return 0;
	} else if (!*p1) {
		return 1;
	} else {
		return -1;
	}
}
#endif

/* string arena */
static struct str_a {
	char str[1000];		/* area */
	char *p;		/* pointer in area */
	struct str_a *n;	/* next area */
	short r;		/* remaining space in area */
} *str_r, *str_p;		/* root and current area pointers */

/* ----- error warning ----- */
void wng(char msg[],
	 char str[])
{
	printf("++++ %s%s\n", msg, str);
}

/* ----- error exit ----- */
void rx(char msg[],
	char str[])
{
	printf("\n++++ %s%s\n", msg, str);
	exit(1);
}

/* ----- bug: print message for internal error and maybe stop -----  */
void bug(char msg[],
	 int fatal)
{
	printf("\n\nThis cannot happen!");
	if (msg[0] != '\0')
		printf("\nInternal error: %s.\n", msg);
	if (fatal) {
		printf("Emergency stop.\n\n");
		exit(1);
	}
	printf("Trying to continue...\n\n");
}

/* ----- clrarena: clear the string arena ----- */
void clrarena(void)
{
	str_p = 0;
}

/* ----- getarena: get a string area ----- */
char *getarena(int len)
{
	char *p;

	len++;			/* room for EOS */
	if (str_p == 0
	    || str_p->r < len) {
		if (str_p == 0) {
			if (str_r == 0) {
				str_r = calloc(1, sizeof *str_r);
				str_p = str_r;
			} else	str_p = str_r;
		} else {
			if (str_p->n == 0)
				str_p->n = calloc(1, sizeof *str_r);
			str_p = str_p->n;
		}
		str_p->p = str_p->str;
		str_p->r = sizeof str_p->str;
	}
	p = str_p->p;
	str_p->p += len;
	str_p->r -= len;
	return p;
}

/* ----- ranf(x1,x2): return random float between x1 and x2 --- */
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 */
  
	j = (j * a + c) % m;
	return (float)(x1 + (x2 - x1) * (double) j / (double) m);
}

/* ----- strip: allocate memory and remove leading and trailing blanks ----- */
char *strip(char *str)
{
	int l,i,i1,i2;
	char *p;

	l=strlen(str);
	p = getarena(l);

	i1=0;
	for (i=0; i<l; i++)
		if (!isspace(str[i])) {
			i1=i;
			break;
		}
	i2=0;
	for (i = l; --i >= 0; ) 
		if (!isspace(str[i])) {
			i2=i+1;
			break;
		}
	strncpy(p, &str[i1], i2 - i1);
	p[i2-i1]=0;
/*	printf(" l=%d i1=%d i2=%d <%s> <%s>\n", l, i1, i2, str, str1);*/
	return p;
}

/* ----- nwords: count words in string ----- */
int nwords(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(int iw,
	    char *c,
	    char *str1)      
{
	int w,k;
	char *cc;

	if (iw<0) {
		*str1='\0';
		return 0;
	}
	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++;
			*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(char str[],
	   char ab[],
	   int nchar)
{
	int nc;

	nc = strlen(str);
	if (nc > (int)strlen(ab))
		return 0;
	if (nc<nchar)
		nc=nchar;
	if (strncmp(str, ab, nc) != 0)
		return 0;
	return 1;
}

/* ----- strext: set extension on a file identifier ----- */
void strext(char fid1[],
	    char ext[])
{
	char *p, *q;

	if ((p = strchr(fid1,'/')) == 0)
		p = fid1;

	if ((q = strchr(p, '.')) == 0)
		strcat(p, ".");
	else	q[1] = '\0';
	strcat(p, ext);
}

/* ----- cutext: cut off extension on a file identifier ----- */
void cutext(char fid[])
{
	char *p;

	if ((p = strchr(fid, '.')) != 0)
		*p = '\0';
}

/* ----- getext: get extension on a file identifier ----- */
void getext(char fid[],
	    char ext[])
{
	char *p;

	if ((p = strchr(fid, '.')) != 0) {
		strcpy(ext, p+1);
	} else	ext[0] = '\0';
}

/* ----- sscanu ----- */
float scan_u(char str[])
{
	char unit[81];
	float a,b;

	strcpy(unit,"pt");
	sscanf(str,"%f%s", &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;
	else {
		printf ("++++ Unknown unit \"%s\" in: %s\n",unit,str);
		exit(3);
	}
	return b;
}

/* ----- match ------- */
int match(char s[],
	  char p[])
{
	if (*p =='\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;
}

/* ----- isblankstr: check for blank string ---- */
int isblankstr(char str[])
{
	int i;

	for (i=0;i<(int)strlen(str);i++)
		if (!isspace(str[i]))
			return 0;
	return 1;
}

/* ----- cap_str: capitalize a string ----- */
void cap_str(char *c)
{
	while (*c!='\0') {
		*c = toupper(*c);
		c++;
	}
}
    
/* ----- cwid ----- */
/*  These are char widths for Times-Roman */
float cwid(char c)
{
	float w;

	if	(c=='a') w=(float)44.4;
	else if (c=='b') w=(float)50.0;
	else if (c=='c') w=(float)44.4;
	else if (c=='d') w=(float)50.0;
	else if (c=='e') w=(float)44.4;
	else if (c=='f') w=(float)33.3;
	else if (c=='g') w=(float)50.0;
	else if (c=='h') w=(float)50.0;
	else if (c=='i') w=(float)27.8;
	else if (c=='j') w=(float)27.8;
	else if (c=='k') w=(float)50.0;
	else if (c=='l') w=(float)27.8;
	else if (c=='m') w=(float)77.8;
	else if (c=='n') w=(float)50.0;
	else if (c=='o') w=(float)50.0;
	else if (c=='p') w=(float)50.0;
	else if (c=='q') w=(float)50.0;
	else if (c=='r') w=(float)33.3;
	else if (c=='s') w=(float)38.9;
	else if (c=='t') w=(float)27.8;
	else if (c=='u') w=(float)50.0;
	else if (c=='v') w=(float)50.0;
	else if (c=='w') w=(float)72.2;
	else if (c=='x') w=(float)50.0;
	else if (c=='y') w=(float)50.0;
	else if (c=='z') w=(float)44.4;

	else if (c=='A') w=(float)72.2;
	else if (c=='B') w=(float)66.7;
	else if (c=='C') w=(float)66.7;
	else if (c=='D') w=(float)72.2;
	else if (c=='E') w=(float)61.1;
	else if (c=='F') w=(float)55.6;
	else if (c=='G') w=(float)72.2;
	else if (c=='H') w=(float)72.2;
	else if (c=='I') w=(float)33.3;
	else if (c=='J') w=(float)38.9;
	else if (c=='K') w=(float)72.2;
	else if (c=='L') w=(float)61.1;
	else if (c=='M') w=(float)88.9;
	else if (c=='N') w=(float)72.2;
	else if (c=='O') w=(float)72.2;
	else if (c=='P') w=(float)55.6;
	else if (c=='Q') w=(float)72.2;
	else if (c=='R') w=(float)66.7;
	else if (c=='S') w=(float)55.6;
	else if (c=='T') w=(float)61.1;
	else if (c=='U') w=(float)72.2;
	else if (c=='V') w=(float)72.2;
	else if (c=='W') w=(float)94.4;
	else if (c=='X') w=(float)72.2;
	else if (c=='Y') w=(float)72.2;
	else if (c=='Z') w=(float)61.1;
	
	else if (c=='0') w=(float)50.0;
	else if (c=='1') w=(float)50.0;
	else if (c=='2') w=(float)50.0;
	else if (c=='3') w=(float)50.0;
	else if (c=='4') w=(float)50.0;
	else if (c=='5') w=(float)50.0;
	else if (c=='6') w=(float)50.0;
	else if (c=='7') w=(float)50.0;
	else if (c=='8') w=(float)50.0;
	else if (c=='9') w=(float)50.0;

	else if (c=='~') w=(float)54.1;
	else if (c=='!') w=(float)33.3;
	else if (c=='@') w=(float)92.1;
	else if (c=='#') w=(float)50.0;
	else if (c=='$') w=(float)50.0;
	else if (c=='%') w=(float)83.3;
	else if (c=='^') w=(float)46.9;
	else if (c=='&') w=(float)77.8;
	else if (c=='*') w=(float)50.0;
	else if (c=='(') w=(float)33.3;
	else if (c==')') w=(float)33.3;
/*|   else if (c=='-') w=33.3; |*/
	else if (c=='-') w=(float)40.0;
	else if (c=='_') w=(float)50.0;
	else if (c=='+') w=(float)56.4;
	else if (c=='=') w=(float)55.0;
	else if (c=='[') w=(float)33.3;
	else if (c==']') w=(float)33.3;
	else if (c=='{') w=(float)48.0;
	else if (c=='}') w=(float)48.0;
	else if (c=='|') w=(float)20.0;
	else if (c==':') w=(float)27.8;
	else if (c==';') w=(float)27.8;
	else if (c=='.') w=(float)27.8;
	else if (c==',') w=(float)27.8;
	else if (c=='\\') w=(float)27.8;
	else if (c=='\'') w=(float)33.3;
	else if (c=='\"') w=(float)40.8;
	else if (c=='<') w=(float)56.4;
	else if (c=='>') w=(float)56.4;
	else if (c=='?') w=(float)44.4;
	else if (c=='/') w=(float)27.8;
	else if (c=='`') w=(float)33.3;
	else if (c==' ') w=(float)25.0;
	else		 w=(float)50.0;
	return w/(float)100.0;
}

/* ----- get_file_size ------- */
/* version using standard function stat */
int get_file_size(char fname[])
{
	struct stat statbuf;

	if (stat(fname,&statbuf) < 0) {
		printf("Unsuccessful call to stat for file %s\n", fname);
		return -1;
	}
	return statbuf.st_size;
}

#if 0
/* version which counts bytes by hand */
int get_file_size1(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;
}
#endif
