1 /*
2 tickcount -- Display the kernel tick count (or any tick count passed as an
3 argument or as input) in human-readable format
4
5 This is public domain software
6 */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <tchar.h>
12 #include <windows.h>
13
14 typedef __int64 int64_;
15 typedef unsigned __int64 uint64_;
16
17 #define TICKS_YEAR (TICKS_DAY * ((uint64_)365))
18 #define TICKS_MONTH (TICKS_DAY * ((uint64_)30))
19 #define TICKS_WEEK (TICKS_DAY * ((uint64_)7))
20 #define TICKS_DAY (TICKS_HOUR * ((uint64_)24))
21 #define TICKS_HOUR (TICKS_MINUTE * ((uint64_)60))
22 #define TICKS_MINUTE (TICKS_SECOND * ((uint64_)60))
23 #define TICKS_SECOND ((uint64_)1000)
24
25 #define SLICES_COUNT (sizeof(ticks_per_slice) / sizeof(ticks_per_slice[0]))
26
27 uint64_ ticks_per_slice[] =
28 {
29 TICKS_YEAR,
30 TICKS_MONTH,
31 TICKS_WEEK,
32 TICKS_DAY,
33 TICKS_HOUR,
34 TICKS_MINUTE,
35 TICKS_SECOND,
36 1
37 };
38
39 _TCHAR * slice_names_singular[SLICES_COUNT] =
40 {
41 _T("year"),
42 _T("month"),
43 _T("week"),
44 _T("day"),
45 _T("hour"),
46 _T("minute"),
47 _T("second"),
48 _T("millisecond")
49 };
50
51 _TCHAR * slice_names_plural[SLICES_COUNT] =
52 {
53 _T("years"),
54 _T("months"),
55 _T("weeks"),
56 _T("days"),
57 _T("hours"),
58 _T("minutes"),
59 _T("seconds"),
60 _T("milliseconds")
61 };
62
print_uptime(uint64_ tickcount,uint64_ prevsliceval,_TCHAR * prevsliceunit,int curslice)63 void print_uptime
64 (
65 uint64_ tickcount,
66 uint64_ prevsliceval,
67 _TCHAR * prevsliceunit,
68 int curslice
69 )
70 {
71 uint64_ tick_cur = tickcount / ticks_per_slice[curslice];
72 uint64_ tick_residual = tickcount % ticks_per_slice[curslice];
73
74 assert(tick_cur <= (~((uint64_)0)));
75
76 if(tick_residual == 0)
77 {
78 /* the current slice is the last */
79
80 if(prevsliceval == 0)
81 {
82 /* the current slice is the only */
83 _tprintf
84 (
85 _T("%u %s"),
86 (unsigned)tick_cur,
87 (tick_cur == 1 ? slice_names_singular : slice_names_plural)[curslice]
88 );
89 }
90 else
91 {
92 /* the current slice is the last, and there's a previous slice */
93 assert(prevsliceunit);
94
95 /* print the previous and the current slice, and terminate */
96 _tprintf
97 (
98 _T("%u %s %s %u %s"),
99 (unsigned)prevsliceval,
100 prevsliceunit,
101 _T("and"),
102 (unsigned)tick_cur,
103 (tick_cur == 1 ? slice_names_singular : slice_names_plural)[curslice]
104 );
105 }
106 }
107 else if(tick_cur != 0)
108 {
109 /* the current slice is not the last, and non-zero */
110
111 if(prevsliceval != 0)
112 {
113 /* there's a previous slice: print it */
114 assert(prevsliceunit);
115 _tprintf(_T("%u %s, "), (unsigned)prevsliceval, prevsliceunit);
116 }
117
118 /* recursion on the next slice size, storing the current slice */
119 print_uptime
120 (
121 tick_residual,
122 tick_cur,
123 (tick_cur == 1 ? slice_names_singular : slice_names_plural)[curslice],
124 curslice + 1
125 );
126 }
127 else
128 {
129 /*
130 the current slice is not the last, and zero: recursion, remembering the
131 previous non-zero slice
132 */
133 print_uptime(tick_residual, prevsliceval, prevsliceunit, curslice + 1);
134 }
135 }
136
parse_print(const _TCHAR * str)137 int parse_print(const _TCHAR * str)
138 {
139 int64_ tickcount;
140
141 tickcount = _ttoi64(str);
142
143 if(tickcount < 0)
144 tickcount = - tickcount;
145 else if(tickcount == 0)
146 return 1;
147
148 print_uptime(tickcount, 0, NULL, 0);
149 _puttc(_T('\n'), stdout);
150
151 return 0;
152 }
153
_tmain(int argc,_TCHAR * argv[])154 int _tmain(int argc, _TCHAR * argv[])
155 {
156 int r;
157
158 if(argc <= 1)
159 {
160 print_uptime((uint64_)GetTickCount(), 0, NULL, 0);
161 _puttc(_T('\n'), stdout);
162 }
163 else if(argc == 2 && argv[1][0] == _T('-') && argv[1][1] == 0)
164 {
165 while(!feof(stdin))
166 {
167 _TCHAR buf[23];
168 _TCHAR * str;
169
170 str = _fgetts(buf, 22, stdin);
171
172 if(str == NULL)
173 return 0;
174
175 if((r = parse_print(str)) != 0)
176 return r;
177 }
178 }
179 else
180 {
181 int i;
182
183 for(i = 1; i < argc; ++ i)
184 if((r = parse_print(argv[i])) != 0)
185 return r;
186 }
187
188 return 0;
189 }
190