diff options
| author | B. Watson <urchlay@slackware.uk> | 2024-04-25 00:11:30 -0400 | 
|---|---|---|
| committer | B. Watson <urchlay@slackware.uk> | 2024-04-25 00:11:30 -0400 | 
| commit | 190dfb3149ebb353b0bde2b108b9282bfcd58dcc (patch) | |
| tree | d9a331f6de2764cd35976002a4dd497197b07872 | |
| parent | 3286d83fb8ddbcbbcde3adca2b41dbb3339daa02 (diff) | |
| download | bw-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.1 | 26 | ||||
| -rw-r--r-- | blob2xex.c | 94 | ||||
| -rw-r--r-- | blob2xex.rst | 24 | 
3 files changed, 97 insertions, 47 deletions
| @@ -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 @@ -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* | 
