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_deprecated_accept(Visitor *v, const char *name, 250 Error **errp) 251 { 252 ForwardFieldVisitor *ffv = to_ffv(v); 253 254 if (!forward_field_translate_name(ffv, &name, errp)) { 255 return false; 256 } 257 return visit_deprecated_accept(ffv->target, name, errp); 258 } 259 260 static bool forward_field_deprecated(Visitor *v, const char *name) 261 { 262 ForwardFieldVisitor *ffv = to_ffv(v); 263 264 if (!forward_field_translate_name(ffv, &name, NULL)) { 265 return false; 266 } 267 return visit_deprecated(ffv->target, name); 268 } 269 270 static void forward_field_complete(Visitor *v, void *opaque) 271 { 272 /* 273 * Do nothing, the complete method will be called in due time 274 * on the target visitor. 275 */ 276 } 277 278 static void forward_field_free(Visitor *v) 279 { 280 ForwardFieldVisitor *ffv = to_ffv(v); 281 282 g_free(ffv->from); 283 g_free(ffv->to); 284 g_free(ffv); 285 } 286 287 Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to) 288 { 289 ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1); 290 291 /* 292 * Clone and dealloc visitors don't use a name for the toplevel 293 * visit, so they make no sense here. 294 */ 295 assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT); 296 297 v->visitor.type = target->type; 298 v->visitor.start_struct = forward_field_start_struct; 299 v->visitor.check_struct = forward_field_check_struct; 300 v->visitor.end_struct = forward_field_end_struct; 301 v->visitor.start_list = forward_field_start_list; 302 v->visitor.next_list = forward_field_next_list; 303 v->visitor.check_list = forward_field_check_list; 304 v->visitor.end_list = forward_field_end_list; 305 v->visitor.start_alternate = forward_field_start_alternate; 306 v->visitor.end_alternate = forward_field_end_alternate; 307 v->visitor.type_int64 = forward_field_type_int64; 308 v->visitor.type_uint64 = forward_field_type_uint64; 309 v->visitor.type_size = forward_field_type_size; 310 v->visitor.type_bool = forward_field_type_bool; 311 v->visitor.type_str = forward_field_type_str; 312 v->visitor.type_number = forward_field_type_number; 313 v->visitor.type_any = forward_field_type_any; 314 v->visitor.type_null = forward_field_type_null; 315 v->visitor.optional = forward_field_optional; 316 v->visitor.deprecated_accept = forward_field_deprecated_accept; 317 v->visitor.deprecated = forward_field_deprecated; 318 v->visitor.complete = forward_field_complete; 319 v->visitor.free = forward_field_free; 320 321 v->target = target; 322 v->from = g_strdup(from); 323 v->to = g_strdup(to); 324 325 return &v->visitor; 326 } 327