updates from orpheus for windoze build
[feisty_meow.git] / nucleus / library / timely / time_stamp.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : time_stamp                                                        *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 1995-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 #include "earth_time.h"
16 #include "time_stamp.h"
17
18 #include <application/windoze_helper.h>
19 #include <basis/environment.h>
20 #include <basis/mutex.h>
21 #include <loggers/program_wide_logger.h>
22
23 #include <stdlib.h>
24 //#ifdef __WIN32__
25 //  #define _WINSOCKAPI_  // make windows.h happy about winsock.
26 //  #include <winsock2.h>  // timeval.
27 //#endif
28
29 //#define DEBUG_TIME_STAMP
30
31 #ifdef DEBUG_TIME_STAMP
32   #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
33   using namespace loggers;
34 #endif
35
36 using namespace basis;
37
38 namespace timely {
39
40 static mutex &__uptime_synchronizer() {
41   static mutex uptiming_syncher;
42   return uptiming_syncher;
43 }
44
45 basis::astring time_stamp::notarize(bool add_space)
46 {
47   const time_locus the_time = now();
48   astring to_return;
49   the_time.text_form_long(to_return, clock_time::MILITARY | clock_time::MILLISECONDS);
50   if (add_space) to_return += " ";
51   return to_return;
52 }
53
54 time_stamp::time_stamp() : c_stamp(0) { fill_in_time(); }
55
56 time_stamp::time_stamp(time_representation offset)
57 : c_stamp(0) { reset(offset); }
58
59 void time_stamp::reset() { fill_in_time(); }
60
61 astring time_stamp::text_form(stamp_display_style style) const
62 {
63   time_representation stump = c_stamp;
64   bool past = false;
65   if (style == STAMP_RELATIVE) {
66     // adjust the returned time by subtracting the current time.
67     stump -= get_time_now();
68     if (negative(stump)) {
69       // if we're negative, just note that the stamp is in the past.
70       past = true;
71       stump = absolute_value(stump);
72     }
73   }
74   time_representation divisor = 3600 * SECOND_ms;
75   basis::un_int hours = basis::un_int(stump / divisor);
76   stump -= divisor * time_representation(hours);
77   divisor /= 60;
78   basis::un_int minutes = basis::un_int(stump / divisor);
79   stump -= divisor * time_representation(minutes);
80   divisor /= 60;
81   basis::un_int seconds = basis::un_int(stump / divisor);
82   stump -= divisor * time_representation(seconds);
83   basis::un_int milliseconds = basis::un_int(stump);
84   // make absolutely sure we are between 0 and 999.
85   milliseconds %= 1000;
86
87   astring to_return;
88   bool did_hours = false;
89   if (hours) {
90     to_return += astring(astring::SPRINTF, "%uh:", hours);
91     did_hours = true;
92   }
93   if (minutes || did_hours)
94     to_return += astring(astring::SPRINTF, "%02um:", minutes);
95   to_return += astring(astring::SPRINTF, "%02us.%03u", seconds, milliseconds);
96   if (style == STAMP_RELATIVE) {
97     if (past) to_return += " ago";
98     else to_return += " from now";
99   }
100   return to_return;
101 }
102
103 void time_stamp::fill_in_time()
104 {
105   time_representation current = get_time_now();
106   c_stamp = current;  // reset our own time now.
107 }
108
109 void time_stamp::reset(time_representation offset)
110 {
111   fill_in_time();
112   c_stamp += offset;
113 }
114
115 time_stamp::time_representation time_stamp::get_time_now()
116 { return rolling_uptime(); }
117
118 const double __rollover_point = 2.0 * MAXINT32;
119   // this number is our rollover point for 32 bit integers.
120
121 double time_stamp::rolling_uptime()
122 {
123   auto_synchronizer l(__uptime_synchronizer());
124     // protect our rollover records.
125
126   static basis::un_int __last_ticks = 0;
127   static int __rollovers = 0;
128
129   basis::un_int ticks_up = environment::system_uptime();
130     // acquire the current uptime as a 32 bit unsigned int.
131
132   if (ticks_up < __last_ticks) {
133     // rollover happened.  increment our tracker.
134     __rollovers++;
135   }
136   __last_ticks = ticks_up;
137
138   return double(__rollovers) * __rollover_point + double(ticks_up);
139 }
140
141 void time_stamp::fill_timeval_ms(struct timeval &time_out, int duration)
142 {
143   FUNCDEF("fill_timeval_ms");
144   // timeval has tv_sec=seconds, tv_usec=microseconds.
145   if (!duration) {
146     // duration is immediate for the check; just a quick poll.
147     time_out.tv_sec = 0;
148     time_out.tv_usec = 0;
149 #ifdef DEBUG_TIME_STAMP
150     LOG("no duration specified");
151 #endif
152   } else {
153     // a non-zero duration means we need to compute secs and usecs.
154     time_out.tv_sec = duration / 1000;
155     // set the number of seconds from the input in milliseconds.
156     duration -= time_out.tv_sec * 1000;
157     // now take out the chunk we've already recorded as seconds.
158     time_out.tv_usec = duration * 1000;
159     // set the number of microseconds from the remaining milliseconds.
160 #ifdef DEBUG_TIME_STAMP
161     LOG(a_sprintf("duration of %d ms went to %d sec and %d usec.", duration,
162         time_out.tv_sec, time_out.tv_usec));
163 #endif
164   }
165 }
166
167 } //namespace.
168