1132451Sroberto/*  Copyright (C) 1996 N.M. Maclaren
2132451Sroberto    Copyright (C) 1996 The University of Cambridge
3132451Sroberto
4132451SrobertoThis includes all of the code needed to handle the time.  It assumes rather
5132451Srobertomore than is defined by POSIX, unfortunately.  Systems that do not have the
6132451Sroberto'X/Open' extensions may need changes. */
7132451Sroberto
8132451Sroberto
9132451Sroberto
10132451Sroberto#include "header.h"
11132451Sroberto
12132451Sroberto#include <sys/types.h>
13132451Sroberto#include <sys/time.h>
14132451Sroberto
15132451Sroberto#define TIMING
16132451Sroberto#include "kludges.h"
17132451Sroberto#undef TIMING
18132451Sroberto
19132451Sroberto
20132451Sroberto
21132451Sroberto#define MILLION_L    1000000l          /* For conversion to/from timeval */
22132451Sroberto#define MILLION_D       1.0e6          /* Must be equal to MILLION_L */
23132451Sroberto
24132451Sroberto
25132451Sroberto
26132451Srobertodouble current_time (double offset) {
27132451Sroberto
28132451Sroberto/* Get the current UTC time in seconds since the Epoch plus an offset (usually
29132451Srobertothe time from the beginning of the century to the Epoch!) */
30132451Sroberto
31132451Sroberto    struct timeval current;
32132451Sroberto
33132451Sroberto    errno = 0;
34132451Sroberto    if (gettimeofday(&current,NULL))
35132451Sroberto        fatal(1,"unable to read current machine/system time",NULL);
36132451Sroberto    return offset+current.tv_sec+1.0e-6*current.tv_usec;
37132451Sroberto}
38132451Sroberto
39132451Sroberto
40132451Sroberto
41132451Srobertotime_t convert_time (double value, int *millisecs) {
42132451Sroberto
43132451Sroberto/* Convert the time to the ANSI C form. */
44132451Sroberto
45132451Sroberto    time_t result = (time_t)value;
46132451Sroberto
47132451Sroberto    if ((*millisecs = (int)(1000.0*(value-result))) >= 1000) {
48132451Sroberto        *millisecs = 0;
49132451Sroberto        ++result;
50132451Sroberto    }
51132451Sroberto    return result;
52132451Sroberto}
53132451Sroberto
54132451Sroberto
55132451Sroberto
56132451Srobertovoid adjust_time (double difference, int immediate, double ignore) {
57132451Sroberto
58132451Sroberto/* Adjust the current UTC time.  This is portable, even if struct timeval uses
59132451Srobertoan unsigned long for tv_sec. */
60132451Sroberto
61132451Sroberto    struct timeval old, new, adjust, previous;
62132451Sroberto    char text[40];
63132451Sroberto    long n;
64132451Sroberto
65132451Sroberto/* Start by converting to timeval format. Note that we have to cater for
66132451Srobertonegative, unsigned values. */
67132451Sroberto
68132451Sroberto    if ((n = (long)difference) > difference) --n;
69132451Sroberto    adjust.tv_sec = n;
70132451Sroberto    adjust.tv_usec = (long)(MILLION_D*(difference-n));
71132451Sroberto    errno = 0;
72132451Sroberto    if (gettimeofday(&old,NULL))
73132451Sroberto        fatal(1,"unable to read machine/system time",NULL);
74132451Sroberto    new.tv_sec = old.tv_sec+adjust.tv_sec;
75132451Sroberto    new.tv_usec = (n = (long)old.tv_usec+(long)adjust.tv_usec);
76132451Sroberto    if (n < 0) {
77132451Sroberto        new.tv_usec += MILLION_L;
78132451Sroberto        --new.tv_sec;
79132451Sroberto    } else if (n >= MILLION_L) {
80132451Sroberto        new.tv_usec -= MILLION_L;
81132451Sroberto        ++new.tv_sec;
82132451Sroberto    }
83132451Sroberto
84132451Sroberto/* Now diagnose the situation if necessary, and perform the dirty deed. */
85132451Sroberto
86132451Sroberto    if (verbose > 2)
87132451Sroberto        fprintf(stderr,
88132451Sroberto            "Times: old=(%ld,%.6ld) new=(%ld,%.6ld) adjust=(%ld,%.6ld)\n",
89132451Sroberto            (long)old.tv_sec,(long)old.tv_usec,
90132451Sroberto            (long)new.tv_sec,(long)new.tv_usec,
91132451Sroberto            (long)adjust.tv_sec,(long)adjust.tv_usec);
92132451Sroberto    if (immediate) {
93132451Sroberto        errno = 0;
94182007Sroberto        if (settimeofday(&new,NULL))
95182007Sroberto            fatal(1,"unable to reset current system time",NULL);
96132451Sroberto    } else {
97182007Sroberto	previous.tv_sec  = 0;
98182007Sroberto	previous.tv_usec = 0;
99132451Sroberto        errno = 0;
100182007Sroberto        if (adjtime(&adjust,&previous))
101182007Sroberto            fatal(1,"unable to adjust current system time",NULL);
102132451Sroberto        if (previous.tv_sec != 0 || previous.tv_usec != 0) {
103132451Sroberto            sprintf(text,"(%ld,%.6ld)",
104132451Sroberto                (long)previous.tv_sec,(long)previous.tv_usec);
105132451Sroberto            if (previous.tv_sec+1.0e-6*previous.tv_usec > ignore)
106132451Sroberto                fatal(0,"outstanding time adjustment %s",text);
107132451Sroberto            else if (verbose)
108132451Sroberto                fprintf(stderr,"%s: outstanding time adjustment %s\n",
109132451Sroberto                    argv0,text);
110132451Sroberto        }
111132451Sroberto    }
112132451Sroberto}
113