Rewrite system_calls.exp
[platform/upstream/ltrace.git] / lens_default.c
index f0bd616..958114f 100644 (file)
@@ -21,6 +21,8 @@
  * 02110-1301 USA
  */
 
+#define _XOPEN_SOURCE /* For wcwidth from wchar.h.  */
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <wchar.h>
 
 #include "bits.h"
-#include "proc.h"
-#include "lens_default.h"
-#include "value.h"
 #include "expr.h"
+#include "lens_default.h"
+#include "options.h"
+#include "output.h"
 #include "type.h"
-#include "common.h"
+#include "value.h"
 #include "zero.h"
 
 #define READER(NAME, TYPE)                                             \
@@ -123,13 +126,8 @@ acc_fprintf(int *countp, FILE *stream, const char *format, ...)
 }
 
 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 +171,23 @@ format_char(FILE *stream, struct value *value, struct value_dict *arguments)
 }
 
 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 +347,7 @@ done:
  * 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 +415,8 @@ toplevel_format_lens(struct lens *lens, FILE *stream,
 
        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 +551,51 @@ struct lens bool_lens = {
        .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;
+       if (fprintf(stream, "%s", buf) < 0)
+               return -1;
+
+       c = wcwidth(wc);
+       return c >= 0 ? c : 0;
+}
 
 static int
 string_lens_format_cb(struct lens *lens, FILE *stream,
@@ -554,39 +608,39 @@ string_lens_format_cb(struct lens *lens, FILE *stream,
                 * 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;
-               }
-
-               /* fall-through */
+               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);
+
+               /* 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);