[MINOR] acl: support loading values from files

The "acl XXX -f <file>" syntax was supported but nothing was read from
the file. This is now possible. All lines are merged verbatim, even if
they contain spaces (useful for user-agents). There are shortcomings
though. The worst one is that error reporting is too approximative.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 47e4ed4..1ca54fe 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -5886,9 +5886,27 @@
 
 The following ACL flags are currently supported :
 
-   -i : ignore case during matching.
+   -i : ignore case during matching of all subsequent patterns.
+   -f : load patterns from a file.
    -- : force end of flags. Useful when a string looks like one of the flags.
 
+The "-f" flag is special as it loads all of the lines it finds in the file
+specified in argument and loads all of them before continuing. It is even
+possible to pass multiple "-f" arguments if the patterns are to be loaded from
+multiple files. Also, note that the "-i" flag applies to subsequent entries and
+not to entries loaded from files preceeding it. For instance :
+
+    acl valid-ua hdr(user-agent) -f exact-ua.lst -i -f generic-ua.lst  test
+
+In this example, each line of "exact-ua.lst" will be exactly matched against
+the "user-agent" header of the request. Then each line of "generic-ua" will be
+case-insensitively matched. Then the word "test" will be insensitively matched
+too.
+
+Note that right now it is difficult for the ACL parsers to report errors, so if
+a file is unreadable or unparsable, the most you'll get is a parse error in the
+ACL. Thus, file-based ACLs should only be produced by reliable processes.
+
 Supported types of values are :
 
   - integers or integer ranges
diff --git a/src/acl.c b/src/acl.c
index be752b0..a4ea068 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -19,6 +19,8 @@
 #include <common/standard.h>
 #include <common/uri_auth.h>
 
+#include <types/global.h>
+
 #include <proto/acl.h>
 #include <proto/auth.h>
 #include <proto/log.h>
@@ -658,6 +660,52 @@
 	return expr;
 }
 
+static int acl_read_patterns_from_file(	struct acl_keyword *aclkw,
+					struct acl_expr *expr,
+					const char *filename, int patflags)
+{
+	FILE *file;
+	char *c;
+	const char *args[2];
+	struct acl_pattern *pattern;
+	int opaque;
+
+	file = fopen(filename, "r");
+	if (!file)
+		return 0;
+
+	/* now parse all patterns. The file may contain only one pattern per
+	 * line. If the line contains spaces, they will be part of the pattern.
+	 * The pattern stops at the first CR, LF or EOF encountered.
+	 */
+	opaque = 0;
+	args[0] = trash;
+	args[1] = "";
+	while (fgets(trash, sizeof(trash), file) != NULL) {
+
+		c = trash;
+		while (*c && *c != '\n' && *c != '\r')
+			c++;
+		*c = 0;
+
+		pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
+		if (!pattern)
+			goto out_close;
+		pattern->flags = patflags;
+
+		if (!aclkw->parse(args, pattern, &opaque))
+			goto out_free_pattern;
+		LIST_ADDQ(&expr->patterns, &pattern->list);
+	}
+	return 1;
+
+ out_free_pattern:
+	free_pattern(pattern);
+ out_close:
+	fclose(file);
+	return 0;
+}
+
 /* Parse an ACL expression starting at <args>[0], and return it.
  * Right now, the only accepted syntax is :
  * <subject> [<value>...]
@@ -711,8 +759,11 @@
 	while (**args == '-') {
 		if ((*args)[1] == 'i')
 			patflags |= ACL_PAT_F_IGNORE_CASE;
-		else if ((*args)[1] == 'f')
-			patflags |= ACL_PAT_F_FROM_FILE;
+		else if ((*args)[1] == 'f') {
+			if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE))
+				goto out_free_expr;
+			args++;
+		}
 		else if ((*args)[1] == '-') {
 			args++;
 			break;