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 >
Text File  |  1989-01-14  |  11KB  |  306 lines

  1. /*                       Listing 1 -- File HEXIO.C                          */
  2. /*
  3.               Intel Hex and Motorola S-Record File I/O Functions
  4.  
  5.                           By William C. Colley, III
  6.  
  7.      This package of functions presents an interface to two ASCII hexadecimal
  8. absolute object module formats that is as close to the traditional stream I/O
  9. interface as I could make it.  The two formats are the Intel hexadecimal
  10. object module format (Intel hex) and the Motorola S-Record object module
  11. format (S-record).  The functions and data structure of the package are
  12. declared in a companion header file, hexio.h.  The functions in the package
  13. are:
  14.  
  15.         HFILE *fopen(filename,mode)
  16.         char *filename, *mode;
  17.  
  18.      Use this function to open a hex file just as you use fopen() to open a
  19. normal stream file.  The following access modes are supported:
  20.                                         
  21.         "r" or "ri"     open Intel hex file for reading
  22.  
  23.         "rs"            open S-record file for reading
  24.  
  25.         "w" or "wi"     open Intel hex file for writing -- If the file exists,
  26.                         it is truncated to 0 length first.
  27.  
  28.         "ws"            open S-record file for writing -- If the file exists,
  29.                         it is truncated to 0 length first.
  30.  
  31.     The return parameter is used as a file handle just like the return value
  32. of fopen() is.  A return value of NULL indicates that the file could not be
  33. opened.  See your compiler's documentation on function fopen() for details.
  34.  
  35.         int hclose(filehandle)
  36.         HFILE *filehandle;
  37.  
  38.     Use this function to close a hex file when you are finished with it.  It
  39. returns 0 if no errors have occurred since the file was opened and if the file
  40. has been successfully closed.  Otherwise, the function returns HEOF.
  41.  
  42.         int hgetc(filehandle)
  43.         HFILE *filehandle;
  44.  
  45.      Use this function to retreive the next data byte from a hex file that
  46. has been opened for reading.  A return value of 0 - 255 is a valid byte.  A
  47. return value of HEOF indicates that a read error occurred on the file.  Some
  48. possible causes are an error from getc(), an illegal character in the file,
  49. or a checksum that doesn't check.
  50.  
  51.          int hputc(byte,filehandle)
  52.          unsigned char byte;
  53.          HFILE *filehandle;
  54.  
  55.      Use this function to write the next data byte to a hex file that has
  56. been opened for writing.  A return value of 0 - 255 is the byte that was
  57. written to the file.  A return value of HEOF indicates that a write error
  58. occurred on the file.  The error comes from putc().
  59.  
  60.         void hseek(filehandle,address)
  61.         HFILE *filehandle;
  62.         unsigned address;
  63.  
  64.      Use this function before using hputc() to set the load address for the
  65. following byte written to the file.  If hseek() is not used, the first byte
  66. written to the file is assigned a load address of 0x0000, and the rest load
  67. in sequence after their preceding bytes.  Use of this function on a file
  68. opened for reading has no effect.
  69.  
  70.         unsigned htell(filehandle)
  71.  
  72.      Use this function after using hgetc() to find out the load address of
  73. the byte that the previous call to hgetc() returned.  Use of this function on
  74. a file opened for writing will return the load address of the last byte
  75. written to the file with hputc().
  76.  
  77.         int herror(filehandle)
  78.         HFILE *filehandle;
  79.  
  80.     Use this function to determine if an error has occurred on this hex file
  81. since it was opened.  The function returns HEOF if an error has occurred or 0
  82. otherwise.
  83.  
  84.         int heof(filehandle)
  85.         HFILE *filehandle;
  86.  
  87.     Use this function to determine if a file opened for reading has been read
  88. all the way to end of file yet.  The function returns HEOF if end of file has
  89. been reached or 0 if more data may be left.  The function always returns 0 for
  90. files opened for writing.
  91. */
  92.  
  93. /*  Note that the names of the following #include file sometimes varies */
  94. /*  from system to system.  Adjust it as needed to fit yours.           */
  95.  
  96. #include <alloc.h>              /*  often called malloc.h               */
  97. #include <ctype.h>              /*  usually called ctype.h              */
  98. #include <setjmp.h>             /*  always called setjmp.h              */
  99. #include "hexio.h"              /*  #include our own header file, too.  */
  100.  
  101. /*  This defines the bits in the flag byte of the HFILE structure:      */
  102.  
  103. #define WRITE           0x01    /*  bit 0 set if file open for writing  */
  104. #define SRECORD         0x02    /*  bit 1 set if file is S-record type  */
  105. #define ERROR           0x04    /*  bit 2 set if an error has occurred  */
  106. #define AT_EOF          0x08    /*  bit 3 set if we've read to EOF      */
  107.  
  108. /*  Some static variables to allow data sharing amongst the routines    */
  109. /*  and their service routines:                                         */
  110.  
  111. static unsigned char chksum;
  112. static jmp_buf error;
  113.  
  114. /*  Finally, the routines themselves:                                   */
  115.  
  116. HFILE *hopen(filename,mode)
  117. char *filename, *mode;
  118. {
  119.     unsigned char tflags;
  120.     HFILE *filehandle;
  121.  
  122.     tflags = 0;
  123.     switch (toupper(mode[0])) {
  124.         case 'W':   tflags += WRITE;
  125.         case 'R':   break;
  126.  
  127.         default:    return NULL;
  128.     }
  129.     switch (toupper(mode[1])) {
  130.         case 'S':   tflags += SRECORD;
  131.         case 'I':
  132.         case '\0':  break;
  133.  
  134.         default:    return NULL;
  135.     }
  136.     if (filehandle = (HFILE *)malloc(sizeof(HFILE))) {
  137.         mode[1] = '\0';
  138.         if (filehandle->file = fopen(filename,mode)) {
  139.             if ((tflags & (SRECORD + WRITE)) != (SRECORD + WRITE) ||
  140.                 fputs("S007000048445239E1\n",filehandle->file) != EOF) {
  141.                 filehandle->loadaddr = filehandle->count = 0;
  142.                 filehandle->bufp = filehandle->buf;
  143.                 filehandle->flags = tflags;  return filehandle;
  144.             }
  145.             fclose(filehandle->file);
  146.         }
  147.         free(filehandle);
  148.     }
  149.     return NULL;
  150. }
  151.  
  152. /*  This routine is for use by hgetc() only, so it's declared static.    */
  153.  
  154. static int hgetb(filehandle)
  155. HFILE *filehandle;
  156. {
  157.     int c, d;
  158.  
  159.     if ((c = getc(filehandle->file)) == EOF || !isxdigit(c) || islower(c))
  160.         longjmp(error,ERROR);
  161.     c = c - (isdigit(c) ? '0' : 'A' - 10) << 4;
  162.     if ((d = getc(filehandle->file)) == EOF || !isxdigit(d) || islower(d))
  163.         longjmp(error,ERROR);
  164.     chksum += c += d - (isdigit(d) ? '0' : 'A' - 10);
  165.     return c;
  166. }
  167.  
  168. int hgetc(filehandle)
  169. HFILE *filehandle;
  170. {
  171.     int c, t;
  172.     unsigned char *p;
  173.  
  174.     if (setjmp(error) || filehandle->flags & (AT_EOF + ERROR + WRITE)) {
  175.         filehandle->flags |= ERROR;  return HEOF;
  176.     }
  177.     while (!filehandle->count--) {
  178.         while ((c = getc(filehandle->file)) !=
  179.             (filehandle->flags & SRECORD ? 'S' : ':'))
  180.             if (c == EOF) longjmp(error,ERROR);
  181.         if (filehandle->flags & SRECORD) {
  182.             if ((t = getc(filehandle->file)) != '0' && t != '1' && t != '9')
  183.                 longjmp(error,ERROR);
  184.             chksum = 1;  c = -3;
  185.         }
  186.         else chksum = c = 0;
  187.         filehandle->count = c += hgetb(filehandle);
  188.         filehandle->loadaddr = hgetb(filehandle) << 8;
  189.         filehandle->loadaddr += hgetb(filehandle);
  190.         if (!(filehandle->flags & SRECORD))
  191.             if ((t = hgetb(filehandle)) != 0 && t != 1) longjmp(error,ERROR);
  192.             else t = (t << 3) + '1';
  193.         p = filehandle->bufp = filehandle->buf;
  194.         while (c--) *p++ = hgetb(filehandle);
  195.         (void)hgetb(filehandle);
  196.         if (chksum) longjmp(error,ERROR);
  197.         if (t == '0') filehandle->count = 0;
  198.         if (t == '9') { filehandle->flags |= AT_EOF;  return HEOF; }
  199.     }
  200.     filehandle->loadaddr = filehandle->loadaddr + 1 & 0xffff;
  201.     return *filehandle->bufp++;
  202. }
  203.  
  204. /*  This routine is for use by put_record() only, so it's declared static.  */
  205.  
  206. static void hputb(byte,filehandle)
  207. unsigned char byte;
  208. HFILE *filehandle;
  209. {
  210.     static char digits[] = "0123456789ABCDEF";
  211.  
  212.     chksum += byte;
  213.     if (putc(digits[byte >> 4],filehandle->file) == EOF ||
  214.         putc(digits[byte & 0x0f],filehandle->file) == EOF)
  215.         longjmp(error,ERROR);
  216. }
  217.  
  218. /*  This routine is for use by hputc(), hseek(), and hclose() only, so it's */
  219. /*  declared static.                                                        */
  220.  
  221. static void put_record(type,filehandle)
  222. char type;
  223. HFILE *filehandle;
  224. {
  225.     unsigned a;
  226.  
  227.     if (filehandle->flags & SRECORD) {
  228.         if (putc('S',filehandle->file) == EOF ||
  229.             putc(type,filehandle->file) == EOF) longjmp(error,ERROR);
  230.         chksum = 1;  hputb(filehandle->count + 3,filehandle);
  231.     }
  232.     else {
  233.         if (putc(':',filehandle->file) == EOF) longjmp(error,ERROR);
  234.         chksum = 0;  hputb(filehandle->count,filehandle);
  235.     }
  236.     a = (filehandle->loadaddr - filehandle->count) & 0xffff;
  237.     hputb(a >> 8,filehandle);  hputb(a & 0xff,filehandle);
  238.     if (!(filehandle->flags & SRECORD)) hputb(type == '9',filehandle);
  239.     
  240.     for (filehandle->bufp = filehandle->buf; filehandle->count;
  241.         --filehandle->count) hputb(*filehandle->bufp++,filehandle);
  242.     hputb(-chksum,filehandle);
  243.     if (putc('\n',filehandle->file) == EOF) longjmp(error,ERROR);
  244.     filehandle->bufp = filehandle->buf;
  245. }
  246.  
  247. int hputc(byte,filehandle)
  248. unsigned char byte;
  249. HFILE *filehandle;
  250. {
  251.     if (setjmp(error) || (filehandle->flags & (ERROR + WRITE)) != WRITE) {
  252.         filehandle->flags |= ERROR;  return HEOF;
  253.     }
  254.     *filehandle->bufp++ = byte;
  255.     filehandle->loadaddr = filehandle->loadaddr + 1 & 0xffff;
  256.     if (++filehandle->count == HEXRECSIZE) put_record('1',filehandle);
  257.     return byte;
  258. }
  259.  
  260. void hseek(filehandle,address)
  261. HFILE *filehandle;
  262. unsigned address;
  263. {
  264.     if (setjmp(error)) filehandle->flags |= ERROR;
  265.     if ((filehandle->flags & (ERROR + WRITE)) == WRITE &&
  266.         filehandle->loadaddr != address) {
  267.         if (filehandle->count) put_record('1',filehandle);
  268.         filehandle->loadaddr = address;
  269.     }
  270. }
  271.  
  272. int hclose(filehandle)
  273. HFILE *filehandle;
  274. {
  275.     int i;
  276.  
  277.     if (i = setjmp(error)) {
  278.         if (fclose(filehandle->file)) i = ERROR;
  279.         i = ((filehandle->flags | i) & ERROR) ? HEOF : 0;
  280.         free(filehandle);  return i;
  281.     }
  282.     if (filehandle->flags & WRITE) {
  283.         if (filehandle->count) put_record('1',filehandle);
  284.         put_record('9',filehandle);
  285.     }
  286.     longjmp(error,AT_EOF);  
  287. }
  288.  
  289. unsigned htell(filehandle)
  290. HFILE *filehandle;
  291. {
  292.     return (filehandle->loadaddr - 1) & 0xffff;
  293. }
  294.  
  295. int herror(filehandle)
  296. HFILE *filehandle;
  297. {
  298.     return filehandle->flags & ERROR ? HEOF : 0;
  299. }
  300.  
  301. int heof(filehandle)
  302. HFILE *filehandle;
  303. {
  304.     return filehandle->flags & AT_EOF ? HEOF : 0;
  305. }
  306.