Skip to content
Advertisement

How do I read a dbus array of dicts with the c api sd-bus?

I am try to read a dbus data structure that looks like this a{sv} with sd-bus but when i use the code down below i can only read one of the 8 dicts.

#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>

int main ()
{
  sd_bus *bus = NULL;
  sd_bus_error err = SD_BUS_ERROR_NULL;
  sd_bus_message *msg = NULL;
  char const *sign;
  int signi = 0;
  int error;

  sd_bus_default_user (&bus);

  sd_bus_get_property (bus,
                       "org.mpris.MediaPlayer2.plasma-browser-integration",
                       "/org/mpris/MediaPlayer2",
                       "org.mpris.MediaPlayer2.Player",
                       "Metadata", &err, &msg, "a{sv}");
  sign = sd_bus_message_get_signature (msg, signi);

  error = sd_bus_message_enter_container (msg, SD_BUS_TYPE_ARRAY, "{sv}");
  while (error =
         sd_bus_message_enter_container (msg, SD_BUS_TYPE_DICT_ENTRY,
                                         "sv") > 0) {

    const char *key;

    sd_bus_message_read_basic (msg, SD_BUS_TYPE_STRING, &key);
    sign = sd_bus_message_get_signature (msg, signi);
    printf ("returned: %s n", key);

    sd_bus_message_exit_container (msg);
  }
  sd_bus_message_exit_container (msg);

  if (err._need_free != 0) {
    printf ("%d n", error);
    printf ("returned error: %sn", err.message);
  }
  else {
    printf ("%s", sign);

  }
  sd_bus_error_free (&err);
  sd_bus_unref (bus);

  return 0;
}

I have looked up the function sd_bus_message_enter_container on hotexamples.com and all of them seemed to have while more than one loop around the function that enters the dict it seemed to me that this would loop an tell it had all of the values but this dose not seem to work i also tried using the loop with the function that entered the array and that did not work. another way that tried is to run a for loop that cycled 8 times after that i tried to look for other solutions and there are none that i can see. i also use the documtation on freedesktops web site (https://www.freedesktop.org/software/systemd/man/sd-bus.html) i have it working with gdbus but as far as i understand that is depreciated. how come this is not working i don’t understand.

Thank you in advance for your help.

Advertisement

Answer

I did not realise that I had to read each value otherwise it will throw an error and if you don’t want to there is a skip function. this is the code that worked

#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <stdbool.h>
#include <string.h>

int bus_print_property(const char *name, sd_bus_message *property) {
        char type;
        const char *contents;
        int r;



        r = sd_bus_message_peek_type(property, &type, &contents);
        if (r < 0)
                return r;

        switch (type) {

        case SD_BUS_TYPE_STRING: {
                const char *s;

                r = sd_bus_message_read_basic(property, type, &s);
                if (r < 0)
                        return r;

                printf("%s=%sn", name, s);

                return 1;
        }

        case SD_BUS_TYPE_BOOLEAN: {
                bool b;

                r = sd_bus_message_read_basic(property, type, &b);
                if (r < 0)
                        return r;

                printf("%sn", name);

                return 1;
        }

        case SD_BUS_TYPE_INT64: {
                int64_t i64;

                r = sd_bus_message_read_basic(property, type, &i64);
                if (r < 0)
                    return r;

                printf("%s=%in", name, (int) i64);
            return 1;
        }

        case SD_BUS_TYPE_INT32: {
                int32_t i;

                r = sd_bus_message_read_basic(property, type, &i);
                if (r < 0)
                        return r;

                printf("%s=%in", name, (int) i);
                return 1;
        }

        case SD_BUS_TYPE_OBJECT_PATH:{
            const char *p;

            r = sd_bus_message_read_basic(property, type, &p);
            if (r < 0)
                return r;

            printf("%s=%sn", name, p);

            return 1;


        }

        case SD_BUS_TYPE_DOUBLE: {
                double d;

                r = sd_bus_message_read_basic(property, type, &d);
                if (r < 0)
                        return r;

                printf("%s=%gn", name, d);
                return 1;
        }

        case SD_BUS_TYPE_ARRAY:
                if (strcmp(contents, "s")==0) {
                        bool first = true;
                        const char *str;

                        r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents);
                        if (r < 0)
                                return r;

                        while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
                                if (first)
                                        printf("%s=", name);

                                printf("%s%s", first ? "" : " ", str);

                                first = false;
                        }
                        if (r < 0)
                                return r;

                        if (first )
                                printf("%s=", name);
                        if (!first )
                                puts("");

                        r = sd_bus_message_exit_container(property);
                        if (r < 0)
                                return r;

                        return 1;

                } else {
                        printf("array unreadable");
                        return 0;
                }

                break;
        }

        return 0;
}

int main()
{
sd_bus* bus = NULL;
sd_bus_error err = SD_BUS_ERROR_NULL;
sd_bus_message *msg = NULL;
int error;



sd_bus_default_user(&bus);

sd_bus_get_property(bus,
"org.mpris.MediaPlayer2.plasma-browser-integration",
"/org/mpris/MediaPlayer2",
"org.mpris.MediaPlayer2.Player",
"Metadata",
&err,&msg,"a{sv}");
error = sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, "{sv}");
        if (error < 0)
                return error;

        while ((error = sd_bus_message_enter_container(msg, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
                const char *name;
                const char *contents;

                error = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &name);
                if (error < 0)
                    return error;


                error = sd_bus_message_peek_type(msg, NULL, &contents);
                if (error < 0)
                    return error;

                error = sd_bus_message_enter_container(msg, SD_BUS_TYPE_VARIANT, contents);
                if (error < 0)
                   return error;

                error = bus_print_property(name, msg);
                if (error < 0)
                    return error;
                if (error == 0) {

                                        printf("%s=[unprintable]n", name);
                                /* skip what we didn't read */
                                error = sd_bus_message_skip(msg, contents);
                                if (error < 0)
                                        return error;
                        }

                        error = sd_bus_message_exit_container(msg);
                        if (error < 0)
                                return error;


                error = sd_bus_message_exit_container(msg);
                if (error < 0)
                        return error;
        }
        if (error < 0)
                return error;

        error = sd_bus_message_exit_container(msg);
        if (error < 0)
                return error;


if(err._need_free!=0){
     printf("%d n",error);
    printf("returned error: %sn",err.message);
}else{


}
sd_bus_error_free(&err);
sd_bus_unref(bus);

return 0;
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement