1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
3 Copyright (C) 2007,2008 Nedko Arnaudov
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #if defined(HAVE_CONFIG_H)
26 #include <sys/types.h>
33 #include <dbus/dbus.h>
35 #include "controller_internal.h"
39 jack_controller_settings_init()
45 jack_controller_settings_uninit()
49 #define PARSE_CONTEXT_ROOT 0
50 #define PARSE_CONTEXT_JACK 1
51 #define PARSE_CONTEXT_ENGINE 1
52 #define PARSE_CONTEXT_DRIVERS 2
53 #define PARSE_CONTEXT_DRIVER 3
54 #define PARSE_CONTEXT_OPTION 4
55 #define PARSE_CONTEXT_INTERNALS 5
56 #define PARSE_CONTEXT_INTERNAL 6
58 #define MAX_STACK_DEPTH 10
62 struct jack_controller
*controller_ptr
;
64 unsigned int element
[MAX_STACK_DEPTH
];
66 jackctl_driver_t
*driver
;
67 jackctl_internal_t
*internal
;
68 char option
[JACK_PARAM_STRING_MAX
+1];
73 #define context_ptr ((struct parse_context *)data)
76 jack_controller_settings_callback_chrdata(void *data
, const XML_Char
*s
, int len
)
78 if (context_ptr
->error
)
83 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_OPTION
)
85 if (context_ptr
->option_used
+ len
>= JACK_PARAM_STRING_MAX
)
87 jack_error("xml parse max char data length reached");
88 context_ptr
->error
= XML_TRUE
;
92 memcpy(context_ptr
->option
+ context_ptr
->option_used
, s
, len
);
93 context_ptr
->option_used
+= len
;
98 jack_controller_settings_callback_elstart(void *data
, const char *el
, const char **attr
)
100 jackctl_driver_t
*driver
;
101 jackctl_internal_t
*internal
;
103 if (context_ptr
->error
)
108 if (context_ptr
->depth
+ 1 >= MAX_STACK_DEPTH
)
110 jack_error("xml parse max stack depth reached");
111 context_ptr
->error
= XML_TRUE
;
115 if (strcmp(el
, "jack") == 0)
117 //jack_info("<jack>");
118 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_JACK
;
122 if (strcmp(el
, "engine") == 0)
124 //jack_info("<engine>");
125 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_ENGINE
;
129 if (strcmp(el
, "drivers") == 0)
131 //jack_info("<drivers>");
132 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_DRIVERS
;
136 if (strcmp(el
, "internals") == 0)
138 //jack_info("<internals>");
139 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_INTERNALS
;
143 if (strcmp(el
, "driver") == 0)
145 if ((attr
[0] == NULL
|| attr
[2] != NULL
) || strcmp(attr
[0], "name") != 0)
147 jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
148 context_ptr
->error
= XML_TRUE
;
152 //jack_info("<driver>");
153 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_DRIVER
;
155 driver
= jack_controller_find_driver(context_ptr
->controller_ptr
->server
, attr
[1]);
158 jack_error("ignoring settings for unknown driver \"%s\"", attr
[1]);
162 jack_info("setting for driver \"%s\" found", attr
[1]);
165 context_ptr
->driver
= driver
;
170 if (strcmp(el
, "internal") == 0)
172 if ((attr
[0] == NULL
|| attr
[2] != NULL
) || strcmp(attr
[0], "name") != 0)
174 jack_error("<internal> XML element must contain exactly one attribute, named \"name\"");
175 context_ptr
->error
= XML_TRUE
;
179 //jack_info("<internal>");
180 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_INTERNAL
;
182 internal
= jack_controller_find_internal(context_ptr
->controller_ptr
->server
, attr
[1]);
183 if (internal
== NULL
)
185 jack_error("ignoring settings for unknown internal \"%s\"", attr
[1]);
189 jack_info("setting for internal \"%s\" found", attr
[1]);
192 context_ptr
->internal
= internal
;
198 if (strcmp(el
, "option") == 0)
200 //jack_info("<option>");
201 if ((attr
[0] == NULL
|| attr
[2] != NULL
) || strcmp(attr
[0], "name") != 0)
203 jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
204 context_ptr
->error
= XML_TRUE
;
208 context_ptr
->name
= strdup(attr
[1]);
209 if (context_ptr
->name
== NULL
)
211 jack_error("strdup() failed");
212 context_ptr
->error
= XML_TRUE
;
216 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_OPTION
;
217 context_ptr
->option_used
= 0;
221 jack_error("unknown element \"%s\"", el
);
222 context_ptr
->error
= XML_TRUE
;
226 jack_controller_settings_callback_elend(void *data
, const char *el
)
228 if (context_ptr
->error
)
233 //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
235 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_OPTION
)
237 context_ptr
->option
[context_ptr
->option_used
] = 0;
239 if (context_ptr
->depth
== 2 &&
240 context_ptr
->element
[0] == PARSE_CONTEXT_JACK
&&
241 context_ptr
->element
[1] == PARSE_CONTEXT_ENGINE
)
243 jack_controller_settings_set_engine_option(context_ptr
->controller_ptr
, context_ptr
->name
, context_ptr
->option
);
246 if (context_ptr
->depth
== 3 &&
247 context_ptr
->element
[0] == PARSE_CONTEXT_JACK
&&
248 context_ptr
->element
[1] == PARSE_CONTEXT_DRIVERS
&&
249 context_ptr
->element
[2] == PARSE_CONTEXT_DRIVER
&&
250 context_ptr
->driver
!= NULL
)
252 jack_controller_settings_set_driver_option(context_ptr
->driver
, context_ptr
->name
, context_ptr
->option
);
255 if (context_ptr
->depth
== 3 &&
256 context_ptr
->element
[0] == PARSE_CONTEXT_JACK
&&
257 context_ptr
->element
[1] == PARSE_CONTEXT_INTERNALS
&&
258 context_ptr
->element
[2] == PARSE_CONTEXT_INTERNAL
&&
259 context_ptr
->internal
!= NULL
)
261 jack_controller_settings_set_internal_option(context_ptr
->internal
, context_ptr
->name
, context_ptr
->option
);
265 context_ptr
->depth
--;
267 if (context_ptr
->name
!= NULL
)
269 free(context_ptr
->name
);
270 context_ptr
->name
= NULL
;
277 jack_controller_settings_load(
278 struct jack_controller
* controller_ptr
)
287 enum XML_Status xmls
;
288 struct parse_context context
;
290 conf_len
= strlen(JACKDBUS_CONF
);
292 filename
= malloc(g_jackdbus_config_dir_len
+ conf_len
+ 1);
293 if (filename
== NULL
)
295 jack_error("Out of memory.");
299 memcpy(filename
, g_jackdbus_config_dir
, g_jackdbus_config_dir_len
);
300 memcpy(filename
+ g_jackdbus_config_dir_len
, JACKDBUS_CONF
, conf_len
);
301 filename
[g_jackdbus_config_dir_len
+ conf_len
] = 0;
303 jack_info("Loading settings from \"%s\" using %s ...", filename
, XML_ExpatVersion());
305 if (stat(filename
, &st
) != 0)
307 jack_error("failed to stat \"%s\", error is %d (%s)", filename
, errno
, strerror(errno
));
310 fd
= open(filename
, O_RDONLY
);
313 jack_error("open() failed to open conf filename.");
314 goto exit_free_filename
;
317 parser
= XML_ParserCreate(NULL
);
320 jack_error("XML_ParserCreate() failed to create parser object.");
321 goto exit_close_file
;
324 //jack_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
326 /* we are expecting that conf file has small enough size to fit in memory */
328 buffer
= XML_GetBuffer(parser
, st
.st_size
);
331 jack_error("XML_GetBuffer() failed.");
332 goto exit_free_parser
;
335 bytes_read
= read(fd
, buffer
, st
.st_size
);
336 if (bytes_read
!= st
.st_size
)
338 jack_error("read() returned unexpected result.");
339 goto exit_free_parser
;
342 context
.controller_ptr
= controller_ptr
;
343 context
.error
= XML_FALSE
;
347 XML_SetElementHandler(parser
, jack_controller_settings_callback_elstart
, jack_controller_settings_callback_elend
);
348 XML_SetCharacterDataHandler(parser
, jack_controller_settings_callback_chrdata
);
349 XML_SetUserData(parser
, &context
);
351 xmls
= XML_ParseBuffer(parser
, bytes_read
, XML_TRUE
);
352 if (xmls
== XML_STATUS_ERROR
)
354 jack_error("XML_ParseBuffer() failed.");
355 goto exit_free_parser
;
359 XML_ParserFree(parser
);