home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_07_04
/
v7n4029a.txt
< prev
next >
Wrap
Text File
|
1989-01-14
|
11KB
|
306 lines
/* Listing 1 -- File HEXIO.C */
/*
Intel Hex and Motorola S-Record File I/O Functions
By William C. Colley, III
This package of functions presents an interface to two ASCII hexadecimal
absolute object module formats that is as close to the traditional stream I/O
interface as I could make it. The two formats are the Intel hexadecimal
object module format (Intel hex) and the Motorola S-Record object module
format (S-record). The functions and data structure of the package are
declared in a companion header file, hexio.h. The functions in the package
are:
HFILE *fopen(filename,mode)
char *filename, *mode;
Use this function to open a hex file just as you use fopen() to open a
normal stream file. The following access modes are supported:
"r" or "ri" open Intel hex file for reading
"rs" open S-record file for reading
"w" or "wi" open Intel hex file for writing -- If the file exists,
it is truncated to 0 length first.
"ws" open S-record file for writing -- If the file exists,
it is truncated to 0 length first.
The return parameter is used as a file handle just like the return value
of fopen() is. A return value of NULL indicates that the file could not be
opened. See your compiler's documentation on function fopen() for details.
int hclose(filehandle)
HFILE *filehandle;
Use this function to close a hex file when you are finished with it. It
returns 0 if no errors have occurred since the file was opened and if the file
has been successfully closed. Otherwise, the function returns HEOF.
int hgetc(filehandle)
HFILE *filehandle;
Use this function to retreive the next data byte from a hex file that
has been opened for reading. A return value of 0 - 255 is a valid byte. A
return value of HEOF indicates that a read error occurred on the file. Some
possible causes are an error from getc(), an illegal character in the file,
or a checksum that doesn't check.
int hputc(byte,filehandle)
unsigned char byte;
HFILE *filehandle;
Use this function to write the next data byte to a hex file that has
been opened for writing. A return value of 0 - 255 is the byte that was
written to the file. A return value of HEOF indicates that a write error
occurred on the file. The error comes from putc().
void hseek(filehandle,address)
HFILE *filehandle;
unsigned address;
Use this function before using hputc() to set the load address for the
following byte written to the file. If hseek() is not used, the first byte
written to the file is assigned a load address of 0x0000, and the rest load
in sequence after their preceding bytes. Use of this function on a file
opened for reading has no effect.
unsigned htell(filehandle)
Use this function after using hgetc() to find out the load address of
the byte that the previous call to hgetc() returned. Use of this function on
a file opened for writing will return the load address of the last byte
written to the file with hputc().
int herror(filehandle)
HFILE *filehandle;
Use this function to determine if an error has occurred on this hex file
since it was opened. The function returns HEOF if an error has occurred or 0
otherwise.
int heof(filehandle)
HFILE *filehandle;
Use this function to determine if a file opened for reading has been read
all the way to end of file yet. The function returns HEOF if end of file has
been reached or 0 if more data may be left. The function always returns 0 for
files opened for writing.
*/
/* Note that the names of the following #include file sometimes varies */
/* from system to system. Adjust it as needed to fit yours. */
#include <alloc.h> /* often called malloc.h */
#include <ctype.h> /* usually called ctype.h */
#include <setjmp.h> /* always called setjmp.h */
#include "hexio.h" /* #include our own header file, too. */
/* This defines the bits in the flag byte of the HFILE structure: */
#define WRITE 0x01 /* bit 0 set if file open for writing */
#define SRECORD 0x02 /* bit 1 set if file is S-record type */
#define ERROR 0x04 /* bit 2 set if an error has occurred */
#define AT_EOF 0x08 /* bit 3 set if we've read to EOF */
/* Some static variables to allow data sharing amongst the routines */
/* and their service routines: */
static unsigned char chksum;
static jmp_buf error;
/* Finally, the routines themselves: */
HFILE *hopen(filename,mode)
char *filename, *mode;
{
unsigned char tflags;
HFILE *filehandle;
tflags = 0;
switch (toupper(mode[0])) {
case 'W': tflags += WRITE;
case 'R': break;
default: return NULL;
}
switch (toupper(mode[1])) {
case 'S': tflags += SRECORD;
case 'I':
case '\0': break;
default: return NULL;
}
if (filehandle = (HFILE *)malloc(sizeof(HFILE))) {
mode[1] = '\0';
if (filehandle->file = fopen(filename,mode)) {
if ((tflags & (SRECORD + WRITE)) != (SRECORD + WRITE) ||
fputs("S007000048445239E1\n",filehandle->file) != EOF) {
filehandle->loadaddr = filehandle->count = 0;
filehandle->bufp = filehandle->buf;
filehandle->flags = tflags; return filehandle;
}
fclose(filehandle->file);
}
free(filehandle);
}
return NULL;
}
/* This routine is for use by hgetc() only, so it's declared static. */
static int hgetb(filehandle)
HFILE *filehandle;
{
int c, d;
if ((c = getc(filehandle->file)) == EOF || !isxdigit(c) || islower(c))
longjmp(error,ERROR);
c = c - (isdigit(c) ? '0' : 'A' - 10) << 4;
if ((d = getc(filehandle->file)) == EOF || !isxdigit(d) || islower(d))
longjmp(error,ERROR);
chksum += c += d - (isdigit(d) ? '0' : 'A' - 10);
return c;
}
int hgetc(filehandle)
HFILE *filehandle;
{
int c, t;
unsigned char *p;
if (setjmp(error) || filehandle->flags & (AT_EOF + ERROR + WRITE)) {
filehandle->flags |= ERROR; return HEOF;
}
while (!filehandle->count--) {
while ((c = getc(filehandle->file)) !=
(filehandle->flags & SRECORD ? 'S' : ':'))
if (c == EOF) longjmp(error,ERROR);
if (filehandle->flags & SRECORD) {
if ((t = getc(filehandle->file)) != '0' && t != '1' && t != '9')
longjmp(error,ERROR);
chksum = 1; c = -3;
}
else chksum = c = 0;
filehandle->count = c += hgetb(filehandle);
filehandle->loadaddr = hgetb(filehandle) << 8;
filehandle->loadaddr += hgetb(filehandle);
if (!(filehandle->flags & SRECORD))
if ((t = hgetb(filehandle)) != 0 && t != 1) longjmp(error,ERROR);
else t = (t << 3) + '1';
p = filehandle->bufp = filehandle->buf;
while (c--) *p++ = hgetb(filehandle);
(void)hgetb(filehandle);
if (chksum) longjmp(error,ERROR);
if (t == '0') filehandle->count = 0;
if (t == '9') { filehandle->flags |= AT_EOF; return HEOF; }
}
filehandle->loadaddr = filehandle->loadaddr + 1 & 0xffff;
return *filehandle->bufp++;
}
/* This routine is for use by put_record() only, so it's declared static. */
static void hputb(byte,filehandle)
unsigned char byte;
HFILE *filehandle;
{
static char digits[] = "0123456789ABCDEF";
chksum += byte;
if (putc(digits[byte >> 4],filehandle->file) == EOF ||
putc(digits[byte & 0x0f],filehandle->file) == EOF)
longjmp(error,ERROR);
}
/* This routine is for use by hputc(), hseek(), and hclose() only, so it's */
/* declared static. */
static void put_record(type,filehandle)
char type;
HFILE *filehandle;
{
unsigned a;
if (filehandle->flags & SRECORD) {
if (putc('S',filehandle->file) == EOF ||
putc(type,filehandle->file) == EOF) longjmp(error,ERROR);
chksum = 1; hputb(filehandle->count + 3,filehandle);
}
else {
if (putc(':',filehandle->file) == EOF) longjmp(error,ERROR);
chksum = 0; hputb(filehandle->count,filehandle);
}
a = (filehandle->loadaddr - filehandle->count) & 0xffff;
hputb(a >> 8,filehandle); hputb(a & 0xff,filehandle);
if (!(filehandle->flags & SRECORD)) hputb(type == '9',filehandle);
for (filehandle->bufp = filehandle->buf; filehandle->count;
--filehandle->count) hputb(*filehandle->bufp++,filehandle);
hputb(-chksum,filehandle);
if (putc('\n',filehandle->file) == EOF) longjmp(error,ERROR);
filehandle->bufp = filehandle->buf;
}
int hputc(byte,filehandle)
unsigned char byte;
HFILE *filehandle;
{
if (setjmp(error) || (filehandle->flags & (ERROR + WRITE)) != WRITE) {
filehandle->flags |= ERROR; return HEOF;
}
*filehandle->bufp++ = byte;
filehandle->loadaddr = filehandle->loadaddr + 1 & 0xffff;
if (++filehandle->count == HEXRECSIZE) put_record('1',filehandle);
return byte;
}
void hseek(filehandle,address)
HFILE *filehandle;
unsigned address;
{
if (setjmp(error)) filehandle->flags |= ERROR;
if ((filehandle->flags & (ERROR + WRITE)) == WRITE &&
filehandle->loadaddr != address) {
if (filehandle->count) put_record('1',filehandle);
filehandle->loadaddr = address;
}
}
int hclose(filehandle)
HFILE *filehandle;
{
int i;
if (i = setjmp(error)) {
if (fclose(filehandle->file)) i = ERROR;
i = ((filehandle->flags | i) & ERROR) ? HEOF : 0;
free(filehandle); return i;
}
if (filehandle->flags & WRITE) {
if (filehandle->count) put_record('1',filehandle);
put_record('9',filehandle);
}
longjmp(error,AT_EOF);
}
unsigned htell(filehandle)
HFILE *filehandle;
{
return (filehandle->loadaddr - 1) & 0xffff;
}
int herror(filehandle)
HFILE *filehandle;
{
return filehandle->flags & ERROR ? HEOF : 0;
}
int heof(filehandle)
HFILE *filehandle;
{
return filehandle->flags & AT_EOF ? HEOF : 0;
}