Support wide character strings

- "string" lens and "format" pack were extended such that using an
  integer as underlying array type denotes a wide character string.

- several prototypes from wchar.h were added to libc.so.conf.

- ltrace.conf.5 was updated
diff --git a/lens_default.c b/lens_default.c
index f0bd616..1e57587 100644
--- a/lens_default.c
+++ b/lens_default.c
@@ -123,13 +123,8 @@
 }
 
 static int
-format_char(FILE *stream, struct value *value, struct value_dict *arguments)
+print_char(FILE *stream, int c)
 {
-	long lc;
-	if (value_extract_word(value, &lc, arguments) < 0)
-		return -1;
-	int c = (int)lc;
-
 	const char *fmt;
 	switch (c) {
 	case -1:
@@ -173,13 +168,23 @@
 }
 
 static int
-format_naked_char(FILE *stream, struct value *value,
-		  struct value_dict *arguments)
+format_char(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+	long lc;
+	if (value_extract_word(value, &lc, arguments) < 0)
+		return -1;
+	return print_char(stream, (int) lc);
+}
+
+static int
+format_naked(FILE *stream, struct value *value,
+	     struct value_dict *arguments,
+	     int (*what)(FILE *, struct value *, struct value_dict *))
 {
 	int written = 0;
 	if (acc_fprintf(&written, stream, "'") < 0
 	    || account_output(&written,
-			      format_char(stream, value, arguments)) < 0
+			      what(stream, value, arguments)) < 0
 	    || acc_fprintf(&written, stream, "'") < 0)
 		return -1;
 
@@ -339,7 +344,7 @@
  * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
  *    delimiter.
  */
-int
+static int
 format_array(FILE *stream, struct value *value, struct value_dict *arguments,
 	     struct expr_node *length, size_t maxlen, int before,
 	     const char *open, const char *close, const char *delim)
@@ -407,7 +412,8 @@
 
 	case ARGTYPE_CHAR:
 		if (int_fmt == INT_FMT_default)
-			return format_naked_char(stream, value, arguments);
+			return format_naked(stream, value, arguments,
+					    &format_char);
 		return format_integer(stream, value, int_fmt, arguments);
 
 	case ARGTYPE_FLOAT:
@@ -542,6 +548,47 @@
 	.format_cb = bool_lens_format_cb,
 };
 
+static int
+redispatch_as_array(struct lens *lens, FILE *stream,
+		    struct value *value, struct value_dict *arguments,
+		    int (*cb)(struct lens *, FILE *,
+			      struct value *, struct value_dict *))
+{
+	struct arg_type_info info[2];
+	type_init_array(&info[1], value->type->u.ptr_info.info, 0,
+			expr_node_zero(), 0);
+	type_init_pointer(&info[0], &info[1], 0);
+	info->lens = lens;
+	info->own_lens = 0;
+	struct value tmp;
+	if (value_clone(&tmp, value) < 0)
+		return -1;
+	value_set_type(&tmp, info, 0);
+	int ret = cb(lens, stream, &tmp, arguments);
+	type_destroy(&info[0]);
+	type_destroy(&info[1]);
+	value_destroy(&tmp);
+	return ret;
+}
+
+static int
+format_wchar(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+	long l;
+	if (value_extract_word(value, &l, arguments) < 0)
+		return -1;
+	wchar_t wc = (wchar_t) l;
+	char buf[MB_CUR_MAX + 1];
+
+	int c = wctomb(buf, wc);
+	if (c < 0)
+		return -1;
+	if (c == 1)
+		return print_char(stream, buf[0]);
+
+	buf[c] = 0;
+	return fprintf(stream, "%s", buf) >= 0 ? 1 : -1;
+}
 
 static int
 string_lens_format_cb(struct lens *lens, FILE *stream,
@@ -554,39 +601,39 @@
 		 * I suspect people are so used to the char * C idiom,
 		 * that string(char *) might actually turn up.  So
 		 * let's just support it.  */
-		if (value->type->u.ptr_info.info->type == ARGTYPE_CHAR) {
-			struct arg_type_info info[2];
-			type_init_array(&info[1],
-					value->type->u.ptr_info.info, 0,
-					expr_node_zero(), 0);
-			type_init_pointer(&info[0], &info[1], 0);
-			info->lens = lens;
-			info->own_lens = 0;
-			struct value tmp;
-			if (value_clone(&tmp, value) < 0)
-				return -1;
-			value_set_type(&tmp, info, 0);
-			int ret = string_lens_format_cb(lens, stream, &tmp,
-							arguments);
-			type_destroy(&info[0]);
-			type_destroy(&info[1]);
-			value_destroy(&tmp);
-			return ret;
-		}
+		switch ((int) value->type->u.ptr_info.info->type)
+		case ARGTYPE_CHAR:
+		case ARGTYPE_SHORT:
+		case ARGTYPE_USHORT:
+		case ARGTYPE_INT:
+		case ARGTYPE_UINT:
+		case ARGTYPE_LONG:
+		case ARGTYPE_ULONG:
+			return redispatch_as_array(lens, stream, value,
+						   arguments,
+						   &string_lens_format_cb);
 
-		/* fall-through */
+		/* Otherwise dispatch to whatever the default for the
+		 * pointee is--most likely this will again be us.  */
+		/* Fall through.  */
 	case ARGTYPE_VOID:
 	case ARGTYPE_FLOAT:
 	case ARGTYPE_DOUBLE:
 	case ARGTYPE_STRUCT:
+		return toplevel_format_lens(lens, stream, value,
+					    arguments, INT_FMT_default);
+
 	case ARGTYPE_SHORT:
 	case ARGTYPE_INT:
 	case ARGTYPE_LONG:
 	case ARGTYPE_USHORT:
 	case ARGTYPE_UINT:
 	case ARGTYPE_ULONG:
-		return toplevel_format_lens(lens, stream, value,
-					    arguments, INT_FMT_default);
+		if (value->parent != NULL && value->type->lens == NULL)
+			return format_wchar(stream, value, arguments);
+		else
+			return format_naked(stream, value, arguments,
+					    &format_wchar);
 
 	case ARGTYPE_CHAR:
 		return format_char(stream, value, arguments);