aboutsummaryrefslogtreecommitdiff
path: root/blob2xex.c
diff options
context:
space:
mode:
Diffstat (limited to 'blob2xex.c')
-rw-r--r--blob2xex.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/blob2xex.c b/blob2xex.c
index e3740f6..fb339e7 100644
--- a/blob2xex.c
+++ b/blob2xex.c
@@ -4,6 +4,7 @@
#include <errno.h>
#include <string.h>
+#include "get_address.h"
#include "xex.h"
#ifndef VERSION
@@ -12,5 +13,180 @@
#define SELF "blob2xex"
+#define DEFAULT_SIZE 0xffff
+
+static FILE *outfh = 0;
+
+/* get_offset() is patterned on get_address(), but isn't limited
+ to 64K. TODO: it won't handle offsets >2GB. */
+int get_offset(const char *arg) {
+ unsigned int got;
+
+ if(sscanf(arg, "0x%x", &got) != 1)
+ if(sscanf(arg, "$%x", &got) != 1)
+ if(sscanf(arg, "%d", &got) != 1) {
+ fprintf(stderr, "Invalid offset '%s'\n", arg);
+ return -1;
+ }
+
+ return (int)got;
+}
+
+void write_segment(
+ const char *infile,
+ const char *outfile,
+ int loadaddr,
+ int initaddr,
+ int offset,
+ int size)
+{
+ FILE *infh;
+ unsigned char buffer[65536], *p = buffer;
+ xex_segment seg;
+ int c;
+
+ if(size < 1) {
+ fprintf(stderr, SELF ": invalid size %d (must be >= 1).\n", size);
+ exit(1);
+ }
+
+ if(strcmp(infile, "-") == 0) {
+ infh = stdout;
+ } else {
+ infh = fopen(infile, "rb");
+ if(!infh) {
+ perror(outfile);
+ exit(1);
+ }
+ }
+
+ if(outfh) {
+ seg.has_ff_header = 0;
+ } else {
+ seg.has_ff_header = 1;
+ if(strcmp(outfile, "-") == 0) {
+ outfh = stdout;
+ } else {
+ outfh = fopen(outfile, "wb");
+ if(!outfh) {
+ perror(outfile);
+ exit(-1);
+ }
+ }
+ }
+
+ seg.object = buffer;
+ seg.len = 0;
+ seg.start_addr = loadaddr;
+
+ /* skip <offset> bytes in input. don't seek, input might be stdin */
+ while(offset) {
+ /* TODO: not very efficient to read 1 byte at a time? */
+ c = getc(infh);
+ if(c < 0) {
+ fprintf(stderr, SELF ": offset extends past EOF on file %s\n", infile);
+ exit(1); /* TODO: handle this better? */
+ }
+ offset--;
+ }
+
+ /* read <size> bytes, or until EOF (which is not an error) */
+ while(size) {
+ c = getc(infh);
+ if(c < 0) break;
+ *p++ = c;
+ seg.len++;
+ size--;
+ }
+ seg.end_addr = seg.start_addr + seg.len - 1;
+
+ xex_fwrite_seg(&seg, outfh);
+
+ if(initaddr >= 0) {
+ xex_init_seg(&seg, buffer, initaddr);
+ xex_fwrite_seg(&seg, outfh);
+ }
+
+ fclose(infh);
+}
+
+void usage() {
+ printf(SELF ": Usage:\n\t"
+ SELF " outfile [-r runaddr] [-l loadaddr [-i initaddr] "
+ "[-o offset] [-s size] infile] ..."
+ "\nSee man page for details.\n");
+}
+
int main(int argc, char **argv) {
+ char *outfile = 0, *infile = 0;
+ int i, loadaddr = -1, runaddr = -1, initaddr = -1, offset = 0, size = DEFAULT_SIZE, *param = 0;
+
+ xex_verbose = 1;
+
+ if(argc < 5) {
+ fprintf(stderr, SELF ": not enough arguments.\n");
+ usage();
+ exit(1);
+ }
+
+ outfile = argv[1];
+
+ for(i = 2; i < argc; i++) {
+ char *arg = argv[i];
+
+ if(!arg[0]) continue; /* skip empty args */
+
+ if(param) { /* previous option needs an argument */
+ if(param == &offset) {
+ if( (offset = get_offset(arg) ) < 0 )
+ exit(1);
+ } else {
+ if( (*param = get_address(SELF, arg) ) < 0 )
+ exit(1);
+ }
+ param = 0;
+ } else if(arg[0] == '-') {
+ infile = 0;
+ switch(arg[1]) {
+ case 'l': param = &loadaddr; break;
+ case 'r': param = &runaddr; break;
+ case 'i': param = &initaddr; break;
+ case 'o': param = &offset; break;
+ case 's': param = &size; break;
+ default:
+ fprintf(stderr, SELF ": unknown option '-%c'\n", arg[1]);
+ usage();
+ exit(1);
+ break;
+ }
+ } else {
+ if(infile) {
+ fprintf(stderr, SELF ": input filename without -l option: %s\n", arg);
+ usage();
+ exit(1);
+ }
+ infile = arg;
+ write_segment(infile, outfile, loadaddr, initaddr, offset, size);
+ loadaddr = -1; initaddr = -1; offset = 0; size = DEFAULT_SIZE;
+ }
+ }
+
+ if(param || (loadaddr >= 0) || (initaddr >= 0) ||
+ (offset != 0) || (size != DEFAULT_SIZE)) {
+ fprintf(stderr, SELF ": "
+ "warning: extra arguments after last input file ignored.\n");
+ }
+
+ if(outfh) {
+ if(runaddr >= 0) {
+ xex_segment seg;
+ unsigned char buf[10];
+
+ xex_run_seg(&seg, buf, runaddr);
+ xex_fwrite_seg(&seg, outfh);
+ }
+ fclose(outfh);
+ }
+
+ return 0;
}