1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* format_tv 3 6/* SUMMARY 7/* format time value with sane precision 8/* SYNOPSIS 9/* #include <format_tv.h> 10/* 11/* VSTRING *format_tv(buffer, sec, usec, sig_dig, max_dig) 12/* VSTRING *buffer; 13/* int sec; 14/* int usec; 15/* int sig_dig; 16/* int max_dig; 17/* DESCRIPTION 18/* format_tv() formats the specified time as a floating-point 19/* number while suppressing irrelevant digits in the output. 20/* Large numbers are always rounded up to an integral number 21/* of seconds. Small numbers are produced with a limited number 22/* of significant digits, provided that the result does not 23/* exceed the limit on the total number of digits after the 24/* decimal point. Trailing zeros are always omitted from the 25/* output. 26/* 27/* Arguments: 28/* .IP buffer 29/* The buffer to which the result is appended. 30/* .IP sec 31/* The seconds portion of the time value. 32/* .IP usec 33/* The microseconds portion of the time value. 34/* .IP sig_dig 35/* The maximal number of significant digits when formatting 36/* small numbers. Leading nulls don't count as significant, 37/* and trailing nulls are not included in the output. Specify 38/* a number in the range 1..6. 39/* .IP max_dig 40/* The maximal number of all digits after the decimal point. 41/* Specify a number in the range 0..6. 42/* LICENSE 43/* .ad 44/* fi 45/* The Secure Mailer license must be distributed with this 46/* software. 47/* AUTHOR(S) 48/* Wietse Venema 49/* IBM T.J. Watson Research 50/* P.O. Box 704 51/* Yorktown Heights, NY 10598, USA 52/*--*/ 53 54#include <sys_defs.h> 55 56/* Utility library. */ 57 58#include <msg.h> 59#include <format_tv.h> 60 61/* Application-specific. */ 62 63#define MILLION 1000000 64 65/* format_tv - print time with limited precision */ 66 67VSTRING *format_tv(VSTRING *buf, int sec, int usec, 68 int sig_dig, int max_dig) 69{ 70 static int pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000}; 71 int n; 72 int rem; 73 int wid; 74 int ures; 75 76 /* 77 * Sanity check. 78 */ 79 if (max_dig < 0 || max_dig > 6) 80 msg_panic("format_tv: bad maximum decimal count %d", max_dig); 81 if (sec < 0 || usec < 0 || usec > MILLION) 82 msg_panic("format_tv: bad time %ds %dus", sec, usec); 83 if (sig_dig < 1 || sig_dig > 6) 84 msg_panic("format_tv: bad significant decimal count %d", sig_dig); 85 ures = MILLION / pow10[max_dig]; 86 wid = pow10[sig_dig]; 87 88 /* 89 * Adjust the resolution to suppress irrelevant digits. 90 */ 91 if (ures < MILLION) { 92 if (sec > 0) { 93 for (n = 1; sec >= n && n <= wid / 10; n *= 10) 94 /* void */ ; 95 ures = (MILLION / wid) * n; 96 } else { 97 while (usec >= wid * ures) 98 ures *= 10; 99 } 100 } 101 102 /* 103 * Round up the number if necessary. Leave thrash below the resolution. 104 */ 105 if (ures > 1) { 106 usec += ures / 2; 107 if (usec >= MILLION) { 108 sec += 1; 109 usec -= MILLION; 110 } 111 } 112 113 /* 114 * Format the number. Truncate trailing null and thrash below resolution. 115 */ 116 vstring_sprintf_append(buf, "%d", sec); 117 if (usec >= ures) { 118 VSTRING_ADDCH(buf, '.'); 119 for (rem = usec, n = MILLION / 10; rem >= ures && n > 0; n /= 10) { 120 VSTRING_ADDCH(buf, "0123456789"[rem / n]); 121 rem %= n; 122 } 123 } 124 VSTRING_TERMINATE(buf); 125 return (buf); 126} 127 128#ifdef TEST 129 130#include <stdio.h> 131#include <stdlib.h> 132#include <vstring_vstream.h> 133 134int main(int argc, char **argv) 135{ 136 VSTRING *in = vstring_alloc(10); 137 VSTRING *out = vstring_alloc(10); 138 double tval; 139 int sec; 140 int usec; 141 int sig_dig; 142 int max_dig; 143 144 while (vstring_get_nonl(in, VSTREAM_IN) > 0) { 145 vstream_printf(">> %s\n", vstring_str(in)); 146 if (vstring_str(in)[0] == 0 || vstring_str(in)[0] == '#') 147 continue; 148 if (sscanf(vstring_str(in), "%lf %d %d", &tval, &sig_dig, &max_dig) != 3) 149 msg_fatal("bad input: %s", vstring_str(in)); 150 sec = (int) tval; /* raw seconds */ 151 usec = (tval - sec) * MILLION; /* raw microseconds */ 152 VSTRING_RESET(out); 153 format_tv(out, sec, usec, sig_dig, max_dig); 154 vstream_printf("%s\n", vstring_str(out)); 155 vstream_fflush(VSTREAM_OUT); 156 } 157 vstring_free(in); 158 vstring_free(out); 159 return (0); 160} 161 162#endif 163