#include #include "xex.h" /* This is a minimal program illustrating the use of the xex library. It expects to read one or more Atari executables from standard input, and writes one (possibly multi-segment) Atari executable to standard output. This code is provided an an example only; for a useful real-world tool, use xexcat. To compile: "make xextest" if you have the full bw_atari8_utils source distribution. Otherwise, (assuming you at least have xex.c and xex.h): gcc -o xextest xextest.c xex.c (should work with other compilers too). */ int main(int argc, char **argv) { xex_segment seg; unsigned char buffer[64 * 1024]; /* 64K buffer is guaranteed big enough */ int count = 1; /* tell xex library to emit debugging trace to stderr. Default value is 0 (no trace). */ xex_verbose = 1; /* xex_fread_seg_header() returns false on error or at EOF. */ while(xex_fread_seg_header(&seg, stdin)) { seg.object = buffer; /* We're using a static buffer here. If we were using dynamically allocated buffers, we'd say "seg.object = malloc(seg.len)" above, and put a "free(seg.object)" somewhere after the xex_fwrite_seg(). Note that the xex lib NEVER calls malloc() or free() itself. (Also, it never calls any of the standard I/O functions except fread(), fwrite(), feof(), or ferror(); you have to fopen() and fclose() in the calling code). */ /* xex library doesn't care if the first segment is missing the required Atari $FFFF header, so we handle it ourselves. */ if(count == 1 && !seg.has_ff_header) fprintf(stderr, "missing initial $FFFF header (bad XEX file?)\n"); /* Force the first segment to have a $FFFF header, and remove the (optional) $FFFF header from subsequent segments. */ seg.has_ff_header = (count == 1); /* Read the segment data. xex_fread_seg_data() returns false for failure (with xex_errno set to indicate the reason). An EOF in the middle of a segment is an error (means the file was truncated). */ if(!xex_fread_seg_data(&seg, stdin)) break; /* xex_fwrite_seg() returns true for success, or false for failure (with xex_errno set). Unless you've diddled with seg's fields, xex_errno will always be XERR_SYSCALL when xex_fwrite_seg() fails (and xex_perror() or xex_strerror() will call the real strerror() to get the system's error message). */ if(!xex_fwrite_seg(&seg, stdout)) break; /* If we weren't using xex_verbose mode, we might want to call xex_print_seg_info() ourselves to print some info about the segment, like so: */ /* xex_print_seg_info(&seg); */ fprintf(stderr, "segment #%d done\n\n", count); count++; } /* If xex_fread_seg_header() returned false due to EOF, xex_errno will be zero (aka XERR_NONE). Otherwise, xex_fread_seg_header() didn't like the header, or else xex_fread_seg_data() returned false (probably due to a premature EOF in the middle of the segment data), so we print an error message about it. */ if(xex_errno) xex_perror("error"); /* xex_errno will be 0 for error or non-zero otherwise, so it's suitable for use as a standard UNIX exit status. */ return xex_errno; }