From 1165045c943202c6bb96ff9b372e95ac1aeeaac2 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Fri, 26 Apr 2024 04:04:37 -0400 Subject: xexsplit: add -r (raw output) option. --- xexamine.1 | 6 ++++- xexamine.rst | 6 ++++- xexsplit.1 | 85 +++++++++++++++++++++++++++++++++--------------------------- xexsplit.c | 22 +++++++++++----- xexsplit.rst | 83 ++++++++++++++++++++++++++++++++-------------------------- 5 files changed, 119 insertions(+), 83 deletions(-) diff --git a/xexamine.1 b/xexamine.1 index 8573fda..a07291a 100644 --- a/xexamine.1 +++ b/xexamine.1 @@ -109,7 +109,11 @@ screen. Often, the 2nd or some further segment contains the actual code/data, and is identical. .SH EXIT STATUS .sp -Exit status is zero if \fIxexfile\fP is a valid Atari .xex file, non\-zero otherwise. +Exit status is zero if all \fIxexfile\fPs are valid Atari .xex files, non\-zero otherwise. +.sp +When processing multiple files, \fBxexamine\fP exits if there\(aqs an error +reading one of the files; any files after that on the command line are +not processed. .SH COPYRIGHT .sp WTFPL. See \fI\%http://www.wtfpl.net/txt/copying/\fP for details. diff --git a/xexamine.rst b/xexamine.rst index ea28feb..246c2aa 100644 --- a/xexamine.rst +++ b/xexamine.rst @@ -84,6 +84,10 @@ code/data, and is identical. EXIT STATUS =========== -Exit status is zero if *xexfile* is a valid Atari .xex file, non-zero otherwise. +Exit status is zero if all *xexfile*\s are valid Atari .xex files, non-zero otherwise. + +When processing multiple files, **xexamine** exits if there's an error +reading one of the files; any files after that on the command line are +not processed. .. include:: manftr.rst diff --git a/xexsplit.1 b/xexsplit.1 index dfc4e40..157490c 100644 --- a/xexsplit.1 +++ b/xexsplit.1 @@ -40,44 +40,53 @@ xexsplit \- Split a multi-segment Atari 8-bit executable (XEX) into multiple sin . .SH SYNOPSIS .sp -\fIxexsplit\fP [\fI\-hv\fP] \fIinfile.xex\fP [\fIoutfile\-prefix\fP] +\fIxexsplit\fP [\fI\-hvr\fP] \fIinfile.xex\fP [\fIoutfile\-prefix\fP] .SH DESCRIPTION .sp -xexsplit reads an Atari executable (XEX/BIN/COM/etc) from \fIinfile\fP and -writes each segment to a separate file. To read from standard input, +xexsplit reads an Atari executable (XEX/BIN/COM/etc) from \fIinfile\fP and +writes each segment to a separate file. To read from standard input, infile may be omitted, or given as \fB\-\fP\&. .sp -Output files are named \fBoutfile\-prefix.NNN.SSSS.EEEE\fP, where \fBNNN\fP is -the segment number (decimal, 3 digits, with leading zeroes), \fBSSSS\fP -is the start address of the segment (4 digits, hex), and \fBEEEE\fP is the -end address of the segment (4 digits, hex). If \fIoutfile\-prefix\fP is -omitted, the default prefix is \fBxexsplit.xex\fP\&. -.sp -Each output file is a valid single\-segment Atari executable, including -the required \fI$FFFF\fP header. They may be joined back together (possibly -after being modified) with xexcat or plain old \fBcat\fP(1). +Output files are named \fBoutfile\-prefix.NNN.SSSS.EEEE.EXT\fP, where +\fBNNN\fP is the segment number (decimal, 3 digits, with leading +zeroes), \fBSSSS\fP is the start address of the segment (4 digits, +hex), \fBEEEE\fP is the end address of the segment (4 digits, hex), +and \fBEXT\fP is \fI\&.xex\fP for .xex output or \fI\&.bin\fP for raw (\fB\-r\fP) +output. If \fIoutfile\-prefix\fP is omitted, the default prefix is the +input filename. +.sp +By default, each output file is a valid single\-segment Atari +executable, including the required \fI$FFFF\fP header. They may be joined +back together (possibly after being modified) with xexcat or plain old +\fBcat\fP(1). .SH OPTIONS .INDENT 0.0 .TP +.B \-r +Raw output: the output files will just contain the data from each +segment, without the \fI$FFFF\fP header, start, and end addresses. +Useful for feeding the results to tools like disassemblers that +don\(aqt understand the .xex format. +.TP .B \-h Print a short help message and exit. .TP .B \-v -Verbose operation. Each segment\(aqs information is printed to +Verbose operation. Each segment\(aqs information is printed to standard error, including start/end address and length. .UNINDENT .SH NOTES .sp -The terms "Atari executable", "binary load file", and "XEX file" +The terms "Atari executable", "binary load file", and "XEX file" all refer to the same thing. Also, there is no difference between Atari executables named with "XEX", "COM", "BIN", "EXE", etc. The Atari and its DOS don\(aqt care about the names, only the contents. .sp -It is not possible to use \fB\-\fP to write to standard output. This makes +It is not possible to use \fB\-\fP to write to standard output. This makes sense, because there\(aqs no way to write multiple, separate files to stdout. .sp -The output filenames were chosen so they will sort in the order they -were created, when used with the shell\(aqs globbing. This means that you +The output filenames were chosen so they will sort in the order they +were created, when used with the shell\(aqs globbing. This means that you can join them back into a single valid XEX file with a command like: .INDENT 0.0 .INDENT 3.5 @@ -102,42 +111,42 @@ xexcat \-o joined.xex prefix.* .UNINDENT .UNINDENT .sp -The Atari binary load format requires the \fI$FFFF\fP header only for -the first segment in a file. The second and subsequent segments may +The Atari binary load format requires the \fI$FFFF\fP header only for +the first segment in a file. The second and subsequent segments may also have a \fI$FFFF\fP header, but it\(aqs optional. \fBxexsplit\fP\(aqs output -files will always have the \fI$FFFF\fP header, regardless of whether +files will always have the \fI$FFFF\fP header, regardless of whether the segments in the original file had it or not (in fact, \fBxexsplit\fP -can handle an invalid XEX file which is missing the initial $FFFF -header for the first seg‐ ment). +can handle an invalid XEX file which is missing the initial $FFFF +header for the first segment). .sp -A segment starting at address \fB$02E2\fP contains an init address. +A segment starting at address \fB$02E2\fP contains an init address. During loading, Atari DOSes JSR to the init address immediately after its segment has loaded. Init addresses are optinal; there\(aqs no -rule that says that every file has to have one. It\(aqs also normal +rule that says that every file has to have one. It\(aqs also normal and fairly common for there to be several init addresses in a -multi\-segment file. An init ad‐ dress segment is normally located -right after the code segment it\(aqs in‐ tended to run, but this is not +multi\-segment file. An init address segment is normally located +right after the code segment it\(aqs intended to run, but this is not a requirement. .sp -A segment starting at address \fB$02E0\fP contains a run address. -After all segments have been loaded, Atari DOSes JSR to the run +A segment starting at address \fB$02E0\fP contains a run address. +After all segments have been loaded, Atari DOSes JSR to the run address to run the program just loaded. The run address is optional; -a file containing no run address segment will simply be loaded into -memory and not executed (user will be returned to the DOS menu). -It\(aqs legal for a multi\-segment file to contain multiple run +a file containing no run address segment will simply be loaded into +memory and not executed (user will be returned to the DOS menu). +It\(aqs legal for a multi\-segment file to contain multiple run address segments, but only the last run address will actually be -used. Normally, there is only one run address; if there are more than -one, only the last one is used. The run address is normally the last +used. Normally, there is only one run address; if there are more than +one, only the last one is used. The run address is normally the last segment in the file, but this is not a requirement. .sp Attempting to run a single\-segment file consisting of a run or init address only, will generally crash the Atari. .sp -Some Atari executables contain raw blocks of data, which are meant -to be read into memory by the init routine. These blocks do not -have start/end address headers, so \fBxexsplit\fP is unable to handle -them. Raw data blocks usually occur in files created with "packer" -or "compressor" programs, or occasionally in other large programs +Some Atari executables contain raw blocks of data, which are meant +to be read into memory by the init routine. These blocks do not +have start/end address headers, so \fBxexsplit\fP is unable to handle +them. Raw data blocks usually occur in files created with "packer" +or "compressor" programs, or occasionally in other large programs (Turbo BASIC is an example). Raw data blocks are generally found just after an init address segment. If you have an executable that loads just fine on a real Atari or emulator, but fails with \fBxexsplit\fP, diff --git a/xexsplit.c b/xexsplit.c index 4df51f3..c120ae6 100644 --- a/xexsplit.c +++ b/xexsplit.c @@ -11,7 +11,7 @@ #endif #define SELF "xexsplit" -#define OPTIONS "hv" +#define OPTIONS "hvr" char *usage = SELF " v" VERSION " by B. Watson (WTFPL)\n" @@ -27,12 +27,16 @@ int main(int argc, char **argv) { char outfile[4096]; unsigned char buffer[65536]; FILE *out = NULL; - int count = 1, outlen, c; + int count = 1, outlen, c, raw_output = 0; strcpy(outfile, "xexsplit"); while( (c = getopt(argc, argv, OPTIONS)) > 0) { switch(c) { + case 'r': + raw_output = 1; + break; + case 'h': printf(usage); exit(0); @@ -86,8 +90,9 @@ int main(int argc, char **argv) { seg.has_ff_header = 1; sprintf(outfile + outlen, - ".%03d.%04X.%04X", - count, seg.start_addr, seg.end_addr); + ".%03d.%04X.%04X.%s", + count, seg.start_addr, seg.end_addr, + (raw_output ? "bin" : "xex")); if( !(out = fopen(outfile, "wb")) ) { fprintf(stderr, SELF ": %s: %s\n", outfile, strerror(errno)); @@ -95,8 +100,13 @@ int main(int argc, char **argv) { exit(1); } - if(!xex_fwrite_seg(&seg, out)) - break; + if(raw_output) { + if(fwrite(seg.object, seg.len, 1, out) < 1) + break; + } else { + if(!xex_fwrite_seg(&seg, out)) + break; + } fclose(out); out = NULL; diff --git a/xexsplit.rst b/xexsplit.rst index 3a304c3..906257c 100644 --- a/xexsplit.rst +++ b/xexsplit.rst @@ -17,48 +17,57 @@ Split a multi-segment Atari 8-bit executable (XEX) into multiple single-segment SYNOPSIS ======== -*xexsplit* [*-hv*] *infile.xex* [*outfile-prefix*] +*xexsplit* [*-hvr*] *infile.xex* [*outfile-prefix*] DESCRIPTION =========== -xexsplit reads an Atari executable (XEX/BIN/COM/etc) from *infile* and -writes each segment to a separate file. To read from standard input, +xexsplit reads an Atari executable (XEX/BIN/COM/etc) from *infile* and +writes each segment to a separate file. To read from standard input, infile may be omitted, or given as **-**. -Output files are named **outfile-prefix.NNN.SSSS.EEEE**, where **NNN** is -the segment number (decimal, 3 digits, with leading zeroes), **SSSS** -is the start address of the segment (4 digits, hex), and **EEEE** is the -end address of the segment (4 digits, hex). If *outfile-prefix* is -omitted, the default prefix is **xexsplit.xex**. +Output files are named **outfile-prefix.NNN.SSSS.EEEE.EXT**, where +**NNN** is the segment number (decimal, 3 digits, with leading +zeroes), **SSSS** is the start address of the segment (4 digits, +hex), **EEEE** is the end address of the segment (4 digits, hex), +and **EXT** is *.xex* for .xex output or *.bin* for raw (**-r**) +output. If *outfile-prefix* is omitted, the default prefix is the +input filename. -Each output file is a valid single-segment Atari executable, including -the required *$FFFF* header. They may be joined back together (possibly -after being modified) with xexcat or plain old **cat**\(1). +By default, each output file is a valid single-segment Atari +executable, including the required *$FFFF* header. They may be joined +back together (possibly after being modified) with xexcat or plain old +**cat**\(1). OPTIONS ======= +-r + Raw output: the output files will just contain the data from each + segment, without the *$FFFF* header, start, and end addresses. + Useful for feeding the results to tools like disassemblers that + don't understand the .xex format. + -h Print a short help message and exit. -v - Verbose operation. Each segment's information is printed to + Verbose operation. Each segment's information is printed to standard error, including start/end address and length. NOTES ===== -The terms "Atari executable", "binary load file", and "XEX file" +The terms "Atari executable", "binary load file", and "XEX file" all refer to the same thing. Also, there is no difference between Atari executables named with "XEX", "COM", "BIN", "EXE", etc. The Atari and its DOS don't care about the names, only the contents. -It is not possible to use **-** to write to standard output. This makes +It is not possible to use **-** to write to standard output. This makes sense, because there's no way to write multiple, separate files to stdout. -The output filenames were chosen so they will sort in the order they -were created, when used with the shell's globbing. This means that you +The output filenames were chosen so they will sort in the order they +were created, when used with the shell's globbing. This means that you can join them back into a single valid XEX file with a command like:: cat prefix.* > joined.xex @@ -67,42 +76,42 @@ or use **xexcat**\(1) instead of **cat**:: xexcat -o joined.xex prefix.* -The Atari binary load format requires the *$FFFF* header only for -the first segment in a file. The second and subsequent segments may +The Atari binary load format requires the *$FFFF* header only for +the first segment in a file. The second and subsequent segments may also have a *$FFFF* header, but it's optional. **xexsplit**'s output -files will always have the *$FFFF* header, regardless of whether +files will always have the *$FFFF* header, regardless of whether the segments in the original file had it or not (in fact, **xexsplit** -can handle an invalid XEX file which is missing the initial $FFFF -header for the first seg‐ ment). +can handle an invalid XEX file which is missing the initial $FFFF +header for the first segment). -A segment starting at address **$02E2** contains an init address. +A segment starting at address **$02E2** contains an init address. During loading, Atari DOSes JSR to the init address immediately after its segment has loaded. Init addresses are optinal; there's no -rule that says that every file has to have one. It's also normal +rule that says that every file has to have one. It's also normal and fairly common for there to be several init addresses in a -multi-segment file. An init ad‐ dress segment is normally located -right after the code segment it's in‐ tended to run, but this is not +multi-segment file. An init address segment is normally located +right after the code segment it's intended to run, but this is not a requirement. -A segment starting at address **$02E0** contains a run address. -After all segments have been loaded, Atari DOSes JSR to the run +A segment starting at address **$02E0** contains a run address. +After all segments have been loaded, Atari DOSes JSR to the run address to run the program just loaded. The run address is optional; -a file containing no run address segment will simply be loaded into -memory and not executed (user will be returned to the DOS menu). -It's legal for a multi-segment file to contain multiple run +a file containing no run address segment will simply be loaded into +memory and not executed (user will be returned to the DOS menu). +It's legal for a multi-segment file to contain multiple run address segments, but only the last run address will actually be -used. Normally, there is only one run address; if there are more than -one, only the last one is used. The run address is normally the last +used. Normally, there is only one run address; if there are more than +one, only the last one is used. The run address is normally the last segment in the file, but this is not a requirement. Attempting to run a single-segment file consisting of a run or init address only, will generally crash the Atari. -Some Atari executables contain raw blocks of data, which are meant -to be read into memory by the init routine. These blocks do not -have start/end address headers, so **xexsplit** is unable to handle -them. Raw data blocks usually occur in files created with "packer" -or "compressor" programs, or occasionally in other large programs +Some Atari executables contain raw blocks of data, which are meant +to be read into memory by the init routine. These blocks do not +have start/end address headers, so **xexsplit** is unable to handle +them. Raw data blocks usually occur in files created with "packer" +or "compressor" programs, or occasionally in other large programs (Turbo BASIC is an example). Raw data blocks are generally found just after an init address segment. If you have an executable that loads just fine on a real Atari or emulator, but fails with **xexsplit**, -- cgit v1.2.3