2012-04-29 05:25:57 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type XML struct {
|
|
|
|
// Root 'xcb' element properties.
|
|
|
|
XMLName xml.Name `xml:"xcb"`
|
|
|
|
Header string `xml:"header,attr"`
|
|
|
|
ExtensionXName string `xml:"extension-xname,attr"`
|
|
|
|
ExtensionName string `xml:"extension-name,attr"`
|
|
|
|
MajorVersion string `xml:"major-version,attr"`
|
|
|
|
MinorVersion string `xml:"minor-version,attr"`
|
|
|
|
|
|
|
|
// Types for all top-level elements.
|
|
|
|
// First are the simple ones.
|
|
|
|
Imports Imports `xml:"import"`
|
|
|
|
Enums Enums `xml:"enum"`
|
|
|
|
Xids Xids `xml:"xidtype"`
|
|
|
|
XidUnions Xids `xml:"xidunion"`
|
|
|
|
TypeDefs TypeDefs `xml:"typedef"`
|
|
|
|
EventCopies EventCopies `xml:"eventcopy"`
|
|
|
|
ErrorCopies ErrorCopies `xml:"errorcopy"`
|
|
|
|
|
|
|
|
// Here are the complex ones, i.e., anything with "structure contents"
|
|
|
|
Structs Structs `xml:"struct"`
|
|
|
|
Unions Unions `xml:"union"`
|
|
|
|
Requests Requests `xml:"request"`
|
|
|
|
Events Events `xml:"event"`
|
|
|
|
Errors Errors `xml:"error"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Morph cascades down all of the XML and calls each type's corresponding
|
|
|
|
// Morph function with itself as an argument (the context).
|
|
|
|
func (x *XML) Morph(c *Context) {
|
|
|
|
// Start the header...
|
|
|
|
c.Putln("package xgb")
|
|
|
|
c.Putln("/*")
|
|
|
|
c.Putln("\tX protocol API for '%s.xml'.", c.xml.Header)
|
|
|
|
c.Putln("\tThis file is automatically generated. Edit at your own peril!")
|
|
|
|
c.Putln("\tGenerated on %s",
|
|
|
|
time.Now().Format("Jan 2, 2006 at 3:04:05pm MST"))
|
|
|
|
c.Putln("*/")
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Imports.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Enums.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Xids.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.XidUnions.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.TypeDefs.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Structs.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Unions.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
x.Requests.Morph(c)
|
|
|
|
c.Putln("")
|
|
|
|
|
2012-04-29 09:38:29 +02:00
|
|
|
x.Errors.Morph(c)
|
2012-04-29 05:25:57 +02:00
|
|
|
c.Putln("")
|
|
|
|
|
2012-04-29 09:38:29 +02:00
|
|
|
x.ErrorCopies.Morph(c)
|
2012-04-29 05:25:57 +02:00
|
|
|
c.Putln("")
|
|
|
|
|
2012-04-29 09:38:29 +02:00
|
|
|
x.Events.Morph(c)
|
2012-04-29 05:25:57 +02:00
|
|
|
c.Putln("")
|
|
|
|
|
2012-04-29 09:38:29 +02:00
|
|
|
x.EventCopies.Morph(c)
|
2012-04-29 05:25:57 +02:00
|
|
|
c.Putln("")
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsResource returns true if the 'needle' type is a resource type.
|
|
|
|
// i.e., an "xid"
|
|
|
|
func (x *XML) IsResource(needle Type) bool {
|
|
|
|
for _, xid := range x.Xids {
|
|
|
|
if needle == xid.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, xidunion := range x.XidUnions {
|
|
|
|
if needle == xidunion.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, imp := range x.Imports {
|
|
|
|
if imp.xml.IsResource(needle) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasType returns true if the 'needle' type can be found in the protocol
|
|
|
|
// description represented by 'x'.
|
|
|
|
func (x *XML) HasType(needle Type) bool {
|
|
|
|
for _, enum := range x.Enums {
|
|
|
|
if needle == enum.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, xid := range x.Xids {
|
|
|
|
if needle == xid.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, xidunion := range x.XidUnions {
|
|
|
|
if needle == xidunion.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, typedef := range x.TypeDefs {
|
|
|
|
if needle == typedef.New {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, evcopy := range x.EventCopies {
|
|
|
|
if needle == evcopy.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, errcopy := range x.ErrorCopies {
|
|
|
|
if needle == errcopy.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, strct := range x.Structs {
|
|
|
|
if needle == strct.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, union := range x.Unions {
|
|
|
|
if needle == union.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, ev := range x.Events {
|
|
|
|
if needle == ev.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, err := range x.Errors {
|
|
|
|
if needle == err.Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
type Name string
|
|
|
|
|
|
|
|
type Type string
|
|
|
|
|
2012-04-29 20:09:03 +02:00
|
|
|
// Union returns the 'Union' struct corresponding to this type, if
|
|
|
|
// one exists.
|
|
|
|
func (typ Type) Union(c *Context) *Union {
|
|
|
|
// If this is a typedef, use that instead.
|
|
|
|
if oldTyp, ok := typ.TypeDef(c); ok {
|
|
|
|
return oldTyp.Union(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, just look for a union type with 'typ' name.
|
|
|
|
for _, union := range c.xml.Unions {
|
|
|
|
if typ == union.Name {
|
|
|
|
return union
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, imp := range c.xml.Imports {
|
|
|
|
for _, union := range imp.xml.Unions {
|
|
|
|
if typ == union.Name {
|
|
|
|
return union
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TypeDef returns the 'old' type corresponding to this type, if it's found
|
|
|
|
// in a type def. If not found, the second return value is false.
|
|
|
|
func (typ Type) TypeDef(c *Context) (Type, bool) {
|
|
|
|
for _, typedef := range c.xml.TypeDefs {
|
|
|
|
if typ == typedef.New {
|
|
|
|
return typedef.Old, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, imp := range c.xml.Imports {
|
|
|
|
for _, typedef := range imp.xml.TypeDefs {
|
|
|
|
if typ == typedef.New {
|
|
|
|
return typedef.Old, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
2012-04-29 09:38:29 +02:00
|
|
|
// Size is a nifty function that takes any type and digs until it finds
|
|
|
|
// its underlying base type. At which point, the size can be determined.
|
|
|
|
func (typ Type) Size(c *Context) uint {
|
|
|
|
// If this is a base type, we're done.
|
|
|
|
if size, ok := BaseTypeSizes[string(typ)]; ok {
|
|
|
|
return size
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's a resource, we're also done.
|
|
|
|
if c.xml.IsResource(typ) {
|
|
|
|
return BaseTypeSizes["Id"]
|
|
|
|
}
|
|
|
|
|
|
|
|
// It's not, so that implies there is *some* typedef declaring it
|
|
|
|
// in terms of another type. Just follow that chain until we get to
|
|
|
|
// a base type. We also need to check imported stuff.
|
|
|
|
for _, typedef := range c.xml.TypeDefs {
|
|
|
|
if typ == typedef.New {
|
|
|
|
return typedef.Old.Size(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, imp := range c.xml.Imports {
|
|
|
|
for _, typedef := range imp.xml.TypeDefs {
|
|
|
|
if typ == typedef.New {
|
|
|
|
return typedef.Old.Size(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Panicf("Could not find base size of type '%s'.", typ)
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
|
2012-04-29 05:25:57 +02:00
|
|
|
type Imports []*Import
|
|
|
|
|
|
|
|
func (imports Imports) Eval() {
|
|
|
|
for _, imp := range imports {
|
|
|
|
xmlBytes, err := ioutil.ReadFile(*protoPath + "/" + imp.Name + ".xml")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Could not read X protocol description for import " +
|
|
|
|
"'%s' because: %s", imp.Name, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
imp.xml = &XML{}
|
|
|
|
err = xml.Unmarshal(xmlBytes, imp.xml)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Could not parse X protocol description for import " +
|
|
|
|
"'%s' because: %s", imp.Name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Import struct {
|
|
|
|
Name string `xml:",chardata"`
|
|
|
|
xml *XML `xml:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Enums []Enum
|
|
|
|
|
|
|
|
// Eval on the list of all enum types goes through and forces every enum
|
|
|
|
// item to have a valid expression.
|
|
|
|
// This is necessary because when an item is empty, it is defined to have
|
|
|
|
// the value of "one more than that of the previous item, or 0 for the first
|
|
|
|
// item".
|
|
|
|
func (enums Enums) Eval() {
|
|
|
|
for _, enum := range enums {
|
|
|
|
nextValue := uint(0)
|
|
|
|
for _, item := range enum.Items {
|
|
|
|
if item.Expr == nil {
|
|
|
|
item.Expr = newValueExpression(nextValue)
|
|
|
|
nextValue++
|
|
|
|
} else {
|
|
|
|
nextValue = item.Expr.Eval() + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Enum struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
|
|
|
Items []*EnumItem `xml:"item"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type EnumItem struct {
|
|
|
|
Name Name `xml:"name,attr"`
|
|
|
|
Expr *Expression `xml:",any"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Xids []*Xid
|
|
|
|
|
|
|
|
type Xid struct {
|
|
|
|
XMLName xml.Name
|
|
|
|
Name Type `xml:"name,attr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type TypeDefs []*TypeDef
|
|
|
|
|
|
|
|
type TypeDef struct {
|
|
|
|
Old Type `xml:"oldname,attr"`
|
|
|
|
New Type `xml:"newname,attr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type EventCopies []*EventCopy
|
|
|
|
|
|
|
|
type EventCopy struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Number int `xml:"number,attr"`
|
2012-04-29 05:25:57 +02:00
|
|
|
Ref Type `xml:"ref,attr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ErrorCopies []*ErrorCopy
|
|
|
|
|
|
|
|
type ErrorCopy struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Number int `xml:"number,attr"`
|
2012-04-29 05:25:57 +02:00
|
|
|
Ref Type `xml:"ref,attr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Structs []*Struct
|
|
|
|
|
|
|
|
type Struct struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Unions []*Union
|
|
|
|
|
|
|
|
type Union struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Requests []*Request
|
|
|
|
|
|
|
|
type Request struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
|
|
|
Opcode int `xml:"opcode,attr"`
|
|
|
|
Combine bool `xml:"combine-adjacent,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
Reply *Reply `xml:"reply"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Reply struct {
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Events []*Event
|
|
|
|
|
|
|
|
type Event struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
|
|
|
Number int `xml:"number,attr"`
|
|
|
|
NoSequence bool `xml:"no-sequence-number,true"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Errors []*Error
|
|
|
|
|
|
|
|
type Error struct {
|
|
|
|
Name Type `xml:"name,attr"`
|
|
|
|
Number int `xml:"number,attr"`
|
2012-04-29 09:38:29 +02:00
|
|
|
Fields Fields `xml:",any"`
|
2012-04-29 05:25:57 +02:00
|
|
|
}
|
|
|
|
|