+static int read_type(const char *buffer, const char *filepath, int line)
+{
+ size_t length;
+ int count;
+ struct execdesc *descs;
+ char *type;
+
+ /* check the type */
+ length = strcspn(buffer, separators);
+ assert(length);
+ if (buffer[length + strspn(buffer + length, separators)] != 0) {
+ ERROR("%s:%d: extra characters found after type", filepath, line);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* allocates data */
+ type = strndup(buffer, length);
+ count = launchers.count + 1;
+ descs = realloc(launchers.descs, count * sizeof(struct execdesc));
+ if (descs == NULL || type == NULL) {
+ free(type);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* fill data */
+ launchers.descs = descs;
+ descs += count - 1;
+ descs->type = type;
+ descs->execs[0] = NULL;
+ descs->execs[1] = NULL;
+ launchers.count = count;
+ return 0;
+}
+
+static int read_args(const char *buffer, int bottom, int offset, const char *filepath, int line)
+{
+ char **vector, *args;
+ size_t index, len, length;
+ int count;
+
+ /* count */
+ count = 0;
+ length = index = 0;
+ while(buffer[index]) {
+ count++;
+ /* skips the spaces */
+ len = strcspn(buffer + index, separators);
+ length += len;
+ /* skips the spaces */
+ index += len;
+ index += strspn(buffer + index, separators);
+ }
+ /* allocates */
+ while (bottom < launchers.count) {
+ vector = malloc(length + count + (count + 1) * sizeof(char*));
+ if (vector == NULL) {
+ ERROR("%s:%d: out of memory", filepath, line);
+ return -1;
+ }
+ args = (char*)(vector + count + 1);
+ count = 0;
+ index = 0;
+ while(buffer[index]) {
+ /* skips the spaces */
+ len = strcspn(buffer + index, separators);
+ vector[count++] = args;
+ memcpy(args, buffer + index, len);
+ args += len;
+ index += len;
+ *args++ = 0;
+ /* skips the spaces */
+ len = strspn(buffer + index, separators);
+ index += len;
+ }
+ vector[count] = NULL;
+ launchers.descs[bottom++].execs[offset] = vector;
+ }
+ return 0;
+}
+
+static int read_launchers(FILE *file, const char *filepath)
+{
+ char buffer[4096];
+ int index, line, rc, bottom, offset, typed;
+
+ /* reads the file */
+ line = 0;
+ offset = 0;
+ typed = 0;
+ bottom = launchers.count;
+ while (fgets(buffer, sizeof buffer, file) != NULL) {
+ line++;
+
+ /* find start of line */
+ index = strspn(buffer, separators);
+
+ /* skip empty lines and comments */
+ if (buffer[index] == 0 || buffer[index] == '#')
+ continue;
+
+ if (index == 0) {
+ if (!typed)
+ bottom = launchers.count;
+ rc = read_type(buffer, filepath, line);
+ if (rc)
+ return rc;
+ if (!typed) {
+ typed = 1;
+ offset = 0;
+ }
+ } else if (!typed && !offset) {
+ ERROR("%s:%d: untyped launcher found", filepath, line);
+ errno = EINVAL;
+ return -1;
+ } else if (offset >= 2) {
+ ERROR("%s:%d: extra launcher found", filepath, line);
+ errno = EINVAL;
+ return -1;
+ } else {
+ rc = read_args(buffer + index, bottom, offset, filepath, line);
+ if (rc)
+ return rc;
+ offset++;
+ typed = 0;
+ }
+ }
+ if (ferror(file)) {
+ ERROR("%s:%d: error while reading, %m", filepath, line);
+ return -1;
+ }
+ return 0;
+}
+
+static int read_configuration_file(const char *filepath)
+{
+ int rc;
+ FILE *file;
+
+ /* opens the configuration file */
+ file = fopen(filepath, "r");
+ if (file == NULL) {
+ /* error */
+ ERROR("can't read file %s: %m", filepath);
+ rc = -1;
+ } else {
+ /* reads it */
+ rc = read_launchers(file, filepath);
+ fclose(file);
+ }
+ return rc;
+}
+