Add enum lens, drop ARGTYPE_ENUM
diff --git a/ChangeLog b/ChangeLog
index fbaa9dc..cd35662 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2012-01-09  Petr Machata  <pmachata@redhat.com>
 
+	* lens_enum.c, lens_enum.h: New files
+	* type.c, type.h (enum arg_type): Drop ARGTYPE_ENUM
+	(type_is_integral, type_is_signed): New functions
+	* read_config_file.c: Rewrite enum parsing
+	* testsuite/ltrace.main/parameters*: Test it
+	* lens_default.c: Drop support for ARGTYPE_ENUM
+	* sysdeps/linux-gnu/x86_64/trace.c: Likewise
+
+2012-01-09  Petr Machata  <pmachata@redhat.com>
+
 	* sysdeps/linux-gnu/*/arch.h
 	(ARCH_ENDIAN_BIG, ARCH_ENDIAN_LITTLE): Declare either at each backend
 
diff --git a/Makefile.am b/Makefile.am
index ceafdf1..c47e851 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,7 +39,8 @@
 	printf.c \
 	zero.c \
 	lens.c \
-	lens_default.c
+	lens_default.c \
+	lens_enum.c
 
 libltrace_la_LIBADD = \
 	$(libelf_LIBS) \
@@ -88,7 +89,8 @@
 	printf.h \
 	zero.h \
 	lens.h \
-	lens_default.h
+	lens_default.h \
+	lens_enum.h
 
 dist_man1_MANS = \
 	ltrace.1
diff --git a/lens_default.c b/lens_default.c
index 75b8abe..afda095 100644
--- a/lens_default.c
+++ b/lens_default.c
@@ -107,20 +107,6 @@
 #undef HANDLE_WIDTH
 
 static int
-format_enum(FILE *stream, struct value *value, struct value_dict *arguments)
-{
-	long l;
-	if (value_extract_word(value, &l, arguments) < 0)
-		return -1;
-
-	const char *name = type_enum_get(value->type, l);
-	if (name != NULL)
-		return fprintf(stream, "%s", name);
-
-	return format_integer(stream, value, INT_FMT_i, arguments);
-}
-
-static int
 acc_fprintf(int *countp, FILE *stream, const char *format, ...)
 {
 	va_list pa;
@@ -350,9 +336,6 @@
 		return format_array(stream, value, arguments,
 				    value->type->u.array_info.length,
 				    options.arraylen, 1, "[ ", " ]", ", ");
-
-	case ARGTYPE_ENUM:
-		return format_enum(stream, value, arguments);
 	}
 	abort();
 }
@@ -433,7 +416,6 @@
 					    arguments, INT_FMT_i);
 
 		int zero;
-	case ARGTYPE_ENUM:
 	case ARGTYPE_SHORT:
 	case ARGTYPE_INT:
 	case ARGTYPE_LONG:
@@ -498,7 +480,6 @@
 	case ARGTYPE_USHORT:
 	case ARGTYPE_UINT:
 	case ARGTYPE_ULONG:
-	case ARGTYPE_ENUM:
 		return toplevel_format_lens(lens, stream, value,
 					    arguments, INT_FMT_i);
 
diff --git a/lens_enum.c b/lens_enum.c
new file mode 100644
index 0000000..1af94d2
--- /dev/null
+++ b/lens_enum.c
@@ -0,0 +1,163 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "arch.h"
+#include "lens_enum.h"
+#include "lens_default.h"
+#include "value.h"
+#include "type.h"
+
+struct enum_entry {
+	char *key;
+	int own_key;
+	struct value *value;
+	int own_value;
+};
+
+static void
+enum_entry_dtor(struct enum_entry *entry, void *data)
+{
+	if (entry->own_key)
+		free(entry->key);
+	if (entry->own_value) {
+		value_destroy(entry->value);
+		free(entry->value);
+	}
+}
+
+static void
+enum_lens_destroy_cb(struct lens *lens)
+{
+	struct enum_lens *self = (void *)lens;
+
+	VECT_DESTROY(&self->entries, struct enum_entry,
+		     enum_entry_dtor, NULL);
+}
+
+enum {
+#ifdef ARCH_ENDIAN_BIG
+	big_endian = 1,
+#elif defined (ARCH_ENDIAN_LITTLE)
+	big_endian = 0,
+#else
+# error Undefined endianness.
+#endif
+};
+
+/* Returns 0 if they are not equal, >0 if they are, and <0 if there
+ * was an error.  */
+static int
+enum_values_equal(struct value *inf_value, struct value *enum_value,
+		  struct value_dict *arguments)
+{
+	/* Width may not match between what's defined in config file
+	 * and what arrives from the back end.  Typically, if there is
+	 * a mismatch, the config file size will be larger, as we are
+	 * in a situation where 64-bit tracer traces 32-bit process.
+	 * But opposite situation can occur e.g. on PPC, where it's
+	 * apparently possible for 32-bit tracer to trace 64-bit
+	 * inferior, or hypothetically in a x32/x86_64 situation.  */
+
+	unsigned char *inf_data = value_get_data(inf_value, arguments);
+	size_t inf_sz = value_size(inf_value, arguments);
+	if (inf_data == NULL || inf_sz == (size_t)-1)
+		return -1;
+
+	assert(inf_value->type->type == enum_value->type->type);
+
+	unsigned char *enum_data = value_get_data(enum_value, arguments);
+	size_t enum_sz = value_size(enum_value, arguments);
+	if (enum_data == NULL || enum_sz == (size_t)-1)
+		return -1;
+
+	size_t sz = enum_sz > inf_sz ? inf_sz : enum_sz;
+
+	if (big_endian)
+		return memcmp(enum_data + enum_sz - sz,
+			      inf_data + inf_sz - sz, sz) == 0;
+	else
+		return memcmp(enum_data, inf_data, sz) == 0;
+}
+
+static const char *
+enum_get(struct enum_lens *lens, struct value *value,
+	 struct value_dict *arguments)
+{
+	size_t i;
+	for (i = 0; i < vect_size(&lens->entries); ++i) {
+		struct enum_entry *entry = VECT_ELEMENT(&lens->entries,
+							struct enum_entry, i);
+		int st = enum_values_equal(value, entry->value, arguments);
+		if (st < 0)
+			return NULL;
+		else if (st != 0)
+			return entry->key;
+	}
+	return NULL;
+}
+
+static int
+enum_lens_format_cb(struct lens *lens, FILE *stream,
+		    struct value *value, struct value_dict *arguments)
+{
+	struct enum_lens *self = (void *)lens;
+
+	long l;
+	if (value_extract_word(value, &l, arguments) < 0)
+		return -1;
+
+	const char *name = enum_get(self, value, arguments);
+	if (name != NULL)
+		return fprintf(stream, "%s", name);
+
+	return lens_format(&default_lens, stream, value, arguments);
+}
+
+
+void
+lens_init_enum(struct enum_lens *lens)
+{
+	*lens = (struct enum_lens){
+		{
+			.format_cb = enum_lens_format_cb,
+			.destroy_cb = enum_lens_destroy_cb,
+		},
+	};
+	VECT_INIT(&lens->entries, struct enum_entry);
+}
+
+int
+lens_enum_add(struct enum_lens *lens,
+	      const char *key, int own_key,
+	      struct value *value, int own_value)
+{
+	struct enum_entry entry = { (char *)key, own_key, value, own_value };
+	return VECT_PUSHBACK(&lens->entries, &entry);
+}
+
+size_t
+lens_enum_size(struct enum_lens *lens)
+{
+	return vect_size(&lens->entries);
+}
diff --git a/lens_enum.h b/lens_enum.h
new file mode 100644
index 0000000..de7b386
--- /dev/null
+++ b/lens_enum.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef LENS_ENUM_H
+#define LENS_ENUM_H
+
+#include "lens.h"
+#include "vect.h"
+
+struct enum_lens {
+	struct lens super;
+	struct vect entries;
+	int own;
+};
+
+/* Init enumeration LENS.  */
+void lens_init_enum(struct enum_lens *lens);
+
+/* Push another member of the enumeration, named KEY, with given
+ * VALUE.  If OWN_KEY, KEY is owned and released after the type is
+ * destroyed.  KEY is typed as const char *, but note that if OWN_KEY,
+ * this value will be freed.  If OWN_VALUE, then VALUE is owned and
+ * destroyed by LENS.  */
+int lens_enum_add(struct enum_lens *lens,
+		  const char *key, int own_key,
+		  struct value *value, int own_value);
+
+/* Return number of enum elements of type INFO.  */
+size_t lens_enum_size(struct enum_lens *lens);
+
+#endif /* LENS_ENUM_H */
diff --git a/read_config_file.c b/read_config_file.c
index 9faa5cf..058a857 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -38,6 +38,8 @@
 #include "zero.h"
 #include "type.h"
 #include "lens.h"
+#include "lens_default.h"
+#include "lens_enum.h"
 
 static int line_no;
 static char *filename;
@@ -49,6 +51,7 @@
 					size_t param_num, int *ownp);
 static struct arg_type_info *parse_lens(char **str, struct param **extra_param,
 					size_t param_num, int *ownp);
+static int parse_enum(char **str, struct arg_type_info **retp, int *ownp);
 
 Function *list_of_functions = NULL;
 
@@ -78,7 +81,6 @@
 	KEYWORD("float", ARGTYPE_FLOAT);
 	KEYWORD("double", ARGTYPE_DOUBLE);
 	KEYWORD("array", ARGTYPE_ARRAY);
-	KEYWORD("enum", ARGTYPE_ENUM);
 	KEYWORD("struct", ARGTYPE_STRUCT);
 
 	assert(rest == NULL);
@@ -633,6 +635,10 @@
 
 		return build_printf_pack(extra_param, param_num);
 
+	} else if (try_parse_kwd(str, "enum") >=0) {
+
+		return parse_enum(str, retp, ownp);
+
 	} else {
 		*retp = NULL;
 		return 0;
@@ -673,17 +679,64 @@
 	return 0;
 }
 
-/* Syntax: enum ( keyname=value,keyname=value,... ) */
+/* Syntax:
+ *   enum (keyname[=value],keyname[=value],... )
+ *   enum<type> (keyname[=value],keyname[=value],... )
+ */
 static int
-parse_enum(char **str, struct arg_type_info *info)
+parse_enum(char **str, struct arg_type_info **retp, int *ownp)
 {
+	/* Optional type argument.  */
+	eat_spaces(str);
+	if (**str == '[') {
+		parse_char(str, '[');
+		eat_spaces(str);
+		*retp = parse_nonpointer_type(str, NULL, 0, ownp);
+		if (*retp == NULL)
+			return -1;
+
+		if (!type_is_integral((*retp)->type)) {
+			report_error(filename, line_no,
+				     "integral type required as enum argument");
+		fail:
+			if (*ownp) {
+				/* This also releases associated lens
+				 * if any was set so far.  */
+				type_destroy(*retp);
+				free(*retp);
+			}
+			return -1;
+		}
+
+		eat_spaces(str);
+		if (parse_char(str, ']') < 0)
+			goto fail;
+
+	} else {
+		*retp = type_get_simple(ARGTYPE_INT);
+		*ownp = 0;
+	}
+
+	/* We'll need to set the lens, so unshare.  */
+	if (unshare_type_info(retp, ownp) < 0)
+		goto fail;
+
 	eat_spaces(str);
 	if (parse_char(str, '(') < 0)
+		goto fail;
+
+	struct enum_lens *lens = malloc(sizeof(*lens));
+	if (lens == NULL) {
+		report_error(filename, line_no,
+			     "malloc enum lens: %s", strerror(errno));
 		return -1;
+	}
 
-	type_init_enum(info);
+	lens_init_enum(lens);
+	(*retp)->lens = &lens->super;
+	(*retp)->own_lens = 1;
 
-	int last_val = 0;
+	long last_val = 0;
 	while (1) {
 		eat_spaces(str);
 		if (**str == 0 || **str == ')') {
@@ -694,7 +747,7 @@
 		/* Field delimiter.  XXX should we support the C
 		 * syntax, where the enumeration can end in pending
 		 * comma?  */
-		if (type_enum_size(info) > 0)
+		if (lens_enum_size(lens) > 0)
 			parse_char(str, ',');
 
 		eat_spaces(str);
@@ -702,23 +755,26 @@
 		if (key == NULL) {
 		err:
 			free(key);
-			return -1;
+			goto fail;
 		}
 
 		if (**str == '=') {
 			++*str;
 			eat_spaces(str);
-			long l;
-			if (parse_int(str, &l) < 0 || check_int(l) < 0)
+			if (parse_int(str, &last_val) < 0)
 				goto err;
-			last_val = l;
-
-		} else {
-			last_val++;
 		}
 
-		if (type_enum_add(info, key, 1, last_val) < 0)
+		struct value *value = malloc(sizeof(*value));
+		if (value == NULL)
 			goto err;
+		value_init_detached(value, NULL, *retp, 0);
+		value_set_long(value, last_val);
+
+		if (lens_enum_add(lens, key, 1, value, 1) < 0)
+			goto err;
+
+		last_val++;
 	}
 
 	return 0;
@@ -766,10 +822,6 @@
 		parser = parse_array;
 		break;
 
-	case ARGTYPE_ENUM:
-		parser = parse_enum;
-		break;
-
 	case ARGTYPE_STRUCT:
 		parser = parse_struct;
 		break;
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
index eaae05e..8e89ae7 100644
--- a/sysdeps/linux-gnu/x86_64/trace.c
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -455,7 +455,6 @@
 	case ARGTYPE_UINT:
 	case ARGTYPE_LONG:
 	case ARGTYPE_ULONG:
-	case ARGTYPE_ENUM:
 
 	case ARGTYPE_POINTER:
 		/* and LONGLONG */
@@ -612,7 +611,6 @@
 	case ARGTYPE_CHAR:
 	case ARGTYPE_SHORT:
 	case ARGTYPE_USHORT:
-	case ARGTYPE_ENUM:
 	case ARGTYPE_POINTER:
 		cls = allocate_integer(context, valuep, sz, 0, POOL_RETVAL);
 		assert(cls == CLASS_INTEGER);
@@ -858,7 +856,6 @@
 	case ARGTYPE_LONG:
 	case ARGTYPE_ULONG:
 	case ARGTYPE_POINTER:
-	case ARGTYPE_ENUM:
 		return 4;
 	}
 	abort();
@@ -890,7 +887,6 @@
 	case ARGTYPE_LONG:
 	case ARGTYPE_ULONG:
 	case ARGTYPE_POINTER:
-	case ARGTYPE_ENUM:
 		return 4;
 
 	case ARGTYPE_VOID:
diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c
index d3ad69c..f9a869d 100644
--- a/testsuite/ltrace.main/parameters-lib.c
+++ b/testsuite/ltrace.main/parameters-lib.c
@@ -219,6 +219,24 @@
 {
 }
 
+long *
+func_short_enums(short values[])
+{
+	static long retvals[4];
+	retvals[0] = values[0];
+	retvals[1] = values[1];
+	retvals[2] = values[2];
+	retvals[3] = values[3];
+	return retvals;
+}
+
+long
+func_negative_enum(short a, unsigned short b, int c, unsigned d,
+		   long e, unsigned long f)
+{
+	return -1;
+}
+
 void
 func_charp_string(char *p)
 {
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
index 5a3f6b2..e8207fe 100644
--- a/testsuite/ltrace.main/parameters.c
+++ b/testsuite/ltrace.main/parameters.c
@@ -207,6 +207,14 @@
   void func_hide(int a, int b, int c, int d, int e, int f);
   func_hide(1, 2, 3, 4, 5, 6);
 
+  enum ab { A, B };
+  long *func_short_enums(short abs[]);
+  func_short_enums((short[]){ A, B, A, A });
+
+  long func_negative_enum(short a, unsigned short b, int c, unsigned d,
+                         long e, unsigned long f);
+  func_negative_enum(-1, -1, -1, -1, -1, -1);
+
   void func_charp_string(char *p);
   func_charp_string("null-terminated string");
 
diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf
index 419ad1f..9e0c967 100644
--- a/testsuite/ltrace.main/parameters.conf
+++ b/testsuite/ltrace.main/parameters.conf
@@ -26,4 +26,6 @@
 void func_lens(octal, octal(long), hex(short), hex(long));
 bool(int) func_bool(int, bool(int));
 void func_hide(int, hide(int), hide(int), int, hide(int), int);
+array(enum[long](A,B), 4) *func_short_enums(array(enum[short](A,B), 4));
+enum[long](A=-1) func_negative_enum(enum[short](A=-1), enum[ushort](A=-1), enum[int](A=-1), enum[uint](A=-1), enum[long](A=-1), enum[ulong](A=-1));
 void func_charp_string(string(char *));
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
index 9be7b58..62991e9 100644
--- a/testsuite/ltrace.main/parameters.exp
+++ b/testsuite/ltrace.main/parameters.exp
@@ -127,5 +127,11 @@
 set pattern "func_hide(1, 4, 6)"
 ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
 
+set pattern "func_short_enums(. A, B, A, A .).*= . A, B, A, A ."
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
+
+set pattern "func_negative_enum(A, A, A, A, A, A).*= A"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
+
 set pattern "func_charp_string(\\\"null-terminated string\\\")"
 ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
diff --git a/type.c b/type.c
index 00775aa..6341042 100644
--- a/type.c
+++ b/type.c
@@ -21,6 +21,7 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#include <limits.h>
 
 #include "type.h"
 #include "sysdep.h"
@@ -51,7 +52,6 @@
 #undef HANDLE
 
 	case ARGTYPE_ARRAY:
-	case ARGTYPE_ENUM:
 	case ARGTYPE_STRUCT:
 	case ARGTYPE_POINTER:
 		assert(!"Not a simple type!");
@@ -67,63 +67,6 @@
 	info->own_lens = 0;
 }
 
-struct enum_entry {
-	char *key;
-	int own_key;
-	int value;
-};
-
-void
-type_init_enum(struct arg_type_info *info)
-{
-	type_init_common(info, ARGTYPE_ENUM);
-	VECT_INIT(&info->u.entries, struct enum_entry);
-}
-
-int
-type_enum_add(struct arg_type_info *info,
-	      const char *key, int own_key, int value)
-{
-	assert(info->type == ARGTYPE_ENUM);
-	struct enum_entry entry = { (char *)key, own_key, value };
-	return VECT_PUSHBACK(&info->u.entries, &entry);
-}
-
-size_t
-type_enum_size(struct arg_type_info *info)
-{
-	assert(info->type == ARGTYPE_ENUM);
-	return vect_size(&info->u.entries);
-}
-
-const char *
-type_enum_get(struct arg_type_info *info, int value)
-{
-	assert(info->type == ARGTYPE_ENUM);
-	size_t i;
-	for (i = 0; i < vect_size(&info->u.entries); ++i) {
-		struct enum_entry *entry = VECT_ELEMENT(&info->u.entries,
-							struct enum_entry, i);
-		if (value == entry->value)
-			return entry->key;
-	}
-	return NULL;
-}
-
-static void
-enum_entry_dtor(struct enum_entry *entry, void *data)
-{
-	if (entry->own_key)
-		free(entry->key);
-}
-
-static void
-type_enum_destroy(struct arg_type_info *info)
-{
-	VECT_DESTROY(&info->u.entries, struct enum_entry,
-		     enum_entry_dtor, NULL);
-}
-
 struct struct_field {
 	struct arg_type_info *info;
 	int own_info;
@@ -279,10 +222,6 @@
 		return;
 
 	switch (info->type) {
-	case ARGTYPE_ENUM:
-		type_enum_destroy(info);
-		break;
-
 	case ARGTYPE_STRUCT:
 		type_struct_destroy(info);
 		break;
@@ -367,7 +306,6 @@
 
 	case ARGTYPE_INT:
 	case ARGTYPE_UINT:
-	case ARGTYPE_ENUM:
 		return sizeof(int);
 
 	case ARGTYPE_LONG:
@@ -521,3 +459,57 @@
 		abort();
 	}
 }
+
+int
+type_is_integral(enum arg_type type)
+{
+	switch (type) {
+	case ARGTYPE_INT:
+	case ARGTYPE_UINT:
+	case ARGTYPE_LONG:
+	case ARGTYPE_ULONG:
+	case ARGTYPE_CHAR:
+	case ARGTYPE_SHORT:
+	case ARGTYPE_USHORT:
+		return 1;
+
+	case ARGTYPE_VOID:
+	case ARGTYPE_FLOAT:
+	case ARGTYPE_DOUBLE:
+	case ARGTYPE_ARRAY:
+	case ARGTYPE_STRUCT:
+	case ARGTYPE_POINTER:
+		return 0;
+	}
+	abort();
+}
+
+int
+type_is_signed(enum arg_type type)
+{
+	assert(type_is_integral(type));
+
+	switch (type) {
+	case ARGTYPE_CHAR:
+		return CHAR_MIN != 0;
+
+	case ARGTYPE_SHORT:
+	case ARGTYPE_INT:
+	case ARGTYPE_LONG:
+		return 1;
+
+	case ARGTYPE_UINT:
+	case ARGTYPE_ULONG:
+	case ARGTYPE_USHORT:
+		return 0;
+
+	case ARGTYPE_VOID:
+	case ARGTYPE_FLOAT:
+	case ARGTYPE_DOUBLE:
+	case ARGTYPE_ARRAY:
+	case ARGTYPE_STRUCT:
+	case ARGTYPE_POINTER:
+		abort();
+	}
+	abort();
+}
diff --git a/type.h b/type.h
index d0b106f..545173c 100644
--- a/type.h
+++ b/type.h
@@ -38,7 +38,6 @@
 	ARGTYPE_FLOAT,
 	ARGTYPE_DOUBLE,
 	ARGTYPE_ARRAY,		/* Series of values in memory */
-	ARGTYPE_ENUM,		/* Enumeration */
 	ARGTYPE_STRUCT,		/* Structure of values */
 	ARGTYPE_POINTER,	/* Pointer to some other type */
 };
@@ -68,27 +67,10 @@
 };
 
 /* Return a type info for simple type TYPE (which shall not be array,
- * struct, enum or pointer.  Each call with the same TYPE yields the
- * same arg_type_info pointer.  */
+ * struct, or pointer.  Each call with the same TYPE yields the same
+ * arg_type_info pointer.  */
 struct arg_type_info *type_get_simple(enum arg_type type);
 
-/* Initialize INFO so it becomes ARGTYPE_ENUM.  Returns 0 on success
- * or negative value on failure.  */
-void type_init_enum(struct arg_type_info *info);
-
-/* Push another member of the enumeration, named KEY, with given
- * VALUE.  If OWN_KEY, KEY is owned and released after the type is
- * destroyed.  KEY is typed as const char *, but note that if
- * OWN_KEY, this value will be freed.  */
-int type_enum_add(struct arg_type_info *info,
-		  const char *key, int own_key, int value);
-
-/* Return number of enum elements of type INFO.  */
-size_t type_enum_size(struct arg_type_info *info);
-
-/* Look up enum key with given VALUE in INFO.  */
-const char *type_enum_get(struct arg_type_info *info, int value);
-
 /* Initialize INFO so it becomes ARGTYPE_STRUCT.  The created
  * structure contains no fields.  Use type_struct_add to populate the
  * structure.  */
@@ -142,4 +124,10 @@
 size_t type_offsetof(struct Process *proc,
 		     struct arg_type_info *type, size_t elt);
 
+/* Whether TYPE is an integral type as defined by the C standard.  */
+int type_is_integral(enum arg_type type);
+
+/* Whether TYPE, which shall be integral, is a signed type.  */
+int type_is_signed(enum arg_type type);
+
 #endif /* TYPE_H */