All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mark Yacoub <markyacoub@google.com>
To: igt-dev@lists.freedesktop.org
Cc: louis.chauvet@bootlin.com, Mark Yacoub <markyacoub@google.com>
Subject: [PATCH 1/3] android: Implement lightweight GKeyFile INI string parser in glib shim
Date: Wed, 15 Jul 2026 15:29:47 -0400	[thread overview]
Message-ID: <20260715192949.1984280-1-markyacoub@google.com> (raw)

[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


             reply	other threads:[~2026-07-15 19:30 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-15 19:29 Mark Yacoub [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260715192949.1984280-1-markyacoub@google.com \
    --to=markyacoub@google.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=louis.chauvet@bootlin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.