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