1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup format C-string formatting
36 * @ingroup dnscore
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44 #include "dnscore/dnscore-config.h"
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <stddef.h>
48 #include <stdarg.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <pthread.h>
52
53 #include "dnscore/timeformat.h"
54
55 #include "dnscore/ctrl-rfc.h"
56 #include "dnscore/hash.h"
57
58 // Enables or disables the feature
59 #define HAS_DLADDR_SUPPORT 0
60
61 #ifdef __linux__
62 #ifdef __GNUC__
63 // linux + gnu: Enabling enhanced function address translation
64 #define __USE_GNU
65 #define _GNU_SOURCE
66 #include <dlfcn.h>
67 #undef HAS_DLADDR_SUPPORT
68 #define HAS_DLADDR_SUPPORT 0 // keep it disabled for the rest of the binary
69 #endif
70 #endif
71
72 /* Added this for FreeBSD */
73 #ifdef __FreeBSD__
74 #include <sys/types.h>
75 #include <sys/socket.h>
76 #include <netinet/in.h>
77 #elif defined __OpenBSD__
78 #include <sys/socket.h>
79 #endif
80 /**/
81
82 #include <arpa/inet.h>
83 #include <time.h>
84
85 #include "dnscore/format.h"
86 #include "dnscore/bytearray_output_stream.h"
87 #include "dnscore/counter_output_stream.h"
88 #include "dnscore/ptr_vector.h"
89 #include "dnscore/base64.h"
90 #include "dnscore/base16.h"
91 #include "dnscore/base32hex.h"
92 #include "dnscore/sys_error.h"
93
94 #define FMTHDESC_TAG 0x4353454448544d46
95
96 #define SENTINEL '%'
97 #define NULL_STRING_SUBSTITUTE "(NULL)"
98 #define NULL_STRING_SUBSTITUTE_LEN (sizeof(NULL_STRING_SUBSTITUTE)-1)
99
100 #define CHR0 '\0'
101
102 static const u8* STREOL = (const u8*)"\n";
103 //static const u8* STRCHR0 = (const u8*)"\0";
104 static const u8* STRMINUS = (const u8*)"-";
105 static const u8* STRESCAPE = (const u8*)"\\";
106 static const u8* STRQUOTE = (const u8*)"\"";
107 static const u8 STRSEPARATOR[] = {' ', '|', ' '};
108
109 #if 0
110 static const char ESCAPE_CHARS[] = {'@', '$', '\\', ';', ' ', '\t'};
111 #endif
112
113 #define TXT_ESCAPE_TYPE_NONE 0
114 #define TXT_ESCAPE_TYPE_CHAR 1
115 #define TXT_ESCAPE_TYPE_OCTL 2
116
117 static const u8 TXT_ESCAPE_TYPE[256] =
118 {
119 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
120 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
121 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
122 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
123
124 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_CHAR,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x20
125 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x28
126 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x30
127 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x38
128 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x40
129 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x48
130 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x50
131 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_CHAR,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x58
132 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x60
133 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x68
134 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x70
135 TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE,TXT_ESCAPE_TYPE_NONE, // 0x78
136
137 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
138 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
139 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
140 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
141 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
142 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
143 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
144 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
145 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
146 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
147 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
148 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
149 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
150 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
151 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
152 TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,TXT_ESCAPE_TYPE_OCTL,
153 };
154
155 /*
156 * Linear access to the format handlers. Accessed through a dichotomy.
157 */
158
159 static ptr_vector format_handler_descriptor_table = {NULL, -1, -1};
160
161 static const format_handler_descriptor** format_handler_descriptor_hash_table = NULL;
162 static int format_handler_descriptor_hash_table_size = 0;
163
164 //static bool g_format_usable = FALSE;
165
166 static int
format_handler_compare(const char * str1,s32 str1_len,const char * str2,s32 str2_len)167 format_handler_compare(const char* str1, s32 str1_len, const char* str2, s32 str2_len)
168 {
169
170 s32 len = MIN(str1_len, str2_len);
171
172 int ret = memcmp(str1, str2, len);
173
174 if(ret == 0)
175 {
176 ret = str1_len - str2_len;
177 }
178
179 return ret;
180 }
181
182 static int
format_handler_qsort_compare(const void * a_,const void * b_)183 format_handler_qsort_compare(const void* a_, const void* b_)
184 {
185 format_handler_descriptor* a = (format_handler_descriptor*)a_;
186 format_handler_descriptor* b = (format_handler_descriptor*)b_;
187
188 return format_handler_compare(a->name, a->name_len, b->name, b->name_len);
189 }
190
191 static const format_handler_descriptor*
format_get_format_handler(const char * name,u32 name_len)192 format_get_format_handler(const char* name, u32 name_len)
193 {
194 #if 0 /* fix */
195 #else
196 if(format_handler_descriptor_table.data == NULL)
197 {
198 return NULL; /* Not initialized */
199 }
200
201 format_handler_descriptor* fh = NULL;
202
203 u32 low = 0;
204 u32 high = format_handler_descriptor_table.offset + 1;
205
206 while(high - low > 3)
207 {
208 u32 mid = (high + low) / 2;
209
210 fh = format_handler_descriptor_table.data[mid];
211
212 int cmp = format_handler_compare(name, name_len, fh->name, fh->name_len);
213
214 if(cmp == 0)
215 {
216 return fh;
217 }
218
219 if(cmp > 0)
220 {
221 low = mid + 1;
222 }
223 else
224 {
225 high = mid;
226 }
227 }
228
229 for(; low < high; low++)
230 {
231 fh = format_handler_descriptor_table.data[low];
232
233 int cmp = format_handler_compare(fh->name, fh->name_len, name, name_len);
234
235 if(cmp == 0)
236 {
237 return fh;
238 }
239 }
240
241 return NULL;
242 #endif
243 }
244
245 /* Example of custom format handler -> */
246
247 /*
248 * The dummy format handler simply prints the pointer in hexadecimal / lo-case
249 */
250
251 static void
dummy_format_handler_method(const void * val,output_stream * stream,s32 padding,char pad_char,bool left_justified,void * reserved_for_method_parameters)252 dummy_format_handler_method(const void* val, output_stream* stream, s32 padding, char pad_char, bool left_justified, void* reserved_for_method_parameters)
253 {
254 (void)reserved_for_method_parameters;
255
256 intptr ival = (intptr)val;
257 format_hex_u64_lo(ival, stream, padding, pad_char, left_justified);
258 }
259
260 static format_handler_descriptor dummy_format_handler_descriptor =
261 {
262 "Unsupported",
263 11,
264 dummy_format_handler_method
265 };
266
267 /* <- Example of custom format handler */
268
269 static void format_grow_hash_table();
270
271 void
format_class_init()272 format_class_init()
273 {
274 if(format_handler_descriptor_table.data != NULL)
275 {
276 return;
277 }
278
279 ptr_vector_init(&format_handler_descriptor_table);
280
281 format_grow_hash_table();
282 }
283
284 void
format_class_finalize()285 format_class_finalize()
286 {
287 ptr_vector_destroy(&format_handler_descriptor_table);
288 free(format_handler_descriptor_hash_table);
289 format_handler_descriptor_hash_table = NULL;
290 }
291
292 bool
format_available()293 format_available()
294 {
295 return format_handler_descriptor_table.data != NULL;
296 }
297
format_grow_hash_table()298 static void format_grow_hash_table()
299 {
300 bool retry;
301
302 do
303 {
304 if(format_handler_descriptor_hash_table != NULL)
305 {
306 free(format_handler_descriptor_hash_table);
307
308 int next = (format_handler_descriptor_hash_table_size * 2) | 1;
309
310 for(int i = 3; i < next; i += 2)
311 {
312 if((next % i) == 0)
313 {
314 next += 2;
315 i = 1;
316 }
317 }
318
319 format_handler_descriptor_hash_table_size = next;
320 }
321 else
322 {
323 format_handler_descriptor_hash_table_size = 1117; // prime
324 }
325
326 retry = FALSE;
327
328 MALLOC_OBJECT_ARRAY_OR_DIE(format_handler_descriptor_hash_table, const format_handler_descriptor*, format_handler_descriptor_hash_table_size, FMTHDESC_TAG);
329 ZEROMEMORY(format_handler_descriptor_hash_table, format_handler_descriptor_hash_table_size * sizeof(format_handler_descriptor*));
330
331 for(int i = 0; i <= ptr_vector_last_index(&format_handler_descriptor_table); ++i)
332 {
333 const format_handler_descriptor* fhd = (format_handler_descriptor*)ptr_vector_get(&format_handler_descriptor_table, i);
334 hashcode code = hash_chararray(fhd->name, fhd->name_len);
335
336 int slot = code % format_handler_descriptor_hash_table_size;
337
338 if(format_handler_descriptor_hash_table[slot] != NULL)
339 {
340 retry = TRUE;
341 break;
342 }
343
344 format_handler_descriptor_hash_table[slot] = fhd; // VS false positive: slot is unsigned and limited by the modulo of the size of the table
345 }
346 }
347 while(retry);
348 }
349
350 ya_result
format_registerclass(const format_handler_descriptor * fhd)351 format_registerclass(const format_handler_descriptor* fhd)
352 {
353 if(format_get_format_handler(fhd->name, fhd->name_len) != NULL)
354 {
355 return FORMAT_ALREADY_REGISTERED; /* Already registered */
356 }
357
358 ptr_vector_append(&format_handler_descriptor_table, (format_handler_descriptor*)fhd);
359
360 ptr_vector_qsort(&format_handler_descriptor_table, format_handler_qsort_compare);
361
362 hashcode code = hash_chararray(fhd->name, fhd->name_len);
363 int slot = code % format_handler_descriptor_hash_table_size;
364
365 if(format_handler_descriptor_hash_table[slot] == NULL)
366 {
367 format_handler_descriptor_hash_table[slot] = fhd;
368 }
369 else
370 {
371 format_grow_hash_table();
372 }
373
374 return SUCCESS;
375 }
376
377 /*typedef size_t formatter(char* output, size_t max_chars, bool left-aligned, void* value_to_convert,int arg_count,va_list args);*/
378
379 typedef void
380 u64_formatter_function(u64, output_stream*, s32, char, bool);
381
382 static const char __HEXA__[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
383 static const char __hexa__[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
384
385 static void
do_padding(output_stream * stream,s32 padding,char pad_char)386 do_padding(output_stream* stream, s32 padding, char pad_char)
387 {
388 output_stream_write_method* os_write = stream->vtbl->write;
389
390 while(padding-- > 0)
391 {
392 os_write(stream, (u8*) & pad_char, 1);
393 }
394 }
395
396 static void
format_unsigned(const char * input,size_t size,output_stream * stream,s32 padding,char pad_char,bool left_justified)397 format_unsigned(const char* input, size_t size, output_stream* stream, s32 padding, char pad_char, bool left_justified)
398 {
399 padding -= size;
400
401 if(left_justified)
402 {
403 output_stream_write(stream, (const u8*)input, size);
404 do_padding(stream, padding, pad_char);
405 }
406 else
407 {
408 do_padding(stream, padding, pad_char);
409 output_stream_write(stream, (const u8*)input, size);
410 }
411
412 /* Done */
413 }
414
415 static void
format_signed(const char * input,size_t size,output_stream * stream,s32 padding,char pad_char,bool left_justified,bool sign)416 format_signed(const char* input, size_t size, output_stream* stream, s32 padding, char pad_char, bool left_justified, bool sign)
417 {
418 padding -= size;
419
420 if(left_justified)
421 {
422 if(sign)
423 {
424 output_stream_write(stream, STRMINUS, 1);
425 }
426
427 output_stream_write(stream, (const u8*)input, size);
428 do_padding(stream, padding, pad_char);
429 }
430 else
431 {
432 if(sign && pad_char == '0')
433 {
434 output_stream_write(stream, STRMINUS, 1);
435 }
436
437 do_padding(stream, padding, pad_char);
438
439 if(sign && pad_char != '0')
440 {
441 output_stream_write(stream, STRMINUS, 1);
442 }
443
444 output_stream_write(stream, (const u8*)input, size);
445 }
446
447 /* Done */
448 }
449
450 static void
format_hex_u64_common(const char * hexa_table,u64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)451 format_hex_u64_common(const char* hexa_table, u64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
452 {
453 char tmp[__SIZEOF_POINTER__ * 2];
454 char* next = &tmp[sizeof(tmp)];
455
456 do
457 {
458 *--next = hexa_table[val & 0x0f];
459 val >>= 4;
460 }
461 while(val != 0);
462
463 format_unsigned(next, &tmp[sizeof(tmp)] - next, stream, padding, pad_char, left_justified);
464 }
465
466 void
format_oct_u64(u64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)467 format_oct_u64(u64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
468 {
469 char tmp[20];
470 char* next = &tmp[sizeof(tmp)];
471
472 do
473 {
474 *--next = '0' + (val & 7);
475 val >>= 3;
476 }
477 while(val != 0);
478
479 /* next points at the first char of the 10-based representation of the integer */
480
481 format_unsigned(next, &tmp[sizeof(tmp)] - next, stream, padding, pad_char, left_justified);
482 }
483
484 void
format_dec_u64(u64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)485 format_dec_u64(u64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
486 {
487 char tmp[20];
488 char* next = &tmp[sizeof(tmp)];
489
490 do
491 {
492 *--next = '0' + (val % 10);
493 val /= 10;
494 }
495 while(val != 0);
496
497 /* next points at the first char of the 10-based representation of the integer */
498
499 format_unsigned(next, &tmp[sizeof(tmp)] - next, stream, padding, pad_char, left_justified);
500 }
501
502 void
format_dec_s64(s64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)503 format_dec_s64(s64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
504 {
505 char tmp[20];
506 char* next = &tmp[sizeof(tmp)];
507
508 bool sign;
509
510 if((sign = (val < 0)))
511 {
512 val = -val;
513 }
514
515 u64 uval = (u64)val;
516
517 do
518 {
519 *--next = '0' + (uval % 10);
520 uval /= 10;
521 }
522 while(uval != 0);
523
524 format_signed(next, &tmp[sizeof(tmp)] - next, stream, padding, pad_char, left_justified, sign);
525 }
526
527 void
format_hex_u64_lo(u64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)528 format_hex_u64_lo(u64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
529 {
530 format_hex_u64_common(__hexa__, val, stream, padding, pad_char, left_justified);
531 }
532
533 void
format_hex_u64_hi(u64 val,output_stream * stream,s32 padding,char pad_char,bool left_justified)534 format_hex_u64_hi(u64 val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
535 {
536 format_hex_u64_common(__HEXA__, val, stream, padding, pad_char, left_justified);
537 }
538
539 static void
format_double_make_format(char * p,s32 padding,s32 float_padding,char pad_char,bool left_justified,bool long_double)540 format_double_make_format(char* p, s32 padding, s32 float_padding, char pad_char, bool left_justified, bool long_double)
541 {
542 *p++ = '%';
543
544 if(!left_justified)
545 {
546 *p++ = '-';
547 }
548 if(pad_char != ' ')
549 {
550 *p++ = pad_char;
551 }
552 if(padding >= 0)
553 {
554 p += sprintf(p, "%i", padding);
555 }
556 if(float_padding >= 0)
557 {
558 *p++ = '.';
559 p += sprintf(p, "%i", float_padding);
560 }
561 if(long_double)
562 {
563 *p++ = 'L';
564 }
565 *p++ = 'f';
566 *p++ = CHR0;
567 }
568
569 static void
format_longdouble(long double val,output_stream * stream,s32 padding,s32 float_padding,char pad_char,bool left_justified)570 format_longdouble(long double val, output_stream* stream, s32 padding, s32 float_padding, char pad_char, bool left_justified)
571 {
572 char fmt[32];
573 char tmp[64];
574
575 format_double_make_format(fmt, padding, float_padding, pad_char, left_justified, TRUE);
576
577 int len = snprintf(tmp, sizeof(tmp), fmt, val);
578
579 output_stream_write(stream, (const u8*)tmp, len);
580 }
581
582 static void
format_double(double val,output_stream * stream,s32 padding,s32 float_padding,char pad_char,bool left_justified)583 format_double(double val, output_stream* stream, s32 padding, s32 float_padding, char pad_char, bool left_justified)
584 {
585 char fmt[32];
586 char tmp[64];
587
588 format_double_make_format(fmt, padding, float_padding, pad_char, left_justified, FALSE);
589
590 int len = snprintf(tmp, sizeof(tmp), fmt, val);
591
592 output_stream_write(stream, (const u8*)tmp, len);
593 }
594
595 void
format_asciiz(const char * val,output_stream * stream,s32 padding,char pad_char,bool left_justified)596 format_asciiz(const char* val, output_stream* stream, s32 padding, char pad_char, bool left_justified)
597 {
598 if(val == NULL)
599 {
600 val = NULL_STRING_SUBSTITUTE;
601 }
602
603 size_t val_len = strlen(val);
604
605 padding -= val_len;
606
607 if(left_justified)
608 {
609 output_stream_write(stream, (const u8*)val, val_len);
610 do_padding(stream, padding, pad_char);
611 }
612 else
613 {
614 do_padding(stream, padding, pad_char);
615 output_stream_write(stream, (const u8*)val, val_len);
616 }
617 }
618
619 ya_result
vosformat(output_stream * os_,const char * fmt,va_list args)620 vosformat(output_stream* os_, const char* fmt, va_list args)
621 {
622 counter_output_stream_data cosd;
623 output_stream os;
624
625 counter_output_stream_init(os_, &os, &cosd);
626
627 const char* next = fmt;
628
629 s32 padding = -1;
630 s32 float_padding = -1;
631 u8 type_size = sizeof(int);
632 u8 size_modifier_count = 0;
633 char pad_char = ' ';
634 bool left_justified = TRUE;
635
636 char c;
637
638 for(;;)
639 {
640 c = *next;
641
642 if(c == 0)
643 {
644 /* copy the rest, return */
645 size_t size = next - fmt;
646
647 output_stream_write(&os, (const u8*)fmt, size);
648
649 ya_result ret;
650
651 if(ISOK(cosd.result))
652 {
653 ret = cosd.write_count;
654 }
655 else
656 {
657 ret = cosd.result;
658 }
659
660 /**
661 * NOTE: counter_output_stream has changed a bit since its first version.
662 *
663 *
664 * It does not closes the fitlered stream on "close"
665 * It does not flushes the filtered stream on "close" either.
666 * It only flushes the filtered stream when explicitly asked with "flush"
667 *
668 * It is thus useless to call close here (we just loose the time for the call)
669 *
670 */
671
672 /* output_stream_close(&os); */
673
674 return ret;
675 }
676
677 if(c == SENTINEL)
678 {
679 size_modifier_count = 0;
680
681 /* copy the rest, format */
682
683 size_t size = next - fmt;
684
685 output_stream_write(&os, (const u8*)fmt, size);
686
687 next++;
688
689 fmt += size;
690
691 /* format */
692
693 c = *next++;
694
695 if(c == '%')
696 {
697 /*
698 * warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
699 * (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
700 * if this code is reached, the program will abort
701 *
702 * => int
703 */
704
705 format_asciiz("%", &os, padding, pad_char, left_justified);
706
707 fmt = next;
708
709 padding = 0;
710 type_size = sizeof(int);
711 pad_char = ' ';
712 left_justified = TRUE;
713
714 continue;
715 }
716
717 /* Justify */
718
719 if(c == '-')
720 {
721 left_justified = FALSE;
722 c = *next++;
723 }
724
725 /* Padding */
726
727 if(c == '0')
728 {
729 pad_char = c;
730
731 left_justified = FALSE;
732
733 c = *next++;
734 }
735
736 /* Padding */
737
738 if(isdigit(c))
739 {
740 char padding_string[10];
741
742 char* p = padding_string;
743 int n = 9;
744
745 do
746 {
747 *p++ = c;
748 c = *next++;
749 }
750 while(isdigit(c) && (n > 0));
751
752 *p = CHR0;
753
754 padding = atoi(padding_string);
755 }
756
757 if(c == '.')
758 {
759 char padding_string[10];
760
761 char* p = padding_string;
762 int n = 9;
763 c = *next++;
764 do
765 {
766 *p++ = c;
767 c = *next++;
768 }
769 while(isdigit(c) && (n > 0));
770
771 *p = CHR0;
772
773 float_padding = atoi(padding_string);
774 }
775
776 /* Type size */
777
778 if(c == 'h')
779 {
780 c = *next++;
781
782 type_size = sizeof(u16);
783
784 if(c == 'h')
785 {
786 c = *next++;
787
788 type_size = sizeof(u8);
789 }
790 }
791 else if(c == 'l')
792 {
793 c = *next++;
794
795 type_size = sizeof(u32);
796 size_modifier_count = 1;
797
798 if(c == 'l')
799 {
800 c = *next++;
801
802 type_size = sizeof(u64);
803 size_modifier_count = 2;
804 }
805 }
806 else if(c == 'L')
807 {
808 c = *next++;
809
810 type_size = sizeof(long double);
811 }
812
813 /* Type */
814
815 switch(c)
816 {
817 case 'i':
818 {
819 s64 val;
820
821 switch(type_size)
822 {
823 case sizeof(s8):
824 {
825 /*
826 * warning: ‘u8’ is promoted to ‘int’ when passed through ‘...’
827 * (so you should pass ‘int’ not ‘u8’ to ‘va_arg’)
828 * if this code is reached, the program will abort
829 *
830 * => int
831 */
832 val = (s8)va_arg(args, int);
833 break;
834 }
835
836 case sizeof(s16):
837 {
838 /*
839 * warning: ‘u16’ is promoted to ‘int’ when passed through ‘...’
840 * (so you should pass ‘int’ not ‘u16’ to ‘va_arg’)
841 * if this code is reached, the program will abort
842 *
843 * => int
844 */
845
846 val = (s16)va_arg(args, int);
847 break;
848 }
849
850 case sizeof(s32):
851 {
852 val = (s32)va_arg(args, s32);
853 break;
854 }
855
856 case sizeof(s64):
857 {
858 val = va_arg(args, s64);
859 break;
860 }
861 default:
862 {
863 /* Invalid formatting : FULL STOP */
864
865 flushout();
866 flusherr();
867
868 fprintf(stderr, "Invalid type size '%i' in string '%s'", type_size, fmt); /* Keep native */
869 fflush(stderr);
870
871 abort();
872 }
873 }
874
875 format_dec_s64(val, &os, padding, pad_char, left_justified);
876
877 break;
878 }
879
880 case 'r':
881 {
882 ya_result val = va_arg(args, ya_result);
883
884 error_writetext(&os, val);
885
886 break;
887 }
888
889 case 'x':
890 case 'X':
891 case 'u':
892 case 'd':
893 case 'o':
894 {
895 u64_formatter_function* formatter;
896
897 u64 val;
898
899 if(c == 'u' || c == 'd')
900 {
901 formatter = format_dec_u64;
902 }
903 else if(c == 'X')
904 {
905 formatter = format_hex_u64_hi;
906 }
907 else if(c == 'x')
908 {
909 formatter = format_hex_u64_lo;
910 }
911 else
912 {
913 formatter = format_oct_u64;
914 }
915
916 switch(type_size)
917 {
918
919 case sizeof(u8):
920 {
921 /*
922 * warning: ‘u8’ is promoted to ‘int’ when passed through ‘...’
923 * (so you should pass ‘int’ not ‘u8’ to ‘va_arg’)
924 * if this code is reached, the program will abort
925 *
926 * => int
927 */
928 val = va_arg(args, int);
929 break;
930 }
931
932 case sizeof(u16):
933 {
934 /*
935 * warning: ‘u16’ is promoted to ‘int’ when passed through ‘...’
936 * (so you should pass ‘int’ not ‘u16’ to ‘va_arg’)
937 * if this code is reached, the program will abort
938 *
939 * => int
940 */
941
942 val = va_arg(args, int);
943 break;
944 }
945
946 case sizeof(u32):
947 {
948 val = va_arg(args, u32);
949 break;
950 }
951
952 case sizeof(u64):
953 {
954 val = va_arg(args, u64);
955 break;
956 }
957 default:
958 {
959 /* Invalid formatting : FULL STOP */
960
961 flushout();
962 flusherr();
963
964 fprintf(stderr, "Invalid type size '%i' in string '%s'", type_size, fmt); /* Keep native */
965 fflush(stderr);
966
967 abort();
968 }
969 }
970
971 formatter(val, &os, padding, pad_char, left_justified);
972 break;
973 }
974 case 'P':
975 {
976
977 intptr val = va_arg(args, intptr);
978
979 #if HAS_DLADDR_SUPPORT
980 Dl_info info;
981
982 if(val != 0)
983 {
984 if(dladdr((void*)val, &info) != 0)
985 {
986 if(info.dli_sname != NULL)
987 {
988 format_asciiz(info.dli_sname, &os, padding, pad_char, left_justified);
989 break;
990 }
991 else if(info.dli_fname != NULL)
992 {
993 format_asciiz(info.dli_fname, &os, padding, pad_char, left_justified);
994 val -= (intptr)info.dli_fbase;
995 output_stream_write_u8(&os, (u8)':');
996 }
997 }
998 }
999 #endif
1000
1001 format_hex_u64_hi(val, &os, __SIZEOF_POINTER__ * 2, '0', FALSE);
1002 break;
1003 }
1004 case 'p':
1005 {
1006 intptr val = va_arg(args, intptr);
1007
1008 format_hex_u64_hi(val, &os, __SIZEOF_POINTER__ * 2, '0', FALSE);
1009 break;
1010 }
1011 case 'f':
1012 {
1013 if(type_size == sizeof(long double))
1014 {
1015 long double val = va_arg(args, long double);
1016
1017 format_longdouble(val, &os, padding, float_padding, pad_char, left_justified);
1018 }
1019 else
1020 {
1021 double val = va_arg(args, double);
1022
1023 format_double(val, &os, padding, float_padding, pad_char, left_justified);
1024 }
1025
1026 break;
1027 }
1028 case 's':
1029 {
1030 const char* val;
1031
1032 val = va_arg(args, const char*);
1033
1034 format_asciiz(val, &os, padding, pad_char, left_justified);
1035
1036 break;
1037 }
1038 case 'c':
1039 {
1040 /* I'm using the string formatter. It's slower than it could but ... */
1041 char tmp[2];
1042 tmp[1] = CHR0;
1043
1044 /*
1045 * warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
1046 * (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
1047 * if this code is reached, the program will abort
1048 *
1049 * => int
1050 */
1051
1052 tmp[0] = va_arg(args, int);
1053
1054 format_asciiz(tmp, &os, padding, pad_char, left_justified);
1055
1056 break;
1057 }
1058
1059 case '{':
1060 {
1061 const char* type_name = next;
1062 do
1063 {
1064 c = *next++;
1065
1066 if(c == 0)
1067 {
1068 flushout();
1069 flusherr();
1070
1071 fprintf(stderr, "PANIC: Invalid format type in string '%s' : '}' expected.", fmt); /* Keep native */
1072 fflush(stderr);
1073 abort();
1074 }
1075 }
1076 while(c != '}');
1077
1078 /* type_name -> next contains the type name and arguments
1079 * arguments can be integers
1080 */
1081
1082 size_t type_name_len = next - 1 - type_name;
1083
1084 const format_handler_descriptor* desc = format_get_format_handler(type_name, type_name_len);
1085
1086 if(desc == NULL)
1087 {
1088 /* Uses the "dummy" handler */
1089
1090 desc = &dummy_format_handler_descriptor;
1091 }
1092
1093 void* ptr = va_arg(args, void*);
1094 desc->format_handler(ptr, &os, padding, pad_char, left_justified, NULL);
1095
1096 break;
1097 }
1098
1099 case 'w':
1100 {
1101 void* ptr = va_arg(args, void*);
1102 format_writer *fw = (format_writer*)ptr;
1103 fw->callback(fw->value, &os, padding, pad_char, left_justified, NULL);
1104 break;
1105 }
1106
1107 case 't':
1108 {
1109 int val = (int)va_arg(args, int);
1110 do_padding(&os, val, '\t');
1111 break;
1112 }
1113
1114 case 'S':
1115 {
1116 int val = (int)va_arg(args, int);
1117 do_padding(&os, val, ' ');
1118 break;
1119 }
1120
1121 case 'T':
1122 {
1123 switch(size_modifier_count)
1124 {
1125 case 0:
1126 {
1127 s64 val = (s64)va_arg(args, u32);
1128 localepoch_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1129 break;
1130 }
1131
1132 case 1:
1133 {
1134 s64 val = (s64)va_arg(args, s64);
1135 localdatetime_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1136 break;
1137 }
1138
1139 case 2:
1140 {
1141
1142 s64 val = (s64)va_arg(args, s64);
1143 localdatetimeus_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1144 break;
1145 }
1146 default:
1147 {
1148 abort();
1149 }
1150 }
1151
1152 break;
1153 }
1154
1155 case 'U':
1156 {
1157 switch(size_modifier_count)
1158 {
1159 case 0:
1160 {
1161 s64 val = (s64)va_arg(args, u32);
1162 epoch_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1163 break;
1164 }
1165
1166 case 1:
1167 {
1168 s64 val = (s64)va_arg(args, s64);
1169 datetime_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1170 break;
1171 }
1172
1173 case 2:
1174 {
1175
1176 s64 val = (s64)va_arg(args, s64);
1177 datetimeus_format_handler_method((void*)(intptr)val, &os, 0, 0, FALSE, NULL);
1178 break;
1179 }
1180 default:
1181 {
1182 abort();
1183 }
1184 }
1185
1186 break;
1187 }
1188 }
1189
1190 fmt = next;
1191
1192 padding = -1;
1193 float_padding = -1;
1194 type_size = sizeof(int);
1195 pad_char = ' ';
1196 left_justified = TRUE;
1197
1198 continue;
1199 }
1200
1201 next++;
1202
1203 /* look for the sentinel */
1204 }
1205 }
1206
1207 ya_result
osprint(output_stream * stream,const char * text)1208 osprint(output_stream* stream, const char* text)
1209 {
1210 return output_stream_write(stream, (const u8*)text, strlen(text));
1211 }
1212
1213 ya_result
osprintln(output_stream * stream,const char * text)1214 osprintln(output_stream* stream, const char* text)
1215 {
1216 ya_result n = strlen(text);
1217
1218 output_stream_write(stream, (const u8*)text, n);
1219 output_stream_write(stream, STREOL, 1);
1220
1221 return n + 1;
1222 }
1223
1224 ya_result
osformat(output_stream * stream,const char * fmt,...)1225 osformat(output_stream* stream, const char* fmt, ...)
1226 {
1227 va_list args;
1228 va_start(args, fmt);
1229 ya_result err = vosformat(stream, fmt, args);
1230 va_end(args);
1231 return err;
1232 }
1233
1234 ya_result
osformatln(output_stream * stream,const char * fmt,...)1235 osformatln(output_stream* stream, const char* fmt, ...)
1236 {
1237 va_list args;
1238 va_start(args, fmt);
1239 ya_result err1 = vosformat(stream, fmt, args);
1240 va_end(args);
1241
1242 if(ISOK(err1))
1243 {
1244 ya_result err2 = output_stream_write(stream, STREOL, 1);
1245
1246 if(ISOK(err2))
1247 {
1248 return err1 + err2;
1249 }
1250
1251 return err2;
1252 }
1253
1254 return err1;
1255 }
1256
1257 ya_result
debug_osformatln(output_stream * stream,const char * fmt,...)1258 debug_osformatln(output_stream* stream, const char* fmt, ...)
1259 {
1260 s64 now = timeus();
1261 localdatetimeus_format_handler_method((void*)(intptr)now, stream, 0, 0, FALSE, NULL);
1262 output_stream_write(stream, STRSEPARATOR, sizeof(STRSEPARATOR));
1263 format_dec_u64(getpid(), stream, 0, 0, FALSE);
1264 output_stream_write(stream, STRSEPARATOR, sizeof(STRSEPARATOR));
1265 format_hex_u64_lo((u64)(intptr)pthread_self(), stream, 0, 0, FALSE);
1266 output_stream_write(stream, STRSEPARATOR, sizeof(STRSEPARATOR));
1267 va_list args;
1268 va_start(args, fmt);
1269 ya_result err1 = vosformat(stream, fmt, args);
1270 va_end(args);
1271 output_stream_write(stream, STREOL, 1);
1272 return err1;
1273 }
1274
1275 ya_result
debug_println(const char * text)1276 debug_println(const char* text)
1277 {
1278 s64 now = timeus();
1279 localdatetimeus_format_handler_method((void*)(intptr)now, termout, 0, 0, FALSE, NULL);
1280 output_stream_write(termout, STRSEPARATOR, sizeof(STRSEPARATOR));
1281 format_dec_u64(getpid(), termout, 0, 0, FALSE);
1282 output_stream_write(termout, STRSEPARATOR, sizeof(STRSEPARATOR));
1283 format_hex_u64_lo((u64)(intptr)pthread_self(), termout, 0, 0, FALSE);
1284 output_stream_write(termout, STRSEPARATOR, sizeof(STRSEPARATOR));
1285 ya_result n = strlen(text);
1286 output_stream_write(termout, (const u8*)text, n);
1287 output_stream_write(termout, STREOL, 1);
1288 return n + 1;
1289 }
1290
1291 ya_result
print(const char * text)1292 print(const char* text)
1293 {
1294 return output_stream_write(termout, (const u8*)text, strlen(text));
1295 }
1296
1297 ya_result
println(const char * text)1298 println(const char* text)
1299 {
1300 ya_result n = strlen(text);
1301 output_stream_write(termout, (const u8*)text, n);
1302 output_stream_write(termout, STREOL, 1);
1303
1304 return n + 1;
1305 }
1306
1307 int
format(const char * fmt,...)1308 format(const char* fmt, ...)
1309 {
1310 va_list args;
1311 va_start(args, fmt);
1312 ya_result err = vosformat(termout, fmt, args);
1313 va_end(args);
1314 return err;
1315 }
1316
1317 ya_result
formatln(const char * fmt,...)1318 formatln(const char* fmt, ...)
1319 {
1320 va_list args;
1321 va_start(args, fmt);
1322 ya_result err1 = vosformat(termout, fmt, args);
1323 va_end(args);
1324
1325 if(ISOK(err1))
1326 {
1327 ya_result err2 = output_stream_write(termout, STREOL, 1);
1328
1329 if(ISOK(err2))
1330 {
1331 return err1 + err2;
1332 }
1333
1334 return err2;
1335 }
1336
1337 return err1;
1338 }
1339
1340 int
vsnformat(char * out,size_t out_size,const char * fmt,va_list args)1341 vsnformat(char* out, size_t out_size, const char* fmt, va_list args)
1342 {
1343 if(out_size == 0)
1344 {
1345 return 0;
1346 }
1347
1348 output_stream baos;
1349 bytearray_output_stream_context baos_context;
1350
1351 bytearray_output_stream_init_ex_static(&baos, (u8*)out, out_size - 1, 0, &baos_context);
1352
1353 int ret = vosformat(&baos, fmt, args);
1354
1355 if(ret < (int)out_size)
1356 {
1357 out[ret] = CHR0;
1358 }
1359 else
1360 {
1361 out[out_size - 1] = CHR0;
1362 }
1363
1364 output_stream_close(&baos);
1365
1366 return ret;
1367 }
1368
1369 /**
1370 * This formatter will return an allocated (malloc) string as a result of the format
1371 *
1372 * @param outp
1373 * @param out_size
1374 * @param fmt
1375 * @param args
1376 * @return
1377 */
1378
1379 int
vasnformat(char ** outp,size_t out_size,const char * fmt,va_list args)1380 vasnformat(char** outp, size_t out_size, const char* fmt, va_list args)
1381 {
1382 output_stream baos;
1383 bytearray_output_stream_context baos_context;
1384
1385 bytearray_output_stream_init_ex_static(&baos, NULL, out_size, 0, &baos_context);
1386
1387 int ret = vosformat(&baos, fmt, args);
1388
1389 if(ISOK(ret) && ((out_size == 0) || (ret < (int)out_size)))
1390 {
1391 output_stream_write_u8(&baos, 0);
1392 *outp =(char*)bytearray_output_stream_dup(&baos);
1393 }
1394 else
1395 {
1396 *outp = NULL;
1397 }
1398
1399 output_stream_close(&baos);
1400
1401 return ret;
1402 }
1403
1404 /**
1405 * This formatter will return an allocated (malloc) string as a result of the format
1406 *
1407 * @param outp
1408 * @param out_size
1409 * @param fmt
1410 * @param ...
1411 * @return
1412 */
1413
1414 int
asnformat(char ** outp,size_t out_size,const char * fmt,...)1415 asnformat(char** outp, size_t out_size, const char* fmt, ...)
1416 {
1417 int ret;
1418 va_list args;
1419 va_start(args, fmt);
1420 ret = vasnformat(outp, out_size, fmt, args);
1421 va_end(args);
1422
1423 return ret;
1424 }
1425
1426
1427 /**
1428 * This formatter will return an allocated (malloc) string as a result of the format
1429 *
1430 * @param outp
1431
1432 * @param fmt
1433 * @param ...
1434 * @return
1435 */
1436
1437 int
asformat(char ** outp,const char * fmt,...)1438 asformat(char** outp, const char* fmt, ...)
1439 {
1440 int ret;
1441 va_list args;
1442 va_start(args, fmt);
1443 ret = vasnformat(outp, 0, fmt, args);
1444 va_end(args);
1445
1446 return ret;
1447 }
1448
1449 int
snformat(char * out,size_t out_size,const char * fmt,...)1450 snformat(char* out, size_t out_size, const char* fmt, ...)
1451 {
1452 int ret;
1453 va_list args;
1454 va_start(args, fmt);
1455 ret = vsnformat(out, out_size, fmt, args);
1456 va_end(args);
1457
1458 return ret;
1459 }
1460
1461 int
osprint_base64(output_stream * os,const u8 * rdata_pointer,u32 rdata_size)1462 osprint_base64(output_stream* os, const u8* rdata_pointer, u32 rdata_size)
1463 {
1464 char buffer[65];
1465 int total = 0;
1466 u32 n;
1467
1468 while(rdata_size > 48)
1469 {
1470 n = base64_encode(rdata_pointer, 48, buffer);
1471 buffer[n++] = ' ';
1472 output_stream_write(os, (u8*)buffer, n);
1473 total += n;
1474 rdata_pointer += 48;
1475 rdata_size -= 48;
1476 }
1477
1478 n = base64_encode(rdata_pointer, rdata_size, buffer);
1479 output_stream_write(os, (u8*)buffer, n);
1480
1481 total += n;
1482
1483 return total;
1484 }
1485
1486 int
osprint_base16(output_stream * os,const u8 * rdata_pointer,u32 rdata_size)1487 osprint_base16(output_stream* os, const u8* rdata_pointer, u32 rdata_size)
1488 {
1489 char buffer[65];
1490 int total = 0;
1491 u32 n;
1492
1493 while(rdata_size > 32)
1494 {
1495 n = base16_encode(rdata_pointer, 32, buffer);
1496 buffer[n++] = ' ';
1497 output_stream_write(os, (u8*)buffer, n);
1498 total += n;
1499 rdata_pointer += 32;
1500 rdata_size -= 32;
1501 }
1502
1503 n = base16_encode(rdata_pointer, rdata_size, buffer);
1504 output_stream_write(os, (u8*)buffer, n);
1505
1506 total += n;
1507
1508 return total;
1509 }
1510
1511 int
fformat(FILE * out,const char * fmt,...)1512 fformat(FILE* out, const char* fmt, ...)
1513 {
1514 char tmp[4096];
1515
1516 #if DEBUG
1517 memset(tmp, '!', sizeof(tmp));
1518 #endif
1519
1520 int ret;
1521 va_list args;
1522 va_start(args, fmt);
1523 ret = vsnformat(tmp, sizeof(tmp), fmt, args);
1524 fputs(tmp, out);
1525 va_end(args);
1526
1527 return ret;
1528 }
1529
1530 /*------------------------------------------------------------------------------
1531 * FUNCTIONS */
1532
1533 void
osprint_u32(output_stream * os,u32 value)1534 osprint_u32(output_stream* os, u32 value)
1535 {
1536 format_dec_u64(value, os, 9, ' ', FALSE);
1537 }
1538
1539 void
osprint_u16(output_stream * os,u16 value)1540 osprint_u16(output_stream* os, u16 value)
1541 {
1542 format_dec_u64(value, os, 5, ' ', FALSE);
1543 }
1544
1545 void
osprint_u32_hex(output_stream * os,u32 value)1546 osprint_u32_hex(output_stream* os, u32 value)
1547 {
1548 format_hex_u64_common(__hexa__, value, os, 8, '0', FALSE);
1549 }
1550
1551 void
print_char(char value)1552 print_char(char value)
1553 {
1554 char tmp[1];
1555 tmp[0] = value;
1556 output_stream_write(&__termout__, (u8*)tmp, 1);
1557 }
1558
1559 void
osprint_char(output_stream * os,char value)1560 osprint_char(output_stream* os, char value)
1561 {
1562 char tmp[1];
1563 tmp[0] = value;
1564 output_stream_write(os, (u8*)tmp, 1);
1565 }
1566
osprint_char_times(output_stream * os,char value,int times)1567 void osprint_char_times(output_stream *os, char value, int times)
1568 {
1569 char tmp[32];
1570
1571 if(times < 0)
1572 {
1573 return;
1574 }
1575
1576 if(times > 32)
1577 {
1578 memset(tmp, value, 32);
1579
1580 do
1581 {
1582 output_stream_write(os, tmp, 32);
1583 times -= 32;
1584 }
1585 while(times >= 32);
1586
1587 output_stream_write(os, tmp, times);
1588 }
1589 else
1590 {
1591 memset(tmp, value, times);
1592 output_stream_write(os, tmp, times);
1593 }
1594 }
1595
1596
1597 ya_result
osprint_type_bitmap(output_stream * os,const u8 * rdata_pointer,u16 rdata_size)1598 osprint_type_bitmap(output_stream* os, const u8* rdata_pointer, u16 rdata_size)
1599 {
1600 /*
1601 * WindowIndex + WindowSize + bits => a minimum of 3 bytes
1602 */
1603 while(rdata_size >= 3)
1604 {
1605 u16 type_hi = *rdata_pointer++;
1606 u8 count = *rdata_pointer++;
1607
1608 rdata_size -= 2;
1609
1610 if(rdata_size < count)
1611 {
1612 return INCORRECT_RDATA;
1613 }
1614
1615 rdata_size -= count;
1616
1617 /*type_hi <<= 8;*/
1618
1619 u16 type_lo = 0;
1620
1621 while(count-- > 0)
1622 {
1623 u8 bitmap = *rdata_pointer++;
1624 u32 b;
1625
1626 for(b = 8; b > 0; b--)
1627 {
1628 if((bitmap & 0x80) != 0)
1629 {
1630 /* Enabled */
1631
1632 u16 type = type_hi + type_lo;
1633
1634 osformat(os, " %{dnstype}", &type);
1635 }
1636
1637 bitmap <<= 1;
1638
1639 type_lo+=0x100;
1640 }
1641 }
1642 }
1643
1644 return SUCCESS;
1645 }
1646
1647 static const u32 loc_pow10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
1648 static const char loc_ns[2] = {'N','S'};
1649 static const char loc_ew[2] = {'E','W'};
1650
loc_float(u8 v,u32 * out_value)1651 static bool loc_float(u8 v, u32* out_value)
1652 {
1653 u32 m = v >> 4;
1654 u32 e = v & 0x0f;
1655
1656 if(!((m > 9) || (e > 9) || ((m == 0) && (e != 0))))
1657 {
1658 *out_value = m * loc_pow10[e];
1659 return TRUE;
1660 }
1661 else
1662 {
1663 return FALSE;
1664 }
1665 }
1666
1667 struct loc_coordinate
1668 {
1669 int secfrac;
1670 int sec;
1671 int min;
1672 int deg;
1673 int cardinal_index; // N S // E W
1674 };
1675
1676 static void
loc_coordinate_init(struct loc_coordinate * c,s32 val)1677 loc_coordinate_init(struct loc_coordinate* c, s32 val)
1678 {
1679 val -= (s32)0x80000000LU;
1680
1681 if(val < 0)
1682 {
1683 val = -val;
1684 c->cardinal_index = 1;
1685 }
1686 else
1687 {
1688 c->cardinal_index = 0;
1689 }
1690
1691 c->secfrac = val % 1000;
1692 val /= 1000;
1693 c->sec = val % 60;
1694 val /= 60;
1695 c->min = val % 60;
1696 val /= 60;
1697 c->deg = val;
1698 }
1699
1700 ya_result
osprint_rdata(output_stream * os,u16 type,const u8 * rdata_pointer,u16 rdata_size)1701 osprint_rdata(output_stream* os, u16 type, const u8* rdata_pointer, u16 rdata_size)
1702 {
1703 char tmp[16];
1704
1705 switch(type)
1706 {
1707 case TYPE_A:
1708 {
1709 if(rdata_size == 4)
1710 {
1711 osformat(os, "%d.%d.%d.%d", rdata_pointer[0], rdata_pointer[1], rdata_pointer[2], rdata_pointer[3]);
1712 return SUCCESS;
1713 }
1714 return INCORRECT_RDATA;
1715 }
1716
1717 case TYPE_AAAA:
1718 {
1719 u16* rdata_u16 = (u16*)rdata_pointer;
1720 if(rdata_size == 16)
1721 {
1722 char ip6txt[INET6_ADDRSTRLEN];
1723
1724 inet_ntop(AF_INET6, rdata_u16, ip6txt, sizeof(ip6txt));
1725
1726 osprint(os, ip6txt);
1727
1728 return SUCCESS;
1729 }
1730 return INCORRECT_RDATA;
1731 }
1732 case TYPE_MX:
1733
1734
1735 case TYPE_KX:
1736 case TYPE_LP:
1737 case TYPE_AFSDB:
1738 osformat(os, "%hd ", ntohs(GET_U16_AT(*rdata_pointer)));
1739 rdata_pointer += 2;
1740 rdata_size -= 2;
1741 FALLTHROUGH // fall through
1742 case TYPE_NS:
1743 case TYPE_CNAME:
1744 case TYPE_DNAME:
1745 case TYPE_PTR:
1746 case TYPE_MB:
1747 case TYPE_MD:
1748 case TYPE_MF:
1749 case TYPE_MG:
1750 case TYPE_MR:
1751 {
1752 /* ONE NAME record */
1753 if(rdata_size > 0)
1754 {
1755 output_stream_write_dnsname_text(os, rdata_pointer);
1756 return SUCCESS;
1757 }
1758 return INCORRECT_RDATA;
1759 }
1760 case TYPE_PX:
1761 {
1762 if(rdata_size >= 4)
1763 {
1764 osformat(os, "%hd ", ntohs(GET_U16_AT(*rdata_pointer)));
1765 rdata_pointer += 2;
1766 rdata_size -= 2;
1767 }
1768 else
1769 {
1770 return INCORRECT_RDATA;
1771 }
1772 }
1773 FALLTHROUGH // fall through
1774 case TYPE_TALINK:
1775 {
1776 if(rdata_size >= 2)
1777 {
1778 u32 len = output_stream_write_dnsname_text(os, rdata_pointer);
1779 rdata_size -= len;
1780
1781 if(rdata_size > 0)
1782 {
1783 rdata_pointer += len;
1784
1785 len = output_stream_write_dnsname_text(os, rdata_pointer);
1786 rdata_size -= len;
1787
1788 if(rdata_size == 0)
1789 {
1790 return SUCCESS;
1791 }
1792 }
1793 }
1794
1795 return INCORRECT_RDATA;
1796 }
1797
1798 case TYPE_WKS:
1799 {
1800 if(rdata_size >= 6)
1801 {
1802 osformat(os, "%d.%d.%d.%d", rdata_pointer[0], rdata_pointer[1], rdata_pointer[2], rdata_pointer[3]);
1803
1804 rdata_pointer += 4;
1805 rdata_size -= 4;
1806
1807 ya_result len = protocol_id_to_name(rdata_pointer[0], tmp + 1, sizeof(tmp) - 1);
1808
1809 if(len < 0)
1810 {
1811 return len;
1812 }
1813
1814 tmp[0] = ' ';
1815 output_stream_write(os, tmp, len + 1);
1816
1817 rdata_pointer++;
1818 rdata_size--;
1819
1820 for(int index = 0; index < rdata_size; ++index)
1821 {
1822 u8 m;
1823 if((m = *rdata_pointer) != 0)
1824 {
1825 for(int i = 7; i >= 0; --i)
1826 {
1827 if((m & (1 << i)) != 0)
1828 {
1829 u16 port = (u16) ((index << 3) + 7 - i);
1830
1831 len = server_port_to_name(port, tmp + 1, sizeof(tmp) - 1);
1832
1833 if(len < 0)
1834 {
1835 return len;
1836 }
1837
1838 output_stream_write(os, tmp, len + 1);
1839 }
1840 }
1841 }
1842 }
1843
1844 return SUCCESS;
1845 }
1846 return INCORRECT_RDATA;
1847 }
1848
1849 case TYPE_GPOS:
1850 {
1851 const u8 *limit = &rdata_pointer[rdata_size];
1852
1853 for(int i = 0; i < 3; ++i)
1854 {
1855 u8 len = *rdata_pointer++;
1856
1857 if(len == 0)
1858 {
1859 return INCORRECT_RDATA;
1860 }
1861
1862 if(&rdata_pointer[len] >= limit)
1863 {
1864 return INCORRECT_RDATA;
1865 }
1866
1867 output_stream_write_u8(os, (u8)'"');
1868 output_stream_write(os, rdata_pointer, len);
1869 output_stream_write_u8(os, (u8)'"');
1870
1871 rdata_pointer += len;
1872 }
1873
1874 return SUCCESS;
1875 }
1876
1877 case TYPE_LOC:
1878 {
1879 /*
1880 * VERSION: This must be zero.
1881 * Implementations are required to check this field and make
1882 * no assumptions about the format of unrecognized versions.
1883 */
1884 if(rdata_size != 16 || rdata_pointer[0] != 0)
1885 {
1886 return INCORRECT_RDATA;
1887 }
1888
1889 /*
1890 * SIZE: The diameter of a sphere enclosing the described entity, in centimeters
1891 * format is a pair of four-bit unsigned integers, each ranging from zero to nine
1892 * This allows sizes from 0e0 (<1cm) to 9e9 (90,000km) to be expressed.
1893 * Four-bit values greater than 9 are undefined, as are values with a base of zero and a non-zero exponent
1894 */
1895
1896 u32 size, horizp, vertp;
1897
1898 if(!loc_float(rdata_pointer[1], &size) || !loc_float(rdata_pointer[2], &horizp) || !loc_float(rdata_pointer[3], &vertp))
1899 {
1900 return INCORRECT_RDATA;
1901 }
1902
1903 /*
1904 * LATITUDE
1905 */
1906 struct loc_coordinate loc_latitude;
1907 loc_coordinate_init(&loc_latitude, ntohl(GET_U32_AT(rdata_pointer[4])));
1908
1909 /*
1910 * LONGITUDE
1911 */
1912
1913 struct loc_coordinate loc_longitude;
1914 loc_coordinate_init(&loc_longitude, ntohl(GET_U32_AT(rdata_pointer[8])));
1915
1916 /*
1917 * ALTITUDE
1918 */
1919
1920 const u32 wgs84_reference = 10000000; // cm
1921
1922 u32 altitude = ntohl(GET_U32_AT(rdata_pointer[12]));
1923 int altfrac;
1924 if(altitude < wgs84_reference)
1925 {
1926 altitude = wgs84_reference - altitude;
1927 altfrac = altitude % 100;
1928 altitude /= -100;
1929 }
1930 else
1931 {
1932 altitude = altitude - wgs84_reference;
1933 altfrac = altitude % 100;
1934 altitude /= 100;
1935 }
1936
1937 osformat(os, "%u %u %u.%03u %c %u %u %u.%03u %c %d.%02um %dm %dm %dm",
1938 loc_latitude.deg, // degrees latitude [0 .. 90]
1939 loc_latitude.min, // minutes latitude [0 .. 59]
1940 loc_latitude.sec, // seconds latitude [0 .. 59]
1941 loc_latitude.secfrac, // fractions of seconds of latitude]
1942 loc_ns[loc_latitude.cardinal_index],// ['N' / 'S']
1943
1944 loc_longitude.deg, // degrees longitude [0 .. 90]
1945 loc_longitude.min, // minutes longitude [0 .. 59]
1946 loc_longitude.sec, // seconds longitude [0 .. 59]
1947 loc_longitude.secfrac, // fractions of seconds of longitude]
1948 loc_ew[loc_longitude.cardinal_index],// ['E' / 'W']
1949
1950 altitude, // altitude in meters [-100000.00 .. 42849672.95]
1951 altfrac,
1952
1953 size, horizp, vertp);
1954
1955 return SUCCESS;
1956 }
1957
1958 case TYPE_CSYNC:
1959 {
1960 if(rdata_size > 6)
1961 {
1962 osformat(os, "%u %hu ",
1963 ntohl(GET_U32_AT(rdata_pointer[0])),
1964 ntohs(GET_U16_AT(rdata_pointer[4]))
1965 );
1966
1967 rdata_pointer += 6;
1968 rdata_size -= 6;
1969
1970 return osprint_type_bitmap(os, rdata_pointer, rdata_size);
1971 }
1972
1973 return INCORRECT_RDATA;
1974 }
1975 case TYPE_OPENPGPKEY:
1976 {
1977 if(rdata_size > 0)
1978 {
1979 return osprint_base64(os, rdata_pointer, rdata_size);
1980 }
1981
1982 return INCORRECT_RDATA;
1983 }
1984 case TYPE_HINFO:
1985 case TYPE_MINFO:
1986 {
1987 /* Two Pascal String records */
1988
1989 /*
1990 * <character-string> is a single length octet followed by that number
1991 * of characters. <character-string> is treated as binary information,
1992 * and can be up to 256 characters in length (including the length octet).
1993 *
1994 */
1995
1996 int i;
1997
1998 for(i = 0; i < 2; i++)
1999 {
2000 u32 len = (*rdata_pointer) + 1;
2001
2002 if(len > rdata_size)
2003 {
2004 return INCORRECT_RDATA;
2005 }
2006
2007 osformat(os, "%{dnslabel}", rdata_pointer);
2008
2009 rdata_size -= len;
2010 rdata_pointer += len;
2011 }
2012
2013 return SUCCESS;
2014 }
2015
2016 case TYPE_SOA:
2017 {
2018 static u8 dot = (u8)'.';
2019 static u8 space = (u8)' ';
2020 static u8 escape = (u8)'\\';
2021
2022 output_stream_write_dnsname_text(os, rdata_pointer);
2023
2024 output_stream_write(os, &space, 1);
2025
2026 u32 len = dnsname_len(rdata_pointer);
2027
2028 rdata_size -= len;
2029
2030 if(rdata_size > 0)
2031 {
2032 rdata_pointer += len;
2033
2034 const u8 *label = rdata_pointer;
2035 u8 label_len = *label;
2036
2037 if(label_len > 0)
2038 {
2039 label++;
2040
2041 do
2042 {
2043 do
2044 {
2045 if(!dnsname_is_charspace(*label))
2046 {
2047 output_stream_write(os, &escape, 1);
2048 }
2049
2050 output_stream_write(os, label++, 1);
2051 }
2052 while(--label_len > 0);
2053
2054 output_stream_write(os, &dot, 1);
2055
2056 label_len = *label++;
2057 }
2058 while(label_len > 0);
2059
2060 len = label - rdata_pointer;
2061 }
2062 else
2063 {
2064 output_stream_write(os, &dot, 1);
2065
2066 len = 1;
2067 }
2068
2069 rdata_size -= len;
2070
2071 if(rdata_size == 20)
2072 {
2073 rdata_pointer += len;
2074
2075 osformat(os, " %u %u %u %u %u",
2076 ntohl(GET_U32_AT(rdata_pointer[ 0])),
2077 ntohl(GET_U32_AT(rdata_pointer[ 4])),
2078 ntohl(GET_U32_AT(rdata_pointer[ 8])),
2079 ntohl(GET_U32_AT(rdata_pointer[12])),
2080 ntohl(GET_U32_AT(rdata_pointer[16])));
2081
2082 return SUCCESS;
2083 }
2084 }
2085
2086 return INCORRECT_RDATA;
2087 }
2088 case TYPE_RRSIG:
2089 {
2090 struct tm exp;
2091 struct tm inc;
2092
2093 time_t t = (time_t)ntohl(GET_U32_AT(rdata_pointer[8]));
2094 gmtime_r(&t, &exp);
2095 t = (time_t)ntohl(GET_U32_AT(rdata_pointer[12]));
2096 gmtime_r(&t, &inc);
2097
2098 u16 covered_type = (GET_U16_AT(rdata_pointer[0])); /** @note NATIVETYPE */
2099
2100 osformat(os, "%{dnstype} %u %u %u %04u%02u%02u%02u%02u%02u %04u%02u%02u%02u%02u%02u %u ",
2101 &covered_type,
2102 U8_AT(rdata_pointer[2]),
2103 U8_AT(rdata_pointer[3]),
2104 ntohl(GET_U32_AT(rdata_pointer[4])),
2105 exp.tm_year + 1900, exp.tm_mon + 1, exp.tm_mday, exp.tm_hour, exp.tm_min, exp.tm_sec,
2106 inc.tm_year + 1900, inc.tm_mon + 1, inc.tm_mday, inc.tm_hour, inc.tm_min, inc.tm_sec,
2107 ntohs(GET_U16_AT(rdata_pointer[16])));
2108
2109 rdata_pointer += RRSIG_RDATA_HEADER_LEN;
2110 rdata_size -= RRSIG_RDATA_HEADER_LEN;
2111
2112 output_stream_write_dnsname_text(os, rdata_pointer);
2113 u32 len = dnsname_len(rdata_pointer);
2114 output_stream_write_u8(os, ' ');
2115
2116 rdata_pointer += len;
2117 rdata_size -= len;
2118
2119 if(rdata_size > 0)
2120 {
2121 osprint_base64(os, rdata_pointer, rdata_size);
2122 }
2123
2124 return SUCCESS;
2125 }
2126 case TYPE_DNSKEY:
2127 case TYPE_KEY:
2128 case TYPE_CDNSKEY:
2129 {
2130 osformat(os, "%u %u %u ",
2131 ntohs(GET_U16_AT(rdata_pointer[0])),
2132 U8_AT(rdata_pointer[2]),
2133 U8_AT(rdata_pointer[3]));
2134
2135 rdata_pointer += 4;
2136 rdata_size -= 4;
2137
2138 osprint_base64(os, rdata_pointer, rdata_size);
2139
2140 return SUCCESS;
2141 }
2142 case TYPE_DS:
2143 case TYPE_CDS:
2144 {
2145 osformat(os, "%u %u %u ",
2146 ntohs(GET_U16_AT(rdata_pointer[0])),
2147 U8_AT(rdata_pointer[2]),
2148 U8_AT(rdata_pointer[3]));
2149
2150 rdata_pointer += 4;
2151 rdata_size -= 4;
2152
2153 while(rdata_size-- > 0)
2154 {
2155 osformat(os, "%02X", *rdata_pointer++);
2156 }
2157
2158 return SUCCESS;
2159 }
2160 case TYPE_NSEC:
2161 {
2162 output_stream_write_dnsname_text(os, rdata_pointer);
2163 u32 len = dnsname_len(rdata_pointer);
2164 output_stream_write_u8(os, ' ');
2165
2166 rdata_pointer += len;
2167 rdata_size -= len;
2168
2169 ya_result ret;
2170
2171 if(ISOK(ret = osprint_type_bitmap(os, rdata_pointer, rdata_size)))
2172 {
2173 return SUCCESS;
2174 }
2175
2176 return ret;
2177 }
2178 case TYPE_NSEC3:
2179 case TYPE_NSEC3PARAM:
2180 {
2181 osformat(os, "%hhd %hhd %hd ",
2182 rdata_pointer[0],
2183 (type != TYPE_NSEC3PARAM) ? rdata_pointer[1] : 0,
2184 ntohs(GET_U16_AT(rdata_pointer[2])));
2185 u8 len = rdata_pointer[4];
2186
2187 rdata_pointer += 5;
2188 rdata_size -= 5;
2189
2190 if(len == 0)
2191 {
2192 osprint(os, "-");
2193 }
2194 else
2195 {
2196 rdata_size -= len;
2197
2198 while(len-- > 0)
2199 {
2200 osformat(os, "%02x", *rdata_pointer++);
2201 }
2202 }
2203
2204 if(type == TYPE_NSEC3)
2205 {
2206 output_stream_write_u8(os, ' ');
2207
2208 len = *rdata_pointer++;
2209
2210 rdata_size -= 1 + len;
2211
2212 ya_result return_code;
2213
2214 if(FAIL(return_code = output_stream_write_base32hex(os, rdata_pointer, len)))
2215 {
2216 return return_code;
2217 }
2218
2219 rdata_pointer += len;
2220
2221 return_code = osprint_type_bitmap(os, rdata_pointer, rdata_size);
2222
2223 return return_code;
2224 }
2225
2226 return SUCCESS;
2227 }
2228 case TYPE_TLSA:
2229 {
2230 osformat(os, "%hhd %hhd %hhd ", rdata_pointer[0], rdata_pointer[1], rdata_pointer[2]);
2231
2232 return osprint_base16(os, &rdata_pointer[3], rdata_size - 3);
2233 }
2234 case TYPE_SSHFP:
2235 {
2236 osformat(os, "%hhd %hhd ", rdata_pointer[0], rdata_pointer[1]);
2237
2238 return osprint_base16(os, &rdata_pointer[2], rdata_size - 2);
2239 }
2240 case TYPE_NID:
2241 case TYPE_L64:
2242 {
2243 if(rdata_size == 10)
2244 {
2245 osformat(os, "%hu %04x:%04x:%04x:%04x",
2246 ntohs(GET_U16_AT(rdata_pointer[0])),
2247 ntohs(GET_U16_AT(rdata_pointer[2])),
2248 ntohs(GET_U16_AT(rdata_pointer[4])),
2249 ntohs(GET_U16_AT(rdata_pointer[6])),
2250 ntohs(GET_U16_AT(rdata_pointer[8]))
2251 );
2252
2253 return SUCCESS;
2254 }
2255
2256 return INCORRECT_RDATA;
2257 }
2258
2259 case TYPE_L32:
2260 {
2261 if(rdata_size == 6)
2262 {
2263 osformat(os, "%hu %hhu.%hhu.%hhu.%hhu",
2264 ntohs(GET_U16_AT(rdata_pointer[0])),
2265 rdata_pointer[2],
2266 rdata_pointer[3],
2267 rdata_pointer[4],
2268 rdata_pointer[5]
2269 );
2270
2271 return SUCCESS;
2272 }
2273
2274 return INCORRECT_RDATA;
2275 }
2276
2277 case TYPE_EUI48:
2278 {
2279 if(rdata_size == 6)
2280 {
2281 osformat(os, "%02x-%02x-%02x-%02x-%02x-%02x",
2282 rdata_pointer[0],
2283 rdata_pointer[1],
2284 rdata_pointer[2],
2285 rdata_pointer[3],
2286 rdata_pointer[4],
2287 rdata_pointer[5]
2288 );
2289
2290 return SUCCESS;
2291 }
2292
2293 return INCORRECT_RDATA;
2294 }
2295
2296 case TYPE_EUI64:
2297 {
2298 if(rdata_size == 8)
2299 {
2300 osformat(os, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
2301 rdata_pointer[0],
2302 rdata_pointer[1],
2303 rdata_pointer[2],
2304 rdata_pointer[3],
2305 rdata_pointer[4],
2306 rdata_pointer[5],
2307 rdata_pointer[6],
2308 rdata_pointer[7]
2309 );
2310
2311 return SUCCESS;
2312 }
2313
2314 return INCORRECT_RDATA;
2315 }
2316
2317 case TYPE_SRV:
2318 {
2319 u16 priority = GET_U16_AT(rdata_pointer[0]);
2320 u16 weight = GET_U16_AT(rdata_pointer[2]);
2321 u16 port = GET_U16_AT(rdata_pointer[4]);
2322 const u8 *fqdn = (const u8*)&rdata_pointer[6];
2323
2324 return osformat(os, "%hd %hd %hd %{dnsname}", priority, weight, port, fqdn);
2325 }
2326 case TYPE_ZONE_TYPE:
2327 {
2328 u8 zone_type = rdata_pointer[0];
2329
2330 char *txt;
2331
2332 switch(zone_type)
2333 {
2334 case ZT_HINT:
2335 {
2336 txt = "hint";
2337 break;
2338 }
2339 case ZT_MASTER:
2340 {
2341 txt = "master";
2342 break;
2343 }
2344 case ZT_SLAVE:
2345 {
2346 txt = "slave";
2347 break;
2348 }
2349 case ZT_STUB:
2350 {
2351 txt = "stub";
2352 break;
2353 }
2354 default:
2355 {
2356 txt = "undefined";
2357 break;
2358 }
2359 }
2360
2361 return osprint(os, txt);
2362 }
2363 case TYPE_ZONE_MASTER:
2364 case TYPE_ZONE_SLAVES:
2365 case TYPE_ZONE_NOTIFY:
2366 {
2367 u8 flags = rdata_pointer[0];
2368 const u8 *src = &rdata_pointer[1];
2369
2370 ya_result total = 0;
2371
2372 switch(flags & 0x0f)
2373 {
2374 case 4:
2375 {
2376 // 4 bytes
2377
2378 total += osformat(os, "%d.%d.%d.%d", src[0], src[1], src[2], src[3]);
2379
2380 src += 4;
2381
2382 break;
2383 }
2384 case 6:
2385 {
2386 // 16 bytes
2387
2388 char ip6txt[INET6_ADDRSTRLEN];
2389
2390 inet_ntop(AF_INET6, &src, ip6txt, sizeof(ip6txt));
2391
2392 total += osprint(os, ip6txt);
2393
2394 src += 16;
2395
2396 break;
2397 }
2398 }
2399
2400 if((flags & REMOTE_SERVER_FLAGS_PORT_MASK) != 0)
2401 {
2402 u16 port = GET_U16_AT(*src);
2403
2404 total += osformat(os, " %hd", port);
2405
2406 src += 2;
2407 }
2408
2409 if((flags & REMOTE_SERVER_FLAGS_KEY_MASK) != 0)
2410 {
2411
2412 total += osformat(os, " %{dnsname}", src);
2413 }
2414
2415 return total;
2416 }
2417
2418 case TYPE_TXT:
2419 case TYPE_SPF:
2420 {
2421 u8 c;
2422
2423 if(rdata_size > 0)
2424 {
2425 for(;;)
2426 {
2427 c = *rdata_pointer++;
2428
2429 if(c > 0)
2430 {
2431 c = MIN(c, rdata_size);
2432 output_stream_write(os, (u8*)"\"", 1);
2433 output_stream_write(os, rdata_pointer, c);
2434 output_stream_write(os, (u8*)"\"", 1);
2435 }
2436
2437 rdata_size--;
2438 rdata_pointer += c;
2439 rdata_size -= c;
2440
2441 if(rdata_size == 0)
2442 {
2443 break;
2444 }
2445
2446 output_stream_write(os, (u8*)" ", 1);
2447 }
2448 }
2449
2450 return SUCCESS;
2451 }
2452 case TYPE_CTRL_ZONEFREEZE:
2453 case TYPE_CTRL_ZONEUNFREEZE:
2454 case TYPE_CTRL_ZONENOTIFY:
2455 case TYPE_CTRL_ZONERELOAD:
2456 case TYPE_CTRL_ZONECFGRELOAD:
2457 {
2458 /* ONE NAME record */
2459 if(rdata_size > 0)
2460 {
2461 ya_result ret = output_stream_write_dnsname_text(os, rdata_pointer);
2462 return ret;
2463 }
2464 return SUCCESS;
2465 }
2466 case TYPE_CTRL_SRVLOGLEVEL:
2467 case TYPE_CTRL_SRVQUERYLOG:
2468 {
2469 if(rdata_size == 1)
2470 {
2471 format_hex_u64_lo(rdata_pointer[0], os, 2, '0', FALSE);
2472 return SUCCESS;
2473 }
2474 return INCORRECT_RDATA;
2475 }
2476 case TYPE_CTRL_ZONESYNC:
2477 {
2478 /* ONE NAME record */
2479 if(rdata_size > 0)
2480 {
2481 format_hex_u64_lo(rdata_pointer[0], os, 2, '0', FALSE);
2482
2483 if(rdata_size > 1)
2484 {
2485 output_stream_write_u8(os, (u8)' ');
2486 ya_result ret = output_stream_write_dnsname_text(os, rdata_pointer + 1);
2487
2488 if(ISOK(ret))
2489 {
2490 return ret + 3;
2491 }
2492 else
2493 {
2494 return ret;
2495 }
2496 }
2497 }
2498 return SUCCESS;
2499 }
2500
2501 case TYPE_TSIG:
2502 {
2503 const u8 *limit = &rdata_pointer[rdata_size];
2504
2505 ya_result ret = output_stream_write_dnsname_text(os, rdata_pointer);
2506
2507 if(FAIL(ret))
2508 {
2509 return ret;
2510 }
2511
2512 rdata_pointer += ret;
2513
2514 if(limit - rdata_pointer < 16)
2515 {
2516 return ERROR;
2517 }
2518
2519 u16 time_hi = ntohs(GET_U16_AT(rdata_pointer[0]));
2520 u32 time_lo = ntohl(GET_U32_AT(rdata_pointer[2]));
2521 u16 fudge = ntohs(GET_U16_AT(rdata_pointer[6]));
2522 u16 mac_size = ntohs(GET_U16_AT(rdata_pointer[8]));
2523
2524 rdata_pointer += 10;
2525
2526 if(limit - rdata_pointer < mac_size + 6)
2527 {
2528 return ERROR;
2529 }
2530
2531 u64 epoch = time_hi;
2532 epoch <<= 32;
2533 epoch |= time_lo;
2534
2535 osformat(os, " %u %hu %hu", epoch, fudge, mac_size);
2536
2537 if(mac_size > 0)
2538 {
2539 osprint_char(os, ' ');
2540 osprint_base64(os, rdata_pointer, mac_size);
2541 rdata_pointer += mac_size;
2542 }
2543
2544 u16 oid = ntohs(GET_U16_AT(rdata_pointer[0]));
2545 u16 error = ntohs(GET_U16_AT(rdata_pointer[2]));
2546 u16 olen = ntohs(GET_U16_AT(rdata_pointer[4]));
2547
2548 rdata_pointer += 6;
2549
2550 if(limit - rdata_pointer != olen)
2551 {
2552 return ERROR;
2553 }
2554
2555 osformat(os, " %i %s %i ", ntohs(oid), dns_message_rcode_get_name(error), olen);
2556
2557 for(; rdata_pointer < limit; ++rdata_pointer)
2558 {
2559 osformat(os, "%02x", rdata_pointer[0]);
2560 }
2561
2562 break;
2563 }
2564
2565 case TYPE_A6:
2566 case TYPE_IXFR:
2567 case TYPE_AXFR:
2568 case TYPE_SIG:
2569 case TYPE_ANY:
2570 default:
2571
2572 osformat(os, "\\# %u ", rdata_size); /* rfc 3597 */
2573 osprint_base16(os, rdata_pointer, rdata_size);
2574
2575 return SUCCESS;
2576 }
2577
2578 return INCORRECT_RDATA;
2579 }
2580
2581 #if 0
2582 static int
2583 osprint_rdata_count_escapes(const u8* name, size_t name_len)
2584 {
2585 int ret = 0;
2586 for(size_t i = 0; i < name_len; ++i)
2587 {
2588 const char c = name[i];
2589
2590 for(size_t j = 0; j < sizeof(ESCAPE_CHARS); ++j)
2591 {
2592 if(c == ESCAPE_CHARS[j])
2593 {
2594 ++ret;
2595 }
2596 }
2597 }
2598
2599 return ret;
2600 }
2601 #endif
2602
2603 ya_result
osprint_rdata_escaped(output_stream * os,u16 type,const u8 * rdata_pointer,u16 rdata_size)2604 osprint_rdata_escaped(output_stream* os, u16 type, const u8* rdata_pointer, u16 rdata_size)
2605 {
2606 switch(type)
2607 {
2608 case TYPE_MX:
2609 case TYPE_KX:
2610 case TYPE_LP:
2611 case TYPE_AFSDB:
2612 osformat(os, "%hd ", ntohs(GET_U16_AT(*rdata_pointer)));
2613 rdata_pointer += 2;
2614 rdata_size -= 2;
2615 FALLTHROUGH // fall through
2616 case TYPE_NS:
2617 case TYPE_CNAME:
2618 case TYPE_DNAME:
2619 case TYPE_PTR:
2620 case TYPE_MB:
2621 case TYPE_MD:
2622 case TYPE_MF:
2623 case TYPE_MG:
2624 case TYPE_MR:
2625 {
2626 /* ONE NAME record */
2627 if(rdata_size > 0)
2628 {
2629 output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2630 return SUCCESS;
2631 }
2632 return INCORRECT_RDATA;
2633 }
2634
2635
2636
2637 case TYPE_TALINK:
2638 {
2639 if(rdata_size >= 2)
2640 {
2641 u32 len = output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2642 rdata_size -= len;
2643
2644 if(rdata_size > 0)
2645 {
2646 rdata_pointer += len;
2647
2648 len = output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2649 rdata_size -= len;
2650
2651 if(rdata_size == 0)
2652 {
2653 return SUCCESS;
2654 }
2655 }
2656 }
2657
2658 return INCORRECT_RDATA;
2659 }
2660
2661 case TYPE_HINFO:
2662 case TYPE_MINFO:
2663 {
2664 /* Two Pascal String records */
2665
2666 /*
2667 * <character-string> is a single length octet followed by that number
2668 * of characters. <character-string> is treated as binary information,
2669 * and can be up to 256 characters in length (including the length octet).
2670 *
2671 */
2672
2673 int i;
2674
2675 for(i = 0; i < 2; i++)
2676 {
2677 u32 len = (*rdata_pointer) + 1;
2678
2679 if(len > rdata_size)
2680 {
2681 return INCORRECT_RDATA;
2682 }
2683
2684 output_stream_write_dnslabel_text_escaped(os, rdata_pointer);
2685
2686 rdata_size -= len;
2687 rdata_pointer += len;
2688 }
2689
2690 return SUCCESS;
2691 }
2692
2693 case TYPE_SOA:
2694 {
2695 output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2696 output_stream_write_u8(os, ' ');
2697
2698 u32 len = dnsname_len(rdata_pointer);
2699 rdata_size -= len;
2700
2701 if(rdata_size > 0)
2702 {
2703 rdata_pointer += len;
2704
2705 output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2706 output_stream_write_u8(os, ' ');
2707
2708 len = dnsname_len(rdata_pointer);
2709 rdata_size -= len;
2710
2711 if(rdata_size == 20)
2712 {
2713 rdata_pointer += len;
2714
2715 osformat(os, " %u %u %u %u %u",
2716 ntohl(GET_U32_AT(rdata_pointer[ 0])),
2717 ntohl(GET_U32_AT(rdata_pointer[ 4])),
2718 ntohl(GET_U32_AT(rdata_pointer[ 8])),
2719 ntohl(GET_U32_AT(rdata_pointer[12])),
2720 ntohl(GET_U32_AT(rdata_pointer[16])));
2721
2722 return SUCCESS;
2723 }
2724 }
2725
2726 return INCORRECT_RDATA;
2727 }
2728 case TYPE_RRSIG:
2729 {
2730 struct tm exp;
2731 struct tm inc;
2732
2733 time_t t = (time_t)ntohl(GET_U32_AT(rdata_pointer[8]));
2734 gmtime_r(&t, &exp);
2735 t = (time_t)ntohl(GET_U32_AT(rdata_pointer[12]));
2736 gmtime_r(&t, &inc);
2737
2738 u16 covered_type = (GET_U16_AT(rdata_pointer[0])); /** @note NATIVETYPE */
2739
2740 osformat(os, "%{dnstype} %u %u %u %04u%02u%02u%02u%02u%02u %04u%02u%02u%02u%02u%02u %u ",
2741 &covered_type,
2742 U8_AT(rdata_pointer[2]),
2743 U8_AT(rdata_pointer[3]),
2744 ntohl(GET_U32_AT(rdata_pointer[4])),
2745 exp.tm_year + 1900, exp.tm_mon + 1, exp.tm_mday, exp.tm_hour, exp.tm_min, exp.tm_sec,
2746 inc.tm_year + 1900, inc.tm_mon + 1, inc.tm_mday, inc.tm_hour, inc.tm_min, inc.tm_sec,
2747 ntohs(GET_U16_AT(rdata_pointer[16])));
2748
2749 rdata_pointer += RRSIG_RDATA_HEADER_LEN;
2750 rdata_size -= RRSIG_RDATA_HEADER_LEN;
2751
2752 output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2753 u32 len = dnsname_len(rdata_pointer);
2754 output_stream_write_u8(os, ' ');
2755
2756 rdata_pointer += len;
2757 rdata_size -= len;
2758
2759 if(rdata_size > 0)
2760 {
2761 osprint_base64(os, rdata_pointer, rdata_size);
2762 }
2763
2764 return SUCCESS;
2765 }
2766
2767 case TYPE_NSEC:
2768 {
2769 output_stream_write_dnsname_text_escaped(os, rdata_pointer);
2770 u32 len = dnsname_len(rdata_pointer);
2771 output_stream_write_u8(os, ' ');
2772
2773 rdata_pointer += len;
2774 rdata_size -= len;
2775
2776 ya_result ret;
2777
2778 if(ISOK(ret = osprint_type_bitmap(os, rdata_pointer, rdata_size)))
2779 {
2780 return SUCCESS;
2781 }
2782
2783 return ret;
2784 }
2785
2786 case TYPE_SRV:
2787 {
2788 u16 priority = GET_U16_AT(rdata_pointer[0]);
2789 u16 weight = GET_U16_AT(rdata_pointer[2]);
2790 u16 port = GET_U16_AT(rdata_pointer[4]);
2791 const u8 *fqdn = (const u8*)&rdata_pointer[6];
2792
2793 osformat(os, "%hd %hd %hd ", priority, weight, port);
2794
2795 ya_result ret = output_stream_write_dnsname_text_escaped(os, fqdn);
2796
2797 return ret;
2798 }
2799
2800 case TYPE_TXT:
2801 case TYPE_SPF:
2802 {
2803 u8 pascal_string_size;
2804 int space_len = 0;
2805
2806 while(rdata_size > 0)
2807 {
2808 pascal_string_size = *rdata_pointer++;
2809
2810 if(pascal_string_size > 0)
2811 {
2812 output_stream_write(os, (u8*)" ", space_len);
2813
2814 pascal_string_size = MIN(pascal_string_size, rdata_size);
2815
2816 output_stream_write(os, STRQUOTE, 1);
2817
2818 for(int i = 0; i < pascal_string_size; ++i)
2819 {
2820 u8 escape_type = TXT_ESCAPE_TYPE[rdata_pointer[i]];
2821
2822 switch(escape_type)
2823 {
2824 case TXT_ESCAPE_TYPE_NONE:
2825 {
2826 output_stream_write(os, &rdata_pointer[i], 1);
2827 break;
2828 }
2829 case TXT_ESCAPE_TYPE_CHAR:
2830 {
2831 output_stream_write(os, STRESCAPE, 1);
2832 output_stream_write(os, &rdata_pointer[i], 1);
2833 break;
2834 }
2835 case TXT_ESCAPE_TYPE_OCTL:
2836 {
2837 u8 decimal[4];
2838 decimal[0] = '\\';
2839 decimal[1] = ((rdata_pointer[i] / 100) % 10) + '0';
2840 decimal[2] = ((rdata_pointer[i] / 10) % 10) + '0';
2841 decimal[3] = (rdata_pointer[i] % 10) + '0';
2842 output_stream_write(os, decimal, 4);
2843 break;
2844 }
2845 }
2846 }
2847
2848 output_stream_write(os, STRQUOTE, 1);
2849 }
2850 else
2851 {
2852 output_stream_write(os, "\"\"", 2);
2853 }
2854
2855 space_len = 1;
2856
2857 rdata_size--;
2858 rdata_pointer += pascal_string_size;
2859 rdata_size -= pascal_string_size;
2860 }
2861
2862 return SUCCESS;
2863 }
2864 default:
2865 {
2866 ya_result ret = osprint_rdata(os, type, rdata_pointer, rdata_size);
2867
2868 return ret;
2869 }
2870 }
2871
2872 return INCORRECT_RDATA;
2873 }
2874
2875
2876 ya_result
print_rdata(u16 type,u8 * rdata_pointer,u16 rdata_size)2877 print_rdata(u16 type, u8* rdata_pointer, u16 rdata_size)
2878 {
2879 return osprint_rdata(termout, type, rdata_pointer, rdata_size);
2880 }
2881
2882 void
osprint_dump_with_base(output_stream * os,const void * data_pointer_,size_t size_,size_t line_size,u32 flags,const void * base_pointer_)2883 osprint_dump_with_base(output_stream *os, const void* data_pointer_, size_t size_, size_t line_size, u32 flags, const void* base_pointer_)
2884 {
2885 const u8* data_pointer = (const u8*)data_pointer_;
2886 size_t size = size_;
2887
2888 bool offset = (flags & OSPRINT_DUMP_OFFSET) != 0;
2889 bool address = (flags & OSPRINT_DUMP_ADDRESS) != 0;
2890 bool hex = (flags & OSPRINT_DUMP_HEX) != 0;
2891 bool text = (flags & OSPRINT_DUMP_TEXT) != 0;
2892 bool squeeze_zeroes = (flags & OSPRINT_DUMP_SQUEEZE_ZEROES) != 0;
2893
2894 size_t group = flags & OSPRINT_DUMP_LAYOUT_GROUP_MASK;
2895 group >>= OSPRINT_DUMP_LAYOUT_GROUP_SHIFT;
2896 size_t separator = flags & OSPRINT_DUMP_LAYOUT_SEPARATOR_MASK;
2897 separator >>= OSPRINT_DUMP_LAYOUT_SEPARATOR_SHIFT;
2898
2899 s32 offset_width = 2 * 2;
2900
2901 if(offset)
2902 {
2903 if(size_ > MAX_U16)
2904 {
2905 if(size_ <= MAX_U32)
2906 {
2907 offset_width = 4 * 2;
2908 }
2909 else
2910 {
2911 offset_width = 8 * 2;
2912 }
2913 }
2914 }
2915
2916 size_t dump_size;
2917 size_t i;
2918 s64 zeroes_count = 0;
2919
2920 char hexbyte[2];
2921
2922 do
2923 {
2924 if(line_size != 0)
2925 {
2926 dump_size = MIN(line_size, size);
2927 }
2928 else
2929 {
2930 dump_size = size;
2931 }
2932
2933 const u8* data;
2934
2935 if(squeeze_zeroes && (dump_size == line_size))
2936 {
2937 if(base_pointer_ < (const void*)data_pointer)
2938 {
2939 bool zeroes = TRUE;
2940 for(int i = 0; i < (int)line_size; ++i)
2941 {
2942 if(data_pointer[i] != 0)
2943 {
2944 zeroes = FALSE;
2945 break;
2946 }
2947 }
2948
2949 if(zeroes)
2950 {
2951 zeroes_count += line_size;
2952 data_pointer += dump_size;
2953 size -= dump_size;
2954 continue;
2955 }
2956 else if(zeroes_count > 0)
2957 {
2958 osformatln(os,"\t\t... %lli zeroes ...", zeroes_count);
2959 zeroes_count = 0;
2960 }
2961 }
2962 }
2963
2964 if(address)
2965 {
2966 format_hex_u64_hi((intptr)data_pointer, os, __SIZEOF_POINTER__ * 2, '0', FALSE);
2967 output_stream_write(os, (const u8*)" | ", 3);
2968 }
2969
2970 if(offset)
2971 {
2972 format_hex_u64_hi((intptr)data_pointer - (intptr)base_pointer_, os, offset_width, '0', FALSE);
2973 output_stream_write(os, (const u8*)" | ", 3);
2974 }
2975
2976 if(hex)
2977 {
2978 data = data_pointer;
2979
2980 for(i = 0; i < dump_size; i++)
2981 {
2982 u8 val = *data++;
2983
2984 hexbyte[0] = __hexa__[val >> 4];
2985 hexbyte[1] = __hexa__[val & 0x0f];
2986
2987 output_stream_write(os, (u8*)hexbyte, 2);
2988
2989 if((i & group) == group)
2990 {
2991 output_stream_write_u8(os, (u8)' ');
2992 }
2993 if((i & separator) == separator)
2994 {
2995 output_stream_write_u8(os, (u8)' ');
2996 }
2997 }
2998
2999 for(; i < line_size; i++)
3000 {
3001 output_stream_write(os, (const u8*)" ", 2); // these are two spaces
3002 if((i & group) == group)
3003 {
3004 output_stream_write_u8(os, (u8)' ');
3005 }
3006 if((i & separator) == separator)
3007 {
3008 output_stream_write_u8(os, (u8)' ');
3009 }
3010 }
3011 }
3012
3013 if(text)
3014 {
3015 if(hex)
3016 {
3017 output_stream_write(os, (const u8*)" | ", 4);
3018 }
3019
3020 data = data_pointer;
3021
3022 for(i = 0; i < dump_size; i++)
3023 {
3024 char c = *data++;
3025
3026 if(c < ' ')
3027 {
3028 c = '.';
3029 }
3030
3031 output_stream_write_u8(os, (u8)c);
3032 }
3033 }
3034
3035 data_pointer += dump_size;
3036 size -= dump_size;
3037
3038 if(size != 0)
3039 {
3040 output_stream_write_u8(os, (u8)'\n');
3041 }
3042 }
3043 while(size > 0);
3044 }
3045
3046 void
osprint_dump(output_stream * os,const void * data_pointer_,size_t size_,size_t line_size,u32 flags)3047 osprint_dump(output_stream *os, const void* data_pointer_, size_t size_, size_t line_size, u32 flags)
3048 {
3049 osprint_dump_with_base(os, data_pointer_, size_, line_size, flags, data_pointer_);
3050 }
3051
3052 void
osprint_question(output_stream * os,u8 * qname,u16 qclass,u16 qtype)3053 osprint_question(output_stream* os, u8* qname, u16 qclass, u16 qtype)
3054 {
3055 osformat(os, ";; QUESTION SECTION:\n%{dnsname} %{dnsclass} %{dnstype}\n\n", qname, &qclass, &qtype);
3056 }
3057
3058 void
print_question(u8 * qname,u16 qclass,u16 qtype)3059 print_question(u8* qname, u16 qclass, u16 qtype)
3060 {
3061 osprint_question(termout, qname, qclass, qtype);
3062 }
3063
3064 /** @} */
3065