/* 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 /* often called malloc.h */ #include /* usually called ctype.h */ #include /* 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; }