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