Add module param.c/param.h

- this allows support of parameter packs, which in particular enables
  re-introducing of "format" and others in a more systematic manner
diff --git a/output.c b/output.c
index ee444d5..59e02b7 100644
--- a/output.c
+++ b/output.c
@@ -32,6 +32,7 @@
 #include <sys/time.h>
 #include <unistd.h>
 #include <errno.h>
+#include <assert.h>
 
 #include "common.h"
 #include "proc.h"
@@ -39,6 +40,7 @@
 #include "type.h"
 #include "value.h"
 #include "value_dict.h"
+#include "param.h"
 #include "fetch.h"
 
 /* TODO FIXME XXX: include in common.h: */
@@ -142,13 +144,23 @@
 	ret->return_info = unknown_type;
 
 	ret->num_params = 4;
-	for (i = 0; i < (size_t)ret->num_params; ++i)
-		ret->arg_info[i] = unknown_type;
+	ret->params = malloc(sizeof(*ret->params) * ret->num_params);
+	if (ret->params == NULL)
+		goto err;
+
+	for (i = 0; i < ret->num_params; ++i)
+		param_init_type(&ret->params[i], unknown_type, 0);
 
 	return ret;
 
 err:
 	report_global_error("malloc: %s", strerror(errno));
+	if (ret->params != NULL) {
+		while (i-- > 0)
+			param_destroy(&ret->params[i]);
+		free(ret->params);
+	}
+
 	free(ret);
 
 	return NULL;
@@ -264,12 +276,76 @@
 }
 
 static int
+fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
+		 struct value_dict *arguments, struct param *param,
+		 ssize_t *params_leftp)
+{
+	struct param_enum *e = param_pack_init(param, arguments);
+	if (e == NULL)
+		return -1;
+
+	int ret = 0;
+	while (1) {
+		int insert_stop = 0;
+		struct arg_type_info *info = malloc(sizeof(*info));
+		if (info == NULL
+		    || param_pack_next(param, e, info, &insert_stop) < 0) {
+		fail:
+			free(info);
+			ret = -1;
+			break;
+		}
+
+		if (insert_stop)
+			fetch_param_stop(arguments, params_leftp);
+
+		if (info->type == ARGTYPE_VOID)
+			break;
+
+		struct value val;
+		if (fetch_simple_param(type, proc, context, arguments,
+				       info, &val) < 0)
+			goto fail;
+
+		int stop = 0;
+		switch (param_pack_stop(param, e, &val)) {
+		case PPCB_ERR:
+			goto fail;
+		case PPCB_STOP:
+			stop = 1;
+		case PPCB_CONT:
+			break;
+		}
+
+		if (stop)
+			break;
+	}
+
+	param_pack_done(param, e);
+	return ret;
+}
+
+static int
 fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
-		struct value_dict *arguments, struct arg_type_info *info,
+		struct value_dict *arguments, struct param *param,
 		ssize_t *params_leftp)
 {
-	return fetch_simple_param(type, proc, context, arguments,
-				  info, NULL);
+	switch (param->flavor) {
+	case PARAM_FLAVOR_TYPE:
+		return fetch_simple_param(type, proc, context, arguments,
+					  param->u.type.type, NULL);
+
+	case PARAM_FLAVOR_PACK:
+		return fetch_param_pack(type, proc, context, arguments,
+					param, params_leftp);
+
+	case PARAM_FLAVOR_STOP:
+		fetch_param_stop(arguments, params_leftp);
+		return 0;
+	}
+
+	assert(!"Invalid param flavor!");
+	abort();
 }
 
 static int
@@ -277,16 +353,14 @@
 	     struct value_dict *arguments, Function *func, ssize_t *params_leftp)
 {
 	size_t i;
-	for (i = 0; i < (size_t)func->num_params; ++i) {
-		if (i == (size_t)(func->num_params - func->params_right))
-			fetch_param_stop(arguments, params_leftp);
+	for (i = 0; i < func->num_params; ++i)
 		if (fetch_one_param(type, proc, context, arguments,
-				    func->arg_info[i], params_leftp) < 0)
+				    &func->params[i], params_leftp) < 0)
 			return -1;
-	}
 
 	/* Implicit stop at the end of parameter list.  */
 	fetch_param_stop(arguments, params_leftp);
+
 	return 0;
 }
 
@@ -370,7 +444,8 @@
 	    || output_params(arguments, 0, params_left, &need_delim) < 0) {
 		val_dict_destroy(arguments);
 		fetch_arg_done(context);
-		return;
+		arguments = NULL;
+		context = NULL;
 	}
 
 	struct callstack_element *stel
@@ -474,9 +549,12 @@
 	if (own_retval)
 		value_destroy(&retval);
 
-	val_dict_destroy(stel->arguments);
-	free(stel->arguments);
-	fetch_arg_done(context);
+	if (stel->arguments != NULL) {
+		val_dict_destroy(stel->arguments);
+		free(stel->arguments);
+	}
+	if (context != NULL)
+		fetch_arg_done(context);
 
 	if (opt_T) {
 		fprintf(options.output, " <%lu.%06d>",