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.
|
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
|
3270 information
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ var screen1 = go3270.Screen{
|
|||||||
{Row: 15, Col: 0, Content: "Detected code page:"},
|
{Row: 15, Col: 0, Content: "Detected code page:"},
|
||||||
{Row: 15, Col: 20, Name: "codepage"},
|
{Row: 15, Col: 20, Name: "codepage"},
|
||||||
{Row: 16, Col: 0, Content: "The following should be left and right square brackets: [ ]"},
|
{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"},
|
{Row: 22, Col: 0, Content: "PF3 Exit"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +126,7 @@ mainLoop:
|
|||||||
} else {
|
} else {
|
||||||
fieldValues["codepage"] = devinfo.Codepage().ID()
|
fieldValues["codepage"] = devinfo.Codepage().ID()
|
||||||
}
|
}
|
||||||
|
fieldValues["gesupport"] = fmt.Sprintf("%v", devinfo.SupportsGE())
|
||||||
|
|
||||||
screen1Loop:
|
screen1Loop:
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ type DevInfo interface {
|
|||||||
// default codepage).
|
// default codepage).
|
||||||
Codepage() 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
|
// Private version of AltDimensions() so callers can't fake us out; only
|
||||||
// real implementations returned by NegotiateTelnet() will work.
|
// real implementations returned by NegotiateTelnet() will work.
|
||||||
altDimensions() (rows, cols int)
|
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) {
|
func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
||||||
var rows, cols, cpid int
|
var rows, cols, cpid int
|
||||||
|
var hasGE bool
|
||||||
var codepage Codepage
|
var codepage Codepage
|
||||||
var isx3270 bool
|
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
|
// 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
|
// reply to our query command. In that case, we'll return whatever
|
||||||
// we're already assuming.
|
// we're already assuming.
|
||||||
return &deviceInfo{24, 80, termtype, nil}, nil
|
return &deviceInfo{24, 80, termtype, nil, false}, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
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
|
// structured field queries? If we're not getting the kind of reply
|
||||||
// we're expecting, we'll return whatever we're already assuming.
|
// we're expecting, we'll return whatever we're already assuming.
|
||||||
flushConnection(conn, 50*time.Millisecond)
|
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
|
// 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 {
|
} else if buf[0] == 0x81 && buf[1] == 0x85 {
|
||||||
// Character Sets
|
// Character Sets
|
||||||
cpid = getCodepageID(buf)
|
cpid, hasGE = getCodepageID(buf)
|
||||||
} else if buf[0] == 0x81 && buf[1] == 0xA1 {
|
} else if buf[0] == 0x81 && buf[1] == 0xA1 {
|
||||||
// RPQ Names. We use this to determine if the client is x3270
|
// RPQ Names. We use this to determine if the client is x3270
|
||||||
// family.
|
// family.
|
||||||
@@ -429,7 +434,7 @@ func makeDeviceInfo(conn net.Conn, termtype string) (DevInfo, error) {
|
|||||||
codepage = nil
|
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
|
// 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
|
// getCodepageID processes the "Query Reply (Character Sets)" response to
|
||||||
// return the integer code page number if present. If unable, returns 0. The
|
// return the integer code page number if present. Also returns a boolean
|
||||||
// byte slice passed in to buf must begin with {0x81, 0x85}.
|
// indicating if graphic escape to code page 310 is supported. If unable,
|
||||||
func getCodepageID(buf []byte) int {
|
// returns 0. The byte slice passed in to buf must begin with {0x81, 0x85}.
|
||||||
|
func getCodepageID(buf []byte) (int, bool) {
|
||||||
// Initial validity check.
|
// Initial validity check.
|
||||||
if len(buf) < 11 || buf[0] != 0x81 || buf[1] != 0x85 {
|
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 the GF bit is not set, no point in continuing.
|
||||||
if buf[2]&(1<<1) != 1<<1 {
|
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
|
// Descriptor length
|
||||||
dl := int(buf[10])
|
dl := int(buf[10])
|
||||||
|
|
||||||
// There may be more than one descriptors, and we need to find the first
|
// There may be more than one descriptors, and we need to find local ID 0,
|
||||||
// one with local ID 0.
|
// and possibly local ID 1 (the alternate codepage).
|
||||||
|
var primaryCPID, altCPID int
|
||||||
pos := 11 // first descriptor
|
pos := 11 // first descriptor
|
||||||
for {
|
for {
|
||||||
if len(buf) < pos+dl {
|
if len(buf) < pos+dl {
|
||||||
// No more descriptors and we haven't found anything yet
|
// No more descriptors
|
||||||
return 0
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if buf[pos] != 0 {
|
// CPID of this descriptor. No matter how long the descriptor is, the
|
||||||
// not the descriptor we're looking for, try the next one
|
// code page will be 2-byte big endian integer in the last two bytes.
|
||||||
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 := int(buf[pos+dl-2])<<8 + int(buf[pos+dl-1])
|
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
|
// getRPGNames checks the "Query Reply (RPQ NAMES)" response to see if the
|
||||||
@@ -656,6 +670,7 @@ type deviceInfo struct {
|
|||||||
rows, cols int
|
rows, cols int
|
||||||
termtype string
|
termtype string
|
||||||
codepage Codepage
|
codepage Codepage
|
||||||
|
hasGE bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deviceInfo) AltDimensions() (rows, cols int) {
|
func (d *deviceInfo) AltDimensions() (rows, cols int) {
|
||||||
@@ -673,3 +688,7 @@ func (d *deviceInfo) altDimensions() (rows, cols int) {
|
|||||||
func (d *deviceInfo) Codepage() Codepage {
|
func (d *deviceInfo) Codepage() Codepage {
|
||||||
return d.codepage
|
return d.codepage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *deviceInfo) SupportsGE() bool {
|
||||||
|
return d.hasGE
|
||||||
|
}
|
||||||
Reference in new issue
Block a user