From 1c01d79ba14a802c603ca2e5bbd35156e3363b85 Mon Sep 17 00:00:00 2001 From: aarzilli Date: Wed, 18 Jan 2017 09:53:26 +0100 Subject: [PATCH] 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 --- nexgb/xgbgen/aligngap.go | 120 ------------------------------- nexgb/xgbgen/context.go | 19 ++++- nexgb/xgbgen/expression.go | 54 ++++++++++++++ nexgb/xgbgen/field.go | 79 +++++++++++++++++--- nexgb/xgbgen/go.go | 27 ++++--- nexgb/xgbgen/go_request_reply.go | 14 ++-- nexgb/xgbgen/request_reply.go | 12 ++-- nexgb/xgbgen/translation.go | 6 +- nexgb/xgbgen/xml_fields.go | 1 + 9 files changed, 174 insertions(+), 158 deletions(-) delete mode 100644 nexgb/xgbgen/aligngap.go 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"`