1 #include <cstdio>
2 #include <unistd.h>
3 #include <signal.h>
4 #include <stdexcept>
5
6 #include <glib.h>
7 #include <gconf/gconf.h>
8 #include <gconf/gconf-client.h>
9
10 using namespace std;
11
12 static GMainLoop* loop = NULL;
13
print_value(const GConfValue * value,const char * suffix)14 static int print_value(const GConfValue *value, const char *suffix) {
15 int count = 0;
16 GSList* cursor = NULL;
17
18 if (!value) return 0;
19
20 switch (value->type) {
21 case GCONF_VALUE_STRING:
22 return printf("%s%s", gconf_value_get_string(value), suffix);
23 case GCONF_VALUE_INT:
24 return printf("%d%s", gconf_value_get_int(value), suffix);
25 case GCONF_VALUE_FLOAT:
26 return printf("%f%s", gconf_value_get_float(value), suffix);
27 case GCONF_VALUE_BOOL:
28 if (gconf_value_get_bool(value))
29 return printf("true%s", suffix);
30 return printf("false%s", suffix);
31 case GCONF_VALUE_LIST:
32 cursor = gconf_value_get_list(value);
33 if (g_slist_length (cursor) == 0)
34 count += printf("%s", suffix);
35 else for ( ; cursor ; cursor = g_slist_next(cursor))
36 count += print_value((const GConfValue *) cursor->data, cursor->next ? "," : suffix);
37 return count;
38 case GCONF_VALUE_PAIR:
39 return print_value(gconf_value_get_car(value), ",") +
40 print_value(gconf_value_get_cdr(value), suffix);
41 default:
42 throw exception();
43 }
44
45
46 return 0;
47 }
48
on_value_change(GConfClient *,guint,GConfEntry * entry,void *)49 static void on_value_change(GConfClient* /*client*/, guint /*cnxn_id*/, GConfEntry* entry, void* /*user_data*/) {
50 printf("%s\t", gconf_entry_get_key(entry));
51 print_value(gconf_entry_get_value(entry), "\n");
52 }
53
on_sig(int)54 static void on_sig(int /*signal*/) {
55 g_main_loop_quit(loop);
56 }
57
err(GIOChannel *,GIOCondition,gpointer)58 static gboolean err(GIOChannel* /*source*/, GIOCondition /*condition*/, gpointer /*data*/) {
59 g_main_loop_quit(loop);
60 return false;
61 }
62
set_key(const char * key,const char * val)63 static gboolean set_key(const char *key, const char *val) {
64 gboolean error = false;
65 GConfClient *client = gconf_client_get_default();
66 GConfValue *value = gconf_client_get(client, key, NULL);
67 GConfValueType type = value ? value->type : GCONF_VALUE_STRING;
68 gconf_value_free(value);
69
70 switch (type) {
71 case GCONF_VALUE_STRING:
72 error = !gconf_client_set_string(client, key, val, NULL);
73 break;
74 case GCONF_VALUE_INT:
75 int ival;
76 error = sscanf(val, "%d", &ival) != 1;
77 error = error || !gconf_client_set_int(client, key, ival, NULL);
78 break;
79 case GCONF_VALUE_FLOAT:
80 float fval;
81 error = sscanf(val, "%f", &fval) != 1;
82 error = error || !gconf_client_set_float(client, key, fval, NULL);
83 break;
84 case GCONF_VALUE_BOOL:
85 error = !gconf_client_set_float(client, key, !g_strcmp0(val, "true"), NULL);
86 break;
87 case GCONF_VALUE_LIST:
88 case GCONF_VALUE_PAIR:
89 default:
90 g_critical("Invalid value type!");
91 error = true;
92 }
93
94 g_object_unref(client);
95 return !error;
96 }
97
in(GIOChannel * source,GIOCondition condition,gpointer data)98 static gboolean in(GIOChannel *source, GIOCondition condition, gpointer data) {
99 gchar *key, *val;
100 GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL);
101
102 // Remove the trailing '\n'
103 for (int i=0 ; key && key[i] ; i++)
104 if (key[i] == '\n')
105 key[i] = '\0';
106
107 // If we were successful
108 if (key && st == G_IO_STATUS_NORMAL) {
109 if (!g_strrstr(key, "\t"))
110 goto exit;
111
112 val = g_strrstr(key, "\t") + 1;
113 *(val-1) = '\0';
114
115 if (!set_key(key, val))
116 goto exit;
117
118 g_free(key);
119 return true;
120 }
121 else if (key && st == G_IO_STATUS_AGAIN) {
122 g_free(key);
123 return in(source, condition, data);
124 }
125
126 exit:
127 g_free(key);
128 return err(source, condition, data);
129 }
130
main(int argc,char ** argv)131 int main(int argc, char **argv) {
132 if (argc < 2) return 1;
133
134 // Register sighup handler
135 if (signal(SIGHUP, on_sig) == SIG_ERR || signal(SIGPIPE, on_sig) == SIG_ERR || signal(SIGABRT, on_sig) == SIG_ERR) {
136 fprintf(stderr, "Unable to trap signals!");
137 return 2;
138 }
139
140 // Switch stdout to line buffering
141 if (setvbuf(stdout, NULL, _IOLBF, 0)) {
142 fprintf(stderr, "Unable to switch stdout to line buffering!");
143 return 3;
144 }
145
146 // Switch stdin to line buffering
147 if (setvbuf(stdin, NULL, _IOLBF, 0)) {
148 fprintf(stderr, "Unable to switch stdin to line buffering!");
149 return 4;
150 }
151
152 // Init
153 g_type_init();
154
155 // Get the main loop
156 loop = g_main_loop_new(NULL, false);
157
158 // Setup our GIO Channels
159 GIOChannel* inchan = g_io_channel_unix_new(fileno(stdin));
160 GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout));
161 g_io_add_watch(inchan, G_IO_IN, in, NULL);
162 g_io_add_watch(inchan, G_IO_PRI, in, NULL);
163 g_io_add_watch(inchan, G_IO_ERR, err, NULL);
164 g_io_add_watch(inchan, G_IO_HUP, err, NULL);
165 g_io_add_watch(outchan, G_IO_ERR, err, NULL);
166 g_io_add_watch(outchan, G_IO_HUP, err, NULL);
167
168 // Get GConf client
169 GConfClient* client = gconf_client_get_default();
170
171 // Add server notifications for all keys
172 for (int i=1 ; i < argc ; i++) {
173 GConfValue *value;
174 gconf_client_add_dir(client, argv[i], GCONF_CLIENT_PRELOAD_NONE, NULL);
175 gconf_client_notify_add(client, argv[i], on_value_change, NULL, NULL, NULL);
176 value = gconf_client_get(client, argv[i], NULL);
177 if (value) {
178 gconf_value_free (value);
179 gconf_client_notify(client, argv[i]);
180 } else {
181 printf("%s\n", argv[i]);
182 }
183 }
184
185 g_main_loop_run(loop);
186
187 // Cleanup
188 g_object_unref(client);
189 g_io_channel_shutdown(inchan, FALSE, NULL);
190 g_io_channel_shutdown(outchan, FALSE, NULL);
191 g_io_channel_unref(inchan);
192 g_io_channel_unref(outchan);
193 g_main_loop_unref(loop);
194 }
195