From b89c79b5a8b2084574f2645d7034ba595b9d5cd0 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Wed, 13 Sep 2023 14:40:48 -0400 Subject: Refactor stuff into separate files, finally --- Makefile | 25 +-- include/zx/basic.h | 35 ++++ include/zx/charset.h | 40 +++++ include/zx/hexdump.h | 12 ++ main.c | 475 --------------------------------------------------- src/Makefile | 27 +++ src/basic.c | 163 ++++++++++++++++++ src/charset.c | 66 +++++++ src/hexdump.c | 109 ++++++++++++ src/main.c | 99 +++++++++++ 10 files changed, 556 insertions(+), 495 deletions(-) create mode 100644 include/zx/basic.h create mode 100644 include/zx/charset.h create mode 100644 include/zx/hexdump.h delete mode 100644 main.c create mode 100644 src/Makefile create mode 100644 src/basic.c create mode 100644 src/charset.c create mode 100644 src/hexdump.c create mode 100644 src/main.c diff --git a/Makefile b/Makefile index c0d8cd0..e476f4e 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,8 @@ -CC = cc -CFLAGS = -g -Wall -O2 -LDFLAGS = -OBJS = main.o -NAME = zxdump +all: + $(MAKE) -C src all -PREFIX = /usr/local -INSTALL = /usr/bin/install -RM = /bin/rm - -all: $(NAME) - -$(NAME): $(OBJS) - $(CC) $(OBJS) -o $(NAME) $(LDFLAGS) - -$(OBJS): %.o: %.c - $(CC) $(CFLAGS) -c $< - -install: $(NAME) - $(INSTALL) -c -m 0755 $(NAME) $(PREFIX)/bin +install: + $(MAKE) -C src install clean: - $(RM) -f $(NAME) $(OBJS) + $(MAKE) -C src clean diff --git a/include/zx/basic.h b/include/zx/basic.h new file mode 100644 index 0000000..1989954 --- /dev/null +++ b/include/zx/basic.h @@ -0,0 +1,35 @@ +#ifndef _ZX_BASIC_H +#define _ZX_BASIC_H + +#include +#include +#include + +#define ZX81_CHAR_TOKEN_LOW_START 0x40 +#define ZX81_CHAR_TOKEN_LOW_END 0x42 + +#define ZX81_CHAR_TOKEN_HIGH_START 0xc0 +#define ZX81_CHAR_TOKEN_HIGH_END 0xff + +#define ZX_BASIC_STATE_SIZE 116 +#define ZX_BASIC_LINE_LAST 0x7676 + +extern char *zx81_basic_tokens_low[3]; + +extern char *zx81_basic_tokens[64]; + +typedef struct _zx_basic_line { + uint16_t num, len; +} zx_basic_line; + +enum zx_basic_token_type { + ZX_BASIC_TOKEN_UNKNOWN, + ZX_BASIC_TOKEN_ALNUM, + ZX_BASIC_TOKEN_QUOTE, + ZX_BASIC_TOKEN_SYMBOL, + ZX_BASIC_TOKEN_WORD, +}; + +ssize_t zx81_basic_dump(int fd, FILE *stream); + +#endif /* _ZX_BASIC_H */ diff --git a/include/zx/charset.h b/include/zx/charset.h new file mode 100644 index 0000000..34f6eb8 --- /dev/null +++ b/include/zx/charset.h @@ -0,0 +1,40 @@ +#ifndef _ZX_CHARSET_H +#define _ZX_CHARSET_H + +#include +#include + +#define ZX81_CHARSET_LEN 64 + +#define ZX81_CHAR_LOW(c) \ + (c <= ZX81_CHARSET_LEN) + +#define ZX81_CHAR_INVERSE_START 0x80 +#define ZX81_CHAR_INVERSE_END 0xbf + +#define ZX81_CHAR_INVERSE(c) \ + (c >= ZX81_CHAR_INVERSE_START && c <= ZX81_CHAR_INVERSE_END) + +#define ZX81_CHAR_TOKEN_LOW(c) \ + (c >= ZX81_CHAR_TOKEN_LOW_START && c <= ZX81_CHAR_TOKEN_LOW_END) + +#define ZX81_CHAR_NEWLINE(c) \ + (c == 0x76) + +#define ZX81_CHAR_TOKEN_HIGH(c) \ + (c >= 0xc0) + +#define ZX81_CHAR_TOKEN(c) \ + (ZX81_CHAR_TOKEN_LOW(c) || ZX81_CHAR_TOKEN_HIGH(c)) + +#define ZX81_CHAR_TOKEN_INTEGRAL(c) \ + (c == 0x0e) + +#define ZX81_CHAR_TOKEN_FLOAT(c) \ + (c == 0x7e) + +extern uint32_t zx81_charset[ZX81_CHARSET_LEN]; + +int zx81_fputc(uint8_t c, int inverse, FILE *stream); + +#endif /* _ZX_CHARSET_H */ diff --git a/include/zx/hexdump.h b/include/zx/hexdump.h new file mode 100644 index 0000000..5b38796 --- /dev/null +++ b/include/zx/hexdump.h @@ -0,0 +1,12 @@ +#ifndef _ZX81_HEXDUMP_H +#define _ZX81_HEXDUMP_H + +#include +#include + +#define ZX81_HEXDUMP_STRIDE_LINE 16 +#define ZX81_HEXDUMP_STRIDE_GROUP 2 + +ssize_t zx81_hexdump(int source_fd, FILE *stream); + +#endif /* _ZX81_HEXDUMP_H */ diff --git a/main.c b/main.c deleted file mode 100644 index 488d230..0000000 --- a/main.c +++ /dev/null @@ -1,475 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ZX_CHARSET_LEN 64 - -#define ZX_CHAR_LOW(c) \ - (c <= ZX_CHARSET_LEN) - -#define ZX_CHAR_INVERSE_START 0x80 -#define ZX_CHAR_INVERSE_END 0xbf - -#define ZX_CHAR_INVERSE(c) \ - (c >= ZX_CHAR_INVERSE_START && c <= ZX_CHAR_INVERSE_END) - -#define ZX_CHAR_TOKEN_LOW_START 0x40 -#define ZX_CHAR_TOKEN_LOW_END 0x42 - -#define ZX_CHAR_TOKEN_LOW(c) \ - (c >= ZX_CHAR_TOKEN_LOW_START && c <= ZX_CHAR_TOKEN_LOW_END) - -#define ZX_CHAR_NEWLINE(c) \ - (c == 0x76) - -#define ZX_CHAR_TOKEN_HIGH_START 0xc0 -#define ZX_CHAR_TOKEN_HIGH_END 0xff - -#define ZX_CHAR_TOKEN_HIGH(c) \ - (c >= 0xc0) - -#define ZX_CHAR_TOKEN(c) \ - (ZX_CHAR_TOKEN_LOW(c) || ZX_CHAR_TOKEN_HIGH(c)) - -#define ZX_CHAR_TOKEN_INTEGRAL(c) \ - (c == 0x0e) - -#define ZX_CHAR_TOKEN_FLOAT(c) \ - (c == 0x7e) - -typedef struct _zx_basic_line { - uint16_t num, len; -} zx_basic_line; - -enum zx_basic_token_type { - ZX_BASIC_TOKEN_UNKNOWN, - ZX_BASIC_TOKEN_ALNUM, - ZX_BASIC_TOKEN_QUOTE, - ZX_BASIC_TOKEN_SYMBOL, - ZX_BASIC_TOKEN_WORD, -}; - -#define ZX_BASIC_STATE_SIZE 116 -#define ZX_BASIC_LINE_LAST 0x7676 - -static uint32_t zx_charset[ZX_CHARSET_LEN] = { - 0x0020, 0x2598, 0x259d, 0x2580, 0x2596, 0x258c, 0x259e, 0x259b, - 0x2592, '.', '.', '"', 0x00a3, '$', ':', '?', - '(', ')', '>', '<', '=', '+', '-', '*', - '/', ';', ',', '.', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', 'A', 'B', - 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', -}; - -static char *zx_tokens_low[3] = { - "RND", "INKEY$", "PI", -}; - -static char *zx_tokens[64] = { - "\"\"", "AT", "TAB", NULL, "CODE", "VAL", "LEN", "SIN", - "COS", "TAN", "ASN", "ACS", "ATN", "LN", "EXP", "INT", - "SQR", "SGN", "ABS", "PEEK", "USR", "STR$", "CHR$", "NOT", - "**", "OR", "AND", "<=", ">=", "<>", "THEN", "TO", - "STEP", "LPRINT", "LLIST", "STOP", "SLOW", "FAST", "NEW", "SCROLL", - "CONT", "DIM", "REM", "FOR", "GOTO", "GOSUB", "INPUT", "LOAD", - "LIST", "LET", "PAUSE", "NEXT", "POKE", "PRINT", "PLOT", "RUN", - "SAVE", "RAND", "IF", "CLS", "UNPLOT", "CLEAR", "RETURN", "COPY", -}; - -static inline size_t utf8_encode(uint8_t *buf, uint32_t codepoint) { - if ((codepoint & 0x007f) == codepoint) { - buf[0] = codepoint & 0x007f; - - return 1; - } else if ((codepoint & 0x07ff) == codepoint) { - buf[0] = 0xc0 | ((codepoint & 0x07c0) >> 6); - buf[1] = 0x80 | (codepoint & 0x003f); - - return 2; - } else if ((codepoint & 0xffff) == codepoint) { - buf[0] = 0xe0 | ((codepoint & 0xf000) >> 12); - buf[1] = 0x80 | ((codepoint & 0x0fc0) >> 6); - buf[2] = 0x80 | (codepoint & 0x003f); - - return 3; - } else { - buf[0] = 0xf0 | ((codepoint & 0x1c0000) >> 18); - buf[1] = 0x80 | ((codepoint & 0x03f000) >> 12); - buf[2] = 0x80 | ((codepoint & 0x000fc0) >> 6); - buf[3] = 0x80 | (codepoint & 0x00003f); - - return 4; - } -} - -static inline int zx_putchar(uint8_t c, int inverse) { - uint8_t sequence[4]; - size_t len = utf8_encode(sequence, zx_charset[c]); - - if (inverse) { - if (fputs("\033[7m", stdout) < 0) { - goto error_io; - } - } - - if (fwrite(sequence, len, 1, stdout) < 1) { - goto error_io; - } - - if (inverse) { - if (fputs("\033[27m", stdout) < 0) { - goto error_io; - } - } - - return 0; - -error_io: - return -1; -} - -#define ZX_HEXDUMP_STRIDE_LINE 16 -#define ZX_HEXDUMP_STRIDE_GROUP 2 - -static ssize_t hexdump_line(off_t offset, void *buf, size_t len, int tty) { - size_t i; - - if (printf("%08zx: ", offset) < 0) { - goto error_io; - } - - for (i=0; i 0 && (i % ZX_HEXDUMP_STRIDE_GROUP) == 0) { - if (putchar(' ') < 0) { - goto error_io; - } - } - - if (printf("%02x", ((uint8_t *)buf)[offset+i]) < 0) { - goto error_io; - } - } - - if (fputs(" ", stdout) < 0) { - goto error_io; - } - - for (i=0; i= 0xa0 && c <= 0xbf) { - if (zx_putchar(c - 0xa0, tty) < 0) { - goto error_io; - } - } else { - if (putchar('.') < 0) { - goto error_io; - } - } - } - - if (putchar('\n') < 0) { - goto error_io; - } - - return fflush(stdout); - -error_io: - return -1; -} - -static ssize_t zx_dump_hex(int fd) { - void *buf; - ssize_t total = 0; - int tty = isatty(fileno(stdout)); - struct stat st; - - if (fstat(fd, &st) < 0) { - goto error_fstat; - } - - if ((buf = malloc(st.st_blksize)) == NULL) { - goto error_malloc; - } - - while (1) { - ssize_t len, i; - off_t offset = 0; - - if ((len = read(fd, buf, st.st_blksize)) < 0) { - goto error_read; - } else if (len == 0) { - break; - } - - for (i=0; i= 'A' && codepoint <= 'Z') - || (codepoint >= '0' && codepoint <= '9')) { - return ZX_BASIC_TOKEN_ALNUM; - } else if (codepoint == '"') { - return ZX_BASIC_TOKEN_QUOTE; - } else { - return ZX_BASIC_TOKEN_SYMBOL; - } - } else if (ZX_CHAR_INVERSE(b)) { - return zx_basic_token_type_get(b - ZX_CHAR_INVERSE_START); - } else if (ZX_CHAR_TOKEN_LOW(b)) { - return ZX_BASIC_TOKEN_WORD; - } else if (ZX_CHAR_TOKEN_HIGH(b)) { - char *token = zx_tokens[b-ZX_CHAR_TOKEN_HIGH_START]; - - if (token[0] >= 'A' && token[0] <= 'Z') { - return ZX_BASIC_TOKEN_WORD; - } else { - return ZX_BASIC_TOKEN_SYMBOL; - } - } - - return ZX_BASIC_TOKEN_UNKNOWN; -} - -static ssize_t zx_dump_basic(int fd) { - void *buf; - ssize_t total = 0; - int tty = isatty(fileno(stdout)); - struct stat st; - - if (fstat(fd, &st) < 0) { - goto error_fstat; - } - - if ((buf = malloc(st.st_blksize)) == NULL) { - goto error_malloc; - } - - if (lseek(fd, ZX_BASIC_STATE_SIZE, SEEK_CUR) < 0) { - goto error_io; - } - - while (1) { - ssize_t readlen, len, i; - zx_basic_line line; - uint8_t last = 0xc0; - - if ((readlen = read(fd, &line, sizeof(line))) < 0) { - goto error_io; - } else if (readlen == 0) { - break; - } - - len = le16toh(line.len); - - if (be16toh(line.num) == len && len == ZX_BASIC_LINE_LAST) { - break; - } - - if (printf("%d ", (int)be16toh(line.num)) < 0) { - goto error_io; - } - - if (read(fd, buf, len) < 0) { - goto error_io; - } - - for (i=0; i +#include + +#include +#include + +char *zx81_basic_tokens_low[3] = { + "RND", "INKEY$", "PI", +}; + +char *zx81_basic_tokens[64] = { + "\"\"", "AT", "TAB", NULL, "CODE", "VAL", "LEN", "SIN", + "COS", "TAN", "ASN", "ACS", "ATN", "LN", "EXP", "INT", + "SQR", "SGN", "ABS", "PEEK", "USR", "STR$", "CHR$", "NOT", + "**", "OR", "AND", "<=", ">=", "<>", "THEN", "TO", + "STEP", "LPRINT", "LLIST", "STOP", "SLOW", "FAST", "NEW", "SCROLL", + "CONT", "DIM", "REM", "FOR", "GOTO", "GOSUB", "INPUT", "LOAD", + "LIST", "LET", "PAUSE", "NEXT", "POKE", "PRINT", "PLOT", "RUN", + "SAVE", "RAND", "IF", "CLS", "UNPLOT", "CLEAR", "RETURN", "COPY", +}; + +static inline enum zx_basic_token_type zx_basic_token_type_get(uint8_t b) { + if (ZX81_CHAR_LOW(b)) { + uint32_t codepoint = zx81_charset[b]; + + if ((codepoint >= 'A' && codepoint <= 'Z') + || (codepoint >= '0' && codepoint <= '9')) { + return ZX_BASIC_TOKEN_ALNUM; + } else if (codepoint == '"') { + return ZX_BASIC_TOKEN_QUOTE; + } else { + return ZX_BASIC_TOKEN_SYMBOL; + } + } else if (ZX81_CHAR_INVERSE(b)) { + return zx_basic_token_type_get(b - ZX81_CHAR_INVERSE_START); + } else if (ZX81_CHAR_TOKEN_LOW(b)) { + return ZX_BASIC_TOKEN_WORD; + } else if (ZX81_CHAR_TOKEN_HIGH(b)) { + char *token = zx81_basic_tokens[b-ZX81_CHAR_TOKEN_HIGH_START]; + + if (token[0] >= 'A' && token[0] <= 'Z') { + return ZX_BASIC_TOKEN_WORD; + } else { + return ZX_BASIC_TOKEN_SYMBOL; + } + } + + return ZX_BASIC_TOKEN_UNKNOWN; +} + +static inline int basic_print(uint8_t c, int tty, FILE *stream) { + if (ZX81_CHAR_LOW(c)) { + return zx81_fputc(c, 0, stream); + } else if (ZX81_CHAR_TOKEN_LOW(c)) { + return fputs(zx81_basic_tokens_low[c - ZX81_CHAR_TOKEN_LOW_START], stream); + } else if (ZX81_CHAR_NEWLINE(c)) { + return putchar('\n'); + } else if (ZX81_CHAR_INVERSE(c)) { + return zx81_fputc(c - ZX81_CHAR_INVERSE_START, tty, stream); + } else if (ZX81_CHAR_TOKEN_HIGH(c)) { + return fputs(zx81_basic_tokens[c - ZX81_CHAR_TOKEN_HIGH_START], stream); + } + + return 0; +} +ssize_t zx81_basic_dump(int fd, FILE *stream) { + void *buf; + ssize_t total = 0; + int tty = isatty(fileno(stream)); + struct stat st; + + if (fstat(fd, &st) < 0) { + goto error_fstat; + } + + if ((buf = malloc(st.st_blksize)) == NULL) { + goto error_malloc; + } + + if (lseek(fd, ZX_BASIC_STATE_SIZE, SEEK_CUR) < 0) { + goto error_io; + } + + while (1) { + ssize_t readlen, len, i; + zx_basic_line line; + uint8_t last = 0xc0; + + if ((readlen = read(fd, &line, sizeof(line))) < 0) { + goto error_io; + } else if (readlen == 0) { + break; + } + + len = le16toh(line.len); + + if (be16toh(line.num) == len && len == ZX_BASIC_LINE_LAST) { + break; + } + + if (printf("%d ", (int)be16toh(line.num)) < 0) { + goto error_io; + } + + if (read(fd, buf, len) < 0) { + goto error_io; + } + + for (i=0; i + +#include + +uint32_t zx81_charset[ZX81_CHARSET_LEN] = { + 0x0020, 0x2598, 0x259d, 0x2580, 0x2596, 0x258c, 0x259e, 0x259b, + 0x2592, '.', '.', '"', 0x00a3, '$', ':', '?', + '(', ')', '>', '<', '=', '+', '-', '*', + '/', ';', ',', '.', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', +}; + +static inline size_t utf8_encode(uint8_t *buf, uint32_t codepoint) { + if ((codepoint & 0x007f) == codepoint) { + buf[0] = codepoint & 0x007f; + + return 1; + } else if ((codepoint & 0x07ff) == codepoint) { + buf[0] = 0xc0 | ((codepoint & 0x07c0) >> 6); + buf[1] = 0x80 | (codepoint & 0x003f); + + return 2; + } else if ((codepoint & 0xffff) == codepoint) { + buf[0] = 0xe0 | ((codepoint & 0xf000) >> 12); + buf[1] = 0x80 | ((codepoint & 0x0fc0) >> 6); + buf[2] = 0x80 | (codepoint & 0x003f); + + return 3; + } else { + buf[0] = 0xf0 | ((codepoint & 0x1c0000) >> 18); + buf[1] = 0x80 | ((codepoint & 0x03f000) >> 12); + buf[2] = 0x80 | ((codepoint & 0x000fc0) >> 6); + buf[3] = 0x80 | (codepoint & 0x00003f); + + return 4; + } +} + +int zx81_fputc(uint8_t c, int inverse, FILE *stream) { + uint8_t sequence[4]; + size_t len = utf8_encode(sequence, zx81_charset[c]); + + if (inverse) { + if (fputs("\033[7m", stream) < 0) { + goto error_io; + } + } + + if (fwrite(sequence, len, 1, stream) < 1) { + goto error_io; + } + + if (inverse) { + if (fputs("\033[27m", stream) < 0) { + goto error_io; + } + } + + return 0; + +error_io: + return -1; +} diff --git a/src/hexdump.c b/src/hexdump.c new file mode 100644 index 0000000..fd7d7ff --- /dev/null +++ b/src/hexdump.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +#include +#include + +static ssize_t hexdump_line(off_t offset, void *buf, size_t len, int tty, FILE *stream) { + size_t i; + + if (printf("%08zx: ", offset) < 0) { + goto error_io; + } + + for (i=0; i 0 && (i % ZX81_HEXDUMP_STRIDE_GROUP) == 0) { + if (fputc(' ', stream) < 0) { + goto error_io; + } + } + + if (fprintf(stream, "%02x", ((uint8_t *)buf)[offset+i]) < 0) { + goto error_io; + } + } + + if (fputs(" ", stream) < 0) { + goto error_io; + } + + for (i=0; i= 0xa0 && c <= 0xbf) { + if (zx81_fputc(c - 0xa0, tty, stream) < 0) { + goto error_io; + } + } else { + if (fputc('.', stream) < 0) { + goto error_io; + } + } + } + + if (fputc('\n', stream) < 0) { + goto error_io; + } + + return fflush(stream); + +error_io: + return -1; +} + +ssize_t zx81_hexdump(int fd, FILE *stream) { + void *buf; + ssize_t total = 0; + int tty = isatty(fileno(stdout)); + struct stat st; + + if (fstat(fd, &st) < 0) { + goto error_fstat; + } + + if ((buf = malloc(st.st_blksize)) == NULL) { + goto error_malloc; + } + + while (1) { + ssize_t len, i; + off_t offset = 0; + + if ((len = read(fd, buf, st.st_blksize)) < 0) { + goto error_read; + } else if (len == 0) { + break; + } + + for (i=0; i +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ZX_DUMP_FLAGS_NONE 0 +#define ZX_DUMP_FLAGS_BASIC (1 << 0) + +static void usage(const char *prog, char *message, ...) { + if (message != NULL) { + va_list args; + + va_start(args, message); + vfprintf(stderr, message, args); + fputc('\n', stderr); + va_end(args); + } + + fprintf(stderr, "usage: %s [-b] [file]\n", prog); + exit(1); +} + +int main(int argc, char **argv) { + int fd, + flags = ZX_DUMP_FLAGS_NONE, + argn; + + while (1) { + int c; + + if ((c = getopt(argc, argv, "b")) < 0) { + break; + } + + switch (c) { + case 'b': + flags |= ZX_DUMP_FLAGS_BASIC; + break; + + case '?': + default: + usage(argv[0], NULL); + } + } + + argn = argc - optind; + + if (argn == 0) { + fd = fileno(stdin); + } else if (argn == 1) { + if ((fd = open(argv[optind], O_RDONLY)) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + + goto error_open; + } + } else { + usage(argv[0], "Too many arguments provided"); + } + + if (flags & ZX_DUMP_FLAGS_BASIC) { + if (zx81_basic_dump(fd, stdout) < 0) { + fprintf(stderr, "%s: %s: %s\n", + argv[0], + (argn == 1)? argv[optind]: "(stdin)", + strerror(errno)); + + goto error_dump; + } + } else { + if (zx81_hexdump(fd, stdout) < 0) { + fprintf(stderr, "%s: %s: %s\n", + argv[0], + (argn == 1)? argv[optind]: "(stdin)", + strerror(errno)); + + goto error_dump; + } + } + + if (argn == 1) { + close(fd); + } + + return 0; + +error_dump: + if (argn == 1) { + close(fd); + } + +error_open: + return 1; +} -- cgit v1.2.3