/*
//
// textfile.c
//
// Text file functions
//
// Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
// granted by the author.  No warranties are made on the fitness of this
// source code.
// Amiga version - 1997 - Geert Bevin
//
*/

/*
// see the note in msg.c for why this is done
*/
#define DUMB_TEXTFILE_PROTOTYPE

#include "htp.h"

BOOL OpenFile(const char *name, const char *filename, const char *openFlags,
    TEXTFILE *textFile)
{
    assert(name != NULL);
    assert(filename != NULL);
    assert(openFlags != NULL);
    assert(textFile != NULL);

    /* convert the filename to the native machine's format */
    /* (MS-DOS to UNIX and vice-versa) */
    /* this returns an allocated copy of the string, so it must be freed */
    /* when the structure is destroyed */
    if((textFile->filename = ConvertDirDelimiter(filename)) == NULL)
    {
        DEBUG_PRINT(("unable to convert dir delimiter"));
        return FALSE;
    }

    /* create a copy of the printed name */
    if((textFile->name = DuplicateString(name)) == NULL)
    {
        DEBUG_PRINT(("unable to duplicate name"));
        FreeMemory(textFile->filename);
        textFile->filename = NULL;
        return FALSE;
    }

    /* initialize the rest of the structure */
    textFile->lineNumber = 1;
    textFile->bytesReadThisLine = 0;
    textFile->bytesWrittenThisLine = 0;
    textFile->flags = TEXTFILE_FLAG_NONE;

    if((textFile->file = fopen(textFile->filename, openFlags)) == NULL)
    {
        DEBUG_PRINT(("unable to open file %s", filename));
        FreeMemory(textFile->filename);
        textFile->filename = NULL;
        FreeMemory(textFile->name);
        textFile->name = NULL;
        return FALSE;
    }

    return TRUE;
}   

void CreateNullFile(TEXTFILE *textFile)
{
    assert(textFile != NULL);

    memset(textFile, 0, sizeof(TEXTFILE));
    textFile->flags = TEXTFILE_FLAG_NULL_FILE;
}

void CloseFile(TEXTFILE *textFile)
{
    assert(textFile != NULL);

    if(textFile->flags & TEXTFILE_FLAG_NULL_FILE)
    {
        return;
    }

    assert(textFile->filename != NULL);
    assert(textFile->name != NULL);
    assert(textFile->file != NULL);

    FreeMemory(textFile->filename);
    FreeMemory(textFile->name);
    fclose(textFile->file);

    textFile->filename = NULL;
    textFile->name = NULL;
    textFile->file = NULL;
}   

void SuppressLinefeeds(TEXTFILE *textFile)
{
    textFile->flags |= TEXTFILE_FLAG_NO_CR;
}

void AllowLinefeeds(TEXTFILE *textFile)
{
    textFile->flags &= (~TEXTFILE_FLAG_NO_CR);
}

BOOL GetFileChar(TEXTFILE *textFile, char *ch)
{
    int getCh;

    assert(textFile != NULL);

    if(textFile->flags & TEXTFILE_FLAG_NULL_FILE)
    {
        return FALSE;
    }

    assert(ch != NULL);
    assert(textFile->file != NULL);

    do
    {
        if((getCh = fgetc(textFile->file)) == EOF)
        {
            return FALSE;
        }
    } while(getCh == '\r');

    if((*ch = (char) getCh) != '\n')
    {
        textFile->bytesReadThisLine++;
    }
    else
    {
        textFile->lineNumber++;
        textFile->bytesReadThisLine = 0;
        textFile->bytesWrittenThisLine = 0;
    }

    return TRUE;
}   

BOOL PutFileChar(TEXTFILE *textFile, char ch)
{
    uint bytesWrittenThisLine;

    assert(textFile != NULL);

    if(textFile->flags & TEXTFILE_FLAG_NULL_FILE)
    {
        return TRUE;
    }

    if(ch == '\r')
    {
        return TRUE;
    }
    else if(ch == '\n')
    {
        bytesWrittenThisLine = textFile->bytesWrittenThisLine;

        textFile->lineNumber++;
        textFile->bytesReadThisLine = 0;
        textFile->bytesWrittenThisLine = 0;

        /* suppress linefeeds? */
        if(textFile->flags & TEXTFILE_FLAG_NO_CR)
        {
            if(bytesWrittenThisLine != 0)
            {
                /* emit a SPACE to avoid a run-on word from the C/R being */
                /* dropped between words */
                fputc(' ', textFile->file);
            }

            return TRUE;
        }
    }
    else
    {
        textFile->bytesWrittenThisLine++;
    }

    assert(textFile->file != NULL);
    fputc(ch, textFile->file);

    return TRUE;
}   

BOOL PutFileString(va_alist) va_dcl
{
    va_list argptr;
    char *str;
    char *strptr;
    TEXTFILE *textFile;
    const char *format;

    /* allocate room to hold the final string ... allocating 16K to be safe, */
    /* although a better method would be more deterministic */
    /* (originally allocated 1K, but now allocating 16K due to JavaScript */
    /* and VBScript comments ... suggested by Allan Todd) */
    if((str = AllocMemory(16 * KBYTE)) == NULL)
    {
        return FALSE;
    }

    /* convert formatted arguments into single string */
    va_start(argptr);
    textFile = va_arg(argptr, TEXTFILE *);
    format = va_arg(argptr, const char *);
    vsprintf(str, format, argptr);
    va_end(argptr);
    
    /* check the arguments */
    assert(textFile != NULL);

    if(textFile->flags & TEXTFILE_FLAG_NULL_FILE)
    {
        FreeMemory(str);
        return TRUE;
    }

    assert(format != NULL);

    strptr = str;
    while(*strptr != NUL)
    {
        if(PutFileChar(textFile, *strptr++) == FALSE)
        {
            FreeMemory(str);
            return FALSE;
        }
    }

    FreeMemory(str);

    return TRUE;
}   

BOOL GetFileLine(TEXTFILE *textfile, char *buffer, uint size)
{
    char *ptr;

    assert(textfile != NULL);
    assert(buffer != NULL);

    if(feof(textfile->file))
    {
        return FALSE;
    }

    ptr = buffer;

    /* compare size to 1 rather than 0 to leave room for trailing NUL */
    while(size-- > 1)
    {
        if(GetFileChar(textfile, ptr) == FALSE)
        {
            break;
        }

        if(*ptr == '\n')
        {
            break;
        }

        ptr++;
    }

    /* watch for empty string, which should basically count as EOF */
    if(buffer == ptr)
    {
        return FALSE;
    }

    /* set the EOL to NUL */
    *ptr = NUL;

    return TRUE;
}

