diff options
-rw-r--r-- | .gitignore | 19 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | README.txt | 4 | ||||
-rw-r--r-- | a8cat.1 | 1 | ||||
-rw-r--r-- | a8eol.1 | 1 | ||||
-rw-r--r-- | a8xd.1 | 1 | ||||
-rw-r--r-- | atascii.7 | 1 | ||||
-rw-r--r-- | atr2xfd.1 | 1 | ||||
-rw-r--r-- | atrsize.1 | 1 | ||||
-rw-r--r-- | axe.1 | 1 | ||||
-rw-r--r-- | bas.c | 18 | ||||
-rw-r--r-- | blob2c.1 | 1 | ||||
-rw-r--r-- | blob2xex.1 | 1 | ||||
-rw-r--r-- | cart2xex.1 | 1 | ||||
-rw-r--r-- | cxrefbas.1 | 1 | ||||
-rw-r--r-- | dasm2atasm.1 | 1 | ||||
-rw-r--r-- | dumpbas.1 | 1 | ||||
-rw-r--r-- | fenders.1 | 1 | ||||
-rw-r--r-- | listbas.1 | 88 | ||||
-rw-r--r-- | listbas.c | 209 | ||||
-rw-r--r-- | listbas.rst | 77 | ||||
-rw-r--r-- | protbas.1 | 1 | ||||
-rw-r--r-- | renumbas.1 | 1 | ||||
-rw-r--r-- | rom2cart.1 | 1 | ||||
-rw-r--r-- | unmac65.1 | 1 | ||||
-rw-r--r-- | unprotbas.1 | 1 | ||||
-rw-r--r-- | vxrefbas.1 | 1 | ||||
-rw-r--r-- | whichbas.c | 417 | ||||
-rw-r--r-- | whichbas.rst | 84 | ||||
-rw-r--r-- | xex.5 | 1 | ||||
-rw-r--r-- | xex1to2.1 | 1 | ||||
-rw-r--r-- | xexamine.1 | 1 | ||||
-rw-r--r-- | xexcat.1 | 1 | ||||
-rw-r--r-- | xexsplit.1 | 1 | ||||
-rw-r--r-- | xfd2atr.1 | 1 |
35 files changed, 878 insertions, 84 deletions
@@ -1,11 +1,15 @@ *.bas *.BAS +*.LST +*.XEX *.car *.cart *.rom *.swp *.syms +*.a8s 1 +1.* 2 3 *.atr @@ -44,3 +48,18 @@ ksiders/atrextr ksiders/makeatr ksiders/sortatr ksiders/unmakatr +jindroush/acvt/acvt +jindroush/acvt/switches.cpp +jindroush/adir/adir +jindroush/adir/switches.cpp +jindroush/aext/aext +jindroush/aext/switches.cpp +jindroush/bas2boot/bas2boot +jindroush/bas2boot/switches.cpp +jindroush/chkbas/chkbas +jindroush/chkbas/switches.cpp +jindroush/chkexe/chkexe +jindroush/chkexe/switches.cpp +jindroush/chkrom/chkrom +jindroush/chkrom/switches.cpp +jindroush/lib/libjindroush.a @@ -16,9 +16,9 @@ CC=gcc CFLAGS=-Wall $(COPT) -ansi -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" # BINS and SCRIPTS go in $BINDIR, DOCS go in $DOCDIR -BINS=a8eol atr2xfd atrsize axe blob2c blob2xex cart2xex cxrefbas dumpbas fenders protbas renumbas rom2cart unmac65 unprotbas vxrefbas xex1to2 xexamine xexcat xexsplit xfd2atr listbas a8cat a8xd +BINS=a8eol atr2xfd atrsize axe blob2c blob2xex cart2xex cxrefbas dumpbas fenders protbas renumbas rom2cart unmac65 unprotbas vxrefbas xex1to2 xexamine xexcat xexsplit xfd2atr listbas a8cat a8xd whichbas SCRIPTS=dasm2atasm -MANS=a8eol.1 xfd2atr.1 atr2xfd.1 blob2c.1 cart2xex.1 fenders.1 xexsplit.1 xexcat.1 atrsize.1 rom2cart.1 unmac65.1 axe.1 dasm2atasm.1 blob2xex.1 xexamine.1 xex1to2.1 unprotbas.1 protbas.1 renumbas.1 dumpbas.1 vxrefbas.1 cxrefbas.1 listbas.1 a8cat.1 a8xd.1 +MANS=a8eol.1 xfd2atr.1 atr2xfd.1 blob2c.1 cart2xex.1 fenders.1 xexsplit.1 xexcat.1 atrsize.1 rom2cart.1 unmac65.1 axe.1 dasm2atasm.1 blob2xex.1 xexamine.1 xex1to2.1 unprotbas.1 protbas.1 renumbas.1 dumpbas.1 vxrefbas.1 cxrefbas.1 listbas.1 a8cat.1 a8xd.1 whichbas.1 MAN5S=xex.5 MAN7S=atascii.7 DOCS=README.txt equates.inc *.dasm LICENSE ksiders/atr.txt @@ -57,12 +57,14 @@ renumbas: bas.o bcdfp.o linetab.o dumpbas: bas.o +whichbas: bas.o + vxrefbas: bas.o cxrefbas: bas.o bcdfp.o linetab.o -listbas: listbas.c bas.o bcdfp.o tokens.o - $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o -lm +listbas: listbas.c bas.o bcdfp.o tokens.o atables.o + $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o -lm bas.o: bas.c bas.h @@ -227,3 +229,13 @@ install-subdirs: subdirs for dir in $(SUBDIRS); do \ make -C $$dir DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) BINDIR=$(BINDIR) MAN1DIR=$(MAN1DIR) GZIP_MAN=$(GZIP_MAN) DOCDIR=$(DOCDIR) install; \ done + +user-symlinks: all + SRC=$$( pwd ) ; \ + mkdir -p ~/bin ; \ + cd ~/bin ; \ + for i in $(BINS) \ + ksiders/atrdir ksiders/atrextr ksiders/makeatr ksiders/sortatr ksiders/unmakatr \ + jindroush/chkrom/chkrom jindroush/chkbas/chkbas jindroush/bas2boot/bas2boot \ + jindroush/chkexe/chkexe jindroush/adir/adir jindroush/acvt/acvt jindroush/aext/aext \ + ; do rm -f $$i; ln -s $$SRC/$$i . ; done @@ -63,8 +63,8 @@ xexsplit - Split a multi-segment Atari 8-bit executable (XEX) into xfd2atr - Convert an Atari 8-bit XFD (raw) disk image to an ATR image. -All are written in C, except a8utf8 and dasm2atasm which are written -in Perl. All utilities have man pages. +All are written in C, except dasm2atasm which is written in Perl. All +utilities have man pages. Also included is "equates.inc", a 6502 assembly header file that defines the Atari 8-bit system equates. It's meant to be used with either the @@ -158,6 +158,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -482,6 +482,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -253,6 +253,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -2171,6 +2171,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -202,6 +202,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -216,6 +216,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -157,6 +157,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -171,15 +171,19 @@ int vntable_ok(void) { /* first pass: bad = 1 if all the bytes in the table have the same value, no matter what it is. */ vp = vnstart + 1; - bad = 1; - while(vp < vvstart - 1) { - if(program[vp] != program[vnstart]) { - bad = 0; - break; + + /* don't do this check if the table is only one byte long! */ + if(vp < vvstart - 1) { + bad = 1; + while(vp < vvstart - 1) { + if(program[vp] != program[vnstart]) { + bad = 0; + break; + } + vp++; } - vp++; + if(bad) return 0; } - if(bad) return 0; /* 2nd pass: bad = 1 if there's any invalid character in the table. */ vp = vnstart; @@ -137,6 +137,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -228,6 +228,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -246,6 +246,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -175,6 +175,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), diff --git a/dasm2atasm.1 b/dasm2atasm.1 index b853071..18f0100 100644 --- a/dasm2atasm.1 +++ b/dasm2atasm.1 @@ -244,6 +244,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -225,6 +225,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -291,6 +291,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "LISTBAS" 1 "2024-07-02" "0.2.1" "Urchlay's Atari 8-bit Tools" +.TH "LISTBAS" 1 "2024-07-05" "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 @@ -39,26 +39,29 @@ listbas [\fB\-v\fP] [\fB\-i\fP] [\fB\-a\fP | \fB\-m\fP ] \fBinput\-file\fP tokenized (SAVEd) BASIC program and prints the code in human\-readable format. .sp -By default, output is piped through \fBa8cat\fP(1), to covert ATASCII -characters into Unicode equivalents. Raw ATASCII and "magazine listing" -mode are also available. -.sp -\fBa8cat\fP is run as an external processe. The executables is searched -for first in the current directory, and then in \fIPATH\fP\&. +By default, output is Unicode in UTF\-8 encoding, with ANSI/VT220 +escape sequences for inverse video and color syntax highlighting. .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\-b\fP +Use bold, for color output. This may make it easier to read on +some terminals. Or, it may hurt your eyes... +.TP +.B \fB\-i\fP +Include the immediate mode command (line 32768) in the output. +.TP .B \fB\-m\fP -Output "magazine listing". Pipes output through \fBa8cat \-m\fP; see the man -page for \fBa8cat\fP for details. +Output "magazine listing". See the \fB\-m\fP option for \fBa8cat\fP for details. +.TP +.B \fB\-n\fP +No color. Has no effect if \fB\-a\fP or \fB\-m\fP are in effect, since these +modes don\(aqt support color anyway. .UNINDENT .SS General Options .INDENT 0.0 @@ -73,6 +76,42 @@ Print version number and exit. 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 COLORS +.sp +Color output only works on terminal emulators (or real terminals) +that support ANSI/VT220 style escape codes. This includes all modern +terminal emulators, and most not\-so\-modern ones in the UNIX world. +.sp +The color scheme is: +.INDENT 0.0 +.TP +.B \fByellow\fP +Commands. Also "command operators" such as the \fBGOTO\fP in \fBON/GOTO\fP and +the \fBSTEP\fP in a \fBFOR\fP command. These are really operators as far as +BASIC is concerned, but it makes more sense to colorize them as commands. +.TP +.B \fBgreen\fP +Operators (except functions and "command operators"). +.TP +.B \fBpurple\fP +Functions. +.TP +.B \fBred\fP +Numbers (except line numbers at the start of a line) and string +constants. +.TP +.B \fBcyan\fP +Line numbers at the start of a line, comments (\fBREM\fP text) and \fBDATA\fP elements. +.UNINDENT +.sp +Variable names and commas between \fBDATA\fP elements are not highlighted, +so they\(aqll appear in the default foreground color (usually white if the +terminal has a black background, or black if the background is white). +.sp +Note that nothing is highlighted in blue. This is because it\(aqs +difficult to read on many terminals. Also, black and white are not +used because presumably, one or the other is the background color of +the terminal. .SH NOTES .sp \fBlistbas\fP will refuse to operate on a LIST\-protected program with @@ -83,6 +122,11 @@ protection. \fBlistbas\fP is similar to Jindroush\(aqs \fBchkbas\fP(1). The main differences are: .INDENT 0.0 .IP \(bu 2 +\fBlistbas\fP prints ATASCII graphics as Unicode equivalents, so the listing +looks very similar to how it would appear on the Atari. +.IP \(bu 2 +\fBlistbas\fP does color syntax highlighting. +.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(1) @@ -101,9 +145,26 @@ specifically asked to do so. \fBlistbas\fP tells you if the program is protected, and refuses to operate on variable\-protected programs. .UNINDENT +.sp +I thought about adding an HTML output option, but there\(aqs no need: if you want +a colorful listing of an Atari BASIC program, install \fBaha\fP(1) from +\fI\%https://github.com/theZiz/aha\fP (or your distro\(aqs package repo) and run +something like: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +listbas PROGRAM.BAS | aha > program.html +.ft P +.fi +.UNINDENT +.UNINDENT .SH EXIT STATUS .sp -0 for success, 1 for failure. +0 for success, 1 if there was an error reading the input (e.g. file +not found), or 2 if the input file has invalid tokens (if this +happens, you will also see a warning about it on stderr). .SH COPYRIGHT .sp WTFPL. See \fI\%http://www.wtfpl.net/txt/copying/\fP for details. @@ -135,6 +196,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -11,28 +11,42 @@ #include "bas.h" #include "bcdfp.h" #include "tokens.h" +#include "atables.h" -int immediate = 0, a8cat = 1, magazine = 0; +#define C_RED 1 +#define C_GREEN 2 +#define C_YELLOW 3 +#define C_PURPLE 5 +#define C_CYAN 6 + +int immediate = 0, utf8 = 1, magazine = 0, inv = 0, + color = 1, bold = 0, badtok = 0; + +const char **table = ata2utf; FILE *outfh; void print_help(void) { - printf("Usage: %s [-v] [-i] [-a|-u] <inputfile>\n", self); - printf(" -v: verbose.\n"); - printf(" -i: show immediate mode command (line 32768).\n"); + printf("Usage: %s [-a] [-b] [-i] [-m] [-n] [-v] <inputfile>\n", self); printf(" -a: output raw ATASCII.\n"); + printf(" -b: use bold for color output.\n"); + printf(" -i: show immediate mode command (line 32768).\n"); printf(" -m: magazine style listing (see a8cat(1)).\n"); + printf(" -n: disable color syntax highlighting.\n"); + printf(" -v: verbose.\n"); } void parse_args(int argc, char **argv) { int opt; - while( (opt = getopt(argc, argv, "viamh")) != -1) { + while( (opt = getopt(argc, argv, "viamnbh")) != -1) { switch(opt) { case 'v': verbose = 1; break; case 'i': immediate = 1; break; - case 'a': a8cat = magazine = 0; break; - case 'm': a8cat = magazine = 1; break; + case 'a': utf8 = magazine = 0; color = 0; break; + case 'm': utf8 = 0 ; magazine = 1; color = 0; table = ata2mag; break; + case 'n': color = 0; break; + case 'b': bold = 1; break; case 'h': print_help(); exit(0); default: print_help(); @@ -47,38 +61,13 @@ void parse_args(int argc, char **argv) { } 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(a8cat) { - if(magazine) - cmd = "./a8cat -m 2>/dev/null || a8cat -m 2>/dev/null || exit 1"; - else - cmd = "./a8cat 2>/dev/null || a8cat 2>/dev/null || exit 1"; - } else { + if(! (utf8 || magazine) ) { 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(a8cat) { - if(pclose(outfh)) { - die("output filter failed; a8cat not in current dir or $PATH."); - } } + outfh = stdout; + return; } void outchr(char c) { @@ -110,18 +99,100 @@ double bcd2double(const unsigned char *num) { return result; } +void color_on(unsigned char c) { + printf("\x1b[%d;3%dm", bold, c); +} + +void color_off(void) { + fputs("\x1b[0m", outfh); +} + void print_number(unsigned int pos) { + if(color) color_on(C_RED); fprintf(outfh, "%G", bcd2double(program + pos)); + if(color) color_off(); +} + +/* only called in magazine mode. cursor control characters + like a bell in the middle of a non-inverse string + should not cause it to print {inv}{bell}{norm}. The {bell} + is "inherently" inverse (since its high bit is set) but doesn't + need to be printed that way. */ +int affects_inv(unsigned char c) { + switch(c) { + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + case 0x7d: + case 0x7e: + case 0x7f: + case 0xfd: + case 0xfe: + case 0xff: + return 0; + default: + return 1; + } +} + +void start_inv(unsigned char c) { + if(utf8) { + fputs("\x1b[7m", outfh); + inv = 1; + } else if(magazine) { + if(affects_inv(c)) { + fputs("{inv}", outfh); + inv = 1; + } + } +} + +void end_inv(unsigned char c) { + if(utf8) { + fputs("\x1b[0m", outfh); + inv = 0; + } else if(magazine) { + if(affects_inv(c)) { + fputs("{norm}", outfh); + inv = 0; + } + } +} + +void print_ata_chr(unsigned char c) { + if(c & 0x80) { + if(!inv) { + start_inv(c); + } + } else { + if(inv) { + end_inv(c); + } + } + fputs(table[c & 0x7f], outfh); } void print_string(unsigned int pos, unsigned int len) { + inv = 0; + if(color) color_on(C_RED); outchr('"'); - while(len--) outchr(program[pos++]); + while(len--) print_ata_chr(program[pos++]); + if(inv) end_inv(0); outchr('"'); + if(color) color_off(); } CALLBACK(print_lineno) { + if(color) color_on(C_CYAN); fprintf(outfh, "%d ", lineno); + if(color) color_off(); } CALLBACK(print_cmd) { @@ -129,10 +200,14 @@ CALLBACK(print_cmd) { if(tok == CMD_ILET) return; - if(tok > last_command || (!(name = commands[tok]))) + if(color) color_on(C_YELLOW); + if(tok > last_command || (!(name = commands[tok]))) { fprintf(outfh, "(bad cmd token $%02x) ", tok); - else + badtok = 1; + } else { fprintf(outfh, "%s ", name); + } + if(color) color_off(); } CALLBACK(print_op) { @@ -150,36 +225,74 @@ CALLBACK(print_op) { default: break; } - if(tok > last_operator || (!(name = operators[tok]))) + if(color) { + if(tok > 0x3c) + color_on(C_PURPLE); + else if(tok == OP_UMINUS) + color_on(C_RED); /* show leading - in same color as the number */ + else if((tok >= 0x17 && tok <= 0x1b) || (tok >= 0x28 && tok <= 0x2a)) + color_on(C_YELLOW); + else + color_on(C_GREEN); + } + if(tok > last_operator || (!(name = operators[tok]))) { fprintf(outfh, "(bad op token $%02x)", tok); - else + badtok = 1; + } else { fprintf(outfh, "%s", name); + } + if(color) color_off(); } CALLBACK(print_varname) { int i, count; - unsigned char c; + unsigned char c, c_on = 0;; tok &= 0x7f; for(i = vnstart, count = 0; count < tok; i++) { if(program[i] & 0x80) count++; } do { - outchr( (c = program[i++]) & 0x7f); + c = program[i++]; + if(color && c == ('(' | 0x80)) { + color_on(C_GREEN); + c_on = 1; + } + outchr(c & 0x7f); } while (c < 0x80); + if(c_on) color_off(); } CALLBACK(print_text) { - while(program[pos] != 0x9b) outchr(program[pos++]); + unsigned char c, is_data = program[pos - 1] == CMD_DATA, comma = 0; + + inv = 0; + if(color) color_on(C_CYAN); + while(program[pos] != 0x9b) { + c = program[pos++]; + if(color && is_data && c == ',') { + color_off(); + comma = 1; + } else { + comma = 0; + } + print_ata_chr(c); + if(comma) + color_on(C_CYAN); + } + if(inv) end_inv(0); + if(color) color_off(); } CALLBACK(print_newline) { - outchr(0x9b); + if(utf8 || magazine) + outchr('\n'); + else + outchr(0x9b); } CALLBACK(code_prot) { fprintf(stderr, "%s: Program is code-protected, stopping at line %d.\n", self, lineno); - close_outfh(); exit(0); } @@ -207,7 +320,11 @@ int main(int argc, char **argv) { setup_outfh(); list(); - close_outfh(); + + if(badtok) { + fprintf(stderr, "%s: program has unknown tokens; maybe Turbo BASIC or BASIC XL/XE?\n", self); + return 2; + } return 0; } diff --git a/listbas.rst b/listbas.rst index d6d17b1..881da5f 100644 --- a/listbas.rst +++ b/listbas.rst @@ -20,12 +20,8 @@ DESCRIPTION tokenized (SAVEd) BASIC program and prints the code in human-readable format. -By default, output is piped through **a8cat**\(1), to covert ATASCII -characters into Unicode equivalents. Raw ATASCII and "magazine listing" -mode are also available. - -**a8cat** is run as an external processe. The executables is searched -for first in the current directory, and then in *PATH*. +By default, output is Unicode in UTF-8 encoding, with ANSI/VT220 +escape sequences for inverse video and color syntax highlighting. OPTIONS ======= @@ -33,19 +29,62 @@ 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. +**-b** + Use bold, for color output. This may make it easier to read on + some terminals. Or, it may hurt your eyes... + +**-i** + Include the immediate mode command (line 32768) in the output. + **-m** - Output "magazine listing". Pipes output through **a8cat -m**; see the man - page for **a8cat** for details. + Output "magazine listing". See the **-m** option for **a8cat** for details. + +**-n** + No color. Has no effect if **-a** or **-m** are in effect, since these + modes don't support color anyway. .. include:: genopts.rst +COLORS +====== + +Color output only works on terminal emulators (or real terminals) +that support ANSI/VT220 style escape codes. This includes all modern +terminal emulators, and most not-so-modern ones in the UNIX world. + +The color scheme is: + +**yellow** + Commands. Also "command operators" such as the **GOTO** in **ON/GOTO** and + the **STEP** in a **FOR** command. These are really operators as far as + BASIC is concerned, but it makes more sense to colorize them as commands. + +**green** + Operators (except functions and "command operators"). + +**purple** + Functions. + +**red** + Numbers (except line numbers at the start of a line) and string + constants. + +**cyan** + Line numbers at the start of a line, comments (**REM** text) and **DATA** elements. + +Variable names and commas between **DATA** elements are not highlighted, +so they'll appear in the default foreground color (usually white if the +terminal has a black background, or black if the background is white). + +Note that nothing is highlighted in blue. This is because it's +difficult to read on many terminals. Also, black and white are not +used because presumably, one or the other is the background color of +the terminal. + NOTES ===== @@ -56,6 +95,11 @@ protection. **listbas** is similar to Jindroush's **chkbas**\(1). The main differences are: +- **listbas** prints ATASCII graphics as Unicode equivalents, so the listing + looks very similar to how it would appear on the Atari. + +- **listbas** does color syntax highlighting. + - **listbas** only supports Atari BASIC, not Turbo BASIC or BASIC XL/XE. - **listbas** doesn't show information about the variables. Use **vxrefbas**\(1) @@ -74,9 +118,18 @@ protection. - **listbas** tells you if the program is protected, and refuses to operate on variable-protected programs. +I thought about adding an HTML output option, but there's no need: if you want +a colorful listing of an Atari BASIC program, install **aha**\(1) from +https://github.com/theZiz/aha (or your distro's package repo) and run +something like:: + + listbas PROGRAM.BAS | aha > program.html + EXIT STATUS =========== -0 for success, 1 for failure. +0 for success, 1 if there was an error reading the input (e.g. file +not found), or 2 if the input file has invalid tokens (if this +happens, you will also see a warning about it on stderr). .. include:: manftr.rst @@ -132,6 +132,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -194,6 +194,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -260,6 +260,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -392,6 +392,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), diff --git a/unprotbas.1 b/unprotbas.1 index e4372a0..c521116 100644 --- a/unprotbas.1 +++ b/unprotbas.1 @@ -359,6 +359,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -135,6 +135,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), diff --git a/whichbas.c b/whichbas.c new file mode 100644 index 0000000..dabf414 --- /dev/null +++ b/whichbas.c @@ -0,0 +1,417 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include "bas.h" + +#define BT_ATARI 1 +#define BT_TURBO 2 +#define BT_BXL 4 +#define BT_BXE 8 + +#define BT_BXL_BXE (BT_BXL | BT_BXE) + +int bas_type = 0x0f; /* start out with all enabled */ + +int comma_count; /* count of regular commas (not string/array) in statement */ +unsigned char last_cmd; +unsigned short last_cmd_pos; + +int keep_going = 0; /* -k flag */ + +void print_help(void) { + printf("Usage: %s [-v] [-k] <inputfile>\n", self); +} + +void parse_args(int argc, char **argv) { + int opt; + + while( (opt = getopt(argc, argv, "vk")) != -1) { + switch(opt) { + case 'v': verbose = 1; break; + case 'k': keep_going = verbose = 1; break; + default: + print_help(); + exit(1); + } + } + + if(optind >= argc) + die("No input file given (and stdin not supported)."); + else + open_input(argv[optind]); + if(input_file == stdin) + die("Reading from standard input not supported."); +} + +/* don't need this. +void add_type(int type) { + bas_type |= type; +} +*/ + +void print_result(void) { + const char *name; + + if(bas_type & BT_ATARI) { + name = "Atari BASIC"; + } else if(bas_type == BT_BXL || bas_type == (BT_BXL | BT_BXE)) { + name = "OSS BASIC XL"; + } else if(bas_type == BT_BXE) { + name = "OSS BASIC XE"; + } else if(bas_type == BT_TURBO) { + name = "Turbo BASIC XL"; + } else { + name = "Not Atari BASIC; probably either Turbo or BXL/BXE"; + } + + fputs(name, stdout); + putchar('\n'); + + exit(bas_type == BT_ATARI ? 0 : bas_type + 8); +} + +void remove_type(int type) { + bas_type &= ((~type) & 0x0f); + + if(keep_going) return; + + /* without -k, stop if it gets narrowed down to one of these two. */ + if(bas_type == BT_TURBO || bas_type == BT_BXE) + print_result(); +} + +CALLBACK(handle_cmd) { + int has_args = 0; + unsigned char nexttok; + + last_cmd = tok; + last_cmd_pos = pos; + comma_count = 0; + + if(verbose) fprintf(stderr, "handle_cmd: lineno %d, tok $%02x, bas_type was %02x\n", lineno, tok, bas_type); + + if(tok <= CMD_ERROR) return; /* legal in BASIC, ignore */ + remove_type(BT_ATARI); + if(tok >= 0x5b) remove_type(BT_BXL); + + nexttok = program[pos + 1]; + has_args = !(nexttok == OP_EOS || nexttok == OP_EOL); + + /* we have tokens 0x3a to 0x68 in both TB and BXE, or 47 + of them. + Some tokens can't be determined, because they take the + same argument (or lack of) in both Turbo and BXL/XE. These + are: + 0x3c: REPEAT or ELSE (no args either way) + 0x42: Maybe: BPUT or RGET (take the same args... but not quite!) + 0x43: Maybe: BGET or BPUT (take the same args... but not quite!) + 0x46: LOOP or CP (no args either way) + 0x49: LOCK or UNPROTECT (take the same args) + 0x4B: RENAME in both Turbo and BXL/XE (take the same args) + 0x60: CLS or HITCLR (no args either way) + This leaves 40 we can check. + Covered so far: 34 (85%) + TODO: Unknown tokens: + 0x54: ??? in TB (find out what), LVAR in BXL/BXE. + 0x5A: BLOAD or... what? (Jindroush lists it as ?5A?) + TODO: + 0x5B: BRUN or CALL (both take a string, CALL allows "USING" though) + 0x5C: GO# (1 arg only) or SORTUP (optional 2nd arg of USING, but no comma) + 0x5D: # (1 arg only) or SORTDOWN (optional 2nd arg of USING, but no comma) + 0x5F: PAINT (req 2 args) or NUM (optional 2 args, probly not appear in program) + */ + switch(tok) { + case 0x39: /* MOVE <args> or ENDWHILE */ + case 0x3a: /* -MOVE <args> or TRACEOFF */ + case 0x3d: /* UNTIL <args> or ENDIF */ + case 0x56: /* DEL <args> or FAST */ + case 0x61: /* DSOUND (4 num args) or INVERSE (no args) */ + case 0x62: /* CIRCLE (3 num args) or NORMAL (no args) */ + if(has_args) { + remove_type(BT_BXL_BXE); + } else { + remove_type(BT_TURBO); + } + break; + case 0x58: /* TRACE (optional + or -), EXTEND (BXE; no args) */ + /* EXTEND can't show up in a program except maybe line 32768, e.g. + EXTEND:SAVE "D:BLAH". */ + remove_type(BT_BXL); + if(lineno < 32768) { + remove_type(BT_BXE); + } + break; + case 0x59: /* TEXT (1st arg is number), PROCEDURE (arg is string const (not var!)) */ + if(nexttok == OP_STRCONST) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + case 0x3f: /* WEND or LOMEM <args> */ + case 0x40: /* ELSE or DEL <args> */ + case 0x41: /* ENDIF or RPUT <args> */ + case 0x45: /* DO or TAB <args> */ + case 0x47: /* EXIT or ERASE <args> */ + case 0x51: /* ENDPROC or PMMOVE <args> */ + if(has_args) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + case 0x48: /* DIR (optional arg) or PROTECT (req'd arg) */ + /* not conclusive: without args means TB, but with arg, + it could be either */ + if(!has_args) { + remove_type(BT_BXL_BXE); + } + break; + case 0x4a: /* UNLOCK (req'd arg) or DIR (optional arg) */ + /* not conclusive: without args means TB, but with arg, + it could be either */ + if(!has_args) { + remove_type(BT_TURBO); + } + break; + case 0x3b: /* *F (optional + or -), TRACE (no arg) */ + case 0x5e: /* *B (optional + or -) or EXIT (no arg) */ + if(has_args) { + remove_type(BT_BXL_BXE); + } + break; + case 0x44: /* FILLTO or BGET (check for a # after the token) */ + if(nexttok == OP_HASH) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + case 0x4e: /* TIME$= (1 string arg) or PMCLR (1 num arg) */ + /* XXX: this doesn't do anything if the arg is a variable; we + could examine the type, but we don't yet */ + if(nexttok == OP_STRCONST) { + remove_type(BT_BXL_BXE); + } else if(nexttok == OP_NUMCONST) { + remove_type(BT_TURBO); + } + break; + case 0x50: /* EXEC (1 arg, *must* be variable) or PMGRAPHICS (1 num arg, may be const) */ + if(nexttok < 0x80) { + remove_type(BT_TURBO); + } + break; + case 0x57: /* DUMP (1 optional string arg) or LOCAL (1 variable arg) */ + if(!has_args || (nexttok == OP_STRCONST)) { + /* if there's no arg, or one string constant arg... */ + /* XXX: DUMP A$ not detected */ + remove_type(BT_BXL_BXE); + } + default: break; + } + if(verbose) fprintf(stderr, " bas_type now %02x\n", bas_type); +} + +CALLBACK(handle_op) { + unsigned char nexttok = program[pos + 1]; + unsigned char nexttok2 = program[pos + 2]; + + if(tok == OP_COMMA) comma_count++; + + if(verbose) fprintf(stderr, "handle_op: lineno %d, tok $%02x, comma_count %d, bas_type was %02x\n", lineno, tok, comma_count, bas_type); + + if(tok == 0x0d) remove_type(BT_ATARI); /* hex const (turbo *and* bxl/xe) */ + if(tok <= OP_FUNC_STRIG) { + if(verbose) fprintf(stderr, " bas_type now %02x\n", bas_type); + return; /* legal in BASIC, ignore */ + } + remove_type(BT_ATARI); + + if(tok >= 0x69) { + remove_type(BT_BXL_BXE); + } + + if(tok == 0x55) { + /* DPEEK (function) TB, USING (infix, not a function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) { + remove_type(BT_BXL_BXE); + } + } + + if(tok == 0x5c) { + /* DEC (function, takes str) in TB, HEX$ (function, takes num) in BXL/BXE */ + if(nexttok2 == OP_STRCONST) { + remove_type(BT_BXL_BXE); + } else if(nexttok2 > 0x80 && (get_vartype(nexttok2) == TYPE_STRING)) { + /* TODO: see if this test is actually valid! */ + remove_type(BT_BXL_BXE); + } + } + + if(tok == 0x5f) { + /* TIME$ in TB, SYS (function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) { + remove_type(BT_TURBO); + } + } + + if(tok == 0x60) { + /* TIME in TB, VSTICK (function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) { + remove_type(BT_TURBO); + } + } + + if(tok == 0x61) { + /* MOD (infix op) in TB, HSTICK (function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) + remove_type(BT_TURBO); + } + + if(tok == 0x62) { + /* EXEC (infix op, with ON) in TB, PMADR (function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) + remove_type(BT_TURBO); + } + + if(tok == 0x66 || tok == 0x67 || tok == 0x68) { + /* either %0 %1 %2 (TB), or LEFT$ RIGHT$ MID$ (BXL/XE) */ + if(nexttok == OP_STRCONST || nexttok >= 0x80) { + /* %0 %1 %2 can't be followed by a string constant *or* a variable */ + remove_type(BT_TURBO); + } + } + if(verbose) fprintf(stderr, " bas_type now %02x\n", bas_type); +} + +CALLBACK(handle_end_stmt) { + if(verbose) fprintf(stderr, "handle_end_stmt: lineno %d, tok $%02x, last_cmd $%02x, comma_count %d, bas_type was %02x\n", lineno, tok, last_cmd, comma_count, bas_type); + switch(last_cmd) { + case 0x38: /* DPOKE (2 args) or WHILE (1 arg) */ + if(comma_count) { + remove_type(BT_BXL_BXE); + } else { + remove_type(BT_TURBO); + } + break; + case 0x3e: /* WHILE (1 arg) or DPOKE (2 args) */ + case 0x4c: /* DELETE (1 arg) or MOVE (3 or 4 args) */ + case 0x4d: /* PAUSE (1 arg) or MISSILE (3 args) */ + case 0x52: /* FCOLOR (1 arg) or PMWIDTH (2 args) */ + case 0x53: /* *L (optional + or - only) or SET (req 2 num args) */ + case 0x4f: /* PROC (1 arg) or PMCOLOR (3 args) */ + if(comma_count) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + case 0x55: /* RENUM in both (TB req 3 args, BXL up to two) */ + if(comma_count == 2) { + remove_type(BT_BXL_BXE); + } else { + remove_type(BT_TURBO); + } + break; + case 0x63: /* %PUT (usually seen with optional #; 1 or 2 args) or BLOAD (1 string arg) */ + if(comma_count) { + /* multiple args */ + remove_type(BT_BXL_BXE); + } else if(program[last_cmd + 1] == OP_STRCONST) { + /* one arg, string const. XXX: check var type */ + remove_type(BT_TURBO); + } + break; + case 0x64: /* %GET (usually seen with optional #; 1 or 2 args) or BSAVE (3 args) */ + if(comma_count == 2) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + default: break; + } + if(verbose) fprintf(stderr, " now %02x\n", bas_type); +} + +void foreign(const char *name) { + fclose(input_file); + puts(name); + exit(0); /* TODO: pick a better number */ +} + +void detect_foreign(void) { + int i, nuls, c, d; + + c = fgetc(input_file); + d = fgetc(input_file); + + if(c == 0 && d == 0) { + /* This is why we can't read from stdin. */ + rewind(input_file); + return; + } + + if(c == EOF || d == EOF) + die("File is too short to be a BASIC program of any kind."); + + if(c == 0xff && d == 0xff) + foreign("XEX executable (not BASIC at all!)"); + + if(c == 0xfe && d == 0xfe) + foreign("Mac/65 tokenized source (not BASIC at all!)"); + + if(c == 0xdd && d == 0x00) + foreign("EXTENDed OSS BASIC XE"); + + if(c == 0x7f && d == 'E') { + c = fgetc(input_file); + d = fgetc(input_file); + if(c == 'L' && d == 'F') + foreign("ELF executable (huh?)"); + } + + if(!(c == 0 && d == 0)) { + if(fseek(input_file, -3, SEEK_END) == 0) { + nuls = 0; + for(i = 0; i < 3; i++) { + if(fgetc(input_file) == 0) nuls++; + } + if(nuls == 3) { + foreign("Microsoft BASIC"); + } + } + } + + if(isdigit(c) && (d == 0x20 || isdigit(d))) + foreign("Text file, could be LISTed BASIC (or not)"); + + if(isprint(c) && isprint(d)) + foreign("Text file (not BASIC at all!)"); + + foreign("Unknown file type (not BASIC at all!)"); +} + +int main(int argc, char **argv) { + set_self(*argv); + parse_general_args(argc, argv, print_help); + parse_args(argc, argv); + + detect_foreign(); + + readfile(); + parse_header(); + + on_cmd_token = handle_cmd; + on_exp_token = handle_op; + on_end_stmt = handle_end_stmt; + + walk_all_code(); + + print_result(); /* always exits */ + return 0; /* never happens, shuts up gcc's warning though */ +} diff --git a/whichbas.rst b/whichbas.rst new file mode 100644 index 0000000..3eb8854 --- /dev/null +++ b/whichbas.rst @@ -0,0 +1,84 @@ +======== +whichbas +======== + +---------------------------------------------------------- +Determine BASIC variant of a tokenized Atari 8-bit program +---------------------------------------------------------- + +.. include:: manhdr.rst + +SYNOPSIS +======== +whichbas [-v] *input-file* + +DESCRIPTION +=========== +**whichbas** reads a tokenized Atari 8-bit BASIC, Turbo BASIC, +BASIC XL, BASIC XE, or Atari Microsoft BASIC program and attempts to +discover which BASIC is required to run it. + +OPTIONS +======= + +Detection Options +----------------- + +**-k** + Keep going. The default is to stop looking at the program if the + BASIC type gets narrowed down to either Turbo BASIC XL or BASIC XE. + This option also enables **-v** (verbose). It's really only useful + for testing, if you're hacking on **whichbas** itself. + +.. include:: genopts.rst + +NOTES +===== +Turbo BASIC, BASIC XL, and BASIC XE are all supersets of Atari BASIC. +If you wrote a program using one of them, but didn't use any of the +extra commands or functions, the result is still an Atari BASIC program. + +There are two types of BASIC XE programs: regular and *EXTEND*\ed. The +extended type is detected 100% reliably, because the first byte of the +file changes from **$00** to **$DD**. Non-extended programs are only +identified as BASIC XE if they use any of the extra commands BASIC XE +adds to those found in BASIC XL. + +Atari BASIC programs can be detected 100% reliably. + +Detection of Turbo vs. BXL/BXE isn't 100% reliable, and probably +never will be. There's too much overlap between the sets of extra +tokens added by each. Programs that don't use very many of the extra +functions provided by Turbo/BXL/BXE may show up as "Not Atari BASIC; +probably either Turbo or BXL/BXE". + +Atari Microsoft BASIC is detected by checking that the first two +bytes of the file are not zero, and that the last 3 are zero. This +may result in false positives (files that aren't BASIC programs at +all might show up as Microsoft). Also, no distinction is made between +Atari MS BASIC 1.0 and 2.0. + +Various non-BASIC files are detected (including Mac/65 source, +ELF binaries, etc) as a convenience, but I wouldn't rely on +**whichbas**\'s non-BASIC file type detection if I were you. + +LIMITATIONS +=========== +Currently, **whichbas** doesn't look at the variable name or type +tables. One problem caused by this: If a program uses only Atari BASIC +tokens, but uses variable(s) with _ in the name, it will be identified +as Atari BASIC... even though _ in variable names is illegal in Atari +BASIC and pretty much guarantees the program is Turbo/BXL/BXE. + +Looking at the variable types could also improve detection, since +Turbo and BXL/BXE support extended variable types. + +**whichbas** knows nothing about other BASICs such as Frost BASIC, +BASIC/A+, Altirra BASIC... + +EXIT STATUS +=========== + +0 for success, 1 for failure. + +.. include:: manftr.rst @@ -319,6 +319,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -93,6 +93,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -151,6 +151,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -211,6 +211,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -204,6 +204,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), @@ -132,6 +132,7 @@ Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\ \fBunmac65\fP(1), \fBunprotbas\fP(1), \fBvxrefbas\fP(1), +\fBxex1to2\fP(1), \fBxexamine\fP(1), \fBxexcat\fP(1), \fBxexsplit\fP(1), |