diff options
| author | B. Watson <urchlay@slackware.uk> | 2024-07-05 04:11:59 -0400 | 
|---|---|---|
| committer | B. Watson <urchlay@slackware.uk> | 2024-07-05 04:11:59 -0400 | 
| commit | f0c8f8555625f60ef85e7f23a7eb36f94a0b7218 (patch) | |
| tree | cd1cd07da22662bd2f8cab5e0b9d94530c0d3f88 | |
| parent | e6095ffbeb4fec2a2d14f70a5c23703cb67fc300 (diff) | |
| download | bw-atari8-tools-f0c8f8555625f60ef85e7f23a7eb36f94a0b7218.tar.gz | |
listbas: do Unicode/magazine internally (no external a8cat); add color syntax highlighting and options related to it.
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | listbas.1 | 62 | ||||
| -rw-r--r-- | listbas.c | 187 | ||||
| -rw-r--r-- | listbas.rst | 60 | 
4 files changed, 254 insertions, 59 deletions
| @@ -61,8 +61,8 @@ 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 @@ -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,16 +39,16 @@ 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\-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 @@ -56,9 +56,12 @@ Include the immediate mode command (line 32768) in the output.  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\-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. +.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.  .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) @@ -11,28 +11,41 @@  #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; + +const char **table = ata2utf;  FILE *outfh;  void print_help(void) { -	printf("Usage: %s [-v] [-i] [-a|-u] <inputfile>\n", self); +	printf("Usage: %s [-v] [-i] [-n] [-a|-m] <inputfile>\n", self);  	printf("  -v: verbose.\n");  	printf("  -i: show immediate mode command (line 32768).\n");  	printf("  -a: output raw ATASCII.\n");  	printf("  -m: magazine style listing (see a8cat(1)).\n"); +	printf("  -n: disable color syntax highlighting.\n"); +	printf("  -b: use bold for color output.\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 +60,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 +98,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 +199,12 @@ CALLBACK(print_cmd) {  	if(tok == CMD_ILET) return; +	if(color) color_on(C_YELLOW);  	if(tok > last_command || (!(name = commands[tok])))  		fprintf(outfh, "(bad cmd token $%02x) ", tok);  	else  		fprintf(outfh, "%s ", name); +	if(color) color_off();  }  CALLBACK(print_op) { @@ -150,36 +222,72 @@ CALLBACK(print_op) {  		default: break;  	} +	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  		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 +315,6 @@ int main(int argc, char **argv) {  	setup_outfh();  	list(); -	close_outfh();  	return 0;  } diff --git a/listbas.rst b/listbas.rst index d6d17b1..d7f5d26 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,6 +29,10 @@ OPTIONS  List options  ------------ +**-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. @@ -40,12 +40,51 @@ List options    Output raw ATASCII; no translation to the host character set. Must be    used with redirection; **listbas** will not write ATASCII to the terminal. +**-n** +  No color. Has no effect if **-a** or **-m** are in effect, since these +  modes don't support color anyway. +  **-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.  .. 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) | 
