MINOR: server: add minimal infrastructure to parse keywords

Just like with the "bind" lines, we'll switch the "server" line
parsing to keyword registration. The code is essentially the same
as for bind keywords, with minor changes such as support for the
default-server keywords and support for variable argument count.
diff --git a/include/proto/server.h b/include/proto/server.h
index a1fa6c2..408427b 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -47,6 +47,18 @@
 #endif /* _PROTO_SERVER_H */
 
 /*
+ * Registers the server keyword list <kwl> as a list of valid keywords for next
+ * parsing sessions.
+ */
+void srv_register_keywords(struct srv_kw_list *kwl);
+
+/* Return a pointer to the server keyword <kw>, or NULL if not found. */
+struct srv_kw *srv_find_kw(const char *kw);
+
+/* Dumps all registered "server" keywords to the <out> string pointer. */
+void srv_dump_kws(char **out);
+
+/*
  * Local variables:
  *  c-indent-level: 8
  *  c-basic-offset: 8
diff --git a/include/types/server.h b/include/types/server.h
index 2a22e72..3e83d64 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -203,6 +203,31 @@
 	} conf;					/* config information */
 };
 
+/* Descriptor for a "server" keyword. The ->parse() function returns 0 in case of
+ * success, or a combination of ERR_* flags if an error is encountered. The
+ * function pointer can be NULL if not implemented. The function also has an
+ * access to the current "server" config line. The ->skip value tells the parser
+ * how many words have to be skipped after the keyword. If the function needs to
+ * parse more keywords, it needs to update cur_arg.
+ */
+struct srv_kw {
+	const char *kw;
+	int (*parse)(char **args, int *cur_arg, struct proxy *px, struct server *srv, char **err);
+	int skip; /* nb min of args to skip, for use when kw is not handled */
+	int default_ok; /* non-zero if kw is supported in default-server section */
+};
+
+/*
+ * A keyword list. It is a NULL-terminated array of keywords. It embeds a
+ * struct list in order to be linked to other lists, allowing it to easily
+ * be declared where it is needed, and linked without duplicating data nor
+ * allocating memory. It is also possible to indicate a scope for the keywords.
+ */
+struct srv_kw_list {
+	const char *scope;
+	struct list list;
+	struct srv_kw kw[VAR_ARRAY];
+};
 
 #endif /* _TYPES_SERVER_H */
 
diff --git a/src/server.c b/src/server.c
index 0016c80..ae46af5 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1,7 +1,7 @@
 /*
  * Server management functions.
  *
- * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
  * Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
  *
  * This program is free software; you can redistribute it and/or
@@ -16,16 +16,21 @@
 
 #include <proto/server.h>
 
-int srv_downtime(struct server *s) {
+/* List head of all known server keywords */
+static struct srv_kw_list srv_keywords = {
+	.list = LIST_HEAD_INIT(srv_keywords.list)
+};
 
+int srv_downtime(struct server *s)
+{
 	if ((s->state & SRV_RUNNING) && s->last_change < now.tv_sec)		// ignore negative time
 		return s->down_time;
 
 	return now.tv_sec - s->last_change + s->down_time;
 }
 
-int srv_getinter(struct server *s) {
-
+int srv_getinter(struct server *s)
+{
 	if ((s->state & SRV_CHECKED) && (s->health == s->rise + s->fall - 1))
 		return s->inter;
 
@@ -35,6 +40,71 @@
 	return (s->fastinter)?(s->fastinter):(s->inter);
 }
 
+/*
+ * Registers the server keyword list <kwl> as a list of valid keywords for next
+ * parsing sessions.
+ */
+void srv_register_keywords(struct srv_kw_list *kwl)
+{
+	LIST_ADDQ(&srv_keywords.list, &kwl->list);
+}
+
+/* Return a pointer to the server keyword <kw>, or NULL if not found. If the
+ * keyword is found with a NULL ->parse() function, then an attempt is made to
+ * find one with a valid ->parse() function. This way it is possible to declare
+ * platform-dependant, known keywords as NULL, then only declare them as valid
+ * if some options are met. Note that if the requested keyword contains an
+ * opening parenthesis, everything from this point is ignored.
+ */
+struct srv_kw *srv_find_kw(const char *kw)
+{
+	int index;
+	const char *kwend;
+	struct srv_kw_list *kwl;
+	struct srv_kw *ret = NULL;
+
+	kwend = strchr(kw, '(');
+	if (!kwend)
+		kwend = kw + strlen(kw);
+
+	list_for_each_entry(kwl, &srv_keywords.list, list) {
+		for (index = 0; kwl->kw[index].kw != NULL; index++) {
+			if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
+			    kwl->kw[index].kw[kwend-kw] == 0) {
+				if (kwl->kw[index].parse)
+					return &kwl->kw[index]; /* found it !*/
+				else
+					ret = &kwl->kw[index];  /* may be OK */
+			}
+		}
+	}
+	return ret;
+}
+
+/* Dumps all registered "server" keywords to the <out> string pointer. The
+ * unsupported keywords are only dumped if their supported form was not
+ * found.
+ */
+void srv_dump_kws(char **out)
+{
+	struct srv_kw_list *kwl;
+	int index;
+
+	*out = NULL;
+	list_for_each_entry(kwl, &srv_keywords.list, list) {
+		for (index = 0; kwl->kw[index].kw != NULL; index++) {
+			if (kwl->kw[index].parse ||
+			    srv_find_kw(kwl->kw[index].kw) == &kwl->kw[index]) {
+				memprintf(out, "%s[%4s] %s%s%s%s\n", *out ? *out : "",
+				          kwl->scope,
+				          kwl->kw[index].kw,
+				          kwl->kw[index].skip ? " <arg>" : "",
+				          kwl->kw[index].default_ok ? " [dflt_ok]" : "",
+				          kwl->kw[index].parse ? "" : " (not supported)");
+			}
+		}
+	}
+}
 
 /*
  * Local variables: