Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/ape/cmd/patch/maketime.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Convert struct partime into time_t.  */
2
 
3
/* Copyright 1992, 1993, 1994, 1995, 1997 Paul Eggert
4
   Distributed under license by the Free Software Foundation, Inc.
5
 
6
   This file is part of RCS.
7
 
8
   RCS is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 2, or (at your option)
11
   any later version.
12
 
13
   RCS is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with RCS; see the file COPYING.
20
   If not, write to the Free Software Foundation,
21
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
 
23
   Report problems and direct all questions to:
24
 
25
	rcs-bugs@cs.purdue.edu
26
 
27
 */
28
 
29
#if has_conf_h
30
# include <conf.h>
31
#else
32
# if HAVE_CONFIG_H
33
#  include <config.h>
34
# else
35
#  ifndef __STDC__
36
#   define const
37
#  endif
38
# endif
39
  /* MIPS RISCOS4.52 defines time_t in <sys/types.h> not <time.h>.  */
40
# include <sys/types.h>
41
# if HAVE_LIMITS_H
42
#  include <limits.h>
43
# endif
44
# ifndef LONG_MIN
45
# define LONG_MIN (-1-2147483647L)
46
# endif
47
# if STDC_HEADERS
48
#  include <stdlib.h>
49
# endif
50
# include <time.h>
51
# ifdef __STDC__
52
#  define P(x) x
53
# else
54
#  define P(x) ()
55
# endif
56
#endif
57
 
58
#include <partime.h>
59
#include <maketime.h>
60
 
61
char const maketId[] =
62
  "$Id: maketime.c,v 5.15 1997/06/17 16:54:36 eggert Exp $";
63
 
64
static int isleap P ((int));
65
static int month_days P ((struct tm const *));
66
static time_t maketime P ((struct partime const *, time_t));
67
 
68
/* For maximum portability, use only localtime and gmtime.
69
   Make no assumptions about the time_t epoch or the range of time_t values.
70
   Avoid mktime because it's not universal and because there's no easy,
71
   portable way for mktime to yield the inverse of gmtime.  */
72
 
73
#define TM_YEAR_ORIGIN 1900
74
 
75
static int
76
isleap (y)
77
     int y;
78
{
79
  return (y & 3) == 0 && (y % 100 != 0 || y % 400 == 0);
80
}
81
 
82
/* days in year before start of months 0-12 */
83
static int const month_yday[] =
84
{
85
  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
86
};
87
 
88
/* Yield the number of days in TM's month.  */
89
static int
90
month_days (tm)
91
     struct tm const *tm;
92
{
93
  int m = tm->tm_mon;
94
  return (month_yday[m + 1] - month_yday[m]
95
	  + (m == 1 && isleap (tm->tm_year + TM_YEAR_ORIGIN)));
96
}
97
 
98
/* Convert UNIXTIME to struct tm form.
99
   Use gmtime if available and if !LOCALZONE, localtime otherwise.  */
100
struct tm *
101
time2tm (unixtime, localzone)
102
     time_t unixtime;
103
     int localzone;
104
{
105
  struct tm *tm;
106
#ifdef TZ_is_unset
107
  static char const *TZ;
108
  if (!TZ && !(TZ = getenv ("TZ")))
109
    TZ_is_unset ("The TZ environment variable is not set; please set it to your timezone");
110
#endif
111
  if (localzone || !(tm = gmtime (&unixtime)))
112
    tm = localtime (&unixtime);
113
  return tm;
114
}
115
 
116
/* Yield A - B, measured in seconds.  */
117
time_t
118
difftm (a, b)
119
     struct tm const *a;
120
     struct tm const *b;
121
{
122
  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
123
  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
124
  int ac = ay / 100 - (ay % 100 < 0);
125
  int bc = by / 100 - (by % 100 < 0);
126
  int difference_in_day_of_year = a->tm_yday - b->tm_yday;
127
  int intervening_leap_days = (((ay >> 2) - (by >> 2))
128
			       - (ac - bc)
129
			       + ((ac >> 2) - (bc >> 2)));
130
  time_t difference_in_years = ay - by;
131
  time_t difference_in_days
132
    = (difference_in_years * 365
133
       + (intervening_leap_days + difference_in_day_of_year));
134
  return (((((difference_in_days * 24
135
	      + (a->tm_hour - b->tm_hour))
136
	     * 60)
137
	    + (a->tm_min - b->tm_min))
138
	   * 60)
139
	  + (a->tm_sec - b->tm_sec));
140
}
141
 
142
/*
143
   * Adjust time T by adding SECONDS.  SECONDS must be at most 24 hours' worth.
144
   * Adjust only T's year, mon, mday, hour, min and sec members;
145
   * plus adjust wday if it is defined.
146
 */
147
void
148
adjzone (t, seconds)
149
     register struct tm *t;
150
     long seconds;
151
{
152
  /*
153
     * This code can be off by a second if SECONDS is not a multiple of 60,
154
     * if T is local time, and if a leap second happens during this minute.
155
     * But this bug has never occurred, and most likely will not ever occur.
156
     * Liberia, the last country for which SECONDS % 60 was nonzero,
157
     * switched to UTC in May 1972; the first leap second was in June 1972.
158
   */
159
  int leap_second = t->tm_sec == 60;
160
  long sec = seconds + (t->tm_sec - leap_second);
161
  if (sec < 0)
162
    {
163
      if ((t->tm_min -= (59 - sec) / 60) < 0)
164
	{
165
	  if ((t->tm_hour -= (59 - t->tm_min) / 60) < 0)
166
	    {
167
	      t->tm_hour += 24;
168
	      if (TM_DEFINED (t->tm_wday) && --t->tm_wday < 0)
169
		t->tm_wday = 6;
170
	      if (--t->tm_mday <= 0)
171
		{
172
		  if (--t->tm_mon < 0)
173
		    {
174
		      --t->tm_year;
175
		      t->tm_mon = 11;
176
		    }
177
		  t->tm_mday = month_days (t);
178
		}
179
	    }
180
	  t->tm_min += 24 * 60;
181
	}
182
      sec += 24L * 60 * 60;
183
    }
184
  else if (60 <= (t->tm_min += sec / 60))
185
    if (24 <= (t->tm_hour += t->tm_min / 60))
186
      {
187
	t->tm_hour -= 24;
188
	if (TM_DEFINED (t->tm_wday) && ++t->tm_wday == 7)
189
	  t->tm_wday = 0;
190
	if (month_days (t) < ++t->tm_mday)
191
	  {
192
	    if (11 < ++t->tm_mon)
193
	      {
194
		++t->tm_year;
195
		t->tm_mon = 0;
196
	      }
197
	    t->tm_mday = 1;
198
	  }
199
      }
200
  t->tm_min %= 60;
201
  t->tm_sec = (int) (sec % 60) + leap_second;
202
}
203
 
204
/*
205
   * Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
206
   * Use only TM's year, mon, mday, hour, min, and sec members.
207
   * Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
208
   * Yield -1 on failure (e.g. a member out of range).
209
   * Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
210
   * have them anyway, so allow them if localtime/gmtime does.
211
 */
212
time_t
213
tm2time (tm, localzone)
214
     struct tm *tm;
215
     int localzone;
216
{
217
  /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime.  */
218
  static time_t t_cache[2];
219
  static struct tm tm_cache[2];
220
 
221
  time_t d, gt;
222
  struct tm const *gtm;
223
  /*
224
     * The maximum number of iterations should be enough to handle any
225
     * combinations of leap seconds, time zone rule changes, and solar time.
226
     * 4 is probably enough; we use a bigger number just to be safe.
227
   */
228
  int remaining_tries = 8;
229
 
230
  /* Avoid subscript errors.  */
231
  if (12 <= (unsigned) tm->tm_mon)
232
    return -1;
233
 
234
  tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
235
    - (tm->tm_mon < 2 || !isleap (tm->tm_year + TM_YEAR_ORIGIN));
236
 
237
  /* Make a first guess.  */
238
  gt = t_cache[localzone];
239
  gtm = gt ? &tm_cache[localzone] : time2tm (gt, localzone);
240
 
241
  /* Repeatedly use the error from the guess to improve the guess.  */
242
  while ((d = difftm (tm, gtm)) != 0)
243
    {
244
      if (--remaining_tries == 0)
245
	return -1;
246
      gt += d;
247
      gtm = time2tm (gt, localzone);
248
    }
249
 
250
  /*
251
     * Check that the guess actually matches;
252
     * overflow can cause difftm to yield 0 even on differing times,
253
     * or tm may have members out of range (e.g. bad leap seconds).
254
   */
255
#define TM_DIFFER(a,b) \
256
		( \
257
			((a)->tm_year ^ (b)->tm_year) | \
258
			((a)->tm_mon ^ (b)->tm_mon) | \
259
			((a)->tm_mday ^ (b)->tm_mday) | \
260
			((a)->tm_hour ^ (b)->tm_hour) | \
261
			((a)->tm_min ^ (b)->tm_min) | \
262
			((a)->tm_sec ^ (b)->tm_sec) \
263
		)
264
  if (TM_DIFFER (tm, gtm))
265
    {
266
      /*
267
         * If gt is a leap second, try gt+1; if it is one greater than
268
         * a leap second, try gt-1; otherwise, it doesn't matter.
269
         * Leap seconds always fall at month end.
270
       */
271
      int yd = tm->tm_year - gtm->tm_year;
272
      gt += yd + (yd ? 0 : tm->tm_mon - gtm->tm_mon);
273
      gtm = time2tm (gt, localzone);
274
      if (TM_DIFFER (tm, gtm))
275
	return -1;
276
    }
277
  t_cache[localzone] = gt;
278
  tm_cache[localzone] = *gtm;
279
 
280
  tm->tm_wday = gtm->tm_wday;
281
  return gt;
282
}
283
 
284
/*
285
   * Check *PT and convert it to time_t.
286
   * If it is incompletely specified, use DEFAULT_TIME to fill it out.
287
   * Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
288
   * Yield -1 on failure.
289
   * ISO 8601 day-of-year and week numbers are not yet supported.
290
 */
291
static time_t
292
maketime (pt, default_time)
293
     struct partime const *pt;
294
     time_t default_time;
295
{
296
  int localzone, wday;
297
  struct tm tm;
298
  struct tm *tm0 = 0;
299
  time_t r;
300
 
301
  tm0 = 0;			/* Keep gcc -Wall happy.  */
302
  localzone = pt->zone == TM_LOCAL_ZONE;
303
 
304
  tm = pt->tm;
305
 
306
  if (TM_DEFINED (pt->ymodulus) || !TM_DEFINED (tm.tm_year))
307
    {
308
      /* Get tm corresponding to default time.  */
309
      tm0 = time2tm (default_time, localzone);
310
      if (!localzone)
311
	adjzone (tm0, pt->zone);
312
    }
313
 
314
  if (TM_DEFINED (pt->ymodulus))
315
    tm.tm_year +=
316
      (tm0->tm_year + TM_YEAR_ORIGIN) / pt->ymodulus * pt->ymodulus;
317
  else if (!TM_DEFINED (tm.tm_year))
318
    {
319
      /* Set default year, month, day from current time.  */
320
      tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
321
      if (!TM_DEFINED (tm.tm_mon))
322
	{
323
	  tm.tm_mon = tm0->tm_mon;
324
	  if (!TM_DEFINED (tm.tm_mday))
325
	    tm.tm_mday = tm0->tm_mday;
326
	}
327
    }
328
 
329
  /* Convert from partime year (Gregorian) to Posix year.  */
330
  tm.tm_year -= TM_YEAR_ORIGIN;
331
 
332
  /* Set remaining default fields to be their minimum values.  */
333
  if (!TM_DEFINED (tm.tm_mon))
334
    tm.tm_mon = 0;
335
  if (!TM_DEFINED (tm.tm_mday))
336
    tm.tm_mday = 1;
337
  if (!TM_DEFINED (tm.tm_hour))
338
    tm.tm_hour = 0;
339
  if (!TM_DEFINED (tm.tm_min))
340
    tm.tm_min = 0;
341
  if (!TM_DEFINED (tm.tm_sec))
342
    tm.tm_sec = 0;
343
 
344
  if (!localzone)
345
    adjzone (&tm, -pt->zone);
346
  wday = tm.tm_wday;
347
 
348
  /* Convert and fill in the rest of the tm.  */
349
  r = tm2time (&tm, localzone);
350
 
351
  /* Check weekday.  */
352
  if (r != -1 && TM_DEFINED (wday) && wday != tm.tm_wday)
353
    return -1;
354
 
355
  return r;
356
}
357
 
358
/* Parse a free-format date in SOURCE, yielding a Unix format time.  */
359
time_t
360
str2time (source, default_time, default_zone)
361
     char const *source;
362
     time_t default_time;
363
     long default_zone;
364
{
365
  struct partime pt;
366
 
367
  if (*partime (source, &pt))
368
    return -1;
369
  if (pt.zone == TM_UNDEFINED_ZONE)
370
    pt.zone = default_zone;
371
  return maketime (&pt, default_time);
372
}
373
 
374
#if TEST
375
#include <stdio.h>
376
int
377
main (argc, argv)
378
     int argc;
379
     char **argv;
380
{
381
  time_t default_time = time ((time_t *) 0);
382
  long default_zone = argv[1] ? atol (argv[1]) : 0;
383
  char buf[1000];
384
  while (fgets (buf, sizeof (buf), stdin))
385
    {
386
      time_t t = str2time (buf, default_time, default_zone);
387
      printf ("%s", asctime (gmtime (&t)));
388
    }
389
  return 0;
390
}
391
#endif