From 8804ea8bd15e1fafbb68b7909aea19cdacf5ca72 Mon Sep 17 00:00:00 2001 From: adam Date: Sat, 16 Sep 2006 15:35:00 +0100 Subject: [PATCH] added applet mode, terminal window --- Makefile | 4 + src/de/mud/telnet/CharDisplayTest.java | 169 ++ src/de/mud/telnet/IOtest.java | 67 + src/de/mud/telnet/appWrapper.java | 262 +++ src/de/mud/telnet/display/CharDisplay.java | 1275 ++++++++++++++ src/de/mud/telnet/display/SoftFont.java | 1009 ++++++++++++ src/de/mud/telnet/display/Terminal.java | 73 + src/de/mud/telnet/display/TerminalHost.java | 46 + src/de/mud/telnet/display/vt320.java | 2018 +++++++++++++++++++++++ src/de/mud/telnet/frame.java | 55 + src/de/mud/telnet/modules/ButtonBar.java | 389 +++++ src/de/mud/telnet/modules/Module.java | 64 + src/de/mud/telnet/modules/Script.java | 181 ++ src/de/mud/telnet/modules/TextLabel.java | 113 ++ src/de/mud/telnet/socket/StatusPeer.java | 51 + src/de/mud/telnet/socket/TelnetIO.java | 618 +++++++ src/de/mud/telnet/socket/TelnetWrapper.java | 400 +++++ src/de/mud/telnet/socket/TimedOutException.java | 23 + src/de/mud/telnet/telnet.java | 562 +++++++ src/edu/berkeley/fleet/Fleet.java | 2 +- src/edu/berkeley/fleet/FleetApplet.java | 81 + src/edu/berkeley/fleet/FleetParser.java | 37 +- src/edu/berkeley/fleet/Log.java | 25 + src/edu/berkeley/fleet/Program.java | 6 +- src/edu/berkeley/fleet/Ship.java | 2 +- src/edu/berkeley/fleet/Term.java | 57 + test.fleet | 37 +- 27 files changed, 7579 insertions(+), 47 deletions(-) create mode 100644 src/de/mud/telnet/CharDisplayTest.java create mode 100644 src/de/mud/telnet/IOtest.java create mode 100644 src/de/mud/telnet/appWrapper.java create mode 100644 src/de/mud/telnet/display/CharDisplay.java create mode 100644 src/de/mud/telnet/display/SoftFont.java create mode 100644 src/de/mud/telnet/display/Terminal.java create mode 100644 src/de/mud/telnet/display/TerminalHost.java create mode 100644 src/de/mud/telnet/display/vt320.java create mode 100644 src/de/mud/telnet/frame.java create mode 100644 src/de/mud/telnet/modules/ButtonBar.java create mode 100644 src/de/mud/telnet/modules/Module.java create mode 100644 src/de/mud/telnet/modules/Script.java create mode 100644 src/de/mud/telnet/modules/TextLabel.java create mode 100644 src/de/mud/telnet/socket/StatusPeer.java create mode 100644 src/de/mud/telnet/socket/TelnetIO.java create mode 100644 src/de/mud/telnet/socket/TelnetWrapper.java create mode 100644 src/de/mud/telnet/socket/TimedOutException.java create mode 100644 src/de/mud/telnet/telnet.java create mode 100644 src/edu/berkeley/fleet/FleetApplet.java create mode 100644 src/edu/berkeley/fleet/Log.java create mode 100644 src/edu/berkeley/fleet/Term.java diff --git a/Makefile b/Makefile index 3626bcd..5c7aa9e 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,12 @@ run: fleet.jar java -cp lib/edu.berkeley.sbp.jar:fleet.jar edu.berkeley.fleet.FleetParser < test.fleet +applet: fleet.jar + java -cp lib/edu.berkeley.sbp.jar:fleet.jar edu.berkeley.fleet.FleetApplet < test.fleet + fleet.jar: $(shell find src -name \*.java) fleet.g mkdir -p bin cp fleet.g bin + cp test.fleet bin javac -cp lib/edu.berkeley.sbp.jar -d bin $(shell find src -name \*.java) cd bin; jar cvf ../$@ . diff --git a/src/de/mud/telnet/CharDisplayTest.java b/src/de/mud/telnet/CharDisplayTest.java new file mode 100644 index 0000000..b40deb8 --- /dev/null +++ b/src/de/mud/telnet/CharDisplayTest.java @@ -0,0 +1,169 @@ +package de.mud.telnet; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * CharDisplayTest + * -- + * $Id: CharDisplayTest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * $timestamp: Mon Feb 17 20:11:20 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.applet.Applet; +import java.awt.Button; +import java.awt.Panel; +import java.awt.Event; +import java.awt.FlowLayout; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.TextField; +import java.awt.Font; + +import de.mud.telnet.display.CharDisplay; + +/** + * CharDisplayTest -- a test applet to show the display/CharDisplay features + * -- + * @version $Id: CharDisplayTest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class CharDisplayTest extends Applet +{ + CharDisplay display = new CharDisplay(80, 24, "Courier", 14); + + Panel buttons = new Panel(); + Button info = new Button("Information"); + Button chars = new Button("Character Table"); + Button attr = new Button("Attributes"); + Choice fonts = new Choice(); + TextField from = new TextField("0", 4); + + public void init() + { + setLayout(new BorderLayout()); + fonts.addItem("Helvetica"); + fonts.addItem("TimesRoman"); + fonts.addItem("Courier"); + fonts.addItem("Dialog"); + fonts.addItem("DialogInput"); + fonts.addItem("ZapfDingBats"); + fonts.addItem("default"); + buttons.add(info); + buttons.add(chars); + buttons.add(attr); + buttons.add(fonts); + buttons.add(from); + add("North", buttons); + display.setResizeStrategy(CharDisplay.RESIZE_FONT); + add("Center", display); + Info(); + } + + public boolean handleEvent(Event evt) + { + if(evt.target == info) { Info(); return true; } + if(evt.target == chars) { CharacterTable(); return true; } + if(evt.target == attr) { Attributes(); return true; } + if(evt.id == Event.ACTION_EVENT && + (evt.target == fonts || evt.target == from)) + { + remove(display); + display = new CharDisplay(80, 24, fonts.getSelectedItem(), 12); + add("Center", display); + CharacterTable(); + layout(); + return true; + } + return false; + } + + private void Clear() + { + display.deleteArea(0, 0, 80, 24); + } + + private void Info() + { + Clear(); + display.putString(4, 1, "CharDisplay.class Information", CharDisplay.INVERT); + display.putString(4, 3, "Version: "+display.version, CharDisplay.BOLD); + display.putString(4, 5, "This class implements several hardware features needed to implement"); + display.putString(4, 6, "a video terminal."); + display.putString(4, 7, "This includes simple operations, such as putting and inserting single"); + display.putString(4, 8, "characters or strings on the screen, character attributes and colors."); + display.putString(4, 9, "Special features like inserting lines, scrolling text up or down and"); + display.putString(4,10, "defining scrollareas help implementing terminal emulations."); + display.redraw(); + } + + private void CharacterTable() + { + int ch = (new Integer(from.getText())).intValue(); + + Clear(); + display.putString( 4, 1, "Character Table", CharDisplay.INVERT); + for(int c = 1; c < 80; c += 6) + for(int l = 3; l < 23; l++) + { + display.putString(c, l, ""+ch, CharDisplay.INVERT); + display.putChar(c+4, l, (char)ch++); + } + display.markLine(3, 20); + display.redraw(); + } + + private void Attributes() + { + int c = 4, l = 8; + + Clear(); + display.putString( 4, 1, "Character attributes", CharDisplay.INVERT); + display.putString( 4, 3, "Normal", CharDisplay.NORMAL); + display.putString(22, 3, "Bold", CharDisplay.BOLD); + display.putString(40, 3, "Underline", CharDisplay.UNDERLINE); + display.putString(58, 3, "Invert", CharDisplay.INVERT); + + display.putString( 4, 5, "Black", 1 << 3 | 8 << 7); + display.putString(13, 5, "Red", 2 << 3); + display.putString(22, 5, "Green", 3 << 3); + display.putString(31, 5, "Yellow", 4 << 3); + display.putString(40, 5, "Blue", 5 << 3); + display.putString(49, 5, "Magenta", 6 << 3); + display.putString(58, 5, "Cyan", 7 << 3); + display.putString(67, 5, "LightGray", 8 << 3); + + for(int bg = 1; bg <= 8; bg++) + { + for(int fg = 1; fg <= 8; fg++) + { + for(int a = 0; a <= 7; a++) + { + display.putChar(c++, l, '@', (fg << 3) | (bg << 7) | a); + display.redraw(); + } + c++; + } + l += 2; c = 4; + } + + } +} diff --git a/src/de/mud/telnet/IOtest.java b/src/de/mud/telnet/IOtest.java new file mode 100644 index 0000000..9f0eff3 --- /dev/null +++ b/src/de/mud/telnet/IOtest.java @@ -0,0 +1,67 @@ +package de.mud.telnet; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/* IOtest.java -- An example how to use the TelnetIO class + * -- + * Author: Matthias L. Jugel + * + * Usage: compile with javac IOtest.java + * run program with java IOtest + * + * This is not an applet, but the idea might be used in one. + */ + +import java.util.Vector; +import java.io.*; +import de.mud.telnet.socket.*; + +/** + * IOtest -- a test class for telnet i/o + * -- + * @version $Id: IOtest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * @author Matthias L. Jugel + */ +class IOtest { + + // create a new telnet io instance + static TelnetIO tio = new TelnetIO(); + + // skip any received data until the prompt appears + private static void wait(String prompt) + { + String tmp = ""; + do { + try { tmp = new String(tio.receive(), 0); } + catch(IOException e) { e.printStackTrace(); } + System.out.println(tmp); + } while(tmp.indexOf(prompt) == -1); + } + + // send a string to the remote host, since TelnetIO needs a byte buffer + // we have to convert the string first + private static void send(String str) + { + byte[] buf = new byte[str.length()]; + str.getBytes(0, str.length(), buf, 0); + try { tio.send(buf); } catch(IOException e) {} + } + + // this function is called when running the class with java IOtest + // looks very much like a modem login script ;-) + public static void main(String args[]) + { + try { + tio.connect("localhost"); + wait("login:"); + send("\r"); + wait("Password:"); + send("\r"); + wait(""); + send("touch /tmp/THIS_WAS_AN_APPLET\r"); + tio.disconnect(); + } catch(IOException e) { e.printStackTrace(); } + } +} diff --git a/src/de/mud/telnet/appWrapper.java b/src/de/mud/telnet/appWrapper.java new file mode 100644 index 0000000..ad38743 --- /dev/null +++ b/src/de/mud/telnet/appWrapper.java @@ -0,0 +1,262 @@ +package de.mud.telnet; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * appWrapper -- applet/application wrapper + * -- + * $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $ + * $timestamp: Thu Jul 24 13:08:23 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.applet.Applet; +import java.applet.AppletStub; + +import java.awt.Frame; +import java.awt.Event; +import java.awt.Panel; +import java.awt.Button; +import java.awt.BorderLayout; +import java.awt.Graphics; +import java.awt.Color; +import java.awt.FontMetrics; + +/** + * The appWrapper is thought to make the applet itself independent from + * the original context. This is necessary to be able to detach the applet + * from the web browsers window without disconnecting it from events. + * Note: This applet should work with any applet without changes. + * + *
+ *
<PARAM NAME="applet" VALUE="applet">
+ *
Defines the applet to be loaded by the appWrapper. State the applet + * class name without ".class"!

+ *

<PARAM NAME="startButton" VALUE="text">
+ *
If this parameter is set the applet is not loaded until the user presses + * the button. This decreases first time download delay. The text + * given as value to the parameter is shown on the button. While loading + * the applet the message "Loading ..." is shown on the button.

+ *

<PARAM NAME="stopButton" VALUE="text">
+ *
This parameter defines the button text when the applet is loaded. When + * pressing the button while the applet is running this causes the applet + * window to be destroyed and the applet is stopped.

+ *

<PARAM NAME="frameTitle" VALUE="text">
+ *
The frameTitle is the text that is shown in the title bar of the + * applet window.

+ *

+ * @version $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $ + * @author Matthias L. Jugel + */ +public class appWrapper extends Applet implements AppletStub, Runnable +{ + Thread loader = null; + + String appletName = null; + Applet applet = null; + + Button startButton = null; + String startLabel, stopLabel, frameTitle; + + frame f; + + /** + * Applet initialization. We load the class giving in parameter "applet" + * and set the stub corresponding to ours. Thus we are able to give + * it access to the parameters and any applet specific context. + */ + public void init() { + + // get the applet parameter + if((appletName = getParameter("applet")) == null) { + showStatus("appWrapper: missing applet parameter, nothing loaded"); + System.err.println("appWrapper: missing applet parameter"); + return; + } + + setLayout(new BorderLayout()); + + // get the button and title parameters + if((startLabel = getParameter("startButton")) == null) + run(); + else { + startButton = new Button(getParameter("startButton")); + add("Center", startButton); + if((stopLabel = getParameter("stopButton")) == null) + stopLabel = "STOP!"; + if((frameTitle = getParameter("frameTitle")) == null) + frameTitle = "The Java Telnet Applet"; + } + + } + + /** + * Load the applet finally. When using a button this creates a new frame + * to put the applet in. + */ + public void run() { + if(applet == null) try { + applet = (Applet)Class.forName(getParameter("applet")).newInstance(); + applet.setStub(this); + } catch(Exception e) { + System.err.println("appWrapper: could not load "+appletName); + e.printStackTrace(); + return; + } else { + System.err.println("appWrapper: applet already loaded"); + return; + } + + if(startButton == null) { + add("Center", applet); + applet.init(); + } else { + f = new frame(frameTitle); + f.setLayout(new BorderLayout()); + f.add("Center", applet); + applet.init(); + f.resize(applet.minimumSize()); + f.pack(); + f.show(); + } + applet.start(); + + if(startButton != null) + startButton.setLabel(stopLabel); + + // stop loader thread + while(loader != null) { + if(f == null || !f.isVisible()) { + startButton.setLabel(startLabel); + loader.stop(); + loader = null; + } + try { loader.sleep(5000); } + catch(InterruptedException e) { + e.printStackTrace(); + } + } + } + + /** + * This method is called when the applet want's to be resized. + * @param width the width of the applet + * @param height the height of the applet + */ + public void appletResize(int width, int height) { + System.err.println("appWrapper: appletResize()"); + if(applet != null) applet.resize(width, height); + } + + /** + * Give information about the applet. + */ + public String getAppletInfo() + { + String info = "appWrapper: $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $\n"; + if(applet != null) + info += applet.getAppletInfo(); + return info; + } + + /** + * Give information about the appWrapper and the applet loaded. + */ + public String[][] getParameterInfo() + { + String info[][]; + String wrapper[][] = { + {"applet", "String", "appWrapper: Applet to load"}, + }; + if(applet != null) { + String tmp[][] = applet.getParameterInfo(); + info = new String[tmp.length + 1][3]; + System.arraycopy(tmp, 0, info, 1, tmp.length); + } + else info = new String[1][3]; + System.arraycopy(wrapper, 0, info, 0, 1); + + return info; + } + + /** + * Write a message to the applet area. + */ + public void paint(Graphics g) + { + String message; + if(applet != null) + message = "Click to reattach the Applet!"; + else message = "The was no applet load (maybe an error)!"; + + + int width = size().width / 2 - + (getFontMetrics(getFont())).stringWidth(message) / 2; + int height = size().height / 2; + + g.setColor(Color.red); + g.drawString(message, width, height); + } + + /** + * reshape the applet and ourself + */ + public void reshape(int x, int y, int w, int h) + { + if(applet != null) applet.reshape(x, y, w, h); + super.reshape(x, y, w, h); + } + + /** + * Handle button events. When pressed it either creates the new applet + * window or destoys it. + */ + public boolean handleEvent(Event evt) + { + if(evt.target == startButton && evt.id == Event.ACTION_EVENT) { + if(applet == null) { + startButton.setLabel("Loading ..."); + (loader = new Thread(this)).start(); + } else { + if(applet.getParent() instanceof Frame) { + Frame frame = (Frame)applet.getParent(); + frame.hide(); + frame.dispose(); + } + applet.stop(); + applet.destroy(); + applet = null; + startButton.setLabel(startLabel); + } + return true; + } + if(evt.id == Event.MOUSE_UP && applet.getParent() instanceof Frame) { + Frame frame = (Frame)applet.getParent(); + frame.hide(); + frame.dispose(); + add("Center", applet); + validate(); + layout(); + return true; + } + return false; + } +} diff --git a/src/de/mud/telnet/display/CharDisplay.java b/src/de/mud/telnet/display/CharDisplay.java new file mode 100644 index 0000000..89795e1 --- /dev/null +++ b/src/de/mud/telnet/display/CharDisplay.java @@ -0,0 +1,1275 @@ +package de.mud.telnet.display; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/** + * CharDisplay -- a simple character display + * -- + * $Id: CharDisplay.java,v 1.27 1998/03/18 12:43:33 leo Exp $ + * $timestamp: Thu Jul 24 15:19:18 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; +import java.awt.Insets; +import java.awt.Event; +import java.awt.TextArea; +import java.awt.Label; +import java.awt.Frame; +import java.awt.Scrollbar; +import java.awt.Rectangle; + +/** + * A simple character display. + * @version $Id: CharDisplay.java,v 1.27 1998/03/18 12:43:33 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class CharDisplay extends Panel +{ + /** + * If you need the runtime version, just ask this variable. + */ + public String version = "$Revision: 1.27 $ $Date: 1998/03/18 12:43:33 $"; + /** + * Enable debug messages. This is final static to prevent unused + * code to be compiled. + */ + public final static int debug = 0; + + private Dimension size; /* rows and columns */ + private Insets insets; /* size of the border */ + private boolean raised; /* indicator if the border is raised */ + + private char charArray[][]; /* contains the characters */ + private int charAttributes[][]; /* contains character attrs */ + private int bufSize, maxBufSize; /* buffer sizes */ + + private int windowBase; /* where the start displaying */ + private int screenBase; /* the actual screen start */ + private int topMargin; /* top scroll margon */ + private int bottomMargin; /* bottom scroll margon */ + private Scrollbar scrollBar; /* the scroll bar */ + private String scrBarPos; /* the scroll bar position */ + + private Font normalFont; /* normal font */ + private FontMetrics fm; /* current font metrics */ + private int charWidth; /* current width of a char */ + private int charHeight; /* current height of a char */ + private int charDescent; /* base line descent */ + private int resizeStrategy; /* current resizing strategy */ + + private int cursorX, cursorY; /* current cursor position */ + private Point selectBegin, selectEnd; /* selection coordinates */ + private TextArea selection; + private Frame selectFrame; + + private de.mud.telnet.display.SoftFont sf = new de.mud.telnet.display.SoftFont(); + + private boolean screenLocked = false; /* screen needs to be locked */ + /* because of paint requests */ + /* during other operations */ + private boolean update[]; + + private Color color[] = { Color.black.brighter(), + Color.red.brighter(), + Color.green.brighter(), + Color.yellow.brighter(), + Color.blue.brighter(), + Color.magenta.brighter(), + Color.cyan.brighter(), + Color.white.brighter(), + }; + private final static int COLOR_FG_STD = 7; + private final static int COLOR_BG_STD = 0; + private final static int COLOR = 0x7f8; + private final static int COLOR_FG = 0x78; + private final static int COLOR_BG = 0x780; + + /** + * Scroll up when inserting a line. + */ + public final static boolean SCROLL_UP = false; + /** + * Scroll down when inserting a line. + */ + public final static boolean SCROLL_DOWN = true; + + /** + * Do nothing when the container is resized. + */ + public final static int RESIZE_NONE = 0; + /** + * Resize the width and height of the characterscreen. + */ + public final static int RESIZE_SCREEN = 1; + /** + * Resize the font to the new screensize. + */ + public final static int RESIZE_FONT = 2; + + /** + * Make character normal. + */ + public final static int NORMAL = 0x00; + /** + * Make character bold. + */ + public final static int BOLD = 0x01; + /** + * Underline character. + */ + public final static int UNDERLINE = 0x02; + /** + * Invert character. + */ + public final static int INVERT = 0x04; + + private void InitializeCharDisplay(int width, int height, + String fontname, int fsize) + { + System.err.println("CharDisplay: screen size: ["+width+","+height+"]"); + normalFont = new Font(fontname, Font.BOLD, fsize); + setFont(normalFont); + fm = getFontMetrics(normalFont); + if(fm != null) + { + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + charDescent = fm.getDescent(); + } + + resizeStrategy = RESIZE_FONT; + size = new Dimension(width, height); + charArray = new char[size.height][size.width]; + charAttributes = new int[size.height][size.width]; + bufSize = size.height; + maxBufSize = 2 * size.height; + + windowBase = 0; + screenBase = 0; + topMargin = 0; + bottomMargin = size.height - 1; + + update = new boolean[size.height + 1]; + for(int i = 1; i <= size.height; i++) update[i] = true; + + selectBegin = new Point(0,0); + selectEnd = new Point(0,0); + + setLayout(null); + } + + /** + * Create a character display with size 80x24 and Font "Courier", size 12. + */ + public CharDisplay() + { + InitializeCharDisplay(80, 24, "Courier", 12); + } + + /** + * Create a character display with specific size, Font is "Courier", size 12. + */ + public CharDisplay(int width, int height) + { + InitializeCharDisplay(width, height, "Courier", 12); + } + + /** + * Create a character display with 80x24 and specific font and font size. + */ + public CharDisplay(String fname, int fsize) + { + InitializeCharDisplay(80, 24, fname, fsize); + } + + /** + * Create a character display with specific size, font and font size. + */ + public CharDisplay(int width, int height, String fname, int fsize) + { + InitializeCharDisplay(width, height, fname, fsize); + } + + /** + * Put a character on the screen with normal font and outline. + * The character previously on that position will be overwritten. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to show on the screen + * @see #insertChar + * @see #deleteChar + * @see #redraw + */ + public void putChar(int c, int l, char ch) + { + putChar(c, l, ch, NORMAL); + } + + /** + * Put a character on the screen with specific font and outline. + * The character previously on that position will be overwritten. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to show on the screen + * @param attributes the character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #insertChar + * @see #deleteChar + * @see #redraw + */ + + public void putChar(int c, int l, char ch, int attributes) + { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + charArray[screenBase + l][c] = ch; + charAttributes[screenBase + l][c] = attributes; + markLine(l, 1); + } + + /** + * Get the character at the specified position. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + */ + public char getChar(int c, int l) + { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + return charArray[l][c]; + } + + /** + * Get the attributes for the specified position. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + */ + public int getAttributes(int c, int l) + { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + return charAttributes[l][c]; + } + + /** + * Insert a character at a specific position on the screen. + * All character right to from this position will be moved one to the right. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to insert + * @param attributes the character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #deleteChar + * @see #redraw + */ + public void insertChar(int c, int l, char ch, int attributes) + { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + System.arraycopy(charArray[screenBase + l], c, + charArray[screenBase + l], c + 1, size.width - c - 1); + System.arraycopy(charAttributes[screenBase + l], c, + charAttributes[screenBase + l], c + 1, size.width - c - 1); + putChar(c, l, ch, attributes); + } + + /** + * Delete a character at a given position on the screen. + * All characters right to the position will be moved one to the left. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + * @see #insertChar + * @see #redraw + */ + public void deleteChar(int c, int l) + { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + if(c < size.width - 1) + { + System.arraycopy(charArray[screenBase + l], c + 1, + charArray[screenBase + l], c, size.width - c - 1); + System.arraycopy(charAttributes[screenBase + l], c + 1, + charAttributes[screenBase + l], c, size.width - c - 1); + } + putChar(size.width - 1, l, (char)0); + } + + /** + * Put a String at a specific position. Any characters previously on that + * position will be overwritten. You need to call redraw() for screen update. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param s the string to be shown on the screen + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #insertLine + * @see #deleteLine + * @see #redraw + */ + public void putString(int c, int l, String s) + { + putString(c, l, s, NORMAL); + } + + /** + * Put a String at a specific position giving all characters the same + * attributes. Any characters previously on that position will be + * overwritten. You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param s the string to be shown on the screen + * @param attributes character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #insertLine + * @see #deleteLine + * @see #redraw + */ + public void putString(int c, int l, String s, int attributes) + { + for(int i = 0; i < s.length() && c + i < size.width; i++) + putChar(c + i, l, s.charAt(i), attributes); + } + + /** + * Insert a blank line at a specific position. + * The current line and all previous lines are scrolled one line up. The + * top line is lost. You need to call redraw() to update the screen. + * @param l the y-coordinate to insert the line + * @see #deleteLine + * @see #redraw + */ + public void insertLine(int l) + { + insertLine(l, 1, SCROLL_UP); + } + + /** + * Insert blank lines at a specific position. + * You need to call redraw() to update the screen + * @param l the y-coordinate to insert the line + * @param n amount of lines to be inserted + * @see #deleteLine + * @see #redraw + */ + public void insertLine(int l, int n) + { + insertLine(l, n, SCROLL_UP); + } + + /** + * Insert a blank line at a specific position. Scroll text according to + * the argument. + * You need to call redraw() to update the screen + * @param l the y-coordinate to insert the line + * @param scrollDown scroll down + * @see #deleteLine + * @see #SCROLL_UP + * @see #SCROLL_DOWN + * @see #redraw + */ + public void insertLine(int l, boolean scrollDown) + { + insertLine(l, 1, scrollDown); + } + + /** + * Insert blank lines at a specific position. + * The current line and all previous lines are scrolled one line up. The + * top line is lost. You need to call redraw() to update the screen. + * @param l the y-coordinate to insert the line + * @param n number of lines to be inserted + * @param scrollDown scroll down + * @see #deleteLine + * @see #SCROLL_UP + * @see #SCROLL_DOWN + * @see #redraw + */ + public synchronized void insertLine(int l, int n, boolean scrollDown) + { + screenLocked = true; + + l = checkBounds(l, 0, size.height - 1); + + char cbuf[][] = null; + int abuf[][] = null; + int offset = 0; + int oldBase = screenBase; + int top = (l < topMargin ? + 0 : (l > bottomMargin ? + (bottomMargin + 1 < size.height ? + bottomMargin + 1 : size.height - 1) : topMargin)); + int bottom = (l > bottomMargin ? + size.height - 1 : (l < topMargin ? + (topMargin > 0 ? + topMargin - 1 : 0) : bottomMargin)); + + + if(scrollDown) { + if(n > (bottom - top)) n = (bottom - top); + cbuf = new char[bottom - l - (n - 1)][size.width]; + abuf = new int[bottom - l - (n - 1)][size.width]; + + System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1)); + System.arraycopy(charAttributes, oldBase + l, + abuf, 0, bottom - l - (n - 1)); + System.arraycopy(cbuf, 0, charArray, oldBase + l + n, + bottom - l - (n - 1)); + System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, + bottom - l - (n - 1)); + cbuf = charArray; + abuf = charAttributes; + } else try { + if(n > (bottom - top) + 1) n = (bottom - top) + 1; + if(bufSize < maxBufSize) { + if(bufSize + n > maxBufSize) { + offset = n - (maxBufSize - bufSize); + bufSize = maxBufSize; + screenBase = maxBufSize - size.height - 1; + windowBase = screenBase; + } else { + screenBase += n; + windowBase += n; + bufSize += n; + } + cbuf = new char[bufSize][size.width]; + abuf = new int[bufSize][size.width]; + } else { + offset = n; + cbuf = charArray; + abuf = charAttributes; + } + /* + * copy anything from the top of the buffer (+offset) to the new top + * up to the screenBase. + */ + if(oldBase > 0) + { + System.arraycopy(charArray, offset, + cbuf, 0, + oldBase - offset); + System.arraycopy(charAttributes, offset, + abuf, 0, + oldBase - offset); + } + /* + * copy anything from the top of the screen (screenBase) up to the + * topMargin to the new screen + */ + if(top > 0) + { + System.arraycopy(charArray, oldBase, + cbuf, screenBase, + top); + System.arraycopy(charAttributes, oldBase, + abuf, screenBase, + top); + } + /* + * copy anything from the topMargin up to the amount of lines inserted + * to the gap left over between scrollback buffer and screenBase + */ + if(oldBase > 0) { + System.arraycopy(charArray, oldBase + top, + cbuf, oldBase - offset, + n); + System.arraycopy(charAttributes, oldBase + top, + abuf, oldBase - offset, + n); + } + /* + * copy anything from topMargin + n up to the line linserted to the + * topMargin + */ + System.arraycopy(charArray, oldBase + top + n, + cbuf, screenBase + top, + l - top - (n - 1)); + System.arraycopy(charAttributes, oldBase + top + n, + abuf, screenBase + top, + l - top - (n - 1)); + /* + * copy the all lines next to the inserted to the new buffer + */ + if(l < size.height - 1) + { + System.arraycopy(charArray, oldBase + l + 1, + cbuf, screenBase + l + 1, + (size.height - 1) - l); + System.arraycopy(charAttributes, oldBase + l + 1, + abuf, screenBase + l + 1, + (size.height - 1) - l); + } + } catch(ArrayIndexOutOfBoundsException e) { + System.err.println("*** Error while scrolling up:"); + System.err.println("--- BEGIN STACKTRACE ---"); + e.printStackTrace(); + System.err.println("--- END STACKTRACE ---"); + System.err.println("bufSize="+bufSize+", maxBufSize="+maxBufSize); + System.err.println("top="+top+", bottom="+bottom); + System.err.println("n="+n+", l="+l); + System.err.println("screenBase="+screenBase+", windowBase="+windowBase); + System.err.println("oldBase="+oldBase); + System.err.println("size.width="+size.width+", size.height="+size.height); + System.err.println("abuf.length="+abuf.length+", cbuf.length="+cbuf.length); + System.err.println("*** done dumping debug information"); + } + + for(int i = 0; i < n; i++) + { + cbuf[(screenBase + l) + (scrollDown ? i : -i) ] = new char[size.width]; + abuf[(screenBase + l) + (scrollDown ? i : -i) ] = new int[size.width]; + } + + charArray = cbuf; + charAttributes = abuf; + + if(scrollDown) + markLine(l, bottom - l + 1); + else + markLine(top, l - top + 1); + + if(scrollBar != null) + scrollBar.setValues(windowBase, size.height, 0, bufSize); + + screenLocked = false; + } + + /** + * Delete a line at a specific position. Subsequent lines will be scrolled + * up to fill the space and a blank line is inserted at the end of the + * screen. + * @param l the y-coordinate to insert the line + * @see #deleteLine + */ + public void deleteLine(int l) + { + l = checkBounds(l, 0, size.height - 1); + + int bottom = (l>bottomMargin?size.height-1: + (l bottomMargin) + { + topMargin = bottomMargin; + bottomMargin = l; + } + else + topMargin = l; + if(topMargin < 0) topMargin = 0; + if(bottomMargin > size.height - 1) bottomMargin = size.height - 1; + } + + /** + * Get the top scroll margin. + */ + public int getTopMargin() + { + return topMargin; + } + + /** + * Set the bottom scroll margin for the screen. If the current top margin + * is bigger it will become the bottom margin and the line will become the + * top margin. + * @param l line that is the margin + */ + public void setBottomMargin(int l) + { + if(l < topMargin) + { + bottomMargin = topMargin; + topMargin = l; + } + else + bottomMargin = l; + if(topMargin < 0) topMargin = 0; + if(bottomMargin > size.height - 1) bottomMargin = size.height - 1; + } + + /** + * Get the bottom scroll margin. + */ + public int getBottomMargin() + { + return bottomMargin; + } + + /** + * Set scrollback buffer size. + * @param amount new size of the buffer + */ + public void setBufferSize(int amount) + { + screenLocked = true; + + if(amount < size.height) amount = size.height; + if(amount < maxBufSize) + { + char cbuf[][] = new char[amount][size.width]; + int abuf[][] = new int[amount][size.width]; + System.arraycopy(charArray, bufSize - amount, cbuf, 0, amount); + System.arraycopy(charAttributes, bufSize - amount, abuf, 0, amount); + charArray = cbuf; + charAttributes = abuf; + } + maxBufSize = amount; + + screenLocked = false; + + repaint(); + } + + /** + * Retrieve current scrollback buffer size. + * @see #setBufferSize + */ + public int getBufferSize() + { + return bufSize; + } + + /** + * Retrieve maximum buffer Size. + * @see #getBufferSize + */ + public int getMaxBufferSize() + { + return maxBufSize; + } + + /** + * Set the current window base. This allows to view the scrollback buffer. + * @param line the line where the screen window starts + * @see setBufferSize + * @see getBufferSize + */ + public void setWindowBase(int line) + { + if(line > screenBase) line = screenBase; + else if(line < 0) line = 0; + windowBase = line; + repaint(); + } + + /** + * Get the current window base. + * @see setWindowBase + */ + public int getWindowBase() + { + return windowBase; + } + + /** + * Change the size of the screen. This will include adjustment of the + * scrollback buffer. + * @param columns width of the screen + * @param columns height of the screen + */ + public void setWindowSize(int width, int height) + { + char cbuf[][]; + int abuf[][]; + int bsize = bufSize; + + if(width < 1 || height < 1) return; + + screenLocked = true; + + super.update(getGraphics()); + + if(height > maxBufSize) + maxBufSize = height; + if(height > bufSize) + { + bufSize = height; + screenBase = 0; + windowBase = 0; + } + + cbuf = new char[bufSize][width]; + abuf = new int[bufSize][width]; + + for(int i = 0; i < bsize && i < bufSize; i++) + { + System.arraycopy(charArray[i], 0, cbuf[i], 0, + width < size.width ? width : size.width); + System.arraycopy(charAttributes[i], 0, abuf[i], 0, + width < size.width ? width : size.width); + } + charArray = cbuf; + charAttributes = abuf; + size = new Dimension(width, height); + topMargin = 0; + bottomMargin = height - 1; + update = new boolean[height + 1]; + for(int i = 0; i <= height; i++) update[i] = true; + screenLocked = false; + } + + /** + * Set the strategy when window is resized. + * RESIZE_FONT is default. + * @param strategy the strategy + * @see #RESIZE_NONE + * @see #RESIZE_FONT + * @see #RESIZE_SCREEN + */ + public void setResizeStrategy(int strategy) + { + resizeStrategy = strategy; + } + + /** + * Get amount of rows on the screen. + */ + public int getRows() { return size.height; } + + /** + * Get amount of columns on the screen. + */ + public int getColumns() { return size.width; } + + /** + * Set the border thickness and the border type. + * @param thickness border thickness in pixels, zero means no border + * @param raised a boolean indicating a raised or embossed border + */ + public void setBorder(int thickness, boolean raised) + { + if(thickness == 0) insets = null; + else insets = new Insets(thickness+1, thickness+1, + thickness+1, thickness+1); + this.raised = raised; + } + + /** + * Set the scrollbar position. valid values are "East" or "West". + * @param position the position of the scrollbar + */ + public void setScrollbar(String position) + { + add(scrollBar = new Scrollbar()); + scrollBar.setValues(windowBase, size.height, 0, bufSize - size.height); + scrBarPos = position; + } + + /** + * Mark lines to be updated with redraw(). + * @param l starting line + * @param n amount of lines to be updated + * @see #redraw + */ + public void markLine(int l, int n) + { + l = checkBounds(l, 0, size.height - 1); + for(int i = 0; i < n && l + i < size.height; i++) + update[l + i + 1] = true; + } + + /** + * Redraw marked lines. + * @see #markLine + */ + public void redraw() + { + update[0] = true; + repaint(); + } + + /** + * Update the display. to reduce flashing we have overridden this method. + */ + public void update(Graphics g) + { + paint(g); + } + + /** + * Paint the current screen. All painting is done here. Only lines that have + * changed will be redrawn! + */ + public synchronized void paint(Graphics g) + { + if(screenLocked) return; + int xoffset = (super.size().width - size.width * charWidth - + (scrollBar != null ? 15 : 0)) / 2; + int yoffset = (super.size().height - size.height * charHeight) / 2; + + Color fg = color[COLOR_FG_STD]; + Color bg = color[COLOR_BG_STD]; + + if(scrollBar != null && scrBarPos.equals("West")) xoffset += 15; + + g.setFont(normalFont); + + for(int l = 0; l < size.height; l++) + { + if(update[0] && !update[l + 1]) continue; + update[l + 1] = false; + for(int c = 0; c < size.width; c++) + { + int addr = 0; + int currAttr = charAttributes[windowBase + l][c]; + + fg = color[COLOR_FG_STD]; + bg = color[COLOR_BG_STD]; + if ((currAttr & COLOR_FG) != 0) { + fg = color[((currAttr & COLOR_FG) >> 3)-1]; + } + if ((currAttr & COLOR_BG) != 0) { + bg = color[((currAttr & COLOR_BG) >> 7)-1]; + } + + if((currAttr & BOLD) != 0) { + if(fg.equals(Color.black)) + fg = Color.gray; + else fg = fg.darker(); + } + if((currAttr & INVERT) != 0) { Color swapc = bg; bg=fg;fg=swapc; } + + if (sf.inSoftFont(charArray[windowBase + l][c])) { + g.setColor(bg); + g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset, + charWidth, charHeight); + g.setColor(fg); + sf.drawChar(g,charArray[windowBase + l][c],xoffset+c*charWidth, + l*charHeight+yoffset, charWidth, charHeight); + continue; + } + + // determine the maximum of characters we can print in one go + while(c + addr < size.width && + charAttributes[windowBase + l][c + addr] == currAttr && + !sf.inSoftFont(charArray[windowBase + l ][c+addr]) + ) { + if(charArray[windowBase + l][c + addr] < ' ') + charArray[windowBase + l][c + addr] = ' '; + addr++; + } + + // clear the part of the screen we want to change (fill rectangle) + g.setColor(bg); + g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset, + addr * charWidth, charHeight); + + g.setColor(fg); + + // draw the characters + g.drawChars(charArray[windowBase + l], c, addr, + c * charWidth + xoffset, + (l+1) * charHeight - charDescent + yoffset); + + if((currAttr & UNDERLINE) != 0) + g.drawLine(c * charWidth + 1 + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset, + c * charWidth + addr * charWidth + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset); + + c += addr - 1; + } + } + + // draw cursor + if(screenBase + cursorY >= windowBase && + screenBase + cursorY < windowBase + size.height) + { + g.setColor(color[COLOR_FG_STD]); + g.setXORMode(color[COLOR_BG_STD]); + g.fillRect( cursorX * charWidth + xoffset, + (cursorY + screenBase - windowBase) * charHeight + yoffset, + charWidth, charHeight); + g.setPaintMode(); + } + + if(windowBase <= selectBegin.y || windowBase <= selectEnd.y) { + int beginLine = selectBegin.y - windowBase; + int endLine = selectEnd.y - selectBegin.y; + if(beginLine < 0) { + endLine += beginLine; + beginLine = 0; + } + if(endLine > size.height) endLine = size.height - beginLine; + + g.setXORMode(color[COLOR_BG_STD]); + g.fillRect(selectBegin.x * charWidth + xoffset, + beginLine * charHeight + yoffset, + (endLine == 0 ? (selectEnd.x - selectBegin.x) : + (size.width - selectBegin.x)) + * charWidth, + charHeight); + if(endLine > 1) + g.fillRect(0 + xoffset, + (beginLine + 1) * charHeight + yoffset, + size.width * charWidth, + (endLine - 1) * charHeight); + if(endLine > 0) + g.fillRect(0 + xoffset, + (beginLine + endLine) * charHeight + yoffset, + selectEnd.x * charWidth, + charHeight); + g.setPaintMode(); + } + + if(insets != null) { + g.setColor(getBackground()); + xoffset--; yoffset--; + for(int i = insets.top - 1; i >= 0; i--) + g.draw3DRect(xoffset - i, yoffset - i, + charWidth * size.width + 1 + i * 2, + charHeight * size.height + 1 + i * 2, + raised); + } + + update[0] = false; + } + + private int checkBounds(int value, int lower, int upper) + { + if(value < lower) return lower; + if(value > upper) return upper; + return value; + } + + /** + * Reshape character display according to resize strategy. + * @see #setResizeStrategy + */ + public void reshape(int x, int y, int w, int h) + { + if(debug > 0) + System.err.println("CharDisplay: reshape("+x+","+y+","+w+","+h+")"); + + int xborder = 0, yborder = 0; + + if(insets != null) { + w -= (xborder = insets.left + insets.right); + h -= (yborder = insets.top + insets.bottom); + } + if(scrollBar != null) { w -= 15;} + + Font tmpFont = normalFont; + String fontName = normalFont.getName(); + fm = getFontMetrics(normalFont); + if(fm != null) + { + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + } + + switch(resizeStrategy) + { + case RESIZE_SCREEN: + setWindowSize(w / charWidth, size.height = h / charHeight); + break; + case RESIZE_FONT: + int height = h / size.height; + int width = w / size.width; + + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + charHeight)); + + // adapt current font size (from small up to best fit) + if(fm.getHeight() < height || fm.charWidth('@') < width) + do { + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + ++charHeight)); + } while(fm.getHeight() < height || + fm.charWidth('@') < width); + + // now check if we got a font that is too large + if(fm.getHeight() > height || fm.charWidth('@') > width) + do { + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + --charHeight)); + } while(charHeight > 1 && + (fm.getHeight() > height || + fm.charWidth('@') > width)); + + if(charHeight <= 1) + { + System.err.println("CharDisplay: error during resize, resetting"); + normalFont = tmpFont; + System.err.println("CharDisplay: disabling font/screen resize"); + resizeStrategy = RESIZE_NONE; + } + + setFont(normalFont); + fm = getFontMetrics(normalFont); + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + charDescent = fm.getDescent(); + break; + case RESIZE_NONE: + default: + break; + } + if(debug > 0) + { + System.err.println("CharDisplay: charWidth="+charWidth+", "+ + "charHeight="+charHeight+", "+ + "charDescent="+charDescent); + System.err.println("CharDisplay: "+normalFont+", "+fm); + } + super.reshape(x, y, + w + xborder + (scrollBar != null ? 15 : 0), + h + yborder); + + if(scrollBar != null) { + int xoffset = (super.size().width - size.width * charWidth - 15) / 2; + int yoffset = (super.size().height - size.height * charHeight) / 2; + if(scrBarPos.equals("West")) + scrollBar.reshape(xoffset - (xborder / 2), yoffset - yborder / 2, + 15, size.height * charHeight + yborder); + else + scrollBar.reshape(xoffset + (xborder / 2) + size.width * charWidth, + yoffset - yborder / 2, 15, + size.height * charHeight + yborder); + } + } + + /** + * Return the real size in points of the character display. + * @return Dimension the dimension of the display + * @see java.awt.Dimension + */ + public Dimension size() + { + int xborder = 0, yborder = 0; + if(insets != null) { + xborder = insets.left + insets.right; + yborder = insets.top + insets.bottom; + } + if(scrollBar != null) xborder += 15; + + return new Dimension(size.width * charWidth + xborder, + size.height * charHeight + yborder); + } + + /** + * Return the preferred Size of the character display. + * This turns out to be the actual size. + * @return Dimension dimension of the display + * @see size + */ + public Dimension preferredSize() + { + return size(); + } + + /** + * The insets of the character display define the border. + * @return Insets border thickness in pixels + */ + public Insets insets() + { + return insets == null ? super.insets() : insets; + } + + /** + * Handle mouse events for copy & paste + * @param evt the event that occured + * @return boolean true if action was taken + * @see java.awt.Event + */ + public boolean handleEvent(Event evt) + { + // handle scrollbar events + if(evt != null && evt.target == scrollBar && evt.arg != null) { + int val = ((Integer)evt.arg).intValue(); + setWindowBase(val); + return true; + } + + if(evt.id == Event.MOUSE_DOWN || evt.id == Event.MOUSE_UP || + evt.id == Event.MOUSE_DRAG) { + int xoffset = (super.size().width - size.width * charWidth) / 2; + int yoffset = (super.size().height - size.height * charHeight) / 2; + switch(evt.id) { + case Event.MOUSE_DOWN: + selectBegin.x = (evt.x - xoffset) / charWidth; + selectBegin.y = (evt.y - yoffset) / charHeight + windowBase; + selectEnd.x = selectBegin.x; + selectEnd.y = selectBegin.y; + if(selectFrame != null) selectFrame.hide(); + break; + case Event.MOUSE_UP: + case Event.MOUSE_DRAG: + int x = (evt.x - xoffset) / charWidth; + int y = (evt.y - yoffset) / charHeight + windowBase; + int oldx = selectEnd.x, oldy = selectEnd.y; + + if((x < selectBegin.x && y < selectBegin.y) && + (x < selectEnd.x && y < selectEnd.y)) { + selectBegin.x = x; + selectBegin.y = y; + } else { + selectEnd.x = x; + selectEnd.y = y; + } + + if(evt.id == Event.MOUSE_UP) { + if(selectBegin.x == selectEnd.x && + selectBegin.y == selectEnd.y) { + repaint(); + return true; + } + String tmp = ""; + // fix end.x and end.y, they can get over the border + if (selectEnd.x < 0) selectEnd.x = 0; + if (selectEnd.y < 0) selectEnd.y = 0; + if (selectEnd.y >= charArray.length) { + selectEnd.y = charArray.length-1; + } + if (selectEnd.x >= charArray[0].length) { + selectEnd.x = charArray[0].length-1; + } + for(int l = selectBegin.y; l <= selectEnd.y; l++) + if(l == selectBegin.y) + tmp = (new String(charArray[l])).substring(selectBegin.x) + "\n"; + else if(l == selectEnd.y) + tmp += (new String(charArray[l])).substring(0, selectEnd.x); + else tmp += new String(charArray[l]) + "\n"; + if(selectFrame == null) { + /* for jdk-1.1 + String s=(String) ((StringSelection)this.getToolkit(). + getSystemClipboard(). + getContents(this)). + getTransferData(DataFlavor.stringFlavor); + System.out.println(s); + */ + + selectFrame = new Frame("Pasteboard"); + selection = new TextArea(); + selection.setFont(normalFont); + selectFrame.add("Center", selection); + selectFrame.add("South", new Label("Click on the terminal window"+ + " to hide!")); + selectFrame.pack(); + } + selection.setText(tmp); + //selectFrame.show(); + selection.selectAll(); + repaint(); + } else + if(oldx != x || oldy != y) repaint(); + break; + } + return true; + } + return false; + } +} diff --git a/src/de/mud/telnet/display/SoftFont.java b/src/de/mud/telnet/display/SoftFont.java new file mode 100644 index 0000000..73dddb5 --- /dev/null +++ b/src/de/mud/telnet/display/SoftFont.java @@ -0,0 +1,1009 @@ +package de.mud.telnet.display; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/* + * SoftFont -- a unicode softfont displayer + * -- + * $Id: SoftFont.java,v 1.8 1997/11/03 17:10:26 marcus Exp $ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.awt.*; +import java.util.*; +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +public class SoftFont { + final static private char SF_BITMAP = 0; + final static private char SF_FILLRECT = 1; + + + final static private char SF_CHAR = 0; + final static private char SF_WIDTH= 1; + final static private char SF_HEIGHT= 2; + final static private char SF_TYPE = 3; + final static private char SF_DATA = 4; + java.util.Hashtable font; + /** + * softfont characterdata + */ + private static char[][] fontdata = { + + {0x01,8,8,SF_BITMAP, /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + },{ 0x02,8,8,SF_BITMAP,/* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + },{ 0x03,8,8,SF_BITMAP,/* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + },{ 0x04,8,8,SF_BITMAP,/* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + },{ 0x05,8,8,SF_BITMAP,/* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + },{ 0x06,8,8,SF_BITMAP,/* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + },{ 0x2666,8,8,SF_BITMAP,/* 9830 0x2666 BLACK DIAMOND */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x07,8,8,SF_BITMAP,/* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x08,8,8,SF_BITMAP,/* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + },{ 0x09,8,8,SF_BITMAP,/* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + },{ 0x0a,8,8,SF_BITMAP,/* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + },{ 0x0b,8,8,SF_BITMAP,/* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + },{ 0x0c,8,8,SF_BITMAP,/* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + },{ 0x0d,8,8,SF_BITMAP,/* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + },{ 0x0e,8,8,SF_BITMAP,/* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + },{ 0x0f,8,8,SF_BITMAP,/* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + },{ 0x10,8,8,SF_BITMAP,/* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + },{ 0x11,8,8,SF_BITMAP,/* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + },{ 0x12,8,8,SF_BITMAP,/* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + },{ 0x13,8,8,SF_BITMAP,/* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + },{ 0x14,8,8,SF_BITMAP,/* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + },{ 0x15,8,8,SF_BITMAP,/* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + },{ 0x16,8,8,SF_BITMAP,/* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + },{ 0x17,8,8,SF_BITMAP,/* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + },{ 0x18,8,8,SF_BITMAP,/* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + },{ 0x19,8,8,SF_BITMAP,/* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + },{ 0x1a,8,8,SF_BITMAP,/* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1b,8,8,SF_BITMAP,/* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1c,8,8,SF_BITMAP,/* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1d,8,8,SF_BITMAP,/* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1e,8,8,SF_BITMAP,/* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1f,8,8,SF_BITMAP,/* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x7f,8,8,SF_BITMAP,/* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + },{ 0x2591,8,8,SF_BITMAP,/* LIGHT SHADE */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + },{ 0x2592,8,8,SF_BITMAP,/* MEDIUM SHADE */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + },{ 0x2593,8,8,SF_BITMAP,/* DARK SHADE */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + },{ 0x221a,8,8,SF_BITMAP,/* SQUARE ROOT */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x2320,8,8,SF_BITMAP,/* UPPER INTERVAL*/ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + },{ 0x25a0,8,8,SF_FILLRECT,/* BLACK SQUARE */ + 0x2244, + /* 00000000 */ + /* 00000000 */ + /* 00111100 */ + /* 00111100 */ + /* 00111100 */ + /* 00111100 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2502,8,8,SF_FILLRECT,/*BOX DRAWINGS LIGHT VERTICAL*/ + 0x3028, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2524,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + 0x3028, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2561,8,8,SF_FILLRECT,/*BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE*/ + 0x3028, + 0x0231, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2562,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */ + 0x2028, + 0x5028, + 0x0421, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2556,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */ + 0x0471, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2555,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */ + 0x3226, + 0x0231, + 0x0431, + /* 00000000 */ + /* 00000000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2563,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND LEFT*/ + 0x2022, + 0x0221, + 0x0421, + 0x2424, + 0x5028, + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00000110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2551,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL */ + 0x2028, + 0x5028, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2557,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND LEFT */ + 0x0271, + 0x5325, + 0x0441, + 0x2523, + /* 00000000 */ + /* 00000000 */ + /* 11111110 */ + /* 00000110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x255d,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND LEFT */ + 0x2022, + 0x0241, + 0x5025, + 0x0451, + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00000110 */ + /* 11111110 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x255c,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */ + 0x2024, + 0x5024, + 0x0471, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111110 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x255b,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */ + 0x3025, + 0x0231, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2510,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND LEFT */ + 0x0451, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2514,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND RIGHT */ + 0x3025, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2534,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + 0x3024, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x252c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + 0x0481, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x251c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + 0x3028, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2500,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT HORIZONTAL */ + 0x0481, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x253c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + 0x3028, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x255e,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */ + 0x3028, + 0x5231, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x255f,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */ + 0x2028, + 0x5028, + 0x7411, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x255a,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND RIGHT */ + 0x2025, + 0x5023, + 0x7211, + 0x4441, + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110000 */ + /* 00111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2554,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND RIGHT */ + 0x2261, + 0x2325, + 0x5424, + 0x7411, + /* 00000000 */ + /* 00000000 */ + /* 00111111 */ + /* 00110000 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2569,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */ + 0x2022, + 0x0241, + 0x5022, + 0x5231, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 11110111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2566,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */ + 0x0281, + 0x0441, + 0x2523, + 0x5431, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2560,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */ + 0x2028, + 0x5022, + 0x5231, + 0x5431, + 0x5623, + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110000 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2550,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE HORIZONTAL */ + 0x0281, + 0x0481, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x256c,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */ + 0x2022, + 0x0241, + 0x5022, + 0x5231, + 0x0441, + 0x2523, + 0x5431, + 0x5523, + /* 00110110 */ + /* 00110110 */ + /* 11110111 */ + /* 00000000 */ + /* 11110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2567,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */ + 0x3022, + 0x0281, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2568,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */ + 0x2024, + 0x5024, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2564,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */ + 0x0281, + 0x0481, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2565,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */ + 0x0481, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2559,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */ + 0x2024, + 0x5024, + 0x2461, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2558,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */ + 0x3025, + 0x5231, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2552,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */ + 0x3226, + 0x5231, + 0x5431, + /* 00000000 */ + /* 00000000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2553,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */ + 0x2461, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x256b,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */ + 0x2028, + 0x5028, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x256a,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */ + 0x3028, + 0x0281, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2518,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND LEFT */ + 0x3025, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x250c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + 0x3451, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2588,8,8,SF_FILLRECT,/* FULL BLOCK */ + 0x0088, + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + },{ 0x2584,8,8,SF_FILLRECT,/* LOWER HALF BLOCK */ + 0x0484, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + },{ 0x258c,8,8,SF_FILLRECT,/* LEFT HALF BLOCK */ + 0x0048, + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + },{ 0x2590,8,8,SF_FILLRECT,/* RIGHT HALF BLOCK */ + 0x4048, + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + },{ 0x2580,8,8,SF_FILLRECT,/* UPPER HALF BLOCK */ + 0x0084, + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + }}; + + public SoftFont() { + font = new java.util.Hashtable(); + for (int i=0;i=0x100) { + System.out.println("Character "+((int)c)+" not in softfont"); + } + return insoftfont; + } + + public void drawChar(Graphics g,char c,int x,int y,int cw,int ch) { + double dw,dh; + Object Ientry; + int w,h,entry,i,fontwidth,fontheight; + + Ientry = font.get(new Integer(c)); + if (Ientry == null) + return; + entry = ((Integer)Ientry).intValue(); + fontwidth = fontdata[entry][SF_WIDTH]; + fontheight = fontdata[entry][SF_HEIGHT]; + + dw = cw*1.0/fontwidth; + dh = ch*1.0/fontheight; + + switch (fontdata[entry][SF_TYPE]) { + case SF_BITMAP: + for (h=0;h>12; + h=(fontdata[entry][i]&0x0F00)>>8; + xw = (fontdata[entry][i]&0x00F0)>>4; + xh = (fontdata[entry][i]&0x000F); + g.fillRect( + x+(int)(w*dw), + y+(int)(h*dh), + ((int)((w+xw)*dw))-(int)(w*dw), + ((int)((h+xh)*dh))-(int)(h*dh) + ); + i++; + } + break; + default: + break; + } + } +} diff --git a/src/de/mud/telnet/display/Terminal.java b/src/de/mud/telnet/display/Terminal.java new file mode 100644 index 0000000..2d14fe4 --- /dev/null +++ b/src/de/mud/telnet/display/Terminal.java @@ -0,0 +1,73 @@ +package de.mud.telnet.display; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/* + * Terminal -- Terminal emulation (abstract class) + * -- + * $Id: Terminal.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * $timestamp: Wed Mar 5 11:27:13 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.awt.Panel; +import java.awt.Dimension; + +/** + * Terminal is an abstract emulation class. + * It contains a character display. + * + * @version $Id: Terminal.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ +public abstract class Terminal extends Panel +{ + /** + * Get the specific parameter info for the emulation. + * @see java.applet.Applet + */ + public abstract String[][] getParameterInfo(); + + /** + * Put a character on the screen. The method has to see if it is + * a special character that needs to be handles special. + * @param c the character + * @see #putString + */ + public abstract void putChar(char c); + + /** + * Put a character on the screen. The method has to parse the string + * may handle special characters. + * @param s the string + * @see #putString + */ + public abstract void putString(String s); + + /** + * Return the current size of the terminal in characters. + */ + public abstract Dimension getSize(); + + /** + * Return actual terminal type identifier. + */ + public abstract String getTerminalType(); +} diff --git a/src/de/mud/telnet/display/TerminalHost.java b/src/de/mud/telnet/display/TerminalHost.java new file mode 100644 index 0000000..341add3 --- /dev/null +++ b/src/de/mud/telnet/display/TerminalHost.java @@ -0,0 +1,46 @@ +package de.mud.telnet.display; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/* + * TerminalHost -- this interface defines the remote end of the connection + * from our Terminal to the Host (virtual). + * -- + * $Id: TerminalHost.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * $timestamp: Wed Mar 5 12:01:31 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * TerminalHost is an interface for the remote (virtual) end of our connection + * to the host computer we are connected to. + * @version $Id: TerminalHost.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * @author Matthias L Jugel, Marcus Meißner + */ +public interface TerminalHost +{ + /** + * Send a string to the host and return if it was received successfully. + * @param s the string to send + * @return True for successful receivement. + */ + public boolean send(String s); +} + diff --git a/src/de/mud/telnet/display/vt320.java b/src/de/mud/telnet/display/vt320.java new file mode 100644 index 0000000..cc7ff1f --- /dev/null +++ b/src/de/mud/telnet/display/vt320.java @@ -0,0 +1,2018 @@ +package de.mud.telnet.display; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/* + * vt320 -- a DEC VT320 Terminal emulation + * -- + * $Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.awt.Scrollbar; +import java.awt.Event; +import java.awt.Dimension; +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.util.Vector; + +import java.applet.Applet; + +/** + * A DEC VT320 Terminal Emulation (includes VT100/220 and ANSI). + * + * The terminal emulation accesses the applet parameters to configure itself. + * The following parameters may be set. Default values are written in + * italics and other possible values are bold. + *
+ *
<PARAM NAME="Fx" VALUE="functionkeytext"> + *
Sets the string sent when the function key Fx (x between 1 und 20) + * is pressed. + *
<PARAM NAME="VTcolumns" VALUE="80"> + *
Sets the columns of the terminal initially. If the parameter + * VTresize is set to screen this may change, else it is fixed. + *
<PARAM NAME="VTrows" VALUE="24"> + *
Sets the rows of the terminal initially. If the parameter + * value of VTresize screen this may change! + *
<PARAM NAME="VTfont" VALUE="Courier"> + *
Sets the font to be used for the terminal. It is recommended to + * use Courier or at least a fixed width font. + *
<PARAM NAME="VTfontsize" VALUE="14"> + *
Sets the font size for the terminal. If the parameter + * value of VTresize is set to font this may change! + *
<PARAM NAME="VTresize" VALUE="font"> + *
This parameter determines what the terminal should do if the window + * is resized. The default setting font will result in + * resizing the font until is matches the window best. Other possible + * values are none or screen. none will let nothing + * happen and screen will let the display try to change the + * amount of rows and columns to match the window best. + *
<PARAM NAME="VTscrollbar" VALUE="false"> + *
Setting this parameter to true will add a scrollbar west to + * the terminal. Other possible values include left to put the + * scrollbar on the left side of the terminal and right to put it + * explicitely to the right side. + *
<PARAM NAME="VTid" VALUE="vt320"> + *
This parameter will override the terminal id vt320. It may + * be used to determine special terminal abilities of VT Terminals. + *
<PARAM NAME="VTbuffer" VALUE="xx"> + *
Initially this parameter is the same as the VTrows parameter. It + * cannot be less than the amount of rows on the display. It determines + * the available scrollback buffer. + *
<PARAM NAME="VTcharset" VALUE="none"> + *
Setting this parameter to ibm will enable mapping of ibm + * characters (as used in PC BBS systems) to UNICODE characters. Note + * that those special characters probably won't show on UNIX systems + * due to lack in X11 UNICODE support. + *
<PARAM NAME="VTvms" VALUE="false"> + *
Setting this parameter to true will change the Backspace key + * into a delete key, cause the numeric keypad keys to emit VT100 + * codes when Ctrl is pressed, and make other VMS-important keyboard + * definitions. + *
<PARAM NAME="Fnr" VALUE="string"> + *
Function keys from F1 to F20 are programmable. You can + * install any possible string including special characters, such as + * + * + * + * + * + *
\eEscape
\bBackspace
\nNewline
\rReturn
+ *
<PARAM NAME="CFnr" VALUE="string"> + *
Function keys (with the Control-key pressed) from CF1 to CF20 are programmable too. + *
<PARAM NAME="SFnr" VALUE="string"> + *
Function keys (with the Shift-key pressed) from SF1 to SF20 are programmable too. + *
<PARAM NAME="AFnr" VALUE="string"> + *
Function keys (with the Alt-key pressed) from AF1 to AF20 are programmable too. + *
+ * @version $Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $ + * @author Matthias L. Jugel, Marcus Mei?ner + */ +public class vt320 extends Terminal implements TerminalHost +{ + /** + * Return the version of the terminal emulation and its display. + */ + public String toString() { return "$Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $ "+display.version; } + + // the input handler takes the keyboard input from us. + private TerminalHost host = this; + + // due to a bug with Windows we need a keypress cache + private int pressedKey = ' '; + private long pressedWhen = ' '; + + // The character display + private CharDisplay display; + private static int debug = 0; + private String terminalID = "vt320"; + + // X - COLUMNS, Y - ROWS + int R,C; + int Sc,Sr,Sa; + int attributes = 0; + int insertmode = 0; + int statusmode = 0; + int vt52mode = 0; + int normalcursor = 0; + boolean originmode = false; + boolean sendcrlf = true; + + private boolean useibmcharset = false; + + private static int lastwaslf = 0; + private static int i; + private final static char ESC = 27; + private final static char IND = 132; + private final static char NEL = 133; + private final static char RI = 141; + private final static char HTS = 136; + private final static char DCS = 144; + private final static char CSI = 155; + private final static char OSC = 157; + private final static int TSTATE_DATA = 0; + private final static int TSTATE_ESC = 1; /* ESC */ + private final static int TSTATE_CSI = 2; /* ESC [ */ + private final static int TSTATE_DCS = 3; /* ESC P */ + private final static int TSTATE_DCEQ = 4; /* ESC [? */ + private final static int TSTATE_ESCSQUARE= 5; /* ESC # */ + private final static int TSTATE_OSC= 6; /* ESC ] */ + private final static int TSTATE_SETG0= 7; /* ESC (? */ + private final static int TSTATE_SETG1= 8; /* ESC )? */ + private final static int TSTATE_SETG2= 9; /* ESC *? */ + private final static int TSTATE_SETG3= 10; /* ESC +? */ + private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */ + + /* The graphics charsets + * B - default ASCII + * A - default UK + * 0 - DEC SPECIAL + * < - User defined + * .... + */ + private static char gx[] = { + 'B', // g0 + '0', // g1 + 'A', // g2 + '<', // g3 + }; + private static char gr = 1; // default GR to G1 + private static char gl = 0; // default GL to G0 + + // array to store DEC Special -> Unicode mapping + // Unicode DEC Unicode name (DEC name) + private static char DECSPECIAL[] = { + '\u0040', //5f blank + '\u2666', //60 black diamond + '\u2592', //61 grey square + '\u2409', //62 Horizontal tab (ht) pict. for control + '\u240c', //63 Form Feed (ff) pict. for control + '\u240d', //64 Carriage Return (cr) pict. for control + '\u240a', //65 Line Feed (lf) pict. for control + '\u00ba', //66 Masculine ordinal indicator + '\u00b1', //67 Plus or minus sign + '\u2424', //68 New Line (nl) pict. for control + '\u240b', //69 Vertical Tab (vt) pict. for control + '\u2518', //6a Forms light up and left + '\u2510', //6b Forms light down and left + '\u250c', //6c Forms light down and right + '\u2514', //6d Forms light up and right + '\u253c', //6e Forms light vertical and horizontal + '\u2594', //6f Upper 1/8 block (Scan 1) + '\u2580', //70 Upper 1/2 block (Scan 3) + '\u2500', //71 Forms light horizontal or ?em dash? (Scan 5) + '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7) + '\u005f', //73 \u005f underscore or \u2581 lower 1/8 (Scan 9) + '\u251c', //74 Forms light vertical and right + '\u2524', //75 Forms light vertical and left + '\u2534', //76 Forms light up and horizontal + '\u252c', //77 Forms light down and horizontal + '\u2502', //78 vertical bar + '\u2264', //79 less than or equal + '\u2265', //7a greater than or equal + '\u00b6', //7b paragraph + '\u2260', //7c not equal + '\u00a3', //7d Pound Sign (british) + '\u00b7' //7e Middle Dot + }; + + private final static int KEYUP = Event.UP % 1000; + private final static int KEYDOWN = Event.DOWN % 1000; + private final static int KEYLEFT = Event.LEFT % 1000; + private final static int KEYRIGHT = Event.RIGHT % 1000; + private final static int KEYF1 = Event.F1 % 1000; + private final static int KEYF2 = Event.F2 % 1000; + private final static int KEYF3 = Event.F3 % 1000; + private final static int KEYF4 = Event.F4 % 1000; + private final static int KEYF5 = Event.F5 % 1000; + private final static int KEYF6 = Event.F6 % 1000; + private final static int KEYF7 = Event.F7 % 1000; + private final static int KEYF8 = Event.F8 % 1000; + private final static int KEYF9 = Event.F9 % 1000; + private final static int KEYF10 = Event.F10 % 1000; + private final static int KEYF11 = Event.F11 % 1000; + private final static int KEYF12 = Event.F12 % 1000; + private final static int KEYPGDN = Event.PGDN % 1000; + private final static int KEYPGUP = Event.PGUP % 1000; + + private final static int KEYHOME = Event.HOME % 1000; + private final static int KEYEND = Event.END % 1000; + + public static final int KEYPRINT_SCREEN = 20; + public static final int KEYSCROLL_LOCK = 21; + public static final int KEYCAPS_LOCK = 22; + public static final int KEYNUM_LOCK = 23; + public static final int KEYPAUSE = 24; + public static final int KEYINSERT = 25; + + /** + * The Insert key. + */ + public static final int INSERT = 1025; + + /** + * Strings to send on function key presseic + */ + private String FunctionKey[]; + private String FunctionKeyShift[]; + private String FunctionKeyCtrl[]; + private String FunctionKeyAlt[]; + private String KeyUp; + private String KeyDown; + private String KeyLeft; + private String KeyRight; + private String KeyBacktab; + private String KeyTab; + + private String KP0; + private String KP1; + private String KP2; + private String KP3; + private String KP4; + private String KP5; + private String KP6; + private String KP7; + private String KP8; + private String KP9; + private String KPMinus; + private String KPComma; + private String KPPeriod; + private String KPEnter; + private String PF1; + private String PF2; + private String PF3; + private String PF4; + private String Help; + private String Do; + private String Find; + private String Insert; + private String Remove; + private String Select; + private String PrevScn; + private String NextScn; + + + private String osc,dcs; /* to memorize OSC & DCS control sequence */ + + private int term_state = TSTATE_DATA; + private boolean vms = false; + private byte[] Tabs; + private int[] DCEvars = new int [10]; + private int DCEvar; + + /* operation system we run on, Scrollbar hack */ + private String osn = System.getProperty("os.name"); + + public String[][] getParameterInfo() { + String pinfo[][] = { + {"VTcolumns", "Integer", "Columns of the terminal"}, + {"VTrows", "Integer", "Rows of the terminal"}, + {"VTfont", "String", "Terminal font (default is Courier)"}, + {"VTfontsize", "Integer", "Font size"}, + {"VTbuffer", "Integer", "Scrollback buffer size"}, + {"VTscrollbar","Boolean", "Enable or disable scrollbar"}, + {"VTresize", "String", "One of none, font, screen"}, + {"VTid", "String", "Terminal id, standard is VT320"}, + {"VTcharset", "String", "Charset used"}, + {"VTvms", "Boolean", "Enable or disable VMS key mappings"}, + {"F1 - F20", "String", "Programmable Function Keys"}, + {"SF1 - SF20", "String", "Programmable Shift-ed Function Keys"}, + {"CF1 - CF20", "String", "Programmable Control-ed Function Keys"}, + {"AF1 - AF20", "String", "Programmable Alt-ed Function Keys"}, + }; + return pinfo; + } + + static String unEscape(String tmp) { + int idx = 0, oldidx = 0; + String cmd; + + cmd = ""; + while((idx = tmp.indexOf('\\', oldidx)) >= 0 && + ++idx <= tmp.length()) { + cmd += tmp.substring(oldidx, idx-1); + if(idx == tmp.length()) return cmd; + switch(tmp.charAt(idx)) { + case 'b': cmd += "\b"; break; + case 'e': cmd += "\u001b"; break; + case 'n': cmd += "\n"; break; + case 'r': cmd += "\r"; break; + case 't': cmd += "\t"; break; + case 'v': cmd += "\u000b"; break; + case 'a': cmd += "\u0012"; break; + default : cmd += tmp.substring(idx, ++idx);break; + } + oldidx = ++idx; + } + if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx); + return cmd; + } + + /** + * Initialize terminal. + * @param parent the applet parent where to get parameters from + * @see display.Terminal + */ + public void addNotify() { + if(display == null) { + String width = "80", height = "24", resize ="screen"; + String font = "monaco", fs = "14", bufs = "100"; + String scrb = "false"; + String vms = "false"; + String ibmcset = "false"; + + Applet applet = getParent() instanceof Applet ? (Applet)getParent() : null; + + if(applet != null) { + try { + host = (TerminalHost)applet; + } catch(ClassCastException e) { + System.err.println("vt320: "+applet+" cannot receive terminal input"); + host = this; + } + + width = applet.getParameter("VTcolumns"); + height = applet.getParameter("VTrows"); + font = applet.getParameter("VTfont"); + fs = applet.getParameter("VTfontsize"); + bufs = applet.getParameter("VTbuffer"); + scrb = applet.getParameter("VTscrollbar"); + vms = applet.getParameter("VTvms"); + resize = applet.getParameter("VTresize"); + resize = resize == null ? "font" : resize; + ibmcset = applet.getParameter("VTcharset"); + if ((ibmcset!=null)&&(ibmcset.equals("ibm"))) + useibmcharset=true; + + if(applet.getParameter("VTid") != null) + terminalID = applet.getParameter("VTid"); + } + + display = new CharDisplay( + width==null?80:(new Integer(width)).intValue(), + (height==null?24:(new Integer(height)).intValue()), + font==null?"Courier":font, + fs==null?14:(new Integer(fs)).intValue() + ); + display.setBottomMargin((height==null? + 24: + (new Integer(height)).intValue()) - 1); + display.setBufferSize(bufs==null?100:(new Integer(bufs)).intValue()); + if(resize.equals("none")) + display.setResizeStrategy(CharDisplay.RESIZE_NONE); + else if(resize.equals("font")) + display.setResizeStrategy(CharDisplay.RESIZE_FONT); + else if(resize.equals("screen")) + display.setResizeStrategy(CharDisplay.RESIZE_SCREEN); + + display.setResizeStrategy(CharDisplay.RESIZE_SCREEN); + + display.setBorder(2, false); + + setLayout(new BorderLayout()); + display.setScrollbar("East"); + /* + if(scrb != null && !scrb.equals("false")) { + if(scrb.equals("left") || scrb.equals("true")) + display.setScrollbar("West"); + else if(scrb.equals("right")) + display.setScrollbar("East"); + else + System.out.println("vt320: unknown scrollbar location: "+scrb); + } + */ + if(vms != null && vms.equals("true")) + { + this.vms = true; + } + add("Center", display); + InitTerminalVars(); + if (applet != null) for (int i=1;i<20;i++) + { + if (applet.getParameter("F"+i)!=null) + FunctionKey[i] = unEscape(applet.getParameter("F"+i)); + if (applet.getParameter("SF"+i)!=null) + FunctionKeyShift[i] = unEscape(applet.getParameter("SF"+i)); + if (applet.getParameter("CF"+i)!=null) + FunctionKeyCtrl[i] = unEscape(applet.getParameter("CF"+i)); + if (applet.getParameter("AF"+i)!=null) + FunctionKeyAlt[i] = unEscape(applet.getParameter("AF"+i)); + } + } + super.addNotify(); + } + + private void InitTerminalVars() { + int nw = display.getColumns(); + + if (nw<132) nw=132; //catch possible later 132/80 resizes + Tabs = new byte[nw]; + for (int i=0;i or + */ + fmap = FunctionKey; + if (shift) + fmap = FunctionKeyShift; + if (control) + fmap = FunctionKeyCtrl; + if (alt) + fmap = FunctionKeyAlt; + switch (evt.key % 1000) { + case KEYF1: + input = fmap[1]; + break; + case KEYF2: + input = fmap[2]; + break; + case KEYF3: + input = fmap[3]; + break; + case KEYF4: + input = fmap[4]; + break; + case KEYF5: + input = fmap[5]; + break; + case KEYF6: + input = fmap[6]; + break; + case KEYF7: + input = fmap[7]; + break; + case KEYF8: + input = fmap[8]; + break; + case KEYF9: + input = fmap[9]; + break; + case KEYF10: + input = fmap[10]; + break; + case KEYF11: + input = fmap[11]; + break; + case KEYF12: + input = fmap[12]; + break; + case KEYUP: + input = KeyUp; + break; + case KEYDOWN: + input = KeyDown; + break; + case KEYLEFT: + input = KeyLeft; + break; + case KEYRIGHT: + input = KeyRight; + break; + case KEYPGDN: + input = NextScn; + break; + case KEYPGUP: + input = PrevScn; + break; + case KEYINSERT: + input = Insert; + break; +// The following cases fall through if not in VMS mode. + case KEYHOME: + if (vms) + { + input = "" + (char)8; + break; + } + //FALLTHROUGH + case KEYEND: + if (vms) + { + input = "" + (char)5; + break; + } + //FALLTHROUGH + case KEYNUM_LOCK: + if (vms && control) { + if (pressedKey != evt.key) { + pressedKey = evt.key; + input = PF1; + } else + pressedKey = ' '; // Here, we eat a second numlock since that returns numlock state + } + break; + default: + /*if (debug>0)*/ + System.out.println("vt320: unknown event:"+(int)evt.key); + break; + } + } + + if(input != null && input.length() > 0) + return host.send(input); + + return false; + } + + /** + * Dummy method to handle input events (String). + * This is only needed if our parent is not TerminalHost + * @param s String to handle + * @return always true + * @see display.TerminalHost + */ + public boolean send(String s) { + putString(s); + return true; + } + + private void handle_dcs(String dcs) { + if (debug>1) + System.out.println("DCS: "+dcs); + } + private void handle_osc(String osc) { + if (debug>1) + System.out.println("OSC: "+osc); + } + + /** + * Put String at current cursor position. Moves cursor + * according to the String. Does NOT wrap. + * @param s the string + */ + public void putString(String s) { + int i,len=s.length(); + + display.markLine(R,1); + for (i=0;i +//# Lori Hoerth +//# General notes: none +//# +//# Format: Three tab-separated columns +//# Column #1 is the cp1255_WinHebrew code (in hex) +//# Column #2 is the Unicode (in hex as 0xXXXX) +//# Column #3 is the Unicode name (follows a comment sign, '#') +//# +//# The entries are in cp437_DOSLatinUS order +//# + + 0x0000,// #NULL + 0x0001,// #START OF HEADING + 0x0002,// #START OF TEXT + 0x0003,// #END OF TEXT + 0x0004,// #END OF TRANSMISSION + 0x0005,// #ENQUIRY + 0x0006,// #ACKNOWLEDGE + 0x0007,// #BELL + 0x0008,// #BACKSPACE + 0x0009,// #HORIZONTAL TABULATION + 0x000a,// #LINE FEED + 0x000b,// #VERTICAL TABULATION + 0x000c,// #FORM FEED + 0x000d,// #CARRIAGE RETURN + 0x000e,// #SHIFT OUT + 0x000f,// #SHIFT IN + 0x0010,// #DATA LINK ESCAPE + 0x0011,// #DEVICE CONTROL ONE + 0x0012,// #DEVICE CONTROL TWO + 0x0013,// #DEVICE CONTROL THREE + 0x0014,// #DEVICE CONTROL FOUR + 0x0015,// #NEGATIVE ACKNOWLEDGE + 0x0016,// #SYNCHRONOUS IDLE + 0x0017,// #END OF TRANSMISSION BLOCK + 0x0018,// #CANCEL + 0x0019,// #END OF MEDIUM + 0x001a,// #SUBSTITUTE + 0x001b,// #ESCAPE + 0x001c,// #FILE SEPARATOR + 0x001d,// #GROUP SEPARATOR + 0x001e,// #RECORD SEPARATOR + 0x001f,// #UNIT SEPARATOR + 0x0020,// #SPACE + 0x0021,// #EXCLAMATION MARK + 0x0022,// #QUOTATION MARK + 0x0023,// #NUMBER SIGN + 0x0024,// #DOLLAR SIGN + 0x0025,// #PERCENT SIGN + 0x0026,// #AMPERSAND + 0x0027,// #APOSTROPHE + 0x0028,// #LEFT PARENTHESIS + 0x0029,// #RIGHT PARENTHESIS + 0x002a,// #ASTERISK + 0x002b,// #PLUS SIGN + 0x002c,// #COMMA + 0x002d,// #HYPHEN-MINUS + 0x002e,// #FULL STOP + 0x002f,// #SOLIDUS + 0x0030,// #DIGIT ZERO + 0x0031,// #DIGIT ONE + 0x0032,// #DIGIT TWO + 0x0033,// #DIGIT THREE + 0x0034,// #DIGIT FOUR + 0x0035,// #DIGIT FIVE + 0x0036,// #DIGIT SIX + 0x0037,// #DIGIT SEVEN + 0x0038,// #DIGIT EIGHT + 0x0039,// #DIGIT NINE + 0x003a,// #COLON + 0x003b,// #SEMICOLON + 0x003c,// #LESS-THAN SIGN + 0x003d,// #EQUALS SIGN + 0x003e,// #GREATER-THAN SIGN + 0x003f,// #QUESTION MARK + 0x0040,// #COMMERCIAL AT + 0x0041,// #LATIN CAPITAL LETTER A + 0x0042,// #LATIN CAPITAL LETTER B + 0x0043,// #LATIN CAPITAL LETTER C + 0x0044,// #LATIN CAPITAL LETTER D + 0x0045,// #LATIN CAPITAL LETTER E + 0x0046,// #LATIN CAPITAL LETTER F + 0x0047,// #LATIN CAPITAL LETTER G + 0x0048,// #LATIN CAPITAL LETTER H + 0x0049,// #LATIN CAPITAL LETTER I + 0x004a,// #LATIN CAPITAL LETTER J + 0x004b,// #LATIN CAPITAL LETTER K + 0x004c,// #LATIN CAPITAL LETTER L + 0x004d,// #LATIN CAPITAL LETTER M + 0x004e,// #LATIN CAPITAL LETTER N + 0x004f,// #LATIN CAPITAL LETTER O + 0x0050,// #LATIN CAPITAL LETTER P + 0x0051,// #LATIN CAPITAL LETTER Q + 0x0052,// #LATIN CAPITAL LETTER R + 0x0053,// #LATIN CAPITAL LETTER S + 0x0054,// #LATIN CAPITAL LETTER T + 0x0055,// #LATIN CAPITAL LETTER U + 0x0056,// #LATIN CAPITAL LETTER V + 0x0057,// #LATIN CAPITAL LETTER W + 0x0058,// #LATIN CAPITAL LETTER X + 0x0059,// #LATIN CAPITAL LETTER Y + 0x005a,// #LATIN CAPITAL LETTER Z + 0x005b,// #LEFT SQUARE BRACKET + 0x005c,// #REVERSE SOLIDUS + 0x005d,// #RIGHT SQUARE BRACKET + 0x005e,// #CIRCUMFLEX ACCENT + 0x005f,// #LOW LINE + 0x0060,// #GRAVE ACCENT + 0x0061,// #LATIN SMALL LETTER A + 0x0062,// #LATIN SMALL LETTER B + 0x0063,// #LATIN SMALL LETTER C + 0x0064,// #LATIN SMALL LETTER D + 0x0065,// #LATIN SMALL LETTER E + 0x0066,// #LATIN SMALL LETTER F + 0x0067,// #LATIN SMALL LETTER G + 0x0068,// #LATIN SMALL LETTER H + 0x0069,// #LATIN SMALL LETTER I + 0x006a,// #LATIN SMALL LETTER J + 0x006b,// #LATIN SMALL LETTER K + 0x006c,// #LATIN SMALL LETTER L + 0x006d,// #LATIN SMALL LETTER M + 0x006e,// #LATIN SMALL LETTER N + 0x006f,// #LATIN SMALL LETTER O + 0x0070,// #LATIN SMALL LETTER P + 0x0071,// #LATIN SMALL LETTER Q + 0x0072,// #LATIN SMALL LETTER R + 0x0073,// #LATIN SMALL LETTER S + 0x0074,// #LATIN SMALL LETTER T + 0x0075,// #LATIN SMALL LETTER U + 0x0076,// #LATIN SMALL LETTER V + 0x0077,// #LATIN SMALL LETTER W + 0x0078,// #LATIN SMALL LETTER X + 0x0079,// #LATIN SMALL LETTER Y + 0x007a,// #LATIN SMALL LETTER Z + 0x007b,// #LEFT CURLY BRACKET + 0x007c,// #VERTICAL LINE + 0x007d,// #RIGHT CURLY BRACKET + 0x007e,// #TILDE + 0x007f,// #DELETE + 0x00c7,// #LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc,// #LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9,// #LATIN SMALL LETTER E WITH ACUTE + 0x00e2,// #LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4,// #LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0,// #LATIN SMALL LETTER A WITH GRAVE + 0x00e5,// #LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7,// #LATIN SMALL LETTER C WITH CEDILLA + 0x00ea,// #LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb,// #LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8,// #LATIN SMALL LETTER E WITH GRAVE + 0x00ef,// #LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee,// #LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec,// #LATIN SMALL LETTER I WITH GRAVE + 0x00c4,// #LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5,// #LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9,// #LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6,// #LATIN SMALL LIGATURE AE + 0x00c6,// #LATIN CAPITAL LIGATURE AE + 0x00f4,// #LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6,// #LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2,// #LATIN SMALL LETTER O WITH GRAVE + 0x00fb,// #LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9,// #LATIN SMALL LETTER U WITH GRAVE + 0x00ff,// #LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6,// #LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc,// #LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00a2,// #CENT SIGN + 0x00a3,// #POUND SIGN + 0x00a5,// #YEN SIGN + 0x20a7,// #PESETA SIGN + 0x0192,// #LATIN SMALL LETTER F WITH HOOK + 0x00e1,// #LATIN SMALL LETTER A WITH ACUTE + 0x00ed,// #LATIN SMALL LETTER I WITH ACUTE + 0x00f3,// #LATIN SMALL LETTER O WITH ACUTE + 0x00fa,// #LATIN SMALL LETTER U WITH ACUTE + 0x00f1,// #LATIN SMALL LETTER N WITH TILDE + 0x00d1,// #LATIN CAPITAL LETTER N WITH TILDE + 0x00aa,// #FEMININE ORDINAL INDICATOR + 0x00ba,// #MASCULINE ORDINAL INDICATOR + 0x00bf,// #INVERTED QUESTION MARK + 0x2310,// #REVERSED NOT SIGN + 0x00ac,// #NOT SIGN + 0x00bd,// #VULGAR FRACTION ONE HALF + 0x00bc,// #VULGAR FRACTION ONE QUARTER + 0x00a1,// #INVERTED EXCLAMATION MARK + 0x00ab,// #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb,// #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591,// #LIGHT SHADE + 0x2592,// #MEDIUM SHADE + 0x2593,// #DARK SHADE + 0x2502,// #BOX DRAWINGS LIGHT VERTICAL + 0x2524,// #BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x2561,// #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0x2562,// #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0x2556,// #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0x2555,// #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0x2563,// #BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551,// #BOX DRAWINGS DOUBLE VERTICAL + 0x2557,// #BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d,// #BOX DRAWINGS DOUBLE UP AND LEFT + 0x255c,// #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0x255b,// #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0x2510,// #BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514,// #BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534,// #BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c,// #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c,// #BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500,// #BOX DRAWINGS LIGHT HORIZONTAL + 0x253c,// #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x255e,// #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0x255f,// #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0x255a,// #BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554,// #BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569,// #BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566,// #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560,// #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550,// #BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c,// #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x2567,// #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0x2568,// #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0x2564,// #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0x2565,// #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0x2559,// #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0x2558,// #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0x2552,// #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0x2553,// #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0x256b,// #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0x256a,// #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0x2518,// #BOX DRAWINGS LIGHT UP AND LEFT + 0x250c,// #BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588,// #FULL BLOCK + 0x2584,// #LOWER HALF BLOCK + 0x258c,// #LEFT HALF BLOCK + 0x2590,// #RIGHT HALF BLOCK + 0x2580,// #UPPER HALF BLOCK + 0x03b1,// #GREEK SMALL LETTER ALPHA + 0x00df,// #LATIN SMALL LETTER SHARP S + 0x0393,// #GREEK CAPITAL LETTER GAMMA + 0x03c0,// #GREEK SMALL LETTER PI + 0x03a3,// #GREEK CAPITAL LETTER SIGMA + 0x03c3,// #GREEK SMALL LETTER SIGMA + 0x00b5,// #MICRO SIGN + 0x03c4,// #GREEK SMALL LETTER TAU + 0x03a6,// #GREEK CAPITAL LETTER PHI + 0x0398,// #GREEK CAPITAL LETTER THETA + 0x03a9,// #GREEK CAPITAL LETTER OMEGA + 0x03b4,// #GREEK SMALL LETTER DELTA + 0x221e,// #INFINITY + 0x03c6,// #GREEK SMALL LETTER PHI + 0x03b5,// #GREEK SMALL LETTER EPSILON + 0x2229,// #INTERSECTION + 0x2261,// #IDENTICAL TO + 0x00b1,// #PLUS-MINUS SIGN + 0x2265,// #GREATER-THAN OR EQUAL TO + 0x2264,// #LESS-THAN OR EQUAL TO + 0x2320,// #TOP HALF INTEGRAL + 0x2321,// #BOTTOM HALF INTEGRAL + 0x00f7,// #DIVISION SIGN + 0x2248,// #ALMOST EQUAL TO + 0x00b0,// #DEGREE SIGN + 0x2219,// #BULLET OPERATOR + 0x00b7,// #MIDDLE DOT + 0x221a,// #SQUARE ROOT + 0x207f,// #SUPERSCRIPT LATIN SMALL LETTER N + 0x00b2,// #SUPERSCRIPT TWO + 0x25a0,// #BLACK SQUARE + 0x00a0,// #NO-BREAK SPACE + }; + + public char map_cp850_unicode(char x) { + if (x>=0x100) + return x; + return unimap[x]; + } + + private void _SetCursor(int row,int col) { + int maxr = display.getRows(); + int tm = display.getTopMargin(); + + R = (row<0)?0:row; + C = (col<0)?0:col; + + if (originmode) { + R += display.getTopMargin(); + maxr = display.getBottomMargin(); + } + if (R>maxr) R = maxr; + } + + public void putChar(char c,boolean doshowcursor) { + Dimension size; + int rows = display.getRows() ; //statusline + int columns = display.getColumns(); + int tm = display.getTopMargin(); + int bm = display.getBottomMargin(); + String tosend; + Vector vec; + byte msg[]; + + if (debug>4) System.out.println("putChar("+c+" ["+((int)c)+"]) at R="+R+" , C="+C+", columns="+columns+", rows="+rows); + display.markLine(R,1); + if (c>255) { + if (debug>0) + System.out.println("char > 255:"+((int)c)); + return; + } + switch (term_state) { + case TSTATE_DATA: + /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset. + * probably... but some BBS do anyway... + */ + if (!useibmcharset) { + boolean doneflag = true; + switch (c) { + case OSC: + osc=""; + term_state = TSTATE_OSC; + break; + case RI: + if (R>tm) + R--; + else + display.insertLine(R,1,display.SCROLL_DOWN); + if (debug>1) + System.out.println("RI"); + break; + case IND: + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + display.insertLine(R,1,display.SCROLL_UP); + else + R++; + if (debug>1) + System.out.println("IND (at "+R+" )"); + break; + case NEL: + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + display.insertLine(R,1,display.SCROLL_UP); + else + R++; + C=0; + if (debug>1) + System.out.println("NEL (at "+R+" )"); + break; + case HTS: + Tabs[C] = 1; + if (debug>1) + System.out.println("HTS"); + break; + case DCS: + dcs=""; + term_state = TSTATE_DCS; + break; + default: + doneflag = false; + break; + } + if (doneflag) break; + } + switch (c) { + case CSI: // should be in the 8bit section, but some BBS use this + term_state = TSTATE_DCEQ; + break; + case ESC: + term_state = TSTATE_ESC; + lastwaslf=0; + break; + case '\b': + C--; + if (C<0) + C=0; + lastwaslf = 0; + break; + case '\t': + if (insertmode == 1) { + int nr,newc; + + newc = C; + do { + display.insertChar(C,R,' ',attributes); + newc++; + } while (newc3) + System.out.println("R= "+R+", bm "+bm+", tm="+tm+", rows="+rows); + if (!vms) + { + if (lastwaslf!=0 && lastwaslf!=c) // Ray: I do not understand this logic. + break; + lastwaslf=c; + C = 0; + } + if (R == tm - 1 || R == bm || R >= rows - 1) + display.insertLine(R,1); + else + R++; + break; + case '\016': + /* ^N, Shift out - Put G1 into GL */ + gl = 1; + break; + case '\017': + /* ^O, Shift in - Put G0 into GL */ + gl = 0; + break; + default: + lastwaslf=0; + if (c<32) { + if (c!=0) + if (debug>0) + System.out.println("TSTATE_DATA char: "+((int)c)); + break; + } + if(C >= columns) { + if(R < rows - 1) + R++; + else + display.insertLine(R,display.SCROLL_UP); + C = 0; + } + + // Mapping if DEC Special is chosen charset + if ( gx[gl] == '0' ) { + if ( c >= '\u005f' && c <= '\u007e' ) { + if (debug>3) + System.out.print("Mapping "+c+" (index "+((short)c-0x5f)+" to "); + c = DECSPECIAL[(short)c - 0x5f]; + if (debug>3) + System.out.println(c+" ("+(int)c+")"); + } + } +/* + if ( gx[gr] == '0' ) { + if ( c >= '\u00bf' && c <= '\u00fe' ) { + if (debug>2) + System.out.print("Mapping "+c); + c = DECSPECIAL[(short)c - 0xbf]; + if (debug>2) + System.out.println("to "+c); + } + } +*/ + if (useibmcharset) + c = map_cp850_unicode(c); + + /*if(true || (statusmode == 0)) { */ + if (debug>4) System.out.println("output "+c+" at "+C+","+R); + if (insertmode==1) { + display.insertChar(C, R, c, attributes); + } else { + display.putChar(C, R, c, attributes); + } + /* + } else { + if (insertmode==1) { + display.insertChar(C, rows, c, attributes); + } else { + display.putChar(C, rows, c, attributes); + } + } + */ + C++; + break; + } /* switch(c) */ + break; + case TSTATE_OSC: + if ((c<0x20) && (c!=ESC)) {// NP - No printing character + handle_osc(osc); + term_state = TSTATE_DATA; + break; + } + //but check for vt102 ESC \ + if (c=='\\' && osc.charAt(osc.length()-1)==ESC) { + handle_osc(osc); + term_state = TSTATE_DATA; + break; + } + osc = osc + c; + break; + case TSTATE_ESC: + switch (c) { + case '#': + term_state = TSTATE_ESCSQUARE; + break; + case 'c': + /* Hard terminal reset */ + /*FIXME:*/ + term_state = TSTATE_DATA; + break; + case '[': + term_state = TSTATE_CSI; + DCEvar = 0; + DCEvars[0] = 0; + DCEvars[1] = 0; + DCEvars[2] = 0; + DCEvars[3] = 0; + break; + case ']': + osc=""; + term_state = TSTATE_OSC; + break; + case 'P': + dcs=""; + term_state = TSTATE_DCS; + break; + case 'E': + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + display.insertLine(R,1,display.SCROLL_UP); + else + R++; + C=0; + if (debug>1) + System.out.println("ESC E (at "+R+")"); + term_state = TSTATE_DATA; + break; + case 'D': + if (R == tm - 1 || R == bm || R == rows - 1) + display.insertLine(R,1,display.SCROLL_UP); + else + R++; + if (debug>1) + System.out.println("ESC D (at "+R+" )"); + term_state = TSTATE_DATA; + break; + case 'M': // IL + if ((R>=tm) && (R<=bm)) // in scrolregion + display.insertLine(R,1,display.SCROLL_DOWN); + /* else do nothing ; */ + if (debug>1) + System.out.println("ESC M "); + term_state = TSTATE_DATA; + break; + case 'H': + if (debug>1) + System.out.println("ESC H at "+C); + /* right border probably ...*/ + if (C>=columns) + C=columns-1; + Tabs[C] = 1; + term_state = TSTATE_DATA; + break; + case '=': + /*application keypad*/ + if (debug>0) + System.out.println("ESC ="); + term_state = TSTATE_DATA; + break; + case '>': + /*normal keypad*/ + if (debug>0) + System.out.println("ESC >"); + term_state = TSTATE_DATA; + break; + case '7': + /*save cursor */ + Sc = C; + Sr = R; + Sa = attributes; + if (debug>1) + System.out.println("ESC 7"); + term_state = TSTATE_DATA; + break; + case '8': + /*restore cursor */ + C = Sc; + R = Sr; + attributes = Sa; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC 7"); + break; + case '(': + /* Designate G0 Character set (ISO 2022) */ + term_state = TSTATE_SETG0; + break; + case ')': + /* Designate G0 character set (ISO 2022) */ + term_state = TSTATE_SETG1; + break; + case '*': + /* Designate G1 Character set (ISO 2022) */ + term_state = TSTATE_SETG2; + break; + case '+': + /* Designate G1 Character set (ISO 2022) */ + term_state = TSTATE_SETG3; + break; + case '~': + /* Locking Shift 1, right */ + term_state = TSTATE_DATA; + gr = 1; + break; + case 'n': + /* Locking Shift 2 */ + term_state = TSTATE_DATA; + gl = 2; + break; + case '}': + /* Locking Shift 2, right */ + term_state = TSTATE_DATA; + gr = 2; + break; + case 'o': + /* Locking Shift 3 */ + term_state = TSTATE_DATA; + gl = 3; + break; + case '|': + /* Locking Shift 3, right */ + term_state = TSTATE_DATA; + gr = 3; + break; + default: + System.out.println("ESC unknown letter: ("+((int)c)+")"); + term_state = TSTATE_DATA; + break; + } + break; + case TSTATE_SETG0: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC ( : G0 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC ( : G0 char set ("+c+" "+((int)c)+")"); + gx[0] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG1: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC ) :G1 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC ) :G1 char set ("+c+" "+((int)c)+")"); + gx[1] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG2: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC*:G2 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC*:G2 char set ("+c+" "+((int)c)+")"); + gx[2] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG3: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC+:G3 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC+:G3 char set ("+c+" "+((int)c)+")"); + gx[3] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_ESCSQUARE: + switch (c) { + case '8': + for (int i=0;i1) + System.out.println("ESC [ ? "+DCEvars[0]+" r"); + /* DEC Mode reset */ + switch (DCEvars[0]){ + case 3: /* 80 columns*/ + size = display.size(); + display.setWindowSize(80,rows); + layout(); + break; + case 4: /* scrolling mode, smooth */ + break; + case 5: /* light background */ + break; + case 6: /* move inside margins ? */ + originmode = false; + break; + case 12:/* local echo off */ + break; + } + term_state = TSTATE_DATA; + break; + case 'h': // DECSET + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" h"); + /* DEC Mode set */ + switch (DCEvars[0]){ + case 1: /* Application cursor keys */ + KeyUp = "\u001bOA"; + KeyDown = "\u001bOB"; + KeyRight= "\u001bOC"; + KeyLeft = "\u001bOD"; + break; + case 3: /* 132 columns*/ + size = display.size(); + display.setWindowSize(132,rows); + layout(); + break; + case 4: /* scrolling mode, smooth */ + break; + case 5: /* light background */ + break; + case 6: /* move inside margins ? */ + originmode = true; + break; + case 12:/* local echo off */ + break; + } + term_state = TSTATE_DATA; + break; + case 'l': //DECRST + /* DEC Mode reset */ + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" l"); + switch (DCEvars[0]){ + case 1: /* Application cursor keys */ + KeyUp = "\u001b[A"; + KeyDown = "\u001b[B"; + KeyRight= "\u001b[C"; + KeyLeft = "\u001b[D"; + break; + case 3: /* 80 columns*/ + size = display.size(); + display.setWindowSize(80,rows); + layout(); + break; + case 4: /* scrolling mode, jump */ + break; + case 5: /* dark background */ + break; + case 6: /* move outside margins ? */ + originmode = false; + break; + case 12:/* local echo on */ + break; + } + term_state = TSTATE_DATA; + break; + case ';': + DCEvar++; + DCEvars[DCEvar] = 0; + break; + case 'n': + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" n"); + switch (DCEvars[0]) { + case 15: + /* printer? no printer. */ + host.send(((char)ESC)+"[?13n"); + System.out.println("ESC[5n"); + break; + default:break; + } + term_state = TSTATE_DATA; + break; + default: + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" "+c); + term_state = TSTATE_DATA; + break; + } + break; + case TSTATE_CSI_DOLLAR: + switch (c) { + case '}': + System.out.println("Active Status Display now "+DCEvars[0]); + statusmode = DCEvars[0]; + break; +/* bad documentation? + case '-': + System.out.println("Set Status Display now "+DCEvars[0]); + break; + */ + case '~': + System.out.println("Status Line mode now "+DCEvars[0]); + break; + default: + System.out.println("UNKNOWN Status Display code "+c+", with Pn="+DCEvars[0]); + break; + } + term_state = TSTATE_DATA; + break; + case TSTATE_CSI: + switch (c) { + case '$': + term_state=TSTATE_CSI_DOLLAR; + break; + case '?': + DCEvar=0; + DCEvars[0]=0; + term_state=TSTATE_DCEQ; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + DCEvars[DCEvar]=DCEvars[DCEvar]*10+((int)c)-48; + break; + case ';': + DCEvar++; + DCEvars[DCEvar] = 0; + break; + case 'c':/* send primary device attributes */ + /* send (ESC[?61c) */ + host.send(((char)ESC)+"[?1;2c"); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" c"); + break; + case 'q': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" q"); + term_state = TSTATE_DATA; + break; + case 'g': + /* used for tabsets */ + switch (DCEvars[0]){ + case 3:/* clear them */ + int nw = display.getColumns(); + Tabs = new byte[nw]; + break; + case 0: + Tabs[C] = 0; + break; + } + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" g"); + term_state = TSTATE_DATA; + break; + case 'h': + switch (DCEvars[0]) { + case 4: + insertmode = 1; + break; + case 20: + sendcrlf = true; + break; + default: + System.out.println("unsupported: ESC [ "+DCEvars[0]+" h"); + break; + } + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" h"); + break; + case 'l': + switch (DCEvars[0]) { + case 4: + insertmode = 0; + break; + case 20: + sendcrlf = false; + break; + } + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" l"); + break; + case 'A': // CUU + { + int limit; + /* FIXME: xterm only cares about 0 and topmargin */ + if (R > bm) + limit = bm+1; + else if (R >= tm) { + limit = tm; + } else + limit = 0; + if (DCEvars[0]==0) + R--; + else + R-=DCEvars[0]; + if (R < limit) + R = limit; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" A"); + break; + } + case 'B': // CUD + /* cursor down n (1) times */ + { + int limit; + if (R < tm) + limit = tm-1; + else if (R <= bm) { + limit = bm; + } else + limit = rows - 1; + if (DCEvars[0]==0) + R++; + else + R+=DCEvars[0]; + if (R > limit) + R = limit; + else { + if (debug>2) System.out.println("Not limited."); + } + if (debug>2) System.out.println("to: " + R); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" B (at C="+C+")"); + break; + } + case 'C': + if (DCEvars[0]==0) + C++; + else + C+=DCEvars[0]; + if (C>columns-1) + C=columns-1; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" C"); + break; + case 'd': // CVA + R = DCEvars[0]; + System.out.println("ESC [ "+DCEvars[0]+" d"); + term_state = TSTATE_DATA; + break; + case 'D': + if (DCEvars[0]==0) + C--; + else + C-=DCEvars[0]; + if (C<0) C=0; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" D"); + break; + case 'r': // DECSTBM + if (DCEvar>0) // Ray: Any argument is optional + { + R = DCEvars[1]-1; + if (R < 0) + R = rows-1; + else if (R >= rows) { + R = rows - 1; + } + } else + R = rows - 1; + display.setBottomMargin(DCEvars[1]-1); + if (R >= DCEvars[0]) + { + R = DCEvars[0]-1; + if (R < 0) + R = 0; + } + display.setTopMargin(DCEvars[0]-1); + _SetCursor(0,0); + if (debug>1) + System.out.println("ESC ["+DCEvars[0]+" ; "+DCEvars[1]+" r"); + term_state = TSTATE_DATA; + break; + case 'G': /* CUP / cursor absolute column */ + C = DCEvars[0]; + System.out.println("ESC [ "+DCEvars[0]+" G"); + term_state = TSTATE_DATA; + break; + case 'H': /* CUP / cursor position */ + /* gets 2 arguments */ + _SetCursor(DCEvars[0]-1,DCEvars[1]-1); + term_state = TSTATE_DATA; + if (debug>2) { + System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" H, originmode "+originmode); + System.out.println(" -> R now "+R+", C now "+C); + } + break; + case 'f': /* move cursor 2 */ + /* gets 2 arguments */ + R = DCEvars[0]-1; + C = DCEvars[1]-1; + if (C<0) C=0; + if (R<0) R=0; + term_state = TSTATE_DATA; + if (debug>2) + System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" f"); + break; + case 'L': + /* insert n lines */ + if (DCEvars[0]==0) + display.insertLine(R,display.SCROLL_DOWN); + else + display.insertLine(R,DCEvars[0],display.SCROLL_DOWN); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" L"); + break; + case 'M': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+"M at R="+R); + if (DCEvars[0]==0) + display.deleteLine(R); + else + for (int i=0;i1) + System.out.println("ESC [ "+DCEvars[0]+" K"); + /* clear in line */ + switch (DCEvars[0]) { + case 0:/*clear to right*/ + if (C0) + display.deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1 + break; + case 2:/*clear whole line */ + display.deleteArea(0,R,columns,1); + break; + } + term_state = TSTATE_DATA; + break; + case 'J': + /* clear display.below current line */ + switch (DCEvars[0]) { + case 0: + if (R0) + display.deleteArea(0,0,columns,R-1); + if (C>0) + display.deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1 + break; + case 2: + display.deleteArea(0,0,columns,rows); + break; + } + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" J"); + term_state = TSTATE_DATA; + break; + case '@': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" @"); + for (int i=0;i1) + System.out.println("ESC [ "+DCEvars[0]+" P, C="+C+",R="+R); + for (int i=0;i 1) + System.out.println("ESC[5n"); + break; + case 6: + host.send(((char)ESC)+"["+R+";"+C+"R"); + if(debug > 1) + System.out.println("ESC[6n"); + break; + default: + if (debug>0) + System.out.println("ESC [ "+DCEvars[0]+" n??"); + break; + } + term_state = TSTATE_DATA; + break; + case 'm': /* attributes as color, bold , blink,*/ + if (debug>1) + System.out.print("ESC [ "); + if (DCEvar == 0 && DCEvars[0] == 0) + attributes = 0; + for (i=0;i<=DCEvar;i++) { + switch (DCEvars[i]) { + case 0: + if (DCEvar>0) + attributes =0; + break; + case 4: + attributes |= CharDisplay.UNDERLINE; + break; + case 1: + attributes |= CharDisplay.BOLD; + break; + case 7: + attributes |= CharDisplay.INVERT; + break; + case 5: /* blink on */ + break; + case 25: /* blinking off */ + break; + case 27: + attributes &= ~CharDisplay.INVERT; + break; + case 24: + attributes &= ~CharDisplay.UNDERLINE; + break; + case 22: + attributes &= ~CharDisplay.BOLD; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + attributes &= ~(0xf<<3); + attributes |= ((DCEvars[i]-30)+1)<<3; + break; + case 39: + attributes &= ~(0xf<<3); + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + attributes &= ~(0xf<<7); + attributes |= ((DCEvars[i]-40)+1)<<7; + break; + case 49: + attributes &= ~(0xf<<7); + break; + + default: + System.out.println("ESC [ "+DCEvars[i]+" m unknown..."); + break; + } + if (debug>1) + System.out.print(""+DCEvars[i]+";"); + } + if (debug>1) + System.out.print(" (attributes = "+attributes+")m \n"); + term_state = TSTATE_DATA; + break; + default: + if (debug>0) + System.out.println("ESC [ unknown letter:"+c+" ("+((int)c)+")"); + term_state = TSTATE_DATA; + break; + } + break; + default: + term_state = TSTATE_DATA; + break; + } + if (C > columns) C = columns; + if (R > rows) R = rows; + if (C < 0) C = 0; + if (R < 0) R = 0; + if (doshowcursor) + display.setCursorPos(C, R); + display.markLine(R,1); + } +} diff --git a/src/de/mud/telnet/frame.java b/src/de/mud/telnet/frame.java new file mode 100644 index 0000000..74f20fd --- /dev/null +++ b/src/de/mud/telnet/frame.java @@ -0,0 +1,55 @@ +package de.mud.telnet; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * frame -- a frame subclass for handling frame events + * -- + * $Id: frame.java,v 1.1 1997/07/08 09:21:56 leo Exp $ + * $timestamp: Tue Jul 8 10:02:36 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.awt.Frame; +import java.awt.Component; +import java.awt.Event; +import java.applet.Applet; + +public class frame extends Frame +{ + public frame(String title) { super(title); } + + public boolean handleEvent(Event evt) { + if(evt.target == this && evt.id == Event.WINDOW_DESTROY) { + Component comp[] = getComponents(); + for(int i = comp.length - 1; i >= 0; i--) + if(comp[i] instanceof Applet) { + ((Applet)comp[i]).stop(); + this.dispose(); + return true; + } + } + return false; + } +} + + + diff --git a/src/de/mud/telnet/modules/ButtonBar.java b/src/de/mud/telnet/modules/ButtonBar.java new file mode 100644 index 0000000..68fc8be --- /dev/null +++ b/src/de/mud/telnet/modules/ButtonBar.java @@ -0,0 +1,389 @@ +package de.mud.telnet.modules; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/** + * ButtonBar -- a programmable button bar + * -- + * $Id: ButtonBar.java,v 1.22 1998/02/24 13:09:09 leo Exp $ + * $timestamp: Mon Aug 4 14:12:21 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +import java.applet.Applet; +import java.util.Hashtable; +import java.util.Vector; +import de.mud.telnet.*; + +import java.awt.Panel; +import java.awt.Button; +import java.awt.TextField; +import java.awt.Event; +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.Dimension; +import java.awt.Container; +import java.awt.Frame; + +/** + * This class implements a programmable button bar. + * You can add Buttons and Input + * fields to trigger actions in the telnet + * applet. On how to load a module, please refer to the + * telnet documentation. + * + *
+ * + *
Buttons: + *
<PARAM NAME=number#Button VALUE="buttontext|buttonaction"> + *
number is the sequence number and determines the place + * of the button on the row. + *

+ *

buttontext is a string displayed on the button. + *

+ *

buttonaction may be one + * of the following functions or strings
+ * (Note: the backslash character + * in front of the dollar sign is mandatory!) + *
    + *
  • simple text + * to be sent to the remote host. Newline and/or carriage return + * characters may be added in C syntax \n and \r. + * To support unimplemented function keys the \e escape + * character may be useful. The \b backspace character is + * also supported. + * The text may contain field + * reference(s). + *

    + *

  • \$connect(host[,port]) + * tries to initiate a connection to the host + * at the port, if given. The standard port is + * 23. host and port may be hostname + * and number or field + * reference(s). If a connection already exists + * nothing will happen.
    + * (Note: It is not allowed to have + * spaces anywhere inside the parenthesis!) + *

    + *

  • \$disconnect() + * terminates the current connection, but if there was no + * connection nothing will happen. + *

    + *

  • \$detach() + * detaches the applet from the web browser window and + * creates a new frame externally. This may be used to allow + * users to use the applet while browsing the web with the + * same browser window.
    + * (Note: You need to load the applet via the + * appWrapper class or + * it will not work properly!) + *
+ *
Examples:
+ * (Note: It makes sense if you look at the + * examples for input fields below.) + *
+ *        <PARAM NAME=1#Button VALUE="HELP!|help\r\n">
+ *        <PARAM NAME=2#Button VALUE="HELP:|help \@help@\r\n">
+ *        <PARAM NAME=4#Button VALUE="simple|\$connect(localhost)">
+ *        <PARAM NAME=5#Button VALUE="complete|\$connect(www,4711)">
+ *        <PARAM NAME=6#Button VALUE="connect|\$connect(\@address@)">
+ *        <PARAM NAME=8#Button VALUE="connect to port|\$connect(\@address@,\@port@)">
+ *        <PARAM NAME=10#Button VALUE="window|\$detach()">
+ *     
+ *

+ * + *

Input fields + *
<PARAM NAME=number#Input VALUE="fieldname[#length]|initial text[|action]"> + *
number is the sequence number and determines the place + * of the field on the row. + *

+ *

fieldname is a + * symbolic name to reference the input field. A reference may be used in + * button actions and + * is constructed as follows: + * \@fieldname@ + * The \@fieldname@ macro will be replaced by the string entered in + * the text field. + *

+ *

length is the length of the input field in numbers of + * characters. + *

+ *

initial text is the text to be placed into the input + * field on startup + *
action may be used similar to a + * button action. This action + * will be used if the users presses Return in the inputfield. Leave + * empty if you only want to use a button to send the text! + *
Examples:
+ * (Note: It makes sense if you look at the + * examples for buttons before.) + *
+ *        <PARAM NAME=3#Input VALUE="help#10|">
+ *        <PARAM NAME=7#Input VALUE="address|www.first.gmd.de">
+ *        <PARAM NAME=8#Input VALUE="send#5|who|\@send@\r\n">
+ *        <PARAM NAME=9#Input VALUE="port#5|4711">
+ *      
+ *

+ *

+ * @version $Id: ButtonBar.java,v 1.22 1998/02/24 13:09:09 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + * @see modules.Module + */ +public class ButtonBar extends Panel implements Module +{ + // our parent is the telnet app + private telnet parent; + + // these tables contain our buttons and fields. + private Hashtable buttons = null; + private Hashtable fields = null; + + // the top level (for detaching) + private Container toplevel; + + /** + * This method is called by our loader to notify us of it. + * @param o The object that has loaded this object. + * @see display.Module + */ + public void setLoader(Object o) { parent = (telnet)o; } + + /** + * If the applet connects this method is called. + * @param host remote hostaddress - not used + * @param port remote port - not used + */ + public void connect(String host, int port) { + // do nothing yet. + } + + /** + * Get notified of disconnection. Do nothing. + */ + public void disconnect() { + // do nothing yet + } + + /** + * This module does not take any input. It works passive. + * @return null to remove from the list of receiver modules. + * @see display.Module + */ + public String receive(String s) { return null; } + + /** + * create the buttonbar from the parameter list. We will know our parent, + * when we have been added. + */ + public void addNotify() { + if(buttons == null && fields == null) { + String tmp; + + int nr = 1; + String button = null, input = null; + while((button = parent.getParameter(nr+"#Button")) != null || + (input = parent.getParameter(nr+"#Input")) != null) { + nr++; + if(button != null) { + if(buttons == null) buttons = new Hashtable(); + int idx = button.indexOf('|'); + if(button.length() == 0) + System.out.println("ButtonBar: Button: no definition"); + if(idx < 0 || idx == 0) { + System.out.println("ButtonBar: Button: empty name \""+button+"\""); + continue; + } + if(idx == button.length() - 1) { + System.out.println("ButtonBar: Button: empty command \""+button+"\""); + continue; + } + Button b = new Button(button.substring(0, idx)); + buttons.put(b, button.substring(idx+1, button.length())); + add(b); + } else + if(input != null) { + if(fields == null) fields = new Hashtable(); + int idx = input.indexOf('|'); + if(input.length() == 0) + System.out.println("ButtonBar: Input field: no definition"); + if(idx < 0 || idx == 0) { + System.out.println("ButtonBar: Input field: empty name \""+input+"\""); + continue; + } + int si, size; + if((si = input.indexOf('#', 0)) == 0) { + System.out.println("ButtonBar: Input field: empty name"); + continue; + } + if(si < 0 || si == idx-1) size = 10; + else size = Integer.parseInt(input.substring(si+1, idx)); + TextField t = + new TextField(input.substring(idx + 1, + ((input.lastIndexOf('|') == idx) ? + input.length() : + (idx = input.lastIndexOf('|')))), + size); + buttons.put(t, input.substring(idx + 1, input.length())); + fields.put(input.substring(0, (si < 0 ? idx : si)), t); + add(t); + } + button = input = null; + } + } + super.addNotify(); + } + + public boolean handleEvent(Event evt) { + String tmp; + if(evt.id == Event.ACTION_EVENT && + (tmp = (String)buttons.get(evt.target)) != null) { + System.out.println("ButtonBar: "+tmp); + String cmd = "", function = null; + int idx = 0, oldidx = 0; + while((idx = tmp.indexOf('\\', oldidx)) >= 0 && + ++idx <= tmp.length()) { + cmd += tmp.substring(oldidx, idx-1); + switch(tmp.charAt(idx)) { + case 'b': cmd += "\b"; break; + case 'e': cmd += ""; break; + case 'n': cmd += "\n"; break; + case 'r': cmd += "\r"; break; + case '$': { + int ni = tmp.indexOf('(', idx+1); + if(ni < idx) { + System.out.println("ERROR: Function: missing '('"); + break; + } + if(ni == ++idx) { + System.out.println("ERROR: Function: missing name"); + break; + } + function = tmp.substring(idx, ni); + idx = ni+1; + ni = tmp.indexOf(')', idx); + if(ni < idx) { + System.out.println("ERROR: Function: missing ')'"); + break; + } + tmp = tmp.substring(idx, ni); + idx = oldidx = 0; + continue; + } + case '@': { + int ni = tmp.indexOf('@', idx+1); + if(ni < idx) { + System.out.println("ERROR: Input Field: '@'-End Marker not found"); + break; + } + if(ni == ++idx) { + System.out.println("ERROR: Input Field: no name specified"); + break; + } + String name = tmp.substring(idx, ni); + idx = ni; + TextField t; + if(fields == null || (t = (TextField)fields.get(name)) == null) { + System.out.println("ERROR: Input Field: requested input \""+ + name+"\" does not exist"); + break; + } + cmd += t.getText(); + t.setText(""); + break; + } + default : cmd += tmp.substring(idx, ++idx); + } + oldidx = ++idx; + } + + if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx, tmp.length()); + + if(function != null) { + if(function.equals("exit")) { + try { + System.exit(0); + } catch(Exception e) { e.printStackTrace(); } + } + if(function.equals("connect")) { + String address = null; + int port = -1; + try { + if((idx = cmd.indexOf(",")) >= 0) { + try { + port = Integer.parseInt(cmd.substring(idx+1, cmd.length())); + } catch(Exception e) { + port = -1; + } + cmd = cmd.substring(0, idx); + } + if(cmd.length() > 0) address = cmd; + if(address != null) + if(port != -1) parent.connect(address, port); + else parent.connect(address); + else parent.connect(); + } catch(Exception e) { + System.err.println("ButtonBar: connect(): failed"); + e.printStackTrace(); + } + } else + if(function.equals("disconnect") && parent.disconnect()) + parent.send("\r\nClosed connection.\r\n"); + else + if(function.equals("detach")) { + if(parent.getParent() instanceof Frame) { + Frame top = (Frame)parent.getParent(); + if(toplevel != null) { + System.out.println("ButtonBar: reattaching applet..."); + toplevel.setLayout(new BorderLayout()); + toplevel.add("Center", parent); + toplevel.validate(); + toplevel.layout(); + toplevel = null; + } else { + System.out.println("ButtonBar: destroying window..."); + parent.disconnect(); + } + top.dispose(); + } else { + System.out.println("ButtonBar: detaching applet..."); + toplevel = parent.getParent(); + frame top = new frame("The Java Telnet Applet"); + Dimension s = parent.size(); + top.reshape(0, 0, s.width, s.height); + top.setLayout(new BorderLayout()); + top.add("Center", parent); + top.pack(); + top.show(); + } + } + else + System.out.println("ERROR: function not implemented: \""+ + function+"\""); + return true; + } + // cmd += tmp.substring(oldidx, tmp.length()); + if(cmd.length() > 0) parent.send(cmd); + return true; + } + return false; + } +} + diff --git a/src/de/mud/telnet/modules/Module.java b/src/de/mud/telnet/modules/Module.java new file mode 100644 index 0000000..61e15c4 --- /dev/null +++ b/src/de/mud/telnet/modules/Module.java @@ -0,0 +1,64 @@ +package de.mud.telnet.modules; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +/** + * Module -- Module interface + * -- + * $Id: Module.java,v 1.3 1997/03/24 14:55:18 leo Exp $ + * $timestamp: Mon Mar 24 15:35:13 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * Modules must implement this interface to be detected as valid modules + * @version $Id: Module.java,v 1.3 1997/03/24 14:55:18 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface Module +{ + /** + * Set the loader of the module. This is necessary to know if you want to + * contact the modules parent. + * @param loader The object that has loaded this module. + */ + public void setLoader(Object loader); + + /** + * Connected to the remote host. This method notifies upon new connection. + * @param host remote hostname + * @param port remote port + */ + public void connect(String host, int port); + + /** + * Disconnect from the host. This method notifies of lost connection. + */ + public void disconnect(); + + /** + * Receive data from somewhere. If a modules does not want to receive data + * it should return null to remove itself from the list of receiver modules. + * @param s The string we receive. + * @return the modified string or null (to remove from receiver list) + */ + public String receive(String s); +} + diff --git a/src/de/mud/telnet/modules/Script.java b/src/de/mud/telnet/modules/Script.java new file mode 100644 index 0000000..a255f14 --- /dev/null +++ b/src/de/mud/telnet/modules/Script.java @@ -0,0 +1,181 @@ +package de.mud.telnet.modules; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * Script -- A module for scripting (very simple). + * -- + * $Id: Script.java,v 1.6 1997/11/03 10:25:57 leo Exp $ + * $timestamp: Mon Mar 24 15:52:12 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import de.mud.telnet.*; +import java.util.Hashtable; +import java.util.Enumeration; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.Label; +import java.awt.Event; + +/** + * A very simple scripting module. It takes pairs of pattern and text and + * sends the corresponding text when the pattern matches. Each pattern is + * only matched once per connected session. + * + *
+ *
Scripts: + *
<PARAM NAME=script VALUE="pattern|text|...">
+ *
A script contains of pairs of pattern and text strings. + * If the pattern is matched against the output from the remote host, + * the corresponding text will be sent. Each pattern will match only + * once per session. A session is defined by connect and + * disconnect.

+ * Thus it is possible to program an autologin as follows:
+ *

"login:|leo|Password:|mypassword|leo@www|ls"
+ * Newlines will be added automatically to the string sent! At the + * moment the order of the pattern and text pairs is not relevant. + *

+ * It is possible to prompt the user for input if a match occurs. If the + * corresponding text is a string enclosed in braces ([] or {}) a + * dialog window is opened with text as prompt. A special case + * is an empty prompt in which case the pattern will be shown as + * prompt. "[Your name:]" would open a dialog window with the + * text "Your name" as prompt. Curly braces have a special + * meaning; any user input will be shown as "*" which makes + * it possible to program password prompts. Example: + * "{Your password:}".

+ * A special match like: "login:|[]" can be used to open a + * dialog and display "login:" as prompt. This works for + * "{}" as well. + * + *

+ * @version $Id: Script.java,v 1.6 1997/11/03 10:25:57 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + * @see modules.Module + */ +public class Script extends Hashtable implements Module +{ + // This is the target for any text we want to send + private telnet applet = null; + + /** + * Set the applet as module loader + * @param o the object that is the applet (must be an Applet) + * @see module.Module + * @see java.applet.Applet + */ + public void setLoader(Object o) { applet = (telnet)o; } + + /** + * Configure the script module by reading the script PARAMeter. + * @param host remote hostaddress - not used + * @param port remote port - not used + */ + public void connect(String host, int port) { + String tmp = applet.getParameter("script"); + + // delete all entries + clear(); + + if(tmp != null) { + int idx = tmp.indexOf('|'); + int oldidx = 0; + while(idx >= 0) { + String match = tmp.substring(oldidx, idx); + oldidx = idx; + idx = tmp.indexOf('|', idx+1); + idx = idx < 0 ? idx = tmp.length() : idx; + String send = tmp.substring(oldidx+1, idx); + put(match, send); + oldidx = idx+1; + idx = tmp.indexOf('|', idx+1); + } + } + } + + /** + * Get notified of disconnection. Do nothing. + */ + public void disconnect() {} + + /** + * This method is called when data is received. It tries to match the + * input to the list of patterns and sends corresponding text on success. + * If the response is [] or {} the user will be prompted with the matching + * text. You can modify the prompt string by entering it inside of the + * brackets or curly braces (e.g. [Enter your id:]). In case of curly + * braces the input area will not show the typed in text (for passwords)! + * + * @param s The string to test. + * @see peer.InputPeer + */ + public String receive(String s) { + if(isEmpty()) return s; + Enumeration match = keys(); + while(match.hasMoreElements()) { + String key = (String)match.nextElement(); + if(s.indexOf(key) != -1) { + String value = (String)get(key); + if(value.indexOf("[") == 0 || value.indexOf("{") == 0) { + TextField input = new TextField(20); + if(value.startsWith("{")) input.setEchoCharacter('*'); + if("[]".equals(value) || "{}".equals(value)) value = key; + else value = value.substring(1, value.length() - 1); + Thread current = Thread.currentThread(); + new UserDialog(new Frame(), value, false, current, input); + current.suspend(); + value = input.getText(); + } + applet.send(value + "\r"); + remove(key); + } + } + return s; + } +static class UserDialog extends Dialog { + TextField input; + Thread thread; + String value; + + public UserDialog(Frame parent, String value, boolean modal, + Thread t, TextField reply) { + super(parent, value, modal); + thread = t; input = reply; + add("West", new Label(value)); + add("Center", input); + pack(); + show(); + } + + public boolean handleEvent(Event evt) { + if(evt.target == input && evt.key == 10) { + thread.resume(); + hide(); dispose(); + return true; + } + return false; + } +} + +} + diff --git a/src/de/mud/telnet/modules/TextLabel.java b/src/de/mud/telnet/modules/TextLabel.java new file mode 100644 index 0000000..2fb57f4 --- /dev/null +++ b/src/de/mud/telnet/modules/TextLabel.java @@ -0,0 +1,113 @@ +package de.mud.telnet.modules; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * TextLabel -- A module to display a Label on the applet. + * -- + * $Id: TextLabel.java,v 1.1 1997/07/09 20:12:05 leo Exp $ + * $timestamp: Wed Jul 9 17:37:28 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import de.mud.telnet.*; +import java.awt.Panel; +import java.awt.Label; +import java.awt.GridLayout; +import java.awt.Font; + +/** + * This small module lets you display text somewhere in the applets area. + * + *
+ *
Label: + *
<PARAM NAME=labelRows    VALUE="rows">
+ *
Defines the how many rows the label will have. + *
<PARAM NAME=labelCols    VALUE="cols">
+ *
Defines the how many columns the label will have. + *
<PARAM NAME=labelFont    VALUE="font[,size]">
+ *
The font for displaying the label text. If the size is left out + * a standard size of 14 points is assumed. + *
<PARAM NAME=label#number VALUE="text">
+ *
The labels are enumerated and displayed in rows and columns. + *
+ * @version $Id: TextLabel.java,v 1.1 1997/07/09 20:12:05 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + * @see modules.Module + */ +public class TextLabel extends Panel implements Module +{ + telnet applet; + + /** + * Set the applet as module loader and configure. + * @param o the object that is the applet (must be an Applet) + * @see module.Module + * @see java.applet.Applet + */ + public void setLoader(Object o) { + applet = (telnet)o; + + int rows = 1, cols = 1; + + String tmp = applet.getParameter("labelRows"); + if(tmp != null) rows = Integer.parseInt(tmp); + if((tmp = applet.getParameter("labelCols")) != null) + cols = Integer.parseInt(tmp); + + setLayout(new GridLayout(rows, cols)); + + Font labelFont = null; + if((tmp = applet.getParameter("labelFont")) != null) { + int idx = tmp.indexOf(","); + int size = 14; + if(idx != -1) size = Integer.parseInt(tmp.substring(idx+1)); + labelFont = new Font(tmp, Font.PLAIN, size); + } + + int no = 1; + while((tmp = applet.getParameter("label#"+no++)) != null) { + Label text = new Label(tmp); + if(labelFont != null) text.setFont(labelFont); + add(text); + } + } + + /** + * Do nothing upon connect. + * @param host remote hostaddress - not used + * @param port remote port - not used + */ + public void connect(String host, int port) {} + + /** + * Do nothing upon disconnecton. + */ + public void disconnect() {} + + /** + * Do nothing when receiving text. Be removed upon first call. + * @param s The string received. + * @see peer.InputPeer + */ + public String receive(String s) { return null; } +} + diff --git a/src/de/mud/telnet/socket/StatusPeer.java b/src/de/mud/telnet/socket/StatusPeer.java new file mode 100644 index 0000000..782de56 --- /dev/null +++ b/src/de/mud/telnet/socket/StatusPeer.java @@ -0,0 +1,51 @@ +package de.mud.telnet.socket; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * Status peer interface. + * -- + * $Id: StatusPeer.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * $timestamp: Wed Mar 5 13:40:54 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.util.Vector; + +/** + * StatusPeer -- interface for status messages + * -- + * @version $Id: StatusPeer.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ + +public interface StatusPeer +{ + /** + * This method is called for the peer of the TelnetIO class if there is + * a statuschange. + * @param status A Vector containing the key as element 0 and any arguments + * from element 1 on. + * @return an object that matches the requested information or null + * @see socket.TelnetIO + */ + public Object notifyStatus(Vector status); +} diff --git a/src/de/mud/telnet/socket/TelnetIO.java b/src/de/mud/telnet/socket/TelnetIO.java new file mode 100644 index 0000000..7ad09e8 --- /dev/null +++ b/src/de/mud/telnet/socket/TelnetIO.java @@ -0,0 +1,618 @@ +package de.mud.telnet.socket; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * socket.TelnetIO - a telnet implementation + * -- + * $Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $ + * $timestamp: Tue May 27 13:27:05 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.net.Socket; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.awt.Dimension; +import java.util.Vector; + +/** + * Implements simple telnet io + * + * @version $Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + * @version 1.2 3/7/97 George Ruban added available() because it was needed. + */ +public class TelnetIO implements StatusPeer +{ + /** + * Return the version of TelnetIO. + */ + public String toString() { return "$Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $"; } + + /** + * Debug level. This results in additional diagnostic messages on the + * java console. + */ + private static int debug = 0; + + /** + * State variable for telnetnegotiation reader + */ + private byte neg_state = 0; + + /** + * constants for the negotiation state + */ + private final static byte STATE_DATA = 0; + private final static byte STATE_IAC = 1; + private final static byte STATE_IACSB = 2; + private final static byte STATE_IACWILL = 3; + private final static byte STATE_IACDO = 4; + private final static byte STATE_IACWONT = 5; + private final static byte STATE_IACDONT = 6; + private final static byte STATE_IACSBIAC = 7; + private final static byte STATE_IACSBDATA = 8; + private final static byte STATE_IACSBDATAIAC = 9; + + /** + * What IAC SB we are handling right now + */ + private byte current_sb; + + /** + * IAC - init sequence for telnet negotiation. + */ + private final static byte IAC = (byte)255; + /** + * [IAC] End Of Record + */ + private final static byte EOR = (byte)239; + /** + * [IAC] WILL + */ + private final static byte WILL = (byte)251; + /** + * [IAC] WONT + */ + private final static byte WONT = (byte)252; + /** + * [IAC] DO + */ + private final static byte DO = (byte)253; + /** + * [IAC] DONT + */ + private final static byte DONT = (byte)254; + /** + * [IAC] Sub Begin + */ + private final static byte SB = (byte)250; + /** + * [IAC] Sub End + */ + private final static byte SE = (byte)240; + /** + * Telnet option: echo text + */ + private final static byte TELOPT_ECHO = (byte)1; /* echo on/off */ + /** + * Telnet option: End Of Record + */ + private final static byte TELOPT_EOR = (byte)25; /* end of record */ + /** + * Telnet option: Negotiate About Window Size + */ + private final static byte TELOPT_NAWS = (byte)31; /* NA-WindowSize*/ + /** + * Telnet option: Terminal Type + */ + private final static byte TELOPT_TTYPE = (byte)24; /* terminal type */ + + private final static byte[] IACWILL = { IAC, WILL }; + private final static byte[] IACWONT = { IAC, WONT }; + private final static byte[] IACDO = { IAC, DO }; + private final static byte[] IACDONT = { IAC, DONT }; + private final static byte[] IACSB = { IAC, SB }; + private final static byte[] IACSE = { IAC, SE }; + + /** + * Telnet option qualifier 'IS' + */ + private final static byte TELQUAL_IS = (byte)0; + + /** + * Telnet option qualifier 'SEND' + */ + private final static byte TELQUAL_SEND = (byte)1; + + /** + * What IAC DO(NT) request do we have received already ? + */ + private byte[] receivedDX; + + /** + * What IAC WILL/WONT request do we have received already ? + */ + private byte[] receivedWX; + /** + * What IAC DO/DONT request do we have sent already ? + */ + private byte[] sentDX; + /** + * What IAC WILL/WONT request do we have sent already ? + */ + private byte[] sentWX; + + private Socket socket; + private BufferedInputStream is; + private BufferedOutputStream os; + + private StatusPeer peer = this; /* peer, notified on status */ + + /** + * Connect to the remote host at the specified port. + * @param address the symbolic host address + * @param port the numeric port + * @see #disconnect + */ + public void connect(String address, int port) throws IOException { + if(debug > 0) System.out.println("Telnet.connect("+address+","+port+")"); + socket = new Socket(address, port); + is = new BufferedInputStream(socket.getInputStream()); + os = new BufferedOutputStream(socket.getOutputStream()); + neg_state = 0; + receivedDX = new byte[256]; + sentDX = new byte[256]; + receivedWX = new byte[256]; + sentWX = new byte[256]; + } + + /** + * Disconnect from remote host. + * @see #connect + */ + public void disconnect() throws IOException { + if(debug > 0) System.out.println("TelnetIO.disconnect()"); + if(socket !=null) socket.close(); + } + + /** + * Connect to the remote host at the default telnet port (23). + * @param address the symbolic host address + */ + public void connect(String address) throws IOException { + connect(address, 23); + } + + /** + * Set the object to be notified about current status. + * @param obj object to be notified. + */ + public void setPeer(StatusPeer obj) { peer = obj; } + + /** Returns bytes available to be read. Since they haven't been + * negotiated over, this could be misleading. + * Most useful as a boolean value - "are any bytes available" - + * rather than as an exact count of "how many ara available." + * + * @exception IOException on problems with the socket connection + */ + public int available() throws IOException + { + return is.available(); + } + + + /** + * Read data from the remote host. Blocks until data is available. + * Returns an array of bytes. + * @see #send + */ + public byte[] receive() throws IOException { + int count = is.available(); + byte buf[] = new byte[count]; + count = is.read(buf); + if(count < 0) throw new IOException("Connection closed."); + if(debug > 1) System.out.println("TelnetIO.receive(): read bytes: "+count); + buf = negotiate(buf, count); + return buf; + } + + /** + * Send data to the remote host. + * @param buf array of bytes to send + * @see #receive + */ + public void send(byte[] buf) throws IOException { + if(debug > 1) System.out.println("TelnetIO.send("+buf+")"); + os.write(buf); + os.flush(); + } + + public void send(byte b) throws IOException { + if(debug > 1) System.out.println("TelnetIO.send("+b+")"); + os.write(b); + os.flush(); + } + + /** + * Handle an incoming IAC SB IAC SE + * @param type type of SB + * @param sbata byte array as + * @param sbcount nr of bytes. may be 0 too. + */ + private void handle_sb(byte type, byte[] sbdata, int sbcount) + throws IOException + { + if(debug > 1) + System.out.println("TelnetIO.handle_sb("+type+")"); + switch (type) { + case TELOPT_TTYPE: + if (sbcount>0 && sbdata[0]==TELQUAL_SEND) { + String ttype; + send(IACSB);send(TELOPT_TTYPE);send(TELQUAL_IS); + /* FIXME: need more logic here if we use + * more than one terminal type + */ + Vector vec = new Vector(2); + vec.addElement("TTYPE"); + ttype = (String)peer.notifyStatus(vec); + if(ttype == null) ttype = "dumb"; + byte[] bttype = new byte[ttype.length()]; + + ttype.getBytes(0,ttype.length(), bttype, 0); + send(bttype); + send(IACSE); + } + + } + } + + /** + * Notify about current telnet status. This method is called top-down. + * @param status contains status information + */ + public Object notifyStatus(Vector status) { + if(debug > 0) + System.out.println("TelnetIO.notifyStatus("+status+")"); + return null; + } + + /* wo faengt buf an bei buf[0] oder bei buf[1] */ + private byte[] negotiate(byte buf[], int count) throws IOException { + if(debug > 1) + System.out.println("TelnetIO.negotiate("+buf+","+count+")"); + byte nbuf[] = new byte[count]; + byte sbbuf[] = new byte[count]; + byte sendbuf[] = new byte[3]; + byte b,reply; + int sbcount = 0; + int boffset = 0, noffset = 0; + Vector vec = new Vector(2); + + while(boffset < count) { + b=buf[boffset++]; + /* of course, byte is a signed entity (-128 -> 127) + * but apparently the SGI Netscape 3.0 doesn't seem + * to care and provides happily values up to 255 + */ + if (b>=128) + b=(byte)((int)b-256); + switch (neg_state) { + case STATE_DATA: + if (b==IAC) { + neg_state = STATE_IAC; + } else { + nbuf[noffset++]=b; + } + break; + case STATE_IAC: + switch (b) { + case IAC: + if(debug > 2) + System.out.print("IAC "); + neg_state = STATE_DATA; + nbuf[noffset++]=IAC; + break; + case WILL: + if(debug > 2) + System.out.print("WILL "); + neg_state = STATE_IACWILL; + break; + case WONT: + if(debug > 2) + System.out.print("WONT "); + neg_state = STATE_IACWONT; + break; + case DONT: + if(debug > 2) + System.out.print("DONT "); + neg_state = STATE_IACDONT; + break; + case DO: + if(debug > 2) + System.out.print("DO "); + neg_state = STATE_IACDO; + break; + case EOR: + if(debug > 2) + System.out.print("EOR "); + neg_state = STATE_DATA; + break; + case SB: + if(debug > 2) + System.out.print("SB "); + neg_state = STATE_IACSB; + sbcount = 0; + break; + default: + if(debug > 2) + System.out.print( + " " + ); + neg_state = STATE_DATA; + break; + } + break; + case STATE_IACWILL: + switch(b) { + case TELOPT_ECHO: + if(debug > 2) + System.out.println("ECHO"); + reply = DO; + vec = new Vector(2); + vec.addElement("NOLOCALECHO"); + peer.notifyStatus(vec); + break; + case TELOPT_EOR: + if(debug > 2) + System.out.println("EOR"); + reply = DO; + break; + default: + if(debug > 2) + System.out.println( + "" + ); + reply = DONT; + break; + } + if(debug > 1) + System.out.println("<"+b+", WILL ="+WILL+">"); + if ( reply != sentDX[b+128] || + WILL != receivedWX[b+128] + ) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + send(sendbuf); + sentDX[b+128] = reply; + receivedWX[b+128] = WILL; + } + neg_state = STATE_DATA; + break; + case STATE_IACWONT: + switch(b) { + case TELOPT_ECHO: + if(debug > 2) + System.out.println("ECHO"); + + vec = new Vector(2); + vec.addElement("LOCALECHO"); + peer.notifyStatus(vec); + reply = DONT; + break; + case TELOPT_EOR: + if(debug > 2) + System.out.println("EOR"); + reply = DONT; + break; + default: + if(debug > 2) + System.out.println( + "" + ); + reply = DONT; + break; + } + if ( reply != sentDX[b+128] || + WONT != receivedWX[b+128] + ) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + send(sendbuf); + sentDX[b+128] = reply; + receivedWX[b+128] = WILL; + } + neg_state = STATE_DATA; + break; + case STATE_IACDO: + switch (b) { + case TELOPT_ECHO: + if(debug > 2) + System.out.println("ECHO"); + reply = WILL; + vec = new Vector(2); + vec.addElement("LOCALECHO"); + peer.notifyStatus(vec); + break; + case TELOPT_TTYPE: + if(debug > 2) + System.out.println("TTYPE"); + reply = WILL; + break; + case TELOPT_NAWS: + if(debug > 2) + System.out.println("NAWS"); + vec = new Vector(2); + vec.addElement("NAWS"); + Dimension size = (Dimension) + peer.notifyStatus(vec); + receivedDX[b] = DO; + if(size == null) + { + /* this shouldn't happen */ + send(IAC); + send(WONT); + send(TELOPT_NAWS); + reply = WONT; + sentWX[b] = WONT; + break; + } + reply = WILL; + sentWX[b] = WILL; + sendbuf[0]=IAC; + sendbuf[1]=WILL; + sendbuf[2]=TELOPT_NAWS; + send(sendbuf); + send(IAC);send(SB);send(TELOPT_NAWS); + send((byte) (size.width >> 8)); + send((byte) (size.width & 0xff)); + send((byte) (size.height >> 8)); + send((byte) (size.height & 0xff)); + send(IAC);send(SE); + break; + default: + if(debug > 2) + System.out.println( + "" + ); + reply = WONT; + break; + } + if ( reply != sentWX[128+b] || + DO != receivedDX[128+b] + ) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + send(sendbuf); + sentWX[b+128] = reply; + receivedDX[b+128] = DO; + } + neg_state = STATE_DATA; + break; + case STATE_IACDONT: + switch (b) { + case TELOPT_ECHO: + if(debug > 2) + System.out.println("ECHO"); + reply = WONT; + vec = new Vector(2); + vec.addElement("NOLOCALECHO"); + peer.notifyStatus(vec); + break; + case TELOPT_NAWS: + if(debug > 2) + System.out.println("NAWS"); + reply = WONT; + break; + default: + if(debug > 2) + System.out.println( + "" + ); + reply = WONT; + break; + } + if ( reply != sentWX[b+128] || + DONT != receivedDX[b+128] + ) { + send(IAC);send(reply);send(b); + sentWX[b+128] = reply; + receivedDX[b+128] = DONT; + } + neg_state = STATE_DATA; + break; + case STATE_IACSBIAC: + if(debug > 2) System.out.println(""+b+" "); + if (b == IAC) { + sbcount = 0; + current_sb = b; + neg_state = STATE_IACSBDATA; + } else { + System.out.println("(bad) "+b+" "); + neg_state = STATE_DATA; + } + break; + case STATE_IACSB: + if(debug > 2) System.out.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBIAC; + break; + default: + current_sb = b; + sbcount = 0; + neg_state = STATE_IACSBDATA; + break; + } + break; + case STATE_IACSBDATA: + if (debug > 2) System.out.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBDATAIAC; + break; + default: + sbbuf[sbcount++] = b; + break; + } + break; + case STATE_IACSBDATAIAC: + if (debug > 2) System.out.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBDATA; + sbbuf[sbcount++] = IAC; + break; + case SE: + handle_sb(current_sb,sbbuf,sbcount); + current_sb = 0; + neg_state = STATE_DATA; + break; + case SB: + handle_sb(current_sb,sbbuf,sbcount); + neg_state = STATE_IACSB; + break; + default: + neg_state = STATE_DATA; + break; + } + break; + default: + if (debug > 2) + System.out.println( + "This should not happen: "+ + neg_state+" " + ); + neg_state = STATE_DATA; + break; + } + } + buf = new byte[noffset]; + System.arraycopy(nbuf, 0, buf, 0, noffset); + return buf; + } +} diff --git a/src/de/mud/telnet/socket/TelnetWrapper.java b/src/de/mud/telnet/socket/TelnetWrapper.java new file mode 100644 index 0000000..adec69c --- /dev/null +++ b/src/de/mud/telnet/socket/TelnetWrapper.java @@ -0,0 +1,400 @@ +package de.mud.telnet.socket; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +import java.io.IOException; +import java.util.Date; + +/** Wrapper for a Java Telnet call. + * To use, make a new TelnetWrapper() with the name or IP address of a host. + * Then, for most uses, the easiest way is to call setPrompt() with the + * expected prompt, then call login(), and a sequence of sendLine()'s + * until you get what you want done. + *

+ * If you don't know the prompt ahead of time, you have to do a sequence of + * send() and wait() or receiveUntil() calls. send() sends a string across + * the telnet connection. Add a '\r' to the end if you want to + * complete a command. wait() waits for an exact string from the other side + * of the telnet connection, and returns nothing, + * receiveUntil() also waits for a string, but returns all the data + * that it received while waiting, including the string itself. + * Use this if you want the output from a command. Please note that + * the telnet connection will usually echo the sent command. + *

+ * sendLine() is generally better, since it adds the '\r' + * automatically, waits for the prompt before returning, and returns all + * data received before the prompt, with the prompt itself cut off the + * end, and the sent command cut off the beginning. login() and + * sendLine() are implemented using send(), wait() and receiveUntil(). + * They can be freely mixed and matched. + *

+ * Here is a simple example of the use of TelnetWrapper: + *

+ * // creates a new file in /tmp, lists the directory to prove it done
+ * {
+ *   TelnetWrapper telnet = new TelnetWrapper("123.45.78.90");
+ *
+ *   // setting the correct prompt ahead of time is very important 
+ *   // if you want to use login and sendLine
+ *   telnet.setPrompt("$ ");
+ *   telnet.login("loginname", "password");
+ *
+ *   // this is how you have to do it otherwise
+ *   telnet.send("touch /tmp/TELNET_WRAPPER" + "\r");
+ *   telnet.wait("$ ");
+ *
+ *   // sendLine 1: adds the \r automatically, 2: waits for the prompt
+ *   // before returning 3: returns what was printed from the command
+ *   String ls = telnet.sendLine("ls /tmp");
+ *   System.out.println(ls);
+ *
+ *   // clean up
+ *   telnet.disconnect();
+ * } 
+ * 
+ * @author George Ruban 3/4/97 + * @version 0.2 5/15/97 - added comments, replaced String += with + * StringBuffer.append() in receiveUntil(), added port constructor + * @version 0.3 7/30/97 - added optional timeout to receiveUntil() and wait() + * @see TelnetIO + */ +public class TelnetWrapper +{ + /** The telnet connection. That which is wrapped. */ + TelnetIO tio; + /** Set to true for System.out.println debugging. */ + public boolean debug = false; + /** The current prompt on the remote system. */ + private String prompt; + + /** The default prompt used by all TelnetWrappers unless specifically + * overridden. + * @see #setPrompt + */ + private static String defaultPrompt = "$ "; + + /** The default login name used by TelnetWrappers. + * If defaultLogin and defaultPassword are both non-null + * when a TelnetWrapper is created, the TelnetWrapper will attempt + * to login. + */ + private static String defaultLogin = null; + + /** The default password used by TelnetWrappers. + * If defaultLogin and defaultPassword are both non-null + * when a TelnetWrapper is created, the TelnetWrapper will attempt + * to login. + */ + private static String defaultPassword = null; + + /** Skip any received data until the token appears. + * More efficient than receiveUntil, but liable to fail on large + * tokens that can be spread over several "send"s. In that case, + * consider using receiveUntil and ignoring the return value. + * @param token String to wait for + * @exception IOException on problems with the socket connection + * @see #receiveUntil + */ + public void wait(String token) throws IOException + { + wait(token, -1); + } + + /** Wait for a String or a timeout. + * If time runs out, throws a TimedOutException. + * Sleeps in intervals of 100 milliseconds until either receiving the + * token or timeout. + *

+ * More efficient than receiveUntil, but liable to fail on large + * tokens that can be spread over several "send"s. In that case, + * consider using receiveUntil and ignoring the return value. + * @param token String to wait for + * @param timeout time in milliseconds to wait (negative means wait forever) + * @exception IOException on problems with the socket connection + * @exception TimedOutException if time runs out before token received + * @see #receiveUntil(String, long) + */ + public void wait(String token, long timeout) + throws IOException, TimedOutException + { + if(debug) System.out.println("wait(" + token + ", " + timeout + ")..."); + String tmp = ""; + long deadline = 0; + if(timeout >= 0) + deadline = new Date().getTime() + timeout; + + do { + if(timeout >= 0) + { + while(available() <= 0) + { + if(new Date().getTime() > deadline) + throw new TimedOutException(); + try{ + Thread.currentThread().sleep(100); + } + catch(InterruptedException ignored) + {} + } + } + tmp = receive(); + } while(tmp.indexOf(token) == -1); + if(debug) System.out.println("wait(" + token + ", " + timeout + + ") successful."); + } + + /** Returns bytes available to be read. Since they haven't been + * negotiated over, this could be misleading... + */ + public int available() throws IOException + { + return tio.available(); + } + + /** Returns a String from the telnet connection. Blocks + * until one is available. No guarantees that the string is in + * any way complete. + * NOTE: uses Java 1.0.2 style String-bytes conversion.*/ + public String receive() throws IOException + { + String s = new String(receiveBytes(), 0); + if(debug) System.out.println(s); + return s; + } + + /** Returns a byte array. Blocks until data is available. */ + public byte[] receiveBytes() throws IOException + { + return tio.receive(); + } + + /** Returns all data received up until a certain token. + * @param token String to wait for + * @exception IOException on problems with the socket connection + * @see #wait + */ + public String receiveUntil(String token) throws IOException + { + return receiveUntil(token, -1); + } + + + /** Returns all data received up until a certain token. + * @param token String to wait for + * @param timeout time in milliseconds to wait (negative means wait forever) + * @exception IOException on problems with the socket connection + * @exception TimedOutException if time runs out before token received + * @see #wait(String, long) + */ + public String receiveUntil(String token, long timeout) + throws IOException, TimedOutException + { + StringBuffer buf = new StringBuffer(); + long deadline = 0; + if(timeout >= 0) + deadline = new Date().getTime() + timeout; + do + { + if(timeout >= 0) + { + while(available() <= 0) + { + if(new Date().getTime() > deadline) + throw new TimedOutException(); + try{ + Thread.currentThread().sleep(100); + } + catch(InterruptedException ignored) + {} + } + } + buf.append(receive()); + } while(buf.toString().indexOf(token) == -1); + return buf.toString(); + } + + /** Sends a String to the remote host. + * NOTE: uses Java 1.0.2 style String-bytes conversion. + * @exception IOException on problems with the socket connection + */ + public void send(String s) throws IOException + { + if(debug) System.out.println(s); + byte[] buf = new byte[s.length()]; + s.getBytes(0, buf.length, buf, 0); + tio.send(buf); + } + + /** Sends a line to the remote host, returns all data before the prompt. + * Since telnet seems to rely on carriage returns ('\r'), + * one will be appended to the sent string, if necessary. + * @param command command line to send + * @return whatever data the command produced before the prompt. + * @see #setPrompt + */ + public String sendLine(String command) throws IOException + { + if(command.charAt(command.length() -1) != '\r') + command += "\r"; + send(command); + String s = receiveUntil(prompt); + + // telnet typically echoes the command with a \r\n ending... + return s.substring(command.length() + 1, s.indexOf(prompt)); + } + + /** Sends bytes over the telnet connection. */ + public void send(byte[] buf) throws IOException + { + tio.send(buf); + } + + /** Logs in as a particular user and password. + * Returns after receiving prompt. */ + public void login(String loginName, String password) throws IOException + { + wait("login:"); + send(loginName + "\r"); + wait("Password:"); + sendLine(password + "\r"); + } + + /** Connects to the default telnet port on the given host. + * If the defaultLogin and defaultPassword are non-null, attempts login. */ + public TelnetWrapper(String host) throws IOException + { + tio = new TelnetIO(); + setPrompt(defaultPrompt); + tio.connect(host); + if(defaultLogin != null && defaultPassword != null) + { + login(defaultLogin, defaultPassword); + } + } + + /** Connects to a specific telnet port on the given host. + * If the defaultLogin and defaultPassword are non-null, attempts login. */ + public TelnetWrapper(String host, int port) throws IOException + { + tio = new TelnetIO(); + setPrompt(defaultPrompt); + tio.connect(host, port); + if(defaultLogin != null && defaultPassword != null) + { + login(defaultLogin, defaultPassword); + } + } + + /** Sets the expected prompt. + * If this function is not explicitly called, the default prompt is used. + * @see #setDefaultPrompt + */ + public void setPrompt(String prompt) + { + if(prompt == null) throw new IllegalArgumentException("null prompt."); + this.prompt = prompt; + } + + /** Sets the default prompt used by all TelnetWrappers. + * This can be specifically overridden for a specific instance. + * The default prompt starts out as "$ " until this function is called. + * @see #setPrompt + */ + public static void setDefaultPrompt(String prompt) + { + if(prompt == null) throw new IllegalArgumentException("null prompt."); + defaultPrompt = prompt; + } + + /** Sets the default login used by TelnetWrappers. + * If this method is called with non-null login and password, + * all TelnetWrappers will attempt to login when first created. + * @param login login name to use + * @param password password to use + * @see #login + * @see #unsetLogin + */ + public static void setLogin(String login, String password) + { + if(login == null || password == null) + throw new IllegalArgumentException("null login or password."); + defaultLogin = login; + defaultPassword = password; + } + + + /** Turns off the default login of TelnetWrappers. + * After this method is called, TelnetWrappers will not + * login until that method is explicitly called. + * @see #setLogin + * @see #login + */ + public static void unsetLogin() + { + defaultLogin = defaultPassword = null; + } + + /** Ends the telnet connection. */ + public void disconnect() throws IOException + { + if(tio != null) tio.disconnect(); + tio = null; + } + + /** Ends the telnet connection. */ + public void finalize() + { + try + { + disconnect(); + } + catch(IOException e) + {} // after all, what can be done at this point? + } + + /** Telnet test driver. + * Modeled after the IOtest.java example in the Telnet Applet. + * Logs in to "host", creates a timestamped file in /tmp, lists the + * /tmp directory to System.out, disconnects. Shows off several + * TelnetWrapper methods. + * @param args host login password prompt + */ + public static void main(String args[]) throws IOException + { + if(args.length != 4) throw new + IllegalArgumentException("Usage: TelnetWrapper host login password prompt"); + + String host = args[0]; + String login = args[1]; + String password = args[2]; + String prompt = args[3]; + + Date now = new Date(); + String timestamp = now.getYear() + "-" + + (now.getMonth()+1) + "-" + now.getDate() + "-" + + now.getHours() + ":" + now.getMinutes() + ":" + + now.getSeconds(); + TelnetWrapper telnet = new TelnetWrapper(host); + telnet.debug = true; + + // setting the correct prompt ahead of time is very important + // if you want to use login and sendLine + telnet.setPrompt(prompt); + telnet.login(login, password); + + // this is how you have to do it otherwise + telnet.send("touch /tmp/TELNET_WRAPPER-" + timestamp + "\r"); + telnet.wait(prompt); + + // sendLine 1: adds the \r automatically, 2: waits for the prompt + // before returning 3: returns what was printed from the command + String ls = telnet.sendLine("ls /tmp"); + System.out.println(ls); + + // clean up + telnet.disconnect(); + } +} + diff --git a/src/de/mud/telnet/socket/TimedOutException.java b/src/de/mud/telnet/socket/TimedOutException.java new file mode 100644 index 0000000..dc12333 --- /dev/null +++ b/src/de/mud/telnet/socket/TimedOutException.java @@ -0,0 +1,23 @@ +package de.mud.telnet.socket; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ +import java.io.IOException; + +/** Exception thrown when a Telnet connection takes too long + * before receiving a specified String token. + * @author George Ruban + * @version 0.1 7/30/97 */ +public class TimedOutException extends IOException +{ + public TimedOutException() + { + } + + public TimedOutException(String message) + { + super(message); + } +} + diff --git a/src/de/mud/telnet/telnet.java b/src/de/mud/telnet/telnet.java new file mode 100644 index 0000000..0d86c4e --- /dev/null +++ b/src/de/mud/telnet/telnet.java @@ -0,0 +1,562 @@ +package de.mud.telnet; +/* "In case you would like to use the packages as libraries please + * apply the GNU Library General Public License as documented in the + * file COPYING.LIB." (from Telnet/Documentation/index.html) + */ + +/** + * telnet -- implements a simple telnet + * -- + * $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $ + * $timestamp: Mon Aug 4 13:11:14 1997 by Matthias L. Jugel :$ + * + * This file is part of "The Java Telnet Applet". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Applet" is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +import java.applet.Applet; +import java.awt.Frame; +import java.awt.Component; +import java.awt.Container; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Panel; +import java.awt.Event; +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; +import java.io.IOException; + +import de.mud.telnet.socket.*; +import de.mud.telnet.display.*; +import de.mud.telnet.modules.*; + +/** + * A telnet implementation that supports different terminal emulations. + * @version $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class telnet extends Applet implements Runnable, TerminalHost, StatusPeer +{ + /** + * The telnet io methods. + * @see socket.TelnetIO + */ + protected TelnetIO tio; + + /** + * The terminal emulation (dynamically loaded). + * @see emulation + * @see display.Terminal + * @see display.TerminalHost + */ + protected Terminal term; + + /** + * The host address to connect to. This is retrieved from the PARAM tag + * "address". + */ + protected String address; + + /** + * The port number (default ist 23). This can be specified as the PARAM tag + * "port". + */ + protected int port = 23; + + /** + * The proxy ip address. If this variable is set telnet will try to connect + * to this address and then send a string to tell the relay where the + * target host is. + * @see address + */ + protected String proxy = null; + /** + * The proxy port number. This is the port where the relay is expected to + * listen for incoming connections. + * @see proxy + * @see port + */ + protected int proxyport; + + /** + * Emulation type (default is vt320). This can be specified as the PARAM + * tag "emulation". + * @see term + * @see display.Terminal + * @see display.TerminalHost + */ + protected String emulation = "vt320"; + + /** + * Dynamically loaded modules are stored here. + */ + protected Vector modules = null; + + // some state variables; + private boolean localecho = true; + private boolean connected = false; + + private Thread t; + private Container parent; + + /** + * This Hashtable contains information retrievable by getParameter() in case + * the program is run as an application and the AppletStub is missing. + */ + public Hashtable params; + + /** + * Retrieve the current version of the applet. + * @return String a string with the version information. + */ + public String getAppletInfo() + { + String info = "The Java(tm) Telnet Applet\n$Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $\n"; + info += "Terminal emulation: "+term.getTerminalType()+ + " ["+term.toString()+"]\n"; + info += "Terminal IO version: "+tio.toString()+"\n"; + if(modules != null && modules.size() > 0) { + info += "Resident modules loaded: ("+modules.size()+")"; + for(int i = 0; i < modules.size(); i++) + info += " + "+(modules.elementAt(i)).toString()+"\n"; + } + + return info; + } + + /** + * Retrieve parameter tag information. This includes the tag information from + * terminal and loaded modules. + * @return String an array of array of string with tag information + * @see java.applet.Applet#getParameterInfo + */ + public String[][] getParameterInfo() + { + String pinfo[][]; + String info[][] = { + {"address", "String", "IP address"}, + {"port", "Integer", "Port number"}, + {"proxy", "String", "IP address of relay"}, + {"proxyport","Integer", "Port number of relay"}, + {"emulation","String", "Emulation to be used (standard is vt320)"}, + }; + String tinfo[][] = (term != null ? term.getParameterInfo() : null); + if(tinfo != null) pinfo = new String[tinfo.length + 3][3]; + else pinfo = new String[3][3]; + System.arraycopy(info, 0, pinfo, 0, 3); + System.arraycopy(tinfo, 0, pinfo, 3, tinfo.length); + return pinfo; + } + + /** + * We override the Applet method getParameter() to be able to handle + * parameters even as application. + * @param name The name of the queried parameter. + * @return the value of the parameter + * @see java.applet.Applet#getParameter + */ + public String getParameter(String name) + { + if(params == null) return super.getParameter(name); + return (String)params.get(name); + } + + /** + * The main function is called on startup of the application. + */ + public static void main(String args[]) + { + // an application has to create a new instance of itself. + telnet applet = new telnet(); + + // create params from command line arguments + applet.params = new Hashtable(); + switch(args.length) + { + case 2: applet.params.put("port", args[1]); + case 1: applet.params.put("address", args[0]); + break; + default: + System.out.println("Usage: java telnet host [port]"); + System.exit(0); + } + applet.params.put("VTscrollbar", "true"); + applet.params.put("module#1", "ButtonBar"); + applet.params.put("1#Button", "Exit|\\$exit()"); + applet.params.put("2#Button", "Connect|\\$connect(\\@address@,\\@port@)"); + applet.params.put("3#Input", "address#30|" + +(args.length > 0 ? args[0] : "localhost")); + applet.params.put("4#Input", "port#4|23"); + applet.params.put("5#Button", "Disconnect|\\$disconnect()"); + + // we put the applet in its own frame + Frame frame = new Frame("The Java Telnet Application ["+args[0]+"]"); + frame.setLayout(new BorderLayout()); + frame.add("Center", applet); + frame.resize(380, 590); + + applet.init(); + + frame.pack(); + frame.show(); + + applet.start(); + } + + /** + * Initialize applet. This method reads the PARAM tags "address", + * "port" and "emulation". The emulation class is loaded dynamically. + * It also loads modules given as parameter "module#". + */ + public void init() + { + String tmp; + + // save the current parent for future use + parent = getParent(); + + // get the address we want to connect to + address = getParameter("address"); + + if((tmp = getParameter("port")) == null) + port = 23; + else + port = Integer.parseInt(tmp); + + if((proxy = getParameter("proxy")) != null) + if((tmp = getParameter("proxyport")) == null) + proxyport = 31415; + else + proxyport = Integer.parseInt(tmp); + + if((emulation = getParameter("emulation")) == null) + emulation = "vt320"; + + // load the terminal emulation + try { + term = (Terminal)Class.forName("display."+emulation).newInstance(); + System.out.println("telnet: load terminal emulation: "+emulation); + } catch(Exception e) { + System.err.println("telnet: cannot load terminal emulation "+emulation); + e.printStackTrace(); + } + setLayout(new BorderLayout()); + + // load modules, position is determined by the @ modifier + modules = new Vector(); + int nr = 1; + while((tmp = getParameter("module#"+nr++)) != null) try { + Panel north = null, south = null, west = null, east = null; + String position = "North", initFile = null; + + // try to get the initialization file name + if(tmp.indexOf(',') != -1) { + initFile = tmp.substring(tmp.indexOf(','+1)); + tmp = tmp.substring(0, tmp.indexOf(',')); + initFile = tmp.substring(tmp.indexOf(','+1)); + } + + // find the desired location + if(tmp.indexOf('@') != -1) { + position = tmp.substring(tmp.indexOf('@')+1); + tmp = tmp.substring(0, tmp.indexOf('@')); + } + Object obj = (Object)Class.forName("modules."+tmp).newInstance(); + + // probe for module (implementing modules.Module) + try { + ((Module)obj).setLoader(this); + modules.addElement((Module)obj); + System.out.println("telnet: module "+tmp+" detected"); + } catch(ClassCastException e) { + System.out.println("telnet: warning: "+tmp+" may not be a "+ + "valid module"); + } + + // probe for visible component (java.awt.Component and descendants) + try { + Component component = (Component)obj; + if(position.equals("North")) { + if(north == null) { north = new Panel(); add("North", north); } + north.add(component); + } else if(position.equals("South")) { + if(south == null) { south = new Panel(); add("South", south); } + south.add(component); + } else if(position.equals("East")) { + if(east == null) { east = new Panel(); add("East", east); } + east.add(component); + } else if(position.equals("West")) { + if(west == null) { west = new Panel(); add("West", west); } + west.add(component); + } + System.err.println("telnet: module "+tmp+" is a visible component"); + } catch(ClassCastException e) {} + + } catch(Exception e) { + System.err.println("telnet: cannot load module "+tmp); + e.printStackTrace(); + } + if(modules.isEmpty()) modules = null; + add("Center", term); + } + + /** + * Upon start of the applet try to create a new connection. + */ + public void start() + { + if(!connect(address, port) && params == null) + showStatus("telnet: connection to "+address+" "+port+" failed"); + } + + /** + * Disconnect when the applet is stopped. + */ + public final void stop() + { + disconnect(); + } + + /** + * Try to read data from the sockets and put it on the terminal. + * This is done until the thread dies or an error occurs. + */ + public void run() + { + while(t != null) + try { + String tmp = new String(tio.receive(), 0); + + // cycle through the list of modules + if(modules != null) { + Enumeration modlist = modules.elements(); + while(modlist.hasMoreElements()) { + Module m = (Module)modlist.nextElement(); + String modified = m.receive(tmp); + // call the receive() method and if it returns null + // remove the module from the list + if(modified == null) modules.removeElement(m); + else tmp = modified; + } + } + // put the modified string to the terminal + term.putString(tmp); + } catch(IOException e) { + disconnect(); + } + } + + /** + * Connect to the specified host and port but don't break existing + * connections. Connects to the host and port specified in the tags. + * @return false if connection was unsuccessful + */ + public boolean connect() + { + return connect(address, port); + } + + /** + * Connect to the specified host and port but don't break existing + * connections. Uses the port specified in the tags or 23. + * @param host destination host address + */ + public boolean connect(String host) + { + return connect(host, port); + } + + /** + * Connect to the specified host and port but don't break existing + * connections. + * @param host destination host address + * @param prt destination hosts port + */ + public boolean connect(String host, int prt) + { + address = host; port = prt; + + if(address == null || address.length() == 0) return false; + + // There should be no thread when we try to connect + if(t != null && connected) { + System.err.println("telnet: connect: existing connection preserved"); + return false; + } else t = null; + + try { + // In any case try to disconnect if tio is still active + // if there was no tio create a new one. + if(tio != null) try { tio.disconnect(); } catch(IOException e) {} + else (tio = new TelnetIO()).setPeer(this); + + term.putString("Trying "+address+(port==23?"":" "+port)+" ...\n\r"); + try { + // connect to to our destination at the given port + if(proxy != null) { + tio.connect(proxy, proxyport); + String str = "relay "+address+" "+port+"\n"; + byte[] bytes = new byte[str.length()]; + str.getBytes(0, str.length(), bytes, 0); + tio.send(bytes); + } else + tio.connect(address, port); + term.putString("Connected to "+address+".\n\r"); + // initial conditions are connected and localecho + connected = true; + localecho = true; + + // cycle through the list of modules and notify connection + if(modules != null) { + Enumeration modlist = modules.elements(); + while(modlist.hasMoreElements()) + // call the connect() method + ((Module)modlist.nextElement()).connect(address, port); + } + } catch(IOException e) { + term.putString("Failed to connect.\n\r"); + // to be sure, we remove the TelnetIO instance + tio = null; + System.err.println("telnet: failed to connect to "+address+" "+port); + e.printStackTrace(); + return false; + } + // if our connection was successful, create a new thread and start it + t = new Thread(this); + t.setPriority(Thread.MIN_PRIORITY); + t.start(); + } catch(Exception e) { + // hmm, what happened? + System.err.println("telnet: an error occured:"); + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Disconnect from the remote host. + * @return false if there was a problem disconnecting. + */ + public boolean disconnect() + { + if(tio == null) { + System.err.println("telnet: no connection"); + return false; + } + try { + connected = false; t = null; + // cycle through the list of modules and notify connection + if(modules != null) { + Enumeration modlist = modules.elements(); + while(modlist.hasMoreElements()) + // call the disconnect() method + ((Module)modlist.nextElement()).disconnect(); + } + term.putString("\n\rConnection closed.\n\r"); + tio.disconnect(); + } catch(Exception e) { + System.err.println("telnet: disconnection problem"); + e.printStackTrace(); + tio = null; t = null; + return false; + } + return true; + } + + /** + * Send a String to the remote host. Implements display.TerminalHost + * @param s String to be sent + * @return true if we are connected + * @see display.TerminalHost + */ + public boolean send(String str) + { + if(connected) try { + byte[] bytes = new byte[str.length()]; + str.getBytes(0, str.length(), bytes, 0); + tio.send(bytes); + if(localecho) { + if ((str.length()==2) && (str.charAt(0)=='\r') && (str.charAt(1)==0)) + term.putString("\r\n"); + else + term.putString(str); + } + } catch(Exception e) { + System.err.println("telnet.send(): disconnected"); + disconnect(); + return false; + } + else return false; + return true; + } + + /** + * Send a String to the remote Host. + * @param str String to be sent + * @return true if we are connected + * @see modules.BSXModule + */ + public boolean writeToSocket(String str) + { + if (connected) try { + byte[] bytes = new byte[str.length()]; + str.getBytes(0, str.length(), bytes, 0); + tio.send(bytes); + } catch(Exception e) { + System.err.println("telnet.send(): disconnected"); + disconnect(); + return false; + } + else return false; + return true; + } + /** + * Send a String to the users terminal + * @param str String to be displayed + * @return void + * @see modules.BSXModule + */ + public void writeToUser(String str) + { + if (term!=null) + term.putString(str); + } + + /** + * This method is called when telnet needs to be notified of status changes. + * @param status Vector of status information. + * @return an object of the information requested. + * @see socket.StatusPeer + */ + public Object notifyStatus(Vector status) + { + String what = (String)status.elementAt(0); + if(what.equals("NAWS")) + return term.getSize(); + if(what.equals("TTYPE")) + if(term.getTerminalType() == null) + return emulation; + else return term.getTerminalType(); + if(what.equals("LOCALECHO")) + localecho = true; + if(what.equals("NOLOCALECHO")) + localecho = false; + return null; + } +} diff --git a/src/edu/berkeley/fleet/Fleet.java b/src/edu/berkeley/fleet/Fleet.java index 8701191..227db43 100644 --- a/src/edu/berkeley/fleet/Fleet.java +++ b/src/edu/berkeley/fleet/Fleet.java @@ -42,7 +42,7 @@ public class Fleet { } public void dispatchCodeBag(int descriptor) { - System.out.println("instr: dispatching codebag #"+descriptor); + Log.println("instr: dispatching codebag #"+descriptor); Program.allCodeBags.get(descriptor).dispatch(this); } diff --git a/src/edu/berkeley/fleet/FleetApplet.java b/src/edu/berkeley/fleet/FleetApplet.java new file mode 100644 index 0000000..93f9d1a --- /dev/null +++ b/src/edu/berkeley/fleet/FleetApplet.java @@ -0,0 +1,81 @@ +package edu.berkeley.fleet; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.applet.*; +import java.io.*; +import java.util.*; + +public class FleetApplet extends Applet { + + public static void main(String[] s) throws Exception { + Frame f = new Frame(); + f.show(); + + PipedOutputStream po1 = new PipedOutputStream(); + PipedInputStream pi1 = new PipedInputStream(po1); + + PipedOutputStream po2 = new PipedOutputStream(); + final PipedInputStream pi2 = new PipedInputStream(po2); + + JPanel top = new JPanel(); + top.setLayout(new BorderLayout()); + final JTextArea text = new JTextArea(100, 10); + top.add(new JScrollPane(text), BorderLayout.CENTER); + + JButton button = new JButton("interpret"); + top.add(button, BorderLayout.SOUTH); + + Term term = new Term(pi1, po2); + term.setMinimumSize(new Dimension(Integer.MAX_VALUE, 10)); + + JSplitPane jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + top, + term + ); + f.add(jsp); + + Log.log = new PrintWriter(new OutputStreamWriter(po1)); + + new Thread() { + public void run() { + try { + while(true) + System.err.println(pi2.read()); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + f.pack(); + + text.setFont(new Font("monospaced", 0, 20)); + StringBuffer in = new StringBuffer(); + BufferedReader br = + new BufferedReader(new InputStreamReader(FleetApplet.class.getClassLoader().getResourceAsStream("test.fleet"))); + while(true) { + String str = br.readLine(); + if (str==null) break; + in.append(str+"\n"); + } + text.setText(in.toString()); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + System.err.println("launching"); + FleetParser.go(new StringReader(text.getText())); + System.err.println("launched"); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + + jsp.setDividerLocation(0.5); + f.pack(); + f.show(); + f.setSize(800, 600); + f.doLayout(); + } + +} diff --git a/src/edu/berkeley/fleet/FleetParser.java b/src/edu/berkeley/fleet/FleetParser.java index 7cd3dee..b05e75c 100644 --- a/src/edu/berkeley/fleet/FleetParser.java +++ b/src/edu/berkeley/fleet/FleetParser.java @@ -12,7 +12,10 @@ import java.io.*; public class FleetParser { public static void main(String[] s) throws Exception { + go(new InputStreamReader(System.in)); + } + public static void go(Reader r) throws Exception { InputStream grammarStream = FleetParser.class.getClassLoader().getResourceAsStream("fleet.g"); @@ -22,38 +25,38 @@ public class FleetParser { Union mathGrammar = Grammar.create(parsedGrammar, "s", gbr); Parser mathParser = new CharParser(mathGrammar); - System.out.println("about to parse: tests/test.fleet"); - Tree tree = mathParser.parse(new CharInput(System.in)).expand1(); + Log.println("about to parse: tests/test.fleet"); + Tree tree = mathParser.parse(new CharInput(r)).expand1(); // below is ugly voodoo which will go away very soon. ignore it. TreeFunctor tf = (TreeFunctor)tree.head(); Program program = (Program)tf.invoke(tree); // above is ugly voodoo which will go away very soon. ignore it. - System.out.println(); - System.out.println("dispatching root codebag:"); - System.out.println(program.root); + Log.println(); + Log.println("dispatching root codebag:"); + Log.println(program.root); Fleet fleet = new Fleet(); program.configure(fleet); - System.out.println("memory before execution:"); - System.out.print(" "); + Log.println("memory before execution:"); + Log.print(" "); for(int i=0; i " + ib); + Log.println("instr: " + ob + " -> " + ib); } } public String toString() { @@ -178,7 +178,7 @@ public class Program { for(Port d : dest) { Ship.Inbox ib = fleet.getInbox(d.ship, d.port); ib.add(val); - System.out.println("instr: " + val + " -> " + ib); + Log.println("instr: " + val + " -> " + ib); } } public String toString() { @@ -200,7 +200,7 @@ public class Program { for(Port d : dest) { Ship.Inbox ib = fleet.getInbox(d.ship, d.port); ib.add(cb.getIdentifier()); - System.out.println("instr: codebag #" + cb.getIdentifier() + " -> " + ib); + Log.println("instr: codebag #" + cb.getIdentifier() + " -> " + ib); } } public String toString() { diff --git a/src/edu/berkeley/fleet/Ship.java b/src/edu/berkeley/fleet/Ship.java index 074b04e..9e9fc4d 100644 --- a/src/edu/berkeley/fleet/Ship.java +++ b/src/edu/berkeley/fleet/Ship.java @@ -38,7 +38,7 @@ public abstract class Ship { int data = ob.data.remove(); Inbox destination = ob.destination.remove(); destination.add(data); - System.out.println("data: " + ob + " ----("+data+")----> " + destination); + Log.println("data: " + ob + " ----("+data+")----> " + destination); } } service(); diff --git a/src/edu/berkeley/fleet/Term.java b/src/edu/berkeley/fleet/Term.java new file mode 100644 index 0000000..4a30a67 --- /dev/null +++ b/src/edu/berkeley/fleet/Term.java @@ -0,0 +1,57 @@ +package edu.berkeley.fleet; + +import de.mud.telnet.*; +import de.mud.telnet.modules.*; +import de.mud.telnet.display.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.table.*; +import javax.swing.border.*; +import java.net.*; +import java.io.*; + +public class Term extends vt320 implements ComponentListener { + private final InputStream is; + private final OutputStream os; + + public Term(InputStream is, OutputStream os) { this.is = is; this.os = os; addComponentListener(this); } + + public void componentResized(ComponentEvent e) { repaint(); } + public void componentMoved(ComponentEvent e) { } + public void componentHidden(ComponentEvent e) { } + public void componentShown(ComponentEvent e) { } + + private class ListenerThread extends Thread { + public void run() { + try { + byte[] buf = new byte[1024]; + while(true) { + int numread = is.read(buf, 0, buf.length); + if (numread==-1) break; + if (numread==0) continue; + Term.this.putString(new String(buf, 0, numread, "US-ASCII")); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + boolean listenerStarted = false; + public void paint(Graphics g) { + if (!listenerStarted) { listenerStarted = true; new ListenerThread().start(); } + super.paint(g); + } + public synchronized void putString(String s) { super.putString(s); } + public synchronized boolean send(String s) { + try { + os.write(s.getBytes("US-ASCII")); + os.flush(); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/test.fleet b/test.fleet index 7bf925a..8081937 100644 --- a/test.fleet +++ b/test.fleet @@ -23,9 +23,13 @@ // define the initial contents of memory - #memory { 000, 100, 200, 300, 400, 500 } +// preload the counter register +4 -> i.write +i.writedone -> gate.release +gate.codebag <- top + top: { i.read -> less.in1 0 -> less.in2 less.out -> ifthen.if @@ -40,31 +44,14 @@ continue: { 1000 -> adder.in2 adder.out -> memwrite.data memwrite.done -> gate.release - gate.codebag <- write + gate.codebag <- { + i.read -> adder2.in1 + -1 -> adder2.in2 + adder2.out -> i.write + i.writedone -> gate2.release + gate2.codebag <- top + } } -write: { - i.read -> adder2.in1 - -1 -> adder2.in2 - adder2.out -> i.write - i.writedone -> gate2.release - gate2.codebag <- top -} - - -4 -> i.write -i.writedone -> gate.release -gate.codebag <- top -//1 -> adder.in1 -//1 -> adder.in2 -//adder.out -> memread.addr -//memread.data -> adder.in1 -//13 -> adder.in2 -// -//adder.out -> less.in1 -//214 -> less.in2 -//less.out -> ifthen.if -//{ 7 -> halt.in } -> ifthen.then -//{ 9 -> halt.in } -> ifthen.else -- 1.7.10.4