1From af34025ea52bdf8a33c2b6978953851e7cda95f4 Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Wed, 7 Apr 2021 08:25:57 +0800
4Subject: [PATCH 47/93] config-parser: Support loading multiple configs
5
6Try loading .ini configs under "<config>.d/".
7
8Tested with:
9/etc/xdg/weston/weston.ini.d/99-pixman.ini
10[core]
11use-pixman=true
12
13Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
14---
15 compositor/main.c      |   5 +-
16 shared/config-parser.c | 146 ++++++++++++++++++++++++++++++++++-------
17 2 files changed, 127 insertions(+), 24 deletions(-)
18
19diff --git a/compositor/main.c b/compositor/main.c
20index 6ec89f3..7a1cc20 100644
21--- a/compositor/main.c
22+++ b/compositor/main.c
23@@ -1209,8 +1209,11 @@ load_configuration(struct weston_config **config, int32_t noconfig,
24 	if (config_file)
25 		file = config_file;
26
27-	if (noconfig == 0)
28+	if (noconfig == 0) {
29+		setenv("WESTON_MAIN_PARSE", "1", 1);
30 		*config = weston_config_parse(file);
31+		unsetenv("WESTON_MAIN_PARSE");
32+	}
33
34 	if (*config) {
35 		full_path = weston_config_get_full_path(*config);
36diff --git a/shared/config-parser.c b/shared/config-parser.c
37index 30779ae..e474963 100644
38--- a/shared/config-parser.c
39+++ b/shared/config-parser.c
40@@ -31,6 +31,7 @@
41 #include <stdlib.h>
42 #include <assert.h>
43 #include <ctype.h>
44+#include <dirent.h>
45 #include <limits.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48@@ -70,6 +71,13 @@ open_config_file(struct weston_config *c, const char *name)
49 	const char *p, *next;
50 	int fd;
51
52+	if (!c) {
53+		if (name[0] != '/')
54+			return -1;
55+
56+		return open(name, O_RDONLY | O_CLOEXEC);
57+	}
58+
59 	if (name[0] == '/') {
60 		snprintf(c->path, sizeof c->path, "%s", name);
61 		return open(name, O_RDONLY | O_CLOEXEC);
62@@ -337,6 +345,15 @@ config_add_section(struct weston_config *config, const char *name)
63 {
64 	struct weston_config_section *section;
65
66+	/* squash single sessions */
67+	if (strcmp(name, "launcher") && strcmp(name, "ivi-launcher") &&
68+	    strcmp(name, "output") && strcmp(name, "remote-output") &&
69+	    strcmp(name, "pipewire-output")) {
70+		section = weston_config_get_section(config, name, NULL, NULL);
71+		if (section)
72+			return section;
73+	}
74+
75 	section = zalloc(sizeof *section);
76 	if (section == NULL)
77 		return NULL;
78@@ -355,10 +372,33 @@ config_add_section(struct weston_config *config, const char *name)
79
80 static struct weston_config_entry *
81 section_add_entry(struct weston_config_section *section,
82-		  const char *key, const char *value)
83+		  const char *key, const char *value, const char *file_name)
84 {
85 	struct weston_config_entry *entry;
86
87+	/* hack for removing entry */
88+	if (key[0] == '-') {
89+		key ++;
90+		value = NULL;
91+	}
92+
93+	/* drop old entry */
94+	entry = config_section_get_entry(section, key);
95+	if (entry) {
96+		if (getenv("WESTON_MAIN_PARSE")) {
97+			printf("%s: \"%s/%s\" from \"%s\" to \"%s\"\n",
98+			       file_name ?: "unknown", section->name,
99+			       entry->key, entry->value ?: "", value ?: "");
100+		}
101+		wl_list_remove(&entry->link);
102+		free(entry->key);
103+		free(entry->value);
104+		free(entry);
105+	}
106+
107+	if (!value || value[0] == '\0')
108+		return NULL;
109+
110 	entry = zalloc(sizeof *entry);
111 	if (entry == NULL)
112 		return NULL;
113@@ -382,14 +422,13 @@ section_add_entry(struct weston_config_section *section,
114 }
115
116 static bool
117-weston_config_parse_internal(struct weston_config *config, FILE *fp)
118+weston_config_parse_internal(struct weston_config *config, FILE *fp,
119+			     const char *file_name)
120 {
121 	struct weston_config_section *section = NULL;
122 	char line[512], *p;
123 	int i;
124
125-	wl_list_init(&config->section_list);
126-
127 	while (fgets(line, sizeof line, fp)) {
128 		switch (line[0]) {
129 		case '#':
130@@ -422,7 +461,7 @@ weston_config_parse_internal(struct weston_config *config, FILE *fp)
131 				p[i - 1] = '\0';
132 				i--;
133 			}
134-			section_add_entry(section, line, p);
135+			section_add_entry(section, line, p, file_name);
136 			continue;
137 		}
138 	}
139@@ -438,7 +477,8 @@ weston_config_parse_fp(FILE *file)
140 	if (config == NULL)
141 		return NULL;
142
143-	if (!weston_config_parse_internal(config, file)) {
144+	wl_list_init(&config->section_list);
145+	if (!weston_config_parse_internal(config, file, NULL)) {
146 		weston_config_destroy(config);
147 		return NULL;
148 	}
149@@ -446,48 +486,108 @@ weston_config_parse_fp(FILE *file)
150 	return config;
151 }
152
153-WL_EXPORT struct weston_config *
154-weston_config_parse(const char *name)
155+static FILE *
156+weston_open_config_file(struct weston_config *config, const char *name)
157 {
158 	FILE *fp;
159 	struct stat filestat;
160-	struct weston_config *config;
161 	int fd;
162-	bool ret;
163-
164-	config = zalloc(sizeof *config);
165-	if (config == NULL)
166-		return NULL;
167
168 	fd = open_config_file(config, name);
169-	if (fd == -1) {
170-		free(config);
171+	if (fd == -1)
172 		return NULL;
173-	}
174
175 	if (fstat(fd, &filestat) < 0 ||
176 	    !S_ISREG(filestat.st_mode)) {
177 		close(fd);
178-		free(config);
179 		return NULL;
180 	}
181
182 	fp = fdopen(fd, "r");
183 	if (fp == NULL) {
184 		close(fd);
185-		free(config);
186 		return NULL;
187 	}
188
189-	ret = weston_config_parse_internal(config, fp);
190+	return fp;
191+}
192
193-	fclose(fp);
194+static int
195+accept_config_file(const struct dirent *entry)
196+{
197+	const char *suffix = ".ini";
198+	char *end = strstr(entry->d_name, suffix);
199+	return end && end[strlen(suffix)] == '\0';
200+}
201
202-	if (!ret) {
203-		weston_config_destroy(config);
204+WL_EXPORT struct weston_config *
205+weston_config_parse(const char *name)
206+{
207+	FILE *fp;
208+	struct weston_config *config;
209+	struct stat st;
210+	struct dirent **namelist;
211+	char path[sizeof(config->path) + 2];
212+	bool ret;
213+	int n, i;
214+
215+	config = zalloc(sizeof *config);
216+	if (config == NULL)
217 		return NULL;
218+
219+	wl_list_init(&config->section_list);
220+
221+	fp = weston_open_config_file(config, name);
222+	if (fp) {
223+		ret = weston_config_parse_internal(config, fp, name);
224+
225+		fclose(fp);
226+
227+		if (!ret) {
228+			fprintf(stderr, "failed to parse %s\n", config->path);
229+			free(config);
230+			return NULL;
231+		}
232+	}
233+
234+	strcpy(path, config->path);
235+	strcat(path, ".d");
236+	if (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))
237+		return config;
238+
239+	n = scandir(path, &namelist, accept_config_file, alphasort);
240+	if (n < 0)
241+		return config;
242+
243+	for (i = 0; i < n; i++) {
244+		char *file = namelist[i]->d_name;
245+		char *sep = "/";
246+		char fpath[strlen(path)+strlen(sep)+strlen(file) + 1];
247+		strcpy(fpath, path);
248+		strcat(fpath, sep);
249+		strcat(fpath, file);
250+		free(namelist[i]);
251+
252+		fp = weston_open_config_file(NULL, fpath);
253+		if (!fp)
254+			continue;
255+
256+		ret = weston_config_parse_internal(config, fp, fpath);
257+
258+		fclose(fp);
259+
260+		if (!ret) {
261+			fprintf(stderr, "failed to parse '%s'\n", fpath);
262+			free(config);
263+			config = NULL;
264+			break;
265+		}
266 	}
267
268+	for (; i < n; i++)
269+		free(namelist[i]);
270+
271+	free(namelist);
272 	return config;
273 }
274
275--
2762.20.1
277
278