/*
* 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
*/