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