1 /* $NetBSD: format_tv.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $ */ 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 67 VSTRING *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 134 int 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