1 /* 2 * Forward Visitor 3 * 4 * Copyright (C) 2021 Red Hat, Inc. 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 7 * See the COPYING.LIB file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 #include "qapi/compat-policy.h" 13 #include "qapi/error.h" 14 #include "qapi/forward-visitor.h" 15 #include "qapi/visitor-impl.h" 16 #include "qemu/queue.h" 17 #include "qapi/qmp/qjson.h" 18 #include "qapi/qmp/qbool.h" 19 #include "qapi/qmp/qdict.h" 20 #include "qapi/qmp/qerror.h" 21 #include "qapi/qmp/qlist.h" 22 #include "qapi/qmp/qnull.h" 23 #include "qapi/qmp/qnum.h" 24 #include "qapi/qmp/qstring.h" 25 #include "qemu/cutils.h" 26 27 struct ForwardFieldVisitor { 28 Visitor visitor; 29 30 Visitor *target; 31 char *from; 32 char *to; 33 34 int depth; 35 }; 36 37 static ForwardFieldVisitor *to_ffv(Visitor *v) 38 { 39 return container_of(v, ForwardFieldVisitor, visitor); 40 } 41 42 static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **name, 43 Error **errp) 44 { 45 if (v->depth) { 46 return true; 47 } 48 if (g_str_equal(*name, v->from)) { 49 *name = v->to; 50 return true; 51 } 52 error_setg(errp, QERR_MISSING_PARAMETER, *name); 53 return false; 54 } 55 56 static bool forward_field_check_struct(Visitor *v, Error **errp) 57 { 58 ForwardFieldVisitor *ffv = to_ffv(v); 59 60 return visit_check_struct(ffv->target, errp); 61 } 62 63 static bool forward_field_start_struct(Visitor *v, const char *name, void **obj, 64 size_t size, Error **errp) 65 { 66 ForwardFieldVisitor *ffv = to_ffv(v); 67 68 if (!forward_field_translate_name(ffv, &name, errp)) { 69 return false; 70 } 71 if (!visit_start_struct(ffv->target, name, obj, size, errp)) { 72 return false; 73 } 74 ffv->depth++; 75 return true; 76 } 77 78 static void forward_field_end_struct(Visitor *v, void **obj) 79 { 80 ForwardFieldVisitor *ffv = to_ffv(v); 81 82 assert(ffv->depth); 83 ffv->depth--; 84 visit_end_struct(ffv->target, obj); 85 } 86 87 static bool forward_field_start_list(Visitor *v, const char *name, 88 GenericList **list, size_t size, 89 Error **errp) 90 { 91 ForwardFieldVisitor *ffv = to_ffv(v); 92 93 if (!forward_field_translate_name(ffv, &name, errp)) { 94 return false; 95 } 96 ffv->depth++; 97 return visit_start_list(ffv->target, name, list, size, errp); 98 } 99 100 static GenericList *forward_field_next_list(Visitor *v, GenericList *tail, 101 size_t size) 102 { 103 ForwardFieldVisitor *ffv = to_ffv(v); 104 105 assert(ffv->depth); 106 return visit_next_list(ffv->target, tail, size); 107 } 108 109 static bool forward_field_check_list(Visitor *v, Error **errp) 110 { 111 ForwardFieldVisitor *ffv = to_ffv(v); 112 113 assert(ffv->depth); 114 return visit_check_list(ffv->target, errp); 115 } 116 117 static void forward_field_end_list(Visitor *v, void **obj) 118 { 119 ForwardFieldVisitor *ffv = to_ffv(v); 120 121 assert(ffv->depth); 122 ffv->depth--; 123 visit_end_list(ffv->target, obj); 124 } 125 126 static bool forward_field_start_alternate(Visitor *v, const char *name, 127 GenericAlternate **obj, size_t size, 128 Error **errp) 129 { 130 ForwardFieldVisitor *ffv = to_ffv(v); 131 132 if (!forward_field_translate_name(ffv, &name, errp)) { 133 return false; 134 } 135 /* 136 * The name passed to start_alternate is used also in the visit_type_* calls 137 * that retrieve the alternate's content; so, do not increase depth here. 138 */ 139 return visit_start_alternate(ffv->target, name, obj, size, errp); 140 } 141 142 static void forward_field_end_alternate(Visitor *v, void **obj) 143 { 144 ForwardFieldVisitor *ffv = to_ffv(v); 145 146 visit_end_alternate(ffv->target, obj); 147 } 148 149 static bool forward_field_type_int64(Visitor *v, const char *name, int64_t *obj, 150 Error **errp) 151 { 152 ForwardFieldVisitor *ffv = to_ffv(v); 153 154 if (!forward_field_translate_name(ffv, &name, errp)) { 155 return false; 156 } 157 return visit_type_int64(ffv->target, name, obj, errp); 158 } 159 160 static bool forward_field_type_uint64(Visitor *v, const char *name, 161 uint64_t *obj, Error **errp) 162 { 163 ForwardFieldVisitor *ffv = to_ffv(v); 164 165 if (!forward_field_translate_name(ffv, &name, errp)) { 166 return false; 167 } 168 return visit_type_uint64(ffv->target, name, obj, errp); 169 } 170 171 static bool forward_field_type_bool(Visitor *v, const char *name, bool *obj, 172 Error **errp) 173 { 174 ForwardFieldVisitor *ffv = to_ffv(v); 175 176 if (!forward_field_translate_name(ffv, &name, errp)) { 177 return false; 178 } 179 return visit_type_bool(ffv->target, name, obj, errp); 180 } 181 182 static bool forward_field_type_str(Visitor *v, const char *name, char **obj, 183 Error **errp) 184 { 185 ForwardFieldVisitor *ffv = to_ffv(v); 186 187 if (!forward_field_translate_name(ffv, &name, errp)) { 188 return false; 189 } 190 return visit_type_str(ffv->target, name, obj, errp); 191 } 192 193 static bool forward_field_type_size(Visitor *v, const char *name, uint64_t *obj, 194 Error **errp) 195 { 196 ForwardFieldVisitor *ffv = to_ffv(v); 197 198 if (!forward_field_translate_name(ffv, &name, errp)) { 199 return false; 200 } 201 return visit_type_size(ffv->target, name, obj, errp); 202 } 203 204 static bool forward_field_type_number(Visitor *v, const char *name, double *obj, 205 Error **errp) 206 { 207 ForwardFieldVisitor *ffv = to_ffv(v); 208 209 if (!forward_field_translate_name(ffv, &name, errp)) { 210 return false; 211 } 212 return visit_type_number(ffv->target, name, obj, errp); 213 } 214 215 static bool forward_field_type_any(Visitor *v, const char *name, QObject **obj, 216 Error **errp) 217 { 218 ForwardFieldVisitor *ffv = to_ffv(v); 219 220 if (!forward_field_translate_name(ffv, &name, errp)) { 221 return false; 222 } 223 return visit_type_any(ffv->target, name, obj, errp); 224 } 225 226 static bool forward_field_type_null(Visitor *v, const char *name, 227 QNull **obj, Error **errp) 228 { 229 ForwardFieldVisitor *ffv = to_ffv(v); 230 231 if (!forward_field_translate_name(ffv, &name, errp)) { 232 return false; 233 } 234 return visit_type_null(ffv->target, name, obj, errp); 235 } 236 237 static void forward_field_optional(Visitor *v, const char *name, bool *present) 238 { 239 ForwardFieldVisitor *ffv = to_ffv(v); 240 241 if (!forward_field_translate_name(ffv, &name, NULL)) { 242 *present = false; 243 return; 244 } 245 visit_optional(ffv->target, name, present); 246 } 247 248 static bool forward_field_policy_reject(Visitor *v, const char *name, 249 unsigned special_features, 250 Error **errp) 251 { 252 ForwardFieldVisitor *ffv = to_ffv(v); 253 254 if (!forward_field_translate_name(ffv, &name, errp)) { 255 return true; 256 } 257 return visit_policy_reject(ffv->target, name, special_features, errp); 258 } 259 260 static bool forward_field_policy_skip(Visitor *v, const char *name, 261 unsigned special_features) 262 { 263 ForwardFieldVisitor *ffv = to_ffv(v); 264 265 if (!forward_field_translate_name(ffv, &name, NULL)) { 266 return true; 267 } 268 return visit_policy_skip(ffv->target, name, special_features); 269 } 270 271 static void forward_field_complete(Visitor *v, void *opaque) 272 { 273 /* 274 * Do nothing, the complete method will be called in due time 275 * on the target visitor. 276 */ 277 } 278 279 static void forward_field_free(Visitor *v) 280 { 281 ForwardFieldVisitor *ffv = to_ffv(v); 282 283 g_free(ffv->from); 284 g_free(ffv->to); 285 g_free(ffv); 286 } 287 288 Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to) 289 { 290 ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1); 291 292 /* 293 * Clone and dealloc visitors don't use a name for the toplevel 294 * visit, so they make no sense here. 295 */ 296 assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT); 297 298 v->visitor.type = target->type; 299 v->visitor.start_struct = forward_field_start_struct; 300 v->visitor.check_struct = forward_field_check_struct; 301 v->visitor.end_struct = forward_field_end_struct; 302 v->visitor.start_list = forward_field_start_list; 303 v->visitor.next_list = forward_field_next_list; 304 v->visitor.check_list = forward_field_check_list; 305 v->visitor.end_list = forward_field_end_list; 306 v->visitor.start_alternate = forward_field_start_alternate; 307 v->visitor.end_alternate = forward_field_end_alternate; 308 v->visitor.type_int64 = forward_field_type_int64; 309 v->visitor.type_uint64 = forward_field_type_uint64; 310 v->visitor.type_size = forward_field_type_size; 311 v->visitor.type_bool = forward_field_type_bool; 312 v->visitor.type_str = forward_field_type_str; 313 v->visitor.type_number = forward_field_type_number; 314 v->visitor.type_any = forward_field_type_any; 315 v->visitor.type_null = forward_field_type_null; 316 v->visitor.optional = forward_field_optional; 317 v->visitor.policy_reject = forward_field_policy_reject; 318 v->visitor.policy_skip = forward_field_policy_skip; 319 v->visitor.complete = forward_field_complete; 320 v->visitor.free = forward_field_free; 321 322 v->target = target; 323 v->from = g_strdup(from); 324 v->to = g_strdup(to); 325 326 return &v->visitor; 327 } 328