#include <stdio.h>
#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;
}
