/*->c.xstr  */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <locale.h>



#include "h.os"
#include "h.flex"


#include "h.xext"
#include "h.xint"





/*****************************************************************************/
/* x string manager */


typedef struct string
{
 int offset;
 int maxlen;
 int curlen;
} string;


char   * stringspace;
int      stringsize;

string * stringmap;
int      nostrings;



char * stringptr(int s)
{
 int offset;
 offset=stringmap[s].offset;
 return(stringspace+offset);
}




static void stringmem(void)
{
 if(zlevel) zraise(ZMEM,"");
 else       xraise(ERRMEM);
}


int mkstring(int len)
{
 if(flex_chunk((flex_ptr)&stringmap,(nostrings+1)*sizeof(string),STRMAPCHUNK))
 {
  stringmap[nostrings++].offset=stringsize;

  stringmap[nostrings-1].curlen=len;
  len++;
  len=(len+0x3)&(~0x3);
  stringmap[nostrings-1].maxlen=len;

  stringsize+=len;

  if(!flex_chunk((flex_ptr)&stringspace,stringsize,STRCHUNK)) stringmem();
 }
 else stringmem();

 return(nostrings-1);
}



void chklen(int s,int newlen)
{
 int len;
 int offset;
 int delta;

 offset=stringmap[s].offset;
 len=stringmap[s].maxlen;

 if(newlen==len) return;

 delta=newlen-len;

 stringmap[s].maxlen+=delta;

 if(delta>0)
 {
  if(!flex_chunk((flex_ptr)&stringspace,stringsize+delta,STRCHUNK)) 
                                                                stringmem();
 }

 memmove(stringspace+offset+len+delta,stringspace+offset+len,
                                      stringsize-offset-len);

 while(++s<nostrings)
 {
  if(stringmap[s].offset>=0) stringmap[s].offset+=delta;
 }

 if(delta<0) flex_chunk((flex_ptr)&stringspace,stringsize+delta,STRCHUNK);
 stringsize+=delta;

}



void chktruelen(int s,int len)
{
 len++;
 len=(len+0x3)&(~0x3);
 chklen(s,len);
}





void rmstring(int s)
{
 int len;
 int offset;

/* dprintf(0,"string s=%d nostrings=%d\n",s,nostrings); */

 if(s<0 || s>=nostrings)
 {
 /* dprintf(0,"string error\n"); */
  return;
 }

 offset=stringmap[s].offset;
 len=stringmap[s].maxlen;

 if(s==(nostrings-1))
 {
  while(1)
  {
   nostrings--;
   s--;

/*   printf("rem loop s=%d nostrings=%d offset=%d",s,nostrings,stringmap[s].offset); */

   if(s<0) break;
   if(stringmap[s].offset>=0) break;
  }
 }
 else
 if(s<(nostrings-1))
 {
  /* shift memory from the end of this string to end of table down by len */
  memmove(stringspace+offset,stringspace+offset+len,stringsize-offset-len);
  stringmap[s].offset=-1;
  while(++s<nostrings)
  {
   if(stringmap[s].offset>=0) stringmap[s].offset-=len;
  }
 }

 stringsize-=len;

/* printf("rmstring stringsize=%d - %d\n",stringsize,len); */

 flex_chunk((flex_ptr)&stringspace,stringsize,STRCHUNK);
 flex_chunk((flex_ptr)&stringmap,nostrings*sizeof(string),STRMAPCHUNK);
}




/* trashes top n strings on string stack, optionally saving top n */


void stringpull(int n,int top)
{
 int i;

 i=nostrings-1-top;

 while(n--)
 {
  while(i>=0)
  {
   if(stringmap[i].offset>=0) break; 
   else i--;
  }

  rmstring(i--);
 }
}



/*
void stringpull(int n,int top)
{
 int i;

 i=nostrings-1-top;

 while(1)
  if(stringmap[i].offset>=0) break; 
  else i--;

 while(n--) rmstring(i--);
}
*/


void setstrings(int n)
{
 while(nostrings>n) rmstring(nostrings-1);
}



/* create a new string */

int createstring(char * p)
{
 int s;
 s=mkstring(strlen(p));
 strcpy(stringptr(s),p);
 return(s);
}




/* creates a string and then copies a string into it */

int duplicatestring(int s1)
{
 char * p;
 char * q;
 int    s2;
 int    len;

 p=stringptr(s1);
 len=stringmap[s1].curlen;

 s2=mkstring(len);
 p=stringptr(s1);
 q=stringptr(s2);
 memcpy(q,p,len+1);
 stringmap[s2].curlen=len;

 return(s2);
}




/* assigns one string to another */

void copystring(int s1,int s2)
{
 char * p;
 char * q;

/* printf("copy string oldlen=%d newlen=%d\n",stringmap[s1].len,stringmap[s2].len); */

 chklen(s1,stringmap[s2].maxlen);
 p=stringptr(s1);
 q=stringptr(s2);

/* printf("after copy string oldlen=%d newlen=%d\n",stringmap[s1].len,stringmap[s2].len); */

 memcpy(p,q,stringmap[s2].maxlen);
 stringmap[s1].curlen=stringmap[s2].curlen;
}



void assignstring(int s,char * p)
{
 int    len;
 char * q;

 len=strlen(p);
 chktruelen(s,len);
 q=stringptr(s);
 strcpy(q,p);
 stringmap[s].curlen=len;
}


void assignstringlen(int s,char * p,int len)
{
 char * q;

 len++;
 chktruelen(s,len);
 q=stringptr(s);
 memcpy(q,p,len);
 stringmap[s].curlen=len;
}



void appendstring(int s,char * p)
{
 int len1;
 int len2;
 char * q;

 len1=strlen(p);

 q=stringptr(s);
 len2=stringmap[s].curlen;

 chktruelen(s,len1+len2);

 q=stringptr(s);
 strcpy(q+len2,p);

 stringmap[s].curlen=len1+len2;
}







/* the string s2 is appended to s1 */

void catstrings(int s1,int s2)
{
 char * p;
 char * q;
 int    len1;
 int    len2;

 p=stringptr(s1);
 q=stringptr(s2);

 len1=stringmap[s1].curlen;
 len2=stringmap[s2].curlen;

/* printf("len1=%d len2=%d\n",len1,len2);
 printf("maplen1=%d maplen2=%d\n",stringmap[s1].len,stringmap[s2].len); */


 chktruelen(s1,len1+len2);


/* printf("after maplen1=%d maplen2=%d\n",stringmap[s1].len,stringmap[s2].len);
*/

 p=stringptr(s1);
 q=stringptr(s2);

 memcpy(p+len1,q,len2);
 *(p+len1+len2)=0;

 stringmap[s1].curlen=len1+len2;
}



/* the string s1 is multiplied n times */

void mulstring(int s1,int n)
{
 char * p;
 int    len;
 int    i;

 p=stringptr(s1);

 len=strlen(p);
 chktruelen(s1,len*n);
 p=stringptr(s1);

 for(i=1;i<n;i++) memcpy(p+i*len,p,len);
 *(p+n*len)=0;
 stringmap[s1].curlen=len*n;
}




int divstring(int s1,int s2)
{
 char * p;
 char * q;

 p=stringptr(s1);
 q=stringptr(s2);

 q=strstr(p,q);
 if(q) return(q-p);
 else  return(-1);
}



int modstring(int s1,int s2)
{
 char * p;
 char * q;

 p=stringptr(s1);
 q=stringptr(s2);

 return(strspn(p,q));
}



int cmpstrings(int s1,int s2)
{
 char * p;
 char * q;
 p=stringptr(s1);
 q=stringptr(s2);

 return(strcmp(p,q));
}



/* the string s1 is made upper case */

void upperstring(int s1)
{
 char * p;
 int    len;
 int    i;
 p=stringptr(s1);
 len=strlen(p);
 for(i=0;i<len;i++) p[i]=toupper(p[i]);
}



/* the string s1 is made lower case */

void lowerstring(int s1)
{
 char * p;
 int    len;
 int    i;
 p=stringptr(s1);
 len=strlen(p);
 for(i=0;i<len;i++) p[i]=tolower(p[i]);
}




/* the case of string s1 is swopped */

void swopstring(int s1)
{
 char * p;
 int    len;
 int    i;
 p=stringptr(s1);
 len=strlen(p);
 for(i=0;i<len;i++) 
  if(islower(p[i])) p[i]=toupper(p[i]);
  else
  if(isupper(p[i])) p[i]=tolower(p[i]);
}




/* string s1 is shifted left */

void shiftstringleft(int s1,int n)
{
 char * p;
 int    len;

 p=stringptr(s1);
 len=stringmap[s1].curlen;

 if(n<0) n=0;
 else
 if(n>len) n=len;

 memmove(p,p+n,len-n+1);
 chktruelen(s1,len-n);
 stringmap[s1].curlen=len-n;
}


/* string s1 is shifted right */

void shiftstringright(int s1,int n)
{
 char * p;
 int    len;

 p=stringptr(s1);
 len=stringmap[s1].curlen;
 if(n<0) n=0;
 else
 if(n>len) n=len;

 p[len-n]=0;
 chktruelen(s1,len-n);
 stringmap[s1].curlen=len-n;
}


/* string s1 has byte catted at right */

/*
void catstringintright(int s1,int byte)
{
 char * p;
 int    len;

 p=stringptr(s1);
 len=strlen(p);
 chktruelen(s1,len+1);
 p[len]=byte;
 p[len+1]=0;
}
 */

/* string s1 has byte catted at left */

/*
void catstringintleft(int s1,int byte)
{
 char * p;
 int    len;

 p=stringptr(s1);
 len=strlen(p);
 chktruelen(s1,len+1);
 memmove(p,p+1,len+1);
 p[0]=byte;
}
 */


/* length of string */

int stringlen(int s1)
{
/* return(strlen(stringptr(s1))); */
 return(stringmap[s1].curlen);
}



/* nth. char in string */

int stringn(int s1,int n)
{
 char * p;
 int    len;

 p=stringptr(s1);
 len=stringmap[s1].curlen;

 if(n<0) n=0;
 if(n>len) n=len;

 return(*(p+n));
}



/* called once boots string table */

void xstringstart(void)
{
 flex_alloc((flex_ptr)&stringspace,0);
 flex_alloc((flex_ptr)&stringmap,0);
 stringsize=0;
 nostrings=0;
}


void stringdump(void)
{
 int i;

 printf("nostrings=%d stringsize=%d\n",nostrings,stringsize); 

 for(i=0;i<nostrings;i++)
 printf("s=%d offset=%d\n",i,stringmap[i].offset);

}

