saturnng/src/disk_io_obj.c
2024-10-10 16:45:44 +02:00

281 lines
9.5 KiB
C

/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
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 the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: disk_io_obj.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: disk_io_obj.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : IRITI-CNR
.creation : 10-Nov-2000
.keywords : *
.description :
This module implements the disk I/O functions used by the emulator to
save and restore an object to/from disk files.
.include : config.h, machdep.h, cpu.h, disk_io.h
.notes :
$Log: disk_io_obj.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.14 2000/11/13 11:24:20 cibrario
*** empty log message ***
.- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libChf/src/Chf.h"
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "disk_io.h"
#include "debug.h"
/* .+
.title : ReadObjectFromFile
.kind : C function
.creation : 10-Nov-2000
.description :
This function reads an object from file 'name' and stores it into
the calculator's memory from nibble address 'start' inclusive to nibble
address 'end' exclusive.
The presence of header 'hdr' in the disk file is checked, then the
header is stripped before starting the transfer. In 'hdr', '?'
is a wildcard character that matches any input character.
Objects with an odd number of nibbles are padded to an even
size adding a 0 nibble to their end; the trailing zero *is* stored
in calculator's memory.
When the object size exceeds the available space this function
transfers its head anyway, thereby corrupting the calculator's
memory between 'start' and 'end', except the first N_SAVE_AREA nibbles.
This function returns to the caller a status code.
.call :
st = ReadObjectFromFile(name, hdr, start, end);
.input :
const char *name, input file name
const char *hdr, file header
Address start, start address (inclusive)
Address end, end address (exclusive)
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_GETC
DISK_IO_E_BAD_HDR
DISK_IO_E_SIZE
.notes :
3.14, 10-Nov-2000, creation
.- */
int ReadObjectFromFile( const char* name, const char* hdr, Address start, Address end )
{
size_t hdr_len = strlen( hdr );
FILE* f;
int i;
int by;
Address cur;
#define N_SAVE_AREA 10
Nibble save_area[ N_SAVE_AREA ];
int st = DISK_IO_S_OK;
debug1( DISK_IO_CHF_MODULE_ID, DEBUG_C_TRACE, DISK_IO_I_CALLED, "ReadObjectFromFile" );
/* Save first nibbles of target space into save_area */
for ( cur = start, i = 0; cur < end && i < N_SAVE_AREA; cur++, i++ )
save_area[ i ] = ReadNibble( cur );
if ( ( f = fopen( name, "rb" ) ) == ( FILE* )NULL ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_OPEN, CHF_ERROR, name );
} else {
/* Check and skip header */
for ( i = 0; i < ( int )hdr_len; i++ ) {
by = getc( f );
if ( by == EOF ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_GETC, CHF_ERROR, name );
break;
} else if ( hdr[ i ] != '?' && by != hdr[ i ] ) {
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_BAD_HDR, CHF_ERROR, name );
break;
}
}
if ( st == DISK_IO_S_OK ) {
cur = start;
/* Header check/skip OK; transfer */
while ( ( by = getc( f ) ) != EOF ) {
/* Next byte available in by; check available space */
if ( cur >= end - 1 ) {
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_SIZE, CHF_ERROR, name );
break;
}
/* Store it */
WriteNibble( cur++, ( Nibble )( by & 0x0F ) );
WriteNibble( cur++, ( Nibble )( ( by & 0xF0 ) >> 4 ) );
}
/* Check why getc() failed */
if ( ferror( f ) && !feof( f ) ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_GETC, CHF_ERROR, name );
}
/* Recover from save_area if transfer failed */
if ( st )
for ( cur = start, i = 0; cur < end && i < N_SAVE_AREA; cur++, i++ )
WriteNibble( cur, save_area[ i ] );
}
( void )fclose( f );
}
return st;
}
/* .+
.title : WriteObjectToFile
.kind : C function
.creation : 10-Nov-2000
.description :
This function writes an object located in calculator's memory,
from nibble address 'start' inclusive to nibble address 'end' exclusive,
into the file 'name'. The header 'hdr' is prepended to the actual
object and objects with an odd number of nibbles are padded to an even
size adding a 0 nibble to their end. In 'hdr', the wildcard character
'?' is replaced by 'S' when the header is written on disk.
This function returns to the caller a status code.
.call :
st = WriteObjectToFile(start, end, hdr, name);
.input :
Address start, start address (inclusive)
Address end, end address (exclusive)
const char *hdr, file header
const char *name, output file name
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_PUTC
DISK_IO_E_CLOSE
.notes :
3.14, 10-Nov-2000, creation
.- */
int WriteObjectToFile( Address start, Address end, const char* hdr, const char* name )
{
size_t hdr_len = strlen( hdr );
FILE* f;
int i;
int by;
Address cur;
int st = DISK_IO_S_OK;
debug1( DISK_IO_CHF_MODULE_ID, DEBUG_C_TRACE, DISK_IO_I_CALLED, "WriteObjectFromFile" );
if ( ( f = fopen( name, "wb" ) ) == ( FILE* )NULL ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_OPEN, CHF_ERROR, name );
} else {
/* Write header; replace wildcard character '?' with 'S' */
for ( i = 0; i < ( int )hdr_len; i++ ) {
if ( putc( hdr[ i ] == '?' ? 'S' : hdr[ i ], f ) == EOF ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_PUTC, CHF_ERROR, name );
break;
}
}
if ( st == DISK_IO_S_OK ) {
cur = start;
while ( cur < end - 1 ) {
/* Make a byte with two nibbles */
by = ( int )ReadNibble( cur++ );
by |= ( int )ReadNibble( cur++ ) << 4;
if ( putc( by, f ) == EOF ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_PUTC, CHF_ERROR, name );
break;
}
}
/* Write the last odd nibble, if necessary */
if ( st == DISK_IO_S_OK && cur == end - 1 ) {
by = ( int )ReadNibble( cur++ );
if ( putc( by, f ) == EOF ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_PUTC, CHF_ERROR, name );
}
}
}
/* Close the output file anyway */
if ( fclose( f ) == EOF ) {
ChfGenerate( CHF_ERRNO_SET, __FILE__, __LINE__, errno, CHF_ERROR );
ChfGenerate( DISK_IO_CHF_MODULE_ID, __FILE__, __LINE__, st = DISK_IO_E_CLOSE, CHF_ERROR, name );
}
}
return st;
}