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"` }