Refactor stuff into separate files, finally
This commit is contained in:
parent
4451e2f2ef
commit
b89c79b5a8
10 changed files with 556 additions and 495 deletions
25
Makefile
25
Makefile
|
@ -1,23 +1,8 @@
|
||||||
CC = cc
|
all:
|
||||||
CFLAGS = -g -Wall -O2
|
$(MAKE) -C src all
|
||||||
LDFLAGS =
|
|
||||||
OBJS = main.o
|
|
||||||
NAME = zxdump
|
|
||||||
|
|
||||||
PREFIX = /usr/local
|
install:
|
||||||
INSTALL = /usr/bin/install
|
$(MAKE) -C src 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
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) -f $(NAME) $(OBJS)
|
$(MAKE) -C src clean
|
||||||
|
|
35
include/zx/basic.h
Normal file
35
include/zx/basic.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef _ZX_BASIC_H
|
||||||
|
#define _ZX_BASIC_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#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 */
|
40
include/zx/charset.h
Normal file
40
include/zx/charset.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef _ZX_CHARSET_H
|
||||||
|
#define _ZX_CHARSET_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#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 */
|
12
include/zx/hexdump.h
Normal file
12
include/zx/hexdump.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef _ZX81_HEXDUMP_H
|
||||||
|
#define _ZX81_HEXDUMP_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#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 */
|
475
main.c
475
main.c
|
@ -1,475 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <endian.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#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<len; i++) {
|
|
||||||
if (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<len; i++) {
|
|
||||||
uint8_t c = ((uint8_t *)buf)[offset+i];
|
|
||||||
|
|
||||||
if (c <= 0x3f) {
|
|
||||||
if (zx_putchar(c, 0) < 0) {
|
|
||||||
goto error_io;
|
|
||||||
}
|
|
||||||
} else if (c >= 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<len; i+=ZX_HEXDUMP_STRIDE_LINE) {
|
|
||||||
size_t left = len - i,
|
|
||||||
linesz = left < ZX_HEXDUMP_STRIDE_LINE? left: ZX_HEXDUMP_STRIDE_LINE;
|
|
||||||
|
|
||||||
if (hexdump_line(offset, buf, linesz, tty) < 0) {
|
|
||||||
goto error_hexdump_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += linesz;
|
|
||||||
total += linesz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return total;
|
|
||||||
|
|
||||||
error_hexdump_line:
|
|
||||||
error_read:
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
error_malloc:
|
|
||||||
error_fstat:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int zx_print(uint8_t c, int tty) {
|
|
||||||
if (ZX_CHAR_LOW(c)) {
|
|
||||||
return zx_putchar(c, 0);
|
|
||||||
} else if (ZX_CHAR_TOKEN_LOW(c)) {
|
|
||||||
return fputs(zx_tokens_low[c - ZX_CHAR_TOKEN_LOW_START], stdout);
|
|
||||||
} else if (ZX_CHAR_NEWLINE(c)) {
|
|
||||||
return putchar('\n');
|
|
||||||
} else if (ZX_CHAR_INVERSE(c)) {
|
|
||||||
return zx_putchar(c - ZX_CHAR_INVERSE_START, tty);
|
|
||||||
} else if (ZX_CHAR_TOKEN_HIGH(c)) {
|
|
||||||
return fputs(zx_tokens[c - ZX_CHAR_TOKEN_HIGH_START], stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum zx_basic_token_type zx_basic_token_type_get(uint8_t b) {
|
|
||||||
if (ZX_CHAR_LOW(b)) {
|
|
||||||
uint32_t codepoint = zx_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 (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<len; i++) {
|
|
||||||
uint8_t c = ((uint8_t *)buf)[i];
|
|
||||||
|
|
||||||
enum zx_basic_token_type type = zx_basic_token_type_get(c),
|
|
||||||
type_last = zx_basic_token_type_get(last);
|
|
||||||
|
|
||||||
int space = 0;
|
|
||||||
|
|
||||||
if (type == ZX_BASIC_TOKEN_ALNUM) {
|
|
||||||
if (type_last == ZX_BASIC_TOKEN_WORD) {
|
|
||||||
space = 1;
|
|
||||||
}
|
|
||||||
} else if (type == ZX_BASIC_TOKEN_QUOTE) {
|
|
||||||
if (type_last == ZX_BASIC_TOKEN_WORD) {
|
|
||||||
space = 1;
|
|
||||||
}
|
|
||||||
} else if (type == ZX_BASIC_TOKEN_SYMBOL) {
|
|
||||||
space = 0;
|
|
||||||
} else if (type == ZX_BASIC_TOKEN_WORD) {
|
|
||||||
if (type_last != ZX_BASIC_TOKEN_SYMBOL) {
|
|
||||||
space = 1;
|
|
||||||
}
|
|
||||||
} else if (ZX_CHAR_TOKEN_INTEGRAL(c) || ZX_CHAR_TOKEN_FLOAT(c)) {
|
|
||||||
i += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (space && putchar(' ') < 0) {
|
|
||||||
goto error_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zx_print(c, tty) < 0) {
|
|
||||||
goto error_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ZX_CHAR_NEWLINE(((uint8_t *)buf)[i-1])) {
|
|
||||||
if (putchar('\n') < 0) {
|
|
||||||
goto error_io;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return total;
|
|
||||||
|
|
||||||
error_io:
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
error_malloc:
|
|
||||||
error_fstat:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ZX_DUMP_FLAGS_NONE 0
|
|
||||||
#define ZX_DUMP_FLAGS_BASIC (1 << 0)
|
|
||||||
|
|
||||||
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 (zx_dump_basic(fd) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0],
|
|
||||||
(argn == 1)? argv[optind]: "(stdin)",
|
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
goto error_dump;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (zx_dump_hex(fd) < 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;
|
|
||||||
}
|
|
27
src/Makefile
Normal file
27
src/Makefile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
CC = cc
|
||||||
|
CFLAGS = -g -Wall -O2
|
||||||
|
LDFLAGS =
|
||||||
|
OBJS = charset.o basic.o hexdump.o main.o
|
||||||
|
NAME = zxdump
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
INSTALL = /usr/bin/install
|
||||||
|
RM = /bin/rm
|
||||||
|
|
||||||
|
INCLUDE_PATH = ../include
|
||||||
|
HEADERS_SUBDIR = zx
|
||||||
|
HEADERS_BUILD = $(addprefix $(INCLUDE_PATH)/$(HEADERS_SUBDIR)/, $(HEADERS))
|
||||||
|
|
||||||
|
all: $(NAME)
|
||||||
|
|
||||||
|
$(NAME): $(OBJS)
|
||||||
|
$(CC) $(OBJS) -o $(NAME) $(LDFLAGS)
|
||||||
|
|
||||||
|
$(OBJS): %.o: %.c $(HEADERS_BUILD)
|
||||||
|
$(CC) $(CFLAGS) -I$(INCLUDE_PATH) -c $<
|
||||||
|
|
||||||
|
install: $(NAME)
|
||||||
|
$(INSTALL) -c -m 0755 $(NAME) $(PREFIX)/bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(NAME) $(OBJS)
|
163
src/basic.c
Normal file
163
src/basic.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <zx/charset.h>
|
||||||
|
#include <zx/basic.h>
|
||||||
|
|
||||||
|
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<len; i++) {
|
||||||
|
uint8_t c = ((uint8_t *)buf)[i];
|
||||||
|
|
||||||
|
enum zx_basic_token_type type = zx_basic_token_type_get(c),
|
||||||
|
type_last = zx_basic_token_type_get(last);
|
||||||
|
|
||||||
|
int space = 0;
|
||||||
|
|
||||||
|
if (type == ZX_BASIC_TOKEN_ALNUM) {
|
||||||
|
if (type_last == ZX_BASIC_TOKEN_WORD) {
|
||||||
|
space = 1;
|
||||||
|
}
|
||||||
|
} else if (type == ZX_BASIC_TOKEN_QUOTE) {
|
||||||
|
if (type_last == ZX_BASIC_TOKEN_WORD) {
|
||||||
|
space = 1;
|
||||||
|
}
|
||||||
|
} else if (type == ZX_BASIC_TOKEN_SYMBOL) {
|
||||||
|
space = 0;
|
||||||
|
} else if (type == ZX_BASIC_TOKEN_WORD) {
|
||||||
|
if (type_last != ZX_BASIC_TOKEN_SYMBOL) {
|
||||||
|
space = 1;
|
||||||
|
}
|
||||||
|
} else if (ZX81_CHAR_TOKEN_INTEGRAL(c) || ZX81_CHAR_TOKEN_FLOAT(c)) {
|
||||||
|
i += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (space && fputc(' ', stream) < 0) {
|
||||||
|
goto error_io;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basic_print(c, tty, stream) < 0) {
|
||||||
|
goto error_io;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ZX81_CHAR_NEWLINE(((uint8_t *)buf)[i-1])) {
|
||||||
|
if (fputc('\n', stream) < 0) {
|
||||||
|
goto error_io;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_malloc:
|
||||||
|
error_fstat:
|
||||||
|
return -1;
|
||||||
|
}
|
66
src/charset.c
Normal file
66
src/charset.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <zx/charset.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
109
src/hexdump.c
Normal file
109
src/hexdump.c
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <zx/charset.h>
|
||||||
|
#include <zx/hexdump.h>
|
||||||
|
|
||||||
|
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<len; i++) {
|
||||||
|
if (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<len; i++) {
|
||||||
|
uint8_t c = ((uint8_t *)buf)[offset+i];
|
||||||
|
|
||||||
|
if (c <= 0x3f) {
|
||||||
|
if (zx81_fputc(c, 0, stream) < 0) {
|
||||||
|
goto error_io;
|
||||||
|
}
|
||||||
|
} else if (c >= 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<len; i+=ZX81_HEXDUMP_STRIDE_LINE) {
|
||||||
|
size_t left = len - i,
|
||||||
|
linesz = left < ZX81_HEXDUMP_STRIDE_LINE? left: ZX81_HEXDUMP_STRIDE_LINE;
|
||||||
|
|
||||||
|
if (hexdump_line(offset, buf, linesz, tty, stream) < 0) {
|
||||||
|
goto error_hexdump_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += linesz;
|
||||||
|
total += linesz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
|
||||||
|
error_hexdump_line:
|
||||||
|
error_read:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_malloc:
|
||||||
|
error_fstat:
|
||||||
|
return -1;
|
||||||
|
}
|
99
src/main.c
Normal file
99
src/main.c
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <zx/hexdump.h>
|
||||||
|
#include <zx/basic.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue