2012-05-03 07:00:01 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-09-29 21:42:23 +02:00
|
|
|
"sort"
|
2012-05-03 07:00:01 +02:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (r *Request) Define(c *Context) {
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %s is a cookie used only for %s requests.",
|
|
|
|
r.CookieName(), r.SrcName())
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("type %s struct {", r.CookieName())
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("*xgb.Cookie")
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
2018-09-29 21:42:23 +02:00
|
|
|
|
|
|
|
if r.Doc.Description != "" {
|
|
|
|
c.PutComment(r.Doc.Description)
|
|
|
|
c.Putln("//")
|
|
|
|
}
|
|
|
|
|
|
|
|
allErrors := make([]string, 0, len(r.Doc.Errors))
|
|
|
|
for kind := range r.Doc.Errors {
|
|
|
|
allErrors = append(allErrors, kind)
|
|
|
|
}
|
|
|
|
sort.Strings(allErrors)
|
|
|
|
|
|
|
|
undocErrors := make([]string, 0)
|
|
|
|
for _, kind := range allErrors {
|
|
|
|
if desc := r.Doc.Errors[kind]; desc == "" {
|
|
|
|
undocErrors = append(undocErrors, kind)
|
|
|
|
} else {
|
|
|
|
c.PutComment(fmt.Sprintf("May return a %s error if %s%s", kind,
|
|
|
|
strings.ToLower(desc[:1]), desc[1:]))
|
|
|
|
c.Putln("//")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(undocErrors) > 0 {
|
|
|
|
c.Putln("// May return %s errors.", strings.Join(undocErrors, ", "))
|
|
|
|
c.Putln("//")
|
|
|
|
}
|
|
|
|
|
2012-05-03 07:00:01 +02:00
|
|
|
if r.Reply != nil {
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %s sends a checked request.", r.SrcName())
|
|
|
|
c.Putln("// If an error occurs, it will be returned with the reply "+
|
2018-09-29 21:39:33 +02:00
|
|
|
"by calling %s.Reply.", r.CookieName())
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func %s(c *xgb.Conn, %s) %s {",
|
2012-05-05 08:55:38 +02:00
|
|
|
r.SrcName(), r.ParamNameTypes(), r.CookieName())
|
2012-05-12 05:58:52 +02:00
|
|
|
r.CheckExt(c)
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("cookie := c.NewCookie(true, true)")
|
|
|
|
c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("return %s{cookie}", r.CookieName())
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %sUnchecked sends an unchecked request.", r.SrcName())
|
|
|
|
c.Putln("// If an error occurs, it can only be retrieved using " +
|
|
|
|
"xgb.WaitForEvent or xgb.PollForEvent.")
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func %sUnchecked(c *xgb.Conn, %s) %s {",
|
2012-05-05 08:55:38 +02:00
|
|
|
r.SrcName(), r.ParamNameTypes(), r.CookieName())
|
2012-05-12 05:58:52 +02:00
|
|
|
r.CheckExt(c)
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("cookie := c.NewCookie(false, true)")
|
|
|
|
c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("return %s{cookie}", r.CookieName())
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
|
|
|
|
r.ReadReply(c)
|
|
|
|
} else {
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %s sends an unchecked request.", r.SrcName())
|
|
|
|
c.Putln("// If an error occurs, it can only be retrieved using " +
|
|
|
|
"xgb.WaitForEvent or xgb.PollForEvent.")
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func %s(c *xgb.Conn, %s) %s {",
|
2012-05-05 08:55:38 +02:00
|
|
|
r.SrcName(), r.ParamNameTypes(), r.CookieName())
|
2012-05-12 05:58:52 +02:00
|
|
|
r.CheckExt(c)
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("cookie := c.NewCookie(false, false)")
|
|
|
|
c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("return %s{cookie}", r.CookieName())
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %sChecked sends a checked request.", r.SrcName())
|
|
|
|
c.Putln("// If an error occurs, it can be retrieved using "+
|
2018-09-29 21:39:33 +02:00
|
|
|
"%s.Check.", r.CookieName())
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func %sChecked(c *xgb.Conn, %s) %s {",
|
2012-05-05 08:55:38 +02:00
|
|
|
r.SrcName(), r.ParamNameTypes(), r.CookieName())
|
2012-05-12 05:58:52 +02:00
|
|
|
r.CheckExt(c)
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("cookie := c.NewCookie(true, false)")
|
|
|
|
c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("return %s{cookie}", r.CookieName())
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
2012-05-05 08:55:38 +02:00
|
|
|
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// Check returns an error if one occurred for checked " +
|
|
|
|
"requests that are not expecting a reply.")
|
|
|
|
c.Putln("// This cannot be called for requests expecting a reply, " +
|
|
|
|
"nor for unchecked requests.")
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func (cook %s) Check() error {", r.CookieName())
|
|
|
|
c.Putln("return cook.Cookie.Check()")
|
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
}
|
2012-05-05 08:55:38 +02:00
|
|
|
r.WriteRequest(c)
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
|
|
|
|
2012-05-12 05:58:52 +02:00
|
|
|
func (r *Request) CheckExt(c *Context) {
|
|
|
|
if !c.protocol.isExt() {
|
|
|
|
return
|
|
|
|
}
|
2016-03-01 15:41:38 +01:00
|
|
|
c.Putln("c.ExtLock.RLock()")
|
|
|
|
c.Putln("defer c.ExtLock.RUnlock()")
|
2013-12-28 16:13:20 +01:00
|
|
|
c.Putln("if _, ok := c.Extensions[\"%s\"]; !ok {", c.protocol.ExtXName)
|
2012-05-12 05:59:38 +02:00
|
|
|
c.Putln("panic(\"Cannot issue request '%s' using the uninitialized "+
|
2012-05-12 05:58:52 +02:00
|
|
|
"extension '%s'. %s.Init(connObj) must be called first.\")",
|
|
|
|
r.SrcName(), c.protocol.ExtXName, c.protocol.PkgName())
|
|
|
|
c.Putln("}")
|
|
|
|
}
|
|
|
|
|
2012-05-03 07:00:01 +02:00
|
|
|
func (r *Request) ReadReply(c *Context) {
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %s represents the data returned from a %s request.",
|
|
|
|
r.ReplyTypeName(), r.SrcName())
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("type %s struct {", r.ReplyTypeName())
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("Sequence uint16 // sequence number of the request for this reply")
|
|
|
|
c.Putln("Length uint32 // number of bytes in this reply")
|
2012-05-03 07:00:01 +02:00
|
|
|
for _, field := range r.Reply.Fields {
|
|
|
|
field.Define(c)
|
|
|
|
}
|
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// Reply blocks and returns the reply data for a %s request.",
|
|
|
|
r.SrcName())
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("func (cook %s) Reply() (*%s, error) {",
|
|
|
|
r.CookieName(), r.ReplyTypeName())
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("buf, err := cook.Cookie.Reply()")
|
2012-05-07 10:09:19 +02:00
|
|
|
c.Putln("if err != nil {")
|
|
|
|
c.Putln("return nil, err")
|
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("if buf == nil {")
|
|
|
|
c.Putln("return nil, nil")
|
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("return %s(buf), nil", r.ReplyName())
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
2012-05-05 08:55:38 +02:00
|
|
|
|
2012-05-11 05:57:34 +02:00
|
|
|
c.Putln("// %s reads a byte slice into a %s value.",
|
|
|
|
r.ReplyName(), r.ReplyTypeName())
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("func %s(buf []byte) *%s {",
|
|
|
|
r.ReplyName(), r.ReplyTypeName())
|
|
|
|
c.Putln("v := new(%s)", r.ReplyTypeName())
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("b := 1 // skip reply determinant")
|
|
|
|
c.Putln("")
|
|
|
|
for i, field := range r.Reply.Fields {
|
2012-05-06 00:21:48 +02:00
|
|
|
field.Read(c, "v.")
|
|
|
|
c.Putln("")
|
|
|
|
if i == 0 {
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("v.Sequence = xgb.Get16(buf[b:])")
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("b += 2")
|
|
|
|
c.Putln("")
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("v.Length = xgb.Get32(buf[b:]) // 4-byte units")
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("b += 4")
|
|
|
|
c.Putln("")
|
|
|
|
}
|
|
|
|
}
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("return v")
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Request) WriteRequest(c *Context) {
|
2014-05-02 15:09:23 +02:00
|
|
|
sz := r.Size(c)
|
|
|
|
writeSize1 := func() {
|
|
|
|
if sz.exact {
|
|
|
|
c.Putln("xgb.Put16(buf[b:], uint16(size / 4)) " +
|
|
|
|
"// write request size in 4-byte units")
|
|
|
|
} else {
|
|
|
|
c.Putln("blen := b")
|
|
|
|
}
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("b += 2")
|
|
|
|
c.Putln("")
|
|
|
|
}
|
2014-05-02 15:09:23 +02:00
|
|
|
writeSize2 := func() {
|
|
|
|
if sz.exact {
|
|
|
|
c.Putln("return buf")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Putln("b = xgb.Pad(b)")
|
2014-05-10 17:41:51 +02:00
|
|
|
c.Putln("xgb.Put16(buf[blen:], uint16(b / 4)) " +
|
|
|
|
"// write request size in 4-byte units")
|
2014-05-02 15:09:23 +02:00
|
|
|
c.Putln("return buf[:b]")
|
|
|
|
}
|
2018-09-29 21:39:33 +02:00
|
|
|
c.Putln("// %s writes a %s request to a byte slice for transfer.",
|
2012-05-11 05:57:34 +02:00
|
|
|
r.ReqName(), r.SrcName())
|
2012-05-10 23:01:42 +02:00
|
|
|
c.Putln("func %s(c *xgb.Conn, %s) []byte {",
|
|
|
|
r.ReqName(), r.ParamNameTypes())
|
2014-05-02 15:09:23 +02:00
|
|
|
c.Putln("size := %s", sz)
|
2012-05-03 07:00:01 +02:00
|
|
|
c.Putln("b := 0")
|
|
|
|
c.Putln("buf := make([]byte, size)")
|
|
|
|
c.Putln("")
|
2012-05-06 23:48:40 +02:00
|
|
|
if c.protocol.isExt() {
|
2016-03-01 15:41:38 +01:00
|
|
|
c.Putln("c.ExtLock.RLock()")
|
2013-12-28 16:13:20 +01:00
|
|
|
c.Putln("buf[b] = c.Extensions[\"%s\"]", c.protocol.ExtXName)
|
2016-03-01 15:41:38 +01:00
|
|
|
c.Putln("c.ExtLock.RUnlock()")
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("b += 1")
|
|
|
|
c.Putln("")
|
|
|
|
}
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("buf[b] = %d // request opcode", r.Opcode)
|
|
|
|
c.Putln("b += 1")
|
|
|
|
c.Putln("")
|
|
|
|
if len(r.Fields) == 0 {
|
2012-05-06 23:48:40 +02:00
|
|
|
if !c.protocol.isExt() {
|
2012-05-06 00:21:48 +02:00
|
|
|
c.Putln("b += 1 // padding")
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
2014-05-02 15:09:23 +02:00
|
|
|
writeSize1()
|
2012-05-06 23:48:40 +02:00
|
|
|
} else if c.protocol.isExt() {
|
2014-05-02 15:09:23 +02:00
|
|
|
writeSize1()
|
2012-05-06 00:21:48 +02:00
|
|
|
}
|
|
|
|
for i, field := range r.Fields {
|
2012-05-03 07:00:01 +02:00
|
|
|
field.Write(c, "")
|
|
|
|
c.Putln("")
|
2012-05-06 23:48:40 +02:00
|
|
|
if i == 0 && !c.protocol.isExt() {
|
2014-05-02 15:09:23 +02:00
|
|
|
writeSize1()
|
2012-05-06 00:21:48 +02:00
|
|
|
}
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
2014-05-02 15:09:23 +02:00
|
|
|
writeSize2()
|
2012-05-05 08:55:38 +02:00
|
|
|
c.Putln("}")
|
|
|
|
c.Putln("")
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Request) ParamNames() string {
|
|
|
|
names := make([]string, 0, len(r.Fields))
|
|
|
|
for _, field := range r.Fields {
|
|
|
|
switch f := field.(type) {
|
|
|
|
case *ValueField:
|
2017-01-18 09:53:26 +01:00
|
|
|
names = append(names, f.MaskName)
|
2012-05-03 07:00:01 +02:00
|
|
|
names = append(names, f.ListName)
|
|
|
|
case *PadField:
|
|
|
|
continue
|
|
|
|
case *ExprField:
|
|
|
|
continue
|
|
|
|
default:
|
|
|
|
names = append(names, fmt.Sprintf("%s", field.SrcName()))
|
|
|
|
}
|
|
|
|
}
|
2012-05-10 23:01:42 +02:00
|
|
|
return strings.Join(names, ", ")
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Request) ParamNameTypes() string {
|
|
|
|
nameTypes := make([]string, 0, len(r.Fields))
|
2018-09-30 10:48:09 +02:00
|
|
|
|
|
|
|
chunk := make([]string, 0)
|
|
|
|
chunkType := ""
|
|
|
|
flushChunk := func() {
|
|
|
|
if len(chunk) > 0 {
|
|
|
|
nameTypes = append(nameTypes, chunk[:len(chunk)-1]...)
|
|
|
|
nameTypes = append(nameTypes,
|
|
|
|
fmt.Sprintf("%s %s", chunk[len(chunk)-1], chunkType))
|
|
|
|
}
|
|
|
|
chunk = nil
|
|
|
|
chunkType = ""
|
|
|
|
}
|
|
|
|
|
2012-05-03 07:00:01 +02:00
|
|
|
for _, field := range r.Fields {
|
|
|
|
switch f := field.(type) {
|
|
|
|
case *ValueField:
|
2018-09-30 10:48:09 +02:00
|
|
|
flushChunk()
|
2017-01-18 09:53:26 +01:00
|
|
|
nameTypes = append(nameTypes,
|
|
|
|
fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
|
2012-05-03 07:00:01 +02:00
|
|
|
nameTypes = append(nameTypes,
|
|
|
|
fmt.Sprintf("%s []uint32", f.ListName))
|
|
|
|
case *PadField:
|
|
|
|
continue
|
|
|
|
case *ExprField:
|
|
|
|
continue
|
2017-01-18 09:53:26 +01:00
|
|
|
case *RequiredStartAlign:
|
|
|
|
continue
|
2012-05-03 07:00:01 +02:00
|
|
|
default:
|
2018-09-30 10:48:09 +02:00
|
|
|
curType := field.SrcType()
|
|
|
|
if curType != chunkType {
|
|
|
|
flushChunk()
|
|
|
|
}
|
|
|
|
chunk = append(chunk, field.SrcName())
|
|
|
|
chunkType = curType
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-30 10:48:09 +02:00
|
|
|
flushChunk()
|
2012-05-10 23:01:42 +02:00
|
|
|
return strings.Join(nameTypes, ", ")
|
2012-05-03 07:00:01 +02:00
|
|
|
}
|