/*
   <p>Temporary storage buffer.</p>

   <kbd>
   <b>environ - C programming support functions</b><br>
   Copyright (C) 2005  Martin C Gregorie
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Lesser GNU General Public License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the Lesser GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   </kbd>
  
   <p>Contact Martin Gregorie at <i>martin@gregorie.org</i></p>
*/

#include "environ.h"

#ifdef OS9
#include <strings.h>
char* mktemp();
#endif

#ifdef MSDOS
#include <string.h>
#include <dir.h>
#endif

#ifdef LINUX
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#endif

/*
   Initialise the storage system to hold <u>s</u> bytes and set the
   debugging level to <u>d</u>.

   A pointer to a <i>tempstore</i> control block is returned if the
   temporary storage was successfully initialised and null if an error
   ocurred.
   
   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsclose(), tsgetc(), tsgetstr(),
      tsputc(), tsputstr()</i>
*/

tempstore* tsopen(long s, int d)
{
    tempstore*    hddr;

    hddr = (tempstore*)malloc(sizeof(tempstore));
    if (hddr == NULL)
        return (tempstore*)(NULL);

    if (s == 0)
        s = TSLIM;
    hddr->buffer = NULL;
    hddr->filename = NULL;
    hddr->fil = NULL;
    hddr->size = s;
    hddr->inptr = 0;
    hddr->outptr = 0;

    if (s<=TSLIM)
    {
        hddr->fileused = FALSE;
        hddr->buffer = (char*)malloc(s);
        if (hddr->buffer == NULL)
            return (tsclose(hddr));
    }
    else
    {
        hddr->fileused = TRUE;
        hddr->filename = (char*)malloc(9);
        if (hddr->filename == NULL)
            return (tsclose(hddr));

        strcpy(hddr->filename,"TSXXXXXX");
        mkstemp(hddr->filename);
        if (hddr->filename == NULL)
            return (tsclose(hddr));
            
        if (d)
            printf("Temp store name is %s\n",hddr->filename);

        hddr->fil = fopen(hddr->filename,"w+");
        if (hddr->fil == NULL)
            return (tsclose(hddr));
    }
    return (hddr);
}

/*
   Close the storage system referenced by the <i>tempstore</i> pointer
   <u>ptr</u>, release the storage and return NULL.

   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsgetc(), tsgetstr(), tsopen(),
      tsputc(), tsputstr()</i>

*/
tempstore* tsclose(tempstore *ptr)
{
    if (ptr == NULL)
        return (NULL);
    if (ptr->fileused)
    {
        if (ptr->fil != NULL)
            fclose(ptr->fil);
        if (ptr->filename != NULL)
            unlink(ptr->filename);
    }
    if (ptr->buffer != NULL)
        free(ptr->buffer);
    if (ptr->filename != NULL)
        free(ptr->filename);
    free(ptr);
    return (NULL);
}

/*
   Append a character <u>c</u> to the <i>tempstore</i> referenced by
   <u>ptr</u>. Returns TRUE on success and FALSE if an error ocurred
   or the temporary store is full.
 
   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsclose(), tsgetc(), tsgetstr(), tsopen(),
      tsputstr()</i>
*/

int tsputc(tempstore *ptr, int c)
{
    int    r;
    
    if (ptr == NULL)
        return (FALSE);
    if (ptr->inptr < ptr->size)
    {
        if (ptr->fileused)
            r = putc(c,ptr->fil);
        else
            r = ptr->buffer[ptr->inptr] = c;
        ptr->inptr += 1;
    }
    else
        r = !c;    
    return ( r == c );
}

/*
   Read the next character from the <i>tempstore</i> <u>ptr</u>.
   The next character is returned if the operation was successful and
   EOF if it failed.

   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsclose(), tsgetstr(), tsopen(),
      tsputc(), tsputstr()</i>
*/
int tsgetc(tempstore *ptr)
{
    int c;
    
    if (ptr == NULL)
        return (EOF);
    if (ptr->outptr >= ptr->inptr)
        return (EOF);
    if (ptr->fileused)
    {
        if (ptr->outptr == 0)              /* first read on the file */
        {
            fflush(ptr->fil);
            if (fseek(ptr->fil,0,0) != 0)  /* beginning of file */
                return(EOF);               /* error trap */
        }
        c = getc(ptr->fil);
    }
    else
        c = ptr->buffer[ptr->outptr];
    ptr->outptr += 1;
    return (c);
}

/*
   Append the string <u>str</u> to the <i>tempstore</i> <u>ptr</u>
   followed by a string delimiter (NULL). Returns TRUE if the string
   was successfully stored and FALSE if errors were encountered.

   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsclose(), tsgetc(), tsgetstr(), tsopen(),
      tsputc()</i>
*/

int tsputstr(tempstore *ptr, char *str)
{
    int r;
    
    r = TRUE;
    while (*str && r)
    {
        r = tsputc(ptr,*str);
        str++;
    }
    if (r)
        r = tsputc(ptr,0);
    return (r);
}

/*
   Read the next string from the <i>tempstore</i> <u>ptr</u> into
   <u>str</u>. Up to <u>n</u> characters will be read unless the string
   termination character (null) or the end of the temporary storage is
   encountered first. It returns TRUE if the string was read successfully
   or FALSE if the end of the storage was reached or an error ocurred.
   Reading <u>n</u> characters before reaching the string terminator is
   <i>NOT</i> an error.

   This function is part of the Temporary storage buffer package.
   It allows charactetrs and strings to be written to and read from
   a block of memory. This is held in memory unless it is bigger than
   a predefined limit TSLIM, when it is put in a temporary file,
   whose name is system dependent but conforms the the pattern TZXXXXXX.
   The Xs are replaced by a system-supplied value which is guaranteed
   to be unique.

   <b>NOTE:</b> If the constant TSLIM is changed the temporary storage
   package should be recompiled because the constant is used internally.

   <b>See also:</b> <i>tsclose(), tsgetc(), tsopen(),
      tsputc(), tsputstr()</i>
*/

int tsgetstr(tempstore *ptr, char *str, int n)
{
    int i;
    int c;
    
    i = 0;
    while ((c = tsgetc(ptr)) != 0)
    {
        if (c == EOF)
            break;
        str[i++] = c;
        if (i>=n)
            break;
    }
    if (i<n)
        str[i] = 0;
    return (c != EOF);
}

