Add lenses
- this adds the lens framework, although there are currently no interesting
lenses. display_args.c was mostly moved to lens_default.c
diff --git a/lens_default.c b/lens_default.c
new file mode 100644
index 0000000..e39f228
--- /dev/null
+++ b/lens_default.c
@@ -0,0 +1,387 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 1998,2004,2007,2008,2009 Juan Cespedes
+ * Copyright (C) 2006 Ian Wienand
+ * Copyright (C) 2006 Steve Fink
+ *
+ * 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 <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "proc.h"
+#include "lens_default.h"
+#include "value.h"
+#include "expr.h"
+#include "type.h"
+#include "common.h"
+#include "zero.h"
+
+#define READER(NAME, TYPE) \
+ static int \
+ NAME(struct value *value, TYPE *ret, struct value_dict *arguments) \
+ { \
+ union { \
+ TYPE val; \
+ unsigned char buf[0]; \
+ } u; \
+ if (value_extract_buf(value, u.buf, arguments) < 0) \
+ return -1; \
+ *ret = u.val; \
+ return 0; \
+ }
+
+READER(read_float, float)
+READER(read_double, double)
+
+#undef READER
+
+#define HANDLE_WIDTH(BITS) \
+ do { \
+ long l; \
+ if (value_extract_word(value, &l, arguments) < 0) \
+ return -1; \
+ int##BITS##_t i = l; \
+ switch (format) { \
+ case INT_FMT_unknown: \
+ if (i < -10000 || i > 10000) \
+ case INT_FMT_x: \
+ return fprintf(stream, "%#"PRIx##BITS, i); \
+ case INT_FMT_i: \
+ return fprintf(stream, "%"PRIi##BITS, i); \
+ case INT_FMT_u: \
+ return fprintf(stream, "%"PRIu##BITS, i); \
+ case INT_FMT_o: \
+ return fprintf(stream, "0%"PRIo##BITS, i); \
+ } \
+ } while (0)
+
+enum int_fmt_t
+{
+ INT_FMT_i,
+ INT_FMT_u,
+ INT_FMT_o,
+ INT_FMT_x,
+ INT_FMT_unknown,
+};
+
+static int
+format_integer(FILE *stream, struct value *value, enum int_fmt_t format,
+ struct value_dict *arguments)
+{
+ switch (type_sizeof(value->inferior, value->type)) {
+
+ case 1: HANDLE_WIDTH(8);
+ case 2: HANDLE_WIDTH(16);
+ case 4: HANDLE_WIDTH(32);
+ case 8: HANDLE_WIDTH(64);
+
+ default:
+ assert(!"unsupported integer width");
+ abort();
+
+ case -1:
+ return -1;
+ }
+}
+
+#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;
+ va_start(pa, format);
+ int i = vfprintf(stream, format, pa);
+ va_end(pa);
+
+ if (i >= 0)
+ *countp += i;
+ return i;
+}
+
+static int
+format_char(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+ long lc;
+ if (value_extract_word(value, &lc, arguments) < 0)
+ return -1;
+ int c = (int)lc;
+
+ /* If this value is not wrapped in array, then this is not a
+ * string, and we need to display quotes. */
+ int quote = !(value->parent != NULL
+ && (value->parent->type->type == ARGTYPE_ARRAY
+ || value->parent->type->type == ARGTYPE_STRING_N));
+ int written = 0;
+ if (quote && acc_fprintf(&written, stream, "'") < 0)
+ return -1;
+
+ const char *fmt;
+ switch (c) {
+ case -1:
+ fmt = "EOF";
+ break;
+ case 0:
+ fmt = "\\0";
+ break;
+ case '\a':
+ fmt = "\\a";
+ break;
+ case '\b':
+ fmt = "\\b";
+ break;
+ case '\t':
+ fmt = "\\t";
+ break;
+ case '\n':
+ fmt = "\\n";
+ break;
+ case '\v':
+ fmt = "\\v";
+ break;
+ case '\f':
+ fmt = "\\f";
+ break;
+ case '\r':
+ fmt = "\\r";
+ break;
+ case '\\':
+ fmt = "\\\\";
+ break;
+ default:
+ if (isprint(c) || c == ' ')
+ fmt = "%c";
+ else if (acc_fprintf(&written, stream, "\\%03o",
+ (unsigned char)c) < 0)
+ return -1;
+ else
+ fmt = NULL;
+ }
+
+ if (fmt != NULL && acc_fprintf(&written, stream, fmt, c) < 0)
+ return -1;
+ if (quote && acc_fprintf(&written, stream, "'") < 0)
+ return -1;
+ return written;
+}
+
+static int
+format_floating(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+ switch (value->type->type) {
+ float f;
+ double d;
+ case ARGTYPE_FLOAT:
+ if (read_float(value, &f, arguments) < 0)
+ return -1;
+ return fprintf(stream, "%f", (double)f);
+ case ARGTYPE_DOUBLE:
+ if (read_double(value, &d, arguments) < 0)
+ return -1;
+ return fprintf(stream, "%f", d);
+ default:
+ abort();
+ }
+}
+
+static int
+format_struct(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+ int written = 0;
+ if (acc_fprintf(&written, stream, "{ ") < 0)
+ return -1;
+ size_t i;
+ for (i = 0; i < type_struct_size(value->type); ++i) {
+ if (i > 0 && acc_fprintf(&written, stream, ", ") < 0)
+ return -1;
+
+ struct value element;
+ if (value_init_element(&element, value, i) < 0)
+ return -1;
+ int o = format_argument(stream, &element, arguments);
+ if (o < 0)
+ return -1;
+ written += o;
+ }
+ if (acc_fprintf(&written, stream, " }") < 0)
+ return -1;
+ return written;
+}
+
+int
+format_pointer(FILE *stream, struct value *value, struct value_dict *arguments)
+{
+ struct value element;
+ if (value_init_deref(&element, value) < 0)
+ return -1;
+ return format_argument(stream, &element, arguments);
+}
+
+/*
+ * LENGTH is an expression whose evaluation will yield the actual
+ * length of the array.
+ *
+ * MAXLEN is the actual maximum length that we care about
+ *
+ * BEFORE if LENGTH>MAXLEN, we display ellipsis. We display it before
+ * the closing parenthesis if BEFORE, otherwise after it.
+ *
+ * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
+ * delimiter.
+ */
+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)
+{
+ /* We need "long" to be long enough to cover the whole address
+ * space. */
+ typedef char assert__long_enough_long[-(sizeof(long) < sizeof(void *))];
+ long l;
+ if (expr_eval_word(length, value, arguments, &l) < 0)
+ return -1;
+ size_t len = (size_t)l;
+
+ int written = 0;
+ if (acc_fprintf(&written, stream, "%s", open) < 0)
+ return -1;
+
+ size_t i;
+ for (i = 0; i < len && i <= maxlen; ++i) {
+ if (i == maxlen) {
+ if (before && acc_fprintf(&written, stream, "...") < 0)
+ return -1;
+ break;
+ }
+
+ if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0)
+ return -1;
+
+ struct value element;
+ if (value_init_element(&element, value, i) < 0)
+ return -1;
+ int o = format_argument(stream, &element, arguments);
+ if (o < 0)
+ return -1;
+ written += o;
+ }
+ if (acc_fprintf(&written, stream, "%s", close) < 0)
+ return -1;
+ if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0)
+ return -1;
+
+ return written;
+}
+
+static int
+toplevel_format_lens(struct lens *lens, FILE *stream,
+ struct value *value, struct value_dict *arguments)
+{
+ switch (value->type->type) {
+ struct value *tmp;
+ int ret;
+
+ case ARGTYPE_VOID:
+ return fprintf(stream, "<void>");
+
+ case ARGTYPE_UNKNOWN:
+ return format_integer(stream, value, INT_FMT_unknown,
+ arguments);
+
+ case ARGTYPE_SHORT:
+ case ARGTYPE_INT:
+ case ARGTYPE_LONG:
+ return format_integer(stream, value, INT_FMT_i, arguments);
+
+ case ARGTYPE_USHORT:
+ case ARGTYPE_UINT:
+ case ARGTYPE_ULONG:
+ return format_integer(stream, value, INT_FMT_u, arguments);
+
+ case ARGTYPE_OCTAL:
+ return format_integer(stream, value, INT_FMT_o, arguments);
+
+ case ARGTYPE_CHAR:
+ return format_char(stream, value, arguments);
+
+ case ARGTYPE_FLOAT:
+ case ARGTYPE_DOUBLE:
+ return format_floating(stream, value, arguments);
+
+ case ARGTYPE_STRUCT:
+ return format_struct(stream, value, arguments);
+
+ case ARGTYPE_POINTER:
+ if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID)
+ return format_pointer(stream, value, arguments);
+ return format_integer(stream, value, INT_FMT_x, arguments);
+
+ case ARGTYPE_ARRAY:
+ if (value->type->u.array_info.elt_type->type != ARGTYPE_CHAR)
+ return format_array(stream, value, arguments,
+ value->type->u.array_info.length,
+ options.arraylen, 1,
+ "[ ", " ]", ", ");
+
+ return format_array(stream, value, arguments,
+ value->type->u.array_info.length,
+ options.strlen, 0, "\"", "\"", "");
+
+ case ARGTYPE_STRING_N:
+ tmp = value_string_to_charp(value);
+ if (tmp == NULL)
+ return -1;
+ ret = format_argument(stream, tmp, arguments);
+ value_destroy(tmp);
+ return ret;
+
+ case ARGTYPE_ENUM:
+ return format_enum(stream, value, arguments);
+ }
+ abort();
+}
+
+static int
+default_lens_format_cb(struct lens *lens, FILE *stream,
+ struct value *value, struct value_dict *arguments)
+{
+ return toplevel_format_lens(lens, stream, value, arguments);
+}
+
+struct lens default_lens = {
+ .format_cb = default_lens_format_cb,
+};