2 * Copyright (c) 2011 Vojtech Horky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup libdrv
39 /** Formatting string for printing number of not-printed items. */
40 #define REMAINDER_STR_FMT " (%zu)..."
41 /** Expected max size of the remainder string.
42 * String + terminator + number width (enough for 4GB).
44 #define REMAINDER_STR_LEN (5 + 1 + 10)
47 #define BUFFER_DUMP_GROUP_SIZE 4
49 /** Space between two items. */
50 #define SPACE_NORMAL " "
51 /** Space between two groups. */
52 #define SPACE_GROUP " "
54 /** Formats the dump with space before, takes care of type casting (ugly). */
55 #define _FORMAT(digits, bits) \
56 snprintf(dump, dump_size, "%s%0" #digits PRIx##bits, \
57 space_before, ((uint##bits##_t *)buf)[0]);
59 /** Dump one item into given buffer.
61 * @param buffer Data buffer.
62 * @param item_size Size of the item (1, 2, 4).
63 * @param index Index into the @p buffer (respecting @p item_size).
64 * @param dump Where to store the dump.
65 * @param dump_size Size of @p dump size.
66 * @return Number of characters printed (see snprintf).
68 static int dump_one_item(const void *buffer
, size_t item_size
, size_t index
,
69 char *dump
, size_t dump_size
)
71 /* Determine space before the number. */
72 const char *space_before
;
75 } else if ((index
% BUFFER_DUMP_GROUP_SIZE
) == 0) {
76 space_before
= SPACE_GROUP
;
78 space_before
= SPACE_NORMAL
;
81 /* Let buf point to the item to be printed. */
82 const uint8_t *buf
= (const uint8_t *) buffer
;
83 buf
+= index
* item_size
;
87 return _FORMAT(8, 32);
89 return _FORMAT(4, 16);
95 /** Count number of characters needed for dumping buffer of given size.
97 * @param item_size Item size in bytes.
98 * @param items Number of items to print.
99 * @return Number of characters the full dump would occupy.
101 static size_t count_dump_length(size_t item_size
, size_t items
)
103 size_t group_space_count
= items
/ BUFFER_DUMP_GROUP_SIZE
- 1;
104 size_t normal_space_count
= items
- 1 - group_space_count
;
106 size_t dump_itself
= item_size
* 2 * items
;
107 size_t group_spaces
= str_size(SPACE_GROUP
) * group_space_count
;
108 size_t normal_spaces
= str_size(SPACE_NORMAL
) * normal_space_count
;
110 return dump_itself
+ group_spaces
+ normal_spaces
;
113 /** Dumps data buffer to a string in hexadecimal format.
115 * Setting @p items_to_print to zero would dump the whole buffer together
116 * with information how many items were omitted. Otherwise, no information
117 * about omitted items is printed.
119 * @param dump Where to store the dumped buffer.
120 * @param dump_size Size of @p dump in bytes.
121 * @param buffer Data buffer to be dumped.
122 * @param item_size Size of items in the @p buffer in bytes (1,2,4 allowed).
123 * @param items Number of items in the @p buffer.
124 * @param items_to_print How many items to actually print.
126 void ddf_dump_buffer(char *dump
, size_t dump_size
,
127 const void *buffer
, size_t item_size
, size_t items
, size_t items_to_print
)
129 if ((dump_size
== 0) || (dump
== NULL
)) {
132 /* We need space for one byte at least. */
134 str_cpy(dump
, dump_size
, "...");
138 /* Special cases first. */
139 if (buffer
== NULL
) {
140 str_cpy(dump
, dump_size
, "(null)");
144 str_cpy(dump
, dump_size
, "(empty)");
147 if (items_to_print
> items
) {
148 items_to_print
= items
;
151 bool print_remainder
= items_to_print
== 0;
153 /* How many available bytes we do have. */
154 size_t dump_size_remaining
= dump_size
- 1;
156 if (print_remainder
) {
157 /* Can't do much when user supplied small buffer. */
158 if (dump_size_remaining
< REMAINDER_STR_LEN
) {
159 print_remainder
= false;
161 size_t needed_size
= count_dump_length(item_size
, items
);
162 if (needed_size
> dump_size_remaining
) {
163 dump_size_remaining
-= REMAINDER_STR_LEN
;
165 print_remainder
= false;
168 items_to_print
= items
;
171 str_cpy(dump
, dump_size
, "");
174 while (index
< items
) {
175 char current_item
[32];
176 int printed
= dump_one_item(buffer
, item_size
, index
,
178 assert(printed
>= 0);
180 if ((size_t) printed
> dump_size_remaining
) {
184 str_append(dump
, dump_size
, current_item
);
186 dump_size_remaining
-= printed
;
189 if (index
>= items_to_print
) {
194 if (print_remainder
&& (index
< items
)) {
195 size_t s
= str_size(dump
);
196 snprintf(dump
+ s
, dump_size
- s
, REMAINDER_STR_FMT
,