1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #define A2J_CONF_HEADER_TEXT \
35 "a2jmidid settings.\n" \
36 "You probably don't want to edit this because\n" \
37 "it will be overwritten next time a2jmidid saves.\n"
40 a2j_settings_write_string(int fd
, const char * string
)
46 if (write(fd
, string
, len
) != len
)
48 a2j_error("write() failed to write config file.");
56 a2j_settings_write_option(
61 if (!a2j_settings_write_string(fd
, " "))
66 if (!a2j_settings_write_string(fd
, "<option name=\""))
71 if (!a2j_settings_write_string(fd
, name
))
76 if (!a2j_settings_write_string(fd
, "\">"))
81 if (!a2j_settings_write_string(fd
, content
))
86 if (!a2j_settings_write_string(fd
, "</option>\n"))
100 char timestamp_str
[26];
103 ctime_r(×tamp
, timestamp_str
);
104 timestamp_str
[24] = 0;
106 a2j_info("Saving settings to \"%s\" ...", g_a2j_conf_path
);
108 fd
= open(g_a2j_conf_path
, O_WRONLY
| O_TRUNC
| O_CREAT
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
111 a2j_error("open() failed to open conf filename. error is %d (%s)", errno
, strerror(errno
));
115 if (!a2j_settings_write_string(fd
, "<?xml version=\"1.0\"?>\n"))
120 if (!a2j_settings_write_string(fd
, "<!--\n"))
125 if (!a2j_settings_write_string(fd
, A2J_CONF_HEADER_TEXT
))
130 if (!a2j_settings_write_string(fd
, "-->\n"))
135 if (!a2j_settings_write_string(fd
, "<!-- "))
140 if (!a2j_settings_write_string(fd
, timestamp_str
))
145 if (!a2j_settings_write_string(fd
, " -->\n"))
150 if (!a2j_settings_write_string(fd
, "<a2jmidid>\n"))
155 if (!a2j_settings_write_option(fd
, "jack_server_name", g_a2j_jack_server_name
))
160 if (!a2j_settings_write_option(fd
, "export_hw_ports", g_a2j_export_hw_ports
? "true" : "false"))
165 if (!a2j_settings_write_string(fd
, "</a2jmidid>\n"))
179 #define PARSE_CONTEXT_ROOT 0
180 #define PARSE_CONTEXT_A2J 1
181 #define PARSE_CONTEXT_OPTION 2
183 #define MAX_STACK_DEPTH 10
184 #define MAX_OPTION_LENGTH 100
189 unsigned int element
[MAX_STACK_DEPTH
];
191 char option
[MAX_OPTION_LENGTH
+1];
197 a2j_conf_set_bool_option(
198 const char * value_str
,
201 if (strcmp(value_str
, "true") == 0)
205 else if (strcmp(value_str
, "false") == 0)
211 a2j_error("ignoring unknown bool value \"%s\"", value_str
);
216 a2j_conf_set_string_option(
225 a2j_error("Out of memory");
234 const char * option_name
,
235 const char * option_value
)
237 a2j_info("setting option \"%s\" to value \"%s\"", option_name
, option_value
);
239 if (strcmp(option_name
, "jack_server_name") == 0)
241 a2j_conf_set_string_option(option_value
, &g_a2j_jack_server_name
);
243 else if (strcmp(option_name
, "export_hw_ports") == 0)
245 a2j_conf_set_bool_option(option_value
, &g_a2j_export_hw_ports
);
250 "Unknown parameter \"%s\"",
256 #define context_ptr ((struct parse_context *)data)
259 a2j_conf_settings_callback_chrdata(void *data
, const XML_Char
*s
, int len
)
261 if (context_ptr
->error
)
266 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_OPTION
)
268 if (context_ptr
->option_used
+ len
>= MAX_OPTION_LENGTH
)
270 a2j_error("xml parse max char data length reached");
271 context_ptr
->error
= XML_TRUE
;
275 memcpy(context_ptr
->option
+ context_ptr
->option_used
, s
, len
);
276 context_ptr
->option_used
+= len
;
281 a2j_conf_settings_callback_elstart(void *data
, const char *el
, const char **attr
)
283 if (context_ptr
->error
)
288 if (context_ptr
->depth
+ 1 >= MAX_STACK_DEPTH
)
290 a2j_error("xml parse max stack depth reached");
291 context_ptr
->error
= XML_TRUE
;
295 if (strcmp(el
, "a2jmidid") == 0)
297 //a2j_info("<jack>");
298 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_A2J
;
302 if (strcmp(el
, "option") == 0)
304 //a2j_info("<option>");
305 if ((attr
[0] == NULL
|| attr
[2] != NULL
) || strcmp(attr
[0], "name") != 0)
307 a2j_error("<option> XML element must contain exactly one attribute, named \"name\"");
308 context_ptr
->error
= XML_TRUE
;
312 context_ptr
->name
= strdup(attr
[1]);
313 if (context_ptr
->name
== NULL
)
315 a2j_error("strdup() failed");
316 context_ptr
->error
= XML_TRUE
;
320 context_ptr
->element
[++context_ptr
->depth
] = PARSE_CONTEXT_OPTION
;
321 context_ptr
->option_used
= 0;
325 a2j_error("unknown element \"%s\"", el
);
326 context_ptr
->error
= XML_TRUE
;
330 a2j_conf_settings_callback_elend(void *data
, const char *el
)
332 if (context_ptr
->error
)
337 //a2j_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
339 if (context_ptr
->element
[context_ptr
->depth
] == PARSE_CONTEXT_OPTION
)
341 context_ptr
->option
[context_ptr
->option_used
] = 0;
343 if (context_ptr
->depth
== 1 &&
344 context_ptr
->element
[0] == PARSE_CONTEXT_A2J
)
346 a2j_conf_set_option(context_ptr
->name
, context_ptr
->option
);
350 context_ptr
->depth
--;
352 if (context_ptr
->name
!= NULL
)
354 free(context_ptr
->name
);
355 context_ptr
->name
= NULL
;
369 enum XML_Status xmls
;
370 struct parse_context context
;
372 a2j_info("Loading settings from \"%s\" using %s ...", g_a2j_conf_path
, XML_ExpatVersion());
374 if (stat(g_a2j_conf_path
, &st
) != 0)
378 a2j_info("No conf file found, using defaults...");
382 a2j_error("failed to stat \"%s\", error is %d (%s)", g_a2j_conf_path
, errno
, strerror(errno
));
385 fd
= open(g_a2j_conf_path
, O_RDONLY
);
388 a2j_error("open() failed to open conf filename.");
392 parser
= XML_ParserCreate(NULL
);
395 a2j_error("XML_ParserCreate() failed to create parser object.");
396 goto exit_close_file
;
399 //a2j_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
401 /* we are expecting that conf file has small enough size to fit in memory */
403 buffer
= XML_GetBuffer(parser
, st
.st_size
);
406 a2j_error("XML_GetBuffer() failed.");
407 goto exit_free_parser
;
410 bytes_read
= read(fd
, buffer
, st
.st_size
);
411 if (bytes_read
!= st
.st_size
)
413 a2j_error("read() returned unexpected result.");
414 goto exit_free_parser
;
417 context
.error
= XML_FALSE
;
421 XML_SetElementHandler(parser
, a2j_conf_settings_callback_elstart
, a2j_conf_settings_callback_elend
);
422 XML_SetCharacterDataHandler(parser
, a2j_conf_settings_callback_chrdata
);
423 XML_SetUserData(parser
, &context
);
425 xmls
= XML_ParseBuffer(parser
, bytes_read
, XML_TRUE
);
426 if (xmls
== XML_STATUS_ERROR
)
428 a2j_error("XML_ParseBuffer() failed.");
429 goto exit_free_parser
;
433 XML_ParserFree(parser
);