From be1c74b4f2da24df6a47318f502808dabc371234 Mon Sep 17 00:00:00 2001
Message-Id: <be1c74b4f2da24df6a47318f502808dabc371234.1502293212.git.hahn@univention.de>
From: Philipp Hahn <hahn@univention.de>
Date: Wed, 9 Aug 2017 11:54:00 +0200
Subject: [PATCH] Process character set escape sequence
Organization: Univention GmbH, Bremen, Germany

Some terminals (xterm) supports two different 'character sets' ('G0' and
'G1'), which can be switched with 'SI' (shift in, '\017') and 'SO'
(shift out, '\016'). Each character set can be configured separately
and can be chosen from a list of pre-defined sets like 'ASCII Set' and
'Special Graphics'.

Running `tput sgr0` to reset the terminal returns an escape sequence
starting with 'ESC ( 0', which selects the 'ASCII Set' for 'G0'. This
currently is not understood by the Jenkins AnsiColor plugin.

Filter out those sequences, as they otherwise clutter the output.

<https://www.in-ulm.de/~mascheck/various/alternate_charset/> has a nice
description for characters sets

Signed-off-by: Philipp Hahn <hahn@univention.de>
---
 .../hudson/plugins/ansicolor/AnsiOutputStream.java | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/src/main/java/hudson/plugins/ansicolor/AnsiOutputStream.java b/src/main/java/hudson/plugins/ansicolor/AnsiOutputStream.java
index bc8e6dc..e456dd8 100644
--- a/src/main/java/hudson/plugins/ansicolor/AnsiOutputStream.java
+++ b/src/main/java/hudson/plugins/ansicolor/AnsiOutputStream.java
@@ -63,6 +63,7 @@ public class AnsiOutputStream extends FilterOutputStream {
     private static final int LOOKING_FOR_OSC_COMMAND_END = 6;
     private static final int LOOKING_FOR_OSC_PARAM = 7;
     private static final int LOOKING_FOR_ST = 8;
+    private static final int LOOKING_FOR_CHARSET = 9;
 
     int state = LOOKING_FOR_FIRST_ESC_CHAR;
 
@@ -71,6 +72,8 @@ public class AnsiOutputStream extends FilterOutputStream {
     private static final int SECOND_OSC_CHAR = ']';
     private static final int BEL = 7;
     private static final int SECOND_ST_CHAR = '\\';
+    private static final int SECOND_CHARSET0_CHAR = '(';
+    private static final int SECOND_CHARSET1_CHAR = ')';
 
     // TODO: implement to get perf boost: public void write(byte[] b, int off, int len)
 
@@ -91,6 +94,12 @@ public class AnsiOutputStream extends FilterOutputStream {
                     state = LOOKING_FOR_NEXT_ARG;
                 } else if (data == SECOND_OSC_CHAR) {
                     state = LOOKING_FOR_OSC_COMMAND;
+                } else if (data == SECOND_CHARSET0_CHAR) {
+                    options.add(new Integer('0'));
+                    state = LOOKING_FOR_CHARSET;
+                } else if (data == SECOND_CHARSET1_CHAR) {
+                    options.add(new Integer('1'));
+                    state = LOOKING_FOR_CHARSET;
                 } else {
                     reset(false);
                 }
@@ -193,6 +202,11 @@ public class AnsiOutputStream extends FilterOutputStream {
                     state = LOOKING_FOR_OSC_PARAM;
                 }
                 break;
+
+            case LOOKING_FOR_CHARSET:
+                options.add(new Character((char) data));
+                reset(processCharsetSelect(options));
+                break;
         }
 
         // Is it just too long?
@@ -545,6 +559,21 @@ public class AnsiOutputStream extends FilterOutputStream {
     protected void processUnknownOperatingSystemCommand(int command, String param) {
     }
 
+    /**
+     * Process character set sequence.
+     * @param options
+     * @return true if the charcter set select command was processed.
+     */
+    private boolean processCharsetSelect(ArrayList<Object> options) throws IOException {
+        int set = optionInt(options, 0);
+        char seq = ((Character) options.get(1)).charValue();
+        processCharsetSelect(set, seq);
+        return true;
+    }
+
+    protected void processCharsetSelect(int set, char seq) {
+    }
+
     private int optionInt(ArrayList<Object> options, int index) {
         if (options.size() <= index)
             throw new IllegalArgumentException();
-- 
2.11.0

