aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-06-25 18:49:54 -0400
committerB. Watson <urchlay@slackware.uk>2024-06-25 18:49:54 -0400
commit9a128303b403eacac3db0351fceade7a0e7c5897 (patch)
tree6c1f8e93655bd2338d6f442f419df3443383c2a7
parent5dfa26d8e5bd1d4b30eaecd6dee51cfee2f03c9d (diff)
downloadbw-atari8-tools-9a128303b403eacac3db0351fceade7a0e7c5897.tar.gz
listbas: pipe through a8eol or a8utf8; do not write ATASCII to terminal; add docs.
-rw-r--r--listbas.1132
-rw-r--r--listbas.c83
-rw-r--r--listbas.rst68
3 files changed, 267 insertions, 16 deletions
diff --git a/listbas.1 b/listbas.1
new file mode 100644
index 0000000..888df21
--- /dev/null
+++ b/listbas.1
@@ -0,0 +1,132 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "LISTBAS" 1 "2024-06-25" "0.2.1" "Urchlay's Atari 8-bit Tools"
+.SH NAME
+listbas \- List the source of a tokenized Atari 8-bit BASIC program
+.SH SYNOPSIS
+.sp
+listbas [\fB\-v\fP] [\fB\-i\fP] \fBinput\-file\fP
+.SH DESCRIPTION
+.sp
+\fBlistbas\fP acts like the \fILIST\fP command in BASIC. It reads a
+tokenized (SAVEd) BASIC program and prints the code in human\-readable
+format.
+.sp
+By default, output is piped through \fBa8eol\fP(1), to convert ATASCII
+characters to human\-readable sequences. Raw ATASCII and Unicode output
+are also available.
+.SH OPTIONS
+.SS List options
+.INDENT 0.0
+.TP
+.B \fB\-i\fP
+Include the immediate mode command (line 32768) in the output.
+.TP
+.B \fB\-a\fP
+Output raw ATASCII; no translation to the host character set. Must be
+used with redirection; \fBlistbas\fP will not write ATASCII to the terminal.
+.TP
+.B \fB\-u\fP
+Use \fBa8utf8\fP(1) to translate ATASCII to ASCII. Requires \fBa8utf8\fP
+somewhere in \fIPATH\fP\&.
+.UNINDENT
+.SS General Options
+.INDENT 0.0
+.TP
+.B \fB\-\-help\fP
+Print usage message and exit.
+.TP
+.B \fB\-\-version\fP
+Print version number and exit.
+.TP
+.B \fB\-v\fP
+Verbose operation. When displaying a number in verbose mode, it will
+be prefixed with \fI$\fP if it\(aqs in hex, or no prefix for decimal.
+.UNINDENT
+.SH NOTES
+.sp
+\fBlistbas\fP is similar to Jindroush\(aqs \fBchkbas\fP\&. The main differences are:
+.INDENT 0.0
+.IP \(bu 2
+\fBlistbas\fP only supports Atari BASIC, not Turbo BASIC or BASIC XL/XE.
+.IP \(bu 2
+\fBlistbas\fP doesn\(aqt show information about the variables. Use \fBvxrefbas\fP
+for that.
+.IP \(bu 2
+\fBlistbas\fP will not write ATASCII data to your terminal. Instead, it uses
+\fBa8eol\fP or \fBa8utf8\fP to convert the output to something human\-readable
+that won\(aqt confuse the terminal.
+.IP \(bu 2
+\fBlistbas\fP only includes line 32768 (the immediate mode command) if
+specifically asked to do so.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+0 for success, 1 for failure.
+.SH COPYRIGHT
+.sp
+WTFPL. See \fI\%http://www.wtfpl.net/txt/copying/\fP for details.
+.SH AUTHOR
+.INDENT 0.0
+.IP B. 3
+Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\&.
+.UNINDENT
+.SH SEE ALSO
+.sp
+\fBa8eol\fP(1),
+\fBa8utf8\fP(1),
+\fBatr2xfd\fP(1),
+\fBatrsize\fP(1),
+\fBaxe\fP(1),
+\fBblob2c\fP(1),
+\fBblob2xex\fP(1),
+\fBcart2xex\fP(1),
+\fBcxrefbas\fP(1),
+\fBdasm2atasm\fP(1),
+\fBdumpbas\fP(1),
+\fBf2toxex\fP(1),
+\fBfenders\fP(1),
+\fBprotbas\fP(1),
+\fBrenumbas\fP(1),
+\fBrom2cart\fP(1),
+\fBunmac65\fP(1),
+\fBunprotbas\fP(1),
+\fBvxrefbas\fP(1),
+\fBxexamine\fP(1),
+\fBxexcat\fP(1),
+\fBxexsplit\fP(1),
+\fBxfd2atr\fP(1),
+\fBxex\fP(5),
+\fBatascii\fP(7).
+.sp
+Any good Atari 8\-bit book: \fIDe Re Atari\fP, \fIThe Atari BASIC Reference
+Manual\fP, the \fIOS Users\(aq Guide\fP, \fIMapping the Atari\fP, etc.
+.\" Generated by docutils manpage writer.
+.
diff --git a/listbas.c b/listbas.c
index 6469009..86bb3f7 100644
--- a/listbas.c
+++ b/listbas.c
@@ -4,25 +4,35 @@
#include <string.h>
#include <ctype.h>
#include <time.h>
+
#include <math.h>
+#include <errno.h>
#include "bas.h"
#include "bcdfp.h"
#include "tokens.h"
-int immediate = 0;
+int immediate = 0, a8utf8 = 0, a8eol = 1;
+
+FILE *outfh;
void print_help(void) {
- printf("Usage: %s [-v] [-i] <inputfile>\n", self);
+ printf("Usage: %s [-v] [-i] [-a|-u] <inputfile>\n", self);
+ printf(" -v: verbose.\n");
+ printf(" -i: show immediate mode command (line 32768).\n");
+ printf(" -a: output raw ATASCII.\n");
+ printf(" -u: output Unicode.\n");
}
void parse_args(int argc, char **argv) {
int opt;
- while( (opt = getopt(argc, argv, "vi")) != -1) {
+ while( (opt = getopt(argc, argv, "viau")) != -1) {
switch(opt) {
case 'v': verbose = 1; break;
case 'i': immediate = 1; break;
+ case 'a': a8utf8 = a8eol = 0; break;
+ case 'u': a8utf8 = 1; a8eol = 0; break;
default:
print_help();
exit(1);
@@ -35,6 +45,11 @@ void parse_args(int argc, char **argv) {
open_input(argv[optind]);
}
+void outchr(char c) {
+ putc(c, outfh);
+}
+
+/* this should probably be moved to bcdfp.c */
double bcd2double(const unsigned char *num) {
double result = 0, sign;
int exp, i;
@@ -60,17 +75,17 @@ double bcd2double(const unsigned char *num) {
}
void print_number(unsigned int pos) {
- printf("%G", bcd2double(program + pos));
+ fprintf(outfh, "%G", bcd2double(program + pos));
}
void print_string(unsigned int pos, unsigned int len) {
- putchar('"');
- while(len--) putchar(program[pos++]);
- putchar('"');
+ outchr('"');
+ while(len--) outchr(program[pos++]);
+ outchr('"');
}
CALLBACK(print_lineno) {
- printf("%d ", lineno);
+ fprintf(outfh, "%d ", lineno);
}
CALLBACK(print_cmd) {
@@ -88,9 +103,9 @@ CALLBACK(print_cmd) {
}
if(bad)
- printf("(bad cmd token $%02x)", tok);
+ fprintf(outfh, "(bad cmd token $%02x)", tok);
else
- printf("%s ", name);
+ fprintf(outfh, "%s ", name);
}
CALLBACK(print_op) {
@@ -119,9 +134,9 @@ CALLBACK(print_op) {
}
if(bad)
- printf("(bad op token $%02x)", tok);
+ fprintf(outfh, "(bad op token $%02x)", tok);
else
- printf("%s", name);
+ fprintf(outfh, "%s", name);
}
CALLBACK(print_varname) {
@@ -134,17 +149,51 @@ CALLBACK(print_varname) {
}
while(1) {
c = program[i++];
- putchar(c & 0x7f);
+ outchr(c & 0x7f);
if(c & 0x80) break;
}
}
CALLBACK(print_text) {
- while(program[pos] != 0x9b) putchar(program[pos++]);
+ while(program[pos] != 0x9b) outchr(program[pos++]);
}
CALLBACK(print_newline) {
- putchar('\n');
+ outchr(0x9b);
+}
+
+void setup_outfh(void) {
+ const char *cmd;
+
+ /* search current dir before PATH. no easy way to detect errors here,
+ have to wait until we call pclose(). */
+ if(a8eol) {
+ cmd = "./a8eol -u -c 2>/dev/null || a8eol -u -c 2>/dev/null || exit 1";
+ } else if(a8utf8) {
+ cmd = "./a8utf8 2>/dev/null || a8utf8 2>/dev/null || exit 1";
+ } else {
+ if(isatty(fileno(stdout))) {
+ die("Refusing to write ATASCII data to the terminal.");
+ }
+ outfh = stdout;
+ return;
+ }
+
+ outfh = popen(cmd, "w");
+ if(!outfh) {
+ /* fork() or pipe() failed. does NOT detect if the command
+ wasn't found. */
+ perror(self);
+ exit(1);
+ }
+}
+
+void close_outfh(void) {
+ if(a8eol || a8utf8) {
+ if(pclose(outfh)) {
+ die("output filter failed; a8eol or a8utf8 not in current dir or $PATH.");
+ }
+ }
}
void list(void) {
@@ -165,7 +214,9 @@ int main(int argc, char **argv) {
readfile();
parse_header();
+ setup_outfh();
list();
-
+ close_outfh();
+
return 0;
}
diff --git a/listbas.rst b/listbas.rst
new file mode 100644
index 0000000..8c672a2
--- /dev/null
+++ b/listbas.rst
@@ -0,0 +1,68 @@
+=======
+listbas
+=======
+
+--------------------------------------------------------
+List the source of a tokenized Atari 8-bit BASIC program
+--------------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+listbas [**-v**] [**-i**] **input-file**
+
+DESCRIPTION
+===========
+
+**listbas** acts like the *LIST* command in BASIC. It reads a
+tokenized (SAVEd) BASIC program and prints the code in human-readable
+format.
+
+By default, output is piped through **a8eol**\(1), to convert ATASCII
+characters to human-readable sequences. Raw ATASCII and Unicode output
+are also available.
+
+OPTIONS
+=======
+
+List options
+------------
+
+**-i**
+ Include the immediate mode command (line 32768) in the output.
+
+**-a**
+ Output raw ATASCII; no translation to the host character set. Must be
+ used with redirection; **listbas** will not write ATASCII to the terminal.
+
+**-u**
+ Use **a8utf8**\(1) to translate ATASCII to ASCII. Requires **a8utf8**
+ somewhere in *PATH*.
+
+.. include:: genopts.rst
+
+NOTES
+=====
+
+**listbas** is similar to Jindroush's **chkbas**. The main differences are:
+
+- **listbas** only supports Atari BASIC, not Turbo BASIC or BASIC XL/XE.
+
+- **listbas** doesn't show information about the variables. Use **vxrefbas**
+ for that.
+
+- **listbas** will not write ATASCII data to your terminal. Instead, it uses
+ **a8eol** or **a8utf8** to convert the output to something human-readable
+ that won't confuse the terminal.
+
+- **listbas** only includes line 32768 (the immediate mode command) if
+ specifically asked to do so.
+
+EXIT STATUS
+===========
+
+0 for success, 1 for failure.
+
+.. include:: manftr.rst