Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] android: Implement lightweight GKeyFile INI string parser in glib shim
@ 2026-07-15 19:29 Mark Yacoub
  2026-07-15 19:29 ` [PATCH 2/3] tests/unigraf: Fix DRM master and heap memory leaks in tests Mark Yacoub
                   ` (12 more replies)
  0 siblings, 13 replies; 20+ messages in thread
From: Mark Yacoub @ 2026-07-15 19:29 UTC (permalink / raw)
  To: igt-dev; +Cc: louis.chauvet, Mark Yacoub

[Why]
Android's Bionic C library lacks libglib2, requiring IGT to build against
an Android-specific mock header (include/android/glib.h). The existing mock
implementation of GKeyFile and g_key_file_load_from_file is a hardcoded
no-op returning NULL, which prevents tests relying on configuration files
(such as .igtrc) from dynamically retrieving values on Android.

[How]
Expand the dummy GKeyFile structure to record the file path upon calling
g_key_file_load_from_file. Implement a minimal internal INI parser function
(__android_g_key_file_get) inside g_key_file_get_string to traverse the file
line-by-line, matching requested [group] and key strings, stripping trailing
newlines, and returning a heap-allocated duplicate string (strdup).

Signed-off-by: Mark Yacoub <markyacoub@google.com>
---
 include/android/glib.h | 120 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 111 insertions(+), 9 deletions(-)

diff --git a/include/android/glib.h b/include/android/glib.h
index 0b6658287..5b8ba86c7 100644
--- a/include/android/glib.h
+++ b/include/android/glib.h
@@ -16,8 +16,7 @@ typedef struct _GError {
 } GError;
 
 typedef struct _GKeyFile {
-	char *key;
-	char *value;
+	char path[512];
 } GKeyFile;
 
 typedef struct _GMatchInfo {
@@ -45,16 +44,119 @@ static inline void g_error_free(GError *error) { }
 
 static inline const char *g_get_home_dir(void) { return "/data/local/tmp/igt"; }
 
-static inline void g_key_file_free(GKeyFile *file) { }
-static inline GKeyFile *g_key_file_new(void) { return NULL; }
+/*
+ * __android_g_key_file_get: Minimal INI parser to mock GLib's GKeyFile getters.
+ *
+ * This function manually traverses a provided INI-style configuration file
+ * (e.g., .igtrc) searching for a specific [group] and key. It parses line-by-line
+ * without relying on the heavy libglib2 parsing dictionary framework natively
+ * required by standard IGT.
+ *
+ * It operates strictly on the specific file path saved in the GKeyFile struct during
+ * g_key_file_load_from_file(). This ensures it properly acts as a decoupled file
+ * parser and prevents it from hijacking other distinct config operations.
+ *
+ * Parameters:
+ * - key_file: The mocked GKeyFile struct holding the parsed file path.
+ * - target_group: The [group] section to search within (e.g. "Unigraf").
+ * - target_key: The key to matching inside the group (e.g. "Connector").
+ *
+ * Returns:
+ * A newly allocated string (`strdup`) containing the right-side value of the
+ * matched key, or NULL if not found. The caller is responsible for freeing it.
+ */
+static inline char *__android_g_key_file_get(GKeyFile *key_file, const char *target_group, const char *target_key)
+{
+	/* Ensure a valid file path was actively loaded into our GKeyFile mock */
+	if (!key_file || !key_file->path[0]) return NULL;
+
+	FILE *fp = fopen(key_file->path, "r");
+	if (!fp)
+		return NULL;
+
+	char line[256];
+	bool in_group = false;
+	size_t key_len = strlen(target_key);
+
+	while (fgets(line, sizeof(line), fp)) {
+		char *trim = line;
+
+		/* Skip any leading whitespace (spaces or tabs) for the current line */
+		while (*trim == ' ' || *trim == '\t') trim++;
+
+		/* Check if this line declares a new [Group] section */
+		if (trim[0] == '[') {
+			/* Verify if it perfectly matches the user's requested [target_group] */
+			in_group = (strncmp(trim + 1, target_group, strlen(target_group)) == 0 &&
+				    trim[1 + strlen(target_group)] == ']');
+			continue; /* Move to the next line of the file */
+		}
+
+		/* If we are inside the correct group, evaluate if the line starts with `target_key=` */
+		if (in_group && strncmp(trim, target_key, key_len) == 0 && trim[key_len] == '=') {
+			/* Pointer to the start of the value (immediately right of '=') */
+			char *val = trim + key_len + 1;
+			char *end = val + strlen(val);
+
+			/* Strip any trailing whitespace, carriage returns, or newlines by inserting null terminators */
+			while (end > val && (end[-1] == '\r' || end[-1] == '\n' || end[-1] == ' ' || end[-1] == '\t'))
+				end[-1] = '\0';
+
+			fclose(fp);
+			/* Return a standard heap-allocated copy of the value string just as GLib would */
+			return strdup(val);
+		}
+	}
+
+	fclose(fp);
+	return NULL;
+}
+
+static inline void g_key_file_free(GKeyFile *file) { free(file); }
+
+static inline GKeyFile *g_key_file_new(void) { return (GKeyFile *)calloc(1, sizeof(GKeyFile)); }
+
 static inline int g_key_file_get_integer(GKeyFile *key_file,
-	const char *group_name, const char *key, GError **error) { return 0; }
+	const char *group_name, const char *key, GError **error) {
+	char *val = __android_g_key_file_get(key_file, group_name, key);
+	if (!val) return 0;
+	int res = atoi(val);
+	free(val);
+	return res;
+}
+
 static inline char *g_key_file_get_string(GKeyFile *key_file,
-	const char *group_name, const char *key, GError **error) { return NULL; }
+	const char *group_name, const char *key, GError **error) {
+	return __android_g_key_file_get(key_file, group_name, key);
+}
+
 static inline double g_key_file_get_double(GKeyFile *key_file,
-	const char *group_name, const char *key, GError **error) { return 0.0; }
-static inline bool g_key_file_load_from_file(GKeyFile *key_file,
-	const char *file, int flags, GError **error) { return false; }
+	const char *group_name, const char *key, GError **error) {
+	char *val = __android_g_key_file_get(key_file, group_name, key);
+	if (!val) return 0.0;
+	double res = strtod(val, NULL);
+	free(val);
+	return res;
+}
+
+static inline bool g_key_file_get_boolean(GKeyFile *key_file,
+	const char *group_name, const char *key, GError **error) {
+	char *val = __android_g_key_file_get(key_file, group_name, key);
+	if (!val) return false;
+	bool res = (strcmp(val, "true") == 0 || strcmp(val, "1") == 0 || strcmp(val, "yes") == 0);
+	free(val);
+	return res;
+}
+
+static inline bool
+		g_key_file_load_from_file(GKeyFile *key_file,
+	const char *file, int flags, GError **error) {
+	if (key_file && file) {
+		snprintf(key_file->path, sizeof(key_file->path), "%s", file);
+		return true;
+	}
+	return false;
+}
 
 static inline GRegex *g_regex_new(const char *pattern, int compile_options,
 	int match_options, GError **error) { return NULL; }
-- 
2.55.0.141.g00534a21ce-goog


^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-07-21 17:40 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-15 19:29 [PATCH 1/3] android: Implement lightweight GKeyFile INI string parser in glib shim Mark Yacoub
2026-07-15 19:29 ` [PATCH 2/3] tests/unigraf: Fix DRM master and heap memory leaks in tests Mark Yacoub
2026-07-16 14:54   ` Louis Chauvet
2026-07-15 19:29 ` [PATCH 3/3] tests/unigraf: Enhance link rate support checking and hardware retrain timing Mark Yacoub
2026-07-17  8:13   ` Louis Chauvet
2026-07-20 20:53   ` [PATCH v2] " Mark Yacoub
2026-07-15 20:27 ` ✓ Xe.CI.BAT: success for series starting with [1/3] android: Implement lightweight GKeyFile INI string parser in glib shim Patchwork
2026-07-15 20:54 ` ✓ i915.CI.BAT: " Patchwork
2026-07-15 23:40 ` ✓ Xe.CI.FULL: " Patchwork
2026-07-16  3:27 ` ✓ i915.CI.Full: " Patchwork
2026-07-17  8:20 ` [PATCH 1/3] " Louis Chauvet
2026-07-17 10:18   ` Kamil Konieczny
2026-07-17 19:23     ` Louis Chauvet
2026-07-20 12:25       ` Kamil Konieczny
2026-07-17 10:27 ` Kamil Konieczny
2026-07-20 18:50 ` [PATCH v2] lib/igt_rc: Introduce generic config parser Mark Yacoub
2026-07-21  3:25 ` ✓ Xe.CI.BAT: success for series starting with [v2] lib/igt_rc: Introduce generic config parser (rev3) Patchwork
2026-07-21  3:53 ` ✓ i915.CI.BAT: " Patchwork
2026-07-21 11:48 ` ✓ Xe.CI.FULL: " Patchwork
2026-07-21 17:40 ` ✓ i915.CI.Full: " Patchwork

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox