github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/xgbgen/go_request_reply.go (about) 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 // mofos... 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 // mofos... 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 }