summaryrefslogtreecommitdiffstats
path: root/c/build-tools
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1995-05-11 17:39:37 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1995-05-11 17:39:37 +0000
commitac7d5ef06a6d6e8d84abbd1f0b82162725f98326 (patch)
tree9304cf759a73f2a1c6fd3191948f00e870af3787 /c/build-tools
downloadrtems-ac7d5ef06a6d6e8d84abbd1f0b82162725f98326.tar.bz2
Initial revision
Diffstat (limited to 'c/build-tools')
-rw-r--r--c/build-tools/README32
-rw-r--r--c/build-tools/cklength.c364
-rw-r--r--c/build-tools/eolstrip.c351
-rw-r--r--c/build-tools/packhex.c513
-rw-r--r--c/build-tools/scripts/README32
-rw-r--r--c/build-tools/src/cklength.c364
-rw-r--r--c/build-tools/src/eolstrip.c351
-rw-r--r--c/build-tools/src/packhex.c513
-rw-r--r--c/build-tools/src/unhex.c719
-rw-r--r--c/build-tools/unhex.c719
10 files changed, 3958 insertions, 0 deletions
diff --git a/c/build-tools/README b/c/build-tools/README
new file mode 100644
index 0000000000..0436fc958d
--- /dev/null
+++ b/c/build-tools/README
@@ -0,0 +1,32 @@
+#
+# $Id$
+#
+
+Misc. support tools for RTEMS workspaces.
+More will be added later as they are converted from Teamware
+to CVS.
+
+install-if-change
+ Smart install script that also can append suffixes as it
+ installs (suffixes used for debug and profile variants).
+ Requires bash or ksh.
+
+rcs-clean
+ deletes all files from the current directory that can be
+ re-created from RCS. Careful to not delete locked files.
+ May be used by 'gmake clobber'
+
+lock-directory
+unlock-directory
+ traverse a directory structure making it unwritable.
+ Useful to keep people from accidentally overwriting
+ "released" trees if they get confused about which
+ module they have loaded.
+
+rtems-glom
+ glom together all the rtems libraries in order to simplify
+ the link line used by applications.
+ Produces rtems.rel.
+ Not used by the RTEMS src tree at all.
+ Strictly optional.
+
diff --git a/c/build-tools/cklength.c b/c/build-tools/cklength.c
new file mode 100644
index 0000000000..48801e1559
--- /dev/null
+++ b/c/build-tools/cklength.c
@@ -0,0 +1,364 @@
+/*
+ * cklength - check the length of lines in a file
+ *
+ * This program check to see if the files passed to it on the command line
+ * contain a line which exceeds the maximum allowable length. The default
+ * maximum line length is 80.
+ *
+ * usage: cklength [ -v ] [ arg ... ] files...
+ * -l length -- maximum line length
+ * -v -- verbose
+ *
+ * $Id$
+ * $Log$
+ */
+
+#define GETOPTARGS "l:nNv"
+
+char *USAGE = "\
+usage: cklength [ -v ] [ arg ... ] files... \n\
+ -l length -- maximum line length\n\
+ -n -- report line numbers for offending lines\n\
+ -N -- report line numbers and length for offending lines\n\
+ -v -- verbose\n\
+\n\
+Print the name of files which have at least 1 line which exceeds the\n\
+maximum line length. The default maximum line length is 80.\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 512
+
+#define SUCCESS 0
+#define FAILURE -1
+#define Failed(x) (((int) (x)) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+#define STREQ(a,b) (strcmp(a,b) == 0)
+#define NUMELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
+
+/*
+ * Definitions for unsigned "ints"; especially for use in data structures
+ * that will be shared among (potentially) different cpu's (we punt on
+ * byte ordering problems tho)
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * vars controlled by command line options
+ */
+
+int verbose = FALSE; /* be verbose */
+int report_line_numbers = FALSE; /* report line numbers of offenders */
+int report_line_length = FALSE; /* report line length of offenders */
+
+int line_length = 80; /* maximum allowable line length */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind, opterr;
+extern int errno;
+
+char *progname; /* for error() */
+
+int process(char *arg);
+void error(int errn, ...);
+long getparm(char *s, long min, long max, char *msg);
+
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* fatal error ; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* fatal error ; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+int Open(), Read(), Write();
+
+int
+main(int argc, char **argv, char **env)
+{
+ register int c;
+ int showusage = FALSE; /* usage error? */
+ int rc = 0;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ opterr = 0; /* we'll report all errors */
+ while ((c = getopt(argc, argv, GETOPTARGS)) != EOF)
+ switch (c)
+ {
+ case 'l': /* line length */
+ line_length = atoi( optarg );
+ if ( line_length < 0 || line_length > BUFFER_SIZE )
+ error(ERR_FATAL, "(%d) is illegal line length\n",line_length);
+ break;
+
+ case 'n': /* toggle report_line_numbers */
+ report_line_numbers = ! report_line_numbers;
+ break;
+
+ case 'N': /* toggle both reports */
+ report_line_numbers = ! report_line_numbers;
+ report_line_length = ! report_line_length;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ /*
+ * traverse and process the arguments
+ */
+
+ for ( ; argv[optind]; optind++)
+ if (Failed(process(argv[optind])))
+ rc = FAILURE;
+
+ return rc;
+}
+
+
+/*
+ * process(arg)
+ */
+
+int
+process(char *arg)
+{
+ FILE *in;
+ char *bptr;
+ char buffer[ BUFFER_SIZE ];
+ int line_number;
+ int length;
+ int count;
+ int rc = SUCCESS; /* succeed by default */
+
+ in = fopen( arg, "r" );
+ if (!in)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+
+ count = 0;
+
+ for ( line_number=1 ; ; line_number++ ) {
+ bptr = fgets( buffer, BUFFER_SIZE, in );
+ if (!bptr)
+ break;
+
+ /*
+ * Don't count the carriage return.
+ */
+
+ length = strlen( buffer ) - 1;
+
+ if ( length <= line_length )
+ continue;
+
+ if ( count == 0 ) {
+ fprintf( stderr, "%s\n", arg );
+ if ( !report_line_numbers )
+ break;
+ }
+
+ if ( verbose )
+ fprintf( stderr, "TOO LONG:%d: %s\n", line_number, buffer );
+
+ if ( report_line_numbers ) {
+ if ( report_line_length )
+ fprintf( stderr, "%d: %d\n" , line_number, length );
+ else
+ fprintf( stderr, "%d\n" , line_number );
+ }
+
+ count++;
+
+ }
+
+ fclose( in );
+ return rc;
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_FATAL bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+
+long
+getparm(char *s,
+ long min,
+ long max,
+ char *msg)
+{
+ long val;
+
+ if ( ! strchr("0123456789-", *s))
+ {
+ error(ERR_FATAL, "'%s' is not a number", s);
+ return min;
+ }
+
+ val = strtol(s, (char **) NULL, 0);
+ if ((val < min) || (val > max))
+ {
+ if (min == max)
+ error(ERR_FATAL, "%s can only be %ld", s, min);
+ else
+ error(ERR_FATAL, "%s must be between %ld and %ld", msg, min, max);
+ }
+
+ return val;
+}
+
+
+/*
+ * Open()
+ * Perform open(2), returning the file descriptor. Prints
+ * error message if open fails.
+ */
+
+int
+Open(char *file,
+ int oflag,
+ int mode)
+{
+ int O_fd;
+
+ if (Failed(O_fd = open(file, oflag, mode)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "open('%s', 0x%x, 0%o) failed", file, oflag, mode
+ );
+
+ return O_fd;
+}
+
+/*
+ * Read()
+ * Perform read(2); prints error message if fails.
+ */
+
+int
+Read(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = read(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "read(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
+
+/*
+ * Write()
+ * Perform write(2); prints error message if fails.
+ */
+
+int
+Write(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = write(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "write(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
diff --git a/c/build-tools/eolstrip.c b/c/build-tools/eolstrip.c
new file mode 100644
index 0000000000..0fa7af15d4
--- /dev/null
+++ b/c/build-tools/eolstrip.c
@@ -0,0 +1,351 @@
+/*
+ * eolstrip - strip white space from end of lines
+ *
+ * This program strips the white space from the end of every line in the
+ * specified program.
+ *
+ * usage: eolstrip [ -v ] [ arg ... ] files...
+ * -v -- verbose
+ *
+ * $Id$
+ * $Log$
+ */
+
+#define GETOPTARGS "vt"
+
+char *USAGE = "\
+usage: cklength [ -v ] [ arg ... ] files... \n\
+ -v -- verbose\n\
+ -t -- test only .. DO NOT OVERWRITE FILE!!!\n\
+\n\
+Strip the white space from the end of every line on the list of files.\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 2048
+#define MAX_PATH 2048
+
+#define SUCCESS 0
+#define FAILURE -1
+#define Failed(x) (((int) (x)) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+#define STREQ(a,b) (strcmp(a,b) == 0)
+#define NUMELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
+
+/*
+ * Definitions for unsigned "ints"; especially for use in data structures
+ * that will be shared among (potentially) different cpu's (we punt on
+ * byte ordering problems tho)
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * vars controlled by command line options
+ */
+
+int verbose = FALSE; /* be verbose */
+int test_only = FALSE; /* test only */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind, opterr;
+extern int errno;
+
+char *progname; /* for error() */
+
+int process(char *arg);
+void error(int errn, ...);
+long getparm(char *s, long min, long max, char *msg);
+
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* fatal error ; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* fatal error ; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+int Open(), Read(), Write();
+
+int
+main(int argc, char **argv, char **env)
+{
+ register int c;
+ int showusage = FALSE; /* usage error? */
+ int rc = 0;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ opterr = 0; /* we'll report all errors */
+ while ((c = getopt(argc, argv, GETOPTARGS)) != EOF)
+ switch (c)
+ {
+ case 't': /* toggle test only mode */
+ test_only = ! test_only;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ /*
+ * traverse and process the arguments
+ */
+
+ for ( ; argv[optind]; optind++)
+ if (Failed(process(argv[optind])))
+ rc = FAILURE;
+
+ return rc;
+}
+
+
+/*
+ * process(arg)
+ */
+
+int
+process(char *arg)
+{
+ FILE *in;
+ FILE *out = (FILE *) 0;
+ char outname[ MAX_PATH ];
+ char *bptr;
+ char buffer[ BUFFER_SIZE ];
+ int length;
+ int line_number;
+ int rc = SUCCESS; /* succeed by default */
+
+ in = fopen( arg, "r" );
+ if (!in)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+
+ if ( !test_only ) {
+ sprintf( outname, "%s.eoltmp", arg );
+
+ out = fopen( outname, "w" );
+ if (!out)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+ }
+
+ if ( verbose )
+ fprintf( stderr, "Processing %s\n", arg );
+
+ for ( line_number=1 ; ; line_number++ ) {
+ bptr = fgets( buffer, BUFFER_SIZE, in );
+ if (!bptr)
+ break;
+
+ /*
+ * Don't count the carriage return.
+ */
+
+ length = strlen( buffer ) - 1;
+
+ if ( buffer[ length ] != '\n' )
+ error(ERR_ERRNO|ERR_FATAL, "Line %d too long in %s\n", line_number, arg);
+
+ while ( isspace( buffer[ length ] ) )
+ buffer[ length-- ] = '\0';
+
+ if ( test_only ) {
+ fprintf( stderr, "%s\n", arg );
+ break;
+ }
+
+ fprintf( out, "%s\n", buffer );
+ }
+
+ fclose( in );
+ if ( !test_only ) {
+ fclose( out );
+ rename( outname, arg );
+ }
+ return rc;
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_FATAL bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+
+long
+getparm(char *s,
+ long min,
+ long max,
+ char *msg)
+{
+ long val;
+
+ if ( ! strchr("0123456789-", *s))
+ {
+ error(ERR_FATAL, "'%s' is not a number", s);
+ return min;
+ }
+
+ val = strtol(s, (char **) NULL, 0);
+ if ((val < min) || (val > max))
+ {
+ if (min == max)
+ error(ERR_FATAL, "%s can only be %ld", s, min);
+ else
+ error(ERR_FATAL, "%s must be between %ld and %ld", msg, min, max);
+ }
+
+ return val;
+}
+
+
+/*
+ * Open()
+ * Perform open(2), returning the file descriptor. Prints
+ * error message if open fails.
+ */
+
+int
+Open(char *file,
+ int oflag,
+ int mode)
+{
+ int O_fd;
+
+ if (Failed(O_fd = open(file, oflag, mode)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "open('%s', 0x%x, 0%o) failed", file, oflag, mode
+ );
+
+ return O_fd;
+}
+
+/*
+ * Read()
+ * Perform read(2); prints error message if fails.
+ */
+
+int
+Read(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = read(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "read(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
+
+/*
+ * Write()
+ * Perform write(2); prints error message if fails.
+ */
+
+int
+Write(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = write(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "write(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
diff --git a/c/build-tools/packhex.c b/c/build-tools/packhex.c
new file mode 100644
index 0000000000..ddd010c4a9
--- /dev/null
+++ b/c/build-tools/packhex.c
@@ -0,0 +1,513 @@
+
+/***** P A C K H E X . C ************************************************
+ *
+ * Packhex is a hex-file compaction utility. It attempts to concatenate
+ * hex records to produce more size-efficient packaging.
+ *
+ * Limitations: Input files must be correctly formatted. This utility
+ * is not robust enough to detect hex-record formatting
+ * errors.
+ *
+ * Published: 5/93 Embedded Systems magazine
+ *
+ * Compiler: Microsoft C 6.0
+ * cl /F 1000 packhex.c
+ *
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/* #define SMALLER_RECORDS */
+#ifdef SMALLER_RECORDS
+#define MAX_LEN_S1_RECS 128
+#define MAX_LEN_S2_RECS 128
+#define MAX_LEN_S3_RECS 128
+#else
+#define MAX_LEN_S1_RECS 252
+#define MAX_LEN_S2_RECS 251
+#define MAX_LEN_S3_RECS 250
+#endif
+
+
+/*--------------------------------- includes ---------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__unix__) && !defined(EXIT_FAILURE)
+#define EXIT_FAILURE -1
+#define EXIT_SUCCESS 0
+#endif
+
+/*--------------------------------- defines ----------------------------------*/
+
+#define YES 1
+#define MAX_LINE_SIZE 600
+#define EOS '\0'
+
+
+/*---------------------------------- macros ----------------------------------*/
+
+/* Convert ASCII hexadecimal digit to value. */
+
+#define HEX_DIGIT( C ) ( ( ( ( C ) > '9' ) ? ( C ) + 25 : ( C ) ) & 0xF )
+
+
+/*--------------------------------- typedefs ---------------------------------*/
+
+typedef unsigned char Boolean;
+typedef unsigned char Uchar;
+typedef unsigned int Uint;
+typedef unsigned long Ulong;
+
+typedef struct /* Functions and constant returning Hex-record vital stats. */
+{
+ Boolean ( *is_data_record )( char * );
+ Ulong ( *get_address )( char * );
+ Uint ( *get_data_count )( char * );
+ const Uint max_data_count;
+ char *( *get_data_start )( char * );
+ void ( *put_data_record )( Uint, Ulong, char * );
+} Rec_vitals;
+
+
+/*--------------------------- function prototypes ----------------------------*/
+
+Rec_vitals * identify_first_data_record( char * );
+Ulong get_ndigit_hex( char *, int );
+
+
+/*----------------------------- Intel Hex format -----------------------------*/
+
+/*
+ * Intel Hex data-record layout
+ *
+ * :aabbbbccd...dee
+ *
+ * : - header character
+ * aa - record data byte count, a 2-digit hex value
+ * bbbb - record address, a 4-digit hex value
+ * cc - record type, a 2-digit hex value:
+ * "00" is a data record
+ * "01" is an end-of-data record
+ * "02" is an extended-address record
+ * "03" is a start record
+ * d...d - data (always an even number of chars)
+ * ee - record checksum, a 2-digit hex value
+ * checksum = 2's complement
+ * [ (sum of bytes: aabbbbccd...d) modulo 256 ]
+ */
+
+
+Boolean is_intel_data_rec( char * rec_str )
+{
+ return( ( rec_str[ 0 ] == ':' ) && ( rec_str[ 8 ] == '0' ) );
+}
+
+Uint get_intel_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 1, 2 ) );
+}
+
+Ulong get_intel_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 3, 4 ) );
+}
+
+char * get_intel_rec_data_start( char * rec_str )
+{
+ return( rec_str + 9 );
+}
+
+void put_intel_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = count + ( address >> 8 & 0xff ) + ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ ":%02X%04lX00%s%02X\n", count, address, data_str, (~sum + 1) & 0xff
+ );
+}
+
+
+Rec_vitals intel_hex =
+{
+ is_intel_data_rec,
+ get_intel_rec_address,
+ get_intel_rec_data_count,
+ 255, /* Maximum data bytes in a record. */
+ get_intel_rec_data_start,
+ put_intel_data_rec
+};
+
+
+/*------------------------- Motorola S1-record format ------------------------*/
+
+/*
+ * Motorola S-record data-record layout
+ *
+ * Sabbc...cd...dee
+ *
+ * S - header character
+ * a - record type, a 1-digit value:
+ * "0" is a header record
+ * "1" is a 2-byte-address data record
+ * "2" is a 3-byte-address data record
+ * "3" is a 4-byte-address data record
+ * "7" is a 4-byte-address end-of-data record
+ * "8" is a 3-byte-address end-of-data record
+ * "9" is a 2-byte-address end-of-data record
+ * bb - record length in bytes, a 2-digit hex value
+ * (record length doesn't count the header/type
+ * chars and checksum byte)
+ * c...c - record address, a 4-, 6-, or 8-digit value,
+ * depending on record type
+ * d...d - data (always an even number of chars)
+ * ee - record checksum, a 2-digit hex value
+ * checksum = 1's complement
+ * [ (sum of all bytes: bbc..cd...d) modulo 256 ]
+ */
+
+#define S1_COUNT_OFFSET 3
+
+
+Boolean is_moto_s1_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '1' ) );
+}
+
+Uint get_moto_s1_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S1_COUNT_OFFSET );
+}
+
+Ulong get_moto_s1_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 4 ) );
+}
+
+char * get_moto_s1_rec_data_start( char * rec_str )
+{
+ return( rec_str + 8 );
+}
+
+void put_moto_s1_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S1_COUNT_OFFSET + count +
+ ( address >> 8 & 0xff ) + ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S1%02X%04lX%s%02X\n",
+ count + S1_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s1_rec =
+{
+ is_moto_s1_data_rec,
+ get_moto_s1_rec_address,
+ get_moto_s1_rec_data_count,
+ MAX_LEN_S1_RECS, /* Maximum data bytes in a record. */
+ get_moto_s1_rec_data_start,
+ put_moto_s1_data_rec
+};
+
+
+/*------------------------- Motorola S2-record format ------------------------*/
+
+#define S2_COUNT_OFFSET 4
+
+Boolean is_moto_s2_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '2' ) );
+}
+
+Uint get_moto_s2_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S2_COUNT_OFFSET );
+}
+
+Ulong get_moto_s2_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 6 ) );
+}
+
+char * get_moto_s2_rec_data_start( char * rec_str )
+{
+ return( rec_str + 10 );
+}
+
+void put_moto_s2_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S2_COUNT_OFFSET + count + ( address >> 16 & 0xff ) +
+ ( address >> 8 & 0xff ) +
+ ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S2%02X%06lX%s%02X\n",
+ count + S2_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s2_rec =
+{
+ is_moto_s2_data_rec,
+ get_moto_s2_rec_address,
+ get_moto_s2_rec_data_count,
+ MAX_LEN_S2_RECS, /* Maximum data bytes in a record. */
+ get_moto_s2_rec_data_start,
+ put_moto_s2_data_rec
+};
+
+
+/*------------------------- Motorola S3-record format ------------------------*/
+
+#define S3_COUNT_OFFSET 5
+
+Boolean is_moto_s3_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '3' ) );
+}
+
+Uint get_moto_s3_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S3_COUNT_OFFSET );
+}
+
+Ulong get_moto_s3_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 8 ) );
+}
+
+char * get_moto_s3_rec_data_start( char * rec_str )
+{
+ return( rec_str + 12 );
+}
+
+void put_moto_s3_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S3_COUNT_OFFSET + count + ( address >> 24 & 0xff ) +
+ ( address >> 16 & 0xff ) +
+ ( address >> 8 & 0xff ) +
+ ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S3%02X%08lX%s%02X\n",
+ count + S3_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s3_rec =
+{
+ is_moto_s3_data_rec,
+ get_moto_s3_rec_address,
+ get_moto_s3_rec_data_count,
+ MAX_LEN_S3_RECS, /* Maximum data bytes in a record. */
+ get_moto_s3_rec_data_start,
+ put_moto_s3_data_rec
+};
+
+
+/*-------------------- Put your favorite hex format here ---------------------*/
+
+/*
+ * * * * The following is a template for an additional hex format: * * *
+ *
+ *
+ * Boolean is_X_data_rec( char * rec_str ) {}
+ *
+ * Uint get_X_rec_data_count( char * rec_str ) {}
+ *
+ * Ulong get_X_rec_address( char * rec_str ) {}
+ *
+ * char * get_X_rec_data_start( char * rec_str ) {}
+ *
+ * void put_X_data_rec( Uint count, Ulong address, char * data_str ) {}
+ *
+ * Rec_vitals X_rec =
+ * {
+ * is_X_data_rec,
+ * get_X_rec_address,
+ * get_X_rec_data_count,
+ * MAXIMUM DATA BYTES IN A RECORD,
+ * get_X_rec_data_start,
+ * put_X_data_rec
+ * };
+ *
+ */
+
+/*----------------------------------------------------------------------------*/
+
+
+/*
+ * Put address of additional Rec_vitals structures
+ * in this array, before the NULL entry.
+ */
+
+Rec_vitals *formats[] =
+{
+ &intel_hex,
+ &motorola_s1_rec,
+ &motorola_s2_rec,
+ &motorola_s3_rec,
+ ( Rec_vitals * ) NULL
+};
+
+
+/**** main *****************************************************************
+*
+*
+* Expects: Nothing (no command-line parameters).
+*
+* Returns: Exit status (EXIT_SUCCESS or EXIT_FAILURE).
+*
+* Reads hex records on the standard input and attempts to
+* splice adjacent data fields together. Results appear on
+* the standard output.
+*
+*******************************************************************************/
+
+void main( void )
+{
+
+ char inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ];
+ char *in_dptr, *out_dptr;
+ int d_total, d_count, d_excess, n;
+ Ulong in_rec_addr, out_rec_addr = 0;
+ Rec_vitals *rptr;
+
+
+ /* Sift through file until first hex record is identified. */
+ if ( ( rptr = identify_first_data_record( inbuff ) ) == NULL )
+ {
+ fputs( "No hex records found.\n", stderr );
+ exit( EXIT_FAILURE );
+ }
+
+
+ /* Attempt data-record splicing until end-of-file is reached. */
+ d_total = 0;
+ do
+ {
+ if ( rptr->is_data_record( inbuff ) == YES )
+ { /* Input record is a data record. */
+ d_count = rptr->get_data_count( inbuff );
+ in_rec_addr = rptr->get_address( inbuff );
+ in_dptr = rptr->get_data_start( inbuff );
+
+ if ( d_total == 0 || in_rec_addr != out_rec_addr + d_total )
+ { /* Begin a new output record. */
+ if ( d_total != 0 )
+ rptr->put_data_record( d_total, out_rec_addr, outbuff );
+ out_dptr = outbuff;
+ n = d_total = d_count;
+ out_rec_addr = in_rec_addr;
+ }
+ else if
+ ( ( d_excess = d_total + d_count - rptr->max_data_count ) > 0 )
+ { /* Output a maximum-length record, then start a new record. */
+ strncat( outbuff, in_dptr, 2 * ( d_count - d_excess ) );
+ rptr->put_data_record(
+ rptr->max_data_count, out_rec_addr, outbuff
+ );
+ in_dptr += 2 * ( d_count - d_excess );
+ out_dptr = outbuff;
+ n = d_total = d_excess;
+ out_rec_addr += rptr->max_data_count;
+ }
+ else
+ { /* Append input record's data field with accumulated data. */
+ out_dptr = outbuff + ( 2 * d_total );
+ d_total += n = d_count;
+ }
+ strncpy( out_dptr, in_dptr, 2 * n );
+ out_dptr[ 2 * n ] = EOS;
+ }
+ else
+ { /* Not a data record;
+ * flush accumulated data then echo non-data record.
+ */
+ if ( d_total != 0 )
+ {
+ rptr->put_data_record( d_total, out_rec_addr, outbuff );
+ d_total = 0;
+ }
+ puts( inbuff );
+ }
+ } while ( gets( inbuff ) != NULL );
+
+
+ exit( EXIT_SUCCESS );
+
+}
+
+
+/**** identify_first_data_record *******************************************
+*
+* Expects: Pointer to hex-record line buffer.
+*
+* Returns: Pointer to hex-record structure (NULL if no match found).
+*
+* Reads the standard input, line by line, searching for a valid
+* record header character. If a valid header is found, a pointer
+* to the hex-record's type structure is returned, otherwise NULL.
+*
+* The input-stream pointer is left pointing to the first valid hex record.
+*
+*******************************************************************************/
+
+Rec_vitals * identify_first_data_record( char * buff_ptr )
+{
+ Rec_vitals ** ptr;
+
+ while ( gets( buff_ptr ) != NULL )
+ {
+ for ( ptr = formats ; *ptr != ( Rec_vitals * ) NULL ; ptr++ )
+ if ( ( *ptr )->is_data_record( buff_ptr ) == YES )
+ return( *ptr ); /* Successful return. */
+
+ puts( buff_ptr ); /* Echo non-hex-record line. */
+ }
+
+ return( ( Rec_vitals * ) NULL ); /* Unsuccessful return. */
+}
+
+
+/**** get_ndigit_hex *******************************************************
+*
+* Expects: Pointer to first ASCII hexadecimal digit, number of digits.
+*
+* Returns: Value of hexadecimal string as an unsigned long.
+*
+*******************************************************************************/
+
+Ulong get_ndigit_hex( char * cptr, int digits )
+{
+ Ulong value;
+
+ for ( value = 0 ; --digits >= 0 ; cptr++ )
+ value = ( value * 16L ) + HEX_DIGIT( *cptr );
+
+ return( value );
+}
diff --git a/c/build-tools/scripts/README b/c/build-tools/scripts/README
new file mode 100644
index 0000000000..0436fc958d
--- /dev/null
+++ b/c/build-tools/scripts/README
@@ -0,0 +1,32 @@
+#
+# $Id$
+#
+
+Misc. support tools for RTEMS workspaces.
+More will be added later as they are converted from Teamware
+to CVS.
+
+install-if-change
+ Smart install script that also can append suffixes as it
+ installs (suffixes used for debug and profile variants).
+ Requires bash or ksh.
+
+rcs-clean
+ deletes all files from the current directory that can be
+ re-created from RCS. Careful to not delete locked files.
+ May be used by 'gmake clobber'
+
+lock-directory
+unlock-directory
+ traverse a directory structure making it unwritable.
+ Useful to keep people from accidentally overwriting
+ "released" trees if they get confused about which
+ module they have loaded.
+
+rtems-glom
+ glom together all the rtems libraries in order to simplify
+ the link line used by applications.
+ Produces rtems.rel.
+ Not used by the RTEMS src tree at all.
+ Strictly optional.
+
diff --git a/c/build-tools/src/cklength.c b/c/build-tools/src/cklength.c
new file mode 100644
index 0000000000..48801e1559
--- /dev/null
+++ b/c/build-tools/src/cklength.c
@@ -0,0 +1,364 @@
+/*
+ * cklength - check the length of lines in a file
+ *
+ * This program check to see if the files passed to it on the command line
+ * contain a line which exceeds the maximum allowable length. The default
+ * maximum line length is 80.
+ *
+ * usage: cklength [ -v ] [ arg ... ] files...
+ * -l length -- maximum line length
+ * -v -- verbose
+ *
+ * $Id$
+ * $Log$
+ */
+
+#define GETOPTARGS "l:nNv"
+
+char *USAGE = "\
+usage: cklength [ -v ] [ arg ... ] files... \n\
+ -l length -- maximum line length\n\
+ -n -- report line numbers for offending lines\n\
+ -N -- report line numbers and length for offending lines\n\
+ -v -- verbose\n\
+\n\
+Print the name of files which have at least 1 line which exceeds the\n\
+maximum line length. The default maximum line length is 80.\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 512
+
+#define SUCCESS 0
+#define FAILURE -1
+#define Failed(x) (((int) (x)) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+#define STREQ(a,b) (strcmp(a,b) == 0)
+#define NUMELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
+
+/*
+ * Definitions for unsigned "ints"; especially for use in data structures
+ * that will be shared among (potentially) different cpu's (we punt on
+ * byte ordering problems tho)
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * vars controlled by command line options
+ */
+
+int verbose = FALSE; /* be verbose */
+int report_line_numbers = FALSE; /* report line numbers of offenders */
+int report_line_length = FALSE; /* report line length of offenders */
+
+int line_length = 80; /* maximum allowable line length */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind, opterr;
+extern int errno;
+
+char *progname; /* for error() */
+
+int process(char *arg);
+void error(int errn, ...);
+long getparm(char *s, long min, long max, char *msg);
+
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* fatal error ; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* fatal error ; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+int Open(), Read(), Write();
+
+int
+main(int argc, char **argv, char **env)
+{
+ register int c;
+ int showusage = FALSE; /* usage error? */
+ int rc = 0;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ opterr = 0; /* we'll report all errors */
+ while ((c = getopt(argc, argv, GETOPTARGS)) != EOF)
+ switch (c)
+ {
+ case 'l': /* line length */
+ line_length = atoi( optarg );
+ if ( line_length < 0 || line_length > BUFFER_SIZE )
+ error(ERR_FATAL, "(%d) is illegal line length\n",line_length);
+ break;
+
+ case 'n': /* toggle report_line_numbers */
+ report_line_numbers = ! report_line_numbers;
+ break;
+
+ case 'N': /* toggle both reports */
+ report_line_numbers = ! report_line_numbers;
+ report_line_length = ! report_line_length;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ /*
+ * traverse and process the arguments
+ */
+
+ for ( ; argv[optind]; optind++)
+ if (Failed(process(argv[optind])))
+ rc = FAILURE;
+
+ return rc;
+}
+
+
+/*
+ * process(arg)
+ */
+
+int
+process(char *arg)
+{
+ FILE *in;
+ char *bptr;
+ char buffer[ BUFFER_SIZE ];
+ int line_number;
+ int length;
+ int count;
+ int rc = SUCCESS; /* succeed by default */
+
+ in = fopen( arg, "r" );
+ if (!in)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+
+ count = 0;
+
+ for ( line_number=1 ; ; line_number++ ) {
+ bptr = fgets( buffer, BUFFER_SIZE, in );
+ if (!bptr)
+ break;
+
+ /*
+ * Don't count the carriage return.
+ */
+
+ length = strlen( buffer ) - 1;
+
+ if ( length <= line_length )
+ continue;
+
+ if ( count == 0 ) {
+ fprintf( stderr, "%s\n", arg );
+ if ( !report_line_numbers )
+ break;
+ }
+
+ if ( verbose )
+ fprintf( stderr, "TOO LONG:%d: %s\n", line_number, buffer );
+
+ if ( report_line_numbers ) {
+ if ( report_line_length )
+ fprintf( stderr, "%d: %d\n" , line_number, length );
+ else
+ fprintf( stderr, "%d\n" , line_number );
+ }
+
+ count++;
+
+ }
+
+ fclose( in );
+ return rc;
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_FATAL bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+
+long
+getparm(char *s,
+ long min,
+ long max,
+ char *msg)
+{
+ long val;
+
+ if ( ! strchr("0123456789-", *s))
+ {
+ error(ERR_FATAL, "'%s' is not a number", s);
+ return min;
+ }
+
+ val = strtol(s, (char **) NULL, 0);
+ if ((val < min) || (val > max))
+ {
+ if (min == max)
+ error(ERR_FATAL, "%s can only be %ld", s, min);
+ else
+ error(ERR_FATAL, "%s must be between %ld and %ld", msg, min, max);
+ }
+
+ return val;
+}
+
+
+/*
+ * Open()
+ * Perform open(2), returning the file descriptor. Prints
+ * error message if open fails.
+ */
+
+int
+Open(char *file,
+ int oflag,
+ int mode)
+{
+ int O_fd;
+
+ if (Failed(O_fd = open(file, oflag, mode)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "open('%s', 0x%x, 0%o) failed", file, oflag, mode
+ );
+
+ return O_fd;
+}
+
+/*
+ * Read()
+ * Perform read(2); prints error message if fails.
+ */
+
+int
+Read(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = read(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "read(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
+
+/*
+ * Write()
+ * Perform write(2); prints error message if fails.
+ */
+
+int
+Write(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = write(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "write(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
diff --git a/c/build-tools/src/eolstrip.c b/c/build-tools/src/eolstrip.c
new file mode 100644
index 0000000000..0fa7af15d4
--- /dev/null
+++ b/c/build-tools/src/eolstrip.c
@@ -0,0 +1,351 @@
+/*
+ * eolstrip - strip white space from end of lines
+ *
+ * This program strips the white space from the end of every line in the
+ * specified program.
+ *
+ * usage: eolstrip [ -v ] [ arg ... ] files...
+ * -v -- verbose
+ *
+ * $Id$
+ * $Log$
+ */
+
+#define GETOPTARGS "vt"
+
+char *USAGE = "\
+usage: cklength [ -v ] [ arg ... ] files... \n\
+ -v -- verbose\n\
+ -t -- test only .. DO NOT OVERWRITE FILE!!!\n\
+\n\
+Strip the white space from the end of every line on the list of files.\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 2048
+#define MAX_PATH 2048
+
+#define SUCCESS 0
+#define FAILURE -1
+#define Failed(x) (((int) (x)) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+#define STREQ(a,b) (strcmp(a,b) == 0)
+#define NUMELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
+
+/*
+ * Definitions for unsigned "ints"; especially for use in data structures
+ * that will be shared among (potentially) different cpu's (we punt on
+ * byte ordering problems tho)
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * vars controlled by command line options
+ */
+
+int verbose = FALSE; /* be verbose */
+int test_only = FALSE; /* test only */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind, opterr;
+extern int errno;
+
+char *progname; /* for error() */
+
+int process(char *arg);
+void error(int errn, ...);
+long getparm(char *s, long min, long max, char *msg);
+
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* fatal error ; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* fatal error ; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+int Open(), Read(), Write();
+
+int
+main(int argc, char **argv, char **env)
+{
+ register int c;
+ int showusage = FALSE; /* usage error? */
+ int rc = 0;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ opterr = 0; /* we'll report all errors */
+ while ((c = getopt(argc, argv, GETOPTARGS)) != EOF)
+ switch (c)
+ {
+ case 't': /* toggle test only mode */
+ test_only = ! test_only;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ /*
+ * traverse and process the arguments
+ */
+
+ for ( ; argv[optind]; optind++)
+ if (Failed(process(argv[optind])))
+ rc = FAILURE;
+
+ return rc;
+}
+
+
+/*
+ * process(arg)
+ */
+
+int
+process(char *arg)
+{
+ FILE *in;
+ FILE *out = (FILE *) 0;
+ char outname[ MAX_PATH ];
+ char *bptr;
+ char buffer[ BUFFER_SIZE ];
+ int length;
+ int line_number;
+ int rc = SUCCESS; /* succeed by default */
+
+ in = fopen( arg, "r" );
+ if (!in)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+
+ if ( !test_only ) {
+ sprintf( outname, "%s.eoltmp", arg );
+
+ out = fopen( outname, "w" );
+ if (!out)
+ error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
+ }
+
+ if ( verbose )
+ fprintf( stderr, "Processing %s\n", arg );
+
+ for ( line_number=1 ; ; line_number++ ) {
+ bptr = fgets( buffer, BUFFER_SIZE, in );
+ if (!bptr)
+ break;
+
+ /*
+ * Don't count the carriage return.
+ */
+
+ length = strlen( buffer ) - 1;
+
+ if ( buffer[ length ] != '\n' )
+ error(ERR_ERRNO|ERR_FATAL, "Line %d too long in %s\n", line_number, arg);
+
+ while ( isspace( buffer[ length ] ) )
+ buffer[ length-- ] = '\0';
+
+ if ( test_only ) {
+ fprintf( stderr, "%s\n", arg );
+ break;
+ }
+
+ fprintf( out, "%s\n", buffer );
+ }
+
+ fclose( in );
+ if ( !test_only ) {
+ fclose( out );
+ rename( outname, arg );
+ }
+ return rc;
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_FATAL bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+
+long
+getparm(char *s,
+ long min,
+ long max,
+ char *msg)
+{
+ long val;
+
+ if ( ! strchr("0123456789-", *s))
+ {
+ error(ERR_FATAL, "'%s' is not a number", s);
+ return min;
+ }
+
+ val = strtol(s, (char **) NULL, 0);
+ if ((val < min) || (val > max))
+ {
+ if (min == max)
+ error(ERR_FATAL, "%s can only be %ld", s, min);
+ else
+ error(ERR_FATAL, "%s must be between %ld and %ld", msg, min, max);
+ }
+
+ return val;
+}
+
+
+/*
+ * Open()
+ * Perform open(2), returning the file descriptor. Prints
+ * error message if open fails.
+ */
+
+int
+Open(char *file,
+ int oflag,
+ int mode)
+{
+ int O_fd;
+
+ if (Failed(O_fd = open(file, oflag, mode)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "open('%s', 0x%x, 0%o) failed", file, oflag, mode
+ );
+
+ return O_fd;
+}
+
+/*
+ * Read()
+ * Perform read(2); prints error message if fails.
+ */
+
+int
+Read(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = read(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "read(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
+
+/*
+ * Write()
+ * Perform write(2); prints error message if fails.
+ */
+
+int
+Write(int file,
+ char *buffer,
+ unsigned int count)
+{
+ int nbytes;
+
+ if (Failed(nbytes = write(file, buffer, count)))
+ error(
+ ERR_ERRNO | ERR_FATAL,
+ "write(%d, 0x%x, %d) failed", file, buffer, count
+ );
+
+ return nbytes;
+}
diff --git a/c/build-tools/src/packhex.c b/c/build-tools/src/packhex.c
new file mode 100644
index 0000000000..ddd010c4a9
--- /dev/null
+++ b/c/build-tools/src/packhex.c
@@ -0,0 +1,513 @@
+
+/***** P A C K H E X . C ************************************************
+ *
+ * Packhex is a hex-file compaction utility. It attempts to concatenate
+ * hex records to produce more size-efficient packaging.
+ *
+ * Limitations: Input files must be correctly formatted. This utility
+ * is not robust enough to detect hex-record formatting
+ * errors.
+ *
+ * Published: 5/93 Embedded Systems magazine
+ *
+ * Compiler: Microsoft C 6.0
+ * cl /F 1000 packhex.c
+ *
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/* #define SMALLER_RECORDS */
+#ifdef SMALLER_RECORDS
+#define MAX_LEN_S1_RECS 128
+#define MAX_LEN_S2_RECS 128
+#define MAX_LEN_S3_RECS 128
+#else
+#define MAX_LEN_S1_RECS 252
+#define MAX_LEN_S2_RECS 251
+#define MAX_LEN_S3_RECS 250
+#endif
+
+
+/*--------------------------------- includes ---------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__unix__) && !defined(EXIT_FAILURE)
+#define EXIT_FAILURE -1
+#define EXIT_SUCCESS 0
+#endif
+
+/*--------------------------------- defines ----------------------------------*/
+
+#define YES 1
+#define MAX_LINE_SIZE 600
+#define EOS '\0'
+
+
+/*---------------------------------- macros ----------------------------------*/
+
+/* Convert ASCII hexadecimal digit to value. */
+
+#define HEX_DIGIT( C ) ( ( ( ( C ) > '9' ) ? ( C ) + 25 : ( C ) ) & 0xF )
+
+
+/*--------------------------------- typedefs ---------------------------------*/
+
+typedef unsigned char Boolean;
+typedef unsigned char Uchar;
+typedef unsigned int Uint;
+typedef unsigned long Ulong;
+
+typedef struct /* Functions and constant returning Hex-record vital stats. */
+{
+ Boolean ( *is_data_record )( char * );
+ Ulong ( *get_address )( char * );
+ Uint ( *get_data_count )( char * );
+ const Uint max_data_count;
+ char *( *get_data_start )( char * );
+ void ( *put_data_record )( Uint, Ulong, char * );
+} Rec_vitals;
+
+
+/*--------------------------- function prototypes ----------------------------*/
+
+Rec_vitals * identify_first_data_record( char * );
+Ulong get_ndigit_hex( char *, int );
+
+
+/*----------------------------- Intel Hex format -----------------------------*/
+
+/*
+ * Intel Hex data-record layout
+ *
+ * :aabbbbccd...dee
+ *
+ * : - header character
+ * aa - record data byte count, a 2-digit hex value
+ * bbbb - record address, a 4-digit hex value
+ * cc - record type, a 2-digit hex value:
+ * "00" is a data record
+ * "01" is an end-of-data record
+ * "02" is an extended-address record
+ * "03" is a start record
+ * d...d - data (always an even number of chars)
+ * ee - record checksum, a 2-digit hex value
+ * checksum = 2's complement
+ * [ (sum of bytes: aabbbbccd...d) modulo 256 ]
+ */
+
+
+Boolean is_intel_data_rec( char * rec_str )
+{
+ return( ( rec_str[ 0 ] == ':' ) && ( rec_str[ 8 ] == '0' ) );
+}
+
+Uint get_intel_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 1, 2 ) );
+}
+
+Ulong get_intel_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 3, 4 ) );
+}
+
+char * get_intel_rec_data_start( char * rec_str )
+{
+ return( rec_str + 9 );
+}
+
+void put_intel_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = count + ( address >> 8 & 0xff ) + ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ ":%02X%04lX00%s%02X\n", count, address, data_str, (~sum + 1) & 0xff
+ );
+}
+
+
+Rec_vitals intel_hex =
+{
+ is_intel_data_rec,
+ get_intel_rec_address,
+ get_intel_rec_data_count,
+ 255, /* Maximum data bytes in a record. */
+ get_intel_rec_data_start,
+ put_intel_data_rec
+};
+
+
+/*------------------------- Motorola S1-record format ------------------------*/
+
+/*
+ * Motorola S-record data-record layout
+ *
+ * Sabbc...cd...dee
+ *
+ * S - header character
+ * a - record type, a 1-digit value:
+ * "0" is a header record
+ * "1" is a 2-byte-address data record
+ * "2" is a 3-byte-address data record
+ * "3" is a 4-byte-address data record
+ * "7" is a 4-byte-address end-of-data record
+ * "8" is a 3-byte-address end-of-data record
+ * "9" is a 2-byte-address end-of-data record
+ * bb - record length in bytes, a 2-digit hex value
+ * (record length doesn't count the header/type
+ * chars and checksum byte)
+ * c...c - record address, a 4-, 6-, or 8-digit value,
+ * depending on record type
+ * d...d - data (always an even number of chars)
+ * ee - record checksum, a 2-digit hex value
+ * checksum = 1's complement
+ * [ (sum of all bytes: bbc..cd...d) modulo 256 ]
+ */
+
+#define S1_COUNT_OFFSET 3
+
+
+Boolean is_moto_s1_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '1' ) );
+}
+
+Uint get_moto_s1_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S1_COUNT_OFFSET );
+}
+
+Ulong get_moto_s1_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 4 ) );
+}
+
+char * get_moto_s1_rec_data_start( char * rec_str )
+{
+ return( rec_str + 8 );
+}
+
+void put_moto_s1_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S1_COUNT_OFFSET + count +
+ ( address >> 8 & 0xff ) + ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S1%02X%04lX%s%02X\n",
+ count + S1_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s1_rec =
+{
+ is_moto_s1_data_rec,
+ get_moto_s1_rec_address,
+ get_moto_s1_rec_data_count,
+ MAX_LEN_S1_RECS, /* Maximum data bytes in a record. */
+ get_moto_s1_rec_data_start,
+ put_moto_s1_data_rec
+};
+
+
+/*------------------------- Motorola S2-record format ------------------------*/
+
+#define S2_COUNT_OFFSET 4
+
+Boolean is_moto_s2_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '2' ) );
+}
+
+Uint get_moto_s2_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S2_COUNT_OFFSET );
+}
+
+Ulong get_moto_s2_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 6 ) );
+}
+
+char * get_moto_s2_rec_data_start( char * rec_str )
+{
+ return( rec_str + 10 );
+}
+
+void put_moto_s2_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S2_COUNT_OFFSET + count + ( address >> 16 & 0xff ) +
+ ( address >> 8 & 0xff ) +
+ ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S2%02X%06lX%s%02X\n",
+ count + S2_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s2_rec =
+{
+ is_moto_s2_data_rec,
+ get_moto_s2_rec_address,
+ get_moto_s2_rec_data_count,
+ MAX_LEN_S2_RECS, /* Maximum data bytes in a record. */
+ get_moto_s2_rec_data_start,
+ put_moto_s2_data_rec
+};
+
+
+/*------------------------- Motorola S3-record format ------------------------*/
+
+#define S3_COUNT_OFFSET 5
+
+Boolean is_moto_s3_data_rec( char * rec_str )
+{
+ return ( ( rec_str[ 0 ] == 'S' ) && ( rec_str[ 1 ] == '3' ) );
+}
+
+Uint get_moto_s3_rec_data_count( char * rec_str )
+{
+ return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S3_COUNT_OFFSET );
+}
+
+Ulong get_moto_s3_rec_address( char * rec_str )
+{
+ return( get_ndigit_hex( rec_str + 4, 8 ) );
+}
+
+char * get_moto_s3_rec_data_start( char * rec_str )
+{
+ return( rec_str + 12 );
+}
+
+void put_moto_s3_data_rec( Uint count, Ulong address, char * data_str )
+{
+ char *ptr;
+ Uint sum = S3_COUNT_OFFSET + count + ( address >> 24 & 0xff ) +
+ ( address >> 16 & 0xff ) +
+ ( address >> 8 & 0xff ) +
+ ( address & 0xff );
+
+ for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+ sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+ printf(
+ "S3%02X%08lX%s%02X\n",
+ count + S3_COUNT_OFFSET, address, data_str, ~sum & 0xff
+ );
+}
+
+
+Rec_vitals motorola_s3_rec =
+{
+ is_moto_s3_data_rec,
+ get_moto_s3_rec_address,
+ get_moto_s3_rec_data_count,
+ MAX_LEN_S3_RECS, /* Maximum data bytes in a record. */
+ get_moto_s3_rec_data_start,
+ put_moto_s3_data_rec
+};
+
+
+/*-------------------- Put your favorite hex format here ---------------------*/
+
+/*
+ * * * * The following is a template for an additional hex format: * * *
+ *
+ *
+ * Boolean is_X_data_rec( char * rec_str ) {}
+ *
+ * Uint get_X_rec_data_count( char * rec_str ) {}
+ *
+ * Ulong get_X_rec_address( char * rec_str ) {}
+ *
+ * char * get_X_rec_data_start( char * rec_str ) {}
+ *
+ * void put_X_data_rec( Uint count, Ulong address, char * data_str ) {}
+ *
+ * Rec_vitals X_rec =
+ * {
+ * is_X_data_rec,
+ * get_X_rec_address,
+ * get_X_rec_data_count,
+ * MAXIMUM DATA BYTES IN A RECORD,
+ * get_X_rec_data_start,
+ * put_X_data_rec
+ * };
+ *
+ */
+
+/*----------------------------------------------------------------------------*/
+
+
+/*
+ * Put address of additional Rec_vitals structures
+ * in this array, before the NULL entry.
+ */
+
+Rec_vitals *formats[] =
+{
+ &intel_hex,
+ &motorola_s1_rec,
+ &motorola_s2_rec,
+ &motorola_s3_rec,
+ ( Rec_vitals * ) NULL
+};
+
+
+/**** main *****************************************************************
+*
+*
+* Expects: Nothing (no command-line parameters).
+*
+* Returns: Exit status (EXIT_SUCCESS or EXIT_FAILURE).
+*
+* Reads hex records on the standard input and attempts to
+* splice adjacent data fields together. Results appear on
+* the standard output.
+*
+*******************************************************************************/
+
+void main( void )
+{
+
+ char inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ];
+ char *in_dptr, *out_dptr;
+ int d_total, d_count, d_excess, n;
+ Ulong in_rec_addr, out_rec_addr = 0;
+ Rec_vitals *rptr;
+
+
+ /* Sift through file until first hex record is identified. */
+ if ( ( rptr = identify_first_data_record( inbuff ) ) == NULL )
+ {
+ fputs( "No hex records found.\n", stderr );
+ exit( EXIT_FAILURE );
+ }
+
+
+ /* Attempt data-record splicing until end-of-file is reached. */
+ d_total = 0;
+ do
+ {
+ if ( rptr->is_data_record( inbuff ) == YES )
+ { /* Input record is a data record. */
+ d_count = rptr->get_data_count( inbuff );
+ in_rec_addr = rptr->get_address( inbuff );
+ in_dptr = rptr->get_data_start( inbuff );
+
+ if ( d_total == 0 || in_rec_addr != out_rec_addr + d_total )
+ { /* Begin a new output record. */
+ if ( d_total != 0 )
+ rptr->put_data_record( d_total, out_rec_addr, outbuff );
+ out_dptr = outbuff;
+ n = d_total = d_count;
+ out_rec_addr = in_rec_addr;
+ }
+ else if
+ ( ( d_excess = d_total + d_count - rptr->max_data_count ) > 0 )
+ { /* Output a maximum-length record, then start a new record. */
+ strncat( outbuff, in_dptr, 2 * ( d_count - d_excess ) );
+ rptr->put_data_record(
+ rptr->max_data_count, out_rec_addr, outbuff
+ );
+ in_dptr += 2 * ( d_count - d_excess );
+ out_dptr = outbuff;
+ n = d_total = d_excess;
+ out_rec_addr += rptr->max_data_count;
+ }
+ else
+ { /* Append input record's data field with accumulated data. */
+ out_dptr = outbuff + ( 2 * d_total );
+ d_total += n = d_count;
+ }
+ strncpy( out_dptr, in_dptr, 2 * n );
+ out_dptr[ 2 * n ] = EOS;
+ }
+ else
+ { /* Not a data record;
+ * flush accumulated data then echo non-data record.
+ */
+ if ( d_total != 0 )
+ {
+ rptr->put_data_record( d_total, out_rec_addr, outbuff );
+ d_total = 0;
+ }
+ puts( inbuff );
+ }
+ } while ( gets( inbuff ) != NULL );
+
+
+ exit( EXIT_SUCCESS );
+
+}
+
+
+/**** identify_first_data_record *******************************************
+*
+* Expects: Pointer to hex-record line buffer.
+*
+* Returns: Pointer to hex-record structure (NULL if no match found).
+*
+* Reads the standard input, line by line, searching for a valid
+* record header character. If a valid header is found, a pointer
+* to the hex-record's type structure is returned, otherwise NULL.
+*
+* The input-stream pointer is left pointing to the first valid hex record.
+*
+*******************************************************************************/
+
+Rec_vitals * identify_first_data_record( char * buff_ptr )
+{
+ Rec_vitals ** ptr;
+
+ while ( gets( buff_ptr ) != NULL )
+ {
+ for ( ptr = formats ; *ptr != ( Rec_vitals * ) NULL ; ptr++ )
+ if ( ( *ptr )->is_data_record( buff_ptr ) == YES )
+ return( *ptr ); /* Successful return. */
+
+ puts( buff_ptr ); /* Echo non-hex-record line. */
+ }
+
+ return( ( Rec_vitals * ) NULL ); /* Unsuccessful return. */
+}
+
+
+/**** get_ndigit_hex *******************************************************
+*
+* Expects: Pointer to first ASCII hexadecimal digit, number of digits.
+*
+* Returns: Value of hexadecimal string as an unsigned long.
+*
+*******************************************************************************/
+
+Ulong get_ndigit_hex( char * cptr, int digits )
+{
+ Ulong value;
+
+ for ( value = 0 ; --digits >= 0 ; cptr++ )
+ value = ( value * 16L ) + HEX_DIGIT( *cptr );
+
+ return( value );
+}
diff --git a/c/build-tools/src/unhex.c b/c/build-tools/src/unhex.c
new file mode 100644
index 0000000000..540095d6f4
--- /dev/null
+++ b/c/build-tools/src/unhex.c
@@ -0,0 +1,719 @@
+/*
+ * unhex
+ * convert a hex file to binary equivalent. If more than one file name
+ * is given, then the output will be logically concatenated together.
+ * stdin and stdout are defaults. Verbose will enable checksum output.
+ *
+ * Supported input formats are Intel hex, Motorola S records, and TI 'B'
+ * records.
+ *
+ * Intel hex input format is
+ * Byte
+ * 1 Colon :
+ * 2..3 Record length, eg: "20"
+ * 4..7 load address nibbles
+ * 8..9 record type: "00" (data) or "02" base addr
+ * 10..x data bytes in ascii-hex
+ * x+1..x+2 cksum (2's compl of (len+addr+data))
+ * x+3 \n -- newline
+ */
+
+char *USAGE = "\
+usage: unhex [-va] [ -o file ] [ file [file ... ] ]\n\
+ -v -- verbose\n\
+ -a base -- 1st byte of output corresponds to this address\n\
+ -l -- linear, just writes data out\n\
+ -o file -- output file; must not be input file\n\
+ -F k_bits -- \"holes\" in input will be filled with 0xFF's\n\
+ up to \"k_bits\" * 1024 bits\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define OK 0
+#define FAILURE (-1)
+#define Failed(x) ((x) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+typedef char bool;
+#define STREQ(a,b) (strcmp(a,b) == 0)
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * Pick out designated bytes
+ */
+
+#define B0(x) ((x) & 0xff)
+#define B1(x) B0((x) >> 8)
+#define B2(x) B0((x) >> 16)
+#define B3(x) B0((x) >> 24)
+
+typedef struct buffer_rec {
+ u32 dl_destaddr;
+ u32 dl_jumpaddr;
+ int dl_count;
+ u8 dl_buf[512];
+} buffer_rec;
+
+/*
+ * vars controlled by command line options
+ */
+
+bool verbose = FALSE; /* be verbose */
+bool linear = FALSE; /* just write out linear data */
+char *outfilename = "-"; /* default output is stdout */
+u32 base = 0L; /* base address */
+u32 FFfill = 0L; /* how far to fill w 0xFF's */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind;
+extern int errno;
+
+char *progname; /* for error() */
+
+void error(int errn, ...);
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* error is fatal; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* error is fatal; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+
+int unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_Intel_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_TI_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+void write_record(buffer_rec *tb, FILE *fp);
+int getnibble(char **p);
+int getbyte(char **p);
+long getNbytes(char **p, int n);
+void badformat(char *s, char *fname, char *msg);
+
+#define get1bytes(p) ((int) getbyte(p))
+#define get2bytes(p) ((int) getNbytes(p, 2))
+#define get3bytes(p) getNbytes(p, 3)
+#define get4bytes(p) getNbytes(p, 4)
+
+char *BADADDR = "Invalid record address";
+char *BADLEN = "Invalid record length";
+char *BADBASE = "Bad base or starting address";
+char *BADFMT = "Unrecognized record type";
+char *BADDATA = "Invalid data byte";
+char *BADCSUM = "Invalid checksum";
+char *MISCSUM = "Checksum mismatch";
+char *BADTYPE = "Unrecognized record type";
+char *MISTYPE = "Incompatible record types";
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ register int c;
+ bool showusage = FALSE; /* usage error? */
+ int rc = 0;
+ FILE *outfp, *infp;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF)
+ switch (c)
+ {
+ case 'a': /* base address */
+ base = stol(optarg);
+ break;
+
+ case 'l': /* linear output */
+ linear = TRUE;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case 'o': /* output file */
+ outfilename = optarg;
+ break;
+
+ case 'F': /* 0xFF fill amount (bytes) */
+ FFfill = stol(optarg) * 1024L / 8L;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ if (linear && (base != 0))
+ {
+ error(0, "-l and -a may not be specified in combination");
+ exit(1);
+ }
+
+ if (STREQ(outfilename, "-"))
+ {
+ outfp = stdout;
+ outfilename = "stdout";
+ }
+ else
+ if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL)
+ {
+ error(-1, "couldn't open '%s' for output", outfilename);
+ exit(1);
+ }
+
+ /*
+ * Now process the input files (or stdin, if none specified)
+ */
+
+ if (argv[optind] == (char *) NULL) /* just stdin */
+ exit(unhex(stdin, "stdin", outfp, outfilename));
+ else
+ for (; (optarg = argv[optind]); optind++)
+ {
+ if (STREQ(optarg, "-"))
+ rc += unhex(stdin, "stdin", outfp, outfilename);
+ else
+ {
+ if ((infp = fopen(optarg, "r")) == (FILE *) NULL)
+ {
+ error(-1, "couldn't open '%s' for input", optarg);
+ exit(1);
+ }
+ rc += unhex(infp, optarg, outfp, outfilename);
+ }
+ }
+
+ return(rc);
+}
+
+u16 filesum;
+
+int
+unhex(FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ int c;
+
+ filesum = 0;
+
+ /*
+ * Make sure holes will be filled with 0xFF's if requested. We
+ * do this the easy way by just filling the file with FF's before
+ * getting started. To do it more optimally would be quite a bit
+ * more difficult since the user can skip around as much as he/she
+ * likes in the input hex file addressing.
+ *
+ * We'll clean this up later (after this program has run) with
+ * 'stripffs'
+ */
+
+ if (FFfill)
+ {
+ (void) fseek(ofp, 0, 0);
+ for (c = FFfill; c > 0; c--)
+ (void) fputc(0xFF, ofp);
+ }
+
+ /*
+ * Read the first char from file and determine record types
+ */
+
+ if ((c = getc(ifp)) != EOF)
+ {
+ ungetc(c, ifp);
+ switch(c)
+ {
+ case 'S':
+ convert_S_records(ifp, inm, ofp, onm);
+ break;
+
+ case ':':
+ convert_Intel_records(ifp, inm, ofp, onm);
+ break;
+
+ case '9':
+ case 'B':
+ convert_TI_records(ifp, inm, ofp, onm);
+ break;
+
+ default:
+ {
+ char tmp[2];
+ tmp[0] = c; tmp[1] = 0;
+ badformat(tmp, inm, BADFMT);
+ }
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
+
+ return 0;
+}
+
+int
+convert_Intel_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ u8 cksum;
+ int incksum;
+ int c;
+ int rectype; /* record type */
+ int len; /* data length of current line */
+ u32 addr;
+ u32 base_address = 0;
+ bool endrecord = FALSE;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ p = &buff[0];
+
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ if (*p != ':')
+ badformat(p, inm, BADFMT);
+ p++;
+
+ if ((len = getbyte(&p)) == -1) /* record len */
+ badformat(buff, inm, BADLEN);
+
+ if ((addr = get2bytes(&p)) == -1L) /* record addr */
+ badformat(buff, inm, BADADDR);
+
+ rectype = getbyte(&p);
+
+ cksum = len + B0(addr) + B1(addr) + rectype;
+
+ switch (rectype)
+ {
+ case 0x00: /* normal data record */
+ tb.dl_destaddr = base_address + addr;
+ while (len--)
+ {
+ if ((c = getbyte(&p)) == -1)
+ badformat(buff, inm, BADDATA);
+ cksum += c;
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ }
+ break;
+
+ case 0x01: /* execution start address */
+ base_address = addr;
+ endrecord = TRUE;
+ break;
+
+ case 0x02: /* new base */
+ if ((base_address = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADBASE);
+ cksum += B0(base_address) + B1(base_address);
+ base_address <<= 4;
+ break;
+
+ case 0x03: /* seg/off execution start address */
+ {
+ u32 seg, off;
+
+ seg = get2bytes(&p);
+ off = get2bytes(&p);
+ if ((seg == -1L) || (off == -1L))
+ badformat(buff, inm, BADADDR);
+
+ cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
+
+ tb.dl_jumpaddr = (seg << 4) + off;
+ break;
+ }
+
+ default:
+ error(0, "unknown Intel-hex record type: 0x%02x", rectype);
+ badformat(buff, inm, BADTYPE);
+ }
+
+ /*
+ * Verify checksums are correct in file.
+ */
+
+ cksum = (-cksum) & 0xff;
+ if ((incksum = getbyte(&p)) == -1)
+ badformat(buff, inm, BADCSUM);
+ if (((u8) incksum) != cksum)
+ badformat(buff, inm, MISCSUM);
+
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+int
+convert_S_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ u8 cksum;
+ int incksum;
+ int c;
+ int len; /* data length of current line */
+ int rectype; /* record type */
+ u32 addr;
+ bool endrecord = FALSE;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ p = &buff[0];
+
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ if (*p != 'S')
+ badformat(p, inm, BADFMT);
+ p++;
+
+ if ((rectype = getnibble(&p)) == -1) /* record type */
+ badformat(buff, inm, BADTYPE);
+
+ if ((len = getbyte(&p)) == -1) /* record len */
+ badformat(buff, inm, BADLEN);
+ cksum = len;
+
+ switch (rectype)
+ {
+ case 0x00: /* comment field, ignored */
+ goto write_it;
+
+ case 0x01: /* data record, 16 bit addr */
+ if ((addr = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 3;
+ goto doit;
+
+ case 0x02: /* ... 24 bit addr */
+ if ((addr = get3bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 4;
+ goto doit;
+
+ case 0x03: /* ... 32 bit addr */
+ if ((addr = get4bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 5;
+ doit:
+ cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
+
+ tb.dl_destaddr = addr;
+ while (len--)
+ {
+ if ((c = getbyte(&p)) == -1)
+ badformat(buff, inm, BADDATA);
+ cksum += c;
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ }
+ break;
+
+ case 0x07: /* 32 bit end record */
+ if ((addr = get4bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ goto end_rec;
+
+ case 0x08: /* 24 bit end record */
+ if ((addr = get3bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ goto end_rec;
+
+ case 0x09: /* 16 bit end record */
+ if ((addr = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+
+end_rec:
+ cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
+ tb.dl_jumpaddr = addr;
+ break;
+
+ default:
+ error(0, "unknown Motorola-S record type: 0x%02x", rectype);
+ badformat(buff, inm, BADTYPE);
+ break;
+ }
+
+ /*
+ * Verify checksums are correct in file.
+ */
+
+ cksum = (~cksum) & 0xff;
+ if ((incksum = getbyte(&p)) == -1)
+ badformat(buff, inm, BADCSUM);
+ if (((u8) incksum) != cksum)
+ badformat(buff, inm, MISCSUM);
+
+write_it:
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+int
+convert_TI_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ int c;
+ bool endrecord = FALSE;
+ bool eol;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ p = &buff[0];
+ eol = FALSE;
+ while ( ! eol && ! endrecord)
+ {
+ switch (*p++)
+ {
+ case '9':
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ tb.dl_destaddr = get2bytes(&p);
+ break;
+
+ case 'B':
+ c = getbyte(&p);
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ c = getbyte(&p);
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ break;
+
+ case 'F':
+ eol = TRUE;
+ break;
+
+ case ':':
+ endrecord = TRUE;
+ break;
+
+ default:
+ badformat(p, inm, BADFMT);
+ }
+ }
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+void
+write_record(buffer_rec *tb,
+ FILE *fp)
+{
+ if ( ! linear)
+ {
+ if (tb->dl_destaddr < base)
+ error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
+ tb->dl_destaddr, base);
+ (void) fseek(fp, tb->dl_destaddr - base, 0);
+ }
+
+ (void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
+ tb->dl_destaddr += tb->dl_count;
+ tb->dl_count = 0;
+}
+
+int
+getnibble(char **p)
+{
+ register int val;
+
+ **p = toupper(**p);
+ switch (**p)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ val = **p - '0';
+ break;
+
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ val = 10 + (**p - 'A');
+ break;
+
+ default:
+ return(-1);
+ }
+ *p += 1;
+
+ return(val & 0x0f);
+}
+
+int
+getbyte(char **p)
+{
+ int n0, n1;
+
+ if ((n0 = getnibble(p)) == -1)
+ return(-1);
+ if ((n1 = getnibble(p)) == -1)
+ return(-1);
+
+ return(((n0 << 4) + n1) & 0xff);
+}
+
+long
+getNbytes(char **p,
+ int n)
+{
+ int t;
+ u32 val = 0;
+
+ while (n--)
+ {
+ if ((t = getbyte(p)) == -1)
+ return(-1L);
+ val <<= 8;
+ val += t;
+ }
+
+ return(val);
+}
+
+void
+badformat(char *s,
+ char *fname,
+ char *msg)
+{
+ if (s[strlen(s)-1] == '\n') /* get rid of newline */
+ s[strlen(s)-1] = '\0';
+ error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
+ exit(1);
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_EXIT bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+
diff --git a/c/build-tools/unhex.c b/c/build-tools/unhex.c
new file mode 100644
index 0000000000..540095d6f4
--- /dev/null
+++ b/c/build-tools/unhex.c
@@ -0,0 +1,719 @@
+/*
+ * unhex
+ * convert a hex file to binary equivalent. If more than one file name
+ * is given, then the output will be logically concatenated together.
+ * stdin and stdout are defaults. Verbose will enable checksum output.
+ *
+ * Supported input formats are Intel hex, Motorola S records, and TI 'B'
+ * records.
+ *
+ * Intel hex input format is
+ * Byte
+ * 1 Colon :
+ * 2..3 Record length, eg: "20"
+ * 4..7 load address nibbles
+ * 8..9 record type: "00" (data) or "02" base addr
+ * 10..x data bytes in ascii-hex
+ * x+1..x+2 cksum (2's compl of (len+addr+data))
+ * x+3 \n -- newline
+ */
+
+char *USAGE = "\
+usage: unhex [-va] [ -o file ] [ file [file ... ] ]\n\
+ -v -- verbose\n\
+ -a base -- 1st byte of output corresponds to this address\n\
+ -l -- linear, just writes data out\n\
+ -o file -- output file; must not be input file\n\
+ -F k_bits -- \"holes\" in input will be filled with 0xFF's\n\
+ up to \"k_bits\" * 1024 bits\n\
+";
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define OK 0
+#define FAILURE (-1)
+#define Failed(x) ((x) == FAILURE)
+#define TRUE 1
+#define FALSE 0
+typedef char bool;
+#define STREQ(a,b) (strcmp(a,b) == 0)
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+/*
+ * Pick out designated bytes
+ */
+
+#define B0(x) ((x) & 0xff)
+#define B1(x) B0((x) >> 8)
+#define B2(x) B0((x) >> 16)
+#define B3(x) B0((x) >> 24)
+
+typedef struct buffer_rec {
+ u32 dl_destaddr;
+ u32 dl_jumpaddr;
+ int dl_count;
+ u8 dl_buf[512];
+} buffer_rec;
+
+/*
+ * vars controlled by command line options
+ */
+
+bool verbose = FALSE; /* be verbose */
+bool linear = FALSE; /* just write out linear data */
+char *outfilename = "-"; /* default output is stdout */
+u32 base = 0L; /* base address */
+u32 FFfill = 0L; /* how far to fill w 0xFF's */
+
+extern char *optarg; /* getopt(3) control vars */
+extern int optind;
+extern int errno;
+
+char *progname; /* for error() */
+
+void error(int errn, ...);
+#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
+#define ERR_FATAL (ERR_ERRNO / 2) /* error is fatal; no return */
+#define ERR_ABORT (ERR_ERRNO / 4) /* error is fatal; abort */
+#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
+
+#define stol(p) strtol(p, (char **) NULL, 0)
+
+int unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_Intel_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+int convert_TI_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
+void write_record(buffer_rec *tb, FILE *fp);
+int getnibble(char **p);
+int getbyte(char **p);
+long getNbytes(char **p, int n);
+void badformat(char *s, char *fname, char *msg);
+
+#define get1bytes(p) ((int) getbyte(p))
+#define get2bytes(p) ((int) getNbytes(p, 2))
+#define get3bytes(p) getNbytes(p, 3)
+#define get4bytes(p) getNbytes(p, 4)
+
+char *BADADDR = "Invalid record address";
+char *BADLEN = "Invalid record length";
+char *BADBASE = "Bad base or starting address";
+char *BADFMT = "Unrecognized record type";
+char *BADDATA = "Invalid data byte";
+char *BADCSUM = "Invalid checksum";
+char *MISCSUM = "Checksum mismatch";
+char *BADTYPE = "Unrecognized record type";
+char *MISTYPE = "Incompatible record types";
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ register int c;
+ bool showusage = FALSE; /* usage error? */
+ int rc = 0;
+ FILE *outfp, *infp;
+
+ /*
+ * figure out invocation leaf-name
+ */
+
+ if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ argv[0] = progname; /* for getopt err reporting */
+
+ /*
+ * Check options and arguments.
+ */
+
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF)
+ switch (c)
+ {
+ case 'a': /* base address */
+ base = stol(optarg);
+ break;
+
+ case 'l': /* linear output */
+ linear = TRUE;
+ break;
+
+ case 'v': /* toggle verbose */
+ verbose = ! verbose;
+ break;
+
+ case 'o': /* output file */
+ outfilename = optarg;
+ break;
+
+ case 'F': /* 0xFF fill amount (bytes) */
+ FFfill = stol(optarg) * 1024L / 8L;
+ break;
+
+ case '?':
+ showusage = TRUE;
+ }
+
+ if (showusage)
+ {
+ (void) fprintf(stderr, "%s", USAGE);
+ exit(1);
+ }
+
+ if (linear && (base != 0))
+ {
+ error(0, "-l and -a may not be specified in combination");
+ exit(1);
+ }
+
+ if (STREQ(outfilename, "-"))
+ {
+ outfp = stdout;
+ outfilename = "stdout";
+ }
+ else
+ if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL)
+ {
+ error(-1, "couldn't open '%s' for output", outfilename);
+ exit(1);
+ }
+
+ /*
+ * Now process the input files (or stdin, if none specified)
+ */
+
+ if (argv[optind] == (char *) NULL) /* just stdin */
+ exit(unhex(stdin, "stdin", outfp, outfilename));
+ else
+ for (; (optarg = argv[optind]); optind++)
+ {
+ if (STREQ(optarg, "-"))
+ rc += unhex(stdin, "stdin", outfp, outfilename);
+ else
+ {
+ if ((infp = fopen(optarg, "r")) == (FILE *) NULL)
+ {
+ error(-1, "couldn't open '%s' for input", optarg);
+ exit(1);
+ }
+ rc += unhex(infp, optarg, outfp, outfilename);
+ }
+ }
+
+ return(rc);
+}
+
+u16 filesum;
+
+int
+unhex(FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ int c;
+
+ filesum = 0;
+
+ /*
+ * Make sure holes will be filled with 0xFF's if requested. We
+ * do this the easy way by just filling the file with FF's before
+ * getting started. To do it more optimally would be quite a bit
+ * more difficult since the user can skip around as much as he/she
+ * likes in the input hex file addressing.
+ *
+ * We'll clean this up later (after this program has run) with
+ * 'stripffs'
+ */
+
+ if (FFfill)
+ {
+ (void) fseek(ofp, 0, 0);
+ for (c = FFfill; c > 0; c--)
+ (void) fputc(0xFF, ofp);
+ }
+
+ /*
+ * Read the first char from file and determine record types
+ */
+
+ if ((c = getc(ifp)) != EOF)
+ {
+ ungetc(c, ifp);
+ switch(c)
+ {
+ case 'S':
+ convert_S_records(ifp, inm, ofp, onm);
+ break;
+
+ case ':':
+ convert_Intel_records(ifp, inm, ofp, onm);
+ break;
+
+ case '9':
+ case 'B':
+ convert_TI_records(ifp, inm, ofp, onm);
+ break;
+
+ default:
+ {
+ char tmp[2];
+ tmp[0] = c; tmp[1] = 0;
+ badformat(tmp, inm, BADFMT);
+ }
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
+
+ return 0;
+}
+
+int
+convert_Intel_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ u8 cksum;
+ int incksum;
+ int c;
+ int rectype; /* record type */
+ int len; /* data length of current line */
+ u32 addr;
+ u32 base_address = 0;
+ bool endrecord = FALSE;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ p = &buff[0];
+
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ if (*p != ':')
+ badformat(p, inm, BADFMT);
+ p++;
+
+ if ((len = getbyte(&p)) == -1) /* record len */
+ badformat(buff, inm, BADLEN);
+
+ if ((addr = get2bytes(&p)) == -1L) /* record addr */
+ badformat(buff, inm, BADADDR);
+
+ rectype = getbyte(&p);
+
+ cksum = len + B0(addr) + B1(addr) + rectype;
+
+ switch (rectype)
+ {
+ case 0x00: /* normal data record */
+ tb.dl_destaddr = base_address + addr;
+ while (len--)
+ {
+ if ((c = getbyte(&p)) == -1)
+ badformat(buff, inm, BADDATA);
+ cksum += c;
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ }
+ break;
+
+ case 0x01: /* execution start address */
+ base_address = addr;
+ endrecord = TRUE;
+ break;
+
+ case 0x02: /* new base */
+ if ((base_address = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADBASE);
+ cksum += B0(base_address) + B1(base_address);
+ base_address <<= 4;
+ break;
+
+ case 0x03: /* seg/off execution start address */
+ {
+ u32 seg, off;
+
+ seg = get2bytes(&p);
+ off = get2bytes(&p);
+ if ((seg == -1L) || (off == -1L))
+ badformat(buff, inm, BADADDR);
+
+ cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
+
+ tb.dl_jumpaddr = (seg << 4) + off;
+ break;
+ }
+
+ default:
+ error(0, "unknown Intel-hex record type: 0x%02x", rectype);
+ badformat(buff, inm, BADTYPE);
+ }
+
+ /*
+ * Verify checksums are correct in file.
+ */
+
+ cksum = (-cksum) & 0xff;
+ if ((incksum = getbyte(&p)) == -1)
+ badformat(buff, inm, BADCSUM);
+ if (((u8) incksum) != cksum)
+ badformat(buff, inm, MISCSUM);
+
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+int
+convert_S_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ u8 cksum;
+ int incksum;
+ int c;
+ int len; /* data length of current line */
+ int rectype; /* record type */
+ u32 addr;
+ bool endrecord = FALSE;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ p = &buff[0];
+
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ if (*p != 'S')
+ badformat(p, inm, BADFMT);
+ p++;
+
+ if ((rectype = getnibble(&p)) == -1) /* record type */
+ badformat(buff, inm, BADTYPE);
+
+ if ((len = getbyte(&p)) == -1) /* record len */
+ badformat(buff, inm, BADLEN);
+ cksum = len;
+
+ switch (rectype)
+ {
+ case 0x00: /* comment field, ignored */
+ goto write_it;
+
+ case 0x01: /* data record, 16 bit addr */
+ if ((addr = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 3;
+ goto doit;
+
+ case 0x02: /* ... 24 bit addr */
+ if ((addr = get3bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 4;
+ goto doit;
+
+ case 0x03: /* ... 32 bit addr */
+ if ((addr = get4bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ len -= 5;
+ doit:
+ cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
+
+ tb.dl_destaddr = addr;
+ while (len--)
+ {
+ if ((c = getbyte(&p)) == -1)
+ badformat(buff, inm, BADDATA);
+ cksum += c;
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ }
+ break;
+
+ case 0x07: /* 32 bit end record */
+ if ((addr = get4bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ goto end_rec;
+
+ case 0x08: /* 24 bit end record */
+ if ((addr = get3bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+ goto end_rec;
+
+ case 0x09: /* 16 bit end record */
+ if ((addr = get2bytes(&p)) == -1L)
+ badformat(buff, inm, BADADDR);
+
+end_rec:
+ cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
+ tb.dl_jumpaddr = addr;
+ break;
+
+ default:
+ error(0, "unknown Motorola-S record type: 0x%02x", rectype);
+ badformat(buff, inm, BADTYPE);
+ break;
+ }
+
+ /*
+ * Verify checksums are correct in file.
+ */
+
+ cksum = (~cksum) & 0xff;
+ if ((incksum = getbyte(&p)) == -1)
+ badformat(buff, inm, BADCSUM);
+ if (((u8) incksum) != cksum)
+ badformat(buff, inm, MISCSUM);
+
+write_it:
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+int
+convert_TI_records(
+ FILE *ifp,
+ char *inm,
+ FILE *ofp,
+ char *onm)
+{
+ char buff[512];
+ char *p;
+ int c;
+ bool endrecord = FALSE;
+ bool eol;
+ buffer_rec tb;
+
+ while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
+ {
+ if (p[strlen(p)-1] == '\n') /* get rid of newline */
+ p[strlen(p)-1] = '\0';
+
+ if (p[strlen(p)-1] == '\r') /* get rid of any CR */
+ p[strlen(p)-1] = '\0';
+
+ tb.dl_count = 0;
+
+ p = &buff[0];
+ eol = FALSE;
+ while ( ! eol && ! endrecord)
+ {
+ switch (*p++)
+ {
+ case '9':
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ tb.dl_destaddr = get2bytes(&p);
+ break;
+
+ case 'B':
+ c = getbyte(&p);
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ c = getbyte(&p);
+ filesum += c;
+ tb.dl_buf[tb.dl_count++] = c;
+ break;
+
+ case 'F':
+ eol = TRUE;
+ break;
+
+ case ':':
+ endrecord = TRUE;
+ break;
+
+ default:
+ badformat(p, inm, BADFMT);
+ }
+ }
+ if (tb.dl_count)
+ write_record(&tb, ofp);
+ }
+ return 0;
+}
+
+void
+write_record(buffer_rec *tb,
+ FILE *fp)
+{
+ if ( ! linear)
+ {
+ if (tb->dl_destaddr < base)
+ error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
+ tb->dl_destaddr, base);
+ (void) fseek(fp, tb->dl_destaddr - base, 0);
+ }
+
+ (void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
+ tb->dl_destaddr += tb->dl_count;
+ tb->dl_count = 0;
+}
+
+int
+getnibble(char **p)
+{
+ register int val;
+
+ **p = toupper(**p);
+ switch (**p)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ val = **p - '0';
+ break;
+
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ val = 10 + (**p - 'A');
+ break;
+
+ default:
+ return(-1);
+ }
+ *p += 1;
+
+ return(val & 0x0f);
+}
+
+int
+getbyte(char **p)
+{
+ int n0, n1;
+
+ if ((n0 = getnibble(p)) == -1)
+ return(-1);
+ if ((n1 = getnibble(p)) == -1)
+ return(-1);
+
+ return(((n0 << 4) + n1) & 0xff);
+}
+
+long
+getNbytes(char **p,
+ int n)
+{
+ int t;
+ u32 val = 0;
+
+ while (n--)
+ {
+ if ((t = getbyte(p)) == -1)
+ return(-1L);
+ val <<= 8;
+ val += t;
+ }
+
+ return(val);
+}
+
+void
+badformat(char *s,
+ char *fname,
+ char *msg)
+{
+ if (s[strlen(s)-1] == '\n') /* get rid of newline */
+ s[strlen(s)-1] = '\0';
+ error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
+ exit(1);
+}
+
+/*
+ * error(errn, arglist)
+ * report an error to stderr using printf(3) conventions.
+ * Any output is preceded by '<progname>: '
+ *
+ * Uses ERR_EXIT bit to request exit(errn)
+ * ERR_ABORT to request abort()
+ * ERR_ERRNO to indicate use of errno instead of argument.
+ *
+ * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
+ * associated error message is appended to the output.
+ */
+
+/*VARARGS*/
+
+void
+error(int error_flag, ...)
+{
+ va_list arglist;
+ register char *format;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ int local_errno;
+
+ extern int errno;
+
+ (void) fflush(stdout); /* in case stdout/stderr same */
+
+ local_errno = error_flag & ~ERR_MASK;
+ if (error_flag & ERR_ERRNO) /* use errno? */
+ local_errno = errno;
+
+ va_start(arglist, error_flag);
+ format = va_arg(arglist, char *);
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, format, arglist);
+ va_end(arglist);
+
+ if (local_errno)
+ if ((local_errno > 0) && (local_errno < sys_nerr))
+ (void) fprintf(stderr, " (%s)\n", sys_errlist[local_errno]);
+ else
+ (void) fprintf(stderr, " (unknown errno=%d)\n", local_errno);
+ else
+ (void) fprintf(stderr, "\n");
+
+ (void) fflush(stderr);
+
+ if (error_flag & (ERR_FATAL | ERR_ABORT))
+ {
+ if (error_flag & ERR_FATAL)
+ {
+ error(0, local_errno ? "fatal error, exiting" : "exiting");
+ exit(local_errno);
+ }
+ else
+ {
+ error(0, "fatal error, aborting");
+ abort();
+ }
+ }
+}
+