aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-04-25 00:11:30 -0400
committerB. Watson <urchlay@slackware.uk>2024-04-25 00:11:30 -0400
commit190dfb3149ebb353b0bde2b108b9282bfcd58dcc (patch)
treed9a331f6de2764cd35976002a4dd497197b07872
parent3286d83fb8ddbcbbcde3adca2b41dbb3339daa02 (diff)
downloadbw-atari8-tools-190dfb3149ebb353b0bde2b108b9282bfcd58dcc.tar.gz
blob2xex: made reading stdin work, limit segment size to end at $FFFF, warn if start/end addrs are in ROM, unlink output file on error.
-rw-r--r--blob2xex.126
-rw-r--r--blob2xex.c94
-rw-r--r--blob2xex.rst24
3 files changed, 97 insertions, 47 deletions
diff --git a/blob2xex.1 b/blob2xex.1
index cf118b1..51344f8 100644
--- a/blob2xex.1
+++ b/blob2xex.1
@@ -40,26 +40,30 @@ blob2xex \fIoutfile\fP [\fB\-v\fP] [\fB\-r\fP \fIrunaddr\fP] [\fB\-l\fP \fIloada
.SH DESCRIPTION
.sp
\fBblob2xex\fP creates an Atari 8\-bit binary load (xex) file from one or
-more files of arbitrary data.
+more files of arbitrary data. Each input file will become a separate
+segment in the binary load file. A run address can be added with the
+\fB\-r\fP option.
.sp
-Each input file \fIrequires\fP a \fB\-l\fP \fIloadaddr\fP option, to set the load
-address. Optionally, run and init addresses can be included. Also,
-using \fB\-o\fP and \fB\-s\fP, it\(aqs possible to include only part of the
-input file. To read from standard input, use \fB\-\fP for the \fIinfile\fP\&.
+Each input file \fIrequires\fP a \fB\-l\fP \fIloadaddr\fP option, to set the
+load address. Optionally, init addresses can be included, per\-segment
+(\fB\-i\fP). Also, using \fB\-o\fP and \fB\-s\fP, it\(aqs possible to include only
+part of the input file. To read from standard input, use \fB\-\fP for the
+\fIinfile\fP\&.
.sp
\fIoutfile\fP must be given as the first argument. When multiple
input files are used, the resulting .xex file will have multiple
-segments. If \fIoutfile\fP already exists, it will be overwritten. Use
-\fB\-\fP to write to standard output. If \fIoutfile\fP is a filename that
-begins with a \fB\-\fP, prefix it with "./", otherwise it\(aqll be taken as
-an option.
+segments. If \fIoutfile\fP already exists, it will be overwritten.
+If \fIoutfile\fP is a filename that begins with a \fB\-\fP, prefix it with
+"./", otherwise it\(aqll be taken as an option. Use \fB\-\fP to write to
+standard output. \fBblob2xex\fP will not write output to a terminal;
+\fB\-\fP must be used with redirection or a pipe.
.sp
Addresses, offsets, and sizes may be given in decimal or hex. Hex
addresses must be prefixed with either \fB$\fP or \fB0x\fP\&.
.SH OPTIONS
.sp
-A space is required between an option and its argument; use e.g. \fB\-l 0x2000*,
-not **\-l0x2000\fP\&.
+A space is required between an option and its argument; use e.g. \fB\-l 0x2000\fP,
+not \fB\-l0x2000\fP\&.
.INDENT 0.0
.TP
.B \-l \fIloadaddr\fP
diff --git a/blob2xex.c b/blob2xex.c
index 9740e45..2ff7249 100644
--- a/blob2xex.c
+++ b/blob2xex.c
@@ -32,7 +32,7 @@ int get_offset(const char *arg) {
return (int)got;
}
-void write_segment(
+int write_segment(
const char *infile,
const char *outfile,
int loadaddr,
@@ -47,16 +47,16 @@ void write_segment(
if(size < 1) {
fprintf(stderr, SELF ": invalid size %d (must be >= 1).\n", size);
- exit(1);
+ return(0);
}
if(strcmp(infile, "-") == 0) {
- infh = stdout;
+ infh = stdin;
} else {
infh = fopen(infile, "rb");
if(!infh) {
- perror(outfile);
- exit(1);
+ fprintf(stderr, SELF ": %s: %s\n", infile, strerror(errno));
+ return(0);
}
}
@@ -69,12 +69,18 @@ void write_segment(
} else {
outfh = fopen(outfile, "wb");
if(!outfh) {
- perror(outfile);
- exit(-1);
+ fprintf(stderr, SELF ": %s: %s\n", outfile, strerror(errno));
+ return(0);
}
}
}
+ if(isatty(fileno(outfh))) {
+ fprintf(stderr,
+ SELF ": Standard output is a terminal; not writing binary data\n");
+ return 0;
+ }
+
seg.object = buffer;
seg.len = 0;
seg.start_addr = loadaddr;
@@ -85,11 +91,15 @@ void write_segment(
c = getc(infh);
if(c < 0) {
fprintf(stderr, SELF ": offset extends past EOF on file %s\n", infile);
- exit(1); /* TODO: handle this better? */
+ return(0);
}
offset--;
}
+ /* make sure we don't wrap the Atari's address space. */
+ if(size + loadaddr > 0xffff)
+ size = (size - loadaddr) + 1;
+
/* read <size> bytes, or until EOF (which is not an error) */
while(size) {
c = getc(infh);
@@ -98,8 +108,22 @@ void write_segment(
seg.len++;
size--;
}
+
+ if(seg.len == 0) {
+ fprintf(stderr, SELF ": read 0 bytes from %s, xex files cannot contain empty segments.\n", infile);
+ return(0);
+ }
+
seg.end_addr = seg.start_addr + seg.len - 1;
+ /* if we start/end in ROM, warn, but it's not an error. */
+ if(seg.start_addr >= 0xc000)
+ fprintf(stderr, SELF ": warning: %s: start address $%04x loads into ROM.\n", infile, seg.start_addr);
+
+ if(seg.end_addr >= 0xc000)
+ fprintf(stderr, SELF ": warning: %s: end address $%04x loads into ROM.\n",
+ infile, seg.end_addr);
+
xex_fwrite_seg(&seg, outfh);
if(initaddr >= 0) {
@@ -108,11 +132,13 @@ void write_segment(
}
fclose(infh);
+ return(1);
}
void usage() {
- printf(SELF ": Usage:\n\t"
- SELF " outfile [-r runaddr] [-l loadaddr [-i initaddr] "
+ printf(SELF ": Usage:\n "
+ SELF " outfile [-v] [-r runaddr]\n"
+ " [-l loadaddr ] [-i initaddr] "
"[-o offset] [-s size] infile] ..."
"\nSee man page for details.\n");
}
@@ -120,6 +146,7 @@ void usage() {
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;
+ int segcount = 0, incount = 0;
outfile = argv[1];
if(!outfile || strcmp(outfile, "--help") == 0 || strcmp(outfile, "-h") == 0) {
@@ -137,12 +164,6 @@ int main(int argc, char **argv) {
exit(1);
}
- if(argc < 5) {
- fprintf(stderr, SELF ": not enough arguments.\n");
- usage();
- exit(1);
- }
-
for(i = 2; i < argc; i++) {
char *arg = argv[i];
@@ -157,7 +178,7 @@ int main(int argc, char **argv) {
exit(1);
}
param = 0;
- } else if(arg[0] == '-') {
+ } else if(arg[0] == '-' && arg[1] != '\0') {
infile = 0;
switch(arg[1]) {
case 'l': param = &loadaddr; break;
@@ -173,21 +194,33 @@ int main(int argc, char **argv) {
break;
}
} else {
- if(infile) {
- fprintf(stderr, SELF ": input filename without -l option: %s\n", arg);
- usage();
- exit(1);
+ if(loadaddr == -1) {
+ fprintf(stderr, SELF ": input filename without load address (-l): %s\n", arg);
+ segcount = 0;
+ break;
}
infile = arg;
- write_segment(infile, outfile, loadaddr, initaddr, offset, size);
+ incount++;
+ if(write_segment(infile, outfile, loadaddr, initaddr, offset, size)) {
+ segcount++;
+ } else {
+ segcount = 0;
+ break;
+ }
+ infile = 0;
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(incount) {
+ if(segcount && ((param || (loadaddr >= 0) || (initaddr >= 0)) ||
+ (offset != 0) || (size != DEFAULT_SIZE)))
+ {
+ fprintf(stderr, SELF ": "
+ "warning: extra arguments after last input file ignored.\n");
+ }
+ } else {
+ fprintf(stderr, SELF ": no input files!\n");
}
if(outfh) {
@@ -201,5 +234,14 @@ int main(int argc, char **argv) {
fclose(outfh);
}
+ if(segcount) {
+ if(xex_verbose)
+ fprintf(stderr, SELF ": read %d input files, wrote %d segments to %s.\n",
+ incount, segcount, outfile);
+ } else {
+ unlink(outfile);
+ return 1;
+ }
+
return 0;
}
diff --git a/blob2xex.rst b/blob2xex.rst
index 18ebd6e..4166f64 100644
--- a/blob2xex.rst
+++ b/blob2xex.rst
@@ -20,19 +20,23 @@ DESCRIPTION
===========
**blob2xex** creates an Atari 8-bit binary load (xex) file from one or
-more files of arbitrary data.
+more files of arbitrary data. Each input file will become a separate
+segment in the binary load file. A run address can be added with the
+**-r** option.
-Each input file *requires* a **-l** *loadaddr* option, to set the load
-address. Optionally, run and init addresses can be included. Also,
-using **-o** and **-s**, it's possible to include only part of the
-input file. To read from standard input, use **-** for the *infile*.
+Each input file *requires* a **-l** *loadaddr* option, to set the
+load address. Optionally, init addresses can be included, per-segment
+(**-i**). Also, using **-o** and **-s**, it's possible to include only
+part of the input file. To read from standard input, use **-** for the
+*infile*.
*outfile* must be given as the first argument. When multiple
input files are used, the resulting .xex file will have multiple
-segments. If *outfile* already exists, it will be overwritten. Use
-**-** to write to standard output. If *outfile* is a filename that
-begins with a **-**, prefix it with "./", otherwise it'll be taken as
-an option.
+segments. If *outfile* already exists, it will be overwritten.
+If *outfile* is a filename that begins with a **-**, prefix it with
+"./", otherwise it'll be taken as an option. Use **-** to write to
+standard output. **blob2xex** will not write output to a terminal;
+**-** must be used with redirection or a pipe.
Addresses, offsets, and sizes may be given in decimal or hex. Hex
addresses must be prefixed with either **$** or **0x**.
@@ -40,7 +44,7 @@ addresses must be prefixed with either **$** or **0x**.
OPTIONS
=======
-A space is required between an option and its argument; use e.g. **-l 0x2000*,
+A space is required between an option and its argument; use e.g. **-l 0x2000**,
not **-l0x2000**.
-l *loadaddr*