Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / format_tv.c
blob9333507ddb034931b14bab641f7e3dc3852ed4d4
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* format_tv 3
6 /* SUMMARY
7 /* format time value with sane precision
8 /* SYNOPSIS
9 /* #include <format_tv.h>
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.
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 /*--*/
54 #include <sys_defs.h>
56 /* Utility library. */
58 #include <msg.h>
59 #include <format_tv.h>
61 /* Application-specific. */
63 #define MILLION 1000000
65 /* format_tv - print time with limited precision */
67 VSTRING *format_tv(VSTRING *buf, int sec, int usec,
68 int sig_dig, int max_dig)
70 static int pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
71 int n;
72 int rem;
73 int wid;
74 int ures;
77 * Sanity check.
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];
89 * Adjust the resolution to suppress irrelevant digits.
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;
103 * Round up the number if necessary. Leave thrash below the resolution.
105 if (ures > 1) {
106 usec += ures / 2;
107 if (usec >= MILLION) {
108 sec += 1;
109 usec -= MILLION;
114 * Format the number. Truncate trailing null and thrash below resolution.
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;
124 VSTRING_TERMINATE(buf);
125 return (buf);
128 #ifdef TEST
130 #include <stdio.h>
131 #include <stdlib.h>
132 #include <vstring_vstream.h>
134 int main(int argc, char **argv)
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;
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);
157 vstring_free(in);
158 vstring_free(out);
159 return (0);
162 #endif