1 package main
2
3 import (
4 "fmt"
5 "strings"
6 )
7
8 func (r *Request) Define(c *Context) {
9 c.Putln("// %s is a cookie used only for %s requests.",
10 r.CookieName(), r.SrcName())
11 c.Putln("type %s struct {", r.CookieName())
12 c.Putln("*xgb.Cookie")
13 c.Putln("}")
14 c.Putln("")
15 if r.Reply != nil {
16 c.Putln("// %s sends a checked request.", r.SrcName())
17 c.Putln("// If an error occurs, it will be returned with the reply "+
18 "by calling %s.Reply()", r.CookieName())
19 c.Putln("func %s(c *xgb.Conn, %s) %s {",
20 r.SrcName(), r.ParamNameTypes(), r.CookieName())
21 r.CheckExt(c)
22 c.Putln("cookie := c.NewCookie(true, true)")
23 c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
24 c.Putln("return %s{cookie}", r.CookieName())
25 c.Putln("}")
26 c.Putln("")
27
28 c.Putln("// %sUnchecked sends an unchecked request.", r.SrcName())
29 c.Putln("// If an error occurs, it can only be retrieved using " +
30 "xgb.WaitForEvent or xgb.PollForEvent.")
31 c.Putln("func %sUnchecked(c *xgb.Conn, %s) %s {",
32 r.SrcName(), r.ParamNameTypes(), r.CookieName())
33 r.CheckExt(c)
34 c.Putln("cookie := c.NewCookie(false, true)")
35 c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
36 c.Putln("return %s{cookie}", r.CookieName())
37 c.Putln("}")
38 c.Putln("")
39
40 r.ReadReply(c)
41 } else {
42 c.Putln("// %s sends an unchecked request.", r.SrcName())
43 c.Putln("// If an error occurs, it can only be retrieved using " +
44 "xgb.WaitForEvent or xgb.PollForEvent.")
45 c.Putln("func %s(c *xgb.Conn, %s) %s {",
46 r.SrcName(), r.ParamNameTypes(), r.CookieName())
47 r.CheckExt(c)
48 c.Putln("cookie := c.NewCookie(false, false)")
49 c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
50 c.Putln("return %s{cookie}", r.CookieName())
51 c.Putln("}")
52 c.Putln("")
53
54 c.Putln("// %sChecked sends a checked request.", r.SrcName())
55 c.Putln("// If an error occurs, it can be retrieved using "+
56 "%s.Check()", r.CookieName())
57 c.Putln("func %sChecked(c *xgb.Conn, %s) %s {",
58 r.SrcName(), r.ParamNameTypes(), r.CookieName())
59 r.CheckExt(c)
60 c.Putln("cookie := c.NewCookie(true, false)")
61 c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
62 c.Putln("return %s{cookie}", r.CookieName())
63 c.Putln("}")
64 c.Putln("")
65
66 c.Putln("// Check returns an error if one occurred for checked " +
67 "requests that are not expecting a reply.")
68 c.Putln("// This cannot be called for requests expecting a reply, " +
69 "nor for unchecked requests.")
70 c.Putln("func (cook %s) Check() error {", r.CookieName())
71 c.Putln("return cook.Cookie.Check()")
72 c.Putln("}")
73 c.Putln("")
74 }
75 r.WriteRequest(c)
76 }
77
78 func (r *Request) CheckExt(c *Context) {
79 if !c.protocol.isExt() {
80 return
81 }
82 c.Putln("c.ExtLock.RLock()")
83 c.Putln("defer c.ExtLock.RUnlock()")
84 c.Putln("if _, ok := c.Extensions[\"%s\"]; !ok {", c.protocol.ExtXName)
85 c.Putln("panic(\"Cannot issue request '%s' using the uninitialized "+
86 "extension '%s'. %s.Init(connObj) must be called first.\")",
87 r.SrcName(), c.protocol.ExtXName, c.protocol.PkgName())
88 c.Putln("}")
89 }
90
91 func (r *Request) ReadReply(c *Context) {
92 c.Putln("// %s represents the data returned from a %s request.",
93 r.ReplyTypeName(), r.SrcName())
94 c.Putln("type %s struct {", r.ReplyTypeName())
95 c.Putln("Sequence uint16 // sequence number of the request for this reply")
96 c.Putln("Length uint32 // number of bytes in this reply")
97 for _, field := range r.Reply.Fields {
98 field.Define(c)
99 }
100 c.Putln("}")
101 c.Putln("")
102
103 c.Putln("// Reply blocks and returns the reply data for a %s request.",
104 r.SrcName())
105 c.Putln("func (cook %s) Reply() (*%s, error) {",
106 r.CookieName(), r.ReplyTypeName())
107 c.Putln("buf, err := cook.Cookie.Reply()")
108 c.Putln("if err != nil {")
109 c.Putln("return nil, err")
110 c.Putln("}")
111 c.Putln("if buf == nil {")
112 c.Putln("return nil, nil")
113 c.Putln("}")
114 c.Putln("return %s(buf), nil", r.ReplyName())
115 c.Putln("}")
116 c.Putln("")
117
118 c.Putln("// %s reads a byte slice into a %s value.",
119 r.ReplyName(), r.ReplyTypeName())
120 c.Putln("func %s(buf []byte) *%s {",
121 r.ReplyName(), r.ReplyTypeName())
122 c.Putln("v := new(%s)", r.ReplyTypeName())
123 c.Putln("b := 1 // skip reply determinant")
124 c.Putln("")
125 for i, field := range r.Reply.Fields {
126 field.Read(c, "v.")
127 c.Putln("")
128 if i == 0 {
129 c.Putln("v.Sequence = xgb.Get16(buf[b:])")
130 c.Putln("b += 2")
131 c.Putln("")
132 c.Putln("v.Length = xgb.Get32(buf[b:]) // 4-byte units")
133 c.Putln("b += 4")
134 c.Putln("")
135 }
136 }
137 c.Putln("return v")
138 c.Putln("}")
139 c.Putln("")
140 }
141
142 func (r *Request) WriteRequest(c *Context) {
143 sz := r.Size(c)
144 writeSize1 := func() {
145 if sz.exact {
146 c.Putln("xgb.Put16(buf[b:], uint16(size / 4)) " +
147 "// write request size in 4-byte units")
148 } else {
149 c.Putln("blen := b")
150 }
151 c.Putln("b += 2")
152 c.Putln("")
153 }
154 writeSize2 := func() {
155 if sz.exact {
156 c.Putln("return buf")
157 return
158 }
159 c.Putln("b = xgb.Pad(b)")
160 c.Putln("xgb.Put16(buf[blen:], uint16(b / 4)) " +
161 "// write request size in 4-byte units")
162 c.Putln("return buf[:b]")
163 }
164 c.Putln("// Write request to wire for %s", r.SrcName())
165 c.Putln("// %s writes a %s request to a byte slice.",
166 r.ReqName(), r.SrcName())
167 c.Putln("func %s(c *xgb.Conn, %s) []byte {",
168 r.ReqName(), r.ParamNameTypes())
169 c.Putln("size := %s", sz)
170 c.Putln("b := 0")
171 c.Putln("buf := make([]byte, size)")
172 c.Putln("")
173 if c.protocol.isExt() {
174 c.Putln("c.ExtLock.RLock()")
175 c.Putln("buf[b] = c.Extensions[\"%s\"]", c.protocol.ExtXName)
176 c.Putln("c.ExtLock.RUnlock()")
177 c.Putln("b += 1")
178 c.Putln("")
179 }
180 c.Putln("buf[b] = %d // request opcode", r.Opcode)
181 c.Putln("b += 1")
182 c.Putln("")
183 if len(r.Fields) == 0 {
184 if !c.protocol.isExt() {
185 c.Putln("b += 1 // padding")
186 }
187 writeSize1()
188 } else if c.protocol.isExt() {
189 writeSize1()
190 }
191 for i, field := range r.Fields {
192 field.Write(c, "")
193 c.Putln("")
194 if i == 0 && !c.protocol.isExt() {
195 writeSize1()
196 }
197 }
198 writeSize2()
199 c.Putln("}")
200 c.Putln("")
201 }
202
203 func (r *Request) ParamNames() string {
204 names := make([]string, 0, len(r.Fields))
205 for _, field := range r.Fields {
206 switch f := field.(type) {
207 case *ValueField:
208
209 if r.SrcName() != "ConfigureWindow" {
210 names = append(names, f.MaskName)
211 }
212 names = append(names, f.ListName)
213 case *PadField:
214 continue
215 case *ExprField:
216 continue
217 default:
218 names = append(names, fmt.Sprintf("%s", field.SrcName()))
219 }
220 }
221 return strings.Join(names, ", ")
222 }
223
224 func (r *Request) ParamNameTypes() string {
225 nameTypes := make([]string, 0, len(r.Fields))
226 for _, field := range r.Fields {
227 switch f := field.(type) {
228 case *ValueField:
229
230 if r.SrcName() != "ConfigureWindow" {
231 nameTypes = append(nameTypes,
232 fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
233 }
234 nameTypes = append(nameTypes,
235 fmt.Sprintf("%s []uint32", f.ListName))
236 case *PadField:
237 continue
238 case *ExprField:
239 continue
240 default:
241 nameTypes = append(nameTypes,
242 fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))
243 }
244 }
245 return strings.Join(nameTypes, ", ")
246 }
247
View as plain text