| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * This file is part of ltrace. | 
| Petr Machata | d8286ed | 2013-11-04 13:35:38 +0100 | [diff] [blame] | 3 |  * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 4 |  * Copyright (C) 1998,2004,2007,2008,2009 Juan Cespedes | 
 | 5 |  * Copyright (C) 2006 Ian Wienand | 
 | 6 |  * Copyright (C) 2006 Steve Fink | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or | 
 | 9 |  * modify it under the terms of the GNU General Public License as | 
 | 10 |  * published by the Free Software Foundation; either version 2 of the | 
 | 11 |  * License, or (at your option) any later version. | 
 | 12 |  * | 
 | 13 |  * This program is distributed in the hope that it will be useful, but | 
 | 14 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 15 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 16 |  * General Public License for more details. | 
 | 17 |  * | 
 | 18 |  * You should have received a copy of the GNU General Public License | 
 | 19 |  * along with this program; if not, write to the Free Software | 
 | 20 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
 | 21 |  * 02110-1301 USA | 
 | 22 |  */ | 
 | 23 |  | 
| Petr Machata | caccda0 | 2013-11-11 16:08:42 +0100 | [diff] [blame] | 24 | #define _XOPEN_SOURCE /* For wcwidth from wchar.h.  */ | 
 | 25 |  | 
| Steve Fink | 7bafff0 | 2006-08-07 04:50:42 +0200 | [diff] [blame] | 26 | #include <ctype.h> | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 27 | #include <stdlib.h> | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 28 | #include <assert.h> | 
 | 29 | #include <inttypes.h> | 
 | 30 | #include <stdarg.h> | 
 | 31 | #include <stdio.h> | 
| Petr Machata | 307b90b | 2012-11-19 00:35:38 +0100 | [diff] [blame] | 32 | #include <string.h> | 
| Petr Machata | caccda0 | 2013-11-11 16:08:42 +0100 | [diff] [blame] | 33 | #include <wchar.h> | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 34 |  | 
| Petr Machata | 1721fc9 | 2013-01-21 16:14:20 +0100 | [diff] [blame] | 35 | #include "bits.h" | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 36 | #include "expr.h" | 
| Petr Machata | caccda0 | 2013-11-11 16:08:42 +0100 | [diff] [blame] | 37 | #include "lens_default.h" | 
 | 38 | #include "options.h" | 
 | 39 | #include "output.h" | 
| Petr Machata | 000e311 | 2012-01-03 17:03:39 +0100 | [diff] [blame] | 40 | #include "type.h" | 
| Petr Machata | caccda0 | 2013-11-11 16:08:42 +0100 | [diff] [blame] | 41 | #include "value.h" | 
| Petr Machata | d7b2292 | 2012-01-06 18:34:22 +0100 | [diff] [blame] | 42 | #include "zero.h" | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 43 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 44 | #define READER(NAME, TYPE)						\ | 
 | 45 | 	static int							\ | 
 | 46 | 	NAME(struct value *value, TYPE *ret, struct value_dict *arguments) \ | 
 | 47 | 	{								\ | 
 | 48 | 		union {							\ | 
 | 49 | 			TYPE val;					\ | 
 | 50 | 			unsigned char buf[0];				\ | 
 | 51 | 		} u;							\ | 
 | 52 | 		if (value_extract_buf(value, u.buf, arguments) < 0)	\ | 
 | 53 | 			return -1;					\ | 
 | 54 | 		*ret = u.val;						\ | 
 | 55 | 		return 0;						\ | 
| Juan Cespedes | a413e5b | 2007-09-04 17:34:53 +0200 | [diff] [blame] | 56 | 	} | 
| Steve Fink | 65b53df | 2006-09-25 02:27:08 +0200 | [diff] [blame] | 57 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 58 | READER(read_float, float) | 
 | 59 | READER(read_double, double) | 
 | 60 |  | 
 | 61 | #undef READER | 
 | 62 |  | 
 | 63 | #define HANDLE_WIDTH(BITS)						\ | 
 | 64 | 	do {								\ | 
 | 65 | 		long l;							\ | 
 | 66 | 		if (value_extract_word(value, &l, arguments) < 0)	\ | 
 | 67 | 			return -1;					\ | 
 | 68 | 		int##BITS##_t i = l;					\ | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 69 | 		uint64_t v = (uint64_t)(uint##BITS##_t)i;		\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 70 | 		switch (format) {					\ | 
 | 71 | 		case INT_FMT_unknown:					\ | 
| Petr Machata | c1e4186 | 2012-08-31 15:13:16 +0200 | [diff] [blame] | 72 | 			if (l < -10000 || l > 10000)			\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 73 | 		case INT_FMT_x:						\ | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 74 | 			return fprintf(stream, "%#"PRIx64, v);		\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 75 | 		case INT_FMT_i:						\ | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 76 | 		case INT_FMT_default:					\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 77 | 			return fprintf(stream, "%"PRIi##BITS, i);	\ | 
 | 78 | 		case INT_FMT_u:						\ | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 79 | 			return fprintf(stream, "%"PRIu64, v);		\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 80 | 		case INT_FMT_o:						\ | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 81 | 			return fprintf(stream, "0%"PRIo64, v);		\ | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 82 | 		}							\ | 
 | 83 | 	} while (0) | 
 | 84 |  | 
 | 85 | enum int_fmt_t | 
 | 86 | { | 
 | 87 | 	INT_FMT_i, | 
 | 88 | 	INT_FMT_u, | 
 | 89 | 	INT_FMT_o, | 
 | 90 | 	INT_FMT_x, | 
 | 91 | 	INT_FMT_unknown, | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 92 | 	INT_FMT_default, | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 93 | }; | 
 | 94 |  | 
 | 95 | static int | 
 | 96 | format_integer(FILE *stream, struct value *value, enum int_fmt_t format, | 
 | 97 | 	       struct value_dict *arguments) | 
 | 98 | { | 
 | 99 | 	switch (type_sizeof(value->inferior, value->type)) { | 
 | 100 |  | 
 | 101 | 	case 1: HANDLE_WIDTH(8); | 
 | 102 | 	case 2: HANDLE_WIDTH(16); | 
 | 103 | 	case 4: HANDLE_WIDTH(32); | 
 | 104 | 	case 8: HANDLE_WIDTH(64); | 
 | 105 |  | 
 | 106 | 	default: | 
 | 107 | 		assert(!"unsupported integer width"); | 
 | 108 | 		abort(); | 
 | 109 |  | 
 | 110 | 	case -1: | 
 | 111 | 		return -1; | 
 | 112 | 	} | 
 | 113 | } | 
 | 114 |  | 
 | 115 | #undef HANDLE_WIDTH | 
 | 116 |  | 
 | 117 | static int | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 118 | acc_fprintf(int *countp, FILE *stream, const char *format, ...) | 
 | 119 | { | 
 | 120 | 	va_list pa; | 
 | 121 | 	va_start(pa, format); | 
| Petr Machata | adec201 | 2012-11-01 22:05:04 +0100 | [diff] [blame] | 122 | 	int i = account_output(countp, vfprintf(stream, format, pa)); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 123 | 	va_end(pa); | 
 | 124 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 125 | 	return i; | 
 | 126 | } | 
 | 127 |  | 
 | 128 | static int | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 129 | print_char(FILE *stream, int c) | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 130 | { | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 131 | 	const char *fmt; | 
 | 132 | 	switch (c) { | 
 | 133 | 	case -1: | 
 | 134 | 		fmt = "EOF"; | 
 | 135 | 		break; | 
 | 136 | 	case 0: | 
 | 137 | 		fmt = "\\0"; | 
 | 138 | 		break; | 
 | 139 | 	case '\a': | 
 | 140 | 		fmt = "\\a"; | 
 | 141 | 		break; | 
 | 142 | 	case '\b': | 
 | 143 | 		fmt = "\\b"; | 
 | 144 | 		break; | 
 | 145 | 	case '\t': | 
 | 146 | 		fmt = "\\t"; | 
 | 147 | 		break; | 
 | 148 | 	case '\n': | 
 | 149 | 		fmt = "\\n"; | 
 | 150 | 		break; | 
 | 151 | 	case '\v': | 
 | 152 | 		fmt = "\\v"; | 
 | 153 | 		break; | 
 | 154 | 	case '\f': | 
 | 155 | 		fmt = "\\f"; | 
 | 156 | 		break; | 
 | 157 | 	case '\r': | 
 | 158 | 		fmt = "\\r"; | 
 | 159 | 		break; | 
 | 160 | 	case '\\': | 
 | 161 | 		fmt = "\\\\"; | 
 | 162 | 		break; | 
 | 163 | 	default: | 
 | 164 | 		if (isprint(c) || c == ' ') | 
 | 165 | 			fmt = "%c"; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 166 | 		else | 
| Petr Machata | 987d27b | 2012-01-17 19:04:04 +0100 | [diff] [blame] | 167 | 			fmt = "\\%03o"; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 168 | 	} | 
 | 169 |  | 
| Petr Machata | 987d27b | 2012-01-17 19:04:04 +0100 | [diff] [blame] | 170 | 	return fprintf(stream, fmt, c); | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 171 | } | 
 | 172 |  | 
 | 173 | static int | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 174 | format_char(FILE *stream, struct value *value, struct value_dict *arguments) | 
 | 175 | { | 
 | 176 | 	long lc; | 
 | 177 | 	if (value_extract_word(value, &lc, arguments) < 0) | 
 | 178 | 		return -1; | 
 | 179 | 	return print_char(stream, (int) lc); | 
 | 180 | } | 
 | 181 |  | 
 | 182 | static int | 
 | 183 | format_naked(FILE *stream, struct value *value, | 
 | 184 | 	     struct value_dict *arguments, | 
 | 185 | 	     int (*what)(FILE *, struct value *, struct value_dict *)) | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 186 | { | 
 | 187 | 	int written = 0; | 
 | 188 | 	if (acc_fprintf(&written, stream, "'") < 0 | 
| Petr Machata | adec201 | 2012-11-01 22:05:04 +0100 | [diff] [blame] | 189 | 	    || account_output(&written, | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 190 | 			      what(stream, value, arguments)) < 0 | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 191 | 	    || acc_fprintf(&written, stream, "'") < 0) | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 192 | 		return -1; | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 193 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 194 | 	return written; | 
 | 195 | } | 
 | 196 |  | 
 | 197 | static int | 
| Petr Machata | f197727 | 2012-11-29 15:49:16 +0100 | [diff] [blame] | 198 | format_double(FILE *stream, double value, enum int_fmt_t format) | 
 | 199 | { | 
 | 200 | 	if (format == INT_FMT_x) | 
 | 201 | 		return fprintf(stream, "%a", value); | 
 | 202 | 	else | 
 | 203 | 		return fprintf(stream, "%f", value); | 
 | 204 | } | 
 | 205 |  | 
 | 206 | static int | 
 | 207 | format_floating(FILE *stream, struct value *value, struct value_dict *arguments, | 
 | 208 | 		enum int_fmt_t format) | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 209 | { | 
 | 210 | 	switch (value->type->type) { | 
 | 211 | 		float f; | 
 | 212 | 		double d; | 
 | 213 | 	case ARGTYPE_FLOAT: | 
 | 214 | 		if (read_float(value, &f, arguments) < 0) | 
 | 215 | 			return -1; | 
| Petr Machata | f197727 | 2012-11-29 15:49:16 +0100 | [diff] [blame] | 216 | 		return format_double(stream, f, format); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 217 | 	case ARGTYPE_DOUBLE: | 
 | 218 | 		if (read_double(value, &d, arguments) < 0) | 
 | 219 | 			return -1; | 
| Petr Machata | f197727 | 2012-11-29 15:49:16 +0100 | [diff] [blame] | 220 | 		return format_double(stream, d, format); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 221 | 	default: | 
 | 222 | 		abort(); | 
 | 223 | 	} | 
 | 224 | } | 
 | 225 |  | 
| Petr Machata | f7c46bb | 2012-11-01 22:15:45 +0100 | [diff] [blame] | 226 | struct format_argument_data | 
 | 227 | { | 
 | 228 | 	struct value *value; | 
 | 229 | 	struct value_dict *arguments; | 
 | 230 | }; | 
 | 231 |  | 
 | 232 | static int | 
 | 233 | format_argument_cb(FILE *stream, void *ptr) | 
 | 234 | { | 
 | 235 | 	struct format_argument_data *data = ptr; | 
 | 236 | 	return format_argument(stream, data->value, data->arguments); | 
 | 237 | } | 
 | 238 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 239 | static int | 
 | 240 | format_struct(FILE *stream, struct value *value, struct value_dict *arguments) | 
 | 241 | { | 
 | 242 | 	int written = 0; | 
 | 243 | 	if (acc_fprintf(&written, stream, "{ ") < 0) | 
 | 244 | 		return -1; | 
| Petr Machata | f7c46bb | 2012-11-01 22:15:45 +0100 | [diff] [blame] | 245 |  | 
 | 246 | 	int need_delim = 0; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 247 | 	size_t i; | 
 | 248 | 	for (i = 0; i < type_struct_size(value->type); ++i) { | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 249 | 		struct value element; | 
 | 250 | 		if (value_init_element(&element, value, i) < 0) | 
 | 251 | 			return -1; | 
| Petr Machata | f7c46bb | 2012-11-01 22:15:45 +0100 | [diff] [blame] | 252 |  | 
 | 253 | 		struct format_argument_data data = { &element, arguments }; | 
 | 254 | 		int o = delim_output(stream, &need_delim, | 
 | 255 | 				     format_argument_cb, &data); | 
| Petr Machata | 8904cdc | 2012-10-30 17:27:20 +0100 | [diff] [blame] | 256 | 		value_destroy(&element); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 257 | 		if (o < 0) | 
 | 258 | 			return -1; | 
| Petr Machata | f7c46bb | 2012-11-01 22:15:45 +0100 | [diff] [blame] | 259 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 260 | 		written += o; | 
 | 261 | 	} | 
 | 262 | 	if (acc_fprintf(&written, stream, " }") < 0) | 
 | 263 | 		return -1; | 
 | 264 | 	return written; | 
 | 265 | } | 
 | 266 |  | 
| Petr Machata | d8286ed | 2013-11-04 13:35:38 +0100 | [diff] [blame] | 267 | static const char null_message[] = "nil"; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 268 | int | 
 | 269 | format_pointer(FILE *stream, struct value *value, struct value_dict *arguments) | 
 | 270 | { | 
| Petr Machata | 26c0c94 | 2012-11-19 00:14:51 +0100 | [diff] [blame] | 271 | 	if (value_is_zero(value, arguments)) | 
| Petr Machata | d8286ed | 2013-11-04 13:35:38 +0100 | [diff] [blame] | 272 | 		return fprintf(stream, null_message); | 
| Petr Machata | 26c0c94 | 2012-11-19 00:14:51 +0100 | [diff] [blame] | 273 |  | 
| Petr Machata | 307b90b | 2012-11-19 00:35:38 +0100 | [diff] [blame] | 274 | 	/* The following is for detecting recursion.  We keep track of | 
 | 275 | 	 * the values that were already displayed.  Each time a | 
 | 276 | 	 * pointer should be dereferenced, we compare its value to the | 
 | 277 | 	 * value of each of the pointers dereferenced so far.  If one | 
 | 278 | 	 * of them matches, instead of recursing, we just printf which | 
 | 279 | 	 * superstructure this pointer recurses to.  */ | 
 | 280 | 	static struct vect pointers = {}; | 
 | 281 | 	if (pointers.elt_size == 0) | 
 | 282 | 		VECT_INIT(&pointers, struct value *); | 
 | 283 |  | 
| Petr Machata | 6248a0a | 2012-11-19 01:00:54 +0100 | [diff] [blame] | 284 | 	/* Trim number of expanded structures of the same type.  Even | 
 | 285 | 	 * for non-recursive structure, we don't want to expand all of | 
 | 286 | 	 * it if it's huge.  */ | 
| Petr Machata | 307b90b | 2012-11-19 00:35:38 +0100 | [diff] [blame] | 287 | 	size_t i; | 
| Petr Machata | 6248a0a | 2012-11-19 01:00:54 +0100 | [diff] [blame] | 288 | 	size_t len = vect_size(&pointers); | 
 | 289 | 	assert(value->type->type == ARGTYPE_POINTER); | 
 | 290 | 	struct arg_type_info *pointee = value->type->u.ptr_info.info; | 
 | 291 | 	if (pointee->type == ARGTYPE_STRUCT) { | 
 | 292 | 		size_t depth = 0; | 
 | 293 | 		for (i = 0; i < len; ++i) { | 
 | 294 | 			struct value *old | 
 | 295 | 				= *VECT_ELEMENT(&pointers, struct value *, i); | 
 | 296 | 			assert(old->type->type == ARGTYPE_POINTER); | 
 | 297 | 			struct arg_type_info *old_pointee | 
 | 298 | 				= old->type->u.ptr_info.info; | 
 | 299 | 			if (old_pointee == pointee) | 
 | 300 | 				depth++; | 
 | 301 | 		} | 
 | 302 | 		if (depth >= options.arraylen) | 
 | 303 | 			return fprintf(stream, "..."); | 
 | 304 | 	} | 
 | 305 |  | 
| Petr Machata | 307b90b | 2012-11-19 00:35:38 +0100 | [diff] [blame] | 306 | 	for (i = len; i-- > 0 ;) { | 
 | 307 | 		struct value **old = VECT_ELEMENT(&pointers, struct value *, i); | 
 | 308 | 		int rc = value_equal(value, *old, arguments); | 
 | 309 | 		if (rc < 0) | 
 | 310 | 			return -1; | 
 | 311 | 		if (rc > 0) { | 
 | 312 | 			size_t reclevel = len - i - 1; | 
 | 313 | 			char buf[reclevel + 1]; | 
 | 314 | 			memset(buf, '^', sizeof buf); | 
 | 315 | 			buf[reclevel] = 0; | 
 | 316 | 			return fprintf(stream, "recurse%s", buf); | 
 | 317 | 		} | 
 | 318 | 	} | 
 | 319 |  | 
 | 320 | 	/* OK, not a recursion.  Remember this value for tracking.  */ | 
 | 321 | 	if (VECT_PUSHBACK(&pointers, &value) < 0) | 
 | 322 | 		return -1; | 
 | 323 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 324 | 	struct value element; | 
| Petr Machata | 26c0c94 | 2012-11-19 00:14:51 +0100 | [diff] [blame] | 325 | 	int o; | 
 | 326 | 	if (value_init_deref(&element, value) < 0) { | 
 | 327 | 		o = -1; | 
 | 328 | 		goto done; | 
 | 329 | 	} | 
 | 330 | 	o = format_argument(stream, &element, arguments); | 
| Petr Machata | 8904cdc | 2012-10-30 17:27:20 +0100 | [diff] [blame] | 331 | 	value_destroy(&element); | 
| Petr Machata | 26c0c94 | 2012-11-19 00:14:51 +0100 | [diff] [blame] | 332 |  | 
 | 333 | done: | 
| Petr Machata | c28410e | 2012-11-23 18:35:05 +0100 | [diff] [blame] | 334 | 	VECT_POPBACK(&pointers, struct value *, NULL, NULL); | 
| Petr Machata | 8904cdc | 2012-10-30 17:27:20 +0100 | [diff] [blame] | 335 | 	return o; | 
| Steve Fink | 1150bc4 | 2006-08-07 06:04:43 +0200 | [diff] [blame] | 336 | } | 
 | 337 |  | 
 | 338 | /* | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 339 |  * LENGTH is an expression whose evaluation will yield the actual | 
 | 340 |  *    length of the array. | 
| Steve Fink | 1150bc4 | 2006-08-07 06:04:43 +0200 | [diff] [blame] | 341 |  * | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 342 |  * MAXLEN is the actual maximum length that we care about | 
 | 343 |  * | 
 | 344 |  * BEFORE if LENGTH>MAXLEN, we display ellipsis.  We display it before | 
 | 345 |  *    the closing parenthesis if BEFORE, otherwise after it. | 
 | 346 |  * | 
 | 347 |  * OPEN, CLOSE, DELIM are opening and closing parenthesis and element | 
 | 348 |  *    delimiter. | 
| Steve Fink | 1150bc4 | 2006-08-07 06:04:43 +0200 | [diff] [blame] | 349 |  */ | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 350 | static int | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 351 | format_array(FILE *stream, struct value *value, struct value_dict *arguments, | 
 | 352 | 	     struct expr_node *length, size_t maxlen, int before, | 
 | 353 | 	     const char *open, const char *close, const char *delim) | 
| Petr Machata | 000e311 | 2012-01-03 17:03:39 +0100 | [diff] [blame] | 354 | { | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 355 | 	/* We need "long" to be long enough to cover the whole address | 
 | 356 | 	 * space.  */ | 
| Peter Wu | a77b267 | 2013-09-26 00:55:55 +0200 | [diff] [blame] | 357 | 	(void)sizeof(char[1 - 2*(sizeof(long) < sizeof(void *))]); | 
| Petr Machata | 31af32c | 2012-01-08 02:36:50 +0100 | [diff] [blame] | 358 | 	long l; | 
| Petr Machata | d7b2292 | 2012-01-06 18:34:22 +0100 | [diff] [blame] | 359 | 	if (expr_eval_word(length, value, arguments, &l) < 0) | 
 | 360 | 		return -1; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 361 | 	size_t len = (size_t)l; | 
| Steve Fink | 7bafff0 | 2006-08-07 04:50:42 +0200 | [diff] [blame] | 362 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 363 | 	int written = 0; | 
 | 364 | 	if (acc_fprintf(&written, stream, "%s", open) < 0) | 
 | 365 | 		return -1; | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 366 |  | 
| Zachary T Welch | ba6aca2 | 2010-12-08 18:55:09 -0800 | [diff] [blame] | 367 | 	size_t i; | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 368 | 	for (i = 0; i < len && i <= maxlen; ++i) { | 
 | 369 | 		if (i == maxlen) { | 
 | 370 | 			if (before && acc_fprintf(&written, stream, "...") < 0) | 
 | 371 | 				return -1; | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 372 | 			break; | 
 | 373 | 		} | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 374 |  | 
 | 375 | 		if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0) | 
 | 376 | 			return -1; | 
 | 377 |  | 
 | 378 | 		struct value element; | 
 | 379 | 		if (value_init_element(&element, value, i) < 0) | 
 | 380 | 			return -1; | 
| Petr Machata | f6ec08a | 2012-01-06 16:58:54 +0100 | [diff] [blame] | 381 | 		int o = format_argument(stream, &element, arguments); | 
| Petr Machata | 8904cdc | 2012-10-30 17:27:20 +0100 | [diff] [blame] | 382 | 		value_destroy(&element); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 383 | 		if (o < 0) | 
 | 384 | 			return -1; | 
 | 385 | 		written += o; | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 386 | 	} | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 387 | 	if (acc_fprintf(&written, stream, "%s", close) < 0) | 
 | 388 | 		return -1; | 
 | 389 | 	if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0) | 
 | 390 | 		return -1; | 
 | 391 |  | 
 | 392 | 	return written; | 
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 393 | } | 
 | 394 |  | 
| Petr Machata | 31af32c | 2012-01-08 02:36:50 +0100 | [diff] [blame] | 395 | static int | 
 | 396 | toplevel_format_lens(struct lens *lens, FILE *stream, | 
| Petr Machata | ce03498 | 2012-01-09 04:25:31 +0100 | [diff] [blame] | 397 | 		     struct value *value, struct value_dict *arguments, | 
 | 398 | 		     enum int_fmt_t int_fmt) | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 399 | { | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 400 | 	switch (value->type->type) { | 
 | 401 | 	case ARGTYPE_VOID: | 
 | 402 | 		return fprintf(stream, "<void>"); | 
 | 403 |  | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 404 | 	case ARGTYPE_SHORT: | 
 | 405 | 	case ARGTYPE_INT: | 
 | 406 | 	case ARGTYPE_LONG: | 
| Petr Machata | ce03498 | 2012-01-09 04:25:31 +0100 | [diff] [blame] | 407 | 		return format_integer(stream, value, int_fmt, arguments); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 408 |  | 
 | 409 | 	case ARGTYPE_USHORT: | 
 | 410 | 	case ARGTYPE_UINT: | 
 | 411 | 	case ARGTYPE_ULONG: | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 412 | 		if (int_fmt == INT_FMT_i || int_fmt == INT_FMT_default) | 
| Petr Machata | ce03498 | 2012-01-09 04:25:31 +0100 | [diff] [blame] | 413 | 			int_fmt = INT_FMT_u; | 
 | 414 | 		return format_integer(stream, value, int_fmt, arguments); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 415 |  | 
 | 416 | 	case ARGTYPE_CHAR: | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 417 | 		if (int_fmt == INT_FMT_default) | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 418 | 			return format_naked(stream, value, arguments, | 
 | 419 | 					    &format_char); | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 420 | 		return format_integer(stream, value, int_fmt, arguments); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 421 |  | 
 | 422 | 	case ARGTYPE_FLOAT: | 
 | 423 | 	case ARGTYPE_DOUBLE: | 
| Petr Machata | f197727 | 2012-11-29 15:49:16 +0100 | [diff] [blame] | 424 | 		return format_floating(stream, value, arguments, int_fmt); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 425 |  | 
 | 426 | 	case ARGTYPE_STRUCT: | 
 | 427 | 		return format_struct(stream, value, arguments); | 
 | 428 |  | 
 | 429 | 	case ARGTYPE_POINTER: | 
| Petr Machata | d8286ed | 2013-11-04 13:35:38 +0100 | [diff] [blame] | 430 | 		if (value_is_zero(value, arguments)) | 
 | 431 | 			return fprintf(stream, null_message); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 432 | 		if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID) | 
 | 433 | 			return format_pointer(stream, value, arguments); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 434 | 		return format_integer(stream, value, INT_FMT_x, arguments); | 
 | 435 |  | 
 | 436 | 	case ARGTYPE_ARRAY: | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 437 | 		return format_array(stream, value, arguments, | 
 | 438 | 				    value->type->u.array_info.length, | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 439 | 				    options.arraylen, 1, "[ ", " ]", ", "); | 
| Petr Machata | 94078ec | 2012-01-05 18:07:02 +0100 | [diff] [blame] | 440 | 	} | 
 | 441 | 	abort(); | 
 | 442 | } | 
| Petr Machata | 31af32c | 2012-01-08 02:36:50 +0100 | [diff] [blame] | 443 |  | 
 | 444 | static int | 
 | 445 | default_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 446 | 		       struct value *value, struct value_dict *arguments) | 
 | 447 | { | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 448 | 	return toplevel_format_lens(lens, stream, value, arguments, | 
 | 449 | 				    INT_FMT_default); | 
| Petr Machata | 31af32c | 2012-01-08 02:36:50 +0100 | [diff] [blame] | 450 | } | 
 | 451 |  | 
 | 452 | struct lens default_lens = { | 
 | 453 | 	.format_cb = default_lens_format_cb, | 
 | 454 | }; | 
| Petr Machata | ce03498 | 2012-01-09 04:25:31 +0100 | [diff] [blame] | 455 |  | 
 | 456 |  | 
 | 457 | static int | 
 | 458 | blind_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 459 | 		     struct value *value, struct value_dict *arguments) | 
 | 460 | { | 
 | 461 | 	return 0; | 
 | 462 | } | 
 | 463 |  | 
 | 464 | struct lens blind_lens = { | 
 | 465 | 	.format_cb = blind_lens_format_cb, | 
 | 466 | }; | 
 | 467 |  | 
 | 468 |  | 
 | 469 | static int | 
 | 470 | octal_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 471 | 		     struct value *value, struct value_dict *arguments) | 
 | 472 | { | 
 | 473 | 	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_o); | 
 | 474 | } | 
 | 475 |  | 
 | 476 | struct lens octal_lens = { | 
 | 477 | 	.format_cb = octal_lens_format_cb, | 
 | 478 | }; | 
 | 479 |  | 
 | 480 |  | 
 | 481 | static int | 
 | 482 | hex_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 483 | 		   struct value *value, struct value_dict *arguments) | 
 | 484 | { | 
 | 485 | 	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_x); | 
 | 486 | } | 
 | 487 |  | 
 | 488 | struct lens hex_lens = { | 
 | 489 | 	.format_cb = hex_lens_format_cb, | 
 | 490 | }; | 
| Petr Machata | b781916 | 2012-01-09 04:26:15 +0100 | [diff] [blame] | 491 |  | 
 | 492 |  | 
 | 493 | static int | 
| Petr Machata | ec4ab25 | 2012-11-20 02:00:16 +0100 | [diff] [blame] | 494 | dec_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 495 | 		   struct value *value, struct value_dict *arguments) | 
 | 496 | { | 
 | 497 | 	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_u); | 
 | 498 | } | 
 | 499 |  | 
 | 500 | struct lens dec_lens = { | 
 | 501 | 	.format_cb = dec_lens_format_cb, | 
 | 502 | }; | 
 | 503 |  | 
 | 504 |  | 
 | 505 | static int | 
| Petr Machata | b781916 | 2012-01-09 04:26:15 +0100 | [diff] [blame] | 506 | guess_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 507 | 		     struct value *value, struct value_dict *arguments) | 
 | 508 | { | 
 | 509 | 	return toplevel_format_lens(lens, stream, value, arguments, | 
 | 510 | 				    INT_FMT_unknown); | 
 | 511 | } | 
 | 512 |  | 
 | 513 | struct lens guess_lens = { | 
 | 514 | 	.format_cb = guess_lens_format_cb, | 
 | 515 | }; | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 516 |  | 
 | 517 |  | 
 | 518 | static int | 
| Petr Machata | 38fb49b | 2012-01-09 04:28:46 +0100 | [diff] [blame] | 519 | bool_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 520 | 		    struct value *value, struct value_dict *arguments) | 
 | 521 | { | 
 | 522 | 	switch (value->type->type) { | 
 | 523 | 	case ARGTYPE_VOID: | 
 | 524 | 	case ARGTYPE_FLOAT: | 
 | 525 | 	case ARGTYPE_DOUBLE: | 
 | 526 | 	case ARGTYPE_STRUCT: | 
 | 527 | 	case ARGTYPE_POINTER: | 
 | 528 | 	case ARGTYPE_ARRAY: | 
 | 529 | 		return toplevel_format_lens(lens, stream, value, | 
| Petr Machata | e773f63 | 2012-11-09 18:52:53 +0100 | [diff] [blame] | 530 | 					    arguments, INT_FMT_default); | 
| Petr Machata | 38fb49b | 2012-01-09 04:28:46 +0100 | [diff] [blame] | 531 |  | 
 | 532 | 		int zero; | 
| Petr Machata | 38fb49b | 2012-01-09 04:28:46 +0100 | [diff] [blame] | 533 | 	case ARGTYPE_SHORT: | 
 | 534 | 	case ARGTYPE_INT: | 
 | 535 | 	case ARGTYPE_LONG: | 
 | 536 | 	case ARGTYPE_USHORT: | 
 | 537 | 	case ARGTYPE_UINT: | 
 | 538 | 	case ARGTYPE_ULONG: | 
 | 539 | 	case ARGTYPE_CHAR: | 
 | 540 | 		if ((zero = value_is_zero(value, arguments)) < 0) | 
 | 541 | 			return -1; | 
 | 542 | 		if (zero) | 
 | 543 | 			return fprintf(stream, "false"); | 
 | 544 | 		else | 
 | 545 | 			return fprintf(stream, "true"); | 
 | 546 | 	} | 
 | 547 | 	abort(); | 
 | 548 | } | 
 | 549 |  | 
 | 550 | struct lens bool_lens = { | 
 | 551 | 	.format_cb = bool_lens_format_cb, | 
 | 552 | }; | 
 | 553 |  | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 554 | static int | 
 | 555 | redispatch_as_array(struct lens *lens, FILE *stream, | 
 | 556 | 		    struct value *value, struct value_dict *arguments, | 
 | 557 | 		    int (*cb)(struct lens *, FILE *, | 
 | 558 | 			      struct value *, struct value_dict *)) | 
 | 559 | { | 
 | 560 | 	struct arg_type_info info[2]; | 
 | 561 | 	type_init_array(&info[1], value->type->u.ptr_info.info, 0, | 
 | 562 | 			expr_node_zero(), 0); | 
 | 563 | 	type_init_pointer(&info[0], &info[1], 0); | 
 | 564 | 	info->lens = lens; | 
 | 565 | 	info->own_lens = 0; | 
 | 566 | 	struct value tmp; | 
 | 567 | 	if (value_clone(&tmp, value) < 0) | 
 | 568 | 		return -1; | 
 | 569 | 	value_set_type(&tmp, info, 0); | 
 | 570 | 	int ret = cb(lens, stream, &tmp, arguments); | 
 | 571 | 	type_destroy(&info[0]); | 
 | 572 | 	type_destroy(&info[1]); | 
 | 573 | 	value_destroy(&tmp); | 
 | 574 | 	return ret; | 
 | 575 | } | 
 | 576 |  | 
 | 577 | static int | 
 | 578 | format_wchar(FILE *stream, struct value *value, struct value_dict *arguments) | 
 | 579 | { | 
 | 580 | 	long l; | 
 | 581 | 	if (value_extract_word(value, &l, arguments) < 0) | 
 | 582 | 		return -1; | 
 | 583 | 	wchar_t wc = (wchar_t) l; | 
 | 584 | 	char buf[MB_CUR_MAX + 1]; | 
 | 585 |  | 
 | 586 | 	int c = wctomb(buf, wc); | 
 | 587 | 	if (c < 0) | 
 | 588 | 		return -1; | 
 | 589 | 	if (c == 1) | 
 | 590 | 		return print_char(stream, buf[0]); | 
 | 591 |  | 
 | 592 | 	buf[c] = 0; | 
| Petr Machata | caccda0 | 2013-11-11 16:08:42 +0100 | [diff] [blame] | 593 | 	if (fprintf(stream, "%s", buf) < 0) | 
 | 594 | 		return -1; | 
 | 595 |  | 
 | 596 | 	c = wcwidth(wc); | 
 | 597 | 	return c >= 0 ? c : 0; | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 598 | } | 
| Petr Machata | 38fb49b | 2012-01-09 04:28:46 +0100 | [diff] [blame] | 599 |  | 
 | 600 | static int | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 601 | string_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 602 | 		      struct value *value, struct value_dict *arguments) | 
 | 603 | { | 
 | 604 | 	switch (value->type->type) { | 
 | 605 | 	case ARGTYPE_POINTER: | 
 | 606 | 		/* This should really be written as either "string", | 
 | 607 | 		 * or, if lens, then string(array(char, zero)*).  But | 
 | 608 | 		 * I suspect people are so used to the char * C idiom, | 
 | 609 | 		 * that string(char *) might actually turn up.  So | 
 | 610 | 		 * let's just support it.  */ | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 611 | 		switch ((int) value->type->u.ptr_info.info->type) | 
 | 612 | 		case ARGTYPE_CHAR: | 
 | 613 | 		case ARGTYPE_SHORT: | 
 | 614 | 		case ARGTYPE_USHORT: | 
 | 615 | 		case ARGTYPE_INT: | 
 | 616 | 		case ARGTYPE_UINT: | 
 | 617 | 		case ARGTYPE_LONG: | 
 | 618 | 		case ARGTYPE_ULONG: | 
 | 619 | 			return redispatch_as_array(lens, stream, value, | 
 | 620 | 						   arguments, | 
 | 621 | 						   &string_lens_format_cb); | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 622 |  | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 623 | 		/* Otherwise dispatch to whatever the default for the | 
 | 624 | 		 * pointee is--most likely this will again be us.  */ | 
 | 625 | 		/* Fall through.  */ | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 626 | 	case ARGTYPE_VOID: | 
 | 627 | 	case ARGTYPE_FLOAT: | 
 | 628 | 	case ARGTYPE_DOUBLE: | 
 | 629 | 	case ARGTYPE_STRUCT: | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 630 | 		return toplevel_format_lens(lens, stream, value, | 
 | 631 | 					    arguments, INT_FMT_default); | 
 | 632 |  | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 633 | 	case ARGTYPE_SHORT: | 
 | 634 | 	case ARGTYPE_INT: | 
 | 635 | 	case ARGTYPE_LONG: | 
 | 636 | 	case ARGTYPE_USHORT: | 
 | 637 | 	case ARGTYPE_UINT: | 
 | 638 | 	case ARGTYPE_ULONG: | 
| Petr Machata | c00837c | 2013-11-11 02:24:42 +0100 | [diff] [blame] | 639 | 		if (value->parent != NULL && value->type->lens == NULL) | 
 | 640 | 			return format_wchar(stream, value, arguments); | 
 | 641 | 		else | 
 | 642 | 			return format_naked(stream, value, arguments, | 
 | 643 | 					    &format_wchar); | 
| Petr Machata | e3f4a98 | 2012-01-09 04:27:26 +0100 | [diff] [blame] | 644 |  | 
 | 645 | 	case ARGTYPE_CHAR: | 
 | 646 | 		return format_char(stream, value, arguments); | 
 | 647 |  | 
 | 648 | 	case ARGTYPE_ARRAY: | 
 | 649 | 		return format_array(stream, value, arguments, | 
 | 650 | 				    value->type->u.array_info.length, | 
 | 651 | 				    options.strlen, 0, "\"", "\"", ""); | 
 | 652 | 	} | 
 | 653 | 	abort(); | 
 | 654 | } | 
 | 655 |  | 
 | 656 | struct lens string_lens = { | 
 | 657 | 	.format_cb = string_lens_format_cb, | 
 | 658 | }; | 
| Petr Machata | ec4ab25 | 2012-11-20 02:00:16 +0100 | [diff] [blame] | 659 |  | 
 | 660 | static int | 
 | 661 | out_bits(FILE *stream, size_t low, size_t high) | 
 | 662 | { | 
 | 663 | 	if (low == high) | 
 | 664 | 		return fprintf(stream, "%zd", low); | 
 | 665 | 	else | 
 | 666 | 		return fprintf(stream, "%zd-%zd", low, high); | 
 | 667 | } | 
 | 668 |  | 
| Petr Machata | ec4ab25 | 2012-11-20 02:00:16 +0100 | [diff] [blame] | 669 | static int | 
 | 670 | bitvect_lens_format_cb(struct lens *lens, FILE *stream, | 
 | 671 | 		       struct value *value, struct value_dict *arguments) | 
 | 672 | { | 
 | 673 | 	unsigned char *data = value_get_data(value, arguments); | 
 | 674 | 	if (data == NULL) | 
 | 675 | 		return -1; | 
 | 676 | 	size_t sz = type_sizeof(value->inferior, value->type); | 
 | 677 | 	if (sz == (size_t)-1) | 
 | 678 | 		return -1; | 
 | 679 |  | 
 | 680 | 	size_t i; | 
 | 681 | 	unsigned char buf[sz]; | 
 | 682 | 	switch ((int)value->type->type) { | 
 | 683 | 		union bitvect_integral_64 | 
 | 684 | 		{ | 
 | 685 | 			uint8_t u8; | 
 | 686 | 			uint16_t u16; | 
 | 687 | 			uint32_t u32; | 
 | 688 | 			uint64_t u64; | 
 | 689 | 			unsigned char buf[0]; | 
 | 690 | 		} bv; | 
 | 691 |  | 
 | 692 | 	case ARGTYPE_POINTER: | 
 | 693 | 		return format_pointer(stream, value, arguments); | 
 | 694 |  | 
 | 695 | 	case ARGTYPE_STRUCT: | 
 | 696 | 	case ARGTYPE_ARRAY: | 
 | 697 | 		break; | 
 | 698 |  | 
 | 699 | 	default: | 
 | 700 | 		assert(sz <= sizeof(bv)); | 
 | 701 | 		memmove(bv.buf, data, sz); | 
 | 702 |  | 
 | 703 | 		if (sz == 1) | 
 | 704 | 			bv.u64 = bv.u8; | 
 | 705 | 		else if (sz == 2) | 
 | 706 | 			bv.u64 = bv.u16; | 
 | 707 | 		else if (sz == 4) | 
 | 708 | 			bv.u64 = bv.u32; | 
 | 709 |  | 
 | 710 | 		for (i = 0; i < sz; ++i) { | 
 | 711 | 			buf[i] = bv.u64 & 0xff; | 
 | 712 | 			bv.u64 >>= 8; | 
 | 713 | 		} | 
 | 714 | 		data = buf; | 
 | 715 | 	} | 
 | 716 |  | 
 | 717 | 	size_t bits = 0; | 
 | 718 | 	for (i = 0; i < sz; ++i) | 
 | 719 | 		bits += bitcount(data[i]); | 
 | 720 |  | 
 | 721 | 	/* If there's more 1's than 0's, show inverse.  */ | 
 | 722 | 	unsigned neg = bits > sz * 4 ? 0xff : 0x00; | 
 | 723 |  | 
 | 724 | 	int o = 0; | 
| Andrey Zonov | 6bb4201 | 2013-02-14 12:32:06 +0100 | [diff] [blame] | 725 | 	if (acc_fprintf(&o, stream, "%s<", &"~"[neg == 0x00]) < 0) | 
| Petr Machata | ec4ab25 | 2012-11-20 02:00:16 +0100 | [diff] [blame] | 726 | 		return -1; | 
 | 727 |  | 
 | 728 | 	size_t bitno = 0; | 
 | 729 | 	ssize_t low = -1; | 
 | 730 | 	for (i = 0; i < sz; ++i) { | 
 | 731 | 		unsigned char m; | 
 | 732 | 		unsigned char d = data[i] ^ neg; | 
 | 733 | 		for (m = 0x01; m != 0; m <<= 1) { | 
 | 734 | 			int bit = !!(m & d); | 
 | 735 | 			if (low < 0) { | 
 | 736 | 				if (bit) { | 
 | 737 | 					if (low == -2 | 
 | 738 | 					    && acc_fprintf(&o, stream, ",") < 0) | 
 | 739 | 						return -1; | 
 | 740 | 					low = bitno; | 
 | 741 | 				} | 
 | 742 | 			} else if (!bit) { | 
 | 743 | 				if (account_output(&o, out_bits(stream, low, | 
 | 744 | 								bitno-1)) < 0) | 
 | 745 | 					return -1; | 
 | 746 | 				low = -2; | 
 | 747 | 			} | 
 | 748 | 			bitno++; | 
 | 749 | 		} | 
 | 750 | 	} | 
 | 751 | 	if (low >= 0 && account_output(&o, out_bits(stream, low, bitno-1)) < 0) | 
 | 752 | 		return -1; | 
 | 753 |  | 
 | 754 | 	if (fputc('>', stream) < 0) | 
 | 755 | 		return -1; | 
 | 756 | 	o += 1; | 
 | 757 |  | 
 | 758 | 	return o; | 
 | 759 | } | 
 | 760 |  | 
 | 761 | struct lens bitvect_lens = { | 
 | 762 | 	.format_cb = bitvect_lens_format_cb, | 
 | 763 | }; |