299 lines
5.7 KiB
Go
299 lines
5.7 KiB
Go
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("")
|
|
|
|
x.Events.Morph(c)
|
|
c.Putln("")
|
|
|
|
x.Errors.Morph(c)
|
|
c.Putln("")
|
|
|
|
x.EventCopies.Morph(c)
|
|
c.Putln("")
|
|
|
|
x.ErrorCopies.Morph(c)
|
|
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
|
|
|
|
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"`
|
|
Number string `xml:"number,attr"`
|
|
Ref Type `xml:"ref,attr"`
|
|
}
|
|
|
|
type ErrorCopies []*ErrorCopy
|
|
|
|
type ErrorCopy struct {
|
|
Name Type `xml:"name,attr"`
|
|
Number string `xml:"number,attr"`
|
|
Ref Type `xml:"ref,attr"`
|
|
}
|
|
|
|
type Structs []*Struct
|
|
|
|
type Struct struct {
|
|
Name Type `xml:"name,attr"`
|
|
Fields []*Field `xml:",any"`
|
|
}
|
|
|
|
type Unions []*Union
|
|
|
|
type Union struct {
|
|
Name Type `xml:"name,attr"`
|
|
Fields []*Field `xml:",any"`
|
|
}
|
|
|
|
type Requests []*Request
|
|
|
|
type Request struct {
|
|
Name Type `xml:"name,attr"`
|
|
Opcode int `xml:"opcode,attr"`
|
|
Combine bool `xml:"combine-adjacent,attr"`
|
|
Fields []*Field `xml:",any"`
|
|
Reply *Reply `xml:"reply"`
|
|
}
|
|
|
|
type Reply struct {
|
|
Fields []*Field `xml:",any"`
|
|
}
|
|
|
|
type Events []*Event
|
|
|
|
type Event struct {
|
|
Name Type `xml:"name,attr"`
|
|
Number int `xml:"number,attr"`
|
|
NoSequence bool `xml:"no-sequence-number,true"`
|
|
Fields []*Field `xml:",any"`
|
|
}
|
|
|
|
type Errors []*Error
|
|
|
|
type Error struct {
|
|
Name Type `xml:"name,attr"`
|
|
Number int `xml:"number,attr"`
|
|
Fields []*Field `xml:",any"`
|
|
}
|
|
|