• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
3  *
4  * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
5  *
6  * Please visit http://javatelnet.org/ for updates and contact.
7  *
8  * --LICENSE NOTICE--
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  * --LICENSE NOTICE--
23  *
24  */
25 
26 package de.mud.terminal;
27 
28 import java.util.Properties;
29 
30 /**
31  * Implementation of a VT terminal emulation plus ANSI compatible.
32  * <P>
33  * <B>Maintainer:</B> Marcus Meißner
34  *
35  * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
36  */
37 @SuppressWarnings("unused")
38 public abstract class vt320 extends VDUBuffer implements VDUInput {
39 
40   /**
41    * The current version id tag.
42    * <P>
43    * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
44    *
45    */
46   public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $";
47 
48   /** the debug level */
49   private final static int debug = 0;
50   private StringBuilder debugStr;
51 
debug(String notice)52   public abstract void debug(String notice);
53 
54   /**
55    * Write an answer back to the remote host. This is needed to be able to send terminal answers
56    * requests like status and type information.
57    *
58    * @param b
59    *          the array of bytes to be sent
60    */
write(byte[] b)61   public abstract void write(byte[] b);
62 
63   /**
64    * Write an answer back to the remote host. This is needed to be able to send terminal answers
65    * requests like status and type information.
66    *
67    * @param b
68    *          the array of bytes to be sent
69    */
write(int b)70   public abstract void write(int b);
71 
72   /**
73    * Play the beep sound ...
74    */
beep()75   public void beep() { /* do nothing by default */
76   }
77 
78   /**
79    * Convenience function for putString(char[], int, int)
80    */
putString(String s)81   public void putString(String s) {
82     int len = s.length();
83     char[] tmp = new char[len];
84     s.getChars(0, len, tmp, 0);
85     putString(tmp, null, 0, len);
86   }
87 
88   /**
89    * Put string at current cursor position. Moves cursor according to the String. Does NOT wrap.
90    *
91    * @param s
92    *          character array
93    * @param start
94    *          place to start in array
95    * @param len
96    *          number of characters to process
97    */
putString(char[] s, byte[] fullwidths, int start, int len)98   public void putString(char[] s, byte[] fullwidths, int start, int len) {
99     if (len > 0) {
100       // markLine(R, 1);
101       int lastChar = -1;
102       char c;
103       boolean isWide = false;
104 
105       for (int i = 0; i < len; i++) {
106         c = s[start + i];
107         // Shortcut for my favorite ASCII
108         if (c <= 0x7F) {
109           if (lastChar != -1) {
110             putChar((char) lastChar, isWide, false);
111           }
112           lastChar = c;
113           isWide = false;
114         } else if (!Character.isLowSurrogate(c) && !Character.isHighSurrogate(c)) {
115           if (Character.getType(c) == Character.NON_SPACING_MARK) {
116             if (lastChar != -1) {
117               char nc = Precomposer.precompose((char) lastChar, c);
118               putChar(nc, isWide, false);
119               lastChar = -1;
120             }
121           } else {
122             if (lastChar != -1) {
123               putChar((char) lastChar, isWide, false);
124             }
125             lastChar = c;
126             if (fullwidths != null) {
127               isWide = fullwidths[i] == 1;
128             }
129           }
130         }
131       }
132 
133       if (lastChar != -1) {
134         putChar((char) lastChar, isWide, false);
135       }
136 
137       setCursorPosition(C, R);
138       redraw();
139     }
140   }
141 
sendTelnetCommand(byte cmd)142   protected void sendTelnetCommand(byte cmd) {
143 
144   }
145 
146   /**
147    * Sent the changed window size from the terminal to all listeners.
148    */
setWindowSize(int c, int r)149   protected void setWindowSize(int c, int r) {
150     /* To be overridden by Terminal.java */
151   }
152 
153   @Override
setScreenSize(int c, int r, boolean broadcast)154   public void setScreenSize(int c, int r, boolean broadcast) {
155     // int oldrows = height;
156 
157     if (debug > 2) {
158       if (debugStr == null) {
159         debugStr = new StringBuilder();
160       }
161 
162       debugStr.append("setscreensize (").append(c).append(',').append(r).append(',')
163           .append(broadcast).append(')');
164       debug(debugStr.toString());
165       debugStr.setLength(0);
166     }
167 
168     super.setScreenSize(c, r, false);
169 
170     boolean cursorChanged = false;
171 
172     // Don't let the cursor go off the screen.
173     if (C >= c) {
174       C = c - 1;
175       cursorChanged = true;
176     }
177 
178     if (R >= r) {
179       R = r - 1;
180       cursorChanged = true;
181     }
182 
183     if (cursorChanged) {
184       setCursorPosition(C, R);
185       redraw();
186     }
187 
188     if (broadcast) {
189       setWindowSize(c, r); /* broadcast up */
190     }
191   }
192 
193   /**
194    * Create a new vt320 terminal and intialize it with useful settings.
195    */
vt320(int width, int height)196   public vt320(int width, int height) {
197     super(width, height);
198 
199     debugStr = new StringBuilder();
200 
201     setVMS(false);
202     setIBMCharset(false);
203     setTerminalID("vt320");
204     setBufferSize(100);
205     // setBorder(2, false);
206 
207     gx = new char[4];
208     reset();
209 
210     /* top row of numpad */
211     PF1 = "\u001bOP";
212     PF2 = "\u001bOQ";
213     PF3 = "\u001bOR";
214     PF4 = "\u001bOS";
215 
216     /* the 3x2 keyblock on PC keyboards */
217     Insert = new String[4];
218     Remove = new String[4];
219     KeyHome = new String[4];
220     KeyEnd = new String[4];
221     NextScn = new String[4];
222     PrevScn = new String[4];
223     Escape = new String[4];
224     BackSpace = new String[4];
225     TabKey = new String[4];
226     Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
227     Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
228     PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
229     NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
230     KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
231     KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
232     Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
233     if (vms) {
234       BackSpace[1] = "" + (char) 10; // VMS shift deletes word back
235       BackSpace[2] = "\u0018"; // VMS control deletes line back
236       BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete
237     } else {
238       // BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
239       // ConnectBot modifications.
240       BackSpace[0] = "\b";
241       BackSpace[1] = "\u007f";
242       BackSpace[2] = "\u001b[3~";
243       BackSpace[3] = "\u001b[2~";
244     }
245 
246     /* some more VT100 keys */
247     Find = "\u001b[1~";
248     Select = "\u001b[4~";
249     Help = "\u001b[28~";
250     Do = "\u001b[29~";
251 
252     FunctionKey = new String[21];
253     FunctionKey[0] = "";
254     FunctionKey[1] = PF1;
255     FunctionKey[2] = PF2;
256     FunctionKey[3] = PF3;
257     FunctionKey[4] = PF4;
258     /* following are defined differently for vt220 / vt132 ... */
259     FunctionKey[5] = "\u001b[15~";
260     FunctionKey[6] = "\u001b[17~";
261     FunctionKey[7] = "\u001b[18~";
262     FunctionKey[8] = "\u001b[19~";
263     FunctionKey[9] = "\u001b[20~";
264     FunctionKey[10] = "\u001b[21~";
265     FunctionKey[11] = "\u001b[23~";
266     FunctionKey[12] = "\u001b[24~";
267     FunctionKey[13] = "\u001b[25~";
268     FunctionKey[14] = "\u001b[26~";
269     FunctionKey[15] = Help;
270     FunctionKey[16] = Do;
271     FunctionKey[17] = "\u001b[31~";
272     FunctionKey[18] = "\u001b[32~";
273     FunctionKey[19] = "\u001b[33~";
274     FunctionKey[20] = "\u001b[34~";
275 
276     FunctionKeyShift = new String[21];
277     FunctionKeyAlt = new String[21];
278     FunctionKeyCtrl = new String[21];
279 
280     for (int i = 0; i < 20; i++) {
281       FunctionKeyShift[i] = "";
282       FunctionKeyAlt[i] = "";
283       FunctionKeyCtrl[i] = "";
284     }
285     FunctionKeyShift[15] = Find;
286     FunctionKeyShift[16] = Select;
287 
288     TabKey[0] = "\u0009";
289     TabKey[1] = "\u001bOP\u0009";
290     TabKey[2] = TabKey[3] = "";
291 
292     KeyUp = new String[4];
293     KeyUp[0] = "\u001b[A";
294     KeyDown = new String[4];
295     KeyDown[0] = "\u001b[B";
296     KeyRight = new String[4];
297     KeyRight[0] = "\u001b[C";
298     KeyLeft = new String[4];
299     KeyLeft[0] = "\u001b[D";
300     Numpad = new String[10];
301     Numpad[0] = "\u001bOp";
302     Numpad[1] = "\u001bOq";
303     Numpad[2] = "\u001bOr";
304     Numpad[3] = "\u001bOs";
305     Numpad[4] = "\u001bOt";
306     Numpad[5] = "\u001bOu";
307     Numpad[6] = "\u001bOv";
308     Numpad[7] = "\u001bOw";
309     Numpad[8] = "\u001bOx";
310     Numpad[9] = "\u001bOy";
311     KPMinus = PF4;
312     KPComma = "\u001bOl";
313     KPPeriod = "\u001bOn";
314     KPEnter = "\u001bOM";
315 
316     NUMPlus = new String[4];
317     NUMPlus[0] = "+";
318     NUMDot = new String[4];
319     NUMDot[0] = ".";
320   }
321 
setBackspace(int type)322   public void setBackspace(int type) {
323     switch (type) {
324     case DELETE_IS_DEL:
325       BackSpace[0] = "\u007f";
326       BackSpace[1] = "\b";
327       break;
328     case DELETE_IS_BACKSPACE:
329       BackSpace[0] = "\b";
330       BackSpace[1] = "\u007f";
331       break;
332     }
333   }
334 
335   /**
336    * Create a default vt320 terminal with 80 columns and 24 lines.
337    */
vt320()338   public vt320() {
339     this(80, 24);
340   }
341 
342   /**
343    * Terminal is mouse-aware and requires (x,y) coordinates of on the terminal (character
344    * coordinates) and the button clicked.
345    *
346    * @param x
347    * @param y
348    * @param modifiers
349    */
mousePressed(int x, int y, int modifiers)350   public void mousePressed(int x, int y, int modifiers) {
351     if (mouserpt == 0) {
352       return;
353     }
354 
355     int mods = modifiers;
356     mousebut = 3;
357     if ((mods & 16) == 16) {
358       mousebut = 0;
359     }
360     if ((mods & 8) == 8) {
361       mousebut = 1;
362     }
363     if ((mods & 4) == 4) {
364       mousebut = 2;
365     }
366 
367     int mousecode;
368     if (mouserpt == 9) {
369       mousecode = 0x20 | mousebut;
370     } else {
371       mousecode = mousebut | 0x20 | ((mods & 7) << 2);
372     }
373 
374     byte b[] = new byte[6];
375 
376     b[0] = 27;
377     b[1] = (byte) '[';
378     b[2] = (byte) 'M';
379     b[3] = (byte) mousecode;
380     b[4] = (byte) (0x20 + x + 1);
381     b[5] = (byte) (0x20 + y + 1);
382 
383     write(b); // FIXME: writeSpecial here
384   }
385 
386   /**
387    * Terminal is mouse-aware and requires the coordinates and button of the release.
388    *
389    * @param x
390    * @param y
391    * @param modifiers
392    */
mouseReleased(int x, int y, int modifiers)393   public void mouseReleased(int x, int y, int modifiers) {
394     if (mouserpt == 0) {
395       return;
396     }
397 
398     /*
399      * problem is tht modifiers still have the released button set in them. int mods = modifiers;
400      * mousebut = 3; if ((mods & 16)==16) mousebut=0; if ((mods & 8)==8 ) mousebut=1; if ((mods &
401      * 4)==4 ) mousebut=2;
402      */
403 
404     int mousecode;
405     if (mouserpt == 9) {
406       mousecode = 0x20 + mousebut; /* same as press? appears so. */
407     } else {
408       mousecode = '#';
409     }
410 
411     byte b[] = new byte[6];
412     b[0] = 27;
413     b[1] = (byte) '[';
414     b[2] = (byte) 'M';
415     b[3] = (byte) mousecode;
416     b[4] = (byte) (0x20 + x + 1);
417     b[5] = (byte) (0x20 + y + 1);
418     write(b); // FIXME: writeSpecial here
419     mousebut = 0;
420   }
421 
422   /** we should do localecho (passed from other modules). false is default */
423   private boolean localecho = false;
424 
425   /**
426    * Enable or disable the local echo property of the terminal.
427    *
428    * @param echo
429    *          true if the terminal should echo locally
430    */
setLocalEcho(boolean echo)431   public void setLocalEcho(boolean echo) {
432     localecho = echo;
433   }
434 
435   /**
436    * Enable the VMS mode of the terminal to handle some things differently for VMS hosts.
437    *
438    * @param vms
439    *          true for vms mode, false for normal mode
440    */
setVMS(boolean vms)441   public void setVMS(boolean vms) {
442     this.vms = vms;
443   }
444 
445   /**
446    * Enable the usage of the IBM character set used by some BBS's. Special graphical character are
447    * available in this mode.
448    *
449    * @param ibm
450    *          true to use the ibm character set
451    */
setIBMCharset(boolean ibm)452   public void setIBMCharset(boolean ibm) {
453     useibmcharset = ibm;
454   }
455 
456   /**
457    * Override the standard key codes used by the terminal emulation.
458    *
459    * @param codes
460    *          a properties object containing key code definitions
461    */
setKeyCodes(Properties codes)462   public void setKeyCodes(Properties codes) {
463     String res, prefixes[] = { "", "S", "C", "A" };
464     int i;
465 
466     for (i = 0; i < 10; i++) {
467       res = codes.getProperty("NUMPAD" + i);
468       if (res != null) {
469         Numpad[i] = unEscape(res);
470       }
471     }
472     for (i = 1; i < 20; i++) {
473       res = codes.getProperty("F" + i);
474       if (res != null) {
475         FunctionKey[i] = unEscape(res);
476       }
477       res = codes.getProperty("SF" + i);
478       if (res != null) {
479         FunctionKeyShift[i] = unEscape(res);
480       }
481       res = codes.getProperty("CF" + i);
482       if (res != null) {
483         FunctionKeyCtrl[i] = unEscape(res);
484       }
485       res = codes.getProperty("AF" + i);
486       if (res != null) {
487         FunctionKeyAlt[i] = unEscape(res);
488       }
489     }
490     for (i = 0; i < 4; i++) {
491       res = codes.getProperty(prefixes[i] + "PGUP");
492       if (res != null) {
493         PrevScn[i] = unEscape(res);
494       }
495       res = codes.getProperty(prefixes[i] + "PGDOWN");
496       if (res != null) {
497         NextScn[i] = unEscape(res);
498       }
499       res = codes.getProperty(prefixes[i] + "END");
500       if (res != null) {
501         KeyEnd[i] = unEscape(res);
502       }
503       res = codes.getProperty(prefixes[i] + "HOME");
504       if (res != null) {
505         KeyHome[i] = unEscape(res);
506       }
507       res = codes.getProperty(prefixes[i] + "INSERT");
508       if (res != null) {
509         Insert[i] = unEscape(res);
510       }
511       res = codes.getProperty(prefixes[i] + "REMOVE");
512       if (res != null) {
513         Remove[i] = unEscape(res);
514       }
515       res = codes.getProperty(prefixes[i] + "UP");
516       if (res != null) {
517         KeyUp[i] = unEscape(res);
518       }
519       res = codes.getProperty(prefixes[i] + "DOWN");
520       if (res != null) {
521         KeyDown[i] = unEscape(res);
522       }
523       res = codes.getProperty(prefixes[i] + "LEFT");
524       if (res != null) {
525         KeyLeft[i] = unEscape(res);
526       }
527       res = codes.getProperty(prefixes[i] + "RIGHT");
528       if (res != null) {
529         KeyRight[i] = unEscape(res);
530       }
531       res = codes.getProperty(prefixes[i] + "ESCAPE");
532       if (res != null) {
533         Escape[i] = unEscape(res);
534       }
535       res = codes.getProperty(prefixes[i] + "BACKSPACE");
536       if (res != null) {
537         BackSpace[i] = unEscape(res);
538       }
539       res = codes.getProperty(prefixes[i] + "TAB");
540       if (res != null) {
541         TabKey[i] = unEscape(res);
542       }
543       res = codes.getProperty(prefixes[i] + "NUMPLUS");
544       if (res != null) {
545         NUMPlus[i] = unEscape(res);
546       }
547       res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
548       if (res != null) {
549         NUMDot[i] = unEscape(res);
550       }
551     }
552   }
553 
554   /**
555    * Set the terminal id used to identify this terminal.
556    *
557    * @param terminalID
558    *          the id string
559    */
setTerminalID(String terminalID)560   public void setTerminalID(String terminalID) {
561     this.terminalID = terminalID;
562 
563     if (terminalID.equals("scoansi")) {
564       FunctionKey[1] = "\u001b[M";
565       FunctionKey[2] = "\u001b[N";
566       FunctionKey[3] = "\u001b[O";
567       FunctionKey[4] = "\u001b[P";
568       FunctionKey[5] = "\u001b[Q";
569       FunctionKey[6] = "\u001b[R";
570       FunctionKey[7] = "\u001b[S";
571       FunctionKey[8] = "\u001b[T";
572       FunctionKey[9] = "\u001b[U";
573       FunctionKey[10] = "\u001b[V";
574       FunctionKey[11] = "\u001b[W";
575       FunctionKey[12] = "\u001b[X";
576       FunctionKey[13] = "\u001b[Y";
577       FunctionKey[14] = "?";
578       FunctionKey[15] = "\u001b[a";
579       FunctionKey[16] = "\u001b[b";
580       FunctionKey[17] = "\u001b[c";
581       FunctionKey[18] = "\u001b[d";
582       FunctionKey[19] = "\u001b[e";
583       FunctionKey[20] = "\u001b[f";
584       PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
585       NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
586       // more theoretically.
587     }
588   }
589 
setAnswerBack(String ab)590   public void setAnswerBack(String ab) {
591     answerBack = unEscape(ab);
592   }
593 
594   /**
595    * Get the terminal id used to identify this terminal.
596    */
getTerminalID()597   public String getTerminalID() {
598     return terminalID;
599   }
600 
601   /**
602    * A small conveniance method thar converts the string to a byte array for sending.
603    *
604    * @param s
605    *          the string to be sent
606    */
write(String s, boolean doecho)607   private boolean write(String s, boolean doecho) {
608     if (debug > 2) {
609       debugStr.append("write(|").append(s).append("|,").append(doecho);
610       debug(debugStr.toString());
611       debugStr.setLength(0);
612     }
613     if (s == null) {
614       return true;
615       /*
616        * NOTE: getBytes() honours some locale, it *CONVERTS* the string. However, we output only
617        * 7bit stuff towards the target, and *some* 8 bit control codes. We must not mess up the
618        * latter, so we do hand by hand copy.
619        */
620     }
621 
622     byte arr[] = new byte[s.length()];
623     for (int i = 0; i < s.length(); i++) {
624       arr[i] = (byte) s.charAt(i);
625     }
626     write(arr);
627 
628     if (doecho) {
629       putString(s);
630     }
631     return true;
632   }
633 
write(int s, boolean doecho)634   private boolean write(int s, boolean doecho) {
635     if (debug > 2) {
636       debugStr.append("write(|").append(s).append("|,").append(doecho);
637       debug(debugStr.toString());
638       debugStr.setLength(0);
639     }
640 
641     write(s);
642 
643     // TODO check if character is wide
644     if (doecho) {
645       putChar((char) s, false, false);
646     }
647     return true;
648   }
649 
write(String s)650   private boolean write(String s) {
651     return write(s, localecho);
652   }
653 
654   // ===================================================================
655   // the actual terminal emulation code comes here:
656   // ===================================================================
657 
658   private String terminalID = "vt320";
659   private String answerBack = "Use Terminal.answerback to set ...\n";
660 
661   // X - COLUMNS, Y - ROWS
662   int R, C;
663   int attributes = 0;
664 
665   int Sc, Sr, Sa, Stm, Sbm;
666   char Sgr, Sgl;
667   char Sgx[];
668 
669   int insertmode = 0;
670   int statusmode = 0;
671   boolean vt52mode = false;
672   boolean keypadmode = false; /* false - numeric, true - application */
673   boolean output8bit = false;
674   int normalcursor = 0;
675   boolean moveoutsidemargins = true;
676   boolean wraparound = true;
677   boolean sendcrlf = true;
678   boolean capslock = false;
679   boolean numlock = false;
680   int mouserpt = 0;
681   byte mousebut = 0;
682 
683   boolean useibmcharset = false;
684 
685   int lastwaslf = 0;
686   boolean usedcharsets = false;
687 
688   private final static char ESC = 27;
689   private final static char IND = 132;
690   private final static char NEL = 133;
691   private final static char RI = 141;
692   private final static char SS2 = 142;
693   private final static char SS3 = 143;
694   private final static char DCS = 144;
695   private final static char HTS = 136;
696   private final static char CSI = 155;
697   private final static char OSC = 157;
698   private final static int TSTATE_DATA = 0;
699   private final static int TSTATE_ESC = 1; /* ESC */
700   private final static int TSTATE_CSI = 2; /* ESC [ */
701   private final static int TSTATE_DCS = 3; /* ESC P */
702   private final static int TSTATE_DCEQ = 4; /* ESC [? */
703   private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
704   private final static int TSTATE_OSC = 6; /* ESC ] */
705   private final static int TSTATE_SETG0 = 7; /* ESC (? */
706   private final static int TSTATE_SETG1 = 8; /* ESC )? */
707   private final static int TSTATE_SETG2 = 9; /* ESC *? */
708   private final static int TSTATE_SETG3 = 10; /* ESC +? */
709   private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
710   private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
711   private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
712   private final static int TSTATE_VT52X = 14;
713   private final static int TSTATE_VT52Y = 15;
714   private final static int TSTATE_CSI_TICKS = 16;
715   private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
716   private final static int TSTATE_TITLE = 18; /* xterm title */
717 
718   /* Keys we support */
719   public final static int KEY_PAUSE = 1;
720   public final static int KEY_F1 = 2;
721   public final static int KEY_F2 = 3;
722   public final static int KEY_F3 = 4;
723   public final static int KEY_F4 = 5;
724   public final static int KEY_F5 = 6;
725   public final static int KEY_F6 = 7;
726   public final static int KEY_F7 = 8;
727   public final static int KEY_F8 = 9;
728   public final static int KEY_F9 = 10;
729   public final static int KEY_F10 = 11;
730   public final static int KEY_F11 = 12;
731   public final static int KEY_F12 = 13;
732   public final static int KEY_UP = 14;
733   public final static int KEY_DOWN = 15;
734   public final static int KEY_LEFT = 16;
735   public final static int KEY_RIGHT = 17;
736   public final static int KEY_PAGE_DOWN = 18;
737   public final static int KEY_PAGE_UP = 19;
738   public final static int KEY_INSERT = 20;
739   public final static int KEY_DELETE = 21;
740   public final static int KEY_BACK_SPACE = 22;
741   public final static int KEY_HOME = 23;
742   public final static int KEY_END = 24;
743   public final static int KEY_NUM_LOCK = 25;
744   public final static int KEY_CAPS_LOCK = 26;
745   public final static int KEY_SHIFT = 27;
746   public final static int KEY_CONTROL = 28;
747   public final static int KEY_ALT = 29;
748   public final static int KEY_ENTER = 30;
749   public final static int KEY_NUMPAD0 = 31;
750   public final static int KEY_NUMPAD1 = 32;
751   public final static int KEY_NUMPAD2 = 33;
752   public final static int KEY_NUMPAD3 = 34;
753   public final static int KEY_NUMPAD4 = 35;
754   public final static int KEY_NUMPAD5 = 36;
755   public final static int KEY_NUMPAD6 = 37;
756   public final static int KEY_NUMPAD7 = 38;
757   public final static int KEY_NUMPAD8 = 39;
758   public final static int KEY_NUMPAD9 = 40;
759   public final static int KEY_DECIMAL = 41;
760   public final static int KEY_ADD = 42;
761   public final static int KEY_ESCAPE = 43;
762 
763   public final static int DELETE_IS_DEL = 0;
764   public final static int DELETE_IS_BACKSPACE = 1;
765 
766   /*
767    * The graphics charsets B - default ASCII A - ISO Latin 1 0 - DEC SPECIAL < - User defined ....
768    */
769   char gx[];
770   char gl; // GL (left charset)
771   char gr; // GR (right charset)
772   int onegl; // single shift override for GL.
773 
774   // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which
775   // is not in linedrawing). Got from experimenting with scoadmin.
776   private final static String scoansi_acs =
777       "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d";
778   // array to store DEC Special -> Unicode mapping
779   // Unicode DEC Unicode name (DEC name)
780   private static char DECSPECIAL[] = { '\u0040', // 5f blank
781     '\u2666', // 60 black diamond
782     '\u2592', // 61 grey square
783     '\u2409', // 62 Horizontal tab (ht) pict. for control
784     '\u240c', // 63 Form Feed (ff) pict. for control
785     '\u240d', // 64 Carriage Return (cr) pict. for control
786     '\u240a', // 65 Line Feed (lf) pict. for control
787     '\u00ba', // 66 Masculine ordinal indicator
788     '\u00b1', // 67 Plus or minus sign
789     '\u2424', // 68 New Line (nl) pict. for control
790     '\u240b', // 69 Vertical Tab (vt) pict. for control
791     '\u2518', // 6a Forms light up and left
792     '\u2510', // 6b Forms light down and left
793     '\u250c', // 6c Forms light down and right
794     '\u2514', // 6d Forms light up and right
795     '\u253c', // 6e Forms light vertical and horizontal
796     '\u2594', // 6f Upper 1/8 block (Scan 1)
797     '\u2580', // 70 Upper 1/2 block (Scan 3)
798     '\u2500', // 71 Forms light horizontal or ?em dash? (Scan 5)
799     '\u25ac', // 72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
800     '\u005f', // 73 \u005f underscore or \u2581 lower 1/8 (Scan 9)
801     '\u251c', // 74 Forms light vertical and right
802     '\u2524', // 75 Forms light vertical and left
803     '\u2534', // 76 Forms light up and horizontal
804     '\u252c', // 77 Forms light down and horizontal
805     '\u2502', // 78 vertical bar
806     '\u2264', // 79 less than or equal
807     '\u2265', // 7a greater than or equal
808     '\u00b6', // 7b paragraph
809     '\u2260', // 7c not equal
810     '\u00a3', // 7d Pound Sign (british)
811     '\u00b7' // 7e Middle Dot
812       };
813 
814   /** Strings to send on function key pressing */
815   private String Numpad[];
816   private String FunctionKey[];
817   private String FunctionKeyShift[];
818   private String FunctionKeyCtrl[];
819   private String FunctionKeyAlt[];
820   private String TabKey[];
821   private String KeyUp[], KeyDown[], KeyLeft[], KeyRight[];
822   private String KPMinus, KPComma, KPPeriod, KPEnter;
823   private String PF1, PF2, PF3, PF4;
824   private String Help, Do, Find, Select;
825 
826   private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
827   private String Escape[], BackSpace[], NUMDot[], NUMPlus[];
828 
829   private String osc, dcs; /* to memorize OSC & DCS control sequence */
830 
831   /** vt320 state variable (internal) */
832   private int term_state = TSTATE_DATA;
833   /** in vms mode, set by Terminal.VMS property */
834   private boolean vms = false;
835   /** Tabulators */
836   private byte[] Tabs;
837   /** The list of integers as used by CSI */
838   private int[] DCEvars = new int[30];
839   private int DCEvar;
840 
841   /**
842    * Replace escape code characters (backslash + identifier) with their respective codes.
843    *
844    * @param tmp
845    *          the string to be parsed
846    * @return a unescaped string
847    */
unEscape(String tmp)848   static String unEscape(String tmp) {
849     int idx = 0, oldidx = 0;
850     String cmd;
851     // f.println("unescape("+tmp+")");
852     cmd = "";
853     while ((idx = tmp.indexOf('\\', oldidx)) >= 0 && ++idx <= tmp.length()) {
854       cmd += tmp.substring(oldidx, idx - 1);
855       if (idx == tmp.length()) {
856         return cmd;
857       }
858       switch (tmp.charAt(idx)) {
859       case 'b':
860         cmd += "\b";
861         break;
862       case 'e':
863         cmd += "\u001b";
864         break;
865       case 'n':
866         cmd += "\n";
867         break;
868       case 'r':
869         cmd += "\r";
870         break;
871       case 't':
872         cmd += "\t";
873         break;
874       case 'v':
875         cmd += "\u000b";
876         break;
877       case 'a':
878         cmd += "\u0012";
879         break;
880       default:
881         if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) {
882           int i;
883           for (i = idx; i < tmp.length(); i++) {
884             if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9')) {
885               break;
886             }
887           }
888           cmd += (char) Integer.parseInt(tmp.substring(idx, i));
889           idx = i - 1;
890         } else {
891           cmd += tmp.substring(idx, ++idx);
892         }
893         break;
894       }
895       oldidx = ++idx;
896     }
897     if (oldidx <= tmp.length()) {
898       cmd += tmp.substring(oldidx);
899     }
900     return cmd;
901   }
902 
903   /**
904    * A small conveniance method thar converts a 7bit string to the 8bit version depending on
905    * VT52/Output8Bit mode.
906    *
907    * @param s
908    *          the string to be sent
909    */
writeSpecial(String s)910   private boolean writeSpecial(String s) {
911     if (s == null) {
912       return true;
913     }
914     if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) {
915       if (vt52mode) {
916         if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) {
917           s = "\u001b" + s.substring(2); /* ESC x */
918         } else {
919           s = "\u001b?" + s.substring(2); /* ESC ? x */
920         }
921       } else {
922         if (output8bit) {
923           s = "\u008f" + s.substring(2); /* SS3 x */
924         } /* else keep string as it is */
925       }
926     }
927     if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) {
928       if (output8bit) {
929         s = "\u009b" + s.substring(2); /* CSI ... */
930       } /* else keep */
931     }
932     return write(s, false);
933   }
934 
935   /**
936    * main keytyping event handler...
937    */
keyPressed(int keyCode, char keyChar, int modifiers)938   public void keyPressed(int keyCode, char keyChar, int modifiers) {
939     boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
940     boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
941     boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
942 
943     if (debug > 1) {
944       debugStr.append("keyPressed(").append(keyCode).append(", ").append((int) keyChar)
945           .append(", ").append(modifiers).append(')');
946       debug(debugStr.toString());
947       debugStr.setLength(0);
948     }
949 
950     int xind;
951     String fmap[];
952     xind = 0;
953     fmap = FunctionKey;
954     if (shift) {
955       fmap = FunctionKeyShift;
956       xind = 1;
957     }
958     if (control) {
959       fmap = FunctionKeyCtrl;
960       xind = 2;
961     }
962     if (alt) {
963       fmap = FunctionKeyAlt;
964       xind = 3;
965     }
966 
967     switch (keyCode) {
968     case KEY_PAUSE:
969       if (shift || control) {
970         sendTelnetCommand((byte) 243); // BREAK
971       }
972       break;
973     case KEY_F1:
974       writeSpecial(fmap[1]);
975       break;
976     case KEY_F2:
977       writeSpecial(fmap[2]);
978       break;
979     case KEY_F3:
980       writeSpecial(fmap[3]);
981       break;
982     case KEY_F4:
983       writeSpecial(fmap[4]);
984       break;
985     case KEY_F5:
986       writeSpecial(fmap[5]);
987       break;
988     case KEY_F6:
989       writeSpecial(fmap[6]);
990       break;
991     case KEY_F7:
992       writeSpecial(fmap[7]);
993       break;
994     case KEY_F8:
995       writeSpecial(fmap[8]);
996       break;
997     case KEY_F9:
998       writeSpecial(fmap[9]);
999       break;
1000     case KEY_F10:
1001       writeSpecial(fmap[10]);
1002       break;
1003     case KEY_F11:
1004       writeSpecial(fmap[11]);
1005       break;
1006     case KEY_F12:
1007       writeSpecial(fmap[12]);
1008       break;
1009     case KEY_UP:
1010       writeSpecial(KeyUp[xind]);
1011       break;
1012     case KEY_DOWN:
1013       writeSpecial(KeyDown[xind]);
1014       break;
1015     case KEY_LEFT:
1016       writeSpecial(KeyLeft[xind]);
1017       break;
1018     case KEY_RIGHT:
1019       writeSpecial(KeyRight[xind]);
1020       break;
1021     case KEY_PAGE_DOWN:
1022       writeSpecial(NextScn[xind]);
1023       break;
1024     case KEY_PAGE_UP:
1025       writeSpecial(PrevScn[xind]);
1026       break;
1027     case KEY_INSERT:
1028       writeSpecial(Insert[xind]);
1029       break;
1030     case KEY_DELETE:
1031       writeSpecial(Remove[xind]);
1032       break;
1033     case KEY_BACK_SPACE:
1034       writeSpecial(BackSpace[xind]);
1035       if (localecho) {
1036         if (BackSpace[xind] == "\b") {
1037           putString("\b \b"); // make the last char 'deleted'
1038         } else {
1039           putString(BackSpace[xind]); // echo it
1040         }
1041       }
1042       break;
1043     case KEY_HOME:
1044       writeSpecial(KeyHome[xind]);
1045       break;
1046     case KEY_END:
1047       writeSpecial(KeyEnd[xind]);
1048       break;
1049     case KEY_NUM_LOCK:
1050       if (vms && control) {
1051         writeSpecial(PF1);
1052       }
1053       if (!control) {
1054         numlock = !numlock;
1055       }
1056       break;
1057     case KEY_CAPS_LOCK:
1058       capslock = !capslock;
1059       return;
1060     case KEY_SHIFT:
1061     case KEY_CONTROL:
1062     case KEY_ALT:
1063       return;
1064     default:
1065       break;
1066     }
1067   }
1068 
1069   /*
1070    * public void keyReleased(KeyEvent evt) { if (debug > 1) debug("keyReleased("+evt+")"); // ignore
1071    * }
1072    */
1073   /**
1074    * Handle key Typed events for the terminal, this will get all normal key types, but no
1075    * shift/alt/control/numlock.
1076    */
keyTyped(int keyCode, char keyChar, int modifiers)1077   public void keyTyped(int keyCode, char keyChar, int modifiers) {
1078     boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
1079     boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
1080     boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
1081 
1082     if (debug > 1) {
1083       debug("keyTyped(" + keyCode + ", " + (int) keyChar + ", " + modifiers + ")");
1084     }
1085 
1086     if (keyChar == '\t') {
1087       if (shift) {
1088         write(TabKey[1], false);
1089       } else {
1090         if (control) {
1091           write(TabKey[2], false);
1092         } else {
1093           if (alt) {
1094             write(TabKey[3], false);
1095           } else {
1096             write(TabKey[0], false);
1097           }
1098         }
1099       }
1100       return;
1101     }
1102     if (alt) {
1103       write(((char) (keyChar | 0x80)));
1104       return;
1105     }
1106 
1107     if (((keyCode == KEY_ENTER) || (keyChar == 10)) && !control) {
1108       write('\r');
1109       if (localecho) {
1110         putString("\r\n"); // bad hack
1111       }
1112       return;
1113     }
1114 
1115     if ((keyCode == 10) && !control) {
1116       debug("Sending \\r");
1117       write('\r');
1118       return;
1119     }
1120 
1121     // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
1122     // so we can't just use it here... will probably break some other VMS
1123     // codes. -Marcus
1124     // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ')
1125     // && control)
1126     if (((!vms && keyChar == '2') || keyChar == ' ') && control) {
1127       write(0);
1128     }
1129 
1130     if (vms) {
1131       if (keyChar == 127 && !control) {
1132         if (shift) {
1133           writeSpecial(Insert[0]); // VMS shift delete = insert
1134         } else {
1135           writeSpecial(Remove[0]); // VMS delete = remove
1136         }
1137         return;
1138       } else if (control) {
1139         switch (keyChar) {
1140         case '0':
1141           writeSpecial(Numpad[0]);
1142           return;
1143         case '1':
1144           writeSpecial(Numpad[1]);
1145           return;
1146         case '2':
1147           writeSpecial(Numpad[2]);
1148           return;
1149         case '3':
1150           writeSpecial(Numpad[3]);
1151           return;
1152         case '4':
1153           writeSpecial(Numpad[4]);
1154           return;
1155         case '5':
1156           writeSpecial(Numpad[5]);
1157           return;
1158         case '6':
1159           writeSpecial(Numpad[6]);
1160           return;
1161         case '7':
1162           writeSpecial(Numpad[7]);
1163           return;
1164         case '8':
1165           writeSpecial(Numpad[8]);
1166           return;
1167         case '9':
1168           writeSpecial(Numpad[9]);
1169           return;
1170         case '.':
1171           writeSpecial(KPPeriod);
1172           return;
1173         case '-':
1174         case 31:
1175           writeSpecial(KPMinus);
1176           return;
1177         case '+':
1178           writeSpecial(KPComma);
1179           return;
1180         case 10:
1181           writeSpecial(KPEnter);
1182           return;
1183         case '/':
1184           writeSpecial(PF2);
1185           return;
1186         case '*':
1187           writeSpecial(PF3);
1188           return;
1189           /* NUMLOCK handled in keyPressed */
1190         default:
1191           break;
1192         }
1193         /*
1194          * Now what does this do and how did it get here. -Marcus if (shift && keyChar < 32) {
1195          * write(PF1+(char)(keyChar + 64)); return; }
1196          */
1197       }
1198     }
1199 
1200     // FIXME: not used?
1201     // String fmap[];
1202     int xind;
1203     xind = 0;
1204     // fmap = FunctionKey;
1205     if (shift) {
1206       // fmap = FunctionKeyShift;
1207       xind = 1;
1208     }
1209     if (control) {
1210       // fmap = FunctionKeyCtrl;
1211       xind = 2;
1212     }
1213     if (alt) {
1214       // fmap = FunctionKeyAlt;
1215       xind = 3;
1216     }
1217 
1218     if (keyCode == KEY_ESCAPE) {
1219       writeSpecial(Escape[xind]);
1220       return;
1221     }
1222 
1223     if ((modifiers & VDUInput.KEY_ACTION) != 0) {
1224       switch (keyCode) {
1225       case KEY_NUMPAD0:
1226         writeSpecial(Numpad[0]);
1227         return;
1228       case KEY_NUMPAD1:
1229         writeSpecial(Numpad[1]);
1230         return;
1231       case KEY_NUMPAD2:
1232         writeSpecial(Numpad[2]);
1233         return;
1234       case KEY_NUMPAD3:
1235         writeSpecial(Numpad[3]);
1236         return;
1237       case KEY_NUMPAD4:
1238         writeSpecial(Numpad[4]);
1239         return;
1240       case KEY_NUMPAD5:
1241         writeSpecial(Numpad[5]);
1242         return;
1243       case KEY_NUMPAD6:
1244         writeSpecial(Numpad[6]);
1245         return;
1246       case KEY_NUMPAD7:
1247         writeSpecial(Numpad[7]);
1248         return;
1249       case KEY_NUMPAD8:
1250         writeSpecial(Numpad[8]);
1251         return;
1252       case KEY_NUMPAD9:
1253         writeSpecial(Numpad[9]);
1254         return;
1255       case KEY_DECIMAL:
1256         writeSpecial(NUMDot[xind]);
1257         return;
1258       case KEY_ADD:
1259         writeSpecial(NUMPlus[xind]);
1260         return;
1261       }
1262     }
1263 
1264     if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) {
1265       write(keyChar);
1266       return;
1267     }
1268   }
1269 
handle_dcs(String dcs)1270   private void handle_dcs(String dcs) {
1271     debugStr.append("DCS: ").append(dcs);
1272     debug(debugStr.toString());
1273     debugStr.setLength(0);
1274   }
1275 
handle_osc(String osc)1276   private void handle_osc(String osc) {
1277     if (osc.length() > 2 && osc.substring(0, 2).equals("4;")) {
1278       // Define color palette
1279       String[] colorData = osc.split(";");
1280 
1281       try {
1282         int colorIndex = Integer.parseInt(colorData[1]);
1283 
1284         if ("rgb:".equals(colorData[2].substring(0, 4))) {
1285           String[] rgb = colorData[2].substring(4).split("/");
1286 
1287           int red = Integer.parseInt(rgb[0].substring(0, 2), 16) & 0xFF;
1288           int green = Integer.parseInt(rgb[1].substring(0, 2), 16) & 0xFF;
1289           int blue = Integer.parseInt(rgb[2].substring(0, 2), 16) & 0xFF;
1290           display.setColor(colorIndex, red, green, blue);
1291         }
1292       } catch (Exception e) {
1293         debugStr.append("OSC: invalid color sequence encountered: ").append(osc);
1294         debug(debugStr.toString());
1295         debugStr.setLength(0);
1296       }
1297     } else {
1298       debug("OSC: " + osc);
1299     }
1300   }
1301 
1302   private final static char unimap[] = {
1303     // #
1304     // # Name: cp437_DOSLatinUS to Unicode table
1305     // # Unicode version: 1.1
1306     // # Table version: 1.1
1307     // # Table format: Format A
1308     // # Date: 03/31/95
1309     // # Authors: Michel Suignard <michelsu@microsoft.com>
1310     // # Lori Hoerth <lorih@microsoft.com>
1311     // # General notes: none
1312     // #
1313     // # Format: Three tab-separated columns
1314     // # Column #1 is the cp1255_WinHebrew code (in hex)
1315     // # Column #2 is the Unicode (in hex as 0xXXXX)
1316     // # Column #3 is the Unicode name (follows a comment sign, '#')
1317     // #
1318     // # The entries are in cp437_DOSLatinUS order
1319     // #
1320 
1321     0x0000, // #NULL
1322     0x0001, // #START OF HEADING
1323     0x0002, // #START OF TEXT
1324     0x0003, // #END OF TEXT
1325     0x0004, // #END OF TRANSMISSION
1326     0x0005, // #ENQUIRY
1327     0x0006, // #ACKNOWLEDGE
1328     0x0007, // #BELL
1329     0x0008, // #BACKSPACE
1330     0x0009, // #HORIZONTAL TABULATION
1331     0x000a, // #LINE FEED
1332     0x000b, // #VERTICAL TABULATION
1333     0x000c, // #FORM FEED
1334     0x000d, // #CARRIAGE RETURN
1335     0x000e, // #SHIFT OUT
1336     0x000f, // #SHIFT IN
1337     0x0010, // #DATA LINK ESCAPE
1338     0x0011, // #DEVICE CONTROL ONE
1339     0x0012, // #DEVICE CONTROL TWO
1340     0x0013, // #DEVICE CONTROL THREE
1341     0x0014, // #DEVICE CONTROL FOUR
1342     0x0015, // #NEGATIVE ACKNOWLEDGE
1343     0x0016, // #SYNCHRONOUS IDLE
1344     0x0017, // #END OF TRANSMISSION BLOCK
1345     0x0018, // #CANCEL
1346     0x0019, // #END OF MEDIUM
1347     0x001a, // #SUBSTITUTE
1348     0x001b, // #ESCAPE
1349     0x001c, // #FILE SEPARATOR
1350     0x001d, // #GROUP SEPARATOR
1351     0x001e, // #RECORD SEPARATOR
1352     0x001f, // #UNIT SEPARATOR
1353     0x0020, // #SPACE
1354     0x0021, // #EXCLAMATION MARK
1355     0x0022, // #QUOTATION MARK
1356     0x0023, // #NUMBER SIGN
1357     0x0024, // #DOLLAR SIGN
1358     0x0025, // #PERCENT SIGN
1359     0x0026, // #AMPERSAND
1360     0x0027, // #APOSTROPHE
1361     0x0028, // #LEFT PARENTHESIS
1362     0x0029, // #RIGHT PARENTHESIS
1363     0x002a, // #ASTERISK
1364     0x002b, // #PLUS SIGN
1365     0x002c, // #COMMA
1366     0x002d, // #HYPHEN-MINUS
1367     0x002e, // #FULL STOP
1368     0x002f, // #SOLIDUS
1369     0x0030, // #DIGIT ZERO
1370     0x0031, // #DIGIT ONE
1371     0x0032, // #DIGIT TWO
1372     0x0033, // #DIGIT THREE
1373     0x0034, // #DIGIT FOUR
1374     0x0035, // #DIGIT FIVE
1375     0x0036, // #DIGIT SIX
1376     0x0037, // #DIGIT SEVEN
1377     0x0038, // #DIGIT EIGHT
1378     0x0039, // #DIGIT NINE
1379     0x003a, // #COLON
1380     0x003b, // #SEMICOLON
1381     0x003c, // #LESS-THAN SIGN
1382     0x003d, // #EQUALS SIGN
1383     0x003e, // #GREATER-THAN SIGN
1384     0x003f, // #QUESTION MARK
1385     0x0040, // #COMMERCIAL AT
1386     0x0041, // #LATIN CAPITAL LETTER A
1387     0x0042, // #LATIN CAPITAL LETTER B
1388     0x0043, // #LATIN CAPITAL LETTER C
1389     0x0044, // #LATIN CAPITAL LETTER D
1390     0x0045, // #LATIN CAPITAL LETTER E
1391     0x0046, // #LATIN CAPITAL LETTER F
1392     0x0047, // #LATIN CAPITAL LETTER G
1393     0x0048, // #LATIN CAPITAL LETTER H
1394     0x0049, // #LATIN CAPITAL LETTER I
1395     0x004a, // #LATIN CAPITAL LETTER J
1396     0x004b, // #LATIN CAPITAL LETTER K
1397     0x004c, // #LATIN CAPITAL LETTER L
1398     0x004d, // #LATIN CAPITAL LETTER M
1399     0x004e, // #LATIN CAPITAL LETTER N
1400     0x004f, // #LATIN CAPITAL LETTER O
1401     0x0050, // #LATIN CAPITAL LETTER P
1402     0x0051, // #LATIN CAPITAL LETTER Q
1403     0x0052, // #LATIN CAPITAL LETTER R
1404     0x0053, // #LATIN CAPITAL LETTER S
1405     0x0054, // #LATIN CAPITAL LETTER T
1406     0x0055, // #LATIN CAPITAL LETTER U
1407     0x0056, // #LATIN CAPITAL LETTER V
1408     0x0057, // #LATIN CAPITAL LETTER W
1409     0x0058, // #LATIN CAPITAL LETTER X
1410     0x0059, // #LATIN CAPITAL LETTER Y
1411     0x005a, // #LATIN CAPITAL LETTER Z
1412     0x005b, // #LEFT SQUARE BRACKET
1413     0x005c, // #REVERSE SOLIDUS
1414     0x005d, // #RIGHT SQUARE BRACKET
1415     0x005e, // #CIRCUMFLEX ACCENT
1416     0x005f, // #LOW LINE
1417     0x0060, // #GRAVE ACCENT
1418     0x0061, // #LATIN SMALL LETTER A
1419     0x0062, // #LATIN SMALL LETTER B
1420     0x0063, // #LATIN SMALL LETTER C
1421     0x0064, // #LATIN SMALL LETTER D
1422     0x0065, // #LATIN SMALL LETTER E
1423     0x0066, // #LATIN SMALL LETTER F
1424     0x0067, // #LATIN SMALL LETTER G
1425     0x0068, // #LATIN SMALL LETTER H
1426     0x0069, // #LATIN SMALL LETTER I
1427     0x006a, // #LATIN SMALL LETTER J
1428     0x006b, // #LATIN SMALL LETTER K
1429     0x006c, // #LATIN SMALL LETTER L
1430     0x006d, // #LATIN SMALL LETTER M
1431     0x006e, // #LATIN SMALL LETTER N
1432     0x006f, // #LATIN SMALL LETTER O
1433     0x0070, // #LATIN SMALL LETTER P
1434     0x0071, // #LATIN SMALL LETTER Q
1435     0x0072, // #LATIN SMALL LETTER R
1436     0x0073, // #LATIN SMALL LETTER S
1437     0x0074, // #LATIN SMALL LETTER T
1438     0x0075, // #LATIN SMALL LETTER U
1439     0x0076, // #LATIN SMALL LETTER V
1440     0x0077, // #LATIN SMALL LETTER W
1441     0x0078, // #LATIN SMALL LETTER X
1442     0x0079, // #LATIN SMALL LETTER Y
1443     0x007a, // #LATIN SMALL LETTER Z
1444     0x007b, // #LEFT CURLY BRACKET
1445     0x007c, // #VERTICAL LINE
1446     0x007d, // #RIGHT CURLY BRACKET
1447     0x007e, // #TILDE
1448     0x007f, // #DELETE
1449     0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA
1450     0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS
1451     0x00e9, // #LATIN SMALL LETTER E WITH ACUTE
1452     0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX
1453     0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS
1454     0x00e0, // #LATIN SMALL LETTER A WITH GRAVE
1455     0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE
1456     0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA
1457     0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX
1458     0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS
1459     0x00e8, // #LATIN SMALL LETTER E WITH GRAVE
1460     0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS
1461     0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX
1462     0x00ec, // #LATIN SMALL LETTER I WITH GRAVE
1463     0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS
1464     0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE
1465     0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE
1466     0x00e6, // #LATIN SMALL LIGATURE AE
1467     0x00c6, // #LATIN CAPITAL LIGATURE AE
1468     0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX
1469     0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS
1470     0x00f2, // #LATIN SMALL LETTER O WITH GRAVE
1471     0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX
1472     0x00f9, // #LATIN SMALL LETTER U WITH GRAVE
1473     0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS
1474     0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS
1475     0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS
1476     0x00a2, // #CENT SIGN
1477     0x00a3, // #POUND SIGN
1478     0x00a5, // #YEN SIGN
1479     0x20a7, // #PESETA SIGN
1480     0x0192, // #LATIN SMALL LETTER F WITH HOOK
1481     0x00e1, // #LATIN SMALL LETTER A WITH ACUTE
1482     0x00ed, // #LATIN SMALL LETTER I WITH ACUTE
1483     0x00f3, // #LATIN SMALL LETTER O WITH ACUTE
1484     0x00fa, // #LATIN SMALL LETTER U WITH ACUTE
1485     0x00f1, // #LATIN SMALL LETTER N WITH TILDE
1486     0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE
1487     0x00aa, // #FEMININE ORDINAL INDICATOR
1488     0x00ba, // #MASCULINE ORDINAL INDICATOR
1489     0x00bf, // #INVERTED QUESTION MARK
1490     0x2310, // #REVERSED NOT SIGN
1491     0x00ac, // #NOT SIGN
1492     0x00bd, // #VULGAR FRACTION ONE HALF
1493     0x00bc, // #VULGAR FRACTION ONE QUARTER
1494     0x00a1, // #INVERTED EXCLAMATION MARK
1495     0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
1496     0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
1497     0x2591, // #LIGHT SHADE
1498     0x2592, // #MEDIUM SHADE
1499     0x2593, // #DARK SHADE
1500     0x2502, // #BOX DRAWINGS LIGHT VERTICAL
1501     0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT
1502     0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
1503     0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
1504     0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
1505     0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
1506     0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
1507     0x2551, // #BOX DRAWINGS DOUBLE VERTICAL
1508     0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT
1509     0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT
1510     0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
1511     0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
1512     0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT
1513     0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT
1514     0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL
1515     0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1516     0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1517     0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL
1518     0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1519     0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
1520     0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
1521     0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT
1522     0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT
1523     0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
1524     0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
1525     0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
1526     0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL
1527     0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
1528     0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
1529     0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
1530     0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
1531     0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
1532     0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
1533     0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
1534     0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
1535     0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
1536     0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
1537     0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
1538     0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT
1539     0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT
1540     0x2588, // #FULL BLOCK
1541     0x2584, // #LOWER HALF BLOCK
1542     0x258c, // #LEFT HALF BLOCK
1543     0x2590, // #RIGHT HALF BLOCK
1544     0x2580, // #UPPER HALF BLOCK
1545     0x03b1, // #GREEK SMALL LETTER ALPHA
1546     0x00df, // #LATIN SMALL LETTER SHARP S
1547     0x0393, // #GREEK CAPITAL LETTER GAMMA
1548     0x03c0, // #GREEK SMALL LETTER PI
1549     0x03a3, // #GREEK CAPITAL LETTER SIGMA
1550     0x03c3, // #GREEK SMALL LETTER SIGMA
1551     0x00b5, // #MICRO SIGN
1552     0x03c4, // #GREEK SMALL LETTER TAU
1553     0x03a6, // #GREEK CAPITAL LETTER PHI
1554     0x0398, // #GREEK CAPITAL LETTER THETA
1555     0x03a9, // #GREEK CAPITAL LETTER OMEGA
1556     0x03b4, // #GREEK SMALL LETTER DELTA
1557     0x221e, // #INFINITY
1558     0x03c6, // #GREEK SMALL LETTER PHI
1559     0x03b5, // #GREEK SMALL LETTER EPSILON
1560     0x2229, // #INTERSECTION
1561     0x2261, // #IDENTICAL TO
1562     0x00b1, // #PLUS-MINUS SIGN
1563     0x2265, // #GREATER-THAN OR EQUAL TO
1564     0x2264, // #LESS-THAN OR EQUAL TO
1565     0x2320, // #TOP HALF INTEGRAL
1566     0x2321, // #BOTTOM HALF INTEGRAL
1567     0x00f7, // #DIVISION SIGN
1568     0x2248, // #ALMOST EQUAL TO
1569     0x00b0, // #DEGREE SIGN
1570     0x2219, // #BULLET OPERATOR
1571     0x00b7, // #MIDDLE DOT
1572     0x221a, // #SQUARE ROOT
1573     0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N
1574     0x00b2, // #SUPERSCRIPT TWO
1575     0x25a0, // #BLACK SQUARE
1576     0x00a0, // #NO-BREAK SPACE
1577   };
1578 
map_cp850_unicode(char x)1579   public char map_cp850_unicode(char x) {
1580     if (x >= 0x100) {
1581       return x;
1582     }
1583     return unimap[x];
1584   }
1585 
_SetCursor(int row, int col)1586   private void _SetCursor(int row, int col) {
1587     int maxr = height - 1;
1588     int tm = getTopMargin();
1589 
1590     R = (row < 0) ? 0 : row;
1591     C = (col < 0) ? 0 : (col >= width) ? width - 1 : col;
1592 
1593     if (!moveoutsidemargins) {
1594       R += tm;
1595       maxr = getBottomMargin();
1596     }
1597     if (R > maxr) {
1598       R = maxr;
1599     }
1600   }
1601 
putChar(char c, boolean isWide, boolean doshowcursor)1602   private void putChar(char c, boolean isWide, boolean doshowcursor) {
1603     int rows = height; // statusline
1604     int columns = width;
1605     // byte msg[];
1606 
1607     // if (debug > 4) {
1608     // debugStr.append("putChar(")
1609     // .append(c)
1610     // .append(" [")
1611     // .append((int) c)
1612     // .append("]) at R=")
1613     // .append(R)
1614     // .append(" , C=")
1615     // .append(C)
1616     // .append(", columns=")
1617     // .append(columns)
1618     // .append(", rows=")
1619     // .append(rows);
1620     // debug(debugStr.toString());
1621     // debugStr.setLength(0);
1622     // }
1623     // markLine(R, 1);
1624     // if (c > 255) {
1625     // if (debug > 0)
1626     // debug("char > 255:" + (int) c);
1627     // //return;
1628     // }
1629 
1630     switch (term_state) {
1631     case TSTATE_DATA:
1632       /*
1633        * FIXME: we shouldn't use chars with bit 8 set if ibmcharset. probably... but some BBS do
1634        * anyway...
1635        */
1636       if (!useibmcharset) {
1637         boolean doneflag = true;
1638         switch (c) {
1639         case OSC:
1640           osc = "";
1641           term_state = TSTATE_OSC;
1642           break;
1643         case RI:
1644           if (R > getTopMargin()) {
1645             R--;
1646           } else {
1647             insertLine(R, 1, SCROLL_DOWN);
1648           }
1649           if (debug > 1) {
1650             debug("RI");
1651           }
1652           break;
1653         case IND:
1654           if (debug > 2) {
1655             debugStr.append("IND at ").append(R).append(", tm is ").append(getTopMargin())
1656                 .append(", bm is ").append(getBottomMargin());
1657             debug(debugStr.toString());
1658             debugStr.setLength(0);
1659           }
1660           if (R == getBottomMargin() || R == rows - 1) {
1661             insertLine(R, 1, SCROLL_UP);
1662           } else {
1663             R++;
1664           }
1665           if (debug > 1) {
1666             debug("IND (at " + R + " )");
1667           }
1668           break;
1669         case NEL:
1670           if (R == getBottomMargin() || R == rows - 1) {
1671             insertLine(R, 1, SCROLL_UP);
1672           } else {
1673             R++;
1674           }
1675           C = 0;
1676           if (debug > 1) {
1677             debug("NEL (at " + R + " )");
1678           }
1679           break;
1680         case HTS:
1681           Tabs[C] = 1;
1682           if (debug > 1) {
1683             debug("HTS");
1684           }
1685           break;
1686         case DCS:
1687           dcs = "";
1688           term_state = TSTATE_DCS;
1689           break;
1690         default:
1691           doneflag = false;
1692           break;
1693         }
1694         if (doneflag) {
1695           break;
1696         }
1697       }
1698       switch (c) {
1699       case SS3:
1700         onegl = 3;
1701         break;
1702       case SS2:
1703         onegl = 2;
1704         break;
1705       case CSI: // should be in the 8bit section, but some BBS use this
1706         DCEvar = 0;
1707         DCEvars[0] = 0;
1708         DCEvars[1] = 0;
1709         DCEvars[2] = 0;
1710         DCEvars[3] = 0;
1711         term_state = TSTATE_CSI;
1712         break;
1713       case ESC:
1714         term_state = TSTATE_ESC;
1715         lastwaslf = 0;
1716         break;
1717       case 5: /* ENQ */
1718         write(answerBack, false);
1719         break;
1720       case 12:
1721         /* FormFeed, Home for the BBS world */
1722         deleteArea(0, 0, columns, rows, attributes);
1723         C = R = 0;
1724         break;
1725       case '\b': /* 8 */
1726         C--;
1727         if (C < 0) {
1728           C = 0;
1729         }
1730         lastwaslf = 0;
1731         break;
1732       case '\t':
1733         do {
1734           // Don't overwrite or insert! TABS are not destructive, but movement!
1735           C++;
1736         } while (C < columns && (Tabs[C] == 0));
1737         lastwaslf = 0;
1738         break;
1739       case '\r': // 13 CR
1740         C = 0;
1741         break;
1742       case '\n': // 10 LF
1743         if (debug > 3) {
1744           debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows="
1745               + rows);
1746         }
1747         if (!vms) {
1748           if (lastwaslf != 0 && lastwaslf != c) {
1749             break;
1750           }
1751           lastwaslf = c;
1752           /* C = 0; */
1753         }
1754         if (R == getBottomMargin() || R >= rows - 1) {
1755           insertLine(R, 1, SCROLL_UP);
1756         } else {
1757           R++;
1758         }
1759         break;
1760       case 7:
1761         beep();
1762         break;
1763       case '\016': /* SMACS , as */
1764         /* ^N, Shift out - Put G1 into GL */
1765         gl = 1;
1766         usedcharsets = true;
1767         break;
1768       case '\017': /* RMACS , ae */
1769         /* ^O, Shift in - Put G0 into GL */
1770         gl = 0;
1771         usedcharsets = true;
1772         break;
1773       default: {
1774         int thisgl = gl;
1775 
1776         if (onegl >= 0) {
1777           thisgl = onegl;
1778           onegl = -1;
1779         }
1780         lastwaslf = 0;
1781         if (c < 32) {
1782           if (c != 0) {
1783             if (debug > 0) {
1784               debug("TSTATE_DATA char: " + ((int) c));
1785             }
1786           }
1787           /* break; some BBS really want those characters, like hearst etc. */
1788           if (c == 0) {
1789             break;
1790           }
1791         }
1792         if (C >= columns) {
1793           if (wraparound) {
1794             int bot = rows;
1795 
1796             // If we're in the scroll region, check against the bottom margin
1797             if (R <= getBottomMargin() && R >= getTopMargin()) {
1798               bot = getBottomMargin() + 1;
1799             }
1800 
1801             if (R < bot - 1) {
1802               R++;
1803             } else {
1804               if (debug > 3) {
1805                 debug("scrolling due to wrap at " + R);
1806               }
1807               insertLine(R, 1, SCROLL_UP);
1808             }
1809             C = 0;
1810           } else {
1811             // cursor stays on last character.
1812             C = columns - 1;
1813           }
1814         }
1815 
1816         boolean mapped = false;
1817 
1818         // Mapping if DEC Special is chosen charset
1819         if (usedcharsets) {
1820           if (c >= '\u0020' && c <= '\u007f') {
1821             switch (gx[thisgl]) {
1822             case '0':
1823               // Remap SCOANSI line drawing to VT100 line drawing chars
1824               // for our SCO using customers.
1825               if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
1826                 for (int i = 0; i < scoansi_acs.length(); i += 2) {
1827                   if (c == scoansi_acs.charAt(i)) {
1828                     c = scoansi_acs.charAt(i + 1);
1829                     break;
1830                   }
1831                 }
1832               }
1833               if (c >= '\u005f' && c <= '\u007e') {
1834                 c = DECSPECIAL[(short) c - 0x5f];
1835                 mapped = true;
1836               }
1837               break;
1838             case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
1839               c = (char) ((c & 0x7f) | 0x80);
1840               mapped = true;
1841               break;
1842             case 'A':
1843             case 'B': // Latin-1 , ASCII -> fall through
1844               mapped = true;
1845               break;
1846             default:
1847               debug("Unsupported GL mapping: " + gx[thisgl]);
1848               break;
1849             }
1850           }
1851           if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
1852             switch (gx[gr]) {
1853             case '0':
1854               if (c >= '\u00df' && c <= '\u00fe') {
1855                 c = DECSPECIAL[c - '\u00df'];
1856                 mapped = true;
1857               }
1858               break;
1859             case '<':
1860             case 'A':
1861             case 'B':
1862               mapped = true;
1863               break;
1864             default:
1865               debug("Unsupported GR mapping: " + gx[gr]);
1866               break;
1867             }
1868           }
1869         }
1870         if (!mapped && useibmcharset) {
1871           c = map_cp850_unicode(c);
1872         }
1873 
1874         /* if(true || (statusmode == 0)) { */
1875         if (isWide) {
1876           if (C >= columns - 1) {
1877             if (wraparound) {
1878               int bot = rows;
1879 
1880               // If we're in the scroll region, check against the bottom margin
1881               if (R <= getBottomMargin() && R >= getTopMargin()) {
1882                 bot = getBottomMargin() + 1;
1883               }
1884 
1885               if (R < bot - 1) {
1886                 R++;
1887               } else {
1888                 if (debug > 3) {
1889                   debug("scrolling due to wrap at " + R);
1890                 }
1891                 insertLine(R, 1, SCROLL_UP);
1892               }
1893               C = 0;
1894             } else {
1895               // cursor stays on last wide character.
1896               C = columns - 2;
1897             }
1898           }
1899         }
1900 
1901         if (insertmode == 1) {
1902           if (isWide) {
1903             insertChar(C++, R, c, attributes | FULLWIDTH);
1904             insertChar(C, R, ' ', attributes | FULLWIDTH);
1905           } else {
1906             insertChar(C, R, c, attributes);
1907           }
1908         } else {
1909           if (isWide) {
1910             putChar(C++, R, c, attributes | FULLWIDTH);
1911             putChar(C, R, ' ', attributes | FULLWIDTH);
1912           } else {
1913             putChar(C, R, c, attributes);
1914           }
1915         }
1916 
1917         /*
1918          * } else { if (insertmode==1) { insertChar(C, rows, c, attributes); } else { putChar(C,
1919          * rows, c, attributes); } }
1920          */
1921         C++;
1922         break;
1923       }
1924       } /* switch(c) */
1925       break;
1926     case TSTATE_OSC:
1927       if ((c < 0x20) && (c != ESC)) {// NP - No printing character
1928         handle_osc(osc);
1929         term_state = TSTATE_DATA;
1930         break;
1931       }
1932       // but check for vt102 ESC \
1933       if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
1934         handle_osc(osc);
1935         term_state = TSTATE_DATA;
1936         break;
1937       }
1938       osc = osc + c;
1939       break;
1940     case TSTATE_ESCSPACE:
1941       term_state = TSTATE_DATA;
1942       switch (c) {
1943       case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
1944         output8bit = false;
1945         break;
1946       case 'G': /* S8C1T, Enable output of 8-bit control codes */
1947         output8bit = true;
1948         break;
1949       default:
1950         debug("ESC <space> " + c + " unhandled.");
1951       }
1952       break;
1953     case TSTATE_ESC:
1954       term_state = TSTATE_DATA;
1955       switch (c) {
1956       case ' ':
1957         term_state = TSTATE_ESCSPACE;
1958         break;
1959       case '#':
1960         term_state = TSTATE_ESCSQUARE;
1961         break;
1962       case 'c':
1963         /* Hard terminal reset */
1964         reset();
1965         break;
1966       case '[':
1967         DCEvar = 0;
1968         DCEvars[0] = 0;
1969         DCEvars[1] = 0;
1970         DCEvars[2] = 0;
1971         DCEvars[3] = 0;
1972         term_state = TSTATE_CSI;
1973         break;
1974       case ']':
1975         osc = "";
1976         term_state = TSTATE_OSC;
1977         break;
1978       case 'P':
1979         dcs = "";
1980         term_state = TSTATE_DCS;
1981         break;
1982       case 'A': /* CUU */
1983         R--;
1984         if (R < 0) {
1985           R = 0;
1986         }
1987         break;
1988       case 'B': /* CUD */
1989         R++;
1990         if (R >= rows) {
1991           R = rows - 1;
1992         }
1993         break;
1994       case 'C':
1995         C++;
1996         if (C >= columns) {
1997           C = columns - 1;
1998         }
1999         break;
2000       case 'I': // RI
2001         insertLine(R, 1, SCROLL_DOWN);
2002         break;
2003       case 'E': /* NEL */
2004         if (R == getBottomMargin() || R == rows - 1) {
2005           insertLine(R, 1, SCROLL_UP);
2006         } else {
2007           R++;
2008         }
2009         C = 0;
2010         if (debug > 1) {
2011           debug("ESC E (at " + R + ")");
2012         }
2013         break;
2014       case 'D': /* IND */
2015         if (R == getBottomMargin() || R == rows - 1) {
2016           insertLine(R, 1, SCROLL_UP);
2017         } else {
2018           R++;
2019         }
2020         if (debug > 1) {
2021           debug("ESC D (at " + R + " )");
2022         }
2023         break;
2024       case 'J': /* erase to end of screen */
2025         if (R < rows - 1) {
2026           deleteArea(0, R + 1, columns, rows - R - 1, attributes);
2027         }
2028         if (C < columns - 1) {
2029           deleteArea(C, R, columns - C, 1, attributes);
2030         }
2031         break;
2032       case 'K':
2033         if (C < columns - 1) {
2034           deleteArea(C, R, columns - C, 1, attributes);
2035         }
2036         break;
2037       case 'M': // RI
2038         debug("ESC M : R is " + R + ", tm is " + getTopMargin() + ", bm is " + getBottomMargin());
2039         if (R > getTopMargin()) { // just go up 1 line.
2040           R--;
2041         } else { // scroll down
2042           insertLine(R, 1, SCROLL_DOWN);
2043         }
2044         /* else do nothing ; */
2045         if (debug > 2) {
2046           debug("ESC M ");
2047         }
2048         break;
2049       case 'H':
2050         if (debug > 1) {
2051           debug("ESC H at " + C);
2052         }
2053         /* right border probably ... */
2054         if (C >= columns) {
2055           C = columns - 1;
2056         }
2057         Tabs[C] = 1;
2058         break;
2059       case 'N': // SS2
2060         onegl = 2;
2061         break;
2062       case 'O': // SS3
2063         onegl = 3;
2064         break;
2065       case '=':
2066         /* application keypad */
2067         if (debug > 0) {
2068           debug("ESC =");
2069         }
2070         keypadmode = true;
2071         break;
2072       case '<': /* vt52 mode off */
2073         vt52mode = false;
2074         break;
2075       case '>': /* normal keypad */
2076         if (debug > 0) {
2077           debug("ESC >");
2078         }
2079         keypadmode = false;
2080         break;
2081       case '7': /* DECSC: save cursor, attributes */
2082         Sc = C;
2083         Sr = R;
2084         Sgl = gl;
2085         Sgr = gr;
2086         Sa = attributes;
2087         Sgx = new char[4];
2088         for (int i = 0; i < 4; i++) {
2089           Sgx[i] = gx[i];
2090         }
2091         if (debug > 1) {
2092           debug("ESC 7");
2093         }
2094         break;
2095       case '8': /* DECRC: restore cursor, attributes */
2096         C = Sc;
2097         R = Sr;
2098         gl = Sgl;
2099         gr = Sgr;
2100         if (Sgx != null) {
2101           for (int i = 0; i < 4; i++) {
2102             gx[i] = Sgx[i];
2103           }
2104         }
2105         attributes = Sa;
2106         if (debug > 1) {
2107           debug("ESC 8");
2108         }
2109         break;
2110       case '(': /* Designate G0 Character set (ISO 2022) */
2111         term_state = TSTATE_SETG0;
2112         usedcharsets = true;
2113         break;
2114       case ')': /* Designate G1 character set (ISO 2022) */
2115         term_state = TSTATE_SETG1;
2116         usedcharsets = true;
2117         break;
2118       case '*': /* Designate G2 Character set (ISO 2022) */
2119         term_state = TSTATE_SETG2;
2120         usedcharsets = true;
2121         break;
2122       case '+': /* Designate G3 Character set (ISO 2022) */
2123         term_state = TSTATE_SETG3;
2124         usedcharsets = true;
2125         break;
2126       case '~': /* Locking Shift 1, right */
2127         gr = 1;
2128         usedcharsets = true;
2129         break;
2130       case 'n': /* Locking Shift 2 */
2131         gl = 2;
2132         usedcharsets = true;
2133         break;
2134       case '}': /* Locking Shift 2, right */
2135         gr = 2;
2136         usedcharsets = true;
2137         break;
2138       case 'o': /* Locking Shift 3 */
2139         gl = 3;
2140         usedcharsets = true;
2141         break;
2142       case '|': /* Locking Shift 3, right */
2143         gr = 3;
2144         usedcharsets = true;
2145         break;
2146       case 'Y': /* vt52 cursor address mode , next chars are x,y */
2147         term_state = TSTATE_VT52Y;
2148         break;
2149       case '_':
2150         term_state = TSTATE_TITLE;
2151         break;
2152       case '\\':
2153         // TODO save title
2154         term_state = TSTATE_DATA;
2155         break;
2156       default:
2157         debug("ESC unknown letter: " + c + " (" + ((int) c) + ")");
2158         break;
2159       }
2160       break;
2161     case TSTATE_VT52X:
2162       C = c - 37;
2163       if (C < 0) {
2164         C = 0;
2165       } else if (C >= width) {
2166         C = width - 1;
2167       }
2168       term_state = TSTATE_VT52Y;
2169       break;
2170     case TSTATE_VT52Y:
2171       R = c - 37;
2172       if (R < 0) {
2173         R = 0;
2174       } else if (R >= height) {
2175         R = height - 1;
2176       }
2177       term_state = TSTATE_DATA;
2178       break;
2179     case TSTATE_SETG0:
2180       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2181         debug("ESC ( " + c + ": G0 char set?  (" + ((int) c) + ")");
2182       } else {
2183         if (debug > 2) {
2184           debug("ESC ( : G0 char set  (" + c + " " + ((int) c) + ")");
2185         }
2186         gx[0] = c;
2187       }
2188       term_state = TSTATE_DATA;
2189       break;
2190     case TSTATE_SETG1:
2191       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2192         debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
2193       } else {
2194         if (debug > 2) {
2195           debug("ESC ) :G1 char set  (" + c + " " + ((int) c) + ")");
2196         }
2197         gx[1] = c;
2198       }
2199       term_state = TSTATE_DATA;
2200       break;
2201     case TSTATE_SETG2:
2202       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2203         debug("ESC*:G2 char set?  (" + ((int) c) + ")");
2204       } else {
2205         if (debug > 2) {
2206           debug("ESC*:G2 char set  (" + c + " " + ((int) c) + ")");
2207         }
2208         gx[2] = c;
2209       }
2210       term_state = TSTATE_DATA;
2211       break;
2212     case TSTATE_SETG3:
2213       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2214         debug("ESC+:G3 char set?  (" + ((int) c) + ")");
2215       } else {
2216         if (debug > 2) {
2217           debug("ESC+:G3 char set  (" + c + " " + ((int) c) + ")");
2218         }
2219         gx[3] = c;
2220       }
2221       term_state = TSTATE_DATA;
2222       break;
2223     case TSTATE_ESCSQUARE:
2224       switch (c) {
2225       case '8':
2226         for (int i = 0; i < columns; i++) {
2227           for (int j = 0; j < rows; j++) {
2228             putChar(i, j, 'E', 0);
2229           }
2230         }
2231         break;
2232       default:
2233         debug("ESC # " + c + " not supported.");
2234         break;
2235       }
2236       term_state = TSTATE_DATA;
2237       break;
2238     case TSTATE_DCS:
2239       if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
2240         handle_dcs(dcs);
2241         term_state = TSTATE_DATA;
2242         break;
2243       }
2244       dcs = dcs + c;
2245       break;
2246 
2247     case TSTATE_DCEQ:
2248       term_state = TSTATE_DATA;
2249       switch (c) {
2250       case '0':
2251       case '1':
2252       case '2':
2253       case '3':
2254       case '4':
2255       case '5':
2256       case '6':
2257       case '7':
2258       case '8':
2259       case '9':
2260         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2261         term_state = TSTATE_DCEQ;
2262         break;
2263       case ';':
2264         DCEvar++;
2265         DCEvars[DCEvar] = 0;
2266         term_state = TSTATE_DCEQ;
2267         break;
2268       case 's': // XTERM_SAVE missing!
2269         if (true || debug > 1) {
2270           debug("ESC [ ? " + DCEvars[0] + " s unimplemented!");
2271         }
2272         break;
2273       case 'r': // XTERM_RESTORE
2274         if (true || debug > 1) {
2275           debug("ESC [ ? " + DCEvars[0] + " r");
2276         }
2277         /* DEC Mode reset */
2278         for (int i = 0; i <= DCEvar; i++) {
2279           switch (DCEvars[i]) {
2280           case 3: /* 80 columns */
2281             setScreenSize(80, height, true);
2282             break;
2283           case 4: /* scrolling mode, smooth */
2284             break;
2285           case 5: /* light background */
2286             break;
2287           case 6: /* DECOM (Origin Mode) move inside margins. */
2288             moveoutsidemargins = true;
2289             break;
2290           case 7: /* DECAWM: Autowrap Mode */
2291             wraparound = false;
2292             break;
2293           case 12:/* local echo off */
2294             break;
2295           case 9: /* X10 mouse */
2296           case 1000: /* xterm style mouse report on */
2297           case 1001:
2298           case 1002:
2299           case 1003:
2300             mouserpt = DCEvars[i];
2301             break;
2302           default:
2303             debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
2304           }
2305         }
2306         break;
2307       case 'h': // DECSET
2308         if (debug > 0) {
2309           debug("ESC [ ? " + DCEvars[0] + " h");
2310         }
2311         /* DEC Mode set */
2312         for (int i = 0; i <= DCEvar; i++) {
2313           switch (DCEvars[i]) {
2314           case 1: /* Application cursor keys */
2315             KeyUp[0] = "\u001bOA";
2316             KeyDown[0] = "\u001bOB";
2317             KeyRight[0] = "\u001bOC";
2318             KeyLeft[0] = "\u001bOD";
2319             break;
2320           case 2: /* DECANM */
2321             vt52mode = false;
2322             break;
2323           case 3: /* 132 columns */
2324             setScreenSize(132, height, true);
2325             break;
2326           case 6: /* DECOM: move inside margins. */
2327             moveoutsidemargins = false;
2328             break;
2329           case 7: /* DECAWM: Autowrap Mode */
2330             wraparound = true;
2331             break;
2332           case 25: /* turn cursor on */
2333             showCursor(true);
2334             break;
2335           case 9: /* X10 mouse */
2336           case 1000: /* xterm style mouse report on */
2337           case 1001:
2338           case 1002:
2339           case 1003:
2340             mouserpt = DCEvars[i];
2341             break;
2342 
2343           /* unimplemented stuff, fall through */
2344           /* 4 - scrolling mode, smooth */
2345           /* 5 - light background */
2346           /* 12 - local echo off */
2347           /* 18 - DECPFF - Printer Form Feed Mode -> On */
2348           /* 19 - DECPEX - Printer Extent Mode -> Screen */
2349           default:
2350             debug("ESC [ ? " + DCEvars[0] + " h, unsupported.");
2351             break;
2352           }
2353         }
2354         break;
2355       case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
2356         // This is different to CSI i!
2357         // Also: "Autoprint prints a final display line only when the
2358         // cursor is moved off the line by an autowrap or LF, FF, or
2359         // VT (otherwise do not print the line)."
2360         switch (DCEvars[0]) {
2361         case 1:
2362           if (debug > 1) {
2363             debug("CSI ? 1 i : Print line containing cursor");
2364           }
2365           break;
2366         case 4:
2367           if (debug > 1) {
2368             debug("CSI ? 4 i : Start passthrough printing");
2369           }
2370           break;
2371         case 5:
2372           if (debug > 1) {
2373             debug("CSI ? 4 i : Stop passthrough printing");
2374           }
2375           break;
2376         }
2377         break;
2378       case 'l': // DECRST
2379         /* DEC Mode reset */
2380         if (debug > 0) {
2381           debug("ESC [ ? " + DCEvars[0] + " l");
2382         }
2383         for (int i = 0; i <= DCEvar; i++) {
2384           switch (DCEvars[i]) {
2385           case 1: /* Application cursor keys */
2386             KeyUp[0] = "\u001b[A";
2387             KeyDown[0] = "\u001b[B";
2388             KeyRight[0] = "\u001b[C";
2389             KeyLeft[0] = "\u001b[D";
2390             break;
2391           case 2: /* DECANM */
2392             vt52mode = true;
2393             break;
2394           case 3: /* 80 columns */
2395             setScreenSize(80, height, true);
2396             break;
2397           case 6: /* DECOM: move outside margins. */
2398             moveoutsidemargins = true;
2399             break;
2400           case 7: /* DECAWM: Autowrap Mode OFF */
2401             wraparound = false;
2402             break;
2403           case 25: /* turn cursor off */
2404             showCursor(false);
2405             break;
2406           /* Unimplemented stuff: */
2407           /* 4 - scrolling mode, jump */
2408           /* 5 - dark background */
2409           /* 7 - DECAWM - no wrap around mode */
2410           /* 12 - local echo on */
2411           /* 18 - DECPFF - Printer Form Feed Mode -> Off */
2412           /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
2413           case 9: /* X10 mouse */
2414           case 1000: /* xterm style mouse report OFF */
2415           case 1001:
2416           case 1002:
2417           case 1003:
2418             mouserpt = 0;
2419             break;
2420           default:
2421             debug("ESC [ ? " + DCEvars[0] + " l, unsupported.");
2422             break;
2423           }
2424         }
2425         break;
2426       case 'n':
2427         if (debug > 0) {
2428           debug("ESC [ ? " + DCEvars[0] + " n");
2429         }
2430         switch (DCEvars[0]) {
2431         case 15:
2432           /* printer? no printer. */
2433           write((ESC) + "[?13n", false);
2434           debug("ESC[5n");
2435           break;
2436         default:
2437           debug("ESC [ ? " + DCEvars[0] + " n, unsupported.");
2438           break;
2439         }
2440         break;
2441       default:
2442         debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
2443         break;
2444       }
2445       break;
2446     case TSTATE_CSI_EX:
2447       term_state = TSTATE_DATA;
2448       switch (c) {
2449       case ESC:
2450         term_state = TSTATE_ESC;
2451         break;
2452       default:
2453         debug("Unknown character ESC[! character is " + (int) c);
2454         break;
2455       }
2456       break;
2457     case TSTATE_CSI_TICKS:
2458       term_state = TSTATE_DATA;
2459       switch (c) {
2460       case 'p':
2461         debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
2462         if (DCEvars[0] == 61) {
2463           output8bit = false;
2464           break;
2465         }
2466         if (DCEvars[1] == 1) {
2467           output8bit = false;
2468         } else {
2469           output8bit = true; /* 0 or 2 */
2470         }
2471         break;
2472       default:
2473         debug("Unknown ESC [...  \"" + c);
2474         break;
2475       }
2476       break;
2477     case TSTATE_CSI_EQUAL:
2478       term_state = TSTATE_DATA;
2479       switch (c) {
2480       case '0':
2481       case '1':
2482       case '2':
2483       case '3':
2484       case '4':
2485       case '5':
2486       case '6':
2487       case '7':
2488       case '8':
2489       case '9':
2490         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2491         term_state = TSTATE_CSI_EQUAL;
2492         break;
2493       case ';':
2494         DCEvar++;
2495         DCEvars[DCEvar] = 0;
2496         term_state = TSTATE_CSI_EQUAL;
2497         break;
2498 
2499       case 'F': /* SCO ANSI foreground */
2500       {
2501         int newcolor;
2502 
2503         debug("ESC [ = " + DCEvars[0] + " F");
2504 
2505         attributes &= ~COLOR_FG;
2506         newcolor = ((DCEvars[0] & 1) << 2) | (DCEvars[0] & 2) | ((DCEvars[0] & 4) >> 2);
2507         attributes |= (newcolor + 1) << COLOR_FG_SHIFT;
2508 
2509         break;
2510       }
2511       case 'G': /* SCO ANSI background */
2512       {
2513         int newcolor;
2514 
2515         debug("ESC [ = " + DCEvars[0] + " G");
2516 
2517         attributes &= ~COLOR_BG;
2518         newcolor = ((DCEvars[0] & 1) << 2) | (DCEvars[0] & 2) | ((DCEvars[0] & 4) >> 2);
2519         attributes |= (newcolor + 1) << COLOR_BG_SHIFT;
2520         break;
2521       }
2522 
2523       default:
2524         debugStr.append("Unknown ESC [ = ");
2525         for (int i = 0; i <= DCEvar; i++) {
2526           debugStr.append(DCEvars[i]).append(',');
2527         }
2528         debugStr.append(c);
2529         debug(debugStr.toString());
2530         debugStr.setLength(0);
2531         break;
2532       }
2533       break;
2534     case TSTATE_CSI_DOLLAR:
2535       term_state = TSTATE_DATA;
2536       switch (c) {
2537       case '}':
2538         debug("Active Status Display now " + DCEvars[0]);
2539         statusmode = DCEvars[0];
2540         break;
2541       /*
2542        * bad documentation? case '-': debug("Set Status Display now "+DCEvars[0]); break;
2543        */
2544       case '~':
2545         debug("Status Line mode now " + DCEvars[0]);
2546         break;
2547       default:
2548         debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
2549         break;
2550       }
2551       break;
2552     case TSTATE_CSI:
2553       term_state = TSTATE_DATA;
2554       switch (c) {
2555       case '"':
2556         term_state = TSTATE_CSI_TICKS;
2557         break;
2558       case '$':
2559         term_state = TSTATE_CSI_DOLLAR;
2560         break;
2561       case '=':
2562         term_state = TSTATE_CSI_EQUAL;
2563         break;
2564       case '!':
2565         term_state = TSTATE_CSI_EX;
2566         break;
2567       case '?':
2568         DCEvar = 0;
2569         DCEvars[0] = 0;
2570         term_state = TSTATE_DCEQ;
2571         break;
2572       case '0':
2573       case '1':
2574       case '2':
2575       case '3':
2576       case '4':
2577       case '5':
2578       case '6':
2579       case '7':
2580       case '8':
2581       case '9':
2582         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2583         term_state = TSTATE_CSI;
2584         break;
2585       case ';':
2586         DCEvar++;
2587         DCEvars[DCEvar] = 0;
2588         term_state = TSTATE_CSI;
2589         break;
2590       case 'c':/* send primary device attributes */
2591         /* send (ESC[?61c) */
2592 
2593         String subcode = "";
2594         if (terminalID.equals("vt320")) {
2595           subcode = "63;";
2596         }
2597         if (terminalID.equals("vt220")) {
2598           subcode = "62;";
2599         }
2600         if (terminalID.equals("vt100")) {
2601           subcode = "61;";
2602         }
2603         write((ESC) + "[?" + subcode + "1;2c", false);
2604         if (debug > 1) {
2605           debug("ESC [ " + DCEvars[0] + " c");
2606         }
2607         break;
2608       case 'q':
2609         if (debug > 1) {
2610           debug("ESC [ " + DCEvars[0] + " q");
2611         }
2612         break;
2613       case 'g':
2614         /* used for tabsets */
2615         switch (DCEvars[0]) {
2616         case 3:/* clear them */
2617           Tabs = new byte[width];
2618           break;
2619         case 0:
2620           Tabs[C] = 0;
2621           break;
2622         }
2623         if (debug > 1) {
2624           debug("ESC [ " + DCEvars[0] + " g");
2625         }
2626         break;
2627       case 'h':
2628         switch (DCEvars[0]) {
2629         case 4:
2630           insertmode = 1;
2631           break;
2632         case 20:
2633           debug("Setting CRLF to TRUE");
2634           sendcrlf = true;
2635           break;
2636         default:
2637           debug("unsupported: ESC [ " + DCEvars[0] + " h");
2638           break;
2639         }
2640         if (debug > 1) {
2641           debug("ESC [ " + DCEvars[0] + " h");
2642         }
2643         break;
2644       case 'i': // Printer Controller mode.
2645         // "Transparent printing sends all output, except the CSI 4 i
2646         // termination string, to the printer and not the screen,
2647         // uses an 8-bit channel if no parity so NUL and DEL will be
2648         // seen by the printer and by the termination recognizer code,
2649         // and all translation and character set selections are
2650         // bypassed."
2651         switch (DCEvars[0]) {
2652         case 0:
2653           if (debug > 1) {
2654             debug("CSI 0 i:  Print Screen, not implemented.");
2655           }
2656           break;
2657         case 4:
2658           if (debug > 1) {
2659             debug("CSI 4 i:  Enable Transparent Printing, not implemented.");
2660           }
2661           break;
2662         case 5:
2663           if (debug > 1) {
2664             debug("CSI 4/5 i:  Disable Transparent Printing, not implemented.");
2665           }
2666           break;
2667         default:
2668           debug("ESC [ " + DCEvars[0] + " i, unimplemented!");
2669         }
2670         break;
2671       case 'l':
2672         switch (DCEvars[0]) {
2673         case 4:
2674           insertmode = 0;
2675           break;
2676         case 20:
2677           debug("Setting CRLF to FALSE");
2678           sendcrlf = false;
2679           break;
2680         default:
2681           debug("ESC [ " + DCEvars[0] + " l, unimplemented!");
2682           break;
2683         }
2684         break;
2685       case 'A': // CUU
2686       {
2687         int limit;
2688         /* FIXME: xterm only cares about 0 and topmargin */
2689         if (R >= getTopMargin()) {
2690           limit = getTopMargin();
2691         } else {
2692           limit = 0;
2693         }
2694         if (DCEvars[0] == 0) {
2695           R--;
2696         } else {
2697           R -= DCEvars[0];
2698         }
2699         if (R < limit) {
2700           R = limit;
2701         }
2702         if (debug > 1) {
2703           debug("ESC [ " + DCEvars[0] + " A");
2704         }
2705         break;
2706       }
2707       case 'B': // CUD
2708         /* cursor down n (1) times */
2709       {
2710         int limit;
2711         if (R <= getBottomMargin()) {
2712           limit = getBottomMargin();
2713         } else {
2714           limit = rows - 1;
2715         }
2716         if (DCEvars[0] == 0) {
2717           R++;
2718         } else {
2719           R += DCEvars[0];
2720         }
2721         if (R > limit) {
2722           R = limit;
2723         } else {
2724           if (debug > 2) {
2725             debug("Not limited.");
2726           }
2727         }
2728         if (debug > 2) {
2729           debug("to: " + R);
2730         }
2731         if (debug > 1) {
2732           debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
2733         }
2734         break;
2735       }
2736       case 'C':
2737         if (DCEvars[0] == 0) {
2738           DCEvars[0] = 1;
2739         }
2740         while (DCEvars[0]-- > 0) {
2741           C++;
2742         }
2743         if (C >= columns) {
2744           C = columns - 1;
2745         }
2746         if (debug > 1) {
2747           debug("ESC [ " + DCEvars[0] + " C");
2748         }
2749         break;
2750       case 'd': // CVA
2751         R = DCEvars[0];
2752         if (R < 0) {
2753           R = 0;
2754         } else if (R >= height) {
2755           R = height - 1;
2756         }
2757         if (debug > 1) {
2758           debug("ESC [ " + DCEvars[0] + " d");
2759         }
2760         break;
2761       case 'D':
2762         if (DCEvars[0] == 0) {
2763           DCEvars[0] = 1;
2764         }
2765         while (DCEvars[0]-- > 0) {
2766           C--;
2767         }
2768         if (C < 0) {
2769           C = 0;
2770         }
2771         if (debug > 1) {
2772           debug("ESC [ " + DCEvars[0] + " D");
2773         }
2774         break;
2775       case 'r': // DECSTBM
2776         if (DCEvar > 0) // Ray: Any argument is optional
2777         {
2778           R = DCEvars[1] - 1;
2779           if (R < 0) {
2780             R = rows - 1;
2781           } else if (R >= rows) {
2782             R = rows - 1;
2783           }
2784         } else {
2785           R = rows - 1;
2786         }
2787         int bot = R;
2788         if (R >= DCEvars[0]) {
2789           R = DCEvars[0] - 1;
2790           if (R < 0) {
2791             R = 0;
2792           }
2793         }
2794         setMargins(R, bot);
2795         _SetCursor(0, 0);
2796         if (debug > 1) {
2797           debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
2798         }
2799         break;
2800       case 'G': /* CUP / cursor absolute column */
2801         C = DCEvars[0];
2802         if (C < 0) {
2803           C = 0;
2804         } else if (C >= width) {
2805           C = width - 1;
2806         }
2807         if (debug > 1) {
2808           debug("ESC [ " + DCEvars[0] + " G");
2809         }
2810         break;
2811       case 'H': /* CUP / cursor position */
2812         /* gets 2 arguments */
2813         _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
2814         if (debug > 2) {
2815           debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins "
2816               + moveoutsidemargins);
2817           debug("	-> R now " + R + ", C now " + C);
2818         }
2819         break;
2820       case 'f': /* move cursor 2 */
2821         /* gets 2 arguments */
2822         R = DCEvars[0] - 1;
2823         C = DCEvars[1] - 1;
2824         if (C < 0) {
2825           C = 0;
2826         } else if (C >= width) {
2827           C = width - 1;
2828         }
2829         if (R < 0) {
2830           R = 0;
2831         } else if (R >= height) {
2832           R = height - 1;
2833         }
2834         if (debug > 2) {
2835           debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
2836         }
2837         break;
2838       case 'S': /* ind aka 'scroll forward' */
2839         if (DCEvars[0] == 0) {
2840           insertLine(rows - 1, SCROLL_UP);
2841         } else {
2842           insertLine(rows - 1, DCEvars[0], SCROLL_UP);
2843         }
2844         break;
2845       case 'L':
2846         /* insert n lines */
2847         if (DCEvars[0] == 0) {
2848           insertLine(R, SCROLL_DOWN);
2849         } else {
2850           insertLine(R, DCEvars[0], SCROLL_DOWN);
2851         }
2852         if (debug > 1) {
2853           debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
2854         }
2855         break;
2856       case 'T': /* 'ri' aka scroll backward */
2857         if (DCEvars[0] == 0) {
2858           insertLine(0, SCROLL_DOWN);
2859         } else {
2860           insertLine(0, DCEvars[0], SCROLL_DOWN);
2861         }
2862         break;
2863       case 'M':
2864         if (debug > 1) {
2865           debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
2866         }
2867         if (DCEvars[0] == 0) {
2868           deleteLine(R);
2869         } else {
2870           for (int i = 0; i < DCEvars[0]; i++) {
2871             deleteLine(R);
2872           }
2873         }
2874         break;
2875       case 'K':
2876         if (debug > 1) {
2877           debug("ESC [ " + DCEvars[0] + " K");
2878         }
2879         /* clear in line */
2880         switch (DCEvars[0]) {
2881         case 6: /* 97801 uses ESC[6K for delete to end of line */
2882         case 0:/* clear to right */
2883           if (C < columns - 1) {
2884             deleteArea(C, R, columns - C, 1, attributes);
2885           }
2886           break;
2887         case 1:/* clear to the left, including this */
2888           if (C > 0) {
2889             deleteArea(0, R, C + 1, 1, attributes);
2890           }
2891           break;
2892         case 2:/* clear whole line */
2893           deleteArea(0, R, columns, 1, attributes);
2894           break;
2895         }
2896         break;
2897       case 'J':
2898         /* clear below current line */
2899         switch (DCEvars[0]) {
2900         case 0:
2901           if (R < rows - 1) {
2902             deleteArea(0, R + 1, columns, rows - R - 1, attributes);
2903           }
2904           if (C < columns - 1) {
2905             deleteArea(C, R, columns - C, 1, attributes);
2906           }
2907           break;
2908         case 1:
2909           if (R > 0) {
2910             deleteArea(0, 0, columns, R, attributes);
2911           }
2912           if (C > 0) {
2913             deleteArea(0, R, C + 1, 1, attributes);// include up to and including current
2914           }
2915           break;
2916         case 2:
2917           deleteArea(0, 0, columns, rows, attributes);
2918           break;
2919         }
2920         if (debug > 1) {
2921           debug("ESC [ " + DCEvars[0] + " J");
2922         }
2923         break;
2924       case '@':
2925         if (debug > 1) {
2926           debug("ESC [ " + DCEvars[0] + " @");
2927         }
2928         for (int i = 0; i < DCEvars[0]; i++) {
2929           insertChar(C, R, ' ', attributes);
2930         }
2931         break;
2932       case 'X': {
2933         int toerase = DCEvars[0];
2934         if (debug > 1) {
2935           debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
2936         }
2937         if (toerase == 0) {
2938           toerase = 1;
2939         }
2940         if (toerase + C > columns) {
2941           toerase = columns - C;
2942         }
2943         deleteArea(C, R, toerase, 1, attributes);
2944         // does not change cursor position
2945         break;
2946       }
2947       case 'P':
2948         if (debug > 1) {
2949           debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
2950         }
2951         if (DCEvars[0] == 0) {
2952           DCEvars[0] = 1;
2953         }
2954         for (int i = 0; i < DCEvars[0]; i++) {
2955           deleteChar(C, R);
2956         }
2957         break;
2958       case 'n':
2959         switch (DCEvars[0]) {
2960         case 5: /* malfunction? No malfunction. */
2961           writeSpecial((ESC) + "[0n");
2962           if (debug > 1) {
2963             debug("ESC[5n");
2964           }
2965           break;
2966         case 6:
2967           // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
2968           // FIXME check again.
2969           // FIXME: but vttest thinks different???
2970           writeSpecial((ESC) + "[" + R + ";" + C + "R");
2971           if (debug > 1) {
2972             debug("ESC[6n");
2973           }
2974           break;
2975         default:
2976           if (debug > 0) {
2977             debug("ESC [ " + DCEvars[0] + " n??");
2978           }
2979           break;
2980         }
2981         break;
2982       case 's': /* DECSC - save cursor */
2983         Sc = C;
2984         Sr = R;
2985         Sa = attributes;
2986         if (debug > 3) {
2987           debug("ESC[s");
2988         }
2989         break;
2990       case 'u': /* DECRC - restore cursor */
2991         C = Sc;
2992         R = Sr;
2993         attributes = Sa;
2994         if (debug > 3) {
2995           debug("ESC[u");
2996         }
2997         break;
2998       case 'm': /* attributes as color, bold , blink, */
2999         if (debug > 3) {
3000           debug("ESC [ ");
3001         }
3002         if (DCEvar == 0 && DCEvars[0] == 0) {
3003           attributes = 0;
3004         }
3005         for (int i = 0; i <= DCEvar; i++) {
3006           switch (DCEvars[i]) {
3007           case 0:
3008             if (DCEvar > 0) {
3009               if (terminalID.equals("scoansi")) {
3010                 attributes &= COLOR; /* Keeps color. Strange but true. */
3011               } else {
3012                 attributes = 0;
3013               }
3014             }
3015             break;
3016           case 1:
3017             attributes |= BOLD;
3018             attributes &= ~LOW;
3019             break;
3020           case 2:
3021             /* SCO color hack mode */
3022             if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
3023               int ncolor;
3024               attributes &= ~(COLOR | BOLD);
3025 
3026               ncolor = DCEvars[i + 1];
3027               if ((ncolor & 8) == 8) {
3028                 attributes |= BOLD;
3029               }
3030               ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3031               attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
3032               ncolor = DCEvars[i + 2];
3033               ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3034               attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
3035               i += 2;
3036             } else {
3037               attributes |= LOW;
3038             }
3039             break;
3040           case 3: /* italics */
3041             attributes |= INVERT;
3042             break;
3043           case 4:
3044             attributes |= UNDERLINE;
3045             break;
3046           case 7:
3047             attributes |= INVERT;
3048             break;
3049           case 8:
3050             attributes |= INVISIBLE;
3051             break;
3052           case 5: /* blink on */
3053             break;
3054           /*
3055            * 10 - ANSI X3.64-1979, select primary font, don't display control chars, don't set bit 8
3056            * on output
3057            */
3058           case 10:
3059             gl = 0;
3060             usedcharsets = true;
3061             break;
3062           /*
3063            * 11 - ANSI X3.64-1979, select second alt. font, display control chars, set bit 8 on
3064            * output
3065            */
3066           case 11: /* SMACS , as */
3067           case 12:
3068             gl = 1;
3069             usedcharsets = true;
3070             break;
3071           case 21: /* normal intensity */
3072             attributes &= ~(LOW | BOLD);
3073             break;
3074           case 23: /* italics off */
3075             attributes &= ~INVERT;
3076             break;
3077           case 25: /* blinking off */
3078             break;
3079           case 27:
3080             attributes &= ~INVERT;
3081             break;
3082           case 28:
3083             attributes &= ~INVISIBLE;
3084             break;
3085           case 24:
3086             attributes &= ~UNDERLINE;
3087             break;
3088           case 22:
3089             attributes &= ~BOLD;
3090             break;
3091           case 30:
3092           case 31:
3093           case 32:
3094           case 33:
3095           case 34:
3096           case 35:
3097           case 36:
3098           case 37:
3099             attributes &= ~COLOR_FG;
3100             attributes |= ((DCEvars[i] - 30) + 1) << COLOR_FG_SHIFT;
3101             break;
3102           case 38:
3103             if (DCEvars[i + 1] == 5) {
3104               attributes &= ~COLOR_FG;
3105               attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT;
3106               i += 2;
3107             }
3108             break;
3109           case 39:
3110             attributes &= ~COLOR_FG;
3111             break;
3112           case 40:
3113           case 41:
3114           case 42:
3115           case 43:
3116           case 44:
3117           case 45:
3118           case 46:
3119           case 47:
3120             attributes &= ~COLOR_BG;
3121             attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
3122             break;
3123           case 48:
3124             if (DCEvars[i + 1] == 5) {
3125               attributes &= ~COLOR_BG;
3126               attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT;
3127               i += 2;
3128             }
3129             break;
3130           case 49:
3131             attributes &= ~COLOR_BG;
3132             break;
3133           case 90:
3134           case 91:
3135           case 92:
3136           case 93:
3137           case 94:
3138           case 95:
3139           case 96:
3140           case 97:
3141             attributes &= ~COLOR_FG;
3142             attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT;
3143             break;
3144           case 100:
3145           case 101:
3146           case 102:
3147           case 103:
3148           case 104:
3149           case 105:
3150           case 106:
3151           case 107:
3152             attributes &= ~COLOR_BG;
3153             attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT;
3154             break;
3155 
3156           default:
3157             debugStr.append("ESC [ ").append(DCEvars[i]).append(" m unknown...");
3158             debug(debugStr.toString());
3159             debugStr.setLength(0);
3160             break;
3161           }
3162           if (debug > 3) {
3163             debugStr.append(DCEvars[i]).append(';');
3164             debug(debugStr.toString());
3165             debugStr.setLength(0);
3166           }
3167         }
3168         if (debug > 3) {
3169           debugStr.append(" (attributes = ").append(attributes).append(")m");
3170           debug(debugStr.toString());
3171           debugStr.setLength(0);
3172         }
3173         break;
3174       default:
3175         debugStr.append("ESC [ unknown letter: ").append(c).append(" (").append((int) c)
3176             .append(')');
3177         debug(debugStr.toString());
3178         debugStr.setLength(0);
3179         break;
3180       }
3181       break;
3182     case TSTATE_TITLE:
3183       switch (c) {
3184       case ESC:
3185         term_state = TSTATE_ESC;
3186         break;
3187       default:
3188         // TODO save title
3189         break;
3190       }
3191       break;
3192     default:
3193       term_state = TSTATE_DATA;
3194       break;
3195     }
3196 
3197     setCursorPosition(C, R);
3198   }
3199 
3200   /* hard reset the terminal */
reset()3201   public void reset() {
3202     gx[0] = 'B';
3203     gx[1] = 'B';
3204     gx[2] = 'B';
3205     gx[3] = 'B';
3206 
3207     gl = 0; // default GL to G0
3208     gr = 2; // default GR to G2
3209 
3210     onegl = -1; // Single shift override
3211 
3212     /* reset tabs */
3213     int nw = width;
3214     if (nw < 132) {
3215       nw = 132;
3216     }
3217     Tabs = new byte[nw];
3218     for (int i = 0; i < nw; i += 8) {
3219       Tabs[i] = 1;
3220     }
3221 
3222     deleteArea(0, 0, width, height, attributes);
3223     setMargins(0, height);
3224     C = R = 0;
3225     _SetCursor(0, 0);
3226 
3227     if (display != null) {
3228       display.resetColors();
3229     }
3230 
3231     showCursor(true);
3232     /* FIXME: */
3233     term_state = TSTATE_DATA;
3234   }
3235 }
3236