Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / wsutil / to_str.c
blob6258fa927b10a60a4cc437a5e6033ad44bc5b0ec
1 /* wsutil/to_str.c
2 * Routines for utilities to convert various other types to strings.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
12 #include "to_str.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <time.h>
18 #include <wsutil/utf8_entities.h>
19 #include <wsutil/wslog.h>
20 #include <wsutil/inet_addr.h>
21 #include <wsutil/pint.h>
22 #include <wsutil/time_util.h>
25 * If a user _does_ pass in a too-small buffer, this is probably
26 * going to be too long to fit. However, even a partial string
27 * starting with "[Buf" should provide enough of a clue to be
28 * useful.
30 #define _return_if_nospace(str_len, buf, buf_len) \
31 do { \
32 if ((str_len) > (buf_len)) { \
33 (void)g_strlcpy(buf, "[Buffer too small]", buf_len); \
34 return; \
35 } \
36 } while (0)
38 static const char fast_strings[][4] = {
39 "0", "1", "2", "3", "4", "5", "6", "7",
40 "8", "9", "10", "11", "12", "13", "14", "15",
41 "16", "17", "18", "19", "20", "21", "22", "23",
42 "24", "25", "26", "27", "28", "29", "30", "31",
43 "32", "33", "34", "35", "36", "37", "38", "39",
44 "40", "41", "42", "43", "44", "45", "46", "47",
45 "48", "49", "50", "51", "52", "53", "54", "55",
46 "56", "57", "58", "59", "60", "61", "62", "63",
47 "64", "65", "66", "67", "68", "69", "70", "71",
48 "72", "73", "74", "75", "76", "77", "78", "79",
49 "80", "81", "82", "83", "84", "85", "86", "87",
50 "88", "89", "90", "91", "92", "93", "94", "95",
51 "96", "97", "98", "99", "100", "101", "102", "103",
52 "104", "105", "106", "107", "108", "109", "110", "111",
53 "112", "113", "114", "115", "116", "117", "118", "119",
54 "120", "121", "122", "123", "124", "125", "126", "127",
55 "128", "129", "130", "131", "132", "133", "134", "135",
56 "136", "137", "138", "139", "140", "141", "142", "143",
57 "144", "145", "146", "147", "148", "149", "150", "151",
58 "152", "153", "154", "155", "156", "157", "158", "159",
59 "160", "161", "162", "163", "164", "165", "166", "167",
60 "168", "169", "170", "171", "172", "173", "174", "175",
61 "176", "177", "178", "179", "180", "181", "182", "183",
62 "184", "185", "186", "187", "188", "189", "190", "191",
63 "192", "193", "194", "195", "196", "197", "198", "199",
64 "200", "201", "202", "203", "204", "205", "206", "207",
65 "208", "209", "210", "211", "212", "213", "214", "215",
66 "216", "217", "218", "219", "220", "221", "222", "223",
67 "224", "225", "226", "227", "228", "229", "230", "231",
68 "232", "233", "234", "235", "236", "237", "238", "239",
69 "240", "241", "242", "243", "244", "245", "246", "247",
70 "248", "249", "250", "251", "252", "253", "254", "255"
73 static inline char
74 low_nibble_of_octet_to_hex(uint8_t oct)
76 /* At least one version of Apple's C compiler/linker is buggy, causing
77 a complaint from the linker about the "literal C string section"
78 not ending with '\0' if we initialize a 16-element "char" array with
79 a 16-character string, the fact that initializing such an array with
80 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
81 '\0' byte in the string nonwithstanding. */
82 static const char hex_digits[16] =
83 { '0', '1', '2', '3', '4', '5', '6', '7',
84 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
86 return hex_digits[oct & 0xF];
89 static inline char *
90 byte_to_hex(char *out, uint32_t dword)
92 *out++ = low_nibble_of_octet_to_hex(dword >> 4);
93 *out++ = low_nibble_of_octet_to_hex(dword);
94 return out;
97 char *
98 uint8_to_hex(char *out, uint8_t val)
100 return byte_to_hex(out, val);
103 char *
104 word_to_hex(char *out, uint16_t word)
106 out = byte_to_hex(out, word >> 8);
107 out = byte_to_hex(out, word);
108 return out;
111 char *
112 word_to_hex_punct(char *out, uint16_t word, char punct)
114 out = byte_to_hex(out, word >> 8);
115 *out++ = punct;
116 out = byte_to_hex(out, word);
117 return out;
120 char *
121 word_to_hex_npad(char *out, uint16_t word)
123 if (word >= 0x1000)
124 *out++ = low_nibble_of_octet_to_hex((uint8_t)(word >> 12));
125 if (word >= 0x0100)
126 *out++ = low_nibble_of_octet_to_hex((uint8_t)(word >> 8));
127 if (word >= 0x0010)
128 *out++ = low_nibble_of_octet_to_hex((uint8_t)(word >> 4));
129 *out++ = low_nibble_of_octet_to_hex((uint8_t)(word >> 0));
130 return out;
133 char *
134 dword_to_hex(char *out, uint32_t dword)
136 out = word_to_hex(out, dword >> 16);
137 out = word_to_hex(out, dword);
138 return out;
141 char *
142 dword_to_hex_punct(char *out, uint32_t dword, char punct)
144 out = word_to_hex_punct(out, dword >> 16, punct);
145 *out++ = punct;
146 out = word_to_hex_punct(out, dword, punct);
147 return out;
150 char *
151 qword_to_hex(char *out, uint64_t qword)
153 out = dword_to_hex(out, (uint32_t)(qword >> 32));
154 out = dword_to_hex(out, (uint32_t)(qword & 0xffffffff));
155 return out;
158 char *
159 qword_to_hex_punct(char *out, uint64_t qword, char punct)
161 out = dword_to_hex_punct(out, (uint32_t)(qword >> 32), punct);
162 *out++ = punct;
163 out = dword_to_hex_punct(out, (uint32_t)(qword & 0xffffffff), punct);
164 return out;
168 * This does *not* null-terminate the string. It returns a pointer
169 * to the position in the string following the last character it
170 * puts there, so that the caller can either put the null terminator
171 * in or can append more stuff to the buffer.
173 * There needs to be at least len * 2 bytes left in the buffer.
175 char *
176 bytes_to_hexstr(char *out, const uint8_t *ad, size_t len)
178 size_t i;
180 ws_return_val_if(!ad, NULL);
182 for (i = 0; i < len; i++)
183 out = byte_to_hex(out, ad[i]);
184 return out;
188 * This does *not* null-terminate the string. It returns a pointer
189 * to the position in the string following the last character it
190 * puts there, so that the caller can either put the null terminator
191 * in or can append more stuff to the buffer.
193 * There needs to be at least len * 3 - 1 bytes left in the buffer.
195 char *
196 bytes_to_hexstr_punct(char *out, const uint8_t *ad, size_t len, char punct)
198 size_t i;
200 ws_return_val_if(!ad, NULL);
202 out = byte_to_hex(out, ad[0]);
203 for (i = 1; i < len; i++) {
204 *out++ = punct;
205 out = byte_to_hex(out, ad[i]);
207 return out;
210 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
211 * digits at a time, with a specified punctuation character between
212 * the bytes.
214 * If punct is '\0', no punctuation is applied (and thus
215 * the resulting string is (len-1) bytes shorter)
217 char *
218 bytes_to_str_punct_maxlen(wmem_allocator_t *scope,
219 const uint8_t *src, size_t src_size,
220 char punct, size_t max_bytes_len)
222 char *buf;
223 size_t max_char_size;
224 char *buf_ptr;
225 int truncated = 0;
227 ws_return_str_if(!src, scope);
229 if (!src_size) {
230 return wmem_strdup(scope, "");
233 if (!punct)
234 return bytes_to_str_maxlen(scope, src, src_size, max_bytes_len);
236 if (max_bytes_len == 0 || max_bytes_len > src_size) {
237 max_bytes_len = src_size;
239 else if (max_bytes_len < src_size) {
240 truncated = 1;
243 /* Include space for ellipsis and '\0'. Optional extra punct
244 * at the end is already accounted for. */
245 max_char_size = max_bytes_len * 3 + strlen(UTF8_HORIZONTAL_ELLIPSIS) + 1;
247 buf = wmem_alloc(scope, max_char_size);
248 buf_ptr = bytes_to_hexstr_punct(buf, src, max_bytes_len, punct);
250 if (truncated) {
251 *buf_ptr++ = punct;
252 buf_ptr = g_stpcpy(buf_ptr, UTF8_HORIZONTAL_ELLIPSIS);
255 *buf_ptr = '\0';
256 return buf;
259 char *
260 bytes_to_str_maxlen(wmem_allocator_t *scope,
261 const uint8_t *src, size_t src_size,
262 size_t max_bytes_len)
264 char *buf;
265 size_t max_char_size;
266 char *buf_ptr;
267 int truncated = 0;
269 ws_return_str_if(!src, scope);
271 if (!src_size) {
272 return wmem_strdup(scope, "");
275 if (max_bytes_len == 0 || max_bytes_len > src_size) {
276 max_bytes_len = src_size;
278 else if (max_bytes_len < src_size) {
279 truncated = 1;
282 max_char_size = max_bytes_len * 2 + strlen(UTF8_HORIZONTAL_ELLIPSIS) + 1;
284 buf = wmem_alloc(scope, max_char_size);
285 buf_ptr = bytes_to_hexstr(buf, src, max_bytes_len);
287 if (truncated)
288 buf_ptr = g_stpcpy(buf_ptr, UTF8_HORIZONTAL_ELLIPSIS);
290 *buf_ptr = '\0';
291 return buf;
295 * The *_to_str_back() functions measured approx. a x7.5 speed-up versus
296 * snprintf() on my Linux system with GNU libc.
299 char *
300 oct_to_str_back(char *ptr, uint32_t value)
302 while (value) {
303 *(--ptr) = '0' + (value & 0x7);
304 value >>= 3;
307 *(--ptr) = '0';
308 return ptr;
311 char *
312 oct64_to_str_back(char *ptr, uint64_t value)
314 while (value) {
315 *(--ptr) = '0' + (value & 0x7);
316 value >>= 3;
319 *(--ptr) = '0';
320 return ptr;
323 char *
324 hex_to_str_back_len(char *ptr, uint32_t value, int len)
326 do {
327 *(--ptr) = low_nibble_of_octet_to_hex(value);
328 value >>= 4;
329 len--;
330 } while (value);
332 /* pad */
333 while (len > 0) {
334 *(--ptr) = '0';
335 len--;
338 *(--ptr) = 'x';
339 *(--ptr) = '0';
341 return ptr;
344 char *
345 hex64_to_str_back_len(char *ptr, uint64_t value, int len)
347 do {
348 *(--ptr) = low_nibble_of_octet_to_hex(value & 0xF);
349 value >>= 4;
350 len--;
351 } while (value);
353 /* pad */
354 while (len > 0) {
355 *(--ptr) = '0';
356 len--;
359 *(--ptr) = 'x';
360 *(--ptr) = '0';
362 return ptr;
365 char *
366 uint_to_str_back(char *ptr, uint32_t value)
368 char const *p;
370 /* special case */
371 if (value == 0)
372 *(--ptr) = '0';
374 while (value >= 10) {
375 p = fast_strings[100 + (value % 100)];
377 value /= 100;
379 *(--ptr) = p[2];
380 *(--ptr) = p[1];
383 if (value)
384 *(--ptr) = (value) | '0';
386 return ptr;
389 char *
390 uint64_to_str_back(char *ptr, uint64_t value)
392 char const *p;
394 /* special case */
395 if (value == 0)
396 *(--ptr) = '0';
398 while (value >= 10) {
399 p = fast_strings[100 + (value % 100)];
401 value /= 100;
403 *(--ptr) = p[2];
404 *(--ptr) = p[1];
407 /* value will be 0..9, so using '& 0xF' is safe, and faster than '% 10' */
408 if (value)
409 *(--ptr) = (value & 0xF) | '0';
411 return ptr;
414 char *
415 uint_to_str_back_len(char *ptr, uint32_t value, int len)
417 char *new_ptr;
419 new_ptr = uint_to_str_back(ptr, value);
421 /* subtract from len number of generated characters */
422 len -= (int)(ptr - new_ptr);
424 /* pad remaining with '0' */
425 while (len > 0)
427 *(--new_ptr) = '0';
428 len--;
431 return new_ptr;
434 char *
435 uint64_to_str_back_len(char *ptr, uint64_t value, int len)
437 char *new_ptr;
439 new_ptr = uint64_to_str_back(ptr, value);
441 /* subtract from len number of generated characters */
442 len -= (int)(ptr - new_ptr);
444 /* pad remaining with '0' */
445 while (len > 0)
447 *(--new_ptr) = '0';
448 len--;
451 return new_ptr;
454 char *
455 int_to_str_back(char *ptr, int32_t value)
457 if (value < 0) {
458 ptr = uint_to_str_back(ptr, -value);
459 *(--ptr) = '-';
460 } else
461 ptr = uint_to_str_back(ptr, value);
463 return ptr;
466 char *
467 int64_to_str_back(char *ptr, int64_t value)
469 if (value < 0) {
470 ptr = uint64_to_str_back(ptr, -value);
471 *(--ptr) = '-';
472 } else
473 ptr = uint64_to_str_back(ptr, value);
475 return ptr;
478 static size_t
479 uint32_to_str_buf_len(const uint32_t u)
481 /* ((2^32)-1) == 2147483647 */
482 if (u >= 1000000000)return 10;
483 if (u >= 100000000) return 9;
484 if (u >= 10000000) return 8;
485 if (u >= 1000000) return 7;
486 if (u >= 100000) return 6;
487 if (u >= 10000) return 5;
488 if (u >= 1000) return 4;
489 if (u >= 100) return 3;
490 if (u >= 10) return 2;
492 return 1;
495 void
496 uint32_to_str_buf(uint32_t u, char *buf, size_t buf_len)
498 size_t str_len = uint32_to_str_buf_len(u)+1;
500 char *bp = &buf[str_len];
502 _return_if_nospace(str_len, buf, buf_len);
504 *--bp = '\0';
506 uint_to_str_back(bp, u);
509 static size_t
510 uint64_to_str_buf_len(const uint64_t u)
512 /* ((2^64)-1) == 18446744073709551615 */
514 if (u >= UINT64_C(10000000000000000000)) return 20;
515 if (u >= UINT64_C(1000000000000000000)) return 19;
516 if (u >= UINT64_C(100000000000000000)) return 18;
517 if (u >= UINT64_C(10000000000000000)) return 17;
518 if (u >= UINT64_C(1000000000000000)) return 16;
519 if (u >= UINT64_C(100000000000000)) return 15;
520 if (u >= UINT64_C(10000000000000)) return 14;
521 if (u >= UINT64_C(1000000000000)) return 13;
522 if (u >= UINT64_C(100000000000)) return 12;
523 if (u >= UINT64_C(10000000000)) return 11;
524 if (u >= UINT64_C(1000000000)) return 10;
525 if (u >= UINT64_C(100000000)) return 9;
526 if (u >= UINT64_C(10000000)) return 8;
527 if (u >= UINT64_C(1000000)) return 7;
528 if (u >= UINT64_C(100000)) return 6;
529 if (u >= UINT64_C(10000)) return 5;
530 if (u >= UINT64_C(1000)) return 4;
531 if (u >= UINT64_C(100)) return 3;
532 if (u >= UINT64_C(10)) return 2;
534 return 1;
537 void
538 uint64_to_str_buf(uint64_t u, char *buf, size_t buf_len)
540 size_t str_len = uint64_to_str_buf_len(u)+1;
542 char *bp = &buf[str_len];
544 _return_if_nospace(str_len, buf, buf_len);
546 *--bp = '\0';
548 uint64_to_str_back(bp, u);
552 This function is very fast and this function is called a lot.
553 XXX update the address_to_str stuff to use this function.
555 void
556 ip_addr_to_str_buf(const ws_in4_addr *_ad, char *buf, const int buf_len)
558 uint8_t *ad = (uint8_t *)_ad;
559 register char const *p;
560 register char *b=buf;
562 _return_if_nospace(WS_INET_ADDRSTRLEN, buf, buf_len);
564 p=fast_strings[*ad++];
565 do {
566 *b++=*p;
567 p++;
568 } while(*p);
569 *b++='.';
571 p=fast_strings[*ad++];
572 do {
573 *b++=*p;
574 p++;
575 } while(*p);
576 *b++='.';
578 p=fast_strings[*ad++];
579 do {
580 *b++=*p;
581 p++;
582 } while(*p);
583 *b++='.';
585 p=fast_strings[*ad];
586 do {
587 *b++=*p;
588 p++;
589 } while(*p);
590 *b=0;
593 char *
594 ip_addr_to_str(wmem_allocator_t *scope, const ws_in4_addr *ad)
596 char *buf = wmem_alloc(scope, WS_INET_ADDRSTRLEN * sizeof(char));
598 ip_addr_to_str_buf(ad, buf, WS_INET_ADDRSTRLEN);
600 return buf;
603 void
604 ip_num_to_str_buf(uint32_t ad, char *buf, const int buf_len)
606 ws_in4_addr addr = g_htonl(ad);
607 ip_addr_to_str_buf(&addr, buf, buf_len);
610 /* Host byte order */
611 char *
612 ip_num_to_str(wmem_allocator_t *scope, uint32_t ad)
614 ws_in4_addr addr = g_htonl(ad);
615 return ip_addr_to_str(scope, &addr);
618 void
619 ip_to_str_buf(const uint8_t *ad, char *buf, const int buf_len)
621 ip_addr_to_str_buf((const ws_in4_addr *)ad, buf, buf_len);
624 char *
625 ip_to_str(wmem_allocator_t *scope, const uint8_t *ad)
627 return ip_addr_to_str(scope, (const ws_in4_addr *)ad);
630 void
631 ip6_to_str_buf(const ws_in6_addr *addr, char *buf, size_t buf_size)
634 * If there is not enough space then ws_inet_ntop6() will leave
635 * an error message in the buffer, we don't need
636 * to use _return_if_nospace().
638 ws_inet_ntop6(addr, buf, (unsigned)buf_size);
641 char *ip6_to_str(wmem_allocator_t *scope, const ws_in6_addr *ad)
643 char *buf = wmem_alloc(scope, WS_INET6_ADDRSTRLEN * sizeof(char));
645 ws_inet_ntop6(ad, buf, WS_INET6_ADDRSTRLEN);
647 return buf;
650 char *
651 ipxnet_to_str_punct(wmem_allocator_t *allocator, const uint32_t ad, const char punct)
653 char *buf = (char *)wmem_alloc(allocator, 12);
655 *dword_to_hex_punct(buf, ad, punct) = '\0';
656 return buf;
659 #define WS_EUI64_STRLEN 24
661 char *
662 eui64_to_str(wmem_allocator_t *scope, const uint64_t ad) {
663 char *buf, *tmp;
664 uint8_t *p_eui64;
666 p_eui64=(uint8_t *)wmem_alloc(NULL, 8);
667 buf=(char *)wmem_alloc(scope, WS_EUI64_STRLEN);
669 /* Copy and convert the address to network byte order. */
670 *(uint64_t *)(void *)(p_eui64) = pntoh64(&(ad));
672 tmp = bytes_to_hexstr_punct(buf, p_eui64, 8, ':');
673 *tmp = '\0'; /* NULL terminate */
674 wmem_free(NULL, p_eui64);
675 return buf;
679 * Number of characters required by a 64-bit signed number.
681 #define CHARS_64_BIT_SIGNED 20 /* sign plus 19 digits */
684 * Number of characters required by a fractional part, in nanoseconds,
685 * not counting the decimal point.
687 #define CHARS_NANOSECONDS 9 /* 000000001 */
690 * Format the fractional part of a time, with the specified precision.
691 * Returns the number of bytes formatted.
694 format_fractional_part_nsecs(char *buf, size_t buflen, uint32_t nsecs, const char *decimal_point, int precision)
696 char *ptr;
697 size_t remaining;
698 int num_bytes;
699 size_t decimal_point_len;
700 uint32_t frac_part;
701 int8_t num_buf[CHARS_NANOSECONDS];
702 int8_t *num_end = &num_buf[CHARS_NANOSECONDS];
703 int8_t *num_ptr;
704 size_t num_len;
706 ws_assert(precision != WS_TSPREC_SEC);
708 if (buflen == 0) {
710 * No room in the buffer for anything, including
711 * a terminating '\0'.
713 return 0;
717 * If the fractional part is >= 1, don't show it as a
718 * fractional part.
720 if (nsecs >= 1000000000U) {
721 num_bytes = snprintf(buf, buflen, "%s(%u nanoseconds)",
722 decimal_point, nsecs);
723 if ((unsigned int)num_bytes >= buflen) {
725 * That filled up or would have overflowed
726 * the buffer. Nothing more to do; return
727 * the remaining space in the buffer, minus
728 * one byte for the terminating '\0',* as
729 * that's the number of bytes we copied.
731 return (int)(buflen - 1);
733 return num_bytes;
736 ptr = buf;
737 remaining = buflen;
738 num_bytes = 0;
741 * Copy the decimal point.
742 * (We assume here that the locale's decimal point does
743 * not contain so many characters that its size doesn't
744 * fit in an int. :-))
746 decimal_point_len = g_strlcpy(buf, decimal_point, buflen);
747 if (decimal_point_len >= buflen) {
749 * The decimal point didn't fit in the buffer
750 * and was truncated. Nothing more to do;
751 * return the remaining space in the buffer,
752 * minus one byte for the terminating '\0',
753 * as that's the number of bytes we copied.
755 return (int)(buflen - 1);
757 ptr += decimal_point_len;
758 remaining -= decimal_point_len;
759 num_bytes += (int)decimal_point_len;
762 * Fill in num_buf with the nanoseconds value, padded with
763 * leading zeroes, to the specified precision.
765 * We scale the fractional part in advance, as that just
766 * takes one division by a constant (which may be
767 * optimized to a faster multiplication by a constant)
768 * and gets rid of some divisions and remainders by 100
769 * done to generate the digits.
771 * We pass preciions as the last argument to
772 * uint_to_str_back_len(), as that might mean that
773 * all of the cases end up using common code to
774 * do part of the call to uint_to_str_back_len().
776 switch (precision) {
778 case WS_TSPREC_100_MSEC:
780 * Scale down to units of 1/10 second.
782 frac_part = nsecs / 100000000U;
783 break;
785 case WS_TSPREC_10_MSEC:
787 * Scale down to units of 1/100 second.
789 frac_part = nsecs / 10000000U;
790 break;
792 case WS_TSPREC_MSEC:
794 * Scale down to units of 1/1000 second.
796 frac_part = nsecs / 1000000U;
797 break;
799 case WS_TSPREC_100_USEC:
801 * Scale down to units of 1/10000 second.
803 frac_part = nsecs / 100000U;
804 break;
806 case WS_TSPREC_10_USEC:
808 * Scale down to units of 1/100000 second.
810 frac_part = nsecs / 10000U;
811 break;
813 case WS_TSPREC_USEC:
815 * Scale down to units of 1/1000000 second.
817 frac_part = nsecs / 1000U;
818 break;
820 case WS_TSPREC_100_NSEC:
822 * Scale down to units of 1/10000000 second.
824 frac_part = nsecs / 100U;
825 break;
827 case WS_TSPREC_10_NSEC:
829 * Scale down to units of 1/100000000 second.
831 frac_part = nsecs / 10U;
832 break;
834 case WS_TSPREC_NSEC:
836 * We're already in units of 1/1000000000 second.
838 frac_part = nsecs;
839 break;
841 default:
842 ws_assert_not_reached();
843 break;
846 num_ptr = uint_to_str_back_len(num_end, frac_part, precision);
849 * The length of the string that we want to copy to the buffer
850 * is the minimum of:
852 * the length of the digit string;
853 * the remaining space in the buffer, minus 1 for the
854 * terminating '\0'.
856 num_len = MIN((size_t)(num_end - num_ptr), remaining - 1);
857 if (num_len == 0) {
859 * Not enough room to copy anything.
860 * Return the number of bytes we've generated.
862 return num_bytes;
866 * Copy over the fractional part.
867 * (We assume here that the fractional part does not contain
868 * so many characters that its size doesn't fit in an int. :-))
870 memcpy(ptr, num_ptr, num_len);
871 ptr += num_len;
872 num_bytes += (int)num_len;
875 * '\0'-terminate it.
877 *ptr = '\0';
878 return num_bytes;
881 void
882 display_epoch_time(char *buf, size_t buflen, const nstime_t *ns, int precision)
884 display_signed_time(buf, buflen, ns, precision);
887 void
888 display_signed_time(char *buf, size_t buflen, const nstime_t *ns, int precision)
890 int nsecs;
891 /* this buffer is not NUL terminated */
892 int8_t num_buf[CHARS_64_BIT_SIGNED];
893 int8_t *num_end = &num_buf[CHARS_64_BIT_SIGNED];
894 int8_t *num_ptr;
895 size_t num_len;
897 if (buflen < 1)
898 return;
900 /* If the fractional part of the time stamp is negative,
901 print its absolute value and, if the seconds part isn't
902 (the seconds part should be zero in that case), stick
903 a "-" in front of the entire time stamp. */
904 nsecs = ns->nsecs;
905 if (nsecs < 0) {
906 nsecs = -nsecs;
907 if (ns->secs >= 0) {
908 buf[0] = '-';
909 buf++;
910 buflen--;
915 * Fill in num_buf with the seconds value.
917 num_ptr = int64_to_str_back(num_end, ns->secs);
920 * The length of the string that we want to copy to the buffer
921 * is the minimum of:
923 * the length of the digit string;
924 * the size of the buffer, minus 1 for the terminating
925 * '\0'.
927 num_len = MIN((size_t)(num_end - num_ptr), buflen - 1);
928 if (num_len == 0) {
930 * Not enough room to copy anything.
932 return;
936 * Copy over the seconds value.
938 memcpy(buf, num_ptr, num_len);
939 buf += num_len;
940 buflen -= num_len;
942 if (precision == WS_TSPREC_SEC) {
944 * Seconds precision, so no nanosecond.
945 * Nothing more to do other than to
946 * '\0'-terminate the string.
948 *buf = '\0';
949 return;
953 * Append the fractional part.
955 format_fractional_part_nsecs(buf, buflen, (uint32_t)nsecs, ".", precision);
958 void
959 format_nstime_as_iso8601(char *buf, size_t buflen, const nstime_t *ns,
960 char *decimal_point, bool local, int precision)
962 struct tm tm, *tmp;
963 char *ptr;
964 size_t remaining;
965 int num_bytes;
967 if (local)
968 tmp = ws_localtime_r(&ns->secs, &tm);
969 else
970 tmp = ws_gmtime_r(&ns->secs, &tm);
971 if (tmp == NULL) {
972 snprintf(buf, buflen, "Not representable");
973 return;
975 ptr = buf;
976 remaining = buflen;
977 num_bytes = snprintf(ptr, remaining,
978 "%04d-%02d-%02d %02d:%02d:%02d",
979 tmp->tm_year + 1900,
980 tmp->tm_mon + 1,
981 tmp->tm_mday,
982 tmp->tm_hour,
983 tmp->tm_min,
984 tmp->tm_sec);
985 if (num_bytes < 0) {
987 * That got an error.
988 * Not much else we can do.
990 snprintf(buf, buflen, "snprintf() failed");
991 return;
993 if ((unsigned int)num_bytes >= remaining) {
995 * That filled up or would have overflowed the buffer.
996 * Nothing more we can do.
998 return;
1000 ptr += num_bytes;
1001 remaining -= num_bytes;
1003 if (precision != 0) {
1005 * Append the fractional part.
1006 * Get the nsecs as a 32-bit unsigned value, as it should
1007 * never be negative, so we treat it as unsigned.
1009 format_fractional_part_nsecs(ptr, remaining, (uint32_t)ns->nsecs, decimal_point, precision);
1014 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1016 * Local variables:
1017 * c-basic-offset: 8
1018 * tab-width: 8
1019 * indent-tabs-mode: t
1020 * End:
1022 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1023 * :indentSize=8:tabSize=8:noTabs=false: