7 /* format time value with sane precision
9 /* #include <format_tv.h>
11 /* VSTRING *format_tv(buffer, sec, usec, sig_dig, max_dig)
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
29 /* The buffer to which the result is appended.
31 /* The seconds portion of the time value.
33 /* The microseconds portion of the time value.
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.
40 /* The maximal number of all digits after the decimal point.
41 /* Specify a number in the range 0..6.
45 /* The Secure Mailer license must be distributed with this
49 /* IBM T.J. Watson Research
51 /* Yorktown Heights, NY 10598, USA
56 /* Utility library. */
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};
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
];
89 * Adjust the resolution to suppress irrelevant digits.
93 for (n
= 1; sec
>= n
&& n
<= wid
/ 10; n
*= 10)
95 ures
= (MILLION
/ wid
) * n
;
97 while (usec
>= wid
* ures
)
103 * Round up the number if necessary. Leave thrash below the resolution.
107 if (usec
>= MILLION
) {
114 * Format the number. Truncate trailing null and thrash below resolution.
116 vstring_sprintf_append(buf
, "%d", sec
);
118 VSTRING_ADDCH(buf
, '.');
119 for (rem
= usec
, n
= MILLION
/ 10; rem
>= ures
&& n
> 0; n
/= 10) {
120 VSTRING_ADDCH(buf
, "0123456789"[rem
/ n
]);
124 VSTRING_TERMINATE(buf
);
132 #include <vstring_vstream.h>
134 int main(int argc
, char **argv
)
136 VSTRING
*in
= vstring_alloc(10);
137 VSTRING
*out
= vstring_alloc(10);
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] == '#')
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 */
153 format_tv(out
, sec
, usec
, sig_dig
, max_dig
);
154 vstream_printf("%s\n", vstring_str(out
));
155 vstream_fflush(VSTREAM_OUT
);