Postfix3.3.1
format_tv.c
[詳解]
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 /* long sec;
12 /* long 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 
65 VSTRING *format_tv(VSTRING *buf, long sec, long 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 %lds %ldus", 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, "%ld", 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 
132 int 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));
154  }
155  vstring_free(in);
156  vstring_free(out);
157  return (0);
158 }
159 
160 #endif
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
#define VSTREAM_IN
Definition: vstream.h:66
VSTRING * format_tv(VSTRING *buf, long sec, long usec, int sig_dig, int max_dig)
Definition: format_tv.c:65
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define MILLION
Definition: format_tv.c:61
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
Definition: vstring.c:624
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int int
Definition: smtpd_proxy.h:21
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380