From: Ari Johnson Date: Fri, 13 Dec 2024 15:23:56 +0000 (-0500) Subject: Implement xterm/256-color palette for ansi() X-Git-Url: https://git.theari.com/?a=commitdiff_plain;h=9406504f73f1643c3257f5625cfc03c3d11cb82f;p=cobramush.git Implement xterm/256-color palette for ansi() --- diff --git a/hdrs/dbdefs.h b/hdrs/dbdefs.h index 80d338a..1c80338 100644 --- a/hdrs/dbdefs.h +++ b/hdrs/dbdefs.h @@ -115,6 +115,7 @@ extern dbref first_free; /* pointer to free list */ #define Gagged(x) (IS(Owner(x), TYPE_PLAYER, "GAGGED")) #define ShowAnsi(x) (IS(Owner(x), TYPE_PLAYER, "ANSI")) #define ShowAnsiColor(x) (IS(Owner(x), TYPE_PLAYER, "COLOR")) +#define ShowXtermColor(x) (IS(Owner(x), TYPE_PLAYER, "XTERMCOLOR")) #define InProg(x) (IS(x, TYPE_PLAYER, "INPROGRAM")) /******* Thing toggles */ diff --git a/hdrs/game.h b/hdrs/game.h index 6dbf852..b99bf9b 100644 --- a/hdrs/game.h +++ b/hdrs/game.h @@ -21,6 +21,7 @@ extern void init_flagspaces(void); /* flags.c */ extern void init_flag_table(const char *ns); /* flags.c */ extern void init_tag_hashtab(void); /* funstr.c */ extern void init_pronouns(void); /* funstr.c */ +extern void init_xterm_colors(void); /* funstr.c */ /* From bsd.c */ extern void fcache_init(void); diff --git a/src/flags.c b/src/flags.c index 3612882..4a8650a 100644 --- a/src/flags.c +++ b/src/flags.c @@ -106,6 +106,7 @@ FLAG flag_table[] = { {"VERBOSE", 'v', NOTYPE, VERBOSE, F_ANY, F_ANY}, {"ANSI", 'A', TYPE_PLAYER, PLAYER_ANSI, F_ANY, F_ANY}, {"COLOR", 'C', TYPE_PLAYER, PLAYER_COLOR, F_ANY, F_ANY}, + {"XTERMCOLOR", '\0', TYPE_PLAYER, 0, F_ANY, F_ANY}, {"MONITOR", 'M', TYPE_PLAYER | TYPE_ROOM | TYPE_THING | TYPE_DIVISION, 0, F_ANY, F_ANY}, {"NOSPOOF", '"', TYPE_PLAYER, PLAYER_NOSPOOF, F_ANY | F_ODARK, F_ANY | F_ODARK}, diff --git a/src/funstr.c b/src/funstr.c index e34db22..6037eb4 100644 --- a/src/funstr.c +++ b/src/funstr.c @@ -37,6 +37,281 @@ #define LC_MESSAGES 6 #endif +struct colormap { + char *name; + int i_xterm; + int i_ansi_fg; + int i_ansi_bg; +}; + +/* This array maps color names to both the 8-bit 'xterm' color number and the + * nearest 4-bit ANSI color. Color names are case-insensitive. Nonstandard + * names for colors can be added at the end of the array. */ +static struct colormap xterm_colors[] = { + { "Black", 0, 0, 0 }, + { "Maroon", 1, 1, 1 }, + { "Green", 2, 2, 2 }, + { "Olive", 3, 3, 3 }, + { "Navy", 4, 4, 4 }, + { "Purple", 5, 5, 5 }, + { "Teal", 6, 6, 6 }, + { "Silver", 7, 7, 7 }, + { "Grey", 8, 8, 3 }, + { "Red", 9, 9, 1 }, + { "Lime", 10, 10, 2 }, + { "Yellow", 11, 11, 3 }, + { "Blue", 12, 4, 4 }, + { "Fuchsia", 13, 13, 5 }, + { "Aqua", 14, 14, 6 }, + { "White", 15, 15, 7 }, + { "Grey0", 16, 0, 0 }, + { "NavyBlue", 17, 0, 0 }, + { "DarkBlue", 18, 4, 4 }, + { "Blue3", 19, 4, 4 }, + { "Blue3", 20, 4, 4 }, + { "Blue1", 21, 4, 4 }, + { "DarkGreen", 22, 0, 0 }, + { "DeepSkyBlue4", 23, 0, 0 }, + { "DeepSkyBlue4", 24, 6, 6 }, + { "DeepSkyBlue4", 25, 4, 4 }, + { "DodgerBlue3", 26, 4, 4 }, + { "DodgerBlue2", 27, 12, 4 }, + { "Green4", 28, 2, 2 }, + { "SpringGreen4", 29, 2, 2 }, + { "Turquoise4", 30, 6, 6 }, + { "DeepSkyBlue3", 31, 6, 6 }, + { "DeepSkyBlue3", 32, 6, 6 }, + { "DodgerBlue1", 33, 6, 6 }, + { "Green3", 34, 2, 2 }, + { "SpringGreen3", 35, 2, 2 }, + { "DarkCyan", 36, 6, 6 }, + { "LightSeaGreen", 37, 6, 6 }, + { "DeepSkyBlue2", 38, 6, 6 }, + { "DeepSkyBlue1", 39, 6, 6 }, + { "Green3", 40, 2, 2 }, + { "SpringGreen3", 41, 2, 2 }, + { "SpringGreen2", 42, 6, 6 }, + { "Cyan3", 43, 6, 6 }, + { "DarkTurquoise", 44, 6, 6 }, + { "Turquoise2", 45, 14, 6 }, + { "Green1", 46, 10, 2 }, + { "SpringGreen2", 47, 10, 2 }, + { "SpringGreen1", 48, 6, 6 }, + { "MediumSpringGreen", 49, 6, 6 }, + { "Cyan2", 50, 14, 6 }, + { "Cyan1", 51, 14, 6 }, + { "DarkRed", 52, 0, 0 }, + { "DeepPink4", 53, 0, 0 }, + { "Purple4", 54, 5, 5 }, + { "Purple4", 55, 4, 4 }, + { "Purple3", 56, 4, 4 }, + { "BlueViolet", 57, 12, 4 }, + { "Orange4", 58, 0, 0 }, + { "Grey37", 59, 8, 0 }, + { "MediumPurple4", 60, 8, 5 }, + { "SlateBlue3", 61, 8, 4 }, + { "SlateBlue3", 62, 12, 4 }, + { "RoyalBlue1", 63, 12, 4 }, + { "Chartreuse4", 64, 2, 2 }, + { "DarkSeaGreen4", 65, 8, 2 }, + { "PaleTurquoise4", 66, 8, 6 }, + { "SteelBlue", 67, 8, 6 }, + { "SteelBlue3", 68, 12, 6 }, + { "CornflowerBlue", 69, 12, 6 }, + { "Chartreuse3", 70, 2, 2 }, + { "DarkSeaGreen4", 71, 8, 2 }, + { "CadetBlue", 72, 8, 6 }, + { "CadetBlue", 73, 8, 6 }, + { "SkyBlue3", 74, 12, 6 }, + { "SteelBlue1", 75, 12, 6 }, + { "Chartreuse3", 76, 2, 2 }, + { "PaleGreen3", 77, 8, 2 }, + { "SeaGreen3", 78, 8, 6 }, + { "Aquamarine3", 79, 6, 6 }, + { "MediumTurquoise", 80, 6, 6 }, + { "SteelBlue1", 81, 14, 6 }, + { "Chartreuse2", 82, 10, 2 }, + { "SeaGreen2", 83, 10, 2 }, + { "SeaGreen1", 84, 6, 6 }, + { "SeaGreen1", 85, 6, 6 }, + { "Aquamarine1", 86, 14, 6 }, + { "DarkSlateGray2", 87, 14, 6 }, + { "DarkRed", 88, 1, 1 }, + { "DeepPink4", 89, 1, 1 }, + { "DarkMagenta", 90, 5, 5 }, + { "DarkMagenta", 91, 5, 5 }, + { "DarkViolet", 92, 5, 5 }, + { "Purple", 93, 5, 5 }, + { "Orange4", 94, 1, 1 }, + { "LightPink4", 95, 8, 1 }, + { "Plum4", 96, 8, 5 }, + { "MediumPurple3", 97, 8, 5 }, + { "MediumPurple3", 98, 12, 5 }, + { "SlateBlue1", 99, 12, 5 }, + { "Yellow4", 100, 3, 3 }, + { "Wheat4", 101, 8, 3 }, + { "Grey53", 102, 8, 7 }, + { "LightSlateGrey", 103, 8, 7 }, + { "MediumPurple", 104, 12, 7 }, + { "LightSlateBlue", 105, 12, 7 }, + { "Yellow4", 106, 3, 3 }, + { "DarkOliveGreen3", 107, 8, 3 }, + { "DarkSeaGreen", 108, 8, 7 }, + { "LightSkyBlue3", 109, 8, 7 }, + { "LightSkyBlue3", 110, 8, 7 }, + { "SkyBlue2", 111, 12, 7 }, + { "Chartreuse2", 112, 3, 3 }, + { "DarkOliveGreen3", 113, 8, 3 }, + { "PaleGreen3", 114, 8, 7 }, + { "DarkSeaGreen3", 115, 8, 7 }, + { "DarkSlateGray3", 116, 7, 7 }, + { "SkyBlue1", 117, 7, 7 }, + { "Chartreuse1", 118, 3, 3 }, + { "LightGreen", 119, 3, 3 }, + { "LightGreen", 120, 8, 7 }, + { "PaleGreen1", 121, 7, 7 }, + { "Aquamarine1", 122, 7, 7 }, + { "DarkSlateGray1", 123, 7, 7 }, + { "Red3", 124, 1, 1 }, + { "DeepPink4", 125, 1, 1 }, + { "MediumVioletRed", 126, 5, 5 }, + { "Magenta3", 127, 5, 5 }, + { "DarkViolet", 128, 5, 5 }, + { "Purple", 129, 5, 5 }, + { "DarkOrange3", 130, 1, 1 }, + { "IndianRed", 131, 8, 1 }, + { "HotPink3", 132, 8, 5 }, + { "MediumOrchid3", 133, 8, 5 }, + { "MediumOrchid", 134, 12, 5 }, + { "MediumPurple2", 135, 12, 5 }, + { "DarkGoldenrod", 136, 3, 3 }, + { "LightSalmon3", 137, 8, 3 }, + { "RosyBrown", 138, 8, 7 }, + { "Grey63", 139, 8, 7 }, + { "MediumPurple2", 140, 8, 7 }, + { "MediumPurple1", 141, 12, 7 }, + { "Gold3", 142, 3, 3 }, + { "DarkKhaki", 143, 8, 3 }, + { "NavajoWhite3", 144, 8, 7 }, + { "Grey69", 145, 8, 7 }, + { "LightSteelBlue3", 146, 7, 7 }, + { "LightSteelBlue", 147, 7, 7 }, + { "Yellow3", 148, 3, 3 }, + { "DarkOliveGreen3", 149, 3, 3 }, + { "DarkSeaGreen3", 150, 8, 7 }, + { "DarkSeaGreen2", 151, 7, 7 }, + { "LightCyan3", 152, 7, 7 }, + { "LightSkyBlue1", 153, 7, 7 }, + { "GreenYellow", 154, 3, 3 }, + { "DarkOliveGreen2", 155, 3, 3 }, + { "PaleGreen1", 156, 7, 7 }, + { "DarkSeaGreen2", 157, 7, 7 }, + { "DarkSeaGreen1", 158, 7, 7 }, + { "PaleTurquoise1", 159, 7, 7 }, + { "Red3", 160, 1, 1 }, + { "DeepPink3", 161, 1, 1 }, + { "DeepPink3", 162, 5, 5 }, + { "Magenta3", 163, 5, 5 }, + { "Magenta3", 164, 5, 5 }, + { "Magenta2", 165, 13, 5 }, + { "DarkOrange3", 166, 1, 1 }, + { "IndianRed", 167, 8, 1 }, + { "HotPink3", 168, 8, 5 }, + { "HotPink2", 169, 5, 5 }, + { "Orchid", 170, 5, 5 }, + { "MediumOrchid1", 171, 13, 5 }, + { "Orange3", 172, 3, 3 }, + { "LightSalmon3", 173, 8, 3 }, + { "LightPink3", 174, 8, 7 }, + { "Pink3", 175, 8, 7 }, + { "Plum3", 176, 7, 7 }, + { "Violet", 177, 7, 7 }, + { "Gold3", 178, 3, 3 }, + { "LightGoldenrod3", 179, 3, 3 }, + { "Tan", 180, 8, 7 }, + { "MistyRose3", 181, 7, 7 }, + { "Thistle3", 182, 7, 7 }, + { "Plum2", 183, 7, 7 }, + { "Yellow3", 184, 3, 3 }, + { "Khaki3", 185, 3, 3 }, + { "LightGoldenrod2", 186, 7, 7 }, + { "LightYellow3", 187, 7, 7 }, + { "Grey84", 188, 7, 7 }, + { "LightSteelBlue1", 189, 7, 7 }, + { "Yellow2", 190, 11, 3 }, + { "DarkOliveGreen1", 191, 11, 3 }, + { "DarkOliveGreen1", 192, 7, 7 }, + { "DarkSeaGreen1", 193, 7, 7 }, + { "Honeydew2", 194, 7, 7 }, + { "LightCyan1", 195, 7, 7 }, + { "Red1", 196, 9, 1 }, + { "DeepPink2", 197, 9, 1 }, + { "DeepPink1", 198, 5, 5 }, + { "DeepPink1", 199, 5, 5 }, + { "Magenta2", 200, 13, 5 }, + { "Magenta1", 201, 13, 5 }, + { "OrangeRed1", 202, 9, 1 }, + { "IndianRed1", 203, 9, 1 }, + { "IndianRed1", 204, 5, 5 }, + { "HotPink", 205, 5, 5 }, + { "HotPink", 206, 13, 5 }, + { "MediumOrchid1", 207, 13, 5 }, + { "DarkOrange", 208, 3, 3 }, + { "Salmon1", 209, 3, 3 }, + { "LightCoral", 210, 8, 7 }, + { "PaleVioletRed1", 211, 7, 7 }, + { "Orchid2", 212, 7, 7 }, + { "Orchid1", 213, 7, 7 }, + { "Orange1", 214, 3, 3 }, + { "SandyBrown", 215, 3, 3 }, + { "LightSalmon1", 216, 7, 7 }, + { "LightPink1", 217, 7, 7 }, + { "Pink1", 218, 7, 7 }, + { "Plum1", 219, 7, 7 }, + { "Gold1", 220, 11, 3 }, + { "LightGoldenrod2", 221, 11, 3 }, + { "LightGoldenrod2", 222, 7, 7 }, + { "NavajoWhite1", 223, 7, 7 }, + { "MistyRose1", 224, 7, 7 }, + { "Thistle1", 225, 7, 7 }, + { "Yellow1", 226, 11, 3 }, + { "LightGoldenrod1", 227, 11, 3 }, + { "Khaki1", 228, 7, 7 }, + { "Wheat1", 229, 7, 7 }, + { "Cornsilk1", 230, 7, 7 }, + { "Grey100", 231, 15, 7 }, + { "Grey3", 232, 0, 0 }, + { "Grey7", 233, 0, 0 }, + { "Grey11", 234, 0, 0 }, + { "Grey15", 235, 0, 0 }, + { "Grey19", 236, 0, 0 }, + { "Grey23", 237, 0, 0 }, + { "Grey27", 238, 8, 0 }, + { "Grey30", 239, 8, 0 }, + { "Grey35", 240, 8, 0 }, + { "Grey39", 241, 8, 0 }, + { "Grey42", 242, 8, 3 }, + { "Grey46", 243, 8, 3 }, + { "Grey50", 244, 8, 3 }, + { "Grey54", 245, 8, 7 }, + { "Grey58", 246, 8, 7 }, + { "Grey62", 247, 8, 7 }, + { "Grey66", 248, 8, 7 }, + { "Grey70", 249, 7, 7 }, + { "Grey74", 250, 7, 7 }, + { "Grey78", 251, 7, 7 }, + { "Grey82", 252, 7, 7 }, + { "Grey85", 253, 7, 7 }, + { "Grey89", 254, 7, 7 }, + { "Grey93", 255, 7, 7 }, + { NULL, 0, 0, 0 } +}; + +int xterm_to_ansi_fg[256]; +int xterm_to_ansi_bg[256]; + +HASHTAB htab_xterm_colors; /**< Hash table of color names */ + HASHTAB htab_tag; /**< Hash table of safe html tags */ #define MAX_COLS 32 /**< Maximum number of columns for align() */ @@ -1472,6 +1747,8 @@ typedef struct { char flags; /**< Ansi text attributes */ char fore; /**< Ansi foreground color */ char back; /**< Ansi background color */ + int forexterm; /**< Ansi xterm foreground color */ + int backxterm; /**< Ansi xterm background color */ } ansi_data; static void dump_ansi_codes(ansi_data * ad, char *buff, char **bp); @@ -1479,28 +1756,53 @@ static void dump_ansi_codes(ansi_data * ad, char *buff, char **bp); /** If we're adding y to x, do we need to add z as well? */ #define EDGE_UP(x,y,z) (((y) & (z)) && !((x) & (z))) +#define ANSI_XTERM_BG "\x1B[48;5;" +#define ANSI_XTERM_FG "\x1B[38;5;" + static void dump_ansi_codes(ansi_data * ad, char *buff, char **bp) { - static ansi_data old_ad = { 0, 0, 0 }; + static ansi_data old_ad = { 0, 0, 0, 0, 0 }; int f = 0; - if ((old_ad.fore && !ad->fore) - || (old_ad.back && !ad->back) + if ( (old_ad.fore && !ad->fore) + || (old_ad.back && !ad->back) + || (old_ad.forexterm && !ad->forexterm) + || (old_ad.backxterm && !ad->backxterm) || ((old_ad.flags & ad->flags) != old_ad.flags)) { safe_str(ANSI_NORMAL, buff, bp); old_ad.flags = 0; old_ad.fore = 0; old_ad.back = 0; + old_ad.forexterm = 0; + old_ad.backxterm = 0; } - if ((old_ad.fore == ad->fore) + if ( (old_ad.fore == ad->fore) && (old_ad.back == ad->back) + && (old_ad.forexterm == ad->forexterm) + && (old_ad.backxterm == ad->backxterm) && (old_ad.flags == ad->flags)) /* If nothing has changed, don't bother doing anything. * This stops the entirely pointless \e[m being generated. */ return; + /* XTERM always has priority */ + if ( ad->forexterm || ad->backxterm ) { + if ( ad->forexterm ) { + safe_str(ANSI_XTERM_FG, buff, bp); + safe_integer(ad->forexterm, buff, bp); + safe_str(ANSI_END, buff, bp); + } + if ( ad->backxterm ) { + safe_str(ANSI_XTERM_BG, buff, bp); + safe_integer(ad->backxterm, buff, bp); + safe_str(ANSI_END, buff, bp); + } + old_ad = *ad; + return; + } + safe_str(ANSI_BEGIN, buff, bp); if (EDGE_UP(old_ad.flags, ad->flags, COL_FLASH)) { @@ -1545,14 +1847,36 @@ dump_ansi_codes(ansi_data * ad, char *buff, char **bp) } +void +init_xterm_colors(void) +{ + int i; + + hashinit(&htab_xterm_colors, 512, sizeof(struct colormap *)); + + for (i = 0; xterm_colors[i].name; i++) { + if (i < 256) { + xterm_to_ansi_fg[i] = xterm_colors[i].i_ansi_fg; + xterm_to_ansi_bg[i] = xterm_colors[i].i_ansi_bg; + } + + hashadd(strlower(xterm_colors[i].name), + &xterm_colors[i], &htab_xterm_colors); + } +} /* ARGSUSED */ FUNCTION(fun_ansi) { static char tbuff[BUFFER_LEN]; - static ansi_data stack[1024] = { {0, 0, 0} }, *sp = stack; + static ansi_data stack[1024] = { {0, 0, 0, 0, 0} }, *sp = stack; char const *arg0, *arg1; char *tbp; + char *solidus; + char *fgname; + char *bgname; + int fgnum, bgnum; + struct colormap *cm; tbp = tbuff; arg0 = args[0]; @@ -1563,85 +1887,134 @@ FUNCTION(fun_ansi) sp[1] = sp[0]; sp++; - for (tbp = tbuff; *tbp; tbp++) { - switch (*tbp) { - case 'n': /* normal */ - sp->flags = 0; - sp->fore = 0; - sp->back = 0; - break; - case 'f': /* flash */ - sp->flags |= COL_FLASH; - break; - case 'h': /* hilite */ - sp->flags |= COL_HILITE; - break; - case 'i': /* inverse */ - sp->flags |= COL_INVERT; - break; - case 'u': /* underscore */ - sp->flags |= COL_UNDERSCORE; - break; - case 'F': /* flash */ - sp->flags &= ~COL_FLASH; - break; - case 'H': /* hilite */ - sp->flags &= ~COL_HILITE; - break; - case 'I': /* inverse */ - sp->flags &= ~COL_INVERT; - break; - case 'U': /* underscore */ - sp->flags &= ~COL_UNDERSCORE; - break; - case 'b': /* blue fg */ - sp->fore = COL_BLUE; - break; - case 'c': /* cyan fg */ - sp->fore = COL_CYAN; - break; - case 'g': /* green fg */ - sp->fore = COL_GREEN; - break; - case 'm': /* magenta fg */ - sp->fore = COL_MAGENTA; - break; - case 'r': /* red fg */ - sp->fore = COL_RED; - break; - case 'w': /* white fg */ - sp->fore = COL_WHITE; - break; - case 'x': /* black fg */ - sp->fore = COL_BLACK; - break; - case 'y': /* yellow fg */ - sp->fore = COL_YELLOW; - break; - case 'B': /* blue bg */ - sp->back = COL_BLUE; - break; - case 'C': /* cyan bg */ - sp->back = COL_CYAN; - break; - case 'G': /* green bg */ - sp->back = COL_GREEN; - break; - case 'M': /* magenta bg */ - sp->back = COL_MAGENTA; - break; - case 'R': /* red bg */ - sp->back = COL_RED; - break; - case 'W': /* white bg */ - sp->back = COL_WHITE; - break; - case 'X': /* black bg */ - sp->back = COL_BLACK; - break; - case 'Y': /* yellow bg */ - sp->back = COL_YELLOW; - break; + fgnum = -1; + bgnum = -1; + solidus = strchr(tbuff, '/'); + if (solidus) { + if (solidus == tbuff) { + fgname = NULL; + bgname = &solidus[1]; + } else { + fgname = tbuff; + solidus[0] = '\0'; + bgname = &solidus[1]; + } + } else { + fgname = tbuff; + bgname = NULL; + } + if (fgname && *fgname) { + if (is_integer(fgname)) { + fgnum = parse_integer(fgname); + if (fgnum < 0 || fgnum > 255) + fgnum = -1; + } + if (fgnum < 0) { + cm = hashfind(strlower(fgname), &htab_xterm_colors); + if (cm) + fgnum = cm->i_xterm; + } + } + if (bgname && *bgname) { + if (is_integer(bgname)) { + bgnum = parse_integer(bgname); + if (bgnum < 0 || bgnum > 255) + bgnum = -1; + } + if (bgnum < 0) { + cm = hashfind(strlower(bgname), &htab_xterm_colors); + if (cm) + bgnum = cm->i_xterm; + } + } + + if (fgnum != -1) + sp->forexterm = fgnum; + + if (bgnum != -1) + sp->backxterm = bgnum; + + if (fgnum == -1 && bgnum == -1) { + for (tbp = tbuff; *tbp; tbp++) { + switch (*tbp) { + case 'n': /* normal */ + sp->flags = 0; + sp->fore = 0; + sp->back = 0; + break; + case 'f': /* flash */ + sp->flags |= COL_FLASH; + break; + case 'h': /* hilite */ + sp->flags |= COL_HILITE; + break; + case 'i': /* inverse */ + sp->flags |= COL_INVERT; + break; + case 'u': /* underscore */ + sp->flags |= COL_UNDERSCORE; + break; + case 'F': /* flash */ + sp->flags &= ~COL_FLASH; + break; + case 'H': /* hilite */ + sp->flags &= ~COL_HILITE; + break; + case 'I': /* inverse */ + sp->flags &= ~COL_INVERT; + break; + case 'U': /* underscore */ + sp->flags &= ~COL_UNDERSCORE; + break; + case 'b': /* blue fg */ + sp->fore = COL_BLUE; + break; + case 'c': /* cyan fg */ + sp->fore = COL_CYAN; + break; + case 'g': /* green fg */ + sp->fore = COL_GREEN; + break; + case 'm': /* magenta fg */ + sp->fore = COL_MAGENTA; + break; + case 'r': /* red fg */ + sp->fore = COL_RED; + break; + case 'w': /* white fg */ + sp->fore = COL_WHITE; + break; + case 'x': /* black fg */ + sp->fore = COL_BLACK; + break; + case 'y': /* yellow fg */ + sp->fore = COL_YELLOW; + break; + case 'B': /* blue bg */ + sp->back = COL_BLUE; + break; + case 'C': /* cyan bg */ + sp->back = COL_CYAN; + break; + case 'G': /* green bg */ + sp->back = COL_GREEN; + break; + case 'M': /* magenta bg */ + sp->back = COL_MAGENTA; + break; + case 'R': /* red bg */ + sp->back = COL_RED; + break; + case 'W': /* white bg */ + sp->back = COL_WHITE; + break; + case 'X': /* black bg */ + sp->back = COL_BLACK; + break; + case 'Y': /* yellow bg */ + sp->back = COL_YELLOW; + break; + } } } diff --git a/src/game.c b/src/game.c index ba30f53..163b35d 100644 --- a/src/game.c +++ b/src/game.c @@ -796,6 +796,7 @@ init_game_config(const char *conf) init_locks(); init_names(); init_pronouns(); + init_xterm_colors(); init_lmods(); memset(¤t_state, 0, sizeof current_state); diff --git a/src/notify.c b/src/notify.c index 2882966..6296f65 100644 --- a/src/notify.c +++ b/src/notify.c @@ -157,6 +157,9 @@ enum na_type { NA_ASCII = 0, /**< Plain old ascii. */ NA_ANSI, /**< ANSI flag */ NA_COLOR, /**< ANSI and COLOR flags */ + NA_XTERMCOLOR, /**< XTERMCOLOR flag */ + NA_TXTERMCOLOR, /**< Like above with telnet-aware client */ + NA_NXTERMCOLOR, /**< XTERMCOLOR and NOACCENTS */ NA_PUEBLO, /**< html */ NA_PASCII, /**< Player without any of the above */ NA_TANSI, /**< Like above with telnet-aware client */ @@ -169,7 +172,7 @@ enum na_type { }; /** Number of possible message text renderings */ -#define MESSAGE_TYPES 12 +#define MESSAGE_TYPES 15 #define TA_BGC 0 /**< Text attribute background color */ #define TA_FGC 1 /**< Text attribute foreground color */ @@ -177,6 +180,8 @@ enum na_type { #define TA_REV 3 /**< Text attribute reverse/inverse */ #define TA_BLINK 4 /**< Text attribute blinking/flashing */ #define TA_ULINE 5 /**< Text attribute underline */ +#define TA_XTERMFG 6 /**< Xterm color, foreground */ +#define TA_XTERMBG 7 /**< Xterm color, background */ static int na_depth = 0; @@ -197,13 +202,15 @@ static unsigned char *notify_makestring(const char *message, struct notify_strings messages[], enum na_type type); +extern int xterm_to_ansi_fg[]; +extern int xterm_to_ansi_bg[]; static void -fillstate(int state[6], const unsigned char **f) +fillstate(int state[8], const unsigned char **f) { const unsigned char *p; int i; - int n; + int n, m; p = *f; p++; if (*p != '[') { @@ -214,11 +221,12 @@ fillstate(int state[6], const unsigned char **f) while (*p && *p != 'm') { if ((*p > '9') || (*p < '0')) { /* Nada */ - } else if (!(*(p + 1)) || (*(p + 1) == 'm') || (*(p + 1) == ';')) { + p++; + } else if (!p[1] || p[1] == 'm' || p[1] == ';') { /* ShortCode */ ; switch (*p) { case '0': - for (i = 0; i < 6; i++) + for (i = 0; i < 8; i++) state[i] = 0; break; case '1': @@ -234,21 +242,129 @@ fillstate(int state[6], const unsigned char **f) state[TA_ULINE] = 1; break; } + p++; } else { n = (*p - '0') * 10; p++; n += (*p - '0'); - if ((n >= 30) && (n <= 37)) + p++; + if ((n >= 30) && (n <= 37)) { state[TA_FGC] = n - 29; - else if ((n >= 40) && (n <= 47)) + } else if ((n >= 40) && (n <= 47)) { state[TA_BGC] = n - 39; + } else if ((n == 38) || (n == 48)) { + if (p[0] == ';' && p[1] == '5' && p[2] == ';') { + p = &p[3]; + m = 0; + while (*p >= '0' && *p <= '9') { + m = m * 10 + *p - '0'; + p++; + } + if (n == 38) { + state[TA_XTERMFG] = m + 1; + } else { + state[TA_XTERMBG] = m + 1; + } + } + } } - p++; } } if ((p != *f) && (*p != 'm')) p--; *f = p; + + if (state[TA_FGC] && !state[TA_XTERMFG]) { + switch (state[TA_FGC]) { + case 1: /* Black */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 244; /* Grey50 */ + else + state[TA_XTERMFG] = 0; /* Black */ + break; + case 2: /* Red */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 9; /* Red */ + else + state[TA_XTERMFG] = 160; /* Red3 */ + break; + case 3: /* Green */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 2; /* Green */ + else + state[TA_XTERMFG] = 40; /* Green3 */ + break; + case 4: /* Yellow */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 11; /* Yellow */ + else + state[TA_XTERMFG] = 148; /* Yellow3 */ + break; + case 5: /* Blue */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 63; /* RoyalBlue1 */ + else + state[TA_XTERMFG] = 20; /* Blue3 */ + break; + case 6: /* Magenta */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 201; /* Magenta1 */ + else + state[TA_XTERMFG] = 164; /* Magenta3 */ + break; + case 7: /* Cyan */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 51; /* Cyan1 */ + else + state[TA_XTERMFG] = 43; /* Cyan3 */ + break; + case 8: /* White */ + if (state[TA_BOLD]) + state[TA_XTERMFG] = 15; /* White */ + else + state[TA_XTERMFG] = 254; /* Grey89 */ + break; + } + state[TA_XTERMFG] += 1; + } else if (state[TA_XTERMFG]) { + state[TA_FGC] = xterm_to_ansi_fg[state[TA_XTERMFG] - 1] + 1; + if (state[TA_FGC] > 8) { + state[TA_FGC] -= 8; + state[TA_BOLD] = 1; + } + } + + if (state[TA_BGC] && !state[TA_XTERMBG]) { + switch (state[TA_BGC]) { + case 1: /* Black */ + state[TA_XTERMBG] = 0; /* Black */ + break; + case 2: /* Red */ + state[TA_XTERMBG] = 160; /* Red3 */ + break; + case 3: /* Green */ + state[TA_XTERMBG] = 40; /* Green3 */ + break; + case 4: /* Yellow */ + state[TA_XTERMBG] = 148; /* Yellow3 */ + break; + case 5: /* Blue */ + state[TA_XTERMBG] = 20; /* Blue3 */ + break; + case 6: /* Magenta */ + state[TA_XTERMBG] = 164; /* Magenta3 */ + break; + case 7: /* Cyan */ + state[TA_XTERMBG] = 43; /* Cyan3 */ + break; + case 8: /* White */ + state[TA_XTERMBG] = 254; /* Grey89 */ + break; + } + state[TA_XTERMBG] += 1; + } else if (state[TA_XTERMBG]) { + state[TA_BGC] = xterm_to_ansi_bg[state[TA_XTERMBG] - 1] + 1; + } } /** Add an ansi tag if it's needed here */ @@ -270,8 +386,10 @@ ansi_change_state(char *t, char **o, int color, int *state, int *newstate) (state[TA_BLINK] && !newstate[TA_BLINK]) || (state[TA_ULINE] && !newstate[TA_ULINE]) || (color && state[TA_FGC] && !newstate[TA_FGC]) || - (color && state[TA_BGC] && !newstate[TA_BGC])) { - for (n = 0; n < 6; n++) + (color && state[TA_BGC] && !newstate[TA_BGC]) || + (color > 1 && state[TA_XTERMFG] && !newstate[TA_XTERMFG]) || + (color > 1 && state[TA_XTERMBG] && !newstate[TA_XTERMBG])) { + for (n = 0; n < 8; n++) state[n] = 0; safe_str(ANSI_NORMAL, t, o); } @@ -280,7 +398,11 @@ ansi_change_state(char *t, char **o, int color, int *state, int *newstate) (newstate[TA_BLINK] && (newstate[TA_BLINK] != state[TA_BLINK])) || (newstate[TA_ULINE] && (newstate[TA_ULINE] != state[TA_ULINE])) || (color && newstate[TA_FGC] && (newstate[TA_FGC] != state[TA_FGC])) || - (color && newstate[TA_BGC] && (newstate[TA_BGC] != state[TA_BGC]))) { + (color && newstate[TA_BGC] && (newstate[TA_BGC] != state[TA_BGC])) || + (color > 1 && newstate[TA_XTERMFG] && + (newstate[TA_XTERMFG] != state[TA_XTERMFG])) || + (color > 1 && newstate[TA_XTERMBG] && + (newstate[TA_XTERMBG] != state[TA_XTERMBG]))) { safe_chr(ESC_CHAR, t, o); safe_chr('[', t, o); i = 0; @@ -288,13 +410,19 @@ ansi_change_state(char *t, char **o, int color, int *state, int *newstate) add_ansi_if(TA_REV, "7"); add_ansi_if(TA_BLINK, "5"); add_ansi_if(TA_ULINE, "4"); - if (color) { + switch (color) { + case 2: /* XTERM */ + add_ansi_if(TA_XTERMFG, tprintf("38;5;%u", newstate[TA_XTERMFG] - 1)); + add_ansi_if(TA_XTERMBG, tprintf("48;5;%u", newstate[TA_XTERMBG] - 1)); + break; + case 1: /* ANSI */ add_ansi_if(TA_FGC, unparse_integer(newstate[TA_FGC] + 29)); add_ansi_if(TA_BGC, unparse_integer(newstate[TA_BGC] + 39)); + break; } safe_chr('m', t, o); } - for (n = 0; n < 6; n++) + for (n = 0; n < 8; n++) state[n] = newstate[n]; } @@ -327,8 +455,8 @@ notify_makestring(const char *message, struct notify_strings messages[], char *o; const unsigned char *p; char *t; - int state[6] = { 0, 0, 0, 0, 0, 0 }; - int newstate[6] = { 0, 0, 0, 0, 0, 0 }; + int state[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int newstate[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int changed = 0; int color = 0; int strip = 0; @@ -420,12 +548,19 @@ notify_makestring(const char *message, struct notify_strings messages[], case NA_COLOR: case NA_TCOLOR: case NA_NCOLOR: - color = 1; + case NA_XTERMCOLOR: + case NA_TXTERMCOLOR: + case NA_NXTERMCOLOR: + if (type == NA_XTERMCOLOR) + color = 2; + else + color = 1; /* FALLTHROUGH */ case NA_ANSI: case NA_TANSI: case NA_NANSI: - if (type == NA_NCOLOR || type == NA_NANSI || type == NA_NPUEBLO) + if (type == NA_NCOLOR || type == NA_NANSI || type == NA_NPUEBLO || + type == NA_NXTERMCOLOR) strip = 1; while (*p) { switch ((unsigned char) *p) { @@ -434,7 +569,7 @@ notify_makestring(const char *message, struct notify_strings messages[], changed = 0; ansi_change_state(t, &o, color, state, newstate); } - if (type == NA_TANSI || type == NA_TCOLOR) + if (type == NA_TANSI || type == NA_TCOLOR || type == NA_TXTERMCOLOR) safe_str("\xFF\xFF", t, &o); else if (strip && accent_table[IAC].base) safe_str(accent_table[IAC].base, t, &o); @@ -506,7 +641,8 @@ notify_makestring(const char *message, struct notify_strings messages[], } if (state[TA_BOLD] || state[TA_REV] || state[TA_BLINK] || state[TA_ULINE] || - (color && (state[TA_FGC] || state[TA_BGC]))) + (color && (state[TA_FGC] || state[TA_BGC] + || state[TA_XTERMFG] || state[TA_XTERMBG]))) safe_str(ANSI_NORMAL, t, &o); break; @@ -693,7 +829,12 @@ notify_type(DESC *d) if (d->conn_flags & CONN_HTML) { poutput = strip ? NA_NPUEBLO : NA_PUEBLO; } else if (ShowAnsi(d->player)) { - if (ShowAnsiColor(d->player)) { + if (ShowXtermColor(d->player)) { + if (strip) + poutput = NA_NXTERMCOLOR; + else + poutput = (d->conn_flags & CONN_TELNET) ? NA_TXTERMCOLOR : NA_XTERMCOLOR; + } else if (ShowAnsiColor(d->player)) { if (strip) poutput = NA_NCOLOR; else