diff options
Diffstat (limited to 'hw/qdev.c')
-rw-r--r-- | hw/qdev.c | 103 |
1 files changed, 103 insertions, 0 deletions
@@ -1221,3 +1221,106 @@ gchar *qdev_get_canonical_path(DeviceState *dev) return newpath; } + +static DeviceState *qdev_resolve_abs_path(DeviceState *parent, + gchar **parts, + int index) +{ + DeviceProperty *prop; + DeviceState *child; + + if (parts[index] == NULL) { + return parent; + } + + if (strcmp(parts[index], "") == 0) { + return qdev_resolve_abs_path(parent, parts, index + 1); + } + + prop = qdev_property_find(parent, parts[index]); + if (prop == NULL) { + return NULL; + } + + child = NULL; + if (strstart(prop->type, "link<", NULL)) { + DeviceState **pchild = prop->opaque; + if (*pchild) { + child = *pchild; + } + } else if (strstart(prop->type, "child<", NULL)) { + child = prop->opaque; + } + + if (!child) { + return NULL; + } + + return qdev_resolve_abs_path(child, parts, index + 1); +} + +static DeviceState *qdev_resolve_partial_path(DeviceState *parent, + gchar **parts, + bool *ambiguous) +{ + DeviceState *dev; + DeviceProperty *prop; + + dev = qdev_resolve_abs_path(parent, parts, 0); + + QTAILQ_FOREACH(prop, &parent->properties, node) { + DeviceState *found; + + if (!strstart(prop->type, "child<", NULL)) { + continue; + } + + found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous); + if (found) { + if (dev) { + if (ambiguous) { + *ambiguous = true; + } + return NULL; + } + dev = found; + } + + if (ambiguous && *ambiguous) { + return NULL; + } + } + + return dev; +} + +DeviceState *qdev_resolve_path(const char *path, bool *ambiguous) +{ + bool partial_path = true; + DeviceState *dev; + gchar **parts; + + parts = g_strsplit(path, "/", 0); + if (parts == NULL || parts[0] == NULL) { + g_strfreev(parts); + return qdev_get_root(); + } + + if (strcmp(parts[0], "") == 0) { + partial_path = false; + } + + if (partial_path) { + if (ambiguous) { + *ambiguous = false; + } + dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous); + } else { + dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1); + } + + g_strfreev(parts); + + return dev; +} + |