MINOR: log: move 'log' keyword parsing in dedicated function

Now, the function parse_logsrv should be used to parse a "log" line. This
function will update the list of loggers passed in argument. It can release all
log servers when "no log" line was parsed (by the caller) or it can parse "log
global" or "log <address> ... " lines. It takes care of checking the caller
context (global or not) to prohibit "log global" usage in the global section.
diff --git a/include/proto/log.h b/include/proto/log.h
index c92217c..05a7acc 100644
--- a/include/proto/log.h
+++ b/include/proto/log.h
@@ -82,6 +82,10 @@
  * You can set arguments using { } : %{many arguments}varname
  */
 int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err);
+
+/* Parse "log" keyword and update the linked list. */
+int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err);
+
 /*
  * Displays the message on stderr with the date and pid. Overrides the quiet
  * mode during startup.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index c40e71d..6100f86 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1500,130 +1500,12 @@
 			goto out;
                 }
 	}
-	else if (!strcmp(args[0], "log") && kwm == KWM_NO) { /* no log */
-		/* delete previous herited or defined syslog servers */
-		struct logsrv *back;
-		struct logsrv *tmp;
-
-		if (*(args[1]) != 0) {
-			ha_alert("parsing [%s:%d]:%s : 'no log' does not expect arguments.\n", file, linenum, args[1]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-
-		list_for_each_entry_safe(tmp, back, &global.logsrvs, list) {
-			LIST_DEL(&tmp->list);
-			free(tmp);
-		}
-	}
-	else if (!strcmp(args[0], "log")) {  /* syslog server address */
-		struct sockaddr_storage *sk;
-		int port1, port2;
-		struct logsrv *logsrv;
-		int arg = 0;
-		int len = 0;
-
-		if (alertif_too_many_args(8, file, linenum, args, &err_code)) /* does not strictly check optional arguments */
-			goto out;
-
-		if (*(args[1]) == 0 || *(args[2]) == 0) {
-			ha_alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-
-		logsrv = calloc(1, sizeof(*logsrv));
-
-		/* just after the address, a length may be specified */
-		if (strcmp(args[arg+2], "len") == 0) {
-			len = atoi(args[arg+3]);
-			if (len < 80 || len > 65535) {
-				ha_alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
-					 file, linenum, args[arg+3]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				goto out;
-			}
-			logsrv->maxlen = len;
-
-			/* skip these two args */
-			arg += 2;
-		}
-		else
-			logsrv->maxlen = MAX_SYSLOG_LEN;
-
-		if (logsrv->maxlen > global.max_syslog_len)
-			global.max_syslog_len = logsrv->maxlen;
-
-		/* after the length, a format may be specified */
-		if (strcmp(args[arg+2], "format") == 0) {
-			logsrv->format = get_log_format(args[arg+3]);
-			if (logsrv->format < 0) {
-				ha_alert("parsing [%s:%d] : unknown log format '%s'\n", file, linenum, args[arg+3]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				free(logsrv);
-				goto out;
-			}
-
-			/* skip these two args */
-			arg += 2;
-		}
-
-		if (alertif_too_many_args_idx(3, arg + 1, file, linenum, args, &err_code)) {
-			free(logsrv);
-			goto out;
-		}
-
-		logsrv->facility = get_log_facility(args[arg+2]);
-		if (logsrv->facility < 0) {
-			ha_alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			logsrv->facility = 0;
-		}
-
-		logsrv->level = 7; /* max syslog level = debug */
-		if (*(args[arg+3])) {
-			logsrv->level = get_log_level(args[arg+3]);
-			if (logsrv->level < 0) {
-				ha_alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				logsrv->level = 0;
-			}
-		}
-
-		logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
-		if (*(args[arg+4])) {
-			logsrv->minlvl = get_log_level(args[arg+4]);
-			if (logsrv->minlvl < 0) {
-				ha_alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				logsrv->minlvl = 0;
-			}
-		}
-
-		sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
-		if (!sk) {
-			ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
+	else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
+		if (!parse_logsrv(args, &global.logsrvs, (kwm == KWM_NO), &errmsg)) {
+			ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
 			err_code |= ERR_ALERT | ERR_FATAL;
-			free(logsrv);
 			goto out;
 		}
-		logsrv->addr = *sk;
-
-		if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
-			if (port1 != port2) {
-				ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
-					 file, linenum, args[0], args[1]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				free(logsrv);
-				goto out;
-			}
-
-			logsrv->addr = *sk;
-			if (!port1)
-				set_host_port(&logsrv->addr, SYSLOG_PORT);
-		}
-
-		LIST_ADDQ(&global.logsrvs, &logsrv->list);
 	}
 	else if (!strcmp(args[0], "log-send-hostname")) { /* set the hostname in syslog header */
 		char *name;
@@ -6165,133 +6047,9 @@
 		chunk_destroy(&curproxy->log_tag);
 		chunk_initstr(&curproxy->log_tag, strdup(args[1]));
 	}
-	else if (!strcmp(args[0], "log") && kwm == KWM_NO) {
-		/* delete previous herited or defined syslog servers */
-		struct logsrv *back;
-
-		if (*(args[1]) != 0) {
-			ha_alert("parsing [%s:%d]:%s : 'no log' does not expect arguments.\n", file, linenum, args[1]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-
-		list_for_each_entry_safe(tmplogsrv, back, &curproxy->logsrvs, list) {
-			LIST_DEL(&tmplogsrv->list);
-			free(tmplogsrv);
-		}
-	}
-	else if (!strcmp(args[0], "log")) {  /* syslog server address */
-		struct logsrv *logsrv;
-
-		if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
-			/* copy global.logrsvs linked list to the end of curproxy->logsrvs */
-			list_for_each_entry(tmplogsrv, &global.logsrvs, list) {
-				struct logsrv *node = malloc(sizeof(*node));
-				memcpy(node, tmplogsrv, sizeof(struct logsrv));
-				LIST_INIT(&node->list);
-				LIST_ADDQ(&curproxy->logsrvs, &node->list);
-			}
-		}
-		else if (*(args[1]) && *(args[2])) {
-			struct sockaddr_storage *sk;
-			int port1, port2;
-			int arg = 0;
-			int len = 0;
-
-			logsrv = calloc(1, sizeof(*logsrv));
-
-			/* just after the address, a length may be specified */
-			if (strcmp(args[arg+2], "len") == 0) {
-				len = atoi(args[arg+3]);
-				if (len < 80 || len > 65535) {
-					ha_alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
-						 file, linenum, args[arg+3]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-				logsrv->maxlen = len;
-
-				/* skip these two args */
-				arg += 2;
-			}
-			else
-				logsrv->maxlen = MAX_SYSLOG_LEN;
-
-			if (logsrv->maxlen > global.max_syslog_len)
-				global.max_syslog_len = logsrv->maxlen;
-
-			/* after the length, a format may be specified */
-			if (strcmp(args[arg+2], "format") == 0) {
-				logsrv->format = get_log_format(args[arg+3]);
-				if (logsrv->format < 0) {
-					ha_alert("parsing [%s:%d] : unknown log format '%s'\n", file, linenum, args[arg+3]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-
-				/* skip these two args */
-				arg += 2;
-			}
-
-			if (alertif_too_many_args_idx(3, arg + 1, file, linenum, args, &err_code))
-				goto out;
-
-			logsrv->facility = get_log_facility(args[arg+2]);
-			if (logsrv->facility < 0) {
-				ha_alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				goto out;
-
-			}
-	    
-			logsrv->level = 7; /* max syslog level = debug */
-			if (*(args[arg+3])) {
-				logsrv->level = get_log_level(args[arg+3]);
-				if (logsrv->level < 0) {
-					ha_alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-
-				}
-			}
-
-			logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
-			if (*(args[arg+4])) {
-				logsrv->minlvl = get_log_level(args[arg+4]);
-				if (logsrv->minlvl < 0) {
-					ha_alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-
-				}
-			}
-
-			sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
-			if (!sk) {
-				ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg);
-				err_code |= ERR_ALERT | ERR_FATAL;
-				goto out;
-			}
-
-			logsrv->addr = *sk;
-
-			if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
-				if (port1 != port2) {
-					ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
-						 file, linenum, args[0], args[1]);
-					err_code |= ERR_ALERT | ERR_FATAL;
-					goto out;
-				}
-
-				if (!port1)
-					set_host_port(&logsrv->addr, SYSLOG_PORT);
-			}
-
-			LIST_ADDQ(&curproxy->logsrvs, &logsrv->list);
-		}
-		else {
-			ha_alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
-				 file, linenum);
+	else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */
+		if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) {
+			ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
diff --git a/src/log.c b/src/log.c
index e2dde84..1be6dcc 100644
--- a/src/log.c
+++ b/src/log.c
@@ -671,6 +671,166 @@
 	return 1;
 }
 
+/*
+ * Parse "log" keyword and update <logsrvs> list accordingly.
+ *
+ * When <do_del> is set, it means the "no log" line was parsed, so all log
+ * servers in <logsrvs> are released.
+ *
+ * Otherwise, we try to parse the "log" line. First of all, when the list is not
+ * the global one, we look for the parameter "global". If we find it,
+ * global.logsrvs is copied. Else we parse each arguments.
+ *
+ * The function returns 1 in success case, otherwise, it returns 0 and err is
+ * filled.
+ */
+int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
+{
+	struct sockaddr_storage *sk;
+	struct logsrv *logsrv = NULL;
+	int port1, port2;
+	int cur_arg;
+
+	/*
+	 * "no log": delete previous herited or defined syslog
+	 *           servers.
+	 */
+	if (do_del) {
+		struct logsrv *back;
+
+		if (*(args[1]) != 0) {
+			memprintf(err, "'no log' does not expect arguments");
+			goto error;
+		}
+
+		list_for_each_entry_safe(logsrv, back, logsrvs, list) {
+			LIST_DEL(&logsrv->list);
+			free(logsrv);
+		}
+		return 1;
+	}
+
+	/*
+	 * "log global": copy global.logrsvs linked list to the end of logsrvs
+	 *               list. But first, we check (logsrvs != global.logsrvs).
+	 */
+	if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
+		if (logsrvs == &global.logsrvs) {
+			memprintf(err, "'global' is not supported for a global syslog server");
+			goto error;
+		}
+		list_for_each_entry(logsrv, &global.logsrvs, list) {
+			struct logsrv *node = malloc(sizeof(*node));
+			memcpy(node, logsrv, sizeof(struct logsrv));
+			LIST_INIT(&node->list);
+			LIST_ADDQ(logsrvs, &node->list);
+		}
+		return 1;
+	}
+
+	/*
+	* "log <address> ...: parse a syslog server line
+	*/
+	if (*(args[1]) == 0 || *(args[2]) == 0) {
+		memprintf(err, "expects <address> and <facility> %s as arguments",
+			  ((logsrvs == &global.logsrvs) ? "" : "or global"));
+		goto error;
+	}
+
+	logsrv = calloc(1, sizeof(*logsrv));
+	if (!logsrv) {
+		memprintf(err, "out of memory");
+		goto error;
+	}
+
+	/* skip address for now, it will be parsed at the end */
+	cur_arg = 2;
+
+	/* just after the address, a length may be specified */
+	logsrv->maxlen = MAX_SYSLOG_LEN;
+	if (strcmp(args[cur_arg], "len") == 0) {
+		int len = atoi(args[cur_arg+1]);
+		if (len < 80 || len > 65535) {
+			memprintf(err, "invalid log length '%s', must be between 80 and 65535",
+				  args[cur_arg+1]);
+			goto error;
+		}
+		logsrv->maxlen = len;
+		cur_arg += 2;
+	}
+	if (logsrv->maxlen > global.max_syslog_len)
+		global.max_syslog_len = logsrv->maxlen;
+
+	/* after the length, a format may be specified */
+	if (strcmp(args[cur_arg], "format") == 0) {
+		logsrv->format = get_log_format(args[cur_arg+1]);
+		if (logsrv->format < 0) {
+			memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
+			goto error;
+		}
+		cur_arg += 2;
+	}
+
+	/* parse the facility */
+	logsrv->facility = get_log_facility(args[cur_arg]);
+	if (logsrv->facility < 0) {
+		memprintf(err, "unknown log facility '%s'", args[cur_arg]);
+		goto error;
+	}
+	cur_arg++;
+
+	/* parse the max syslog level (default: debug) */
+	logsrv->level = 7;
+	if (*(args[cur_arg])) {
+		logsrv->level = get_log_level(args[cur_arg]);
+		if (logsrv->level < 0) {
+			memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
+			goto error;
+		}
+		cur_arg++;
+	}
+
+	/* parse the limit syslog level (default: emerg) */
+	logsrv->minlvl = 0;
+	if (*(args[cur_arg])) {
+		logsrv->minlvl = get_log_level(args[cur_arg]);
+		if (logsrv->minlvl < 0) {
+			memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
+			goto error;
+		}
+		cur_arg++;
+	}
+
+	/* Too many args */
+	if (*(args[cur_arg])) {
+		memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
+		goto error;
+	}
+
+	/* now, back to the address */
+	sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
+	if (!sk)
+		goto error;
+	logsrv->addr = *sk;
+
+	if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
+		if (port1 != port2) {
+			memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
+			goto error;
+		}
+		logsrv->addr = *sk;
+		if (!port1)
+			set_host_port(&logsrv->addr, SYSLOG_PORT);
+	}
+	LIST_ADDQ(logsrvs, &logsrv->list);
+	return 1;
+
+  error:
+	free(logsrv);
+	return 0;
+}
+
+
 /* Generic function to display messages prefixed by a label */
 static void print_message(const char *label, const char *fmt, va_list argp)
 {