/* This file contains source code to read a Motorola S-record file into ** a memory image. The size of the file cannot exceed BUFSIZE of data. ** The image is then written to disk either as binary data starting at ** address 0 with no data gaps, or as a C array of unsigned longs. ** Input lines must be no longer than MAXLINE. No check is made! ** ** Author: Eric McRae, Electro-Logic Machines, Inc. ** Date: Copyright 1994 ** ** This source code is made available to the public "as is". No ** warranty is given or implied for it's proper operation. This source ** code may be used in whole or in part as long as this copyright is ** included. */ #include #include #include /* Comment the following line for non PC applications */ #define PCDOS /* Uncomment the following line if you want a binary output instead of ** a structure */ /* #define BINARY */ #ifdef PCDOS /* Intel x86 architecture */ #define BUFSIZE 49152 /* 48K to avoid segment hopping */ #else /* Any reasonable (non-segmented) arch... */ #define BUFSIZE 65536 /* As big as you want */ #endif #define MAXLINE 256 /* Length of longest input line + 1 */ /* Globals */ FILE *infilePH, *outfilePH; /* Handles for input and output files */ unsigned char *bufAC, /* Allocated image buffer */ *highestPC = NULL; /* Highest buffer address written */ /* Change this string to reflect the name of the output array */ char headerAC[] = "unsigned long sRec[] =\n{\n"; /* Predeclarations */ int parsebufN( char * ); /* Does the actual parsing */ void main(int argc, const char * argv[]) { int c, /* Temp char storage */ resN; /* result status */ char *lbufPC, lbufAC[MAXLINE]; int linectrN = 0; /* Used to correlate parse fail to input line */ #ifndef BINARY int i; unsigned long *codePL; unsigned char *codePC; #endif /* Check the argument count */ if( argc != 3 ) /* If didn't specify input and output files */ { printf("Usage: %s: infile outfile\n", argv[0] ); exit(1); } /* OK, let's open some files */ if( ( infilePH = fopen( argv[1], "r" ) )== NULL ) { printf("%s: Couldn't open input file %s\n", argv[0], argv[1] ); exit(2); } if( ( outfilePH = fopen( argv[2], "w" ) ) == NULL ) { printf("%s: Couldn't open output file %s\n", argv[0], argv[3] ); exit(3); } /* OK, get a buffer and clear it. */ if( (bufAC = calloc( (size_t)BUFSIZE, (size_t)1 )) == NULL ) { printf("%s: Couldn't malloc memory for buffer\n", argv[0] ); exit(4); } lbufPC = lbufAC; /* Point at beginning of line buffer */ while( c = fgetc( infilePH )) { if( (c == '\n') || (c == EOF) ) /* If found end of line or file */ { /* Parse the Line */ if( ( c == EOF ) && ( ferror( infilePH ) ) ) { printf("%s: Error reading input file\n", argv[0] ); exit(5); } else { /* OK, have a complete line in buffer */ linectrN++; /* Increment line counter */ if( lbufPC == lbufAC ) break; /* ignore blank lines */ *lbufPC = 0; /* Terminate the line string */ if( resN = parsebufN( lbufAC ) ) /* Parse data record to mem */ { printf("%s: Error reading input file at line %d, return code = %d\n", argv[0], linectrN, resN ); exit( resN ); } lbufPC = lbufAC; /* Repoint line buffer pointer */ } /* End of have a complete line */ } else *lbufPC++ = c; /* Place char into line buffer */ } /* At this point, the input file has been emptied. Now dispose of the ** output data according to compilation mode. */ #ifdef BINARY /* Write the buffer back to disk as a binary image */ resN = fwrite( bufAC, 1, (size_t)((highestPC - bufAC) + 1), outfilePH ); if( resN != (int)( (highestPC - bufAC) + 1) ) { printf("%s: Error writing output file\n", argv[0] ); exit( 6 ); } #else /* Produce a file that can be included in a C program. Data is read ** from buffer as bytes to avoid portability/endian problems with ** this program. */ /* Output header first, then 1 long per line */ fwrite( (void *)headerAC, 1, (size_t)(sizeof( headerAC )-1), outfilePH ); codePL = (unsigned long *)bufAC; for( i = (highestPC - bufAC + 1) / 4; i; i-- ) /* for each long */ { codePC = (unsigned char *)codePL++; sprintf(lbufAC, "0x%02x%02x%02x%02x%s", *codePC, *(codePC + 1), *(codePC + 2), *(codePC + 3), i == 1 ? "\n" : ",\n" ); /* No comma after final long */ fwrite( lbufAC, 1, (size_t)(strlen( lbufAC )), outfilePH ); } /* OK, data has been written out, close end of array */ fwrite( "};\n", 1, (size_t)3, outfilePH ); #endif } /* Function: parsebufV ** Parses an S-record in the buffer and writes it into the buffer ** if it is has a valid checksum. ** ** Args: pointer to character buffer for null terminated line ** Returns: int result code: 0 = success, else failure */ int parsebufN( char *lbufPC ) { unsigned long addrL; unsigned char cksmB, /* checksum of addr, count, & data length */ *bufPC; /* Pointer into memory array */ int i, countN, /* Number of bytes represented in record */ oheadN, /* Number of overhead (addr + chksum) bytes */ tvalN; /* Temp for check checksum */ switch( *(lbufPC+1) ) /* examine 2nd character on the line */ { case '1': /* 16 bit address field */ if( sscanf(lbufPC, "S1%2x%4lx", &countN, &addrL ) != 2 ) return( 10 ); /* Flag error in S1 record */ oheadN = 3; /* 2 address + 1 checksum */ break; case '2': /* 24 bit address field */ if( sscanf(lbufPC, "S2%2x%6lx", &countN, &addrL ) != 2 ) return( 11 ); /* Flag error in S2 record */ oheadN = 4; /* 3 address + 1 checksum */ break; case '3': /* 32 bit address field */ if( sscanf(lbufPC, "S3%2x%8lx", &countN, &addrL ) != 2 ) return( 12 ); /* Flag error in S3 record */ oheadN = 5; /* 4 address + 1 checksum */ break; default: /* ignore all but S1,2,3 records. */ return( 0 ); } if( addrL > BUFSIZE ) return( 13 ); /* if address exceeds buffer size */ bufPC = bufAC + addrL; /* otherwise, point to right spot in buffer */ /* OK now see if checksum is OK, while reading data to buffer */ cksmB = 0; countN++; /* Bump counter to read final checksum too */ for( i = 1; i <= countN; i++ ) { sscanf( lbufPC + i*2, "%2x", &tvalN ); /* Scan a 2 hex digit byte */ cksmB += (unsigned char)tvalN; if( ( i > oheadN ) && ( i < countN ) ) /* If scanned a data byte */ *bufPC++ = (unsigned char) tvalN; /* write it to the buffer */ } if( cksmB += 1 ) return( 14 ); /* flag checksum error */ if( (bufPC - 1) > highestPC ) highestPC = bufPC - 1; /* track highest address loaded */ return( 0 ); /* Successful return */ }