Add DevInfo.SupportsGE() function
This commit is contained in:
1 parent
6c0b3b038a
commit
bdc1d714d2
3 files changed
+46
-24
No files matched your search
@@ -88,7 +88,7 @@ func init() {
|
||||
|
||||
With the new codepage detection support, you shouldn't typically rely on the default codepage: you should always pass the `DevInfo.Codepage()` value to the `ShowScreenOpts()` function or as the last optional argument to the `HandleScreen()` or `HandleScreenAlt()` functions. The global default should only be a fallback if the client code page isn't detected correctly.
|
||||
|
||||
Additionally, most characters from the "graphic escape" code page 310 are supported in all of the go3270-provided codepage implementations. Correct display on the client will depend on its support of graphic escape and correct characters being available in its font. Use the corresponding Unicode characters in your Go UTF-8 strings and they will be sent as the EBCDIC two-byte sequence of 0x08 followed by the position in code page 310. GE sequences are also processed on incoming field values.
|
||||
Additionally, most characters from the "graphic escape" code page 310 are supported in all of the go3270-provided codepage implementations. Correct display on the client will depend on its support of graphic escape and correct characters being available in its font. The `DevInfo.SupportsGE()` function returns a boolean indicating that the client supports the graphic escape alternate code page. Use the corresponding Unicode characters in your Go UTF-8 strings and they will be sent as the EBCDIC two-byte sequence of 0x08 followed by the position in code page 310. GE sequences are also processed on incoming field values.
|
||||
|
||||
3270 information
|
||||
----------------
|
||||
|
||||
@@ -53,6 +53,8 @@ var screen1 = go3270.Screen{
|
||||
{Row: 15, Col: 0, Content: "Detected code page:"},
|
||||
{Row: 15, Col: 20, Name: "codepage"},
|
||||
{Row: 16, Col: 0, Content: "The following should be left and right square brackets: [ ]"},
|
||||
{Row: 17, Col: 0, Content: "Graphic escape support:"},
|
||||
{Row: 17, Col: 24, Name: "gesupport"},
|
||||
{Row: 22, Col: 0, Content: "PF3 Exit"},
|
||||
}
|
||||
|
||||
@@ -124,6 +126,7 @@ mainLoop:
|
||||
} else {
|
||||
fieldValues["codepage"] = devinfo.Codepage().ID()
|
||||
}
|
||||
fieldValues["gesupport"] = fmt.Sprintf("%v", devinfo.SupportsGE())
|
||||
|
||||
screen1Loop:
|
||||
for {
|
||||
|
||||
@@ -41,6 +41,10 @@ type DevInfo interface {
|
||||
// default codepage).
|
||||
Codepage() Codepage
|
||||
|
||||
// SupportsGE returns true if the client indicated it supports graphic
|
||||
// escape to code page 310.
|
||||
SupportsGE() bool
|
||||
|
||||
// Private version of AltDimensions() so callers can't fake us out; only
|
||||
// real implementations returned by NegotiateTelnet() will work.
|
||||
altDimensions() (rows, cols int)
|
||||
@@ -293,6 +297,7 @@ var modelRegex = regexp.MustCompile(`^IBM-\d{4}-([2-5])`)
|
||||
|
||||
func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||
var rows, cols, cpid int
|
||||
var hasGE bool
|
||||
var codepage Codepage
|
||||
var isx3270 bool
|
||||
|
||||
@@ -355,7 +360,7 @@ func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||
// Timeout. In this case, we'll assume it's because the client didn't
|
||||
// reply to our query command. In that case, we'll return whatever
|
||||
// we're already assuming.
|
||||
return &deviceInfo{24, 80, termtype, nil}, nil
|
||||
return &deviceInfo{24, 80, termtype, nil, false}, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -365,7 +370,7 @@ func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||
// structured field queries? If we're not getting the kind of reply
|
||||
// we're expecting, we'll return whatever we're already assuming.
|
||||
flushConnection(conn, 50*time.Millisecond)
|
||||
return &deviceInfo{24, 80, termtype, nil}, nil
|
||||
return &deviceInfo{24, 80, termtype, nil, false}, nil
|
||||
}
|
||||
|
||||
// There are an arbitrary number of query reply structured fields. We are
|
||||
@@ -404,7 +409,7 @@ func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||
}
|
||||
} else if buf[0] == 0x81 && buf[1] == 0x85 {
|
||||
// Character Sets
|
||||
cpid = getCodepageID(buf)
|
||||
cpid, hasGE = getCodepageID(buf)
|
||||
} else if buf[0] == 0x81 && buf[1] == 0xA1 {
|
||||
// RPQ Names. We use this to determine if the client is x3270
|
||||
// family.
|
||||
@@ -429,7 +434,7 @@ func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||
codepage = nil
|
||||
}
|
||||
|
||||
return &deviceInfo{rows, cols, termtype, codepage}, nil
|
||||
return &deviceInfo{rows, cols, termtype, codepage, hasGE}, nil
|
||||
}
|
||||
|
||||
// getUsableArea processes the "Query Reply (Usable Area)" response to return
|
||||
@@ -465,43 +470,52 @@ func getUsableArea(buf []byte) (rows, cols int, err error) {
|
||||
}
|
||||
|
||||
// getCodepageID processes the "Query Reply (Character Sets)" response to
|
||||
// return the integer code page number if present. If unable, returns 0. The
|
||||
// byte slice passed in to buf must begin with {0x81, 0x85}.
|
||||
func getCodepageID(buf []byte) int {
|
||||
// return the integer code page number if present. Also returns a boolean
|
||||
// indicating if graphic escape to code page 310 is supported. If unable,
|
||||
// returns 0. The byte slice passed in to buf must begin with {0x81, 0x85}.
|
||||
func getCodepageID(buf []byte) (int, bool) {
|
||||
// Initial validity check.
|
||||
if len(buf) < 11 || buf[0] != 0x81 || buf[1] != 0x85 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// If the GF bit is not set, no point in continuing.
|
||||
if buf[2]&(1<<1) != 1<<1 {
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// ALT flag = graphic escape supported
|
||||
hasGE := buf[2]&(1<<7) == 1<<7
|
||||
|
||||
// Descriptor length
|
||||
dl := int(buf[10])
|
||||
|
||||
// There may be more than one descriptors, and we need to find the first
|
||||
// one with local ID 0.
|
||||
// There may be more than one descriptors, and we need to find local ID 0,
|
||||
// and possibly local ID 1 (the alternate codepage).
|
||||
var primaryCPID, altCPID int
|
||||
pos := 11 // first descriptor
|
||||
for {
|
||||
if len(buf) < pos+dl {
|
||||
// No more descriptors and we haven't found anything yet
|
||||
return 0
|
||||
// No more descriptors
|
||||
break
|
||||
}
|
||||
|
||||
if buf[pos] != 0 {
|
||||
// not the descriptor we're looking for, try the next one
|
||||
pos += dl
|
||||
continue
|
||||
}
|
||||
|
||||
// This is the first descriptor we've seen with ID 0, we'll use it.
|
||||
// No matter how long the descriptor is, the code page will 2-byte big
|
||||
// endian integer in the last two bytes.
|
||||
// CPID of this descriptor. No matter how long the descriptor is, the
|
||||
// code page will be 2-byte big endian integer in the last two bytes.
|
||||
cpid := int(buf[pos+dl-2])<<8 + int(buf[pos+dl-1])
|
||||
return cpid
|
||||
|
||||
// First byte of the descriptor is the local ID; 0 is the base set and
|
||||
// 1 is the alternate (graphic escape) set.
|
||||
if buf[pos] == 0 && primaryCPID == 0 {
|
||||
primaryCPID = cpid
|
||||
} else if buf[pos] == 1 {
|
||||
altCPID = cpid
|
||||
}
|
||||
|
||||
pos += dl
|
||||
}
|
||||
|
||||
return primaryCPID, hasGE && altCPID == 310
|
||||
}
|
||||
|
||||
// getRPGNames checks the "Query Reply (RPQ NAMES)" response to see if the
|
||||
@@ -656,6 +670,7 @@ type deviceInfo struct {
|
||||
rows, cols int
|
||||
termtype string
|
||||
codepage Codepage
|
||||
hasGE bool
|
||||
}
|
||||
|
||||
func (d *deviceInfo) AltDimensions() (rows, cols int) {
|
||||
@@ -673,3 +688,7 @@ func (d *deviceInfo) altDimensions() (rows, cols int) {
|
||||
func (d *deviceInfo) Codepage() Codepage {
|
||||
return d.codepage
|
||||
}
|
||||
|
||||
func (d *deviceInfo) SupportsGE() bool {
|
||||
return d.hasGE
|
||||
}
|
||||
Reference in new issue
Block a user