lib: add [SAFE_]FILE_LINES_SCANF
This patch adds 2 macros that try to parse each line from
a file according to user-supplied (scanf) format. First line
that matches all format directives ends the search. If EOF
is reached, SAFE_ version triggers TBROK, non-SAFE_ returns
non-zero retcode to user.
Main motivation is parsing various /proc files, for example:
if (FILE_LINES_SCANF("/proc/meminfo", "MemFree: %ld", &free))
do_something();
SAFE_FILE_LINES_SCANF("/proc/meminfo", "MemFree: %ld", &free);
// automatically calls TBROK if all directives can't be matched
Signed-off-by: Jan Stancek <jstancek@redhat.com>
Acked-by: Cyril Hrubis <chrubis@suse.cz>
diff --git a/lib/safe_file_ops.c b/lib/safe_file_ops.c
index dff85cd..01f64ed 100644
--- a/lib/safe_file_ops.c
+++ b/lib/safe_file_ops.c
@@ -169,6 +169,53 @@
}
}
+
+/*
+ * Try to parse each line from file specified by 'path' according
+ * to scanf format 'fmt'. If all fields could be parsed, stop and
+ * return 0, otherwise continue or return 1 if EOF is reached.
+ */
+int file_lines_scanf(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int strict,
+ const char *path, const char *fmt, ...)
+{
+ FILE *fp;
+ int ret = 0;
+ int arg_count = 0;
+ char line[BUFSIZ];
+ va_list ap;
+
+ if (!fmt) {
+ tst_brkm(TBROK, cleanup_fn, "pattern is NULL, %s:%d",
+ file, lineno);
+ }
+
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to open FILE '%s' for reading at %s:%d",
+ path, file, lineno);
+ }
+
+ arg_count = count_scanf_conversions(fmt);
+
+ while (fgets(line, BUFSIZ, fp) != NULL) {
+ va_start(ap, fmt);
+ ret = vsscanf(line, fmt, ap);
+ va_end(ap);
+
+ if (ret == arg_count)
+ break;
+ }
+ fclose(fp);
+
+ if (strict && ret != arg_count)
+ tst_brkm(TBROK, cleanup_fn, "Expected %i conversions got %i"
+ " at %s:%d", arg_count, ret, file, lineno);
+
+ return !(ret == arg_count);
+}
+
int file_printf(const char *file, const int lineno,
const char *path, const char *fmt, ...)
{