diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-05-17 20:39:40 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-05-17 20:39:40 +0000 |
commit | d751cecbb1ca1b7ac0a7bc8492e0e61e6c5fc0c7 (patch) | |
tree | 84a74c59b9f7f096e0fae3dd351e5274bf836bb5 /tools/build | |
parent | 2011-05-17 Joel Sherrill <joel.sherrill@oarcorp.com> (diff) | |
download | rtems-d751cecbb1ca1b7ac0a7bc8492e0e61e6c5fc0c7.tar.bz2 |
* tools/build/.cvsignore, tools/build/ChangeLog,
tools/build/Makefile.am, tools/build/README, tools/build/binpatch.c,
tools/build/cklength.c, tools/build/config.h.in,
tools/build/configure.ac, tools/build/cvsignore-add.sh,
tools/build/doxy-filter, tools/build/eolstrip.c,
tools/build/install-if-change.in, tools/build/multigen,
tools/build/packhex.c, tools/build/rtems-bin2c.c,
tools/build/search-id.sh, tools/build/unhex.c, tools/cpu/.cvsignore,
tools/cpu/ChangeLog, tools/cpu/Makefile.am, tools/cpu/configure.ac,
tools/cpu/generic/.cvsignore, tools/cpu/generic/ChangeLog,
tools/cpu/generic/Makefile.am, tools/cpu/generic/configure.ac,
tools/cpu/generic/size_rtems.in, tools/cpu/nios2/.cvsignore,
tools/cpu/nios2/ChangeLog, tools/cpu/nios2/Makefile.am,
tools/cpu/nios2/README, tools/cpu/nios2/bridges.c,
tools/cpu/nios2/bridges.h, tools/cpu/nios2/clocks.c,
tools/cpu/nios2/clocks.h, tools/cpu/nios2/configure.ac,
tools/cpu/nios2/devices.c, tools/cpu/nios2/devices.h,
tools/cpu/nios2/linkcmds.c, tools/cpu/nios2/linkcmds.h,
tools/cpu/nios2/memory.c, tools/cpu/nios2/memory.h,
tools/cpu/nios2/nios2gen.c, tools/cpu/nios2/output.c,
tools/cpu/nios2/output.h, tools/cpu/nios2/ptf.c,
tools/cpu/nios2/ptf.h, tools/cpu/nios2/sample.ptf,
tools/cpu/sh/.cvsignore, tools/cpu/sh/AUTHORS, tools/cpu/sh/COPYING,
tools/cpu/sh/ChangeLog, tools/cpu/sh/Makefile.am, tools/cpu/sh/TODO,
tools/cpu/sh/configure.ac, tools/cpu/sh/sci.c, tools/cpu/sh/sci.h,
tools/cpu/sh/shgen.c: New files.
Diffstat (limited to 'tools/build')
-rw-r--r-- | tools/build/.cvsignore | 18 | ||||
-rw-r--r-- | tools/build/ChangeLog | 209 | ||||
-rw-r--r-- | tools/build/Makefile.am | 26 | ||||
-rw-r--r-- | tools/build/README | 10 | ||||
-rw-r--r-- | tools/build/binpatch.c | 156 | ||||
-rw-r--r-- | tools/build/cklength.c | 377 | ||||
-rw-r--r-- | tools/build/config.h.in | 55 | ||||
-rw-r--r-- | tools/build/configure.ac | 26 | ||||
-rwxr-xr-x | tools/build/cvsignore-add.sh | 25 | ||||
-rwxr-xr-x | tools/build/doxy-filter | 21 | ||||
-rw-r--r-- | tools/build/eolstrip.c | 366 | ||||
-rw-r--r-- | tools/build/install-if-change.in | 142 | ||||
-rwxr-xr-x | tools/build/multigen | 173 | ||||
-rw-r--r-- | tools/build/packhex.c | 565 | ||||
-rw-r--r-- | tools/build/rtems-bin2c.c | 291 | ||||
-rwxr-xr-x | tools/build/search-id.sh | 15 | ||||
-rw-r--r-- | tools/build/unhex.c | 737 |
17 files changed, 3212 insertions, 0 deletions
diff --git a/tools/build/.cvsignore b/tools/build/.cvsignore new file mode 100644 index 0000000000..d0e6e41377 --- /dev/null +++ b/tools/build/.cvsignore @@ -0,0 +1,18 @@ +aclocal.m4 +autom4te*.cache +config.cache +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-if-change +install-sh +Makefile +Makefile.in +missing +mkinstalldirs +stamp-h.in diff --git a/tools/build/ChangeLog b/tools/build/ChangeLog new file mode 100644 index 0000000000..e3e344cbcb --- /dev/null +++ b/tools/build/ChangeLog @@ -0,0 +1,209 @@ +2011-02-02 Ralf Corsépius <ralf.corsepius@rtems.org> + + * configure.ac: Require autoconf-2.68, automake-1.11.1. + +2010-07-30 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems-bin2c.c: Fix memory leak in '.c' suffix strip. + Also strip '.h' suffix. + +2010-07-30 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems-bin2c.c: Make -v (verbose) working. + +2010-07-30 Ralf Corsépius <ralf.corsepius@rtems.org> + + * configure.ac: Check for libgen.h, basename. + * rtems-bin2c.c: Use basename(3) instead of strrchr cascade. + Introduce ifbasename. Use ifbasename in generated files. + +2010-07-29 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems-bin2c.c: Add -C and -H options. + +2010-03-12 Joel Sherrill <joel.sherrill@oarcorp.com> + + * eolstrip.c: Readdress use of ctype methods per recommendation from + D.J. Delorie on the newlib mailing list. We should pass an unsigned + char into these methods. + +2007-09-18 Joel Sherrill <joel.sherrill@OARcorp.com> + + * Makefile.am: Rename bin2c to rtems-bin2c. + +2007-09-10 Joel Sherrill <joel.sherrill@OARcorp.com> + + * bin2c.c: Updated license after author changed it. + +2007-09-07 Joel Sherrill <joel.sherrill@OARcorp.com> + + * bin2c.c: Update comments. + +2007-09-04 Joel Sherrill <joel.sherrill@oarcorp.com> + + * bin2c.c: Significant improvements -- add multiple options, generate + both C and H files, do not always generate static. fix indentation, + add comments. + +2007-09-04 Joel Sherrill <joel.sherrill@oarcorp.com> + + * bin2c.c: New file. + http://www.wxwidgets.org/wiki/index.php/Embedding_PNG_Images-Bin2c_In_C + +2007-09-04 Joel Sherrill <joel.sherrill@oarcorp.com> + + * Makefile.am: Add bin2c so we can have a more reliable way to convert + binary files to objects. If they are in C, we can use the correct CPU + CFLAGS and they will link easier. + +2006-12-02 Ralf Corsépius <ralf.corsepius@rtems.org> + + * configure.ac: New BUG-REPORT address. + +2006-10-17 Ralf Corsépius <ralf.corsepius@rtems.org> + + * configure.ac: Require autoconf-2.60. Require automake-1.10. + +2006-07-13 Ralf Corsepius <ralf.corsepius@rtems.org> + + * doxy-filter: New. + * Makefile.am: Add doxy-filter. + +2006-07-11 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Remove. + * Makefile.am: Remove ampolish3. + * configure.ac: Remove ampolish3, perl. + +2006-01-14 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Check Makefile.am for SUBDIRS. + Add all-am: for PREINSTALL_FILES. + +2006-01-12 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Add all: for PREINSTALL_FILES. + Add all-local for TMPINSTALL_FILES. + Misc bug fixes. + +2006-01-12 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Check if Makefile.am already contains CLEANFILES or + DISTCLEANFILES. + +2006-01-10 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Update. + +2005-10-25 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Sync with private bleeding-edge . + +2005-10-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * ampolish3.in: Use @PERL@, partial update from local sources. + +2005-10-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * configure.ac: Add ampolish3. + * Makefile.am: Add ampolish3. + * ampolish3.in: New. + +2004-09-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * configure.ac: Require automake > 1.9. + +2004-02-20 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Add EXTRA_DIST = search-id.sh multigen + cvsignore-add.sh. + +2003-12-12 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Require automake >= 1.8, autoconf >= 2.59. + +2003-08-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Use rtems-bugs@rtems.com as bug report email address. + +2003-03-07 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Add AC_CHECK_HEADERS(getopt.h) to work around a bug + in autoconf-2.57. + +2003-03-06 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove AC_CONFIG_AUX_DIR. + +2003-03-02 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Add AC_CHECK_HEADERS. + +2003-02-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: AM_INIT_AUTOMAKE([1.7.2]). + +2003-02-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: AC_PREREQ(2.57). + +2002-10-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * .cvsignore: Reformat. + Add autom4te*cache. + Remove autom4te.cache. + +2002-10-02 Chris Johns <cjohns@cybertec.com.au> + + * cvsignore-add.sh: Script to append a specific file to all + .cvsignore files if the files exists is a specific directory. + +2002-05-01 Joel Sherrill <joel@OARcorp.com> + + * lock-directory.in, unlock-directory.in: Removed. + * Makefile.am, README, .cvsignore: Updated to reflect above. + +2002-04-01 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove AC_EXEEXT (obsolete). + +2002-03-27 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: + AC_INIT(package,_RTEMS_VERSION,_RTEMS_BUGS). + AM_INIT_AUTOMAKE([no-define foreign 1.6]). + * Makefile.am: Remove AUTOMAKE_OPTIONS. + +2001-10-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * .cvsignore: Add autom4te.cache for autoconf > 2.52. + * configure.in: Remove. + * configure.ac: New file, generated from configure.in by autoupdate. + +2001-01-24 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * config.h.in: Automatically generated. Remove from CVS. + +2000-11-09 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Use ... instead of RTEMS_TOPdir in ACLOCAL_AMFLAGS. + +2000-11-02 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Switch to ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal. + +2000-10-30 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Switch to GNU-canonicalized autoconf macros. + +2000-08-10 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * multigen: Fix BARE_CPU_CFLAGS. + +2000-08-06 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * multigen: Fix usage. + +2000-08-10 Joel Sherrill <joel@OARcorp.com> + + * ChangeLog: New file. diff --git a/tools/build/Makefile.am b/tools/build/Makefile.am new file mode 100644 index 0000000000..f58624929f --- /dev/null +++ b/tools/build/Makefile.am @@ -0,0 +1,26 @@ +## +## $Id$ +## + +ACLOCAL_AMFLAGS = -I ../../aclocal + +bin_PROGRAMS = cklength eolstrip packhex unhex rtems-bin2c + +noinst_PROGRAMS = binpatch + +cklength_SOURCES = cklength.c +eolstrip_SOURCES = eolstrip.c +packhex_SOURCES = packhex.c +unhex_SOURCES = unhex.c +binpatch_SOURCES = binpatch.c +rtems_bin2c_SOURCES = rtems-bin2c.c + +bin_SCRIPTS = install-if-change + +noinst_SCRIPTS = search-id.sh multigen cvsignore-add.sh +EXTRA_DIST = search-id.sh multigen cvsignore-add.sh + +noinst_SCRIPTS += doxy-filter +EXTRA_DIST += doxy-filter + +include $(top_srcdir)/../../automake/host.am diff --git a/tools/build/README b/tools/build/README new file mode 100644 index 0000000000..18899c3c06 --- /dev/null +++ b/tools/build/README @@ -0,0 +1,10 @@ +# +# $Id$ +# + +Misc. support tools for RTEMS workspaces. + +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. diff --git a/tools/build/binpatch.c b/tools/build/binpatch.c new file mode 100644 index 0000000000..b9e2ac1a06 --- /dev/null +++ b/tools/build/binpatch.c @@ -0,0 +1,156 @@ +/* + * $Id$ + */ + + +#include <stdio.h> +#include <stdlib.h> + +/* + * This function will patch binary file + */ + + +static char buf[512]; + +static void +usage(void) +{ + printf("usage: binpatch [-h] <ofile> <ifile> <reloc> <off> <byte0> " + "[<byte1> [<byte2> [<byte3>]]]\n"); + printf("this function patches binary file at specified offset with\n"); + printf("up to 4 bytes provided on command line \n"); + printf("-h - prints this message\n\n"); + printf("<ofile> - output file\n"); + printf("<ifile> - input ifile\n"); + printf("<reloc> - relocation address of image\n"); + printf("<off> - offset of patch, offset in file is at off - reloc\n"); + printf("<byte0> - byte 0 of patch\n"); + printf("<byte1> - byte 1 of patch\n"); + printf("<byte2> - byte 1 of patch\n"); + printf("<byte3> - byte 1 of patch\n"); + + return; +} + +int +main(int argc, char **argv) +{ + int c; + FILE *ofp, *ifp; + char patch[4], *end; + int patchLen, tmp, i, off, cnt, patched, len, reloc; + + + /* parse command line options */ + while ((c = getopt(argc, argv, "h")) >= 0) + { + switch (c) + { + case 'h': + usage(); + return 0; + default: + usage(); + return 1; + } + } + + if(argc < 6) + { + usage(); + return 1; + } + + /* Let us get offset in file */ + reloc = strtol(argv[3], &end, 0); + if(end == argv[3] || off < 0) + { + fprintf(stderr, "bad reloc value %s\n", argv[3]); + return 1; + } + + off = strtol(argv[4], &end, 0); + if(end == argv[4] || off < 0 || off < reloc) + { + fprintf(stderr, "bad offset value %s\n", argv[4]); + return 1; + } + + off -= reloc; + + /* Let us get patch */ + patchLen = argc - 5; + + for(i=0; i<patchLen; i++) + { + tmp = strtol(argv[5+i], &end, 0); + + if(end == argv[4+i] || tmp < 0 || tmp > 0xff) + { + fprintf(stderr, "bad byte value %s\n", argv[5+i]); + return 1; + } + patch[i] = tmp; + } + + ifp = fopen(argv[2], "r"); + if(ifp == NULL) + { + fprintf(stderr, "unable to open file %s\n", argv[2]); + return 1; + } + + ofp = fopen(argv[1], "w"); + if(ofp == NULL) + { + fprintf(stderr, "unable to open file %s\n", argv[1]); + return 1; + } + + cnt = 0; + patched = 0; + for(;;) + { + len = fread(buf, 1, sizeof(buf), ifp); + + if(len == 0) + { + break; + } + + if(cnt <= off && (cnt + len) > off) + { + /* Perform patch */ + for(i=0; i<patchLen && (off+i)<(cnt+len); i++) + { + buf[off-cnt+i] = patch[i]; + } + patched = 1; + } + else if(cnt > off && cnt < (off + patchLen)) + { + /* Perform patch */ + for(i=cnt-off; i<patchLen; i++) + { + buf[off-cnt+i] = patch[i]; + } + patched = 1; + } + + fwrite(buf, 1, len, ofp); + + cnt += len; + } + + fclose(ifp); + fclose(ofp); + + if(!patched) + { + fprintf(stderr, "warning: offset is beyond input file length\n"); + fprintf(stderr, " no patch is performed\n"); + } + + return 0; +} diff --git a/tools/build/cklength.c b/tools/build/cklength.c new file mode 100644 index 0000000000..624bf25e70 --- /dev/null +++ b/tools/build/cklength.c @@ -0,0 +1,377 @@ +/* + * 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$ + */ + +#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 <stdlib.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <errno.h> + +#include "config.h" + +#ifndef VMS +#ifndef HAVE_STRERROR +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror( _err ) \ + ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error" + +#else /* HAVE_STRERROR */ +char *strerror (); +#endif +#else /* VMS */ +char *strerror (int,...); +#endif + + +#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; + +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 +) +{ + 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; + 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) + (void) fprintf(stderr, " (%s)\n", strerror(local_errno)); + + (void) fflush(stderr); + + if (error_flag & (ERR_FATAL | ERR_ABORT)) + { + if (error_flag & ERR_FATAL) + { + error(0, "fatal error, exiting"); + exit(local_errno ? local_errno : 1); + } + 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/tools/build/config.h.in b/tools/build/config.h.in new file mode 100644 index 0000000000..89117dd249 --- /dev/null +++ b/tools/build/config.h.in @@ -0,0 +1,55 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the <getopt.h> header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/tools/build/configure.ac b/tools/build/configure.ac new file mode 100644 index 0000000000..d24f3e2d5a --- /dev/null +++ b/tools/build/configure.ac @@ -0,0 +1,26 @@ +# +# $Id$ +# + +AC_PREREQ([2.68]) +AC_INIT([rtems-tools-build],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla]) +AC_CONFIG_SRCDIR([install-if-change.in]) +RTEMS_TOP(../..) + +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE([no-define foreign 1.11.1]) +AM_MAINTAINER_MODE + +AC_PROG_CC +AC_CHECK_HEADERS([getopt.h libgen.h]) +AC_CHECK_FUNCS(strerror strtol basename) + +RTEMS_PATH_KSH + +AC_CONFIG_HEADERS([config.h]) + +# Explicitly list all Makefiles here +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([install-if-change],[chmod +x install-if-change]) +AC_OUTPUT diff --git a/tools/build/cvsignore-add.sh b/tools/build/cvsignore-add.sh new file mode 100755 index 0000000000..45feab6565 --- /dev/null +++ b/tools/build/cvsignore-add.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Find a file in the directory tree and create or add to a .cvsignore +# file that file name so it is ignored. +# +# Copyright 2001 Cybertec Pty Limited +# All rights reserved. +# +# $Id$ +# + +# +# We need one parameter, the file to add. +# + +if [ $# -eq 0 ]; then + echo "Usage: $0 file, where file is the one to be added." + exit 1 +fi + +for f in `find . -name $1`; +do + echo "`dirname $f`/.cvsignore" + echo "$1" >> `dirname $f`/.cvsignore +done diff --git a/tools/build/doxy-filter b/tools/build/doxy-filter new file mode 100755 index 0000000000..1d47b0806d --- /dev/null +++ b/tools/build/doxy-filter @@ -0,0 +1,21 @@ +#!/bin/sh + +# doxygen input filter +# $Id$ + +# usage: doxy-filter <input-file-name> +# Reads <input-file> and writes to stdout. + +file=$1 + +# Does file contain a doxygen @file directive? +if ! grep -q '@file' $file >/dev/null ; then +# No, add one +echo "/** @file $file */" +cat $file +else +# Yes, adjust path to work around doxygen not being able to +# distinguish file names properly +exec sed -e "s,@file.*$,@file $file," $file +fi + diff --git a/tools/build/eolstrip.c b/tools/build/eolstrip.c new file mode 100644 index 0000000000..398ff72116 --- /dev/null +++ b/tools/build/eolstrip.c @@ -0,0 +1,366 @@ +/* + * 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$ + */ + +#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 <stdlib.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <errno.h> + +#include "config.h" + +#ifndef VMS +#ifndef HAVE_STRERROR +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror( _err ) \ + ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error" + +#else /* HAVE_STRERROR */ +char *strerror (); +#endif +#else /* VMS */ +char *strerror (int,...); +#endif + + +#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; + +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 +) +{ + 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( (unsigned char) 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; + 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) + (void) fprintf(stderr, " (%s)\n", strerror(local_errno)); + else + (void) fprintf(stderr, "\n"); + + (void) fflush(stderr); + + if (error_flag & (ERR_FATAL | ERR_ABORT)) + { + if (error_flag & ERR_FATAL) + { + error(0, "fatal error, exiting"); + exit(local_errno ? local_errno : 1); + } + 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/tools/build/install-if-change.in b/tools/build/install-if-change.in new file mode 100644 index 0000000000..b2f3cb04bb --- /dev/null +++ b/tools/build/install-if-change.in @@ -0,0 +1,142 @@ +#!@KSH@ -p +# +# Either bash or ksh will be ok for this; requires (( )) arithmetic +# (-p above just says to not parse $ENV file; makes it faster for +# those of us who set $ENV) +# +# install files if they have changed by running 'cmp', then 'install' +# as necessary. +# +# Optionally, can append a suffix before last existing suffix (if any) +# +# NOTE +# We avoid using typical install(1M) programs since they have +# large variability across systems and we also need to support ou +# -V option. +# So we just copy and chmod by hand. +# +# $Id$ +# + +progname=`basename $0` +#progname=${0##*/} # fast basename hack for ksh, bash + +USAGE=\ +"usage: $progname [ -vmV ] file [ file ... ] dest-directory-or-file + -v -- verbose + -V suffix -- suffix to append to targets (before any . suffix) + eg: -V _g would change 'foo' to 'foo_g' and + 'libfoo.a' to 'libfoo_g.a' + -m mode -- mode for new file(s)" + +fatal() { + if [ "$1" ] + then + echo $* >&2 + fi + echo "$USAGE" 1>&2 + exit 1 +} + +# +# process the options +# + +verbose="" +suffix="" +mode="" + +while getopts vm:V: OPT +do + case "$OPT" in + v) + verbose="yes";; + V) + eval suffix=$OPTARG;; + m) + mode="$OPTARG";; + *) + fatal + esac +done + +shiftcount=`expr $OPTIND - 1` +shift $shiftcount + +args=$* + +# +# Separate source file(s) from dest directory or file +# + +files="" +dest="" +for d in $args +do + files="$files $dest" + dest=$d +done + +if [ ! "$files" ] || [ ! "$dest" ] +then + fatal "missing files or invalid destination" +fi + +# +# Process the arguments +# + +targets="" +for f in $files +do + # leaf=`basename $f` + leaf=${f##*/} # fast basename hack for ksh, bash + + target=$dest + if [ -d $dest ] + then + # if we were given a suffix, then add it as appropriate + if [ "$suffix" ] + then + case $f in + *.*) + # leaf=`echo $leaf | + # /bin/sed "s/\([~\.]*\)\.\(.*\)$/\1$suffix.\2/"` + # ksh,bash hack for above sed script + leaf=${leaf%%.*}$suffix.${leaf#*.} + + [ "$verbose" = "yes" ] && + echo "$progname: $f will be installed as $leaf" + ;; + *) + leaf=$leaf$suffix;; + esac + fi + target=$target/$leaf + fi + + [ ! -r $f ] && fatal "can not read $f" + + if cmp -s $f $target + then + [ "$verbose" = "yes" ] && echo "'$f' not newer than '$target'" + else + [ "$verbose" = "yes" ] && echo "rm -f $target" + rm -f $target + echo "cp -p $f $target" + cp -p $f $target || exit 1 + targets="$targets $target" # keep list for chmod below + fi +done + +if [ "$mode" -a "$targets" ] +then + [ "$verbose" = "yes" ] && echo "chmod $mode $targets" + chmod $mode $targets +fi + +exit 0 + +# Local Variables: *** +# mode:ksh *** +# End: *** diff --git a/tools/build/multigen b/tools/build/multigen new file mode 100755 index 0000000000..06bfe65449 --- /dev/null +++ b/tools/build/multigen @@ -0,0 +1,173 @@ +#!/bin/sh + +# $Id$ + +version=0.1 +verbose=0 +target= +custom=0 +config=0 + +usage() +{ +program=`basename $0` +cat << EOF + +$program generates RTEMS custom/*.cfgs and config-files for gcc multilib +variants a target's gcc supports + +Usage: $program [options] + +Options: + --target=STRING target + --custom generate make/custom/*.cfg files + --config generate config scripts + --rtems=DIR use DIR as location of RTEMS source tree + -v, --verbose verbose + -h, --help Print this usage + --version Print version and exit + +Examples: +$program --config --target=sh-rtems --rtems=/usr/src/rtems-4.5.0 + Generates config scripts for all possible bare BSPs from all + valid multilib variants sh-rtems-gcc supports + +$program --custom --target=sh-rtems --rtems=/usr/src/rtems-4.5.0 + Generates /usr/src/rtems-4.5.0/make/custom/*.cfg files + for all possible bare BSPs from the multilib variants + sh-rtems-gcc supports + +Written by Ralf Corsepius <corsepiu@faw.uni-ulm.de> +EOF +} + +while test $# -gt 0; do + case "$1" in + --rtems=*) + rtems_srcdir=`echo "$1" | sed -e 's%--rtems=\(.*\)%\1%g'` + ;; + --target=*) + target=`echo "$1" | sed -e 's%--target=\(.*\)%\1%g'` + ;; + -v|--verbose) + verbose=1 + ;; + --custom) + custom=1 + ;; + --config) + config=1 + ;; + --version) + echo `basename $0` version $version + exit 0 + ;; + -h|--help) + usage + exit 1 + ;; + *) + echo "unknown option $1" + usage + exit 1 + ;; + esac + shift +done + +if test $# -gt 0; then + echo "Invalid number of arguments" + exit 1 +fi + +if test x$target = x; then + echo "Missing required option:" + echo " --target" + exit 1 +fi + +if test x$rtems_srcdir = x; then + echo "Missing required option:" + echo " --rtems" + exit 1 +fi + +if test $config -eq 0 && test $custom -eq 0; then + echo "Missing required option:" + echo " --config" + echo " --custom" + echo " (At least one of these is required)" + exit 1 +fi + +if test ! -r $rtems_srcdir/VERSION; then + echo "Can't find rtems" + echo "Check value passed to --rtems=<DIR>" + exit 1 +fi + +if test x$target != x ;then +target_prefix=$target- +fi + +# Check for CC +saved_IFS=$IFS; IFS=":" +for i in $PATH; do + if test -f $i/${target_prefix}gcc; then + CC=$i/${target_prefix}gcc + break + fi +done +IFS=$saved_IFS + +if test x$CC = x; then + echo "No valid gcc found" + exit 1 +fi +test $verbose -gt 0 && echo "Using $CC" + +for i in `${CC} --print-multi-lib 2>/dev/null`; do + dir=`echo $i | sed -e 's/;.*$//'` + case $dir in + .) f=$target + flags="" + ;; + *) f=`echo $target-$dir | sed -e 's%\/%-%g'` + flags=`echo $i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'` + ;; + esac + + if test $config -gt 0; then + cfg="rtems-config.$f" + test $verbose -gt 0 && echo "Generating: $cfg" + +cat << EOF > $cfg +#!/bin/sh + +${rtems_srcdir}/configure --target=$target \\ +'--enable-bare-cpu-cflags=$flags' \\ +--enable-rtemsbsp="bare" \\ +--enable-bare-cpu-model=NONE \\ +--disable-networking \\ +--disable-tests \\ +--enable-maintainer-mode +EOF + chmod +x $cfg + fi + + if test $custom -gt 0; then + cfg=${rtems_srcdir}/make/custom/bare-$f.cfg + test $verbose -gt 0 && echo "Generating: $cfg" +cat << EOF > $cfg +# Config file for the bare-$f BSP + +BARE_CPU_CFLAGS=$flags +BARE_CPU_MODEL=NONE + +include \$(RTEMS_ROOT)/make/custom/bare.cfg +EOF + + fi +done + +exit 0 diff --git a/tools/build/packhex.c b/tools/build/packhex.c new file mode 100644 index 0000000000..1e8edb615e --- /dev/null +++ b/tools/build/packhex.c @@ -0,0 +1,565 @@ + +/***** 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: May 1993 Embedded Systems Programming magazine + * "Creating Faster Hex Files" + * + * URL: ESP magazine: http://www.embedded.com + * Source Code: ftp://ftp.mfi.com/pub/espmag/1993/pakhex.zip + * + * Author: Mark Gringrich + * + * 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> + +#include "config.h" + +#ifndef VMS +#ifndef HAVE_STRERROR +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror( _err ) \ + ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error" + +#else /* HAVE_STRERROR */ +char *strerror (); +#endif +#else /* VMS */ +char *strerror (int,...); +#endif + +#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 *, int ); +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. +* +*******************************************************************************/ + +int main( + int argc, + char **argv +) +{ + + char inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ]; + char *in_dptr, *out_dptr; + int d_total, d_count, d_excess, n; + int length; + Ulong in_rec_addr, out_rec_addr = 0; + Rec_vitals *rptr; + + + /* Sift through file until first hex record is identified. */ + + rptr = identify_first_data_record( inbuff, MAX_LINE_SIZE ); + if ( rptr == NULL ) + { + fputs( "No hex records found.\n", stderr ); + exit( EXIT_FAILURE ); + } + + + /* Attempt data-record splicing until end-of-file is reached. */ + d_total = 0; + for (;;) { + 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 ); + } + + inbuff[ MAX_LINE_SIZE - 1 ] = '\0'; + if ( !fgets( inbuff, MAX_LINE_SIZE, stdin ) ) + break; + if ( inbuff[ MAX_LINE_SIZE - 1 ] ) { + fprintf( stderr, "Input line too long" ); + exit( 1 ); + } + length = strlen(inbuff); + inbuff[length - 1] = '\0'; + + } + + + return ( 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, int max_length ) +{ + Rec_vitals ** ptr; + int length; + + + + for ( ;; ) { + + buff_ptr[ max_length - 1 ] = '\0'; + if ( !fgets( buff_ptr, max_length, stdin ) ) + break; + if ( buff_ptr[ max_length - 1 ] ) { + fprintf( stderr, "Input line too long" ); + exit( 1 ); + } + length = strlen(buff_ptr); + buff_ptr[length - 1] = '\0'; + + 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/tools/build/rtems-bin2c.c b/tools/build/rtems-bin2c.c new file mode 100644 index 0000000000..4e6796aa38 --- /dev/null +++ b/tools/build/rtems-bin2c.c @@ -0,0 +1,291 @@ +/* + * bin2c.c + * + * convert a binary file into a C source array. + * + * THE "BEER-WARE LICENSE" (Revision 3.1415): + * sandro AT sigala DOT it wrote this file. As long as you retain this + * notice you can do whatever you want with this stuff. If we meet some + * day, and you think this stuff is worth it, you can buy me a beer in + * return. Sandro Sigala + * + * Subsequently modified by Joel Sherrill <joel.sherrill@oarcorp.com> + * to add a number of capabilities not in the original. + * + * syntax: bin2c [-c] [-z] <input_file> <output_file> + * + * -c do NOT add the "const" keyword to definition + * -s add the "static" keywork to definition + * -v verbose + * -z terminate the array with a zero (useful for embedded C strings) + * + * examples: + * bin2c -c myimage.png myimage_png.cpp + * bin2c -z sometext.txt sometext_txt.cpp + * + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +int useconst = 1; +int usestatic = 0; +int verbose = 0; +int zeroterminated = 0; +int createC = 1; +int createH = 1; + +int myfgetc(FILE *f) +{ + int c = fgetc(f); + if (c == EOF && zeroterminated) { + zeroterminated = 0; + return 0; + } + return c; +} + +void process(const char *ifname, const char *ofname) +{ + FILE *ifile, *ocfile, *ohfile; + char buf[PATH_MAX], *p; + char obasename[PATH_MAX]; + char ocname[PATH_MAX]; + char ohname[PATH_MAX]; + const char *cp; + size_t len; + + /* Error check */ + if ( !ifname || !ofname ) { + fprintf(stderr, "process has NULL filename\n"); + exit(1); + } + + strncpy( obasename, ofname, PATH_MAX ); + len = strlen( obasename ); + if ( len >= 2 ) { + if ( obasename[len-2] == '.' ) { + if ( (obasename[len-1] == 'c') || (obasename[len-1] == 'h') ) + obasename[len-2] = '\0'; + } + } + + sprintf( ocname, "%s.c", obasename ); + sprintf( ohname, "%s.h", obasename ); + + if ( verbose ) { + fprintf( + stderr, + "in file: %s\n" + "c file: %s\n" + "h file: %s\n", + ifname, + ocname, + ohname + ); + } + + /* Open input and output files */ + ifile = fopen(ifname, "rb"); + if (ifile == NULL) { + fprintf(stderr, "cannot open %s for reading\n", ifname); + exit(1); + } + + if ( createC ) { + ocfile = fopen(ocname, "wb"); + if (ocfile == NULL) { + fprintf(stderr, "cannot open %s for writing\n", ocname); + exit(1); + } + } + + if ( createH ) { + ohfile = fopen(ohname, "wb"); + if (ohfile == NULL) { + fprintf(stderr, "cannot open %s for writing\n", ohname); + exit(1); + } + } + + /* find basename */ + char *ifbasename = strdup(ifname); + ifbasename = basename(ifbasename); + + strcpy(buf, ifbasename); + for (p = buf; *p != '\0'; ++p) + if (!isalnum(*p)) + *p = '_'; + + if ( createC ) { + /* print C file header */ + fprintf( + ocfile, + "/*\n" + " * Declarations for C structure representing binary file %s\n" + " *\n" + " * WARNING: Automatically generated -- do not edit!\n" + " */\n" + "\n" + "#include <sys/types.h>\n" + "\n", + ifbasename + ); + + /* print structure */ + fprintf( + ocfile, + "%s%sunsigned char %s[] = {\n ", + ((usestatic) ? "static " : ""), + ((useconst) ? "const " : ""), + buf + ); + int c, col = 1; + while ((c = myfgetc(ifile)) != EOF) { + if (col >= 78 - 6) { + fprintf(ocfile, "\n "); + col = 1; + } + fprintf(ocfile, "0x%.2x, ", c); + col += 6; + + } + fprintf(ocfile, "\n};\n"); + + /* print sizeof */ + fprintf( + ocfile, + "\n" + "%s%ssize_t %s_size = sizeof(%s);\n", + ((usestatic) ? "static " : ""), + ((useconst) ? "const " : ""), + buf, + buf + ); + } /* createC */ + + /*****************************************************************/ + /****** END OF C FILE *****/ + /*****************************************************************/ + + if ( createH ) { + /* print H file header */ + fprintf( + ohfile, + "/*\n" + " * Extern declarations for C structure representing binary file %s\n" + " *\n" + " * WARNING: Automatically generated -- do not edit!\n" + " */\n" + "\n" + "#ifndef __%s_h\n" + "#define __%s_h\n" + "\n" + "#include <sys/types.h>\n" + "\n", + ifbasename, /* header */ + obasename, /* ifndef */ + obasename /* define */ + ); + + /* print structure */ + fprintf( + ohfile, + "extern %s%sunsigned char %s[];", + ((usestatic) ? "static " : ""), + ((useconst) ? "const " : ""), + buf + ); + /* print sizeof */ + fprintf( + ohfile, + "\n" + "extern %s%ssize_t %s_size;\n", + ((usestatic) ? "static " : ""), + ((useconst) ? "const " : ""), + buf + ); + + fprintf( + ohfile, + "\n" + "#endif\n" + ); + } /* createH */ + + /*****************************************************************/ + /****** END OF H FILE *****/ + /*****************************************************************/ + + fclose(ifile); + if ( createC ) { fclose(ocfile); } + if ( createH ) { fclose(ohfile); } +} + +void usage(void) +{ + fprintf( + stderr, + "usage: bin2c [-csvzCH] <input_file> <output_file>\n" + " <input_file> is the binary file to convert\n" + " <output_file> should not have a .c or .h extension\n" + "\n" + " -c - do NOT use const in declaration\n" + " -s - do use static in declaration\n" + " -v - verbose\n" + " -z - add zero terminator\n" + " -H - create c-header only\n" + " -C - create c-source file only\n" + ); + exit(1); +} + +int main(int argc, char **argv) +{ + while (argc > 3) { + if (!strcmp(argv[1], "-c")) { + useconst = 0; + --argc; + ++argv; + } else if (!strcmp(argv[1], "-s")) { + usestatic = 1; + --argc; + ++argv; + } else if (!strcmp(argv[1], "-v")) { + verbose = 1; + --argc; + ++argv; + } else if (!strcmp(argv[1], "-z")) { + zeroterminated = 1; + --argc; + ++argv; + } else if (!strcmp(argv[1], "-C")) { + createH = 0; + createC = 1; + --argc; + ++argv; + } else if (!strcmp(argv[1], "-H")) { + createC = 0; + createH = 1; + --argc; + ++argv; + } else { + usage(); + } + } + if (argc != 3) { + usage(); + } + + /* process( input_file, output_basename ) */ + process(argv[1], argv[2]); + return 0; +} + diff --git a/tools/build/search-id.sh b/tools/build/search-id.sh new file mode 100755 index 0000000000..a94d2d7cc9 --- /dev/null +++ b/tools/build/search-id.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $Id$ +# + +find $1 -type f -a ! -name "*.scn" -a ! -name "bsp_specs" -a \ + -print > /tmp/$$.0 +find $1 -type f -a ! -name "*.scn" -a ! -name "bsp_specs" -a \ + -exec grep -l '$Id' {} \; > /tmp/$$.1 + +diff /tmp/$$.0 /tmp/$$.1 > /tmp/$$.2 + +grep "<" /tmp/$$.2 | sed 's/< //' >&1 + +rm -f /tmp/$$* diff --git a/tools/build/unhex.c b/tools/build/unhex.c new file mode 100644 index 0000000000..693049f465 --- /dev/null +++ b/tools/build/unhex.c @@ -0,0 +1,737 @@ +/* + * 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 + * + * $Id$ + */ + +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> +#include <errno.h> + +#include "config.h" + +#ifndef VMS +#ifndef HAVE_STRERROR +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror( _err ) \ + ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error" + +#else /* HAVE_STRERROR */ +char *strerror (); +#endif +#else /* VMS */ +char *strerror (int,...); +#endif + + +#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; + +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 */ + +#ifdef HAVE_STRTOUL +#define stol(p) strtoul(p, (char **) NULL, 0) +#else +#define stol(p) strtol(p, (char **) NULL, 0) +#endif + +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( + 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; + 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) + (void) fprintf(stderr, " (%s)\n", strerror(local_errno)); + else + (void) fprintf(stderr, "\n"); + + (void) fflush(stderr); + + if (error_flag & (ERR_FATAL | ERR_ABORT)) + { + if (error_flag & ERR_FATAL) + { + error(0, "fatal error, exiting"); + exit(local_errno ? local_errno : 1); + } + else + { + error(0, "fatal error, aborting"); + abort(); + } + } +} |