#!/bin/sh # Convert ANSI (terminal) colours and attributes to HTML # Licence: LGPLv2 # Author: # http://www.pixelbeat.org/docs/terminal_colours/ # Examples: # ls -l --color=always | ansi2html.sh > ls.html # git show --color | ansi2html.sh > last_change.html # Generally one can use the `script` util to capture full terminal output. # Changes: # V0.1, 24 Apr 2008, Initial release # V0.2, 01 Jan 2009, Phil Harnish # Support `git diff --color` output by # matching ANSI codes that specify only # bold or background colour. # P@draigBrady.com # Support `ls --color` output by stripping # redundant leading 0s from ANSI codes. # Support `grep --color=always` by stripping # unhandled ANSI codes (specifically ^[[K). # V0.3, 20 Mar 2009, http://eexpress.blog.ubuntu.org.cn/ # Remove cat -v usage which mangled non ascii input. # Cleanup regular expressions used. # Support other attributes like reverse, ... # P@draigBrady.com # Correctly nest tags (even across lines). # Add a command line option to use a dark background. # Strip more terminal control codes. # V0.4, 17 Sep 2009, P@draigBrady.com # Handle codes with combined attributes and color. # Handle isolated attributes with css. # Strip more terminal control codes. # V0.23, 28 Feb 2016 # http://github.com/pixelb/scripts/commits/master/scripts/ansi2html.sh gawk --version >/dev/null || exit 1 if test $1 = "--version" { printf '0.23\n' && exit } proc usage { printf '%s\n' \ 'This utility converts ANSI codes in data passed to stdin It has 4 optional parameters: --bg=dark --palette=linux|solarized|tango|xterm --css-only|--body-only E.g.: ls -l --color=always | ansi2html.sh --bg=dark > ls.html' > !2 exit } if test $1 = "--help" { usage } proc processArg { test $1 = "--bg=dark" && do { global dark_bg := 'yes'; return; } test $1 = "--css-only" && do { global css_only := 'yes'; return; } test $1 = "--body-only" && do { global body_only := 'yes'; return; } if test $1 = "--palette=solarized" { # See http://ethanschoonover.com/solarized global P0 := '073642'; global P1 := 'D30102'; global P2 := '859900'; global P3 := 'B58900'; global P4 := '268BD2'; global P5 := 'D33682'; global P6 := '2AA198'; global P7 := 'EEE8D5'; global P8 := '002B36'; global P9 := 'CB4B16'; global P10 := '586E75'; global P11 := '657B83'; global P12 := '839496'; global P13 := '6C71C4'; global P14 := '93A1A1'; global P15 := 'FDF6E3'; return; } elif test $1 = "--palette=solarized-xterm" { # Above mapped onto the xterm 256 color palette global P0 := '262626'; global P1 := 'AF0000'; global P2 := '5F8700'; global P3 := 'AF8700'; global P4 := '0087FF'; global P5 := 'AF005F'; global P6 := '00AFAF'; global P7 := 'E4E4E4'; global P8 := '1C1C1C'; global P9 := 'D75F00'; global P10 := '585858'; global P11 := '626262'; global P12 := '808080'; global P13 := '5F5FAF'; global P14 := '8A8A8A'; global P15 := 'FFFFD7'; return; } elif test $1 = "--palette=tango" { # Gnome default global P0 := '000000'; global P1 := 'CC0000'; global P2 := '4E9A06'; global P3 := 'C4A000'; global P4 := '3465A4'; global P5 := '75507B'; global P6 := '06989A'; global P7 := 'D3D7CF'; global P8 := '555753'; global P9 := 'EF2929'; global P10 := '8AE234'; global P11 := 'FCE94F'; global P12 := '729FCF'; global P13 := 'AD7FA8'; global P14 := '34E2E2'; global P15 := 'EEEEEC'; return; } elif test $1 = "--palette=xterm" { global P0 := '000000'; global P1 := 'CD0000'; global P2 := '00CD00'; global P3 := 'CDCD00'; global P4 := '0000EE'; global P5 := 'CD00CD'; global P6 := '00CDCD'; global P7 := 'E5E5E5'; global P8 := '7F7F7F'; global P9 := 'FF0000'; global P10 := '00FF00'; global P11 := 'FFFF00'; global P12 := '5C5CFF'; global P13 := 'FF00FF'; global P14 := '00FFFF'; global P15 := 'FFFFFF'; return; } else { # linux console global P0 := '000000'; global P1 := 'AA0000'; global P2 := '00AA00'; global P3 := 'AA5500'; global P4 := '0000AA'; global P5 := 'AA00AA'; global P6 := '00AAAA'; global P7 := 'AAAAAA'; global P8 := '555555'; global P9 := 'FF5555'; global P10 := '55FF55'; global P11 := 'FFFF55'; global P12 := '5555FF'; global P13 := 'FF55FF'; global P14 := '55FFFF'; global P15 := 'FFFFFF'; test $1 = "--palette=linux" && return; } } processArg #defaults for var in [@Argv] { processArg $var; } test $css_only && test $body_only && usage # Mac OSX's GNU sed is installed as gsed # use e.g. homebrew 'gnu-sed' to get it if ! sed --version >/dev/null !2 > !1 { if gsed --version >/dev/null !2 > !1 { alias sed=gsed } else { echo "Error, can't find an acceptable GNU sed." > !2 exit 1 } } test $css_only || test $body_only || printf '%s' "
'
test $body_only && printf '%s\n' 'Be sure to use  and 
' > !2

global p := ''\x1b\[''        #shortcut to match escape codes

# Handle various xterm control sequences.
# See /usr/share/doc/xterm-*/ctlseqs.txt
sed "
# escape ampersand and quote
s#&#\&#g; s#\"#\"#g;
s#\x1b[^\x1b]*\x1b\\\##g  # strip anything between \e and ST
s#\x1b][0-9]*;[^\a]*\a##g # strip any OSC (xterm title etc.)

s#\r\$## # strip trailing \r

# strip other non SGR escape sequences
s#[\x07]##g
s#\x1b[]>=\][0-9;]*##g
s#\x1bP+.\{5\}##g
# Mark cursor positioning codes \"Jr;c;
s#$(p)\([0-9]\{1,2\}\)G#\"J;\1;#g
s#$(p)\([0-9]\{1,2\}\);\([0-9]\{1,2\}\)H#\"J\1;\2;#g

# Mark clear as \"Cn where n=1 is screen and n=0 is to end-of-line
s#$(p)H#\"C1;#g
s#$(p)K#\"C0;#g
# Mark Cursor move columns as \"Mn where n is +ve for right, -ve for left
s#$(p)C#\"M1;#g
s#$(p)\([0-9]\{1,\}\)C#\"M\1;#g
s#$(p)\([0-9]\{1,\}\)D#\"M-\1;#g
s#$(p)\([0-9]\{1,\}\)P#\"X\1;#g

s#$(p)[0-9;?]*[^0-9;?m]##g

" |

# Normalize the input before transformation
sed "
# escape HTML (ampersand and quote done above)
s#>#\>#g; s#<#\<#g;

# normalize SGR codes a little

# split 256 colors out and mark so that they're not
# recognised by the following 'split combined' line
:e
s#$(p)\([0-9;]\{1,\}\);\([34]8;5;[0-9]\{1,3\}\)m#$(p)\1m$(p)¬\2m#g; t e
s#$(p)\([34]8;5;[0-9]\{1,3\}\)m#$(p)¬\1m#g;

:c
s#$(p)\([0-9]\{1,\}\);\([0-9;]\{1,\}\)m#$(p)\1m$(p)\2m#g; t c   # split combined
s#$(p)0\([0-7]\)#$(p)\1#g                                 #strip leading 0
s#$(p)1m\(\($(p)[4579]m\)*\)#\1$(p)1m#g                   #bold last (with clr)
s#$(p)m#$(p)0m#g                                          #add leading 0 to norm

# undo any 256 color marking
s#$(p)¬\([34]8;5;[0-9]\{1,3\}\)m#$(p)\1m#g;

# map 16 color codes to color + bold
s#$(p)9\([0-7]\)m#$(p)3\1m$(p)1m#g;
s#$(p)10\([0-7]\)m#$(p)4\1m$(p)1m#g;

# change 'reset' code to \"R
s#$(p)0m#\"R;#g
" |

# Convert SGR sequences to HTML
sed "
# common combinations to minimise html (optional)
:f
s#$(p)3[0-7]m$(p)3\([0-7]\)m#$(p)3\1m#g; t f
:b
s#$(p)4[0-7]m$(p)4\([0-7]\)m#$(p)4\1m#g; t b
s#$(p)3\([0-7]\)m$(p)4\([0-7]\)m##g
s#$(p)4\([0-7]\)m$(p)3\([0-7]\)m##g

s#$(p)1m##g
s#$(p)4m##g
s#$(p)5m##g
s#$(p)7m##g
s#$(p)9m##g
s#$(p)3\([0-9]\)m##g
s#$(p)4\([0-9]\)m##g

s#$(p)38;5;\([0-9]\{1,3\}\)m##g
s#$(p)48;5;\([0-9]\{1,3\}\)m##g

s#$(p)[0-9;]*m##g # strip unhandled codes
" |

# Convert alternative character set and handle cursor movement codes
# Note we convert here, as if we do at start we have to worry about avoiding
# conversion of SGR codes etc., whereas doing here we only have to
# avoid conversions of stuff between &...; or <...>
#
# Note we could use sed to do this based around:
#   sed 'y/abcdefghijklmnopqrstuvwxyz{}`~/▒␉␌␍␊°±␤␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥π£◆·/'
# However that would be very awkward as we need to only conv some input.
# The basic scheme that we do in the awk script below is:
#  1. enable transliterate once "T1; is seen
#  2. disable once "T0; is seen (may be on diff line)
#  3. never transliterate between &; or <> chars
#  4. track x,y movements and active display mode at each position
#  5. buffer line/screen and dump when required
sed "
# change 'smacs' and 'rmacs' to \"T1 and \"T0 to simplify matching.
s#\x1b(0#\"T1;#g;
s#\x0E#\"T1;#g;

s#\x1b(B#\"T0;#g
s#\x0F#\"T0;#g
" |
shell {
gawk '
function dump_line(l,del,c,blanks,ret) {
  for(c=1;c")
  for(i=1;i<=spc;i++) {
    rm=rm?rm:(a[i]!=attr[i]">")
    if(rm) {
      ret=ret ""
      delete a[i];
    }
  }
  for(i=1;i"
    if(a[i]!=attr[i]) {
      a[i]=attr[i]
      ret = ret attr[i]
    }
  }
  return ret
}

function encode(string,start,end,i,ret,pos,sc,buf) {
   if(!end) end=length(string);
   if(!start) start=1;
   state=3
   for(i=1;i<=length(string);i++) {
     c=substr(string,i,1)
     if(state==2) {
       sc=sc c
       if(c==";") {
          c=sc
          state=last_mode
       } else continue
     } else {
       if(c=="\r") { x=1; continue }
       if(c=="<") {
         # Change attributes - store current active
         # attributes in span array
         split(substr(string,i),cord,">");
         i+=length(cord[1])
         span[++spc]=cord[1] ">"
         continue
       }
       else if(c=="&") {
         # All goes to single position till we see a semicolon
         sc=c
         state=2
         continue
       }
       else if(c=="\b") {
          # backspace move insertion point back 1
          if(spc) attr[x,y]=atos(span)
          x=x>1?x-1:1
          continue
       }
       else if(c=="\"") {
          split(substr(string,i+2),cord,";")
          cc=substr(string,i+1,1);
          if(cc=="T") {
              # Transliterate on/off
              if(cord[1]==1&&state==3) last_mode=state=4
              if(cord[1]==0&&state==4) last_mode=state=3
          }
          else if(cc=="C") {
              # Clear
              if(cord[1]+0) {
                # Screen - if Recording dump screen
                if(dumpStatus==dsActive) ret=ret dump_screen()
                dumpStatus=dsActive
                delete dump
                delete attr
                x=y=1
              } else {
                # To end of line
                for(pos=x;posmaxY) maxY=y
                # Change y - start recording
                dumpStatus=dumpStatus?dumpStatus:dsReset
              }
          }
          else if(cc=="M") {
              # Move left/right on current line
              x+=cord[1]
          }
          else if(cc=="X") {
              # delete on right
              for(pos=x;pos<=maxX;pos++) {
                nx=pos+cord[1]
                if(nx=start&&i<=end&&c in Trans) c=Trans[c]
     }
     if(dumpStatus==dsReset) {
       delete dump
       delete attr
       ret=ret"\n"
       dumpStatus=dsActive
     }
     if(dumpStatus==dsNew) {
       # After moving/clearing we are now ready to write
       # somthing to the screen so start recording now
       ret=ret"\n"
       dumpStatus=dsActive
     }
     if(dumpStatus==dsActive||dumpStatus==dsOff) {
       dump[x,y] = c
       if(!spc) delete attr[x,y]
       else attr[x,y] = atos(span)
       if(++x>maxX) maxX=x;
     }
    }
    # End of line if dumping increment y and set x back to first col
    x=1
    if(!dumpStatus) return ret dump_line(y,1);
    else if(++y>maxY) maxY=y;
    return ret
}
BEGIN{
  OFS=FS
  # dump screen status
  dsOff=0    # Not dumping screen contents just write output direct
  dsNew=1    # Just after move/clear waiting for activity to start recording
  dsReset=2  # Screen cleared build new empty buffer and record
  dsActive=3 # Currently recording
  F="abcdefghijklmnopqrstuvwxyz{}`~"
  T="▒␉␌␍␊°±␤␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥π£◆·"
  maxX=80
  delete cur;
  x=y=1
  for(i=1;i<=length(F);i++)Trans[substr(F,i,1)]=substr(T,i,1);
}

{ $0=encode($0) }
1
END {
  if(dumpStatus) {
    print dump_screen();
  }
}'
}

test $body_only || printf '
\n' (CommandList children: [ (AndOr children: [ (SimpleCommand words: [{(gawk)} {(--version)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[109])] ) (C {(exit)} {(1)}) ] op_id: Op_DPipe ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ (--version))} {(Lit_Other "]")} ) terminator: ) ] action: [(AndOr children:[(C {(printf)} {(SQ <"0.23\\n">)})(C {(exit)})] op_id:Op_DAmp)] spids: [-1 136] ) ] spids: [-1 149] ) (FuncDef name: usage body: (BraceGroup children: [ (SimpleCommand words: [ {(printf)} {(SQ <"%s\\n">)} { (SQ <"This utility converts ANSI codes in data passed to stdin\n"> <"It has 4 optional parameters:\n"> <"--bg=dark --palette=linux|solarized|tango|xterm --css-only|--body-only\n"> <"E.g.: ls -l --color=always | ansi2html.sh --bg=dark > ls.html"> ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[172])] ) (C {(exit)}) ] spids: [156] ) spids: [152 155] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ (--help))} {(Lit_Other "]")} ) terminator: ) ] action: [(C {(usage)})] spids: [-1 198] ) ] spids: [-1 203] ) (FuncDef name: processArg body: (BraceGroup children: [ (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--bg=dark"))} {(Lit_Other "]")} ) (BraceGroup children: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:dark_bg) op: Equal rhs: {(yes)} spids: [231] ) ] spids: [231] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [229] ) ] op_id: Op_DAmp ) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ (--css-only))} {(Lit_Other "]")} ) (BraceGroup children: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:css_only) op: Equal rhs: {(yes)} spids: [259] ) ] spids: [259] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [257] ) ] op_id: Op_DAmp ) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ (--body-only))} {(Lit_Other "]")} ) (BraceGroup children: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:body_only) op: Equal rhs: {(yes)} spids: [287] ) ] spids: [287] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [285] ) ] op_id: Op_DAmp ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--palette=solarized"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P0) op: Equal rhs: {(073642)} spids: [321] ) ] spids: [321] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P1) op: Equal rhs: {(D30102)} spids: [325] ) ] spids: [325] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P2) op: Equal rhs: {(859900)} spids: [329] ) ] spids: [329] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P3) op: Equal rhs: {(B58900)} spids: [333] ) ] spids: [333] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P4) op: Equal rhs: {(268BD2)} spids: [338] ) ] spids: [338] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P5) op: Equal rhs: {(D33682)} spids: [342] ) ] spids: [342] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P6) op: Equal rhs: {(2AA198)} spids: [346] ) ] spids: [346] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P7) op: Equal rhs: {(EEE8D5)} spids: [350] ) ] spids: [350] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P8) op: Equal rhs: {(002B36)} spids: [355] ) ] spids: [355] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P9) op: Equal rhs: {(CB4B16)} spids: [359] ) ] spids: [359] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P10) op: Equal rhs: {(586E75)} spids: [363] ) ] spids: [363] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P11) op: Equal rhs: {(657B83)} spids: [367] ) ] spids: [367] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P12) op: Equal rhs: {(839496)} spids: [372] ) ] spids: [372] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P13) op: Equal rhs: {(6C71C4)} spids: [376] ) ] spids: [376] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P14) op: Equal rhs: {(93A1A1)} spids: [380] ) ] spids: [380] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P15) op: Equal rhs: {(FDF6E3)} spids: [384] ) ] spids: [384] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [-1 314] ) (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--palette=solarized-xterm"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P0) op: Equal rhs: {(262626)} spids: [417] ) ] spids: [417] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P1) op: Equal rhs: {(AF0000)} spids: [421] ) ] spids: [421] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P2) op: Equal rhs: {(5F8700)} spids: [425] ) ] spids: [425] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P3) op: Equal rhs: {(AF8700)} spids: [429] ) ] spids: [429] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P4) op: Equal rhs: {(0087FF)} spids: [434] ) ] spids: [434] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P5) op: Equal rhs: {(AF005F)} spids: [438] ) ] spids: [438] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P6) op: Equal rhs: {(00AFAF)} spids: [442] ) ] spids: [442] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P7) op: Equal rhs: {(E4E4E4)} spids: [446] ) ] spids: [446] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P8) op: Equal rhs: {(1C1C1C)} spids: [451] ) ] spids: [451] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P9) op: Equal rhs: {(D75F00)} spids: [455] ) ] spids: [455] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P10) op: Equal rhs: {(585858)} spids: [459] ) ] spids: [459] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P11) op: Equal rhs: {(626262)} spids: [463] ) ] spids: [463] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P12) op: Equal rhs: {(808080)} spids: [468] ) ] spids: [468] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P13) op: Equal rhs: {(5F5FAF)} spids: [472] ) ] spids: [472] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P14) op: Equal rhs: {(8A8A8A)} spids: [476] ) ] spids: [476] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P15) op: Equal rhs: {(FFFFD7)} spids: [480] ) ] spids: [480] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [393 410] ) (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--palette=tango"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P0) op: Equal rhs: {(000000)} spids: [513] ) ] spids: [513] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P1) op: Equal rhs: {(CC0000)} spids: [517] ) ] spids: [517] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P2) op: Equal rhs: {(4E9A06)} spids: [521] ) ] spids: [521] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P3) op: Equal rhs: {(C4A000)} spids: [525] ) ] spids: [525] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P4) op: Equal rhs: {(3465A4)} spids: [530] ) ] spids: [530] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P5) op: Equal rhs: {(75507B)} spids: [534] ) ] spids: [534] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P6) op: Equal rhs: {(06989A)} spids: [538] ) ] spids: [538] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P7) op: Equal rhs: {(D3D7CF)} spids: [542] ) ] spids: [542] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P8) op: Equal rhs: {(555753)} spids: [547] ) ] spids: [547] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P9) op: Equal rhs: {(EF2929)} spids: [551] ) ] spids: [551] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P10) op: Equal rhs: {(8AE234)} spids: [555] ) ] spids: [555] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P11) op: Equal rhs: {(FCE94F)} spids: [559] ) ] spids: [559] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P12) op: Equal rhs: {(729FCF)} spids: [564] ) ] spids: [564] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P13) op: Equal rhs: {(AD7FA8)} spids: [568] ) ] spids: [568] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P14) op: Equal rhs: {(34E2E2)} spids: [572] ) ] spids: [572] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P15) op: Equal rhs: {(EEEEEC)} spids: [576] ) ] spids: [576] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [489 506] ) (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--palette=xterm"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P0) op: Equal rhs: {(000000)} spids: [605] ) ] spids: [605] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P1) op: Equal rhs: {(CD0000)} spids: [609] ) ] spids: [609] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P2) op: Equal rhs: {(00CD00)} spids: [613] ) ] spids: [613] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P3) op: Equal rhs: {(CDCD00)} spids: [617] ) ] spids: [617] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P4) op: Equal rhs: {(0000EE)} spids: [622] ) ] spids: [622] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P5) op: Equal rhs: {(CD00CD)} spids: [626] ) ] spids: [626] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P6) op: Equal rhs: {(00CDCD)} spids: [630] ) ] spids: [630] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P7) op: Equal rhs: {(E5E5E5)} spids: [634] ) ] spids: [634] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P8) op: Equal rhs: {(7F7F7F)} spids: [639] ) ] spids: [639] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P9) op: Equal rhs: {(FF0000)} spids: [643] ) ] spids: [643] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P10) op: Equal rhs: {(00FF00)} spids: [647] ) ] spids: [647] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P11) op: Equal rhs: {(FFFF00)} spids: [651] ) ] spids: [651] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P12) op: Equal rhs: {(5C5CFF)} spids: [656] ) ] spids: [656] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P13) op: Equal rhs: {(FF00FF)} spids: [660] ) ] spids: [660] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P14) op: Equal rhs: {(00FFFF)} spids: [664] ) ] spids: [664] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P15) op: Equal rhs: {(FFFFFF)} spids: [668] ) ] spids: [668] ) terminator: ) (Sentence child: (ControlFlow token:) terminator: ) ] spids: [585 602] ) ] else_action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P0) op:Equal rhs:{(000000)} spids:[683])] spids: [683] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P1) op:Equal rhs:{(AA0000)} spids:[687])] spids: [687] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P2) op:Equal rhs:{(00AA00)} spids:[691])] spids: [691] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P3) op:Equal rhs:{(AA5500)} spids:[695])] spids: [695] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P4) op:Equal rhs:{(0000AA)} spids:[700])] spids: [700] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P5) op:Equal rhs:{(AA00AA)} spids:[704])] spids: [704] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P6) op:Equal rhs:{(00AAAA)} spids:[708])] spids: [708] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P7) op:Equal rhs:{(AAAAAA)} spids:[712])] spids: [712] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P8) op:Equal rhs:{(555555)} spids:[717])] spids: [717] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:P9) op:Equal rhs:{(FF5555)} spids:[721])] spids: [721] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P10) op: Equal rhs: {(55FF55)} spids: [725] ) ] spids: [725] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P11) op: Equal rhs: {(FFFF55)} spids: [729] ) ] spids: [729] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P12) op: Equal rhs: {(5555FF)} spids: [734] ) ] spids: [734] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P13) op: Equal rhs: {(FF55FF)} spids: [738] ) ] spids: [738] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P14) op: Equal rhs: {(55FFFF)} spids: [742] ) ] spids: [742] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:P15) op: Equal rhs: {(FFFFFF)} spids: [746] ) ] spids: [746] ) terminator: ) (Sentence child: (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Number "$1"))} {(Lit_Other "=")} {(DQ ("--palette=linux"))} {(Lit_Other "]")} ) (ControlFlow token:) ] op_id: Op_DAmp ) terminator: ) ] spids: [677 771] ) ] spids: [210] ) spids: [206 209] ) (C {(processArg)}) (ForEach iter_name: var iter_words: [{(DQ ($ VSub_At "$@"))}] do_arg_iter: False body: (DoGroup children: [ (Sentence child: (C {(processArg)} {($ VSub_Name "$var")}) terminator: ) ] spids: [792 799] ) spids: [786 790] ) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$css_only"))} {(Lit_Other "]")}) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$body_only"))} {(Lit_Other "]")}) (C {(usage)}) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) (If arms: [ (if_arm cond: [ (Sentence child: (Pipeline children: [ (SimpleCommand words: [{(sed)} {(--version)}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(/dev/null)} spids: [838] ) (Redir op_id: Redir_GreatAnd fd: 2 arg_word: {(1)} spids: [841] ) ] ) ] negated: True ) terminator: ) ] action: [ (If arms: [ (if_arm cond: [ (Sentence child: (SimpleCommand words: [{(gsed)} {(--version)}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(/dev/null)} spids: [854] ) (Redir op_id: Redir_GreatAnd fd: 2 arg_word: {(1)} spids: [857] ) ] ) terminator: ) ] action: [(C {(alias)} {(Lit_VarLike "sed=") (gsed)})] spids: [-1 861] ) ] else_action: [ (SimpleCommand words: [{(echo)} {(DQ ("Error, can't find an acceptable GNU sed."))}] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[879])] ) (C {(exit)} {(1)}) ] spids: [870 888] ) ] spids: [-1 845] ) ] spids: [-1 890] ) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$css_only"))} {(Lit_Other "]")}) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$body_only"))} {(Lit_Other "]")}) (C {(printf)} {(SQ <"%s">)} { (DQ ("\n") ("\n") (") (Content-Type) (EscapedLiteralPart token:) (" content=") (EscapedLiteralPart token:) ("text/html; charset=utf-8") (EscapedLiteralPart token:) ("/>\n") ("\n"> <"\n"> <"\n"> <"\n"> <"
\n">)}
        )
      ]
      op_id: Op_DPipe
    )
    (AndOr
      children: [
        (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$body_only"))} {(Lit_Other "]")})
        (SimpleCommand
          words: [{(printf)} {(SQ <"%s\\n">)} {(SQ <"Be sure to use  and 
">)}]
          redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[1638])]
        )
      ]
      op_id: Op_DAmp
    )
    (Assignment
      keyword: Assign_None
      pairs: [(assign_pair lhs:(LhsName name:p) op:Equal rhs:{(SQ <"\\x1b\\[">)} spids:[1642])]
      spids: [1642]
    )
    (Pipeline
      children: [
        (C {(sed)} 
          {
            (DQ ("\n") ("# escape ampersand and quote\n") ("s#&#") 
              (EscapedLiteralPart token:) ("amp;#g; s#") (EscapedLiteralPart token:) ("#") 
              (EscapedLiteralPart token:) ("quot;#g;\n") ("s#") (EscapedLiteralPart token:) ("1b[^") 
              (EscapedLiteralPart token:) ("1b]*") (EscapedLiteralPart token:) (1b) 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("#g  # strip anything between ") 
              (EscapedLiteralPart token:) (" and ST\n") ("s#") (EscapedLiteralPart token:) ("1b][0-9]*;[^") 
              (EscapedLiteralPart token:) ("]*") (EscapedLiteralPart token:) ("##g # strip any OSC (xterm title etc.)\n") 
              ("\n") ("s#") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("## # strip trailing ") (EscapedLiteralPart token:) ("\n") ("\n") 
              ("# strip other non SGR escape sequences\n") ("s#[") (EscapedLiteralPart token:) ("07]##g\n") ("s#") 
              (EscapedLiteralPart token:) ("1b[]>=") (EscapedLiteralPart token:) ("[0-9;]*##g\n") ("s#") 
              (EscapedLiteralPart token:) ("1bP+.") (EscapedLiteralPart token:) (5) 
              (EscapedLiteralPart token:) ("##g\n") ("# Mark cursor positioning codes ") (EscapedLiteralPart token:) 
              ("Jr;c;\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,2") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("G#") (EscapedLiteralPart token:) ("J;") 
              (EscapedLiteralPart token:) (";#g\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,2") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (";") (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,2") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("H#") (EscapedLiteralPart token:) (J) 
              (EscapedLiteralPart token:) (";") (EscapedLiteralPart token:) (";#g\n") ("\n") ("# Mark clear as ") 
              (EscapedLiteralPart token:) ("Cn where n=1 is screen and n=0 is to end-of-line\n") ("s#") (${ VSub_Name p) ("H#") 
              (EscapedLiteralPart token:) ("C1;#g\n") ("s#") (${ VSub_Name p) ("K#") (EscapedLiteralPart token:) ("C0;#g\n") 
              ("# Mark Cursor move columns as ") (EscapedLiteralPart token:) ("Mn where n is +ve for right, -ve for left\n") 
              ("s#") (${ VSub_Name p) ("C#") (EscapedLiteralPart token:) ("M1;#g\n") ("s#") 
              (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("C#") (EscapedLiteralPart token:) (M) 
              (EscapedLiteralPart token:) (";#g\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("D#") (EscapedLiteralPart token:) (M-) 
              (EscapedLiteralPart token:) (";#g\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("P#") (EscapedLiteralPart token:) (X) 
              (EscapedLiteralPart token:) (";#g\n") ("\n") ("s#") (${ VSub_Name p) ("[0-9;?]*[^0-9;?m]##g\n") ("\n")
            )
          }
        )
        (C {(sed)} 
          {
            (DQ ("\n") ("# escape HTML (ampersand and quote done above)\n") ("s#>#") 
              (EscapedLiteralPart token:) ("gt;#g; s#<#") (EscapedLiteralPart token:) ("lt;#g;\n") ("\n") 
              ("# normalize SGR codes a little\n") ("\n") ("# split 256 colors out and mark so that they're not\n") 
              ("# recognised by the following 'split combined' line\n") (":e\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) ("[0-9;]") 
              (EscapedLiteralPart token:) ("1,") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (";") (EscapedLiteralPart token:) ("[34]8;5;[0-9]") 
              (EscapedLiteralPart token:) ("1,3") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) (EscapedLiteralPart token:) (m) (${ VSub_Name p) ("\u00ac") 
              (EscapedLiteralPart token:) ("m#g; t e\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) 
              ("[34]8;5;[0-9]") (EscapedLiteralPart token:) ("1,3") 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) ("\u00ac") 
              (EscapedLiteralPart token:) ("m#g;\n") ("\n") (":c\n") ("s#") (${ VSub_Name p) (EscapedLiteralPart token:) 
              ("[0-9]") (EscapedLiteralPart token:) ("1,") 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) (";") 
              (EscapedLiteralPart token:) ("[0-9;]") (EscapedLiteralPart token:) ("1,") 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) 
              (EscapedLiteralPart token:) (m) (${ VSub_Name p) (EscapedLiteralPart token:) 
              ("m#g; t c   # split combined\n") ("s#") (${ VSub_Name p) (0) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) ("#") (${ VSub_Name p) (EscapedLiteralPart token:) 
              ("#g                                 #strip leading 0\n") ("s#") (${ VSub_Name p) (1m) (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (${ VSub_Name p) ("[4579]m") (EscapedLiteralPart token:) ("*") 
              (EscapedLiteralPart token:) ("#") (EscapedLiteralPart token:) (${ VSub_Name p) 
              ("1m#g                   #bold last (with clr)\n") ("s#") (${ VSub_Name p) ("m#") (${ VSub_Name p) 
              ("0m#g                                          #add leading 0 to norm\n") ("\n") ("# undo any 256 color marking\n") ("s#") (${ VSub_Name p) ("\u00ac") 
              (EscapedLiteralPart token:) ("[34]8;5;[0-9]") (EscapedLiteralPart token:) ("1,3") 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) 
              (EscapedLiteralPart token:) ("m#g;\n") ("\n") ("# map 16 color codes to color + bold\n") ("s#") (${ VSub_Name p) (9) 
              (EscapedLiteralPart token:) ("[0-7]") (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) (3) 
              (EscapedLiteralPart token:) (m) (${ VSub_Name p) ("1m#g;\n") ("s#") (${ VSub_Name p) (10) 
              (EscapedLiteralPart token:) ("[0-7]") (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) (4) 
              (EscapedLiteralPart token:) (m) (${ VSub_Name p) ("1m#g;\n") ("\n") ("# change 'reset' code to ") 
              (EscapedLiteralPart token:) ("R\n") ("s#") (${ VSub_Name p) ("0m#") (EscapedLiteralPart token:) ("R;#g\n")
            )
          }
        )
        (C {(sed)} 
          {
            (DQ ("\n") ("# common combinations to minimise html (optional)\n") (":f\n") ("s#") 
              (${ VSub_Name p) ("3[0-7]m") (${ VSub_Name p) (3) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) (3) (EscapedLiteralPart token:) ("m#g; t f\n") (":b\n") 
              ("s#") (${ VSub_Name p) ("4[0-7]m") (${ VSub_Name p) (4) (EscapedLiteralPart token:) 
              ("[0-7]") (EscapedLiteralPart token:) ("m#") (${ VSub_Name p) (4) 
              (EscapedLiteralPart token:) ("m#g; t b\n") ("s#") (${ VSub_Name p) (3) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) (m) (${ VSub_Name p) (4) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) ("m#) (f) 
              (EscapedLiteralPart token:) (" b") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) (4) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) (m) (${ VSub_Name p) (3) (EscapedLiteralPart token:) ("[0-7]") 
              (EscapedLiteralPart token:) ("m#) (f) 
              (EscapedLiteralPart token:) (" b") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (">#g\n") ("\n") ("s#") (${ VSub_Name p) ("1m#) (bold) (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) 
              ("4m#) (underline) 
              (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) ("5m#) 
              (blink) (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) ("7m#) (reverse) (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) 
              ("9m#) (line-through) 
              (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) (3) (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("m#) (f) 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) (4) 
              (EscapedLiteralPart token:) ("[0-9]") (EscapedLiteralPart token:) ("m#) (b) (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (">#g\n") ("\n") ("s#") (${ VSub_Name p) ("38;5;") (EscapedLiteralPart token:) 
              ("[0-9]") (EscapedLiteralPart token:) ("1,3") 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("m#) (ef) (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) (">#g\n") ("s#") (${ VSub_Name p) ("48;5;") (EscapedLiteralPart token:) ("[0-9]") 
              (EscapedLiteralPart token:) ("1,3") (EscapedLiteralPart token:) 
              (EscapedLiteralPart token:) ("m#) (eb) 
              (EscapedLiteralPart token:) (EscapedLiteralPart token:) (">#g\n") ("\n") ("s#") (${ VSub_Name p) 
              ("[0-9;]*m##g # strip unhandled codes\n")
            )
          }
        )
        (C {(sed)} 
          {
            (DQ ("\n") ("# change 'smacs' and 'rmacs' to ") 
              (EscapedLiteralPart token:) ("T1 and ") (EscapedLiteralPart token:) ("T0 to simplify matching.\n") ("s#") 
              (EscapedLiteralPart token:) ("1b(0#") (EscapedLiteralPart token:) ("T1;#g;\n") ("s#") 
              (EscapedLiteralPart token:) ("0E#") (EscapedLiteralPart token:) ("T1;#g;\n") ("\n") ("s#") 
              (EscapedLiteralPart token:) ("1b(B#") (EscapedLiteralPart token:) ("T0;#g\n") ("s#") 
              (EscapedLiteralPart token:) ("0F#") (EscapedLiteralPart token:) ("T0;#g\n")
            )
          }
        )
        (Subshell
          child: 
            (C {(gawk)} 
              {
                (SQ <"\n"> <"function dump_line(l,del,c,blanks,ret) {\n"> <"  for(c=1;c 
                  <"    if ((c SUBSEP l) in attr || length(cur)) {\n"> <"      ret = ret blanks fixas(cur,attr[c,l])\n"> <"      if(del) delete attr[c,l]\n"> 
                  <"      blanks=\"\"\n"> <"    }\n"> <"    if ((c SUBSEP l) in dump) {\n"> <"      ret=ret blanks dump[c,l]\n"> 
                  <"      if(del) delete dump[c,l]\n"> <"      blanks=\"\"\n"> <"    } else blanks=blanks \" \"\n"> <"  }\n"> 
                  <"  if(length(cur)) ret=ret blanks\n"> <"  return ret\n"> <"}\n"> <"\n"> <"function dump_screen(l,ret) {\n"> <"  for(l=1;l<=maxY;l++)\n"> 
                  <"    ret=ret dump_line(l,0) \"\\n\"\n"> <"  return ret fixas(cur, \"\")\n"> <"}\n"> <"\n"> <"function atos(a,i,ret) {\n"> 
                  <"  for(i=1;i<=length(a);i++) if(i in a) ret=ret a[i]\n"> <"  return ret\n"> <"}\n"> <"\n"> <"function fixas(a,s,spc,i,attr,rm,ret) {\n"> <"  spc=length(a)\n"> 
                  <"  l=split(s,attr,\">\")\n"> <"  for(i=1;i<=spc;i++) {\n"> <"    rm=rm?rm:(a[i]!=attr[i]\">\")\n"> <"    if(rm) {\n"> 
                  <"      ret=ret \"\"\n"> <"      delete a[i];\n"> <"    }\n"> <"  }\n"> <"  for(i=1;i <"    attr[i]=attr[i]\">\"\n"> 
                  <"    if(a[i]!=attr[i]) {\n"> <"      a[i]=attr[i]\n"> <"      ret = ret attr[i]\n"> <"    }\n"> <"  }\n"> <"  return ret\n"> <"}\n"> 
                  <"\n"> <"function encode(string,start,end,i,ret,pos,sc,buf) {\n"> <"   if(!end) end=length(string);\n"> 
                  <"   if(!start) start=1;\n"> <"   state=3\n"> <"   for(i=1;i<=length(string);i++) {\n"> <"     c=substr(string,i,1)\n"> 
                  <"     if(state==2) {\n"> <"       sc=sc c\n"> <"       if(c==\";\") {\n"> <"          c=sc\n"> <"          state=last_mode\n"> 
                  <"       } else continue\n"> <"     } else {\n"> <"       if(c==\"\\r\") { x=1; continue }\n"> <"       if(c==\"<\") {\n"> 
                  <"         # Change attributes - store current active\n"> <"         # attributes in span array\n"> <"         split(substr(string,i),cord,\">\");\n"> 
                  <"         i+=length(cord[1])\n"> <"         span[++spc]=cord[1] \">\"\n"> <"         continue\n"> <"       }\n"> 
                  <"       else if(c==\"&\") {\n"> <"         # All goes to single position till we see a semicolon\n"> <"         sc=c\n"> 
                  <"         state=2\n"> <"         continue\n"> <"       }\n"> <"       else if(c==\"\\b\") {\n"> 
                  <"          # backspace move insertion point back 1\n"> <"          if(spc) attr[x,y]=atos(span)\n"> <"          x=x>1?x-1:1\n"> <"          continue\n"> 
                  <"       }\n"> <"       else if(c==\"\\\"\") {\n"> <"          split(substr(string,i+2),cord,\";\")\n"> 
                  <"          cc=substr(string,i+1,1);\n"> <"          if(cc==\"T\") {\n"> <"              # Transliterate on/off\n"> 
                  <"              if(cord[1]==1&&state==3) last_mode=state=4\n"> <"              if(cord[1]==0&&state==4) last_mode=state=3\n"> <"          }\n"> 
                  <"          else if(cc==\"C\") {\n"> <"              # Clear\n"> <"              if(cord[1]+0) {\n"> 
                  <"                # Screen - if Recording dump screen\n"> <"                if(dumpStatus==dsActive) ret=ret dump_screen()\n"> 
                  <"                dumpStatus=dsActive\n"> <"                delete dump\n"> <"                delete attr\n"> <"                x=y=1\n"> 
                  <"              } else {\n"> <"                # To end of line\n"> <"                for(pos=x;pos 
                  <"                  dump[pos,y]=\" \"\n"> <"                  if (!spc) delete attr[pos,y]\n"> 
                  <"                  else attr[pos,y]=atos(span)\n"> <"                }\n"> <"              }\n"> <"          }\n"> <"          else if(cc==\"J\") {\n"> 
                  <"              # Jump to x,y\n"> <"              i+=length(cord[2])+1\n"> 
                  <"              # If line is higher - dump previous screen\n"> <"              if(dumpStatus==dsActive&&cord[1] <"                ret=ret dump_screen();\n"> 
                  <"                dumpStatus=dsNew;\n"> <"              }\n"> <"              x=cord[2]\n"> 
                  <"              if(length(cord[1]) && y!=cord[1]){\n"> <"                y=cord[1]\n"> <"                if(y>maxY) maxY=y\n"> 
                  <"                # Change y - start recording\n"> <"                dumpStatus=dumpStatus?dumpStatus:dsReset\n"> <"              }\n"> <"          }\n"> 
                  <"          else if(cc==\"M\") {\n"> <"              # Move left/right on current line\n"> <"              x+=cord[1]\n"> <"          }\n"> 
                  <"          else if(cc==\"X\") {\n"> <"              # delete on right\n"> <"              for(pos=x;pos<=maxX;pos++) {\n"> 
                  <"                nx=pos+cord[1]\n"> <"                if(nx 
                  <"                  if((nx SUBSEP y) in attr) attr[pos,y] = attr[nx,y]\n"> <"                  else delete attr[pos,y]\n"> 
                  <"                  if((nx SUBSEP y) in dump) dump[pos,y] = dump[nx,y]\n"> <"                  else delete dump[pos,y]\n"> <"                } else if(spc) {\n"> 
                  <"                  attr[pos,y]=atos(span)\n"> <"                  dump[pos,y]=\" \"\n"> <"                }\n"> <"              }\n"> 
                  <"          }\n"> <"          else if(cc==\"R\") {\n"> <"              # Reset attributes\n"> 
                  <"              while(spc) delete span[spc--]\n"> <"          }\n"> <"          i+=length(cord[1])+2\n"> <"          continue\n"> <"       }\n"> 
                  <"       else if(state==4&&i>=start&&i<=end&&c in Trans) c=Trans[c]\n"> <"     }\n"> <"     if(dumpStatus==dsReset) {\n"> <"       delete dump\n"> <"       delete attr\n"> 
                  <"       ret=ret\"\\n\"\n"> <"       dumpStatus=dsActive\n"> <"     }\n"> <"     if(dumpStatus==dsNew) {\n"> 
                  <"       # After moving/clearing we are now ready to write\n"> <"       # somthing to the screen so start recording now\n"> <"       ret=ret\"\\n\"\n"> 
                  <"       dumpStatus=dsActive\n"> <"     }\n"> <"     if(dumpStatus==dsActive||dumpStatus==dsOff) {\n"> <"       dump[x,y] = c\n"> 
                  <"       if(!spc) delete attr[x,y]\n"> <"       else attr[x,y] = atos(span)\n"> <"       if(++x>maxX) maxX=x;\n"> <"     }\n"> <"    }\n"> 
                  <"    # End of line if dumping increment y and set x back to first col\n"> <"    x=1\n"> <"    if(!dumpStatus) return ret dump_line(y,1);\n"> <"    else if(++y>maxY) maxY=y;\n"> 
                  <"    return ret\n"> <"}\n"> <"BEGIN{\n"> <"  OFS=FS\n"> <"  # dump screen status\n"> 
                  <"  dsOff=0    # Not dumping screen contents just write output direct\n"> <"  dsNew=1    # Just after move/clear waiting for activity to start recording\n"> 
                  <"  dsReset=2  # Screen cleared build new empty buffer and record\n"> <"  dsActive=3 # Currently recording\n"> <"  F=\"abcdefghijklmnopqrstuvwxyz{}`~\"\n"> 
                  <
"  T=\"\u2592\u2409\u240c\u240d\u240a\u00b0\u00b1\u2424\u240b\u2518\u2510\u250c\u2514\u253c\u23ba\u23bb\u2500\u23bc\u23bd\u251c\u2524\u2534\u252c\u2502\u2264\u2265\u03c0\u00a3\u25c6\u00b7\"\n"
                  > <"  maxX=80\n"> <"  delete cur;\n"> <"  x=y=1\n"> 
                  <"  for(i=1;i<=length(F);i++)Trans[substr(F,i,1)]=substr(T,i,1);\n"> <"}\n"> <"\n"> <"{ $0=encode($0) }\n"> <"1\n"> <"END {\n"> <"  if(dumpStatus) {\n"> 
                  <"    print dump_screen();\n"> <"  }\n"> <"}">
                )
              }
            )
          spids: [2344 2551]
        )
      ]
      negated: False
    )
    (AndOr
      children: [
        (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$body_only"))} {(Lit_Other "]")})
        (C {(printf)} {(SQ <"
\n"> <"\n"> <"\\n">)}) ] op_id: Op_DPipe ) ] )