/*
**  igmpproxy - IGMP proxy based multicast router
**  Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
**
**  This program 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.
**
**  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 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
**
**----------------------------------------------------------------------------
**
**  This software is derived work from the following software. The original
**  source code has been modified from it's original state by the author
**  of igmpproxy.
**
**  smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
**  - Licensed under the GNU General Public License, either version 2 or
**    any later version.
**
**  mrouted 3.9-beta3 - Copyright (C) 2002 by The Board of Trustees of
**  Leland Stanford Junior University.
**  - Licensed under the 3-clause BSD license, see Stanford.txt file.
**
*/
/**
*   confread.c
*
*   Generic config file reader. Used to open a config file,
*   and read the tokens from it. The parser is really simple,
*   and does no backlogging. This means that no form of
*   text escaping and qouting is currently supported.
*   '#' chars are read as comments, and the comment lasts until
*   a newline or EOF
*
*/

#include "igmpproxy.h"

#define READ_BUFFER_SIZE    512     // Inputbuffer size...

#ifndef MAX_TOKEN_LENGTH
    #define MAX_TOKEN_LENGTH  30    // Default max token length
#endif

FILE            *confFilePtr;       // File handle pointer
char            *iBuffer;           // Inputbuffer for reading...
unsigned int    bufPtr;             // Buffer position pointer.
unsigned int    readSize;           // Number of bytes in buffer after last read...
char    cToken[MAX_TOKEN_LENGTH];   // Token buffer...
short   validToken;

/**
*   Opens config file specified by filename.
*/
int openConfigFile(char *filename) {

    // Set the buffer to null initially...
    iBuffer = NULL;

    // Open the file for reading...
    confFilePtr = fopen(filename, "r");

    // On error, return false
    if(confFilePtr == NULL) {
        return 0;
    }

    // Allocate memory for inputbuffer...
    iBuffer = (char*) malloc( sizeof(char) * READ_BUFFER_SIZE );

    if(iBuffer == NULL) {
        closeConfigFile();
        return 0;
    }

    // Reset bufferpointer and readsize
    bufPtr = 0;
    readSize = 0;

    return 1;
}

/**
*   Closes the currently open config file.
*/
void closeConfigFile(void) {
    // Close the file.
    if(confFilePtr!=NULL) {
        fclose(confFilePtr);
    }
    // Free input buffer memory...
    if(iBuffer != NULL) {
        free(iBuffer);
    }
}

/**
*   Returns the next token from the configfile. The function
*   return NULL if there are no more tokens in the file.
*/
char *nextConfigToken(void) {

    validToken = 0;

    // If no file or buffer, return NULL
    if(confFilePtr == NULL || iBuffer == NULL) {
        return NULL;
    }

    {
        unsigned int tokenPtr       = 0;
        unsigned short finished     = 0;
        unsigned short commentFound = 0;

        // Outer buffer fill loop...
        while ( !finished ) {
            // If readpointer is at the end of the buffer, we should read next chunk...
            if(bufPtr == readSize) {
                // Fill up the buffer...
                readSize = fread (iBuffer, sizeof(char), READ_BUFFER_SIZE, confFilePtr);
                bufPtr = 0;

                // If the readsize is 0, we should just return...
                if(readSize == 0) {
                    return NULL;
                }
            }

            // Inner char loop...
            while ( bufPtr < readSize && !finished ) {

                //printf("Char %s", iBuffer[bufPtr]);

                // Break loop on \0
                if(iBuffer[bufPtr] == '\0') {
                    break;
                }

                if( commentFound ) {
                    if( iBuffer[bufPtr] == '\n' ) {
                        commentFound = 0;
                    }
                } else {

                    // Check current char...
                    switch(iBuffer[bufPtr]) {
                    case '#':
                        // Found a comment start...
                        commentFound = 1;
                        break;

                    case '\n':
                    case '\r':
                    case '\t':
                    case ' ':
                        // Newline, CR, Tab and space are end of token, or ignored.
                        if(tokenPtr > 0) {
                            cToken[tokenPtr] = '\0';    // EOL
                            finished = 1;
                        }
                        break;

                    default:
                        // Append char to token...
                        cToken[tokenPtr++] = iBuffer[bufPtr];
                        break;
                    }
                }

                // Check end of token buffer !!!
                if(tokenPtr == MAX_TOKEN_LENGTH - 1) {
                    // Prevent buffer overrun...
                    cToken[tokenPtr] = '\0';
                    finished = 1;
                }

                // Next char...
                bufPtr++;
            }
            // If the readsize is less than buffersize, we assume EOF.
            if(readSize < READ_BUFFER_SIZE && bufPtr == readSize) {
                if (tokenPtr > 0)
                    finished = 1;
                else
                    return NULL;
            }
        }
        if(tokenPtr>0) {
            validToken = 1;
            return cToken;
        }
    }
    return NULL;
}


/**
*   Returns the currently active token, or null
*   if no tokens are available.
*/
char *getCurrentConfigToken(void) {
    return validToken ? cToken : NULL;
}
