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 
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 
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 
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