aboutsummaryrefslogtreecommitdiff
path: root/nexgb
diff options
context:
space:
mode:
authoraarzilli <alessandro.arzilli@gmail.com>2017-01-18 09:53:26 +0100
committerPřemysl Janouch <p@janouch.name>2018-09-08 16:49:26 +0200
commit1c01d79ba14a802c603ca2e5bbd35156e3363b85 (patch)
tree5ba818deb4c33dd44df9b5c66dc9d45f3b1672e5 /nexgb
parenta102c4056f6b01035772cf79060012ff800c9669 (diff)
downloadhaven-1c01d79ba14a802c603ca2e5bbd35156e3363b85.tar.gz
haven-1c01d79ba14a802c603ca2e5bbd35156e3363b85.tar.xz
haven-1c01d79ba14a802c603ca2e5bbd35156e3363b85.zip
Changed xgbgen to support xcb-proto 1.12
* Added minimal support for switch fields. * Changed the way Size is calculated to accomodate for lists inside structs (added to randr) * Removed heuristic to place alignment gaps, they are now explicitly described in xml
Diffstat (limited to 'nexgb')
-rw-r--r--nexgb/xgbgen/aligngap.go120
-rw-r--r--nexgb/xgbgen/context.go19
-rw-r--r--nexgb/xgbgen/expression.go54
-rw-r--r--nexgb/xgbgen/field.go79
-rw-r--r--nexgb/xgbgen/go.go27
-rw-r--r--nexgb/xgbgen/go_request_reply.go14
-rw-r--r--nexgb/xgbgen/request_reply.go12
-rw-r--r--nexgb/xgbgen/translation.go6
-rw-r--r--nexgb/xgbgen/xml_fields.go1
9 files changed, 174 insertions, 158 deletions
diff --git a/nexgb/xgbgen/aligngap.go b/nexgb/xgbgen/aligngap.go
deleted file mode 100644
index 0cd7ac4..0000000
--- a/nexgb/xgbgen/aligngap.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-)
-
-func (p *Protocol) AddAlignGaps() {
- for i := range p.Imports {
- p.Imports[i].AddAlignGaps()
- }
- for i := range p.Types {
- switch t := p.Types[i].(type) {
- case *Struct:
- t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
- case *Event:
- t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
- case *Error:
- t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
- }
- }
- for i := range p.Requests {
- p.Requests[i].Fields = addAlignGapsToFields(
- p.Requests[i].xmlName, p.Requests[i].Fields)
- if p.Requests[i].Reply != nil {
- p.Requests[i].Reply.Fields = addAlignGapsToFields(
- p.Requests[i].xmlName, p.Requests[i].Reply.Fields)
- }
- }
-}
-
-func addAlignGapsToFields(name string, fields []Field) []Field {
- var i int
- for i = 0; i < len(fields); i++ {
- if _, ok := fields[i].(*ListField); ok {
- break
- }
- }
- if i >= len(fields) {
- return fields
- }
-
- r := make([]Field, 0, len(fields)+2)
- r = append(r, fields[:i]...)
-
- r = append(r, fields[i])
- for i = i + 1; i < len(fields); i++ {
- switch f := fields[i].(type) {
- case *ListField:
- // ok, add padding
- sz := xcbSizeOfType(f.Type)
- switch {
- case sz == 1:
- // nothing
- case sz == 2:
- r = append(r, &PadField{0, 2})
- case sz == 3:
- panic(fmt.Errorf("Alignment is not a power of 2"))
- case sz >= 4:
- r = append(r, &PadField{0, 4})
- }
- case *LocalField:
- // nothing
- default:
- fmt.Fprintf(os.Stderr,
- "Can't add alignment gaps, mix of list and non-list "+
- "fields: %s\n", name)
- return fields
- }
- r = append(r, fields[i])
- }
- return r
-}
-
-func xcbSizeOfField(fld Field) int {
- switch f := fld.(type) {
- case *PadField:
- return int(f.Bytes)
- case *SingleField:
- return xcbSizeOfType(f.Type)
- case *ListField:
- return 0
- case *ExprField:
- return xcbSizeOfType(f.Type)
- case *ValueField:
- return xcbSizeOfType(f.MaskType)
- case *SwitchField:
- return 0
- default:
- return 0
- }
-}
-
-func xcbSizeOfType(typ Type) int {
- switch t := typ.(type) {
- case *Resource:
- return 4
- case *TypeDef:
- return t.Size().Eval()
- case *Base:
- return t.Size().Eval()
- case *Struct:
- sz := 0
- for i := range t.Fields {
- sz += xcbSizeOfField(t.Fields[i])
- }
- return sz
- case *Union:
- sz := 0
- for i := range t.Fields {
- csz := xcbSizeOfField(t.Fields[i])
- if csz > sz {
- sz = csz
- }
- }
- return sz
- default:
- return 0
- }
-}
diff --git a/nexgb/xgbgen/context.go b/nexgb/xgbgen/context.go
index f18fd67..0728b64 100644
--- a/nexgb/xgbgen/context.go
+++ b/nexgb/xgbgen/context.go
@@ -49,8 +49,23 @@ func (c *Context) Morph(xmlBytes []byte) {
// Translate XML types to nice types
c.protocol = parsedXml.Translate(nil)
-
- c.protocol.AddAlignGaps()
+
+ // For backwards compatibility we patch the type of the send_event field of
+ // PutImage to be byte
+ if c.protocol.Name == "shm" {
+ for _, req := range c.protocol.Requests {
+ if req.xmlName != "PutImage" {
+ continue
+ }
+ for _, ifield := range req.Fields {
+ field, ok := ifield.(*SingleField)
+ if !ok || field.xmlName != "send_event" {
+ continue
+ }
+ field.Type = &Base{ srcName: "byte", xmlName: "CARD8", size: newFixedSize(1, true) }
+ }
+ }
+ }
// Start with Go header.
c.Putln("// Package %s is the X client API for the %s extension.",
diff --git a/nexgb/xgbgen/expression.go b/nexgb/xgbgen/expression.go
index f88232c..3e2235d 100644
--- a/nexgb/xgbgen/expression.go
+++ b/nexgb/xgbgen/expression.go
@@ -32,6 +32,9 @@ type Expression interface {
// Initialize makes sure all names in this expression and any subexpressions
// have been translated to Go source names.
Initialize(p *Protocol)
+
+ // Makes all field references relative to path
+ Specialize(path string) Expression
}
// Function is a custom expression not found in the XML. It's simply used
@@ -62,6 +65,12 @@ func (e *Function) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
+func (e *Function) Specialize(path string) Expression {
+ r := *e
+ r.Expr = r.Expr.Specialize(path)
+ return &r
+}
+
// BinaryOp is an expression that performs some operation (defined in the XML
// file) with Expr1 and Expr2 as operands.
type BinaryOp struct {
@@ -150,6 +159,13 @@ func (e *BinaryOp) Initialize(p *Protocol) {
e.Expr2.Initialize(p)
}
+func (e *BinaryOp) Specialize(path string) Expression {
+ r := *e
+ r.Expr1 = r.Expr1.Specialize(path)
+ r.Expr2 = r.Expr2.Specialize(path)
+ return &r
+}
+
// UnaryOp is the same as BinaryOp, except it's a unary operator with only
// one sub-expression.
type UnaryOp struct {
@@ -186,6 +202,12 @@ func (e *UnaryOp) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
+func (e *UnaryOp) Specialize(path string) Expression {
+ r := *e
+ r.Expr = r.Expr.Specialize(path)
+ return &r
+}
+
// Padding represents the application of the 'pad' function to some
// sub-expression.
type Padding struct {
@@ -215,6 +237,12 @@ func (e *Padding) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
+func (e *Padding) Specialize(path string) Expression {
+ r := *e
+ r.Expr = r.Expr.Specialize(path)
+ return &r
+}
+
// PopCount represents the application of the 'PopCount' function to
// some sub-expression.
type PopCount struct {
@@ -244,6 +272,12 @@ func (e *PopCount) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
+func (e *PopCount) Specialize(path string) Expression {
+ r := *e
+ r.Expr = r.Expr.Specialize(path)
+ return &r
+}
+
// Value represents some constant integer.
type Value struct {
v int
@@ -267,6 +301,10 @@ func (e *Value) String() string {
func (e *Value) Initialize(p *Protocol) {}
+func (e *Value) Specialize(path string) Expression {
+ return e
+}
+
// Bit represents some bit whose value is computed by '1 << bit'.
type Bit struct {
b int
@@ -290,6 +328,10 @@ func (e *Bit) String() string {
func (e *Bit) Initialize(p *Protocol) {}
+func (e *Bit) Specialize(path string) Expression {
+ return e
+}
+
// FieldRef represents a reference to some variable in the generated code
// with name Name.
type FieldRef struct {
@@ -321,6 +363,10 @@ func (e *FieldRef) Initialize(p *Protocol) {
e.Name = SrcName(p, e.Name)
}
+func (e *FieldRef) Specialize(path string) Expression {
+ return &FieldRef{Name: path + "." + e.Name}
+}
+
// EnumRef represents a reference to some enumeration field.
// EnumKind is the "group" an EnumItem is the name of the specific enumeration
// value inside that group.
@@ -351,6 +397,10 @@ func (e *EnumRef) Initialize(p *Protocol) {
e.EnumItem = SrcName(p, e.EnumItem)
}
+func (e *EnumRef) Specialize(path string) Expression {
+ return e
+}
+
// SumOf represents a summation of the variable in the generated code named by
// Name. It is not currently used. (It's XKB voodoo.)
type SumOf struct {
@@ -380,3 +430,7 @@ func (e *SumOf) String() string {
func (e *SumOf) Initialize(p *Protocol) {
e.Name = SrcName(p, e.Name)
}
+
+func (e *SumOf) Specialize(path string) Expression {
+ return e
+}
diff --git a/nexgb/xgbgen/field.go b/nexgb/xgbgen/field.go
index 2522a06..58f54c8 100644
--- a/nexgb/xgbgen/field.go
+++ b/nexgb/xgbgen/field.go
@@ -73,6 +73,32 @@ func (p *PadField) Size() Size {
}
}
+type RequiredStartAlign struct {
+}
+
+func (f *RequiredStartAlign) Initialize(p *Protocol) { }
+
+func (f *RequiredStartAlign) SrcName() string {
+ panic("illegal to take source name of a required_start_align field")
+}
+
+func (f *RequiredStartAlign) XmlName() string {
+ panic("illegal to take XML name of a required_start_align field")
+}
+
+func (f *RequiredStartAlign) SrcType() string {
+ panic("it is illegal to call SrcType on a required_start_align field")
+}
+
+func (f *RequiredStartAlign) Size() Size {
+ return newFixedSize(0, true)
+}
+
+func (f *RequiredStartAlign) Define(c *Context) { }
+
+func (f *RequiredStartAlign) Read(c *Context, prefix string) { }
+func (f *RequiredStartAlign) Write(c *Context, prefix string) { }
+
// SingleField represents most of the fields in an XML protocol description.
// It corresponds to any single value.
type SingleField struct {
@@ -289,35 +315,72 @@ func (f *ValueField) Initialize(p *Protocol) {
}
// SwitchField represents a 'switch' element in the XML protocol description
-// file. It is not currently used. (i.e., it is XKB voodoo.)
+// file.
+// Currently we translate this to a slice of uint32 and let the user sort
+// through it.
type SwitchField struct {
+ xmlName string
Name string
+ MaskName string
Expr Expression
Bitcases []*Bitcase
}
func (f *SwitchField) SrcName() string {
- panic("it is illegal to call SrcName on a SwitchField field")
+ return f.Name
}
func (f *SwitchField) XmlName() string {
- panic("it is illegal to call XmlName on a SwitchField field")
+ return f.xmlName
}
func (f *SwitchField) SrcType() string {
- panic("it is illegal to call SrcType on a SwitchField field")
+ return "[]uint32"
}
-// XXX: This is a bit tricky. The size has to be represented as a non-concrete
-// expression that finds *which* bitcase fields are included, and sums the
-// sizes of those fields.
func (f *SwitchField) Size() Size {
- return newFixedSize(0, true)
+ // TODO: size expression used here is not correct unless every element of
+ // the switch is 32 bit long. This assumption holds for xproto but may not
+ // hold for other protocols (xkb?)
+ listSize := newExpressionSize(&Function{
+ Name: "xgb.Pad",
+ Expr: &BinaryOp{
+ Op: "*",
+ Expr1: &Value{v: 4},
+ Expr2: &PopCount{
+ Expr: &Function{
+ Name: "int",
+ Expr: &FieldRef{
+ Name: f.MaskName,
+ },
+ },
+ },
+ },
+ }, true)
+
+ return listSize
+}
+
+func (f *SwitchField) ListLength() Size {
+ return newExpressionSize(&PopCount{
+ Expr: &Function{
+ Name: "int",
+ Expr: &FieldRef{
+ Name: f.MaskName,
+ },
+ },
+ }, true)
}
func (f *SwitchField) Initialize(p *Protocol) {
+ f.xmlName = f.Name
f.Name = SrcName(p, f.Name)
f.Expr.Initialize(p)
+ fieldref, ok := f.Expr.(*FieldRef)
+ if !ok {
+ panic("switch field's expression not a fieldref")
+ }
+ f.MaskName = SrcName(p, fieldref.Name)
for _, bitcase := range f.Bitcases {
bitcase.Expr.Initialize(p)
for _, field := range bitcase.Fields {
diff --git a/nexgb/xgbgen/go.go b/nexgb/xgbgen/go.go
index ace4e00..87b5028 100644
--- a/nexgb/xgbgen/go.go
+++ b/nexgb/xgbgen/go.go
@@ -186,11 +186,8 @@ func (f *ValueField) Read(c *Context, prefix string) {
}
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)
- }
+ 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("xgb.Put32(buf[b:], %s%s[i])", prefix, f.ListName)
c.Putln("b += 4")
@@ -200,16 +197,24 @@ func (f *ValueField) Write(c *Context, prefix string) {
// Switch field
func (f *SwitchField) Define(c *Context) {
- c.Putln("// switch field: %s (%s)", f.Name, f.Expr)
- panic("todo")
+ c.Putln("%s []uint32", f.Name)
}
func (f *SwitchField) Read(c *Context, prefix string) {
- c.Putln("// reading switch field: %s (%s)", f.Name, f.Expr)
- panic("todo")
+ c.Putln("")
+ c.Putln("%s%s = make([]uint32, %s)",
+ prefix, f.Name, f.ListLength().Reduce(prefix))
+ c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
+ c.Putln("%s%s[i] = xgb.Get32(buf[b:])", prefix, f.Name)
+ c.Putln("b += 4")
+ c.Putln("}")
+ c.Putln("b = xgb.Pad(b)")
}
func (f *SwitchField) Write(c *Context, prefix string) {
- c.Putln("// writing switch field: %s (%s)", f.Name, f.Expr)
- panic("todo")
+ c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
+ c.Putln("xgb.Put32(buf[b:], %s%s[i])", prefix, f.Name)
+ c.Putln("b += 4")
+ c.Putln("}")
+ c.Putln("b = xgb.Pad(b)")
}
diff --git a/nexgb/xgbgen/go_request_reply.go b/nexgb/xgbgen/go_request_reply.go
index 396305e..9cadc33 100644
--- a/nexgb/xgbgen/go_request_reply.go
+++ b/nexgb/xgbgen/go_request_reply.go
@@ -205,10 +205,7 @@ func (r *Request) ParamNames() string {
for _, field := range r.Fields {
switch f := field.(type) {
case *ValueField:
- // mofos...
- if r.SrcName() != "ConfigureWindow" {
- names = append(names, f.MaskName)
- }
+ names = append(names, f.MaskName)
names = append(names, f.ListName)
case *PadField:
continue
@@ -226,17 +223,16 @@ func (r *Request) ParamNameTypes() string {
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 %s", f.MaskName, f.MaskType.SrcName()))
nameTypes = append(nameTypes,
fmt.Sprintf("%s []uint32", f.ListName))
case *PadField:
continue
case *ExprField:
continue
+ case *RequiredStartAlign:
+ continue
default:
nameTypes = append(nameTypes,
fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))
diff --git a/nexgb/xgbgen/request_reply.go b/nexgb/xgbgen/request_reply.go
index ae4eccb..5032e31 100644
--- a/nexgb/xgbgen/request_reply.go
+++ b/nexgb/xgbgen/request_reply.go
@@ -105,17 +105,15 @@ func (r *Request) Size(c *Context) Size {
}
for _, field := range r.Fields {
- switch field.(type) {
+ switch field := field.(type) {
case *LocalField: // local fields don't go over the wire
continue
case *SingleField:
- // mofos!!!
- if r.SrcName() == "ConfigureWindow" &&
- field.SrcName() == "ValueMask" {
-
- continue
+ fsz := field.Size()
+ if _, isstruct := field.Type.(*Struct); isstruct {
+ fsz.Expression = fsz.Expression.Specialize(field.SrcName())
}
- size = size.Add(field.Size())
+ size = size.Add(fsz)
default:
size = size.Add(field.Size())
}
diff --git a/nexgb/xgbgen/translation.go b/nexgb/xgbgen/translation.go
index f595e5f..d35fa88 100644
--- a/nexgb/xgbgen/translation.go
+++ b/nexgb/xgbgen/translation.go
@@ -325,12 +325,14 @@ func (x *XMLField) Translate(parent interface{}) Field {
case "pad":
return &PadField{
Bytes: x.Bytes,
+ Align: x.Align,
}
case "field":
- return &SingleField{
+ s := &SingleField{
xmlName: x.Name,
Type: newTranslation(x.Type),
}
+ return s
case "list":
return &ListField{
xmlName: x.Name,
@@ -365,6 +367,8 @@ func (x *XMLField) Translate(parent interface{}) Field {
swtch.Bitcases[i] = bitcase.Translate()
}
return swtch
+ case "required_start_align":
+ return &RequiredStartAlign{}
}
log.Panicf("Unrecognized field element: %s", x.XMLName.Local)
diff --git a/nexgb/xgbgen/xml_fields.go b/nexgb/xgbgen/xml_fields.go
index fe6c5d5..8b7b5c7 100644
--- a/nexgb/xgbgen/xml_fields.go
+++ b/nexgb/xgbgen/xml_fields.go
@@ -10,6 +10,7 @@ type XMLField struct {
// For 'pad' element
Bytes uint `xml:"bytes,attr"`
+ Align uint16 `xml:"align,attr"`
// For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements.
Name string `xml:"name,attr"`