aboutsummaryrefslogtreecommitdiff
path: root/xex.h
diff options
context:
space:
mode:
Diffstat (limited to 'xex.h')
-rw-r--r--xex.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/xex.h b/xex.h
new file mode 100644
index 0000000..2300481
--- /dev/null
+++ b/xex.h
@@ -0,0 +1,117 @@
+#ifndef XEX_H
+#define XEX_H
+
+/* A xex_segment represents one segment of a XEX file. */
+typedef struct {
+ unsigned short start_addr;
+ unsigned short end_addr;
+ unsigned char *object;
+ int len;
+ unsigned char has_ff_header;
+} xex_segment;
+
+/* object points to an array containing ONLY the data bytes, not the
+ header bytes! Use xex_get_object() to reconstitute the full
+ segment with headers.
+
+ (Note that I'm using the word "object" in the sense of "object code",
+ not in its OOP sense)
+ */
+
+#define XEX_RUNAD 0x2e0
+#define XEX_INITAD 0x2e2
+
+#define XEX_LSB(x) (x & 0xff)
+#define XEX_MSB(x) ((x >> 8) & 0xff)
+#define XEX_ADDR(x, y) ((unsigned char)x | ((unsigned char)y << 8))
+
+/* All int functions return true for success or false for failure.
+ On failure, the variable xex_errno will be set to one of the
+ XERR_* constants. Caller may use xex_strerror(xex_errno) to
+ get a human-readable error message (or xex_perror()).
+
+ Note that XERR_NONE == 0, so you can use the construct:
+ if(xex_errno) {
+ // handle error here
+ }
+ */
+
+#define XERR_NONE 0
+#define XERR_SYSCALL 1
+#define XERR_REVERSED 2
+#define XERR_TRUNCATED 3
+#define XERR_NULLDATA 4
+#define XERR_MAXERR 5
+
+extern int xex_errno;
+extern int xex_verbose;
+
+/* Initialize a xex_segment from the data pointed to by segment, which must
+ not be null. segment must be a complete segment, including start/end
+ addresses and possible $FFFF header. seg->object will point within the
+ data, so don't free() it until you're done with seg! */
+int xex_new_seg(xex_segment *seg, unsigned char *segment);
+
+/* Set up seg as an init address segment. object must have room for at
+ least 2 characters. A copy of the object pointer is stored in
+ seg->object, so don't free(object) until you're done with seg. */
+int xex_init_seg(xex_segment *seg, unsigned char *object, unsigned short addr);
+
+/* Set up seg as an run address segment. object must have room for at
+ least 2 characters. A copy of the object pointer is stored in seg->object,
+ so don't free(object) until you're done with seg.*/
+int xex_run_seg(xex_segment *seg, unsigned char *object, unsigned short addr);
+
+/* Since this library does NOT allocate any memory, reading a segment must
+ be done in two pieces. xex_fread_seg_header() reads the 4- or 6-byte
+ header and sets seg->len to the size of the segment. xex_fread_seg_data()
+ then reads this number of bytes from the file, into seg->object.
+
+ Example usage:
+
+ xex_segment seg;
+
+ xex_fread_seg_header(&seg, my_file);
+ seg.object = malloc(seg->len);
+ xex_fread_seg_data(&seg, my_file);
+
+ // ...later, the caller must free(seg.object) when done with it.
+
+ xex_fread_seg_header() returns 0 on EOF, with xex_errno set to
+ XERR_NONE. It also returns 0 on failure, but xex_errno will be
+ something other than XERR_NONE.
+*/
+int xex_fread_seg_header(xex_segment *seg, FILE *file);
+int xex_fread_seg_data(xex_segment *seg, FILE *file);
+
+/* If you're dealing with xex files sequentially, and want to use a
+ static buffer instead of malloc(), you can use xex_fread_seg() instead.
+ seg->object should point to a buffer large enough to hold any segment's
+ object code (64K, to be on the safe side), or you WILL get segfaults. */
+int xex_fread_seg(xex_segment *seg, FILE *file);
+
+/* xex_fwrite_seg() writes a segment to a file, which must be opened
+ for output. */
+int xex_fwrite_seg(xex_segment *seg, FILE *file);
+
+/* Extract the object code from a segment. data must have room for len+6
+ bytes (or len+4 if has_ff_header is false). data will be the raw
+ segment data, suitable for writing to a XEX file. */
+int xex_get_object(xex_segment *seg, unsigned char *data);
+
+/* Sanity check a segment. Make sure start_addr is less than end_addr,
+ that it doesn't wrap around the 6502 address space, and so on.
+ Returns true if segment is OK. */
+int xex_check_seg(xex_segment *seg);
+
+/* Get human-readable error message. If xex_errno is XSYSCALL, the system's
+ strerror() is called. */
+char *xex_strerror(int err);
+
+/* Shortcut for xex_strerror(), like system's perror() */
+void xex_perror(char *msg);
+
+/* Debugging aid */
+void xex_print_seg_info(xex_segment *seg);
+
+#endif /* XEX_H */