summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore21
-rw-r--r--Makefile.am38
-rw-r--r--configure.in24
-rw-r--r--deps/fetch.sh13
-rw-r--r--src/global.h52
-rw-r--r--src/interfaces.itf27
-rwxr-xr-xsrc/itf2h.pl146
-rw-r--r--src/main.c157
8 files changed, 478 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fce4573
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+config.log
+config.status
+config.h
+config.h.in
+configure
+depcomp
+.dirstamp
+.deps/
+install-sh
+missing
+stamp-h1
+*~
+*.o
+*.a
+deps/ev
+src/interfaces.h
+dbustest
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..a9194ab
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,38 @@
+EXTRA_DIST=
+noinst_LIBRARIES=
+CFLAGS+=-I$(top_srcdir)/deps/ev
+
+
+# libev
+noinst_LIBRARIES+=libev.a
+libev_a_SOURCES=deps/ev/ev.c
+EXTRA_DIST+=\
+ deps/ev/LICENSE\
+ deps/ev/ev_epoll.c\
+ deps/ev/ev.h\
+ deps/ev/ev_kqueue.c\
+ deps/ev/ev_poll.c\
+ deps/ev/ev_port.c\
+ deps/ev/ev_select.c\
+ deps/ev/ev_vars.h\
+ deps/ev/ev_wrap.h
+
+
+# dbustest
+bin_PROGRAMS=dbustest
+dbustest_CPPFLAGS=$(DBUS_CFLAGS)
+dbustest_LDADD=libev.a -lm $(DBUS_LIBS)
+dbustest_SOURCES=\
+ src/main.c
+
+noinst_HEADERSS=\
+ src/global.h
+
+MOSTLYCLEANFILES=src/interfaces.h
+EXTRA_DIST+=itf2h.pl src/interfaces.itf
+
+$(dbustest_OBJECTS): src/interfaces.h
+
+src/interfaces.h: $(srcdir)/src/itf2h.pl $(srcdir)/src/interfaces.itf
+ $(AM_V_GEN)$(srcdir)/src/itf2h.pl <$(srcdir)/src/interfaces.itf >src/interfaces.h
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..a5b8b13
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,24 @@
+
+AC_INIT([bdustest],[0.1],[projects@yorhel.nl])
+AC_CONFIG_SRCDIR([.])
+AC_CONFIG_HEADER([config.h])
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+PKG_PROG_PKG_CONFIG([0.18])
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+
+AC_SYS_LARGEFILE
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_DEFINE(EV_COMPAT3, 0, [Define to disable compatibility with pre-4.0 libev.])
+AC_DEFINE(EV_MULTIPLICITY, 0, [Define to disable support for multiple event loops.])
+m4_include([deps/ev/libev.m4])
+
+PKG_CHECK_MODULES([DBUS], [dbus-1])
+
+
+AC_OUTPUT([Makefile])
+
diff --git a/deps/fetch.sh b/deps/fetch.sh
new file mode 100644
index 0000000..17e8d1d
--- /dev/null
+++ b/deps/fetch.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+ev() {
+ d=libev-4.11
+ rm -rf ev\
+ && wget http://dist.schmorp.de/libev/Attic/$d.tar.gz\
+ && tar -xzf $d.tar.gz\
+ && rm $d.tar.gz\
+ && mv $d ev
+}
+
+ev
+
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..5a44160
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,52 @@
+
+#include "config.h"
+
+#include <dbus/dbus.h>
+#include <ev.h>
+
+/* Global dbus connection (defined in main.c) */
+extern DBusConnection *dbuscon;
+
+
+
+/* Interface structures */
+
+#define ITFF_DEPRECATED 1 /* Methods, signals, properties */
+#define ITFF_NOREPLY 2 /* Methods */
+#define ITFF_READ 4 /* Properties */
+#define ITFF_WRITE 8 /* Properties */
+#define ITFF_READWRITE (ITFF_READ|ITFF_WRITE)
+#define ITFF_EMITNONE 16 /* Properties: EmitsChangedSignal = false */
+#define ITFF_EMITCHANGE 32 /* Properties: EmitsChangedSignal = invalidates */
+
+
+typedef struct {
+ const char *name;
+ char flags; /* deprecated, noreply */
+ char **in;
+ char **out;
+} itf_method_t;
+
+
+typedef struct {
+ const char *name;
+ char flags; /* deprecated */
+ char **args;
+} itf_signal_t;
+
+
+typedef struct {
+ const char *name;
+ const char *type;
+ char flags; /* read,write,deprecated,emitnone,emitchange */
+} itf_property_t;
+
+
+typedef struct {
+ const char *name;
+ int n_methods, n_signals, n_properties;
+ itf_method_t *methods;
+ itf_signal_t *signals;
+ itf_property_t *properties;
+} itf_t;
+
diff --git a/src/interfaces.itf b/src/interfaces.itf
new file mode 100644
index 0000000..e8a32ac
--- /dev/null
+++ b/src/interfaces.itf
@@ -0,0 +1,27 @@
+
+props org.freedesktop.DBus.Properties
+
+ -- methods
+
+ # Blah Blah useful stuff for POD documentation.
+ Set [noreply,deprecated]
+ in s interface_name
+ in s property_name
+ in v value
+
+ Get
+ in s interface_name
+ in s property_name
+ out v value
+
+ -- signals
+
+ PropertiesChanged
+ s interface_name
+ a{sv} changed_properties
+ as invalidated_properties
+
+ -- properties
+
+ s ShmDirectory read,deprecated
+
diff --git a/src/itf2h.pl b/src/itf2h.pl
new file mode 100755
index 0000000..9ebce65
--- /dev/null
+++ b/src/itf2h.pl
@@ -0,0 +1,146 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+
+# itf1 => { name, comment, methods, signals, properties }, ...
+# methods = [ { name, comment, flags, in => [ [ type, name ], .. ], out }, .. ]
+# signals = [ { name, comment, args => [ [ type, name ], .. ] }, .. ]
+# properties = [ { type, name, comment }, .. ]
+sub read_itf {
+ my %itf;
+ my $itf;
+ my $comment = '';
+ my $sect;
+
+ while(<>) {
+ chomp;
+ s/[\s\t]+/ /g;
+ s/ $//;
+ next if !$_;
+
+ # Comment
+ if(/^ *#(.+)$/) {
+ $comment = "\n" if !$comment;
+ $comment .= $1;
+ next;
+ }
+
+ # New interface
+ if(/^([^ ]+) ([^ ]+)$/) {
+ $itf = $1;
+ $itf{$itf} = { name => $2, comment => $comment, map +($_=>[]), qw|methods signals properties| };
+ $comment = '';
+ $sect = '';
+ next;
+ }
+ die "Unknown directive or not in an interface: $_\n" if !$itf;
+
+ # Section switcher
+ if(/^ -- (methods|signals|properties)$/) {
+ $sect = $1;
+ next;
+ }
+ die "Unknown directive or not in a section: $_\n" if !$sect;
+
+ # Method start
+ if($sect eq 'methods' && /^ ([^ ]+)(?: \[([^ ]+)\])?$/) {
+ push @{$itf{$itf}{methods}}, { name => $1, comment => $comment, flags => $2, in => [], out => [] };
+ $comment = '';
+ next;
+ }
+
+ # Method arg
+ if($sect eq 'methods' && /^ (in|out) ([^ ]+) ([^ ]+)$/) {
+ die "Argument before method name: $_\n" if !@{$itf{$itf}{methods}};
+ push @{$itf{$itf}{methods}[$#{$itf{$itf}{methods}}]{$1}}, [ $2, $3 ];
+ next;
+ }
+
+ # Signal start
+ if($sect eq 'signals' && /^ ([^ ]+)(?: \[([^ ]+)\])?$/) {
+ push @{$itf{$itf}{signals}}, { name => $1, comment => $comment, flags => $2, args => [] };
+ $comment = '';
+ next;
+ }
+
+ # Signal arg
+ if($sect eq 'signals' && /^ ([^ ]+) ([^ ]+)$/) {
+ die "Argument before signal name: $_\n" if !@{$itf{$itf}{signals}};
+ push @{$itf{$itf}{signals}[$#{$itf{$itf}{signals}}]{args}}, [ $1, $2 ];
+ next;
+ }
+
+ # Properties
+ if($sect eq 'properties' && /^ ([^ ]+) ([^ ]+) ([^ ]+)$/) {
+ push @{$itf{$itf}{properties}}, { type => $1, name => $2, flags => $3, comment => $comment };
+ $comment = '';
+ next;
+ }
+
+ die "Unknown directive: $_\n";
+ }
+
+ return %itf;
+}
+
+
+sub write_h {
+ my %itf = @_;
+
+ my $argl = sub {
+ my($n, $a) = @_;
+ printf "static char *_itf_%s[] = {\n\t", $n;
+ print join ', ', map(qq{"$_->[0]", "$_->[1]"}, @$a), 'NULL';
+ print "\n};\n";
+ };
+
+ my $flags = sub {
+ my $f = shift->{flags}||'';
+ return join '|', 0, map $f=~/$_/?("ITFF_\U$_"):(), qw|deprecated noreply read write emitnone emitchange|;
+ };
+
+ print "/* File automatically generated by itf2h.pl, DO NOT EDIT. */\n\n";
+ for my $itf (keys %itf) {
+ printf "\n#if !defined(ITF_IMPL_%s) && !defined(ITF_IMPL_ALL)\n", $itf;
+ printf "extern itf_t *itf_%s;\n", $itf;
+ printf "#else\n\n", $itf;
+
+ # Method arguments
+ for my $m (@{$itf{$itf}{methods}}) {
+ $argl->(sprintf("%s_%s_%s", $itf, $m->{name}, $_), $m->{$_}) for ('in', 'out');
+ }
+
+ # Method list
+ printf "\nstatic itf_method_t _itf_%s_methods[] = {", $itf;
+ print join ",", map sprintf("\n\t".'{"%2$s", %3$s, _itf_%1$s_%2$s_in, _itf_%1$s_%2$s_out}', $itf, $_->{name}, $flags->($_)), @{$itf{$itf}{methods}};
+ print "\n};\n\n";
+
+ # Signal arguments
+ $argl->(sprintf("%s_%s_args", $itf, $_->{name}), $_->{args}) for (@{$itf{$itf}{signals}});
+
+ # Signal list
+ printf "\nstatic itf_signal_t _itf_%s_signals[] = {", $itf;
+ print join ",", map sprintf("\n\t".'{"%2$s", %3$s, _itf_%1$s_%2$s_args}', $itf, $_->{name}, $flags->($_)), @{$itf{$itf}{signals}};
+ print "\n};\n";
+
+ # Properties
+ printf "\nstatic itf_property_t _itf_%s_properties[] = {", $itf;
+ print join ",", map sprintf("\n\t".'{"%s", "%s", %s}', $_->{name}, $_->{type}, $flags->($_)), @{$itf{$itf}{properties}};
+ print "\n};\n\n";
+
+ # The interface object
+ printf "itf_t _itf_%s = {\n", $itf;
+ printf "\t\"%s\",\n", $itf{$itf}{name};
+ printf "\t%d, %d, %d,\n", scalar @{$itf{$itf}{methods}}, scalar @{$itf{$itf}{signals}}, scalar @{$itf{$itf}{properties}};
+ printf "\t".'_itf_%s_methods, _itf_%1$s_signals, _itf_%1$s_properties'."\n", $itf;
+ print "};\n";
+ printf "itf_t *itf_%s = &_itf_%1\$s;\n\n", $itf;
+
+ printf "#endif /* ITF_IMPL_%s */\n\n", $itf;
+ }
+}
+
+my %interfaces = read_itf;
+write_h(%interfaces);
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ba9ebed
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,157 @@
+#include "global.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+DBusConnection *dbuscon;
+
+#define BUS_NAME "net.blicky.dbustest"
+
+
+
+/* dbus <-> libev IO watchers */
+
+struct dbusev_io { ev_io io; DBusWatch *w; };
+
+static void dbusev_io(ev_io *io, int revents) {
+ printf("io f=%d\n", revents);
+ dbus_watch_handle(((struct dbusev_io *)io)->w, (revents & EV_READ ? DBUS_WATCH_READABLE : 0) | (revents & EV_WRITE ? DBUS_WATCH_WRITABLE : 0));
+}
+
+
+static void dbusev_watchtoggle(DBusWatch *w, void *data) {
+ printf("watchtoggle en=%d, fd=%d, f=%d\n", dbus_watch_get_enabled(w), dbus_watch_get_unix_fd(w), dbus_watch_get_flags(w));
+ ev_io *io = dbus_watch_get_data(w);
+ if(dbus_watch_get_enabled(w)) {
+ int f = dbus_watch_get_flags(w);
+ ev_io_set(io, dbus_watch_get_unix_fd(w), (f & DBUS_WATCH_READABLE ? EV_READ : 0) | (f & DBUS_WATCH_WRITABLE ? EV_WRITE : 0));
+ ev_io_start(io);
+ } else
+ ev_io_stop(io);
+}
+
+
+static dbus_bool_t dbusev_addwatch(DBusWatch *w, void *data) {
+ printf("addwatch\n");
+ ev_io *io = malloc(sizeof(struct dbusev_io));
+ if(!io)
+ return FALSE;
+ ((struct dbusev_io *)io)->w = w;
+ dbus_watch_set_data(w, io, NULL);
+ ev_init(io, dbusev_io);
+ dbusev_watchtoggle(w, data);
+ return TRUE;
+}
+
+
+static void dbusev_removewatch(DBusWatch *w, void *data) {
+ printf("removewatch\n");
+ ev_io *io = dbus_watch_get_data(w);
+ ev_io_stop(io);
+ free(io);
+}
+
+
+
+/* dbus <-> libev timeout functions */
+
+struct dbusev_timer { ev_timer timer; DBusTimeout *t; };
+
+static void dbusev_timer(ev_timer *timer, int revents) {
+ dbus_timeout_handle(((struct dbusev_timer *)timer)->t);
+}
+
+
+static void dbusev_timeouttoggle(DBusTimeout *t, void *data) {
+ printf("timeouttoggle\n");
+ ev_timer *timer = dbus_timeout_get_data(t);
+ if(dbus_timeout_get_enabled(t)) {
+ timer->repeat = ((ev_tstamp)dbus_timeout_get_interval(t))/1000.0;
+ ev_timer_again(timer);
+ } else
+ ev_timer_stop(timer);
+}
+
+
+static dbus_bool_t dbusev_addtimeout(DBusTimeout *t, void *data) {
+ printf("addtimeout\n");
+ ev_timer *timer = malloc(sizeof(struct dbusev_timer));
+ if(!timer)
+ return FALSE;
+ ((struct dbusev_timer *)timer)->t = t;
+ dbus_timeout_set_data(t, timer, NULL);
+ ev_init(timer, dbusev_timer);
+ dbusev_timeouttoggle(t, data);
+ return TRUE;
+}
+
+
+static void dbusev_removetimeout(DBusTimeout *t, void *data) {
+ printf("removetimeout\n");
+ ev_timer *timer = dbus_timeout_get_data(t);
+ ev_timer_stop(timer);
+ free(timer);
+}
+
+
+
+/* dbus <-> libev dispatch handling */
+
+static void dbusev_dispatch(ev_idle *idl, int revents) {
+ if(dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_COMPLETE)
+ ev_idle_stop(idl);
+}
+
+
+static void dbusev_dispatchstatus(DBusConnection *con, DBusDispatchStatus s, void *data) {
+ printf("dispatchstatus = %d\n", s);
+ static ev_idle *idl = NULL;
+ if(!idl) {
+ idl = malloc(sizeof(ev_idle));
+ ev_idle_init(idl, dbusev_dispatch);
+ }
+ ev_idle_start(idl);
+}
+
+
+
+/* Creates a dbus connection, requests (or rather, requires) our BUS_NAME and
+ * sets the connection up for use with libev. Exits on error. */
+static void init_dbus() {
+ DBusError err;
+ dbus_error_init(&err);
+
+ dbuscon = dbus_bus_get(DBUS_BUS_STARTER, &err);
+ if(dbus_error_is_set(&err)) {
+ printf("Failed to connect to the bus: %s\n", err.message);
+ exit(1);
+ }
+
+ int ret = dbus_bus_request_name(dbuscon, BUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
+ if(dbus_error_is_set(&err) || ret == DBUS_REQUEST_NAME_REPLY_EXISTS) {
+ printf("Failed to acquire dbus name: %s\n", dbus_error_is_set(&err) ? err.message : "Name already taken");
+ exit(1);
+ }
+
+ dbus_connection_set_watch_functions(dbuscon, dbusev_addwatch, dbusev_removewatch, dbusev_watchtoggle, NULL, NULL);
+ dbus_connection_set_timeout_functions(dbuscon, dbusev_addtimeout, dbusev_removetimeout, dbusev_timeouttoggle, NULL, NULL);
+ dbus_connection_set_dispatch_status_function(dbuscon, dbusev_dispatchstatus, NULL, NULL);
+}
+
+
+
+int main(int argc, char **argv) {
+ ev_default_loop(0);
+ init_dbus();
+
+ /* Make sure to dispatch() before entering the main loop, we may have missed
+ * a dispatchstatus update while initializing. */
+ while(dbus_connection_dispatch(dbuscon) != DBUS_DISPATCH_COMPLETE)
+ ;
+
+ ev_run(0);
+
+ return 0;
+}
+