Skip to content

Commit

Permalink
Optimize the SGR output of ccat
Browse files Browse the repository at this point in the history
  • Loading branch information
bisqwit committed Dec 29, 2017
1 parent 0ddf6bc commit 70a9ae9
Showing 1 changed file with 103 additions and 25 deletions.
128 changes: 103 additions & 25 deletions ep1/ccat/ccat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
#include <stdlib.h>
#include <vector>
#include <string>

#define strnicmp strncasecmp
#define register
#define cdecl

#include "jsf.hh"

static const char* synfile = "ctcode2.jsf";
Expand Down Expand Up @@ -39,7 +40,7 @@ class Action: public JSF::Applier
struct Attribute
{
unsigned char fg, bg;
bool extcolor:1, underline:1, dim:1, italic:1, bold:1, inverse:1, blink:1;
bool extcolor:1, underline:1, dim:1, italic:1, bold:1, inverse:1, blink:1, dblunder:1, strikeout:1;

void Split(unsigned attr)
{
Expand All @@ -50,10 +51,12 @@ class Action: public JSF::Applier
inverse = attr & 0x100000u;
blink = attr & 0x200000u;
extcolor = attr & 0x800000u;
dblunder = false;
strikeout = false;
if(extcolor)
{ bg = attr >> 8; fg = (attr & 0x7F) | ((attr & 0x400000u) ? 0x80u : 0x00u); }
else
{ bg = (attr >> 4) & 0xF; fg = (attr & 0xF); }
{ bg = (attr >> 4) & 0x7; fg = (attr & 0xF); }
}
};
void Print()
Expand All @@ -67,30 +70,105 @@ class Action: public JSF::Applier
{ result += "\33[m"; cur_attr = 7; }
else if(cur_attr != attr)
{
const char* pfx = "\33[";
#define add(n) do{ result += pfx; pfx = ";"; result += n; }while(0)

Attribute cur; cur.Split(cur_attr);
Attribute rep; rep.Split(attr);

if(cur.underline && !rep.underline) add("24"); else if(rep.underline && !cur.underline) add("4");
if(cur.dim && !rep.dim) add("22"); else if(rep.dim && !cur.dim) add("2");
if(cur.italic && !rep.italic) add("23"); else if(rep.italic && !cur.italic) add("3");
if(cur.bold && !rep.bold) add("21"); else if(rep.bold && !cur.bold) add("1");
if(cur.inverse && !rep.inverse) add("27"); else if(rep.inverse && !cur.inverse) add("7");
if(cur.blink && !rep.blink) add("25"); else if(rep.blink && !cur.blink) add("5");
if(cur.fg != rep.fg)
{
char Buf[16];
if(rep.extcolor) sprintf(Buf, "38;5;%d", rep.fg); else sprintf(Buf, "3%d", (rep.fg&2)|(4*(rep.fg&1))|((rep.fg&4)/4));
add(Buf);
}
if(cur.bg != rep.bg)
std::string chosen_code;
for(unsigned round=0; round<2; ++round)
{
char Buf[16];
if(rep.extcolor) sprintf(Buf, "48;5;%d", rep.bg); else sprintf(Buf, "4%d", (rep.bg&2)|(4*(rep.bg&1))|((rep.bg&4)/4));
add(Buf);
std::string code;
const char* pfx = "";
#define add(n) do{ code += pfx; pfx = ";"; code += n; }while(0)

Attribute cur; cur.Split(cur_attr);
Attribute rep; rep.Split(attr);

/*
SGR codes supported by Xterm
https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
1: Set bold
2: Set dim
3: Set italic
4: Set underline
5: Set blink
7: Set inverse
8: Set invisible
9: Set strike-out
21: SET DOUBLE underline
22: Clear bold AND dim
23: Clear italic
24: Clear underline and DOUBLE underline
25: Clear blink
27: Clear inverse
29: Clear strike-out
30..37: Set foreground attribute (0-7, from ANSI)
38;5;n: Set foreground attribute (n, from xterm-256color)
38;2;r;g;b: Set foreground attribute (truecolor, 256*256*256)
39: Set foreground attribute with default
40..47: Set background attribute (0-7, from ANSI)
48;5;n: Set background attribute (n, from xterm-256color)
48;2;r;g;b: Set background attribute (truecolor, 256*256*256)
49: Set background attribute with default
90..97: Set foreground attribute (0-7, from ANSI but bright & not bold), AIX extension
100: Same as 39;49
101..107: Set background attribute (0-7, from ANSI but bright & not bold), AIX extension
0: Same as 22;23;24;25;27;29;39;49
*/
if(round == 0) { add("0"); cur.Split(7); }

if((!rep.bold && cur.bold) || (!rep.dim && cur.dim))
{ add("22"); cur.bold=false; cur.dim=false; }
if((!rep.underline && cur.underline) || (!rep.dblunder && cur.dblunder))
{ add("24"); cur.underline=false; cur.dblunder=false; }
if(rep.bold && !cur.bold) add("1");
if(rep.dim && !cur.dim) add("2");
if(rep.underline && !cur.underline) add("4");
if(rep.dblunder && !cur.dblunder) add("21");

if(cur.italic && !rep.italic) add("23"); else if(rep.italic && !cur.italic) add("3");
if(cur.blink && !rep.blink) add("25"); else if(rep.blink && !cur.blink) add("5");
if(cur.inverse && !rep.inverse) add("27"); else if(rep.inverse && !cur.inverse) add("7");
if(cur.strikeout && !rep.strikeout) add("29"); else if(rep.strikeout && !cur.strikeout) add("9");

auto getcolor = [&](Attribute& attr, unsigned c) -> std::pair<bool,unsigned>
{
if(!attr.extcolor || c<16) return {false,c};
if(c == 16 || c == 232) return {false,0};
if(c == 255 || c == 231) return {false,15};
return {true,c};
};

if(auto c = getcolor(rep,rep.fg); c != getcolor(cur,cur.fg))
if(auto c2 = getcolor(rep,rep.bg); c2 != getcolor(cur,cur.bg))
if(c == std::pair{false,7u} && c2 == std::pair{false,0u})
{
add("100"); //39+49
cur.bg = 0; cur.fg = 7;
}

if(auto c = getcolor(rep,rep.fg); c != getcolor(cur,cur.fg))
{
char Buf[16];

if(c.first) sprintf(Buf, "38:5:%d", c.second);
else if(c.second&8)sprintf(Buf, "9%d", (c.second&2)|(4*(c.second&1))|((c.second&4)/4));
else sprintf(Buf, "3%d", (c.second&2)|(4*(c.second&1))|((c.second&4)/4));
add(Buf);
}
if(auto c = getcolor(rep,rep.bg); c != getcolor(cur,cur.bg))
{
char Buf[16];
if(c.first) sprintf(Buf, "48:5:%d", c.second);
else if(c.second&8)sprintf(Buf, "10%d", (c.second&2)|(4*(c.second&1))|((c.second&4)/4));
else sprintf(Buf, "4%d", (c.second&2)|(4*(c.second&1))|((c.second&4)/4));
add(Buf);
}
if(!round || code.size() < chosen_code.size())
chosen_code = std::move(code);
}
if(chosen_code.size()==1 && chosen_code[0]=='0') chosen_code.clear();

result += "\33[";
result += std::move(chosen_code);
result += 'm';
cur_attr = attr;
}
Expand Down

0 comments on commit 70a9ae9

Please sign in to comment.