Fix YMS bug
This commit is contained in:
@@ -6,6 +6,7 @@ import org.lib3270j.charset.EbcdicTranslator;
|
||||
import org.lib3270j.listener.ScreenUpdateListener;
|
||||
import static org.lib3270j.protocol.DS3270Constants.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.logging.Logger;
|
||||
@@ -451,8 +452,8 @@ public class DataStreamProcessor {
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
// Fill from current position to target
|
||||
while (baddr != toAddr) {
|
||||
// Fill from current position to target (do-while wraps entire buffer if baddr == toAddr)
|
||||
do {
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0; // Destroy previous field attribute if any
|
||||
ea.ec = (byte) fillChar;
|
||||
@@ -461,7 +462,7 @@ public class DataStreamProcessor {
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.cs = fillCs;
|
||||
baddr = (baddr + 1) % size;
|
||||
}
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
lastWasOrder = true;
|
||||
break;
|
||||
@@ -476,7 +477,7 @@ public class DataStreamProcessor {
|
||||
if (toAddr >= size)
|
||||
toAddr = toAddr % size;
|
||||
|
||||
while (baddr != toAddr) {
|
||||
do {
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
if (!ea.isFieldAttribute()) {
|
||||
int faAddr = screen.findFieldAttribute(baddr);
|
||||
@@ -491,7 +492,7 @@ public class DataStreamProcessor {
|
||||
}
|
||||
}
|
||||
baddr = (baddr + 1) % size;
|
||||
}
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 3;
|
||||
lastWasOrder = true;
|
||||
@@ -637,7 +638,13 @@ public class DataStreamProcessor {
|
||||
|
||||
outputPos = 0;
|
||||
|
||||
int aid = AID_NO; // Last AID
|
||||
int aid = (inputProcessor != null && inputProcessor.getLastAid() != 0)
|
||||
? inputProcessor.getLastAid()
|
||||
: AID_NO;
|
||||
if (inputProcessor != null) {
|
||||
inputProcessor.setLastAid(AID_NO);
|
||||
}
|
||||
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
|
||||
// AID byte
|
||||
@@ -649,31 +656,56 @@ public class DataStreamProcessor {
|
||||
outputWrite(caddr[1] & 0xFF);
|
||||
|
||||
if (!screen.isFormatted()) {
|
||||
// Unformatted: send everything
|
||||
if (all) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
outputWrite(screen.getCell(i).ec & 0xFF);
|
||||
// Unformatted screen: send data up to last non-null
|
||||
int lastNonNull = -1;
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
if (screen.getCell(i).ec != 0) {
|
||||
lastNonNull = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastNonNull >= 0) {
|
||||
for (int i = 0; i <= lastNonNull; i++) {
|
||||
int b = screen.getCell(i).ec & 0xFF;
|
||||
outputWrite(b != 0 ? b : 0x40);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Formatted: send modified fields
|
||||
// Formatted screen: send modified fields with trailing NULLs stripped
|
||||
for (int i = 0; i < size; i++) {
|
||||
ExtendedAttribute ea = screen.getCell(i);
|
||||
if (ea.isFieldAttribute() && (all || faIsModified(ea.fa & 0xFF))) {
|
||||
int fieldStart = (i + 1) % size;
|
||||
// Send SBA for field start
|
||||
|
||||
// Collect field data and find last non-null byte
|
||||
ByteArrayOutputStream fieldData = new ByteArrayOutputStream();
|
||||
int pos = fieldStart;
|
||||
int lastNonNull = -1;
|
||||
int fieldLen = 0;
|
||||
while (!screen.getCell(pos).isFieldAttribute()) {
|
||||
int b = screen.getCell(pos).ec & 0xFF;
|
||||
fieldData.write(b);
|
||||
if (b != 0x00) {
|
||||
lastNonNull = fieldLen;
|
||||
}
|
||||
fieldLen++;
|
||||
pos = (pos + 1) % size;
|
||||
if (pos == fieldStart)
|
||||
break;
|
||||
}
|
||||
|
||||
// Always send SBA and address
|
||||
outputWrite(ORDER_SBA);
|
||||
byte[] addr = encodeAddress(fieldStart, screen.getRows(), screen.getCols());
|
||||
outputWrite(addr[0] & 0xFF);
|
||||
outputWrite(addr[1] & 0xFF);
|
||||
|
||||
// Send field contents until next FA
|
||||
int pos = fieldStart;
|
||||
while (pos < size && !screen.getCell(pos).isFieldAttribute()) {
|
||||
outputWrite(screen.getCell(pos).ec & 0xFF);
|
||||
pos = (pos + 1) % size;
|
||||
if (pos == fieldStart)
|
||||
break;
|
||||
// Send field data (strip trailing nulls)
|
||||
if (lastNonNull >= 0) {
|
||||
byte[] allData = fieldData.toByteArray();
|
||||
for (int k = 0; k <= lastNonNull; k++) {
|
||||
outputWrite(allData[k] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,20 +265,21 @@ public class QueryReplyBuilder {
|
||||
|
||||
private byte[] buildImplicitPartition(int maxCols, int maxRows) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(22);
|
||||
// Implicit partition sizes, 2 self-defining parameters
|
||||
// Implicit partition sizes SDP (Self-Defining Parameter)
|
||||
|
||||
// SDP 1: Default screen size
|
||||
out.write(0x00); // flags
|
||||
out.write(0x00); // reserved
|
||||
out.write(0x0b); // SDP length
|
||||
// SDP 1: Implicit partition sizes
|
||||
out.write(0x00); // SDP length high byte
|
||||
out.write(0x0b); // SDP length low byte (11 bytes: 2 len + 1 type + 1 res + 8 dims)
|
||||
out.write(0x01); // SDP type: implicit partition sizes
|
||||
out.write(0x00); // reserved
|
||||
// Default
|
||||
// Default dimensions (Model 2: 80x24)
|
||||
out.write((MODEL_2_COLS >> 8) & 0xFF);
|
||||
out.write(MODEL_2_COLS & 0xFF);
|
||||
out.write((MODEL_2_ROWS >> 8) & 0xFF);
|
||||
out.write(MODEL_2_ROWS & 0xFF);
|
||||
// Alternate
|
||||
// Alternate dimensions
|
||||
out.write((maxCols >> 8) & 0xFF);
|
||||
out.write(maxCols & 0xFF);
|
||||
out.write((maxRows >> 8) & 0xFF);
|
||||
|
||||
@@ -138,9 +138,10 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
// Advance cursor
|
||||
int startAdvance = baddr;
|
||||
baddr = (baddr + 1) % size;
|
||||
// Skip over field attributes
|
||||
while (screen.getCell(baddr).isFieldAttribute()) {
|
||||
// Skip over field attributes safely
|
||||
while (screen.getCell(baddr).isFieldAttribute() && baddr != startAdvance) {
|
||||
baddr = (baddr + 1) % size;
|
||||
}
|
||||
screen.setCursorAddress(baddr);
|
||||
@@ -255,18 +256,26 @@ public class InputProcessor {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unformatted screen in 3270 mode:
|
||||
// Send character data from address 0 up to last non-null character
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
int lastNonNull = -1;
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
if (screen.getCell(i).ec != 0) {
|
||||
lastNonNull = i;
|
||||
// Unformatted screen in 3270 mode (e.g. line-mode console):
|
||||
// Send AID + cursor address + only the active input line (row containing cursor)
|
||||
int cols = screen.getCols();
|
||||
int curAddr = screen.getCursorAddress();
|
||||
int row = curAddr / cols;
|
||||
int rowStart = row * cols;
|
||||
int rowEnd = rowStart + cols;
|
||||
|
||||
// Find last non-null, non-blank character on the current line
|
||||
int lastChar = rowStart - 1;
|
||||
for (int i = rowEnd - 1; i >= rowStart; i--) {
|
||||
int ec = screen.getCell(i).ec & 0xFF;
|
||||
if (ec != 0x00 && ec != 0x40) {
|
||||
lastChar = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastNonNull >= 0) {
|
||||
for (int i = 0; i <= lastNonNull; i++) {
|
||||
|
||||
if (lastChar >= rowStart) {
|
||||
for (int i = rowStart; i <= lastChar; i++) {
|
||||
int b = screen.getCell(i).ec & 0xFF;
|
||||
out.write(b != 0 ? b : 0x40);
|
||||
}
|
||||
@@ -325,6 +334,13 @@ public class InputProcessor {
|
||||
screen.setCursorAddress(addr);
|
||||
}
|
||||
|
||||
public int getLastAid() { return lastAid; }
|
||||
public void setLastAid(int aid) { this.lastAid = aid; }
|
||||
|
||||
public void setCursorAddress(int baddr) {
|
||||
screen.setCursorAddress(baddr);
|
||||
}
|
||||
|
||||
public void backTab() {
|
||||
// Find previous unprotected field
|
||||
int addr = screen.getCursorAddress();
|
||||
|
||||
@@ -132,10 +132,14 @@ public class TelnetConnection {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("RCVD " + n + " bytes: " + formatHex(buf, 0, n));
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
fsm.feedByte(buf[i] & 0xFF);
|
||||
try {
|
||||
for (int i = 0; i < n; i++) {
|
||||
fsm.feedByte(buf[i] & 0xFF);
|
||||
}
|
||||
fsm.endOfNetworkData();
|
||||
} catch (Throwable t) {
|
||||
log.log(Level.SEVERE, "Exception processing incoming data stream", t);
|
||||
}
|
||||
fsm.endOfNetworkData();
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
@@ -148,6 +152,11 @@ public class TelnetConnection {
|
||||
log.log(Level.WARNING, "Read error", e);
|
||||
fsm.onError("Read error: " + e.getMessage());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (running) {
|
||||
log.log(Level.SEVERE, "Unexpected fatal error in readLoop", t);
|
||||
fsm.onError("Network loop error: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user