/* ------------------------------------------------------------------------ */
/*                                 sststr.c                                 */
/*                                                                          */
/*                        string handling functions                         */
/*                                                                          */
/*       CopyRight (C) 1991,1992  Steven Lutrov.  All rights reserved.      */
/* ------------------------------------------------------------------------ */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <alloc.h>

#include "sststr.h"


/* ------------------------------------------------------------------------ */
/*                         local function prototypes                        */
/* ------------------------------------------------------------------------ */

char  to_lower       (char c);
char  to_upper       (char c);
char  to_nocr        (char c);
int   is_alpha       (char c);
int   is_punct       (char c);
int   is_space       (char c);
int   is_num	     (char c);


/* ------------------------------------------------------------------------ */
/*                converts a long to a string with comma spacing            */
/* ------------------------------------------------------------------------ */
char *strcomma(long n)
{
    static char buf2[15];
    char buf1[15];
    register int p1,p2;
    int positions = 0;

    memset(buf1,0,15);
    memset(buf2,0,15);
    sprintf(buf1,"%ld",n);
    p1 = strlen(buf1);
    p2 = (p1 > 9) ? p1 + 3 : (p1 > 6) ? p1 + 2 : (p1 > 3) ? p1 + 1 : p1;
    p1--;
    p2--;
    while (p1 >= 0) {
        buf2[p2--] = buf1[p1--];
        if (++positions % 3 == 0)
            buf2[p2--] = ',';
    }
    return buf2;
}



/* ------------------------------------------------------------------------ */
/*                   deletes a substring from a string                      */
/* ------------------------------------------------------------------------ */
char *strdelete (char *a,  char *s)

{
   register char *p, *q;

   q = strinc(a, s);
   if(!q)
      return(NULL);
   p = q + strlen(a);
   strcpy(q, p);
   return(s);
}

/* ------------------------------------------------------------------------ */
/*     change all occurances of a case independant substring in a string    */
/* ------------------------------------------------------------------------ */
char *strichangestr (char *s,  char *a,  char *b)

{
    register int n=0;
    register char *p = s;
    int    i;

   i = strlen(b);
   for(;;)  {
     if(strisrep(p, a, b) == NULL)
	 break;
     p += i;
     n++;
   }
   return(n ? s: NULL);
}

/* ------------------------------------------------------------------------ */
/*         return number occurances of a substring found in a string        */
/* ------------------------------------------------------------------------ */
int stricountstr (char *a,  char *s)

{
   register char *p = s;
   register int n = 0;
   int l;

   l = strlen(a);
   p = striinc(a, p);
   while(p != NULL)  {
      n++;
      p += l;
      p = striinc(a, p);
   }
   return(n);
}

/* ------------------------------------------------------------------------ */
/*      search and replace a case independant substring in a string         */
/* ------------------------------------------------------------------------ */
char *strisrep (char *s,  char *a,  char *b)

{
    register char *p;
    register int d;

   if((p = striinc(a, s)) != NULL) {
      stridelete(a, s);
      d = p - s;
      strinsert(b, s, d);
      p = s;
   }
   return(p);
}

/* ------------------------------------------------------------------------ */
/*                           left justify a string                          */
/* ------------------------------------------------------------------------ */
char *strljust (char *s)

{
   register char *p = s;
   register char *q;

   for(q = s; isspace(*q) && (*q != EOS); q++);
   if(p != q)
      while(*q != EOS) {
	 *p++ = *q;
	 *q++ = ' ';
      }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                 trims the leading spaces of a string                     */
/* ------------------------------------------------------------------------ */
char *strltrim (char *s)

{
   register char *p;
   register char *q;

   p = q = s;
   while(isspace(*p))
      p++;
   while(*p != EOS)
      *q++ = *p++;
   *q = EOS;
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                    copy a substring into a new string                    */
/* ------------------------------------------------------------------------ */
char *strmiddle (char *s,  int p,  int l)

{
    register int i;
    char  *r;

   if((r = malloc(l + 1)) != NULL) {
       for(i = 0; i < l; i++)
	 *(r + i) = *(s + p + i);
      *(r + l) = EOS;
   }
   return(r);
}

/* ------------------------------------------------------------------------ */
/*                   count occurances of a char in a string                 */
/* ------------------------------------------------------------------------ */
int strcountchar (char *s,  int c)

{
    register int n = 0;
    register char *p;

   for(p = s; (*p != EOS); p++)
      if(c == *p)
         n++;
   return(n);
}

/* ------------------------------------------------------------------------ */
/*                           right justify a string                         */
/* ------------------------------------------------------------------------ */
char *strrjust (char *s)

{
   register char *p, *q;

   for(p = s; (*p != EOS); p++);           /* find end of string */
   p--;
   for(q = p; isspace(*q) && q >= s; q--); /* find last non-space char */
   if(p != q)   {
      while(q >= s)  {
	 *p-- = *q;
	 *q-- = ' ';
      }
   }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                             rotate a string left                         */
/* ------------------------------------------------------------------------ */
char *strrotleft (char *s,  int n)

{
    register int i, j;
    char  t;

   if(EOS != *s)
      for(j = 0; j < n; j++) {
	 t = *(s);
         for(i = 0; *(s + i); i++)
            *(s + i) = *(s + i + 1);
         *(s + i - 1) = t;
      }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                            rotate a string right                         */
/* ------------------------------------------------------------------------ */
char *strrotright (char *s,  int n)
{
    register int i, j;
    int  l;
    char t;

   if(EOS != *s) {
      l = strlen(s) - 1;
      for(j = 0; j < n; j++)  {
	 t = *(s + l);
	 for(i = l; i > 0; i--)
	    *(s + i) = *(s + i - 1);
	 *s = t;
      }
   }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                   change all occurances of a sunstring                   */
/* ------------------------------------------------------------------------ */
char *strchangestr (char *s,  char *a,  char *b)

{
    register int n = 0;
    register char *p = s;
    int    i;

   i = strlen(b);
   for(;;)  {
   if(strsrep(p, a, b) == NULL)
	 break;
      p += i;
      n++;
   }
   return(n ? s : NULL);
}


/* ------------------------------------------------------------------------ */
/*                      modify the length of a string                       */
/* ------------------------------------------------------------------------ */
char *strresize (char *s,  int n)

{
    register int i;
    register int l;

   l = strlen(s);
   if(n < l)
      *(s + n) = EOS;
   else   {
    for(i = l; i <n; i++)
	 *(s + i) = ' ';
      *(s + i) = EOS;
   }
   return(s);
}


/* ------------------------------------------------------------------------ */
/*                            shift a string left                           */
/* ------------------------------------------------------------------------ */
char *strshiftleft (char *s,  int n)

{
   register int i;
   int    j;

   if(EOS != *s)
      for(j = 0; j < n; j++)  {
	 for(i = 0; *(s + i); i++)
	    *(s + i) = *(s + i + 1);
	 *(s + i - 1) = ' ';
      }
   return(s);
}


/* ------------------------------------------------------------------------ */
/*                           shift a string right                           */
/* ------------------------------------------------------------------------ */
char *strshiftright (char *s,  int n)

{
   register int i;
   int j, l;

   if(EOS != *s) {
     l = strlen(s) - 1;
      for(j = 0; j < n; j++) {
	for(i = l; i > 0; i--)
            *(s + i) = *(s  + i - 1);
         *s = ' ';
      }
   }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                count occurances of a substring in a string               */
/* ------------------------------------------------------------------------ */
int strcountstr (char *a,  char *s)

{
    register char *p;
    register int n = 0;
    int l;

   l = strlen(a);
   p = strinc(a, s);
   while(p != NULL) {
      n++;
      p += l;
      p = strinc(a, p);
   }
   return(n);
}

/* ------------------------------------------------------------------------ */
/*                 search for and replace a sunbstring in a string          */
/* ------------------------------------------------------------------------ */
char *strsrep (char *s,  char *a,  char *b)

{
   register char *p;
   register int d;

   if((p = strinc(a, s)) != NULL) {
      strdelete(a, s);
      d = p - s;
      strinsert(b, s, d);
      p = s;
   }
   return(p);
}

/* ------------------------------------------------------------------------ */
/*                        trim string of trailing blanks                    */
/* ------------------------------------------------------------------------ */
char *strtrim (char *s)

{
   register int i;

   for(i = strlen(s) - 1; isspace(s[i]) && i >= 0; i--);
   s[i+1] = EOS;
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                     convert a string to initial capitals                 */
/* ------------------------------------------------------------------------ */
char *struplow (char *s)

{
   register int i;

   for(i = 0; *(s + i); i++)
      *(s + i) = touplow(s, s + i,*(s + i));
   return(s);
}

/* ------------------------------------------------------------------------ */
/*                     return non-zero if a string is blank                 */
/* ------------------------------------------------------------------------ */
int strisblank(char  *s)
{
   register char *p = s;

   for(p = s; (*p != EOS); p++)
      if(!isspace(*p))
         return(0);
   return(1);
}


/* ------------------------------------------------------------------------ */
/*                   change all matching chars in a string                  */
/* ------------------------------------------------------------------------ */
int strchangechar(char *s,  int a, int b)

{
    register int  n = 0;
    register char  *p;

   for(p = s; (*p != EOS); p++)
      if(a == *p)  {
	 *p = b;
	 n++;
      }
   return(n);
}

/* ------------------------------------------------------------------------ */
/*                      returns the check-sum of a string                   */
/* ------------------------------------------------------------------------ */
unsigned long strchecksum(char *s)

{
    register char *p;
    unsigned long c = 0L;

   for(p = s; (*p != EOS); p++)
      c += ((unsigned long)*p);
   return(c);
}


/* ------------------------------------------------------------------------ */
/*                            encode/decode a string                        */
/* ------------------------------------------------------------------------ */
char *strcode (char *s,  char *k)

{
    register char *q = k;
    register char *p;

   for(p = s; (*p != EOS); p++)
   {  if(*p != *q)
         *p = *p^*q;
      q++;
      if(*q == EOS)
         q = k;
   }
   return(s);
}

/* ------------------------------------------------------------------------ */
/*               delete all occurances of a substring in a string           */
/* ------------------------------------------------------------------------ */
char *strdeleteall (char *a, char *s)

{
    register int n = 0;
    register char *p = s;

   while(NULL != (p = strinc(a, p)))
   {  strdelete(a, p);
      n++;
   }
   return(n ? s : NULL);
}

/* ------------------------------------------------------------------------ */
/*          change all matching case-independant chars in a string          */
/* ------------------------------------------------------------------------ */
int strichange(char *s, int a, int b)

{
    register int n = 0;
    register char *p;

   a = toupper(a);
   for(p = s; (*p != EOS);p++ )
      if(a == toupper(*p)) {
	 *p = b;
	 n++;
      }
   return(n);
}

/* ------------------------------------------------------------------------ */
/*              returns the checksum of a case independant string           */
/* ------------------------------------------------------------------------ */
unsigned long strichecksum (char *s)

{
   register char *p;
   unsigned long c = 0L;

   for(p = s; (*p != EOS); p++)
      c += ((unsigned long)toupper(*p));
   return(c);
}

/* ------------------------------------------------------------------------ */
/*             delete a case independant sunstring from a string            */
/* ------------------------------------------------------------------------ */
char *stridelete (char *a,  char *s)

{
   register char *p, *q;

   if(NULL == (q = striinc(a, s)))
      return(NULL);
   p = q + strlen(a);
   strcpy(q, p);
   return(s);
}

/* ------------------------------------------------------------------------ */
/*    delete all occurances of a case independant substring from a string   */
/* ------------------------------------------------------------------------ */
char *strideleteall (char *a, char *s)

{
    register int n = 0;
    register char *p = s;

   while(NULL != (p = striinc(a, p))) {
      stridelete(a, p);
      n++;
   }
   return(n ? s : NULL);
}

/* ------------------------------------------------------------------------ */
/*                test for inclusion of a case independant string           */
/* ------------------------------------------------------------------------ */
char *striinc (char *a,  char *s)

{
   register int m;
   register char *p;

   m = strlen(a);
   for(p = s; (*p != EOS); p++)
      if(!strnicmp(a, p, m))
         return(p);
   return(NULL);
}

/* ------------------------------------------------------------------------ */
/*                      test for inclusion of a substring                   */
/* ------------------------------------------------------------------------ */
char *strinc (char *a,  char *s)

{
    register int m;
    register char *p;

   m = strlen(a);
   for(p = s; (*p != EOS); p++)
      if(!strncmp(a, p, m))
         return(p);
   return(NULL);
}

/* ------------------------------------------------------------------------ */
/*                        insert one string into another                    */
/* ------------------------------------------------------------------------ */
char *strinsert (char *a,  char *s,  int p)

{
   register int i, l;

   l = strlen(a);
   for(i = strlen(s); i >= p; i--)
      *(s + l + i) = *(s + i);
   for(i = 0; i < l; i++)
      *(s + p + i) = *(a + i);
   return(s);
}

/* ------------------------------------------------------------------------ */
/*          count occurances of a case independant char in a string         */
/* ------------------------------------------------------------------------ */
int stricountchar (char *s, int c)

{
    register int n = 0;
    register char *p;

   c = toupper(c);
   for(p = s; (*p != EOS); p++)
      if(c == toupper(*p))
         n++;
   return(n);
}

/* ------------------------------------------------------------------------ */
/*       convert a char to the opposite case of its predecessing char       */
/* ------------------------------------------------------------------------ */
int touplow(char *s, char *p, int c)

{
   if(strchr(" -_,./", *(p - 1)) || (p == s))
      return(toupper(c));
   return(tolower(c));
}



/* ------------------------------------------------------------------------ */
/*   the source string is copied to the destination string with character   */
/*            conversions as specified in the (option) parameter.           */
/* ------------------------------------------------------------------------ */
char *strcvt(char *d, char *s, int option, int ml)

{
	int bdest,ctr,nbctr,skipc;
	char *savdest,*smaxout,pch;

	if(!d || !s || !ml)
		return((char *)0);
	smaxout = s +strlen(s);
	if(option&NOTRAILBLANKS)
		for(--smaxout;*smaxout==' '&&smaxout >= s;--smaxout)
			;
	for(pch='\0',savdest=d,bdest=skipc=nbctr= ctr=0;
	    s <=smaxout&&ml && *s; ++ctr, ++s, skipc=bdest = 0) {
		if(*s!=' ')
			++nbctr;
		if(option & NOBLANKS && *s == ' ')
			continue;
		if(option & NONONALPHA && (!is_alpha (*s) &&  !is_space(*s)))
			continue;
		if(option & NONONNUMERIC && ! is_num(*s))
			continue;
		if(option & NOLEADBLANKS && !nbctr) {
			pch = ' ';
			continue;
		}
		if(option & NOALPHA && is_alpha(*s))
			continue;
		if(option & NONUMERIC && is_num(*s))
			continue;
		if(option & NOPUNCT && is_punct(*s))
			continue;
        if(option & TOSINGLE && (*s == ' ' && pch==' '))
			continue;
		if(option & TOUPPER) {
			*d= to_upper(*s);
			skipc = bdest = 1;
		}
		if(option & TOLOWER) {
			*d = to_lower(*s);
			skipc = bdest = 1;
		}
        if(option & TONOCR) {
            *d = to_nocr(*s);
			skipc = bdest = 1;
		}
		if(option & TOPROPER && (pch == ' ' || pch == ',' ||
		   pch == '.' || pch == '\0')) {
			*d = to_upper(*s);
			skipc = bdest = 1;
		}
		if(option & TOUNPROPER && (pch==' ' || pch==','||
		   pch == '.' || pch == '\0')) {
			*d = to_lower(*s);
			skipc = bdest = 1;
		}
		if(!skipc) {
			*d++ = *s;	/* default case, copy */
			pch = *s;
			--ml;		/* character and decrement */
		} else if(bdest) {
			pch = *d;
			++d;
			--ml;
		}
	}
	*d='\0';
	return(savdest);
}

/* ------------------------------------------------------------------------ */
/*     translate an upper case character to it's lower case equivalent      */
/* ------------------------------------------------------------------------ */
char to_lower(char c)

{
    return((char)((c>='A' && c<='Z') ? (char)(c+' ') : c));
}

/* ------------------------------------------------------------------------ */
/*                  translate an control character to a space               */
/* ------------------------------------------------------------------------ */
char to_nocr(char c)

{
    return((char) ( (c=='\n') ? (' ') : c));
}

/* ------------------------------------------------------------------------ */
/*        translate a lower case character to it's upper case equivalent    */
/* ------------------------------------------------------------------------ */
char to_upper(char c)
{
    return((char) ( (c >= 'a' && c <= 'z') ? (char)(c-' '):c) );
}

/* ------------------------------------------------------------------------ */
/*                 test if character is an alpha character                  */
/* ------------------------------------------------------------------------ */
int is_alpha(char c)

{
	return(((c>='a'&&c<='z')||(c>='A'&&c<='Z')) ? 1 : 0);
}


/* ------------------------------------------------------------------------ */
/*               test if character is a punctuation character               */
/* ------------------------------------------------------------------------ */
int is_punct(char c)
{
	return((c=='.'||c==','||c=='!'||c==';'||c==':'||c=='\''||c=='"'||
		c=='?') ? 1 : 0);
}

/* ------------------------------------------------------------------------ */
/*                  test if character is a space character.                 */
/* ------------------------------------------------------------------------ */
int is_space(char c)
{
	return((c==' ') ? 1 : 0);
}

/* ------------------------------------------------------------------------ */
/*                        test if character is a numeric.                   */
/* ------------------------------------------------------------------------ */
int is_num(char c)
{
	return((c>='0'&&c<='9') ? 1 : 0);
}


