From addd5eab935391075a063ae120e730ed37cf0fac Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Fri, 12 Jul 2024 15:52:55 -0400 Subject: listbas: make colors customizable (-c), add -U and -C options, add LISTBAS_OPTS environment variable. --- listbas.1 | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- listbas.c | 146 ++++++++++++++++++++++++++++++++++++++++---------------- listbas.rst | 142 ++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 365 insertions(+), 79 deletions(-) diff --git a/listbas.1 b/listbas.1 index 97ebb9c..6aa93ca 100644 --- a/listbas.1 +++ b/listbas.1 @@ -48,18 +48,27 @@ The default output mode is Unicode/UTF\-8 representations of ATASCII characters. .INDENT 0.0 .TP +.B \fB\-U\fP +Output Unicode/UTF\-8 representations of ATASCII characters. This is +the default output mode; the \fB\-U\fP option is provided so you can +override \fB\-a\fP, \fB\-d\fP, \fB\-m\fP, \fB\-x\fP in \fBLISTBAS_OPTS\fP (see +\fBENVIRONMENT\fP, below). +.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\-d\fP Print dots rather than Unicode/UTF\-8 characters. Color and inverse -video are still supported in this mode. Use this only if your -terminal \fIreally\fP doesn\(aqt support Unicode (e.g. \fBrxvt\fP(1)). +video are still supported in this mode, but no Unicode/UTF8 characters +are printed. Use this only if your terminal \fIreally\fP doesn\(aqt support +Unicode (e.g. \fBrxvt\fP(1))... but even then, \fB\-m\fP is preferred, +because you can\(aqt tell what the dots are supposed to represent. .TP .B \fB\-m\fP -Output "magazine listing". See the \fB\-m\fP option for \fBa8cat\fP for details. -Color is supported in this mode, +Output "magazine listing". See the \fB\-m\fP option for \fBa8cat\fP(1) for details. +Color is supported in this mode. No Unicode/UTF\-8 characters are printed in +this mode. .TP .B \fB\-x\fP Output Unicode/UTF\-8 representations of the XL International Character @@ -68,20 +77,31 @@ Set, rather than ATASCII. .SS Other 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 +.B \fB\-C\fP +Enable color syntax highlighting. This option is enabled by default; +the \fB\-C\fP option is provided so you can override \fB\-n\fP in +\fBLISTBAS_OPTS\fP (see \fBENVIRONMENT\fP, below). +.TP .B \fB\-n\fP No color. Has no effect if \fB\-a\fP is in effect, since this mode doesn\(aqt support color anyway. Disabling color does not disable reverse video. .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\-u\fP Use underlining for inverse video, rather than reverse video output. +.TP +.B \fB\-c\fP \fIcolors\fP +Customize the color scheme. See \fBCOLORS\fP, below, for the format of the +\fIcolors\fP argument. Once you\(aqve found a set of colors you like, +you can place this option in the \fBLISTBAS_OPTS\fP environment variable +to use your colors by default. See \fBENVIRONMENT\fP, below. .UNINDENT .SS General Options .INDENT 0.0 @@ -102,7 +122,11 @@ 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: +The color scheme is adjustable via the \fB\-c\fP option; see +\fBCustomization\fP, below. To avoid having to give your custom colors on +the command line every time, see \fBENVIRONMENT\fP, below. +.sp +The default color scheme is: .INDENT 0.0 .TP .B \fByellow\fP @@ -122,17 +146,88 @@ constants (but not the quotes around the string). .TP .B \fBcyan\fP Line numbers at the start of a line, comments (\fBREM\fP text) and \fBDATA\fP elements. +.TP +.B \fBuncolorized\fP +Variable names. .UNINDENT .sp -Quotes around strings, 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). +Quotes around strings and commas between \fBDATA\fP elements are +never colorized, 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 blue in the default color scheme. 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. +.SS Customization +.sp +You can customize the colors by using the \fB\-c\fP \fIcolors\fP option, either +on the command line, or in the \fBLISTBAS_OPTS\fP environment variable. +\fIcolors\fP is a string of exactly 6 characters, each of which must be the +digits \fI0\fP through \fI7\fP to specify a color, or the letter \fIn\fP to specify +no color. +.sp +The colors are the standard ANSI ones, plus \fIn\fP: +.INDENT 0.0 +.TP +.B \fI0\fP +Black. +.TP +.B \fI1\fP +Red. +.TP +.B \fI2\fP +Green. +.TP +.B \fI3\fP +Yellow (or brown, on some terminals). +.TP +.B \fI4\fP +Blue. +.TP +.B \fI5\fP +Purple (aka violet). +.TP +.B \fI6\fP +Cyan. +.TP +.B \fI7\fP +White. +.TP +.B \fIn\fP +No custom color. Output will be in the terminal\(aqs default foreground color. +.UNINDENT .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. +The order they\(aqre used in the \fIcolors\fP argument is: +.INDENT 0.0 +.TP +.B \fB1\fP +Commands. +.TP +.B \fB2\fP +Operators. +.TP +.B \fB3\fP +Functions. +.TP +.B \fB4\fP +Constants. +.TP +.B \fB5\fP +Line numbers (at the start of a line only; \fBGOTO\fP and \fBGOSUB\fP line numbers +are constants). +.TP +.B \fB6\fP +Variable names. +.UNINDENT +.sp +So, the default color scheme is equivalent to: +.INDENT 0.0 +.INDENT 3.5 +\fB\-c\fP \fI32516n\fP +.UNINDENT +.UNINDENT .SH NOTES .sp \fBlistbas\fP will refuse to operate on a LIST\-protected program with @@ -153,8 +248,8 @@ looks very similar to how it would appear on the Atari. \fBlistbas\fP doesn\(aqt show information about the variables. Use \fBvxrefbas\fP(1) for that. .IP \(bu 2 -\fBlistbas\fP will not write ATASCII data to your terminal. By default, it uses -\fBa8cat\fP(1) to convert the output to something human\-readable +\fBlistbas\fP will not write ATASCII data to your terminal. By default, it +converts ATASCII characters into Unicode/UTF\-8 characters that won\(aqt confuse the terminal. When outputting raw ATASCII (\fB\-a\fP option), it refuses to run if standard output is a terminal. .IP \(bu 2 @@ -181,6 +276,29 @@ listbas PROGRAM.BAS | aha > program.html .fi .UNINDENT .UNINDENT +.SH ENVIRONMENT +.INDENT 0.0 +.TP +.B \fBLISTBAS_OPTS\fP +If this environment variable is set, \fBlistbas\fP parses its value as though +the contents were placed on the command line as options, preceding any actual +option. Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +export LISTBAS_OPTS="\-c123456 \-d" +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +If you place the above line in your shell\(aqs startup script, \fBlistbas\fP will +use your custom color scheme, and will default to the "dots" output mode. If +you then run \fBlistbas\fP the \fB\-c\fP and/or \fB\-x\fP, \fB\-m\fP options, the options +on the command line will override the environment. +.UNINDENT .SH EXIT STATUS .sp 0 for success, 1 if there was an error reading the input (e.g. file diff --git a/listbas.c b/listbas.c index e3b4225..def855d 100644 --- a/listbas.c +++ b/listbas.c @@ -30,12 +30,15 @@ #define MAG_NORM "{norm}" /* colors. don't use blue, it's fugly. */ +#define NO_COLOR -1 #define C_RED 1 #define C_GREEN 2 #define C_YELLOW 3 #define C_PURPLE 5 #define C_CYAN 6 +#define ENV_OPTS "LISTBAS_OPTS" + /* output modes */ #define M_UTF8 0 /* default */ #define M_UTF8_I 1 /* -x */ @@ -50,39 +53,77 @@ int color = 1; /* 0 with -n */ int immediate = 0; /* 1 with -i */ int underline = 0; /* 1 with -u */ +int color_cmd = C_YELLOW; +int color_op = C_GREEN; +int color_func = C_PURPLE; +int color_const = C_RED; +int color_lnum_text = C_CYAN; +int color_varnames = NO_COLOR; + int badtok = 0; /* set to 1 if we find a bad token */ int inv = 0; /* set to 1 when we're printing inverse */ int cur_color = -1; /* -1 = no color */ FILE *outfh; +int parse_color(char c) { + if(c == 'n') + return NO_COLOR; + + if(c >= '0' && c <= '7') + return c - '0'; + + fprintf(stderr, "%s: Invalid color '%c'.\n", self, c); + exit(1); +} + +void parse_color_scheme(const char *arg) { + if(!arg) return; + + if(strlen(arg) != 6) + die("Color scheme must be 6 characters."); + + color_cmd = parse_color(arg[0]); + color_op = parse_color(arg[1]); + color_func = parse_color(arg[2]); + color_const = parse_color(arg[3]); + color_lnum_text = parse_color(arg[4]); + color_varnames = parse_color(arg[5]); +} + void print_help(void) { printf("Usage: %s [-a | -d | -m | -x] [-b] [-i] [-n] [-v] \n", self); + printf(" -U: output ATASCII as Unicode/UTF-8 (this is the default).\n"); printf(" -a: output raw ATASCII.\n"); printf(" -d: use dots instead of Unicode/UTF-8.\n"); printf(" -m: magazine style listing (see a8cat(1)).\n"); printf(" -x: XL international character set (UTF-8).\n"); printf(" -b: use bold for color output.\n"); printf(" -i: show immediate mode command (line 32768).\n"); + printf(" -C: enable color syntax highlighting (this is the default).\n"); printf(" -n: disable color syntax highlighting.\n"); - printf(" -n: use underline for inverse video.\n"); + printf(" -u: use underline for inverse video.\n"); printf(" -v: verbose.\n"); } -void parse_args(int argc, char **argv) { +void parse_args(int argc, char **argv, int from_env) { int opt; - int opt_a = 0, opt_m = 0, opt_d = 0, opt_x = 0; - while( (opt = getopt(argc, argv, "viamnbdhxu")) != -1) { + optind = 1; + + while( (opt = getopt(argc, argv, "UCviamnbdhxuc:")) != -1) { switch(opt) { + case 'U': output_mode = M_UTF8; break; + case 'a': output_mode = M_ATASCII; break; + case 'm': output_mode = M_MAG; break; + case 'd': output_mode = M_DOTS; break; + case 'x': output_mode = M_UTF8_I; break; case 'v': verbose = 1; break; case 'i': immediate = 1; break; - case 'a': opt_a = 1; break; - case 'm': opt_m = 1; break; - case 'd': opt_d = 1; break; - case 'x': opt_x = 1; break; case 'b': bold = 1; break; case 'u': underline = 1; break; + case 'C': color = 1; break; case 'n': color = 0; break; + case 'c': parse_color_scheme(optarg); break; case 'h': print_help(); exit(0); default: print_help(); @@ -90,23 +131,40 @@ void parse_args(int argc, char **argv) { } } - if(opt_a + opt_d + opt_m + opt_x > 1) - die("Only use one of the -a, -d, -m, -x options."); - - if(opt_a) { - output_mode = M_ATASCII; - } else if(opt_d) { - output_mode = M_DOTS; - } else if(opt_m) { - output_mode = M_MAG; - } else if(opt_x) { - output_mode = M_UTF8_I; + if(!from_env) { + if(optind >= argc) + die("No input file given (use - for stdin)."); + else + open_input(argv[optind]); } +} - if(optind >= argc) - die("No input file given (use - for stdin)."); - else - open_input(argv[optind]); +/* make a fake argv and argc */ +void parse_env_args(void) { + int fargc; + char *fargv[10]; + char *env, *p; + + env = getenv(ENV_OPTS); + if(!env) return; + + if(verbose) + fprintf(stderr, "%s: read options from environment: \"%s\"\n.", self, env); + + fargv[0] = (char *)self; + fargv[1] = env; + fargc = 2; + + for(p = env; *p; p++) { + if(*p == ' ' || *p == '\t') { + *p = '\0'; + fargv[fargc++] = p + 1; + } + } + + fargv[fargc] = NULL; + + parse_args(fargc, fargv, 1); } void setup_outfh(void) { @@ -115,8 +173,11 @@ void setup_outfh(void) { die("Refusing to write ATASCII data to the terminal."); } } - /* TODO: reopen in binary mode! */ - outfh = stdout; + outfh = freopen(NULL, "wb", stdout); + if(!outfh) { + perror("freopen()"); + die("Can't reopen standard output in binary mode."); + } return; } @@ -151,7 +212,8 @@ double bcd2double(const unsigned char *num) { void color_on(unsigned char c) { cur_color = c; - printf(COLOR_FMT, bold, c); + if(c != NO_COLOR) + printf(COLOR_FMT, bold, c); } void color_off(void) { @@ -160,7 +222,7 @@ void color_off(void) { } void print_number(unsigned int pos) { - if(color) color_on(C_RED); + if(color) color_on(color_const); fprintf(outfh, "%G", bcd2double(program + pos)); if(color) color_off(); } @@ -274,7 +336,7 @@ void print_ata_chr(unsigned char c) { void print_string(unsigned int pos, unsigned int len) { inv = 0; outchr('"'); - if(color) color_on(C_RED); + if(color) color_on(color_const); while(len--) print_ata_chr(program[pos++]); if(inv) { end_inv(0); @@ -284,7 +346,7 @@ void print_string(unsigned int pos, unsigned int len) { } CALLBACK(print_lineno) { - if(color) color_on(C_CYAN); + if(color) color_on(color_lnum_text); fprintf(outfh, "%d ", lineno); if(color) color_off(); } @@ -294,7 +356,7 @@ CALLBACK(print_cmd) { if(tok == CMD_ILET) return; - if(color) color_on(C_YELLOW); + if(color) color_on(color_cmd); if(tok > last_command || (!(name = commands[tok]))) { fprintf(outfh, "(bad cmd token $%02x) ", tok); badtok = 1; @@ -321,13 +383,13 @@ CALLBACK(print_op) { if(color) { if(tok > 0x3c) - color_on(C_PURPLE); + color_on(color_func); else if(tok == OP_UMINUS) - color_on(C_RED); /* show leading - in same color as the number */ + color_on(color_const); /* show leading - in same color as the number */ else if((tok >= 0x17 && tok <= 0x1b) || (tok >= 0x28 && tok <= 0x2a)) - color_on(C_YELLOW); + color_on(color_cmd); else - color_on(C_GREEN); + color_on(color_op); } if(tok > last_operator || (!(name = operators[tok]))) { fprintf(outfh, "(bad op token $%02x)", tok); @@ -340,7 +402,9 @@ CALLBACK(print_op) { CALLBACK(print_varname) { int i, count; - unsigned char c, c_on = 0;; + unsigned char c; + + if(color) color_on(color_varnames); tok &= 0x7f; for(i = vnstart, count = 0; count < tok; i++) { @@ -349,19 +413,18 @@ CALLBACK(print_varname) { do { c = program[i++]; if(color && c == ('(' | 0x80)) { - color_on(C_GREEN); - c_on = 1; + if(color) color_on(color_op); } outchr(c & 0x7f); } while (c < 0x80); - if(c_on) color_off(); + if(color) color_off(); } CALLBACK(print_text) { unsigned char c, is_data = program[pos - 1] == CMD_DATA, comma = 0; inv = 0; - if(color) color_on(C_CYAN); + if(color) color_on(color_lnum_text); while(program[pos] != 0x9b) { c = program[pos++]; if(color && is_data && c == ',') { @@ -372,7 +435,7 @@ CALLBACK(print_text) { } print_ata_chr(c); if(comma) - color_on(C_CYAN); + color_on(color_lnum_text); } if(inv) end_inv(0); if(color) color_off(); @@ -404,7 +467,8 @@ void list(void) { int main(int argc, char **argv) { set_self(*argv); parse_general_args(argc, argv, print_help); - parse_args(argc, argv); + parse_env_args(); + parse_args(argc, argv, 0); readfile(); parse_header(); diff --git a/listbas.rst b/listbas.rst index 8321ab1..b3e4ca7 100644 --- a/listbas.rst +++ b/listbas.rst @@ -32,18 +32,27 @@ Output modes The default output mode is Unicode/UTF-8 representations of ATASCII characters. +**-U** + Output Unicode/UTF-8 representations of ATASCII characters. This is + the default output mode; the **-U** option is provided so you can + override **-a**, **-d**, **-m**, **-x** in **LISTBAS_OPTS** (see + **ENVIRONMENT**, below). + **-a** Output raw ATASCII; no translation to the host character set. Must be used with redirection; **listbas** will not write ATASCII to the terminal. **-d** Print dots rather than Unicode/UTF-8 characters. Color and inverse - video are still supported in this mode. Use this only if your - terminal *really* doesn't support Unicode (e.g. **rxvt**\(1)). + video are still supported in this mode, but no Unicode/UTF8 characters + are printed. Use this only if your terminal *really* doesn't support + Unicode (e.g. **rxvt**\(1))... but even then, **-m** is preferred, + because you can't tell what the dots are supposed to represent. **-m** - Output "magazine listing". See the **-m** option for **a8cat** for details. - Color is supported in this mode, + Output "magazine listing". See the **-m** option for **a8cat**\(1) for details. + Color is supported in this mode. No Unicode/UTF-8 characters are printed in + this mode. **-x** Output Unicode/UTF-8 representations of the XL International Character @@ -52,21 +61,32 @@ characters. Other 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. +**-C** + Enable color syntax highlighting. This option is enabled by default; + the **-C** option is provided so you can override **-n** in + **LISTBAS_OPTS** (see **ENVIRONMENT**, below). + **-n** No color. Has no effect if **-a** is in effect, since this mode doesn't support color anyway. Disabling color does not disable reverse video. +**-b** + Use bold for color output. This may make it easier to read on + some terminals. Or, it may hurt your eyes... + **-u** Use underlining for inverse video, rather than reverse video output. +**-c** *colors* + Customize the color scheme. See **COLORS**, below, for the format of the + *colors* argument. Once you've found a set of colors you like, + you can place this option in the **LISTBAS_OPTS** environment variable + to use your colors by default. See **ENVIRONMENT**, below. + .. include:: genopts.rst COLORS @@ -76,7 +96,11 @@ 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: +The color scheme is adjustable via the **-c** option; see +**Customization**, below. To avoid having to give your custom colors on +the command line every time, see **ENVIRONMENT**, below. + +The default color scheme is: **yellow** Commands. Also "command operators" such as the **GOTO** in **ON/GOTO** and @@ -96,15 +120,80 @@ The color scheme is: **cyan** Line numbers at the start of a line, comments (**REM** text) and **DATA** elements. -Quotes around strings, 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). +**uncolorized** + Variable names. + +Quotes around strings and commas between **DATA** elements are +never colorized, 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 blue in the default color scheme. 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. + +Customization +------------- +You can customize the colors by using the **-c** *colors* option, either +on the command line, or in the **LISTBAS_OPTS** environment variable. +*colors* is a string of exactly 6 characters, each of which must be the +digits *0* through *7* to specify a color, or the letter *n* to specify +no color. + +The colors are the standard ANSI ones, plus *n*: + +*0* + Black. + +*1* + Red. + +*2* + Green. -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. +*3* + Yellow (or brown, on some terminals). + +*4* + Blue. + +*5* + Purple (aka violet). + +*6* + Cyan. + +*7* + White. + +*n* + No custom color. Output will be in the terminal's default foreground color. + +The order they're used in the *colors* argument is: + +**1** + Commands. + +**2** + Operators. + +**3** + Functions. + +**4** + Constants. + +**5** + Line numbers (at the start of a line only; **GOTO** and **GOSUB** line numbers + are constants). + +**6** + Variable names. + +So, the default color scheme is equivalent to: + + **-c** *32516n* NOTES ===== @@ -126,8 +215,8 @@ protection. - **listbas** doesn't show information about the variables. Use **vxrefbas**\(1) for that. -- **listbas** will not write ATASCII data to your terminal. By default, it uses - **a8cat**\(1) to convert the output to something human-readable +- **listbas** will not write ATASCII data to your terminal. By default, it + converts ATASCII characters into Unicode/UTF-8 characters that won't confuse the terminal. When outputting raw ATASCII (**-a** option), it refuses to run if standard output is a terminal. @@ -146,6 +235,21 @@ something like:: listbas PROGRAM.BAS | aha > program.html +ENVIRONMENT +=========== + +**LISTBAS_OPTS** + If this environment variable is set, **listbas** parses its value as though + the contents were placed on the command line as options, preceding any actual + option. Example:: + + export LISTBAS_OPTS="-c123456 -d" + + If you place the above line in your shell's startup script, **listbas** will + use your custom color scheme, and will default to the "dots" output mode. If + you then run **listbas** the **-c** and/or **-x**, **-m** options, the options + on the command line will override the environment. + EXIT STATUS =========== -- cgit v1.2.3