diff options
author | Petr Machata <pmachata@redhat.com> | 2013-11-11 02:24:42 +0100 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-08-22 20:38:23 +0900 |
commit | e6c25f6799825812e2b87990333c649ba796f600 (patch) | |
tree | 8d68002e600f53c912433310ced3b13fb2883b95 /lens_default.c | |
parent | f292cf4e52c73fcc3b63ba2b032d17822f63e6e8 (diff) | |
download | ltrace-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.c | 115 |
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); |