/
Sapphire/bin/
Sapphire/db/
Sapphire/db/OLC_rooms/
Sapphire/db/abi/
Sapphire/db/em_src/
Sapphire/db/helps/
Sapphire/db/helps/emman/ifunc/
Sapphire/db/npcs/Tatt/
Sapphire/db/objects/Tatt/
Sapphire/db/q_data/
Sapphire/db/rooms/Tatt/
Sapphire/doc/
Sapphire/doc/em/
Sapphire/etc/
Sapphire/src/abic/
Sapphire/src/areacon/
Sapphire/src/client/
Sapphire/src/embc/
Sapphire/src/emi/
Sapphire/src/emi/test/
Sapphire/src/include/
Sapphire/src/sapphire/em/
Sapphire/src/tcon/
/*
 * Copyright (C) 1995-1997 Christopher D. Granz
 *
 * This header may not be removed.
 *
 * Refer to the file "License" included in this package for further
 * information and before using any of the following.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>

#include "sapphire.h"


/*
 * Functions
 */

/*
 * Trys to open a file and checks for errors.  If bError is equal to
 * TRUE, it will report errors and exit.
 */
FILE *open_file( char *pFilename, char *pFlags, bool bError )
{
    FILE *pFile;

    if ( ( pFile = fopen( pFilename, pFlags ) ) == NULL )
    {
        if ( bError == TRUE )
            sap_fatal( "Open file: %s: %s.", pFilename,
              strerror( errno ) );
        else
            return ( NULL );
    }

    pCOFilename  = str_dup( pFilename );
    lCurrentLine = 1;

    return ( pFile );
}


/*
 * Trys to close a file and checks for errors (very unlikely with
 * fclose().)
 */
void close_file( FILE *pFile )
{
    if ( fclose( pFile ) != 0 )
        sap_error( "Close file: %s: %s.", pCOFilename,
          strerror( errno ) );

    str_free( pCOFilename );
    pCOFilename = EMPTY_STRING;
}


/*
 * Gets one letter from a file.
 */
char fget_letter( FILE *pFile )
{
    char c;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( '\0' );
        }

        c = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c ) != 0 );

    return ( c );
}


/*
 * Gets one word (terminated by a space) from a file.
 */
char *fget_word( FILE *pFile )
{
    char *pOutput = new_buffer( );
    char c        = '\0';
    int i;

    do
    {
        if ( feof( pFile ) != 0 )
            break;

        c          = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c ) != 0 );

    for ( i = 0; isspace( c ) == 0; i++ )
    {
        if ( i >= ( MAX_INPUT - 1 ) )
        {
            wcerror( "Read file: Word too long." );
            return ( EMPTY_STRING );
        }

        if ( feof( pFile ) != 0 )
            break;

        pOutput[i] = c;
        c          = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }

    pOutput[i]     = '\0';

    return ( pOutput );
}


char *sfget_word( FILE *pFile )
{
    static char cOutput[MAX_INPUT];
    char c         = '\0';
    int i;

    do
    {
        if ( feof( pFile ) != 0 )
            break;

        c          = getc( pFile );
    }
    while ( isspace( c ) != 0 );

    for ( i = 0; isspace( c ) == 0; i++ )
    {
        if ( i >= ( MAX_INPUT - 1 ) )
        {
            wcerror( "Read file: Word too long." );
            return ( EMPTY_STRING );
        }

        if ( feof( pFile ) != 0 )
            break;

        cOutput[i] = c;
        c          = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }

    cOutput[i]     = '\0';

    return ( cOutput );
}


/*
 * Same as fget_word() accept stops read when other special characters
 * besides spaces are read.
 */
char *fget_word_2( FILE *pFile )
{
    char *pOutput = new_buffer( );
    char c        = '\0';
    int i;

    do
    {
        if ( feof( pFile ) != 0 )
            break;

        c          = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c ) != 0 );

    for ( i = 0; isspace( c ) == 0; i++ )
    {
        if ( c == ';' )
        {
            ungetc( ';', pFile );
            break;
        }

        if ( i >= ( MAX_INPUT - 1 ) )
        {
            wcerror( "Read file: Word too long." );
            return ( EMPTY_STRING );
        }

        if ( feof( pFile ) != 0 )
            break;

        pOutput[i] = c;
        c          = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }

    pOutput[i]     = '\0';

    return ( pOutput );
}


/*
 * Prints a string to a file in the format fget_string() reads.
 */
void fput_string( FILE *pFile, char *pFormat, ... )
{
    va_list pArgs;
    char cBuf[MAX_STRING];
    int i;

    va_start( pArgs, pFormat );
    vsnprintf( cBuf, MAX_STRING, pFormat, pArgs );
    putc( '\"', pFile );

    for ( i = 0; cBuf[i] != '\0'; i++ )
    {
        switch ( cBuf[i] )
        {
          case '\\': putc( '\\', pFile ); putc( '\\', pFile ); break;
          case '"' : putc( '\\', pFile ); putc( '"', pFile );  break;
          case '\n':
              putc( '\\', pFile );
              putc( 'n', pFile );

              if ( cBuf[i + 1] != '\r' )
                  putc( '\n', pFile );

              break;

          case '\r':
              putc( '\\', pFile );
              putc( 'r', pFile );

              if ( i > 0 && cBuf[i - 1] == '\n' )
                  putc( '\n', pFile );

              break;

          case '\t': putc( '\\', pFile ); putc( 't', pFile );  break;
          case '\a': putc( '\\', pFile ); putc( 'a', pFile );  break;
          default  : putc( cBuf[i], pFile );                   break;
        }
    }

    putc( '\"', pFile );
    va_end( pArgs );
}


/*
 * Gets a formatted string from a file.
 */
char *fget_string( FILE *pFile )
{
    char *pOutput = new_buffer( );
    char c[2]     = { '\0', '\0' };
    int i;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( EMPTY_STRING );
        }

        c[0]       = getc( pFile );

        if ( c[0] == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c[0] ) != 0 );

    if ( c[0] != '"' )
    {
        wcerror( "Read file: Symbol `\"' not found." );
        return ( EMPTY_STRING );
    }

    c[0]               = getc( pFile );

    if ( c[0] == '\n' )
        lCurrentLine++;

    if ( c[0] == '"' )
        return ( EMPTY_STRING );

    for ( i = 0; ; i++ )
    {
        if ( i >= ( MAX_STRING - 1 ) )
        {
            wcerror( "Read file: String too long." );
            return ( EMPTY_STRING );
        }

        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( EMPTY_STRING );
        }

        if ( c[0] == '\\' )
        {
            switch ( ( c[0] = getc( pFile ) ) )
            {
              case '\\': pOutput[i] = '\\'; break;
              case '"' : pOutput[i] = '"';  break;
              case 'n' : pOutput[i] = '\n'; break;
              case 'r' : pOutput[i] = '\r'; break;
              case 't' : pOutput[i] = '\t'; break;
              case 'a' : pOutput[i] = '\a'; break;
              default  :
                  wcerror( "Read file: Unknown escape '\\%s'.", c );
                  break;
            }

            if ( feof( pFile ) != 0 )
            {
                wcerror( "Read file: Unexpected EOF." );
                return ( EMPTY_STRING );
            }
        }
        else if ( c[0] != '\n' && c[0] != '\r' && c[0] != '\t' )
            pOutput[i] = c[0];
        else
            i--;

        c[0]           = getc( pFile );

        if ( c[0] == '\n' )
            lCurrentLine++;

        if ( c[0] == '"' )
            break;
    }

    pOutput[i + 1]     = '\0';

    return ( pOutput );
}


char *sfget_string( FILE *pFile )
{
    static char cOutput[MAX_STRING];
    char c[2]      = { '\0', '\0' };
    int i;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( EMPTY_STRING );
        }

        c[0]       = getc( pFile );

        if ( c[0] == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c[0] ) != 0 );

    if ( c[0] != '"' )
    {
        wcerror( "Read file: Symbol `\"' not found." );
        return ( EMPTY_STRING );
    }

    c[0]               = getc( pFile );

    if ( c[0] == '\n' )
        lCurrentLine++;

    if ( c[0] == '"' )
        return ( EMPTY_STRING );

    for ( i = 0; ; i++ )
    {
        if ( i >= ( MAX_STRING - 1 ) )
        {
            wcerror( "Read file: String too long." );
            return ( EMPTY_STRING );
        }

        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( EMPTY_STRING );
        }

        if ( c[0] == '\\' )
        {
            switch ( ( c[0] = getc( pFile ) ) )
            {
              case '\\': cOutput[i] = '\\'; break;
              case '"' : cOutput[i] = '"';  break;
              case 'n' : cOutput[i] = '\n'; break;
              case 'r' : cOutput[i] = '\r'; break;
              case 't' : cOutput[i] = '\t'; break;
              case 'a' : cOutput[i] = '\a'; break;
              default  :
                  wcerror( "Read file: Unknown escape '\\%s'.", c );
                  break;
            }

            if ( feof( pFile ) != 0 )
            {
                wcerror( "Read file: Unexpected EOF." );
                return ( EMPTY_STRING );
            }
        }
        else if ( c[0] != '\n' && c[0] != '\r' && c[0] != '\t' )
            cOutput[i] = c[0];
        else
            i--;

        c[0]           = getc( pFile );

        if ( c[0] == '\n' )
            lCurrentLine++;

        if ( c[0] == '"' )
            break;
    }

    cOutput[i + 1]     = '\0';

    return ( cOutput );
}


/*
 * Reads a string.  The next non-whitespace character in the file
 * must be cFrom or there will be an error.  Fget_string_2() stops
 * reading when cTo is reached in the file stream.
 *
 * Fget_string_2() will deal with nesting.  Example (using `[' as
 * cFrom and `]' as cTo):
 *
 * [string1[nested1][nested2]]
 *
 */
char *fget_string_2( FILE *pFile, char cFrom, char cTo )
{
    char *pOutput           = new_buffer( );
    char cFStr[2]           = { '\0', '\0' };
    char cQuote             = '\0';
    int iChar;
    int iCount              = 0;
    int i;

    cFStr[0]                = cFrom;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( EMPTY_STRING );
        }

        iChar               = getc( pFile );

        if ( iChar == '\n' )
            lCurrentLine++;
    }
    while ( isspace( iChar ) != 0 );

    if ( iChar != cFrom )
    {
        wcerror( "Read file: Expected character `%s' not found.",
          cFStr );
        ungetc( iChar, pFile );
        return ( EMPTY_STRING );
    }

    for ( i = 0; ; i++ )
    {
        if ( i >= ( MAX_STRING - 1 ) )
        {
            wcerror( "Read file: String too long." );
            return ( EMPTY_STRING );
        }

        switch ( ( iChar = getc( pFile ) ) )
        {
          case EOF :
              wcerror( "Read file: Unexpected EOF." );
              return ( EMPTY_STRING );

          case '"' :
              if ( cQuote == '\0' )
                  cQuote    = '"';
              else if ( cQuote != '\'' )
                  cQuote    = '\0';

              break;

          case '\'':
              if ( cQuote == '\0' )
                  cQuote    = '\'';
              else if ( cQuote != '"' )
                  cQuote    = '\0';

              break;

          case '\n':
              lCurrentLine++;
              /* There should not be a break here. */

          case '\r':
          case '\t':
              if ( cQuote != '\0' )
                  iChar     = ' ';

              break;

          case '\\':
              if ( cQuote != '\0' )
              {
                  pOutput[i++] = '\\';

                  if ( i >= ( MAX_STRING - 1 ) )
                  {
                      wcerror( "Read file: String too long." );
                      return ( EMPTY_STRING );
                  }

                  switch ( ( iChar = getc( pFile ) ) )
                  {
                    case EOF:
                        wcerror( "Read file: Unexpected EOF." );
                        return ( EMPTY_STRING );

                    case '\\':
                    case '"' :
                    case '\'':
                        break;

                    default  :
                        i--;
                        ungetc( iChar, pFile );
                        iChar = '\\';
                        break;
                  }
              }

          default  :
              break;
        }

        if ( cQuote == '\0' )
        {
            if ( iChar == cTo )
            {
                if ( iCount != 0 )
                    iCount--;
                else
                    break;
            }
            else if ( iChar == cFrom )
                iCount++;
        }

        pOutput[i]          = iChar;
    }

    pOutput[i]              = '\0';
    return ( pOutput );
}


/*
 * Same as fget_string_2() except does not have a limited string size.
 * Uses alloc_mem() instead of new_buffer() so the caller needs to deal
 * with freeing the allocate space.  String size is only limited by how
 * much alloc_mem() can allocate.
 */
char *fget_string_3( FILE *pFile, char cFrom, char cTo )
{
    char *pOutput   = alloc_mem( MAX_STRING );
    char *pBuf      = pOutput;
    char cFStr[2]   = { '\0', '\0' };
    char cQuote     = '\0';
    int iChar;
    int iMem        = 1;
    int iCount      = 0;
    int i;

    cFStr[0]        = cFrom;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            free_mem( (void **) &pOutput );
            return ( EMPTY_STRING );
        }

        iChar       = getc( pFile );

        if ( iChar == '\n' )
            lCurrentLine++;
    }
    while ( isspace( iChar ) != 0 );

    if ( iChar != cFrom )
    {
        wcerror( "Read file: Expected character `%s' not found.",
          cFStr );
        ungetc( iChar, pFile );
        free_mem( (void **) &pOutput );
        return ( EMPTY_STRING );
    }

    for ( i = 0; ; i++ )
    {
        if ( i >= ( MAX_STRING - 1 ) )
        {
            pOutput = realloc_mem( pOutput, ( MAX_STRING * ++iMem ) );
            pBuf    = ( pOutput + ( MAX_STRING * iMem ) );
        }

        switch ( ( iChar = getc( pFile ) ) )
        {
          case EOF :
              wcerror( "Read file: Unexpected EOF." );
              free_mem( (void **) &pOutput );
              return ( EMPTY_STRING );

          case '"' :
              if ( cQuote == '\0' )
                  cQuote    = '"';
              else if ( cQuote != '\'' )
                  cQuote    = '\0';

              break;

          case '\'':
              if ( cQuote == '\0' )
                  cQuote    = '\'';
              else if ( cQuote != '"' )
                  cQuote    = '\0';

              break;

          case '\n':
              lCurrentLine++;
              /* There should not be a break here. */

          case '\r':
          case '\t':
              if ( cQuote != '\0' )
                  iChar     = ' ';

              break;

          case '\\':
              if ( cQuote != '\0' )
              {
                  pBuf[i++]   = '\\';

                  if ( i >= ( MAX_STRING - 1 ) )
                  {
                      pOutput = realloc_mem( pOutput,
                                  ( MAX_STRING * ++iMem ) );
                      pBuf    = ( pOutput + ( MAX_STRING * iMem ) );
                  }

                  switch ( ( iChar = getc( pFile ) ) )
                  {
                    case EOF:
                        wcerror( "Read file: Unexpected EOF." );
                        free_mem( (void **) &pOutput );
                        return ( EMPTY_STRING );

                    case '\\':
                    case '"' :
                    case '\'':
                        break;

                    default  :
                        i--;
                        ungetc( iChar, pFile );
                        iChar = '\\';
                        break;
                  }
              }

          default  :
              break;
        }

        if ( cQuote == '\0' )
        {
            if ( iChar == cTo )
            {
                if ( iCount != 0 )
                    iCount--;
                else
                    break;
            }
            else if ( iChar == cFrom )
                iCount++;
        }

        pBuf[i] = iChar;
    }

    pBuf[i]     = '\0';
    pOutput     = realloc_mem( pOutput, ( strlen( pOutput ) + 1 ) );

    return ( pOutput );
}


/*
 * Gets a number from a file.
 */
long fget_number( FILE *pFile )
{
    char cBuf[MAX_INPUT];
    long lOutput;
    char c;
    int i;
    bool b      = FALSE;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( 0 );
        }

        c       = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c ) != 0 );

    if ( c == '+' )
        c       = getc( pFile );
    else if ( c == '-' )
    {
        b       = TRUE;
        c       = getc( pFile );
    }

    for ( i = 0; isdigit( c ); i++ )
    {
        if ( i >= ( MAX_INPUT - 1 ) )
        {
            wcerror( "Read file: Word too long." );
            return ( 0 );
        }

        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( 0 );
        }

        cBuf[i] = c;
        c       = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }

    cBuf[i]     = '\0';

    if ( cBuf[0] == '\0' )
    {
        wcerror( "Read file: Number not found." );
        return ( 0 );
    }

    lOutput     = atol( cBuf );

    return ( ( b == TRUE ? -lOutput : lOutput ) );
}


/*
 * Same as fget_number() accept calls ungetc() when there are no more
 * digits left to read.
 */
long fget_number_2( FILE *pFile )
{
    char cBuf[MAX_INPUT];
    long lOutput;
    char c;
    int i;
    bool b      = FALSE;

    do
    {
        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( 0 );
        }

        c       = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }
    while ( isspace( c ) != 0 );

    if ( c == '+' )
        c       = getc( pFile );
    else if ( c == '-' )
    {
        b       = TRUE;
        c       = getc( pFile );
    }

    for ( i = 0; isdigit( c ); i++ )
    {
        if ( i >= ( MAX_INPUT - 1 ) )
        {
            wcerror( "Read file: Word too long." );
            return ( 0 );
        }

        if ( feof( pFile ) != 0 )
        {
            wcerror( "Read file: Unexpected EOF." );
            return ( 0 );
        }

        cBuf[i] = c;
        c       = getc( pFile );

        if ( c == '\n' )
            lCurrentLine++;
    }

    ungetc( c, pFile );
    cBuf[i]     = '\0';

    if ( cBuf[0] == '\0' )
    {
        wcerror( "Read file: Number not found." );
        return ( 0 );
    }

    lOutput     = atol( cBuf );

    return ( ( b == TRUE ? -lOutput : lOutput ) );
}


/*
 * End of fileio.c
 */