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