holy toldeo... things might actually be working

This commit is contained in:
Andrew Gallant (Ocelot) 2012-05-03 01:00:01 -04:00
parent 39507f86ab
commit 5cdae5950c
18 changed files with 11831 additions and 265 deletions

View File

@ -95,31 +95,20 @@ type Event interface {
// newEventFuncs is a map from event numbers to functions that create
// the corresponding event.
var newEventFuncs map[int]func(buf []byte) Event
var newEventFuncs = map[int]func(buf []byte) Event{}
// Error contains protocol errors returned to us by the X server.
type Error struct {
Detail uint8
Major uint8
Minor uint16
Cookie uint16
Id Id
}
// Error2 is an interface that can contain any of the errors returned by
// Error is an interface that can contain any of the errors returned by
// the server. Use a type assertion switch to extract the Error structs.
type Error2 interface {
type Error interface {
ImplementsError()
SequenceId() uint16
BadId() Id
Error() string
}
// newErrorFuncs is a map from error numbers to functions that create
// the corresponding error.
var newErrorFuncs map[int]func(buf []byte) Error2
func (e *Error) Error() string {
return fmt.Sprintf("Bad%s (major=%d minor=%d cookie=%d id=0x%x)",
errorNames[e.Detail], e.Major, e.Minor, e.Cookie, e.Id)
}
var newErrorFuncs = map[int]func(buf []byte) Error{}
// NewID generates a new unused ID for use with requests like CreateWindow.
func (c *Conn) NewId() Id {
@ -136,7 +125,7 @@ func (c *Conn) NewId() Id {
// the extensions map.
func (c *Conn) RegisterExtension(name string) error {
nameUpper := strings.ToUpper(name)
reply, err := c.QueryExtension(nameUpper)
reply, err := c.QueryExtension(uint16(len(nameUpper)), nameUpper)
switch {
case err != nil:
@ -253,25 +242,26 @@ func (c *Conn) newReadChannels() {
switch buf[0] {
case 0:
err := &Error{
Detail: buf[1],
Cookie: uint16(get16(buf[2:])),
Id: Id(get32(buf[4:])),
Minor: get16(buf[8:]),
Major: buf[10],
}
if cookie, ok := c.cookies[err.Cookie]; ok {
// err := &Error{
// Detail: buf[1],
// Cookie: uint16(get16(buf[2:])),
// Id: Id(get32(buf[4:])),
// Minor: get16(buf[8:]),
// Major: buf[10],
// }
err := newErrorFuncs[int(buf[1])](buf)
if cookie, ok := c.cookies[err.SequenceId()]; ok {
cookie.errorChan <- err
} else {
fmt.Fprintf(os.Stderr, "x protocol error: %s\n", err)
}
case 1:
seq := uint16(get16(buf[2:]))
seq := uint16(Get16(buf[2:]))
if _, ok := c.cookies[seq]; !ok {
continue
}
size := get32(buf[4:])
size := Get32(buf[4:])
if size > 0 {
bigbuf := make([]byte, 32+size*4, 32+size*4)
copy(bigbuf[0:32], buf)
@ -317,7 +307,8 @@ func (c *Conn) waitForReply(cookie *Cookie) ([]byte, error) {
func (c *Conn) WaitForEvent() (Event, error) {
for {
if reply := c.events.dequeue(c); reply != nil {
return parseEvent(reply)
evCode := reply[0] & 0x7f
return newEventFuncs[int(evCode)](reply), nil
}
if !<-c.eventChan {
return nil, errors.New("Event channel has been closed.")
@ -331,7 +322,8 @@ func (c *Conn) WaitForEvent() (Event, error) {
// Only use this function to empty the queue without blocking.
func (c *Conn) PollForEvent() (Event, error) {
if reply := c.events.dequeue(c); reply != nil {
return parseEvent(reply)
evCode := reply[0] & 0x7f
return newEventFuncs[int(evCode)](reply), nil
}
return nil, nil
}
@ -369,11 +361,11 @@ func Dial(display string) (*Conn, error) {
buf := make([]byte, 12+pad(len(authName))+pad(len(authData)))
buf[0] = 0x6c
buf[1] = 0
put16(buf[2:], 11)
put16(buf[4:], 0)
put16(buf[6:], uint16(len(authName)))
put16(buf[8:], uint16(len(authData)))
put16(buf[10:], 0)
Put16(buf[2:], 11)
Put16(buf[4:], 0)
Put16(buf[6:], uint16(len(authName)))
Put16(buf[8:], uint16(len(authData)))
Put16(buf[10:], 0)
copy(buf[12:], []byte(authName))
copy(buf[12+pad(len(authName)):], authData)
if _, err = c.conn.Write(buf); err != nil {
@ -386,9 +378,9 @@ func Dial(display string) (*Conn, error) {
}
code := head[0]
reasonLen := head[1]
major := get16(head[2:])
minor := get16(head[4:])
dataLen := get16(head[6:])
major := Get16(head[2:])
minor := Get16(head[4:])
dataLen := Get16(head[6:])
if major != 11 || minor != 0 {
return nil, errors.New(fmt.Sprintf("x protocol version mismatch: %d.%d", major, minor))
@ -405,7 +397,7 @@ func Dial(display string) (*Conn, error) {
return nil, errors.New(fmt.Sprintf("x protocol authentication refused: %s", string(reason)))
}
getSetupInfo(buf, &c.Setup)
ReadSetupInfo(buf, &c.Setup)
if c.defaultScreen >= len(c.Setup.Roots) {
c.defaultScreen = 0

View File

@ -1,5 +1,10 @@
package xgb
import (
"fmt"
"strings"
)
// getExtensionOpcode retrieves the extension opcode from the extensions map.
// If one doesn't exist, just return 0. An X error will likely result.
func (c *Conn) getExtensionOpcode(name string) byte {
@ -14,52 +19,50 @@ func (c *Conn) bytesString(str string) []byte {
return c.bytesPadding([]byte(str))
}
func (c *Conn) bytesStrList(list []Str, length int) []byte {
buf := make([]byte, 0)
for _, str := range list {
buf = append(buf, []byte(str.Name)...)
}
return c.bytesPadding(buf)
// stringsJoin is an alias to strings.Join. It allows us to avoid having to
// import 'strings' in each of the generated Go files.
func stringsJoin(ss []string, sep string) string {
return strings.Join(ss, sep)
}
func (c *Conn) bytesUInt32List(list []uint32) []byte {
buf := make([]byte, len(list)*4)
for i, item := range list {
put32(buf[i*4:], item)
}
return c.bytesPadding(buf)
}
func (c *Conn) bytesIdList(list []Id, length int) []byte {
buf := make([]byte, length*4)
for i, item := range list {
put32(buf[i*4:], uint32(item))
}
return c.bytesPadding(buf)
// sprintf is so we don't need to import 'fmt' in the generated Go files.
func sprintf(format string, v ...interface{}) string {
return fmt.Sprintf(format, v...)
}
// Pad a length to align on 4 bytes.
func pad(n int) int { return (n + 3) & ^3 }
func put16(buf []byte, v uint16) {
func Put16(buf []byte, v uint16) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
}
func put32(buf []byte, v uint32) {
func Put32(buf []byte, v uint32) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
buf[2] = byte(v >> 16)
buf[3] = byte(v >> 24)
}
func get16(buf []byte) uint16 {
func Put64(buf []byte, v uint64) {
buf[0] = byte(v)
buf[1] = byte(v >> 8)
buf[2] = byte(v >> 16)
buf[3] = byte(v >> 24)
buf[4] = byte(v >> 32)
buf[5] = byte(v >> 40)
buf[6] = byte(v >> 48)
buf[7] = byte(v >> 56)
}
func Get16(buf []byte) uint16 {
v := uint16(buf[0])
v |= uint16(buf[1]) << 8
return v
}
func get32(buf []byte) uint32 {
func Get32(buf []byte) uint32 {
v := uint32(buf[0])
v |= uint32(buf[1]) << 8
v |= uint32(buf[2]) << 16
@ -67,6 +70,18 @@ func get32(buf []byte) uint32 {
return v
}
func Get64(buf []byte) uint64 {
v := uint64(buf[0])
v |= uint64(buf[1]) << 8
v |= uint64(buf[2]) << 16
v |= uint64(buf[3]) << 24
v |= uint64(buf[4]) << 32
v |= uint64(buf[5]) << 40
v |= uint64(buf[6]) << 48
v |= uint64(buf[7]) << 56
return v
}
// Voodoo to count the number of bits set in a value list mask.
func popCount(mask0 int) int {
mask := uint32(mask0)
@ -82,22 +97,3 @@ func popCount(mask0 int) int {
// DefaultScreen returns the Screen info for the default screen, which is
// 0 or the one given in the display argument to Dial.
func (c *Conn) DefaultScreen() *ScreenInfo { return &c.Setup.Roots[c.defaultScreen] }
// ClientMessageData holds the data from a client message,
// duplicated in three forms because Go doesn't have unions.
// type ClientMessageData struct {
// Data8 [20]byte
// Data16 [10]uint16
// Data32 [5]uint32
// }
//
// func getClientMessageData(b []byte, v *ClientMessageData) int {
// copy(v.Data8[:], b)
// for i := 0; i < 10; i++ {
// v.Data16[i] = get16(b[i*2:])
// }
// for i := 0; i < 5; i++ {
// v.Data32[i] = get32(b[i*4:])
// }
// return 20
// }

View File

@ -5,6 +5,7 @@ import (
"encoding/xml"
"fmt"
"log"
"time"
)
type Context struct {
@ -47,6 +48,26 @@ func (c *Context) Morph(xmlBytes []byte) {
// Translate XML types to nice types
c.protocol = parsedXml.Translate()
// Start with Go header.
c.Putln("package xgb")
c.Putln("")
c.Putln("/*")
c.Putln("\tThis file was generated by %s.xml on %s.",
c.protocol.Name, time.Now().Format("Jan 2 2006 3:04:05pm MST"))
c.Putln("\tThis file is automatically generated. Edit at your peril!")
c.Putln("*/")
c.Putln("")
// Write imports in comments
if len(c.protocol.Imports) > 0 {
c.Putln("// Imports are not necessary for XGB because everything is ")
c.Putln("// in one package. They are still listed here for reference.")
for _, imp := range c.protocol.Imports {
c.Putln("// import \"%s\"", imp.Name)
}
c.Putln("")
}
// Now write Go source code
for _, typ := range c.protocol.Types {
typ.Define(c)

View File

@ -8,7 +8,7 @@ import (
type Expression interface {
Concrete() bool
Eval() uint
Reduce(prefix, fun string) string
Reduce(prefix string) string
String() string
Initialize(p *Protocol)
}
@ -29,12 +29,12 @@ func (e *Function) Eval() uint {
panic("unreachable")
}
func (e *Function) Reduce(prefix, fun string) string {
return fmt.Sprintf("%s(%s)", e.Name, e.Expr.Reduce(prefix, fun))
func (e *Function) Reduce(prefix string) string {
return fmt.Sprintf("%s(%s)", e.Name, e.Expr.Reduce(prefix))
}
func (e *Function) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *Function) Initialize(p *Protocol) {
@ -89,16 +89,34 @@ func (e *BinaryOp) Eval() uint {
panic("unreachable")
}
func (e *BinaryOp) Reduce(prefix, fun string) string {
func (e *BinaryOp) Reduce(prefix string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
// An incredibly dirty hack to make sure any time we perform an operation
// on a field, we're dealing with ints...
expr1, expr2 := e.Expr1, e.Expr2
switch expr1.(type) {
case *FieldRef:
expr1 = &Function{
Name: "int",
Expr: expr1,
}
}
switch expr2.(type) {
case *FieldRef:
expr2 = &Function{
Name: "int",
Expr: expr2,
}
}
return fmt.Sprintf("(%s %s %s)",
e.Expr1.Reduce(prefix, fun), e.Op, e.Expr2.Reduce(prefix, fun))
expr1.Reduce(prefix), e.Op, expr2.Reduce(prefix))
}
func (e *BinaryOp) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *BinaryOp) Initialize(p *Protocol) {
@ -125,15 +143,15 @@ func (e *UnaryOp) Eval() uint {
panic("unreachable")
}
func (e *UnaryOp) Reduce(prefix, fun string) string {
func (e *UnaryOp) Reduce(prefix string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("(%s (%s))", e.Op, e.Expr.Reduce(prefix, fun))
return fmt.Sprintf("(%s (%s))", e.Op, e.Expr.Reduce(prefix))
}
func (e *UnaryOp) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *UnaryOp) Initialize(p *Protocol) {
@ -152,15 +170,15 @@ func (e *PopCount) Eval() uint {
return popCount(e.Expr.Eval())
}
func (e *PopCount) Reduce(prefix, fun string) string {
func (e *PopCount) Reduce(prefix string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("popCount(%s)", e.Expr.Reduce(prefix, fun))
return fmt.Sprintf("popCount(%s)", e.Expr.Reduce(prefix))
}
func (e *PopCount) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *PopCount) Initialize(p *Protocol) {
@ -179,12 +197,12 @@ func (e *Value) Eval() uint {
return e.v
}
func (e *Value) Reduce(prefix, fun string) string {
func (e *Value) Reduce(prefix string) string {
return fmt.Sprintf("%d", e.v)
}
func (e *Value) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *Value) Initialize(p *Protocol) {}
@ -201,12 +219,12 @@ func (e *Bit) Eval() uint {
return 1 << e.b
}
func (e *Bit) Reduce(prefix, fun string) string {
func (e *Bit) Reduce(prefix string) string {
return fmt.Sprintf("%d", e.Eval())
}
func (e *Bit) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *Bit) Initialize(p *Protocol) {}
@ -224,19 +242,16 @@ func (e *FieldRef) Eval() uint {
panic("unreachable")
}
func (e *FieldRef) Reduce(prefix, fun string) string {
func (e *FieldRef) Reduce(prefix string) string {
val := e.Name
if len(prefix) > 0 {
val = fmt.Sprintf("%s%s", prefix, val)
}
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
}
func (e *FieldRef) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *FieldRef) Initialize(p *Protocol) {
@ -257,16 +272,12 @@ func (e *EnumRef) Eval() uint {
panic("unreachable")
}
func (e *EnumRef) Reduce(prefix, fun string) string {
val := fmt.Sprintf("%s%s", e.EnumKind, e.EnumItem)
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
func (e *EnumRef) Reduce(prefix string) string {
return fmt.Sprintf("%s%s", e.EnumKind, e.EnumItem)
}
func (e *EnumRef) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *EnumRef) Initialize(p *Protocol) {
@ -287,7 +298,7 @@ func (e *SumOf) Eval() uint {
panic("unreachable")
}
func (e *SumOf) Reduce(prefix, fun string) string {
func (e *SumOf) Reduce(prefix string) string {
if len(prefix) > 0 {
return fmt.Sprintf("sum(%s%s)", prefix, e.Name)
}
@ -295,7 +306,7 @@ func (e *SumOf) Reduce(prefix, fun string) string {
}
func (e *SumOf) String() string {
return e.Reduce("", "")
return e.Reduce("")
}
func (e *SumOf) Initialize(p *Protocol) {

View File

@ -3,6 +3,7 @@ package main
import (
"fmt"
"log"
"strings"
)
type Field interface {
@ -13,8 +14,8 @@ type Field interface {
Size() Size
Define(c *Context)
Read(c *Context)
Write(c *Context)
Read(c *Context, prefix string)
Write(c *Context, prefix string)
}
func (pad *PadField) Initialize(p *Protocol) {}
@ -32,7 +33,7 @@ func (p *PadField) XmlName() string {
}
func (f *PadField) SrcType() string {
panic("it is illegal to call SrcType on a SwitchField field")
panic("it is illegal to call SrcType on a PadField field")
}
func (p *PadField) Size() Size {
@ -82,22 +83,48 @@ func (f *ListField) XmlName() string {
}
func (f *ListField) SrcType() string {
if strings.ToLower(f.Type.XmlName()) == "char" {
return fmt.Sprintf("string")
}
return fmt.Sprintf("[]%s", f.Type.SrcName())
}
func (f *ListField) Length() Size {
if f.LengthExpr == nil {
return newExpressionSize(&Function{
Name: "len",
Expr: &FieldRef{
Name: f.SrcName(),
},
})
}
return newExpressionSize(f.LengthExpr)
}
func (f *ListField) Size() Size {
simpleLen := &Function{
Name: "pad",
Expr: newBinaryOp("*", f.LengthExpr, f.Type.Size().Expression),
Expr: newBinaryOp("*", f.Length().Expression, f.Type.Size().Expression),
}
switch f.Type.(type) {
switch field := f.Type.(type) {
case *Struct:
if field.HasList() {
sizeFun := &Function{
Name: fmt.Sprintf("%sListSize", f.Type.SrcName()),
Expr: &FieldRef{Name: f.SrcName()},
}
return newExpressionSize(sizeFun)
} else {
return newExpressionSize(simpleLen)
}
case *Union:
return newExpressionSize(simpleLen)
// sizeFun := &Function{
// Name: fmt.Sprintf("%sListSize", f.Type.SrcName()),
// Expr: &FieldRef{Name: f.SrcName()},
// }
// return newExpressionSize(sizeFun)
case *Base:
return newExpressionSize(simpleLen)
case *Resource:
@ -152,6 +179,7 @@ func (f *ExprField) Initialize(p *Protocol) {
}
type ValueField struct {
Parent interface{}
MaskType Type
MaskName string
ListName string
@ -170,7 +198,34 @@ func (f *ValueField) SrcType() string {
}
func (f *ValueField) Size() Size {
return f.MaskType.Size()
maskSize := f.MaskType.Size()
listSize := newExpressionSize(&Function{
Name: "pad",
Expr: &BinaryOp{
Op: "*",
Expr1: &Value{v: 4},
Expr2: &PopCount{
Expr: &Function{
Name: "int",
Expr: &FieldRef{
Name: f.MaskName,
},
},
},
},
})
return maskSize.Add(listSize)
}
func (f *ValueField) ListLength() Size {
return newExpressionSize(&PopCount{
Expr: &Function{
Name: "int",
Expr: &FieldRef{
Name: f.MaskName,
},
},
})
}
func (f *ValueField) Initialize(p *Protocol) {

View File

@ -1,5 +1,9 @@
package main
import (
"fmt"
)
// xgbResourceIdName is the name of the type used for all resource identifiers.
// As of right now, it needs to be declared somewhere manually.
var xgbGenResourceIdName = "Id"
@ -94,26 +98,28 @@ func (f *PadField) Define(c *Context) {
c.Putln("// padding: %d bytes", f.Bytes)
}
func (f *PadField) Read(c *Context) {
func (f *PadField) Read(c *Context, prefix string) {
c.Putln("b += %s // padding", f.Size())
}
func (f *PadField) Write(c *Context) {
func (f *PadField) Write(c *Context, prefix string) {
c.Putln("b += %s // padding", f.Size())
}
// Local fields
func (f *LocalField) Define(c *Context) {
c.Putln("// local field: %s %s", f.SrcName(), f.Type.SrcName())
panic("unreachable")
}
func (f *LocalField) Read(c *Context) {
func (f *LocalField) Read(c *Context, prefix string) {
c.Putln("// reading local field: %s (%s) :: %s",
f.SrcName(), f.Size(), f.Type.SrcName())
panic("unreachable")
}
func (f *LocalField) Write(c *Context) {
c.Putln("// writing local field: %s (%s) :: %s",
func (f *LocalField) Write(c *Context, prefix string) {
c.Putln("// skip writing local field: %s (%s) :: %s",
f.SrcName(), f.Size(), f.Type.SrcName())
}
@ -121,32 +127,49 @@ func (f *LocalField) Write(c *Context) {
func (f *ExprField) Define(c *Context) {
c.Putln("// expression field: %s %s (%s)",
f.SrcName(), f.Type.SrcName(), f.Expr)
panic("unreachable")
}
func (f *ExprField) Read(c *Context) {
func (f *ExprField) Read(c *Context, prefix string) {
c.Putln("// reading expression field: %s (%s) (%s) :: %s",
f.SrcName(), f.Size(), f.Expr, f.Type.SrcName())
panic("unreachable")
}
func (f *ExprField) Write(c *Context) {
c.Putln("// writing expression field: %s (%s) (%s) :: %s",
f.SrcName(), f.Size(), f.Expr, f.Type.SrcName())
func (f *ExprField) Write(c *Context, prefix string) {
// Special case for bools, grrr.
if f.Type.SrcName() == "bool" {
c.Putln("buf[b] = byte(%s)", f.Expr.Reduce(prefix))
c.Putln("b += 1")
} else {
WriteSimpleSingleField(c, f.Expr.Reduce(prefix), f.Type)
}
}
// Value field
func (f *ValueField) Define(c *Context) {
c.Putln("// valueparam field: type: %s, mask name: %s, list name: %s",
f.MaskType.SrcName(), f.MaskName, f.ListName)
panic("todo")
}
func (f *ValueField) Read(c *Context) {
func (f *ValueField) Read(c *Context, prefix string) {
c.Putln("// reading valueparam: type: %s, mask name: %s, list name: %s",
f.MaskType.SrcName(), f.MaskName, f.ListName)
panic("todo")
}
func (f *ValueField) Write(c *Context) {
c.Putln("// writing valueparam: type: %s, mask name: %s, list name: %s",
f.MaskType.SrcName(), f.MaskName, f.ListName)
func (f *ValueField) Write(c *Context, prefix string) {
// big time mofos
if rq, ok := f.Parent.(*Request); !ok || rq.SrcName() != "ConfigureWindow" {
WriteSimpleSingleField(c,
fmt.Sprintf("%s%s", prefix, f.MaskName), f.MaskType)
}
c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
c.Putln("Put32(buf[b:], %s%s[i])", prefix, f.ListName)
c.Putln("b += 4")
c.Putln("}")
c.Putln("b = pad(b)")
}
// Switch field
@ -155,12 +178,12 @@ func (f *SwitchField) Define(c *Context) {
panic("todo")
}
func (f *SwitchField) Read(c *Context) {
func (f *SwitchField) Read(c *Context, prefix string) {
c.Putln("// reading switch field: %s (%s)", f.Name, f.Expr)
panic("todo")
}
func (f *SwitchField) Write(c *Context) {
func (f *SwitchField) Write(c *Context, prefix string) {
c.Putln("// writing switch field: %s (%s)", f.Name, f.Expr)
panic("todo")
}

View File

@ -1,5 +1,9 @@
package main
import (
"fmt"
)
// Error types
func (e *Error) Define(c *Context) {
c.Putln("// Error definition %s (%d)", e.SrcName(), e.Number)
@ -20,9 +24,8 @@ func (e *Error) Define(c *Context) {
// error struct.
e.Read(c)
// Makes sure that this error type is an Error interface.
c.Putln("func (v %s) ImplementsError() { }", e.ErrType())
c.Putln("")
// Makes sure this error type implements the xgb.Error interface.
e.ImplementsError(c)
// Let's the XGB event loop read this error.
c.Putln("func init() {")
@ -33,18 +36,18 @@ func (e *Error) Define(c *Context) {
func (e *Error) Read(c *Context) {
c.Putln("// Error read %s", e.SrcName())
c.Putln("func New%s(buf []byte) %s {", e.ErrType(), e.ErrType())
c.Putln("func New%s(buf []byte) Error {", e.ErrType())
c.Putln("v := %s{}", e.ErrType())
c.Putln("v.NiceName = \"%s\"", e.SrcName())
c.Putln("")
c.Putln("b := 1 // skip error determinant")
c.Putln("b += 1 // don't read error number")
c.Putln("")
c.Putln("v.Sequence = get16(buf[b:])")
c.Putln("v.Sequence = Get16(buf[b:])")
c.Putln("b += 2")
c.Putln("")
for _, field := range e.Fields {
field.Read(c)
field.Read(c, "v.")
c.Putln("")
}
c.Putln("return v")
@ -52,6 +55,24 @@ func (e *Error) Read(c *Context) {
c.Putln("")
}
// ImplementsError writes functions to implement the XGB Error interface.
func (e *Error) ImplementsError(c *Context) {
c.Putln("func (err %s) ImplementsError() { }", e.ErrType())
c.Putln("")
c.Putln("func (err %s) SequenceId() uint16 {", e.ErrType())
c.Putln("return err.Sequence")
c.Putln("}")
c.Putln("")
c.Putln("func (err %s) BadId() Id {", e.ErrType())
c.Putln("return Id(err.BadValue)")
c.Putln("}")
c.Putln("")
c.Putln("func (err %s) Error() string {", e.ErrType())
FieldString(c, e.Fields, e.ErrConst())
c.Putln("}")
c.Putln("")
}
// ErrorCopy types
func (e *ErrorCopy) Define(c *Context) {
c.Putln("// ErrorCopy definition %s (%d)", e.SrcName(), e.Number)
@ -65,9 +86,8 @@ func (e *ErrorCopy) Define(c *Context) {
// error struct.
e.Read(c)
// Makes sure that this error type is an Error interface.
c.Putln("func (err %s) ImplementsError() { }", e.ErrType())
c.Putln("")
// Makes sure this error type implements the xgb.Error interface.
e.ImplementsError(c)
// Let's the XGB know how to read this error.
c.Putln("func init() {")
@ -77,8 +97,54 @@ func (e *ErrorCopy) Define(c *Context) {
}
func (e *ErrorCopy) Read(c *Context) {
c.Putln("func New%s(buf []byte) %s {", e.ErrType(), e.ErrType())
c.Putln("return %s(New%s(buf))", e.ErrType(), e.Old.(*Error).ErrType())
c.Putln("func New%s(buf []byte) Error {", e.ErrType())
c.Putln("v := %s(New%s(buf).(%s))",
e.ErrType(), e.Old.(*Error).ErrType(), e.Old.(*Error).ErrType())
c.Putln("v.NiceName = \"%s\"", e.SrcName())
c.Putln("return v")
c.Putln("}")
c.Putln("")
}
// ImplementsError writes functions to implement the XGB Error interface.
func (e *ErrorCopy) ImplementsError(c *Context) {
c.Putln("func (err %s) ImplementsError() { }", e.ErrType())
c.Putln("")
c.Putln("func (err %s) SequenceId() uint16 {", e.ErrType())
c.Putln("return err.Sequence")
c.Putln("}")
c.Putln("")
c.Putln("func (err %s) BadId() Id {", e.ErrType())
c.Putln("return Id(err.BadValue)")
c.Putln("}")
c.Putln("")
c.Putln("func (err %s) Error() string {", e.ErrType())
FieldString(c, e.Old.(*Error).Fields, e.ErrConst())
c.Putln("}")
c.Putln("")
}
// FieldString works for both Error and ErrorCopy. It assembles all of the
// fields in an error and formats them into a single string.
func FieldString(c *Context, fields []Field, errName string) {
c.Putln("fieldVals := make([]string, 0, %d)", len(fields))
c.Putln("fieldVals = append(fieldVals, \"NiceName: \" + err.NiceName)")
c.Putln("fieldVals = append(fieldVals, " +
"sprintf(\"Sequence: %s\", err.Sequence))", "%d")
for _, field := range fields {
switch field.(type) {
case *PadField:
continue
default:
if field.SrcType() == "string" {
c.Putln("fieldVals = append(fieldVals, \"%s: \" + err.%s)",
field.SrcName(), field.SrcName())
} else {
format := fmt.Sprintf("sprintf(\"%s: %s\", err.%s)",
field.SrcName(), "%d", field.SrcName())
c.Putln("fieldVals = append(fieldVals, %s)", format)
}
}
}
c.Putln("return \"%s {\" + stringsJoin(fieldVals, \", \") + \"}\"", errName)
}

View File

@ -38,17 +38,17 @@ func (e *Event) Define(c *Context) {
func (e *Event) Read(c *Context) {
c.Putln("// Event read %s", e.SrcName())
c.Putln("func New%s(buf []byte) %s {", e.EvType(), e.EvType())
c.Putln("func New%s(buf []byte) Event {", e.EvType())
c.Putln("v := %s{}", e.EvType())
c.Putln("b := 1 // don't read event number")
c.Putln("")
for i, field := range e.Fields {
if i == 1 && !e.NoSequence {
c.Putln("v.Sequence = get16(buf[b:])")
c.Putln("v.Sequence = Get16(buf[b:])")
c.Putln("b += 2")
c.Putln("")
}
field.Read(c)
field.Read(c, "v.")
c.Putln("")
}
c.Putln("return v")
@ -71,7 +71,7 @@ func (e *Event) Write(c *Context) {
c.Putln("b += 2 // skip sequence number")
c.Putln("")
}
field.Write(c)
field.Write(c, "v.")
c.Putln("")
}
c.Putln("return buf")
@ -108,15 +108,16 @@ func (e *EventCopy) Define(c *Context) {
}
func (e *EventCopy) Read(c *Context) {
c.Putln("func New%s(buf []byte) %s {", e.EvType(), e.EvType())
c.Putln("return %s(New%s(buf))", e.EvType(), e.Old.(*Event).EvType())
c.Putln("func New%s(buf []byte) Event {", e.EvType())
c.Putln("return %s(New%s(buf).(%s))",
e.EvType(), e.Old.(*Event).EvType(), e.Old.(*Event).EvType())
c.Putln("}")
c.Putln("")
}
func (e *EventCopy) Write(c *Context) {
c.Putln("func (v %s) Bytes() []byte {", e.EvType())
c.Putln("return %s(ev).Bytes()", e.Old.(*Event).EvType())
c.Putln("return %s(v).Bytes()", e.Old.(*Event).EvType())
c.Putln("}")
c.Putln("")
}

View File

@ -3,74 +3,107 @@ package main
import (
"fmt"
"log"
"strings"
)
// List fields
func (f *ListField) Define(c *Context) {
c.Putln("%s []%s // size: %s",
f.SrcName(), f.Type.SrcName(), f.Size())
c.Putln("%s %s // size: %s",
f.SrcName(), f.SrcType(), f.Size())
}
func (f *ListField) Read(c *Context) {
func (f *ListField) Read(c *Context, prefix string) {
switch t := f.Type.(type) {
case *Resource:
length := f.LengthExpr.Reduce("v.", "")
c.Putln("v.%s = make([]Id, %s)", f.SrcName(), length)
c.Putln("for i := 0; i < %s; i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
length := f.LengthExpr.Reduce(prefix)
c.Putln("%s%s = make([]Id, %s)", prefix, f.SrcName(), length)
c.Putln("for i := 0; i < int(%s); i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
case *Base:
length := f.LengthExpr.Reduce("v.", "")
c.Putln("v.%s = make([]%s, %s)", f.SrcName(), t.SrcName(), length)
if t.SrcName() == "byte" {
c.Putln("copy(v.%s[:%s], buf[b:])", f.SrcName(), length)
c.Putln("b += pad(%s)", length)
length := f.LengthExpr.Reduce(prefix)
if strings.ToLower(t.XmlName()) == "char" {
c.Putln("{")
c.Putln("byteString := make([]%s, %s)", t.SrcName(), length)
c.Putln("copy(byteString[:%s], buf[b:])", length)
c.Putln("%s%s = string(byteString)", prefix, f.SrcName())
c.Putln("b += pad(int(%s))", length)
c.Putln("}")
} else if t.SrcName() == "byte" {
c.Putln("%s%s = make([]%s, %s)",
prefix, f.SrcName(), t.SrcName(), length)
c.Putln("copy(%s%s[:%s], buf[b:])", prefix, f.SrcName(), length)
c.Putln("b += pad(int(%s))", length)
} else {
c.Putln("for i := 0; i < %s; i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
c.Putln("%s%s = make([]%s, %s)",
prefix, f.SrcName(), t.SrcName(), length)
c.Putln("for i := 0; i < int(%s); i++ {", length)
ReadSimpleSingleField(c,
fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
}
case *TypeDef:
length := f.LengthExpr.Reduce(prefix)
c.Putln("%s%s = make([]%s, %s)",
prefix, f.SrcName(), t.SrcName(), length)
c.Putln("for i := 0; i < int(%s); i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
case *Union:
c.Putln("v.%s = make([]%s, %s)",
f.SrcName(), t.SrcName(), f.LengthExpr.Reduce("v.", ""))
c.Putln("b += Read%sList(buf[b:], v.%s)", t.SrcName(), f.SrcName())
c.Putln("%s%s = make([]%s, %s)",
prefix, f.SrcName(), t.SrcName(), f.LengthExpr.Reduce(prefix))
c.Putln("b += Read%sList(buf[b:], %s%s)",
t.SrcName(), prefix, f.SrcName())
case *Struct:
c.Putln("v.%s = make([]%s, %s)",
f.SrcName(), t.SrcName(), f.LengthExpr.Reduce("v.", ""))
c.Putln("b += Read%sList(buf[b:], v.%s)", t.SrcName(), f.SrcName())
c.Putln("%s%s = make([]%s, %s)",
prefix, f.SrcName(), t.SrcName(), f.LengthExpr.Reduce(prefix))
c.Putln("b += Read%sList(buf[b:], %s%s)",
t.SrcName(), prefix, f.SrcName())
default:
log.Panicf("Cannot read list field '%s' with %T type.",
f.XmlName(), f.Type)
}
}
func (f *ListField) Write(c *Context) {
func (f *ListField) Write(c *Context, prefix string) {
switch t := f.Type.(type) {
case *Resource:
length := f.LengthExpr.Reduce("v.", "")
c.Putln("for i := 0; i < %s; i++", length)
WriteSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
length := f.Length().Reduce(prefix)
c.Putln("for i := 0; i < int(%s); i++ {", length)
WriteSimpleSingleField(c,
fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
case *Base:
length := f.LengthExpr.Reduce("v.", "")
length := f.Length().Reduce(prefix)
if t.SrcName() == "byte" {
c.Putln("copy(buf[b:], v.%s[:%s])", f.SrcName(), length)
c.Putln("b += pad(%s)", length)
c.Putln("copy(buf[b:], %s%s[:%s])", prefix, f.SrcName(), length)
c.Putln("b += pad(int(%s))", length)
} else {
c.Putln("for i := 0; i < %s; i++ {", length)
WriteSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
c.Putln("for i := 0; i < int(%s); i++ {", length)
WriteSimpleSingleField(c,
fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
}
case *TypeDef:
length := f.Length().Reduce(prefix)
c.Putln("for i := 0; i < int(%s); i++ {", length)
WriteSimpleSingleField(c,
fmt.Sprintf("%s%s[i]", prefix, f.SrcName()), t)
c.Putln("}")
c.Putln("b = pad(b)")
case *Union:
c.Putln("b += %sListBytes(buf[b:], v.%s)", t.SrcName(), f.SrcName())
c.Putln("b += %sListBytes(buf[b:], %s%s)",
t.SrcName(), prefix, f.SrcName())
case *Struct:
c.Putln("b += %sListBytes(buf[b:], v.%s)", t.SrcName(), f.SrcName())
c.Putln("b += %sListBytes(buf[b:], %s%s)",
t.SrcName(), prefix, f.SrcName())
default:
log.Panicf("Cannot read list field '%s' with %T type.",
log.Panicf("Cannot write list field '%s' with %T type.",
f.XmlName(), f.Type)
}
}

View File

@ -1,19 +0,0 @@
package main
func (r *Request) Define(c *Context) {
c.Putln("// Request %s", r.SrcName())
c.Putln("// size: %s", r.Size(c))
c.Putln("")
if r.Reply != nil {
c.Putln("// Request reply for %s", r.SrcName())
c.Putln("// size: %s", r.Reply.Size())
c.Putln("type %s struct {", r.ReplyName())
c.Putln("Sequence uint16")
for _, field := range r.Reply.Fields {
field.Define(c)
}
c.Putln("}")
c.Putln("")
}
}

View File

@ -0,0 +1,140 @@
package main
import (
"fmt"
"strings"
)
func (r *Request) Define(c *Context) {
c.Putln("// Request %s", r.SrcName())
c.Putln("// size: %s", r.Size(c))
if r.Reply != nil {
c.Putln("func (c *Conn) %s(%s) (*%s, error) {",
r.SrcName(), r.ParamNameTypes(), r.ReplyName())
c.Putln("return c.%s(c.%s(%s))",
r.ReplyName(), r.ReqName(), r.ParamNames())
c.Putln("}")
c.Putln("")
r.WriteRequest(c)
r.ReadReply(c)
} else {
c.Putln("// Write request to wire for %s", r.SrcName())
c.Putln("func (c *Conn) %s(%s) {", r.SrcName(), r.ParamNameTypes())
r.WriteRequestFields(c)
c.Putln("c.sendRequest(false, buf)")
c.Putln("}")
c.Putln("")
}
}
func (r *Request) ReadReply(c *Context) {
c.Putln("// Request reply for %s", r.SrcName())
c.Putln("// size: %s", r.Reply.Size())
c.Putln("type %s struct {", r.ReplyName())
c.Putln("Sequence uint16")
c.Putln("Length uint32")
for _, field := range r.Reply.Fields {
field.Define(c)
}
c.Putln("}")
c.Putln("")
c.Putln("// Read reply %s", r.SrcName())
c.Putln("func (c *Conn) %s(cook *Cookie) (*%s, error) {",
r.ReplyName(), r.ReplyName())
c.Putln("buf, err := c.waitForReply(cook)")
c.Putln("if err != nil {")
c.Putln("return nil, err")
c.Putln("}")
c.Putln("")
c.Putln("v := new(%s)", r.ReplyName())
c.Putln("b := 1 // skip reply determinant")
c.Putln("")
for i, field := range r.Reply.Fields {
if i == 1 {
c.Putln("v.Sequence = Get16(buf[b:])")
c.Putln("b += 2")
c.Putln("")
c.Putln("v.Length = Get32(buf[b:]) // 4-byte units")
c.Putln("b += 4")
c.Putln("")
}
field.Read(c, "v.")
c.Putln("")
}
c.Putln("return v, nil")
c.Putln("}")
c.Putln("")
}
func (r *Request) WriteRequest(c *Context) {
c.Putln("// Write request to wire for %s", r.SrcName())
c.Putln("func (c *Conn) %s(%s) *Cookie {", r.ReqName(), r.ParamNameTypes())
r.WriteRequestFields(c)
c.Putln("return c.sendRequest(true, buf)")
c.Putln("}")
c.Putln("")
}
func (r *Request) WriteRequestFields(c *Context) {
c.Putln("size := %s", r.Size(c))
c.Putln("b := 0")
c.Putln("buf := make([]byte, size)")
c.Putln("")
c.Putln("buf[b] = %d // request opcode", r.Opcode)
c.Putln("b += 1")
c.Putln("")
for i, field := range r.Fields {
if i == 1 {
c.Putln("Put16(buf[b:], uint16(size / 4)) "+
"// write request size in 4-byte units")
c.Putln("b += 2")
c.Putln("")
}
field.Write(c, "")
c.Putln("")
}
}
func (r *Request) ParamNames() string {
names := make([]string, 0, len(r.Fields))
for _, field := range r.Fields {
switch f := field.(type) {
case *ValueField:
names = append(names, f.MaskName)
names = append(names, f.ListName)
case *PadField:
continue
case *ExprField:
continue
default:
names = append(names, fmt.Sprintf("%s", field.SrcName()))
}
}
return strings.Join(names, ",")
}
func (r *Request) ParamNameTypes() string {
nameTypes := make([]string, 0, len(r.Fields))
for _, field := range r.Fields {
switch f := field.(type) {
case *ValueField:
// mofos...
if r.SrcName() != "ConfigureWindow" {
nameTypes = append(nameTypes,
fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
}
nameTypes = append(nameTypes,
fmt.Sprintf("%s []uint32", f.ListName))
case *PadField:
continue
case *ExprField:
continue
default:
nameTypes = append(nameTypes,
fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))
}
}
return strings.Join(nameTypes, ",")
}

View File

@ -12,17 +12,17 @@ func (f *SingleField) Define(c *Context) {
func ReadSimpleSingleField(c *Context, name string, typ Type) {
switch t := typ.(type) {
case *Resource:
c.Putln("%s = get32(buf[b:])", name)
c.Putln("%s = Id(Get32(buf[b:]))", name)
case *TypeDef:
switch t.Size().Eval() {
case 1:
c.Putln("%s = %s(buf[b])", name, t.SrcName())
case 2:
c.Putln("%s = %s(get16(buf[b:]))", name, t.SrcName())
c.Putln("%s = %s(Get16(buf[b:]))", name, t.SrcName())
case 4:
c.Putln("%s = %s(get32(buf[b:]))", name, t.SrcName())
c.Putln("%s = %s(Get32(buf[b:]))", name, t.SrcName())
case 8:
c.Putln("%s = %s(get64(buf[b:]))", name, t.SrcName())
c.Putln("%s = %s(Get64(buf[b:]))", name, t.SrcName())
}
case *Base:
// If this is a bool, stop short and do something special.
@ -40,11 +40,11 @@ func ReadSimpleSingleField(c *Context, name string, typ Type) {
case 1:
val = fmt.Sprintf("buf[b]")
case 2:
val = fmt.Sprintf("get16(buf[b:])")
val = fmt.Sprintf("Get16(buf[b:])")
case 4:
val = fmt.Sprintf("get32(buf[b:])")
val = fmt.Sprintf("Get32(buf[b:])")
case 8:
val = fmt.Sprintf("get64(buf[b:])")
val = fmt.Sprintf("Get64(buf[b:])")
}
// We need to convert base types if they aren't uintXX or byte
@ -61,20 +61,20 @@ func ReadSimpleSingleField(c *Context, name string, typ Type) {
c.Putln("b += %s", typ.Size())
}
func (f *SingleField) Read(c *Context) {
func (f *SingleField) Read(c *Context, prefix string) {
switch t := f.Type.(type) {
case *Resource:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
ReadSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *TypeDef:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
ReadSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *Base:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
ReadSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *Struct:
c.Putln("v.%s = %s{}", f.SrcName(), t.SrcName())
c.Putln("b += Read%s(buf[b:], &v.%s)", t.SrcName(), f.SrcName())
c.Putln("%s%s = %s{}", prefix, f.SrcName(), t.SrcName())
c.Putln("b += Read%s(buf[b:], &%s%s)", t.SrcName(), prefix, f.SrcName())
case *Union:
c.Putln("v.%s = %s{}", f.SrcName(), t.SrcName())
c.Putln("b += Read%s(buf[b:], &v.%s)", t.SrcName(), f.SrcName())
c.Putln("%s%s = %s{}", prefix, f.SrcName(), t.SrcName())
c.Putln("b += Read%s(buf[b:], &%s%s)", t.SrcName(), prefix, f.SrcName())
default:
log.Panicf("Cannot read field '%s' with %T type.", f.XmlName(), f.Type)
}
@ -83,17 +83,17 @@ func (f *SingleField) Read(c *Context) {
func WriteSimpleSingleField(c *Context, name string, typ Type) {
switch t := typ.(type) {
case *Resource:
c.Putln("put32(buf[b:], uint32(%s))", name)
c.Putln("Put32(buf[b:], uint32(%s))", name)
case *TypeDef:
switch t.Size().Eval() {
case 1:
c.Putln("buf[b] = byte(%s)", name)
case 2:
c.Putln("put16(buf[b:], uint16(%s))", name)
c.Putln("Put16(buf[b:], uint16(%s))", name)
case 4:
c.Putln("put32(buf[b:], uint32(%s))", name)
c.Putln("Put32(buf[b:], uint32(%s))", name)
case 8:
c.Putln("put64(buf[b:], uint64(%s))", name)
c.Putln("Put64(buf[b:], uint64(%s))", name)
}
case *Base:
// If this is a bool, stop short and do something special.
@ -115,21 +115,21 @@ func WriteSimpleSingleField(c *Context, name string, typ Type) {
}
case 2:
if t.SrcName() != "uint16" {
c.Putln("put16(buf[b:], uint16(%s))", name)
c.Putln("Put16(buf[b:], uint16(%s))", name)
} else {
c.Putln("put16(buf[b:], %s)", name)
c.Putln("Put16(buf[b:], %s)", name)
}
case 4:
if t.SrcName() != "uint32" {
c.Putln("put32(buf[b:], uint32(%s))", name)
c.Putln("Put32(buf[b:], uint32(%s))", name)
} else {
c.Putln("put32(buf[b:], %s)", name)
c.Putln("Put32(buf[b:], %s)", name)
}
case 8:
if t.SrcName() != "uint64" {
c.Putln("put64(buf[b:], uint64(%s))", name)
c.Putln("Put64(buf[b:], uint64(%s))", name)
} else {
c.Putln("put64(buf[b:], %s)", name)
c.Putln("Put64(buf[b:], %s)", name)
}
}
default:
@ -140,23 +140,23 @@ func WriteSimpleSingleField(c *Context, name string, typ Type) {
c.Putln("b += %s", typ.Size())
}
func (f *SingleField) Write(c *Context) {
func (f *SingleField) Write(c *Context, prefix string) {
switch t := f.Type.(type) {
case *Resource:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
WriteSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *TypeDef:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
WriteSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *Base:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
WriteSimpleSingleField(c, fmt.Sprintf("%s%s", prefix, f.SrcName()), t)
case *Union:
c.Putln("{")
c.Putln("unionBytes := v.%s.Bytes()", f.SrcName())
c.Putln("unionBytes := %s%s.Bytes()", prefix, f.SrcName())
c.Putln("copy(buf[b:], unionBytes)")
c.Putln("b += pad(len(unionBytes))")
c.Putln("}")
case *Struct:
c.Putln("{")
c.Putln("structBytes := v.%s.Bytes()", f.SrcName())
c.Putln("structBytes := %s%s.Bytes()", prefix, f.SrcName())
c.Putln("copy(buf[b:], structBytes)")
c.Putln("b += pad(len(structBytes))")
c.Putln("}")

View File

@ -22,8 +22,11 @@ func (s *Struct) Define(c *Context) {
// Write function that writes a list of this struct.
s.WriteList(c)
// Write function that computes the size of a list of these structs.
// Write function that computes the size of a list of these structs,
// IF there is a list field in this struct.
if s.HasList() {
s.WriteListSize(c)
}
}
// Read for a struct creates a function 'ReadStructName' that takes a source
@ -37,7 +40,8 @@ func (s *Struct) Read(c *Context) {
c.Putln("b := 0")
c.Putln("")
for _, field := range s.Fields {
field.Read(c)
field.Read(c, "v.")
c.Putln("")
}
c.Putln("return b")
@ -68,11 +72,12 @@ func (s *Struct) ReadList(c *Context) {
func (s *Struct) Write(c *Context) {
c.Putln("// Struct write %s", s.SrcName())
c.Putln("func (v %s) Bytes() []byte {", s.SrcName())
c.Putln("buf := make([]byte, %s)", s.Size().Reduce("v.", ""))
c.Putln("buf := make([]byte, %s)", s.Size().Reduce("v."))
c.Putln("b := 0")
c.Putln("")
for _, field := range s.Fields {
field.Write(c)
field.Write(c, "v.")
c.Putln("")
}
c.Putln("return buf")
c.Putln("}")
@ -87,7 +92,7 @@ func (s *Struct) WriteList(c *Context) {
c.Putln("var structBytes []byte")
c.Putln("for _, item := range list {")
c.Putln("structBytes = item.Bytes()")
c.Putln("copy(buf[b:], len(structBytes))")
c.Putln("copy(buf[b:], structBytes)")
c.Putln("b += pad(len(structBytes))")
c.Putln("}")
c.Putln("return b")
@ -100,7 +105,7 @@ func (s *Struct) WriteListSize(c *Context) {
c.Putln("func %sListSize(list []%s) int {", s.SrcName(), s.SrcName())
c.Putln("size := 0")
c.Putln("for _, item := range list {")
c.Putln("size += %s", s.Size().Reduce("item.", ""))
c.Putln("size += %s", s.Size().Reduce("item."))
c.Putln("}")
c.Putln("return size")
c.Putln("}")

View File

@ -34,9 +34,6 @@ func (u *Union) Define(c *Context) {
// Write function that writes a list of this union.
u.WriteList(c)
// Write function that computes the size of a list of these unions.
u.WriteListSize(c)
}
func (u *Union) New(c *Context) {
@ -49,7 +46,7 @@ func (u *Union) New(c *Context) {
c.Putln("var b int")
c.Putln("buf := make([]byte, %s)", u.Size())
c.Putln("")
field.Write(c)
field.Write(c, "")
c.Putln("")
c.Putln("// Create the Union type")
c.Putln("v := %s{}", u.SrcName())
@ -58,7 +55,7 @@ func (u *Union) New(c *Context) {
c.Putln("")
for _, field2 := range u.Fields {
c.Putln("b = 0 // always read the same bytes")
field2.Read(c)
field2.Read(c, "v.")
c.Putln("")
}
c.Putln("return v")
@ -74,7 +71,7 @@ func (u *Union) Read(c *Context) {
c.Putln("")
for _, field := range u.Fields {
c.Putln("b = 0 // re-read the same bytes")
field.Read(c)
field.Read(c, "v.")
c.Putln("")
}
c.Putln("return %s", u.Size())
@ -106,10 +103,10 @@ func (u *Union) Write(c *Context) {
c.Putln("// Each field in a union must contain the same data.")
c.Putln("// So simply pick the first field and write that to the wire.")
c.Putln("func (v %s) Bytes() []byte {", u.SrcName())
c.Putln("buf := make([]byte, %s)", u.Size().Reduce("v.", ""))
c.Putln("buf := make([]byte, %s)", u.Size().Reduce("v."))
c.Putln("b := 0")
c.Putln("")
u.Fields[0].Write(c)
u.Fields[0].Write(c, "v.")
c.Putln("return buf")
c.Putln("}")
c.Putln("")
@ -123,7 +120,7 @@ func (u *Union) WriteList(c *Context) {
c.Putln("var unionBytes []byte")
c.Putln("for _, item := range list {")
c.Putln("unionBytes = item.Bytes()")
c.Putln("copy(buf[b:], len(unionBytes))")
c.Putln("copy(buf[b:], unionBytes)")
c.Putln("b += pad(len(unionBytes))")
c.Putln("}")
c.Putln("return b")
@ -136,7 +133,7 @@ func (u *Union) WriteListSize(c *Context) {
c.Putln("func %sListSize(list []%s) int {", u.SrcName(), u.SrcName())
c.Putln("size := 0")
c.Putln("for _, item := range list {")
c.Putln("size += %s", u.Size().Reduce("item.", ""))
c.Putln("size += %s", u.Size().Reduce("item."))
c.Putln("}")
c.Putln("return size")
c.Putln("}")

View File

@ -65,6 +65,10 @@ func (r *Request) ReplyName() string {
return fmt.Sprintf("%sReply", r.SrcName())
}
func (r *Request) ReqName() string {
return fmt.Sprintf("%sRequest", r.SrcName())
}
// Size for Request needs a context.
// Namely, if this is an extension, we need to account for *four* bytes
// of a header (extension opcode, request opcode, and the sequence number).
@ -80,7 +84,20 @@ func (r *Request) Size(c *Context) Size {
}
for _, field := range r.Fields {
switch field.(type) {
case *LocalField:
continue
case *SingleField:
// mofos!!!
if r.SrcName() == "ConfigureWindow" &&
field.SrcName() == "ValueMask" {
continue
}
size = size.Add(field.Size())
default:
size = size.Add(field.Size())
}
}
return size
}

View File

@ -138,7 +138,7 @@ func (x *XMLEvent) Translate() *Event {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
ev.Fields[i] = field.Translate()
ev.Fields[i] = field.Translate(ev)
}
return ev
}
@ -158,7 +158,7 @@ func (x *XMLError) Translate() *Error {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
err.Fields[i] = field.Translate()
err.Fields[i] = field.Translate(err)
}
return err
}
@ -177,7 +177,7 @@ func (x *XMLStruct) Translate() *Struct {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
s.Fields[i] = field.Translate()
s.Fields[i] = field.Translate(s)
}
return s
}
@ -188,7 +188,7 @@ func (x *XMLUnion) Translate() *Union {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
u.Fields[i] = field.Translate()
u.Fields[i] = field.Translate(u)
}
return u
}
@ -202,7 +202,7 @@ func (x *XMLRequest) Translate() *Request {
Reply: x.Reply.Translate(),
}
for i, field := range x.Fields {
r.Fields[i] = field.Translate()
r.Fields[i] = field.Translate(r)
}
// Address bug (or legacy code) in QueryTextExtents.
@ -230,7 +230,7 @@ func (x *XMLReply) Translate() *Reply {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
r.Fields[i] = field.Translate()
r.Fields[i] = field.Translate(r)
}
return r
}
@ -309,7 +309,7 @@ func (x *XMLExpression) Translate() Expression {
panic("unreachable")
}
func (x *XMLField) Translate() Field {
func (x *XMLField) Translate(parent interface{}) Field {
switch x.XMLName.Local {
case "pad":
return &PadField{
@ -339,6 +339,7 @@ func (x *XMLField) Translate() Field {
}
case "valueparam":
return &ValueField{
Parent: parent,
MaskType: newTranslation(x.ValueMaskType),
MaskName: x.ValueMaskName,
ListName: x.ValueListName,
@ -365,7 +366,7 @@ func (x *XMLBitcase) Translate() *Bitcase {
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
b.Fields[i] = field.Translate()
b.Fields[i] = field.Translate(b)
}
return b
}

View File

@ -334,6 +334,18 @@ func (s *Struct) Initialize(p *Protocol) {
}
}
// HasList returns whether there is a field in this struct that is a list.
// When true, a more involved calculation is necessary to compute this struct's
// size.
func (s *Struct) HasList() bool {
for _, field := range s.Fields {
if _, ok := field.(*ListField); ok {
return true
}
}
return false
}
type Union struct {
srcName string
xmlName string

11215
nexgb/xproto.go Normal file

File diff suppressed because it is too large Load Diff