diff options
author | B. Watson <urchlay@slackware.uk> | 2024-04-24 15:04:50 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2024-04-24 15:04:50 -0400 |
commit | 1deab5d25136624f7e9a6d6446f5d218a243f56b (patch) | |
tree | ab232233646e7d7778c43349b0186f09b660d25e /blob2xex.c | |
parent | 53a0578bd0605cfa39e7d8d126aa78fb216527d3 (diff) | |
download | bw-atari8-tools-1deab5d25136624f7e9a6d6446f5d218a243f56b.tar.gz |
blob2xex: initial implementation, needs testing.
Diffstat (limited to 'blob2xex.c')
-rw-r--r-- | blob2xex.c | 176 |
1 files changed, 176 insertions, 0 deletions
@@ -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; } |