/*
 * ____ DAPHNE COPYRIGHT NOTICE ____
 *
 * Copyright (C) 2001 Matt Ownby
 *
 * This file is part of DAPHNE, a laserdisc arcade game emulator
 *
 * DAPHNE is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * DAPHNE 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 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
 */

// fileparse.cpp
// by Matt Ownby

// some basic file-parsing functions which should be safe enough to prevent
// hypseus from ever
// segfaulting, even if the file is totally corrupt

#include "config.h"

#include "fileparse.h"
#include "conout.h"

// copies into buf everything from the current position in the file until the
// end of a
//  line and positions the file stream at the beginning of the next line.
// returns how many bytes were copied
int read_line(mpo_io *io, string &buf)
{
    unsigned char ch          = 0;
    MPO_BYTES_READ bytes_read = 0;

    buf = ""; // initalize it with an empty string

    // go until we reach EOF (or we reach the end of the line)
    while (!io->eof) {
        if (mpo_read(&ch, 1, &bytes_read, io)) {
            if (bytes_read == 0) break; // if we hit EOF, then break

            // if we have hit the end of the line
            if ((ch == 10) || (ch == 13)) {
                // keep reading until we get passed the end of line chars
                while (((ch == 10) || (ch == 13)) && (bytes_read != 0)) {
                    mpo_read(&ch, 1, &bytes_read, io);
                }

                // if we still have more of the file to read in, then move back
                // one character
                // so that we are at the beginning of the next line
                if (bytes_read != 0) {
                    // if seek was successful
                    if (mpo_seek(-1, MPO_SEEK_CUR, io) == true) {
                    } else {
                        printline("fileparse.cpp : mpo_seek function failed "
                                  "when it shouldn't have");
                    }
                }

                break; // we're done
            }

            // if the character is part of the current line then add it
            else {
                buf = buf + (char)ch;
            }
        } else {
            printline("fileparse.cpp ERROR : mpo_read function failed");
            break;
        }
    }

    return buf.length();
}

// copies into buf everything from the current position in the file until the
// end of a
//  line and positions the file stream at the beginning of the next line.
//  Contents are also
//  null-terminated.
// Returns the # of bytes copied into the buf.
// buf_size is the total size of the buf to prevent buffer overflow
int read_line(mpo_io *io, char *buf, int buf_size)
{
    int index                 = 0;
    unsigned char ch          = 0;
    MPO_BYTES_READ bytes_read = 0;

    // while we haven't overflowed the buffer
    // (we do -1 to leave space for null character at the end)
    while (index < (buf_size - 1)) {
        if (mpo_read(&ch, 1, &bytes_read, io)) {
            if (bytes_read == 0) break; // if we hit EOF, then break

            // if we have hit the end of the line
            if ((ch == 10) || (ch == 13)) {
                // keep reading until we get passed the end of line chars
                while (((ch == 10) || (ch == 13)) && (bytes_read != 0)) {
                    mpo_read(&ch, 1, &bytes_read, io);
                }

                // if we still have more of the file to read in, then move back
                // one character
                // so that we are at the beginning of the next line
                if (bytes_read != 0) {
                    // if seek was successful
                    if (mpo_seek(-1, MPO_SEEK_CUR, io) == true) {
                    } else {
                        printline("fileparse.cpp : mpo_seek function failed "
                                  "when it shouldn't have");
                    }
                }

                break; // we're done
            }

            // if the character is part of the current line
            else {
                buf[index++] = (unsigned char)ch;
            }
        } else {
            printline("fileparse.cpp ERROR : mpo_read function failed");
            break;
        }
    }
    buf[index] = 0;

    return (index + 1); // + 1 to indicate # of bytes actually copied
}

int read_line(FILE *F, char *buf, int buf_size)
{
    int index = 0;
    int ch    = 0;

    // while we haven't overflowed the buffer
    // (we do -1 to leave space for null character at the end)
    while (index < (buf_size - 1)) {
        ch = fgetc(F);

        if (ch == EOF) break; // if we hit the end of file, then break

        // if we have hit the end of the line
        if ((ch == 10) || (ch == 13)) {
            // keep reading until we get passed the end of line chars
            while (((ch == 10) || (ch == 13)) && (ch != EOF)) {
                ch = getc(F);
            }

            // if we still have more of the file to read in, then move back one
            // character
            // so that we are at the beginning of the next line
            if (ch != EOF) {
                fseek(F, -1, SEEK_CUR);
            }

            break;
        }

        // if the character is part of the current line
        else {
            buf[index++] = (unsigned char)ch;
        }
    }
    buf[index] = 0;

    return (index + 1); // + 1 to indicate # of bytes actually copied
}

const char *read_line(const char *pszInBuf, string &line)
{
    const char *result = NULL;
    unsigned char ch   = 0;
    int idx            = 0;

    line = ""; // initalize it with an empty string

    // go until we reach end of the buffer (or end of line)
    while (pszInBuf[idx] != 0) {
        ch = pszInBuf[idx];

        // if we have hit the end of the line
        if ((ch == 10) || (ch == 13)) {
            // keep reading until we get passed the end of line chars
            while (((ch == 10) || (ch == 13)) && (ch != 0)) {
                ++idx;
                ch = pszInBuf[idx];
            }

            break; // we got our line
        }

        // if the character is part of the current line then add it
        else {
            line = line + (char)ch;
        }
        ++idx;
    }

    // if we aren't at the end of the buffer, return pointer to first character
    // of next line
    if (pszInBuf[idx] != 0) result = pszInBuf + idx;

    return result;
}

// takes a pathname (relative or absolute) + a filename and removes the filename
// itself
// therefore it returns just the path (stored in 'path')
// returns false if there is an error (such as the file having no path)
bool get_path_of_file(string file_with_path, string &path)
{
    bool success = false;
    int index    = file_with_path.length() - 1; // start on last character

    // make sure the file_with_path is at least 2 characters long
    // because otherwise our proceeding calculations could cause a segfault
    if (index > 0) {
        // locate the preceeding / or \ character
        while ((index >= 0) && (file_with_path[index] != '/') &&
               (file_with_path[index] != '\\')) {
            index--;
        }

        // if we found a leading / or \ character
        if (index >= 0) {
            path    = file_with_path.substr(0, index + 1);
            success = true;
        }
    }

    return success;
}

// Isolates a word within an arbitrary string (src_buf)
// 'word' will contain the word it found, 'remaining_line' will contain the rest
// of the line that has yet to be examined
// !!!NOTE : 'src_buf' is assumed to be a single line with no linefeed/carriage
// return characters!!!
// Returns 'true' if a word was found, or 'false' if a word could not be found
// (ie if the string was empty)
bool find_word(const char *src_buf, string &word, string &remaining_line)
{
    bool result     = false;
    int index       = 0;
    int start_index = 0;

    // find beginning of word, skip spaces or tabs
    while (my_is_whitespace(src_buf[index])) {
        index++;
    }

    // make sure we aren't at the end of the string already
    if (src_buf[index] != 0) {
        start_index = index;

        // now go to the end of the current word
        while ((!my_is_whitespace(src_buf[index])) && (src_buf[index] != 0)) {
            index++;
        }

        // this section is a little tricky, so verify that it actually works :)
        word           = src_buf;
        remaining_line = word.substr(index, word.length() - index);
        word           = word.substr(start_index, index - start_index);
        result         = true;
    }

    return result;
}

// Isolates a word within an arbitrary string (src_buf)
// 'word_begin' will point to the beginning of the word, and 'word_length' will
// be how long the word is
// !!!NOTE : 'src_buf' is assumed to be a single line with no linefeed/carriage
// return characters!!!
// Returns 'true' if a word was found, or 'false' if a word could not be found
// (ie if the string was empty)
bool find_word(const char *src_buf, const char **word_begin, int *word_length)
{
    bool result = false;
    int index   = 0;

    *word_length = 0;
    *word_begin  = NULL;

    // find beginning of word, skip spaces or tabs
    while (my_is_whitespace(src_buf[index])) {
        index++;
    }

    // make sure we aren't at the end of the string already
    if (src_buf[index] != 0) {
        *word_begin = &src_buf[index]; // point to beginning of word occurance

        // now go to the end of the current word
        while ((!my_is_whitespace(src_buf[index])) && (src_buf[index] != 0)) {
            (*word_length)++;
            index++;
        }
        result = true;
    }

    return result;
}

// miniature version of isspace() because we don't want to consider
// linefeeds/carriage returns to be whitespace
bool my_is_whitespace(char ch)
{
    if ((ch == ' ') || (ch == '\t'))
        return true;
    else
        return false;
}
