diff options
author | B. Watson <urchlay@slackware.uk> | 2022-08-29 16:11:13 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2022-08-29 16:11:13 -0400 |
commit | e2ba8458a5cfdfacfaf103e7ba97d610afa6c970 (patch) | |
tree | cd665e602e6e2b636578a7d3d7894380605dafcc /xex.h | |
download | bw-atari8-tools-e2ba8458a5cfdfacfaf103e7ba97d610afa6c970.tar.gz |
initial commit
Diffstat (limited to 'xex.h')
-rw-r--r-- | xex.h | 117 |
1 files changed, 117 insertions, 0 deletions
@@ -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 */ |