diff options
| author | Alessandro Arzilli <[email protected]> | 2022-10-29 21:44:00 +0200 | 
|---|---|---|
| committer | Milan Nikolic <[email protected]> | 2022-10-29 21:44:00 +0200 | 
| commit | 54fbc6f8722629e1bd14c432e9e17499d2925ac7 (patch) | |
| tree | 325e5c0a0747963e2b9804ee03a577b594731c3f | |
| parent | 7effddcf465f2b8e142c828c90951614922d9b32 (diff) | |
Changed xgbgen to support xcb-proto >= 1.12
| -rw-r--r-- | xgbgen/aligngap.go | 120 | ||||
| -rw-r--r-- | xgbgen/context.go | 19 | ||||
| -rw-r--r-- | xgbgen/expression.go | 54 | ||||
| -rw-r--r-- | xgbgen/field.go | 79 | ||||
| -rw-r--r-- | xgbgen/go.go | 27 | ||||
| -rw-r--r-- | xgbgen/go_request_reply.go | 14 | ||||
| -rw-r--r-- | xgbgen/request_reply.go | 12 | ||||
| -rw-r--r-- | xgbgen/translation.go | 6 | ||||
| -rw-r--r-- | xgbgen/xml_fields.go | 1 | 
9 files changed, 174 insertions, 158 deletions
diff --git a/xgbgen/aligngap.go b/xgbgen/aligngap.go deleted file mode 100644 index 0cd7ac4..0000000 --- a/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/xgbgen/context.go b/xgbgen/context.go index 755cf6e..2e31598 100644 --- a/xgbgen/context.go +++ b/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/xgbgen/expression.go b/xgbgen/expression.go index f88232c..3e2235d 100644 --- a/xgbgen/expression.go +++ b/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/xgbgen/field.go b/xgbgen/field.go index 2522a06..58f54c8 100644 --- a/xgbgen/field.go +++ b/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/xgbgen/go.go b/xgbgen/go.go index ace4e00..87b5028 100644 --- a/xgbgen/go.go +++ b/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/xgbgen/go_request_reply.go b/xgbgen/go_request_reply.go index 396305e..9cadc33 100644 --- a/xgbgen/go_request_reply.go +++ b/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/xgbgen/request_reply.go b/xgbgen/request_reply.go index ae4eccb..5032e31 100644 --- a/xgbgen/request_reply.go +++ b/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/xgbgen/translation.go b/xgbgen/translation.go index f595e5f..d35fa88 100644 --- a/xgbgen/translation.go +++ b/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/xgbgen/xml_fields.go b/xgbgen/xml_fields.go index fe6c5d5..8b7b5c7 100644 --- a/xgbgen/xml_fields.go +++ b/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"`  | 
