/************************************************************
**
** Application: SyncDiscs
**
** Title:       c.zstring
**
*************************************************************/

/*
*
* Copyright (c) 2017, David Pilling and Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */
/* from standard clib */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <locale.h>

/* from TaskLib */
#include "Tasklib:swis.h"
#include "Tasklib:h.os"
#include "Tasklib:h.flex"

/* from application */
#include "h.zstring"

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

#define STRCHUNK     0xC00
#define STRMAPCHUNK  0x300

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


/************************************************************/
/* global variables */

static char   * stringspace;
static int      stringsize;

static string * stringmap;
static int      nostrings;



/************************************************************/

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




/************************************************************/

os_error * zmkstring(int len,int * s)
{
 os_error * err;


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

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

  stringsize+=len;

  err=flex_chunk((flex_ptr)&stringspace,stringsize,STRCHUNK);
 }

 *s=(nostrings-1);

 return(err);
}



/************************************************************/

static os_error * chklen(int s,int newlen)
{
 os_error        * err;
 int               len;
 int               offset;
 int               delta;

 err=NULL;

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

 if(newlen!=len)
 {
  delta=newlen-len;

  stringmap[s].maxlen+=delta;

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

  if(!err)
  {
   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)err=flex_chunk((flex_ptr)&stringspace,stringsize+delta,STRCHUNK);
   stringsize+=delta;
  }
 }

 return(err);
}



/************************************************************/

static os_error * chktruelen(int s,int len)
{
 len++;
 len=(len+0x3)&(~0x3);
 return(chklen(s,len));
}





/************************************************************/

os_error * zrmstring(int s)
{
 os_error * err;
 int        len;
 int        offset;

 err=NULL;

/*  debug_printf(db,"(7) rmstring id %d",s); */

 if(s)
 {
  offset=stringmap[s].offset;
  len=stringmap[s].maxlen;

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

    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;

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

/* printf("nostrings=%d",nostrings); */

 return(err);
}



/*
_kernel_oserror * rmstringr(int * s)
{
 _kernel_oserror * err;

 err=rmstring(*s);
 *s=0;

 return(err);
}
*/


/************************************************************/

/* create a new string */

os_error * zcreatestring(char * p,int * s)
{
 os_error * err;

 err=zmkstring(strlen(p),s);
 if(!err) strcpy(zstringptr(*s),p);

 return(err);
}


/*

_kernel_oserror * createstringr(char ** p,int * s)
{
 _kernel_oserror * err;

 err=mkstring(strlen(*p),s);
 strcpy(stringptr(*s),*p);

 return(err);
}

*/


/************************************************************/

os_error * zassignstring(int s,char * p)
{
 os_error * err;
 int        len;
 char     * q;


 len=strlen(p);
 err=chktruelen(s,len);
 if(!err)
 {
  q=zstringptr(s);
  strcpy(q,p);
  stringmap[s].curlen=len;
 }

 return(err);
}



/************************************************************/

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

os_error * zdupstring(int s1,int * d1)
{
 os_error * err;
 char     * p;
 char     * q;
 int        s2;
 int        len;


 len=stringmap[s1].curlen;

 err=zmkstring(len,&s2);
 if(!err)
 {
  p=zstringptr(s1);
  q=zstringptr(s2);
  memcpy(q,p,len+1);
  stringmap[s2].curlen=len;

  *d1=s2;
 }

 return(err);
}

/************************************************************/

/* called once boots string table */

os_error * zstringstart(void)
{
 os_error * err;
 int        s;


          err=flex_alloc((flex_ptr)&stringspace,0);
 if(!err) err=flex_alloc((flex_ptr)&stringmap,0);

 stringsize=0;
 nostrings=0;
 zmkstring(0,&s);  /* by creating 1 dummy string, we can use 0 as */
                   /* signifying the null string */

 return(err);
}






/*************  End of c.zstring  ***********************/


