summaryrefslogtreecommitdiff
path: root/lens_default.c
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2013-11-11 02:24:42 +0100
committerChanho Park <chanho61.park@samsung.com>2014-08-22 20:38:23 +0900
commite6c25f6799825812e2b87990333c649ba796f600 (patch)
tree8d68002e600f53c912433310ced3b13fb2883b95 /lens_default.c
parentf292cf4e52c73fcc3b63ba2b032d17822f63e6e8 (diff)
downloadltrace-e6c25f6799825812e2b87990333c649ba796f600.tar.gz
ltrace-e6c25f6799825812e2b87990333c649ba796f600.tar.bz2
ltrace-e6c25f6799825812e2b87990333c649ba796f600.zip
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
Diffstat (limited to 'lens_default.c')
-rw-r--r--lens_default.c115
1 files changed, 81 insertions, 34 deletions
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 @@ 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 +168,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 +344,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 +412,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 +548,47 @@ 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;
+ return fprintf(stream, "%s", buf) >= 0 ? 1 : -1;
+}
static int
string_lens_format_cb(struct lens *lens, FILE *stream,
@@ -554,39 +601,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);