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, ...)
 {