Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4973 right-hear 1
#include 
2
#include 
3
#include 
4
#include 
5
#include 
6
#include 
7
#include 
8
#include 
9
#include 
10
#include 
11
#include "posixrul.h"
12
 
13
#define P(s)		s
14
#define alloc_size_t	size_t
15
#define qsort_size_t	size_t
16
#define fread_size_t	size_t
17
#define fwrite_size_t	size_t
18
 
19
#define ACCESS_MODE	O_RDONLY|O_BINARY
20
#define OPEN_MODE	O_RDONLY|O_BINARY
21
 
22
static char WILDABBR[] = "   ";
23
 
24
#ifndef TRUE
25
#define TRUE		1
26
#define FALSE		0
27
#endif /* !defined TRUE */
28
 
29
static const char GMT[] = "GMT";
30
 
31
struct ttinfo {		/* time type information */
32
  long tt_gmtoff;	/* GMT offset in seconds */
33
  int tt_isdst;		/* used to set tm_isdst */
34
  int tt_abbrind;	/* abbreviation list index */
35
  int tt_ttisstd;	/* TRUE if transition is std time */
36
};
37
 
38
struct lsinfo {		/* leap second information */
39
  time_t ls_trans;	/* transition time */
40
  long ls_corr;		/* correction to apply */
41
};
42
 
43
struct state {
44
  int leapcnt;
45
  int timecnt;
46
  int typecnt;
47
  int charcnt;
48
  time_t ats[TZ_MAX_TIMES];
49
  unsigned char types[TZ_MAX_TIMES];
50
  struct ttinfo ttis[TZ_MAX_TYPES];
51
  char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? TZ_MAX_CHARS + 1 : sizeof GMT];
52
  struct lsinfo lsis[TZ_MAX_LEAPS];
53
};
54
 
55
struct rule {
56
  int r_type;		/* type of rule--see below */
57
  int r_day;		/* day number of rule */
58
  int r_week;		/* week number of rule */
59
  int r_mon;		/* month number of rule */
60
  long r_time;		/* transition time of rule */
61
};
62
 
63
#define	JULIAN_DAY		0	/* Jn - Julian day */
64
#define	DAY_OF_YEAR		1	/* n - day of year */
65
#define	MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
66
 
67
/*
68
** Prototypes for static functions.
69
*/
70
 
71
static long		detzcode P((const char * codep));
72
static const char *	getzname P((const char * strp));
73
static const char *	getnum P((const char * strp, int * nump, int min,
74
				int max));
75
static const char *	getsecs P((const char * strp, long * secsp));
76
static const char *	getoffset P((const char * strp, long * offsetp));
77
static const char *	getrule P((const char * strp, struct rule * rulep));
78
static void		gmtload P((struct state * sp));
79
static void		gmtsub P((const time_t * timep, long offset,
80
				struct tm * tmp));
81
static void		localsub P((const time_t * timep, long offset,
82
				struct tm * tmp));
83
static void		normalize P((int * tensptr, int * unitsptr, int base));
84
static void		settzname P((void));
85
static time_t		time1 P((struct tm * tmp, void (* funcp)(const time_t * const, const long, struct tm * const),
86
				long offset));
87
static time_t		time2 P((struct tm *tmp, void (* funcp)(const time_t * const, const long, struct tm * const),
88
				long offset, int * okayp));
89
static void		timesub P((const time_t * timep, long offset,
90
				const struct state * sp, struct tm * tmp));
91
static int		tmcomp P((const struct tm * atmp,
92
				const struct tm * btmp));
93
static time_t		transtime P((time_t janfirst, int year,
94
				const struct rule * rulep, long offset));
95
static int		tzparse P((const char * name, struct state * sp,
96
				int lastditch));
97
//static void		tzsetwall(void);
98
 
99
#ifdef ALL_STATE
100
static struct state *lclptr;
101
static struct state *gmtptr;
102
#endif /* defined ALL_STATE */
103
 
104
#ifndef ALL_STATE
105
static struct state lclmem;
106
static struct state gmtmem;
107
#define lclptr (&lclmem)
108
#define gmtptr (&gmtmem)
109
#endif /* State Farm */
110
 
111
static int lcl_is_set;
112
static int gmt_is_set;
113
 
114
char * tzname[2] = {
115
  WILDABBR,
116
  WILDABBR
117
};
118
 
119
static long
120
detzcode(const char * const codep)
121
{
122
  long result;
123
  int i;
124
 
125
  result = 0;
126
  for (i = 0; i < 4; ++i)
127
    result = (result << 8) | (codep[i] & 0xff);
128
  return result;
129
}
130
 
131
static void
132
settzname(void)
133
{
134
  const struct state * const sp = lclptr;
135
  int i;
136
 
137
  tzname[0] = WILDABBR;
138
  tzname[1] = WILDABBR;
139
#ifdef ALL_STATE
140
  if (sp == NULL)
141
  {
142
    tzname[0] = tzname[1] = GMT;
143
    return;
144
  }
145
#endif /* defined ALL_STATE */
146
  for (i = 0; i < sp->typecnt; ++i)
147
  {
148
    register const struct ttinfo * const ttisp = &sp->ttis[i];
149
 
150
    tzname[ttisp->tt_isdst] =
151
      unconst(&sp->chars[ttisp->tt_abbrind], char *);
152
#if 0
153
    if (ttisp->tt_isdst)
154
      _daylight = 1;
155
    if (i == 0 || !ttisp->tt_isdst)
156
      _timezone = -(ttisp->tt_gmtoff);
157
    if (i == 0 || ttisp->tt_isdst)
158
      _altzone = -(ttisp->tt_gmtoff);
159
#endif
160
  }
161
  /*
162
   ** And to get the latest zone names into tzname. . .
163
   */
164
  for (i = 0; i < sp->timecnt; ++i)
165
  {
166
    const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]];
167
 
168
    tzname[ttisp->tt_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *);
169
  }
170
}
171
 
172
static const int mon_lengths[2][MONSPERYEAR] = {
173
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
174
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
175
};
176
 
177
static const int year_lengths[2] = {
178
DAYSPERNYEAR, DAYSPERLYEAR
179
};
180
 
181
/*
182
** Given a pointer into a time zone string, scan until a character that is not
183
** a valid character in a zone name is found.  Return a pointer to that
184
** character.
185
*/
186
 
187
static const char *
188
getzname(const char *strp)
189
{
190
  char c;
191
 
192
  while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
193
	 c != '+')
194
    ++strp;
195
  return strp;
196
}
197
 
198
/*
199
** Given a pointer into a time zone string, extract a number from that string.
200
** Check that the number is within a specified range; if it is not, return
201
** NULL.
202
** Otherwise, return a pointer to the first character not part of the number.
203
*/
204
 
205
static const char *
206
getnum(const char *strp, int * const nump, const int min, const int max)
207
{
208
  char c;
209
  int num;
210
 
211
  if (strp == NULL || !isdigit(*strp))
212
    return NULL;
213
  num = 0;
214
  while ((c = *strp) != '\0' && isdigit(c))
215
  {
216
    num = num * 10 + (c - '0');
217
    if (num > max)
218
      return NULL;
219
    ++strp;
220
  }
221
  if (num < min)
222
    return NULL;
223
  *nump = num;
224
  return strp;
225
}
226
 
227
/*
228
** Given a pointer into a time zone string, extract a number of seconds,
229
** in hh[:mm[:ss]] form, from the string.
230
** If any error occurs, return NULL.
231
** Otherwise, return a pointer to the first character not part of the number
232
** of seconds.
233
*/
234
 
235
static const char *
236
getsecs(const char *strp, long * const secsp)
237
{
238
  int num;
239
 
240
  strp = getnum(strp, &num, 0, HOURSPERDAY);
241
  if (strp == NULL)
242
    return NULL;
243
  *secsp = num * SECSPERHOUR;
244
  if (*strp == ':')
245
  {
246
    ++strp;
247
    strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
248
    if (strp == NULL)
249
      return NULL;
250
    *secsp += num * SECSPERMIN;
251
    if (*strp == ':')
252
    {
253
      ++strp;
254
      strp = getnum(strp, &num, 0, SECSPERMIN - 1);
255
      if (strp == NULL)
256
	return NULL;
257
      *secsp += num;
258
    }
259
  }
260
  return strp;
261
}
262
 
263
/*
264
** Given a pointer into a time zone string, extract an offset, in
265
** [+-]hh[:mm[:ss]] form, from the string.
266
** If any error occurs, return NULL.
267
** Otherwise, return a pointer to the first character not part of the time.
268
*/
269
 
270
static const char *
271
getoffset(const char *strp, long * const offsetp)
272
{
273
  int neg;
274
 
275
  if (*strp == '-')
276
  {
277
    neg = 1;
278
    ++strp;
279
  }
280
  else if (isdigit(*strp) || *strp++ == '+')
281
    neg = 0;
282
  else
283
    return NULL; /* illegal offset */
284
  strp = getsecs(strp, offsetp);
285
  if (strp == NULL)
286
    return NULL; /* illegal time */
287
  if (neg)
288
    *offsetp = -*offsetp;
289
  return strp;
290
}
291
 
292
/*
293
** Given a pointer into a time zone string, extract a rule in the form
294
** date[/time].  See POSIX section 8 for the format of "date" and "time".
295
** If a valid rule is not found, return NULL.
296
** Otherwise, return a pointer to the first character not part of the rule.
297
*/
298
 
299
static const char *
300
getrule(const char *strp, struct rule * const rulep)
301
{
302
  if (*strp == 'J')
303
  {
304
    /*
305
     ** Julian day.
306
     */
307
    rulep->r_type = JULIAN_DAY;
308
    ++strp;
309
    strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
310
  }
311
  else if (*strp == 'M')
312
  {
313
    /*
314
     ** Month, week, day.
315
     */
316
    rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
317
    ++strp;
318
    strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
319
    if (strp == NULL)
320
      return NULL;
321
    if (*strp++ != '.')
322
      return NULL;
323
    strp = getnum(strp, &rulep->r_week, 1, 5);
324
    if (strp == NULL)
325
      return NULL;
326
    if (*strp++ != '.')
327
      return NULL;
328
    strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
329
  }
330
  else if (isdigit(*strp))
331
  {
332
    /*
333
     ** Day of year.
334
     */
335
    rulep->r_type = DAY_OF_YEAR;
336
    strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
337
  }
338
  else
339
    return NULL;		/* invalid format */
340
  if (strp == NULL)
341
    return NULL;
342
  if (*strp == '/')
343
  {
344
    /*
345
     ** Time specified.
346
     */
347
    ++strp;
348
    strp = getsecs(strp, &rulep->r_time);
349
  }
350
  else
351
    rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
352
  return strp;
353
}
354
 
355
/*
356
** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
357
** year, a rule, and the offset from GMT at the time that rule takes effect,
358
** calculate the Epoch-relative time that rule takes effect.
359
*/
360
 
361
static time_t
362
transtime(const time_t janfirst, const int year, const struct rule * const rulep, const long offset)
363
{
364
  int leapyear;
365
  time_t value=0;
366
  int i;
367
  int d, m1, yy0, yy1, yy2, dow;
368
 
369
  leapyear = isleap(year);
370
  switch (rulep->r_type)
371
  {
372
 
373
  case JULIAN_DAY:
374
    /*
375
     ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
376
     ** years.
377
     ** In non-leap years, or if the day number is 59 or less, just
378
     ** add SECSPERDAY times the day number-1 to the time of
379
     ** January 1, midnight, to get the day.
380
     */
381
    value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
382
    if (leapyear && rulep->r_day >= 60)
383
      value += SECSPERDAY;
384
    break;
385
 
386
  case DAY_OF_YEAR:
387
    /*
388
     ** n - day of year.
389
     ** Just add SECSPERDAY times the day number to the time of
390
     ** January 1, midnight, to get the day.
391
     */
392
    value = janfirst + rulep->r_day * SECSPERDAY;
393
    break;
394
 
395
  case MONTH_NTH_DAY_OF_WEEK:
396
    /*
397
     ** Mm.n.d - nth "dth day" of month m.
398
     */
399
    value = janfirst;
400
    for (i = 0; i < rulep->r_mon - 1; ++i)
401
      value += mon_lengths[leapyear][i] * SECSPERDAY;
402
 
403
    /*
404
     ** Use Zeller's Congruence to get day-of-week of first day of
405
     ** month.
406
     */
407
    m1 = (rulep->r_mon + 9) % 12 + 1;
408
    yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
409
    yy1 = yy0 / 100;
410
    yy2 = yy0 % 100;
411
    dow = ((26 * m1 - 2) / 10 +
412
	   1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
413
    if (dow < 0)
414
      dow += DAYSPERWEEK;
415
 
416
    /*
417
     ** "dow" is the day-of-week of the first day of the month.  Get
418
     ** the day-of-month (zero-origin) of the first "dow" day of the
419
     ** month.
420
     */
421
    d = rulep->r_day - dow;
422
    if (d < 0)
423
      d += DAYSPERWEEK;
424
    for (i = 1; i < rulep->r_week; ++i)
425
    {
426
      if (d + DAYSPERWEEK >=
427
	  mon_lengths[leapyear][rulep->r_mon - 1])
428
	break;
429
      d += DAYSPERWEEK;
430
    }
431
 
432
    /*
433
     ** "d" is the day-of-month (zero-origin) of the day we want.
434
     */
435
    value += d * SECSPERDAY;
436
    break;
437
  }
438
 
439
  /*
440
   ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
441
   ** question.  To get the Epoch-relative time of the specified local
442
   ** time on that day, add the transition time and the current offset
443
   ** from GMT.
444
   */
445
  return value + rulep->r_time + offset;
446
}
447
 
448
/*
449
** Given a POSIX section 8-style TZ string, fill in the rule tables as
450
** appropriate.
451
*/
452
static int tzload (const char * name, struct state * sp)
453
{
454
 return -1;
455
}
456
 
457
static int
458
tzparse(const char *name, struct state * const sp, const int lastditch)
459
{
460
  const char * stdname;
461
  const char * dstname=0;
462
  int stdlen;
463
  int dstlen;
464
  long stdoffset;
465
  long dstoffset;
466
  time_t * atp;
467
  unsigned char * typep;
468
  char * cp;
469
  int load_result;
470
 
471
  stdname = name;
472
  if (lastditch)
473
  {
474
    stdlen = strlen(name);	/* length of standard zone name */
475
    name += stdlen;
476
    if (stdlen >= sizeof sp->chars)
477
      stdlen = (sizeof sp->chars) - 1;
478
  }
479
  else
480
  {
481
    name = getzname(name);
482
    stdlen = name - stdname;
483
    if (stdlen < 3)
484
      return -1;
485
  }
486
  if (*name == '\0')
487
    return -1;
488
  else
489
  {
490
    name = getoffset(name, &stdoffset);
491
    if (name == NULL)
492
      return -1;
493
  }
494
  load_result = tzload(TZDEFRULES, sp);
495
  if (load_result != 0)
496
    sp->leapcnt = 0;		/* so, we're off a little */
497
  if (*name != '\0')
498
  {
499
    dstname = name;
500
    name = getzname(name);
501
    dstlen = name - dstname;	/* length of DST zone name */
502
    if (dstlen < 3)
503
      return -1;
504
    if (*name != '\0' && *name != ',' && *name != ';')
505
    {
506
      name = getoffset(name, &dstoffset);
507
      if (name == NULL)
508
	return -1;
509
    }
510
    else
511
      dstoffset = stdoffset - SECSPERHOUR;
512
    if (*name == ',' || *name == ';')
513
    {
514
      struct rule start;
515
      struct rule end;
516
      int year;
517
      time_t janfirst;
518
      time_t starttime;
519
      time_t endtime;
520
 
521
      ++name;
522
      if ((name = getrule(name, &start)) == NULL)
523
	return -1;
524
      if (*name++ != ',')
525
	return -1;
526
      if ((name = getrule(name, &end)) == NULL)
527
	return -1;
528
      if (*name != '\0')
529
	return -1;
530
      sp->typecnt = 2;		/* standard time and DST */
531
      /*
532
       ** Two transitions per year, from EPOCH_YEAR to 2037.
533
       */
534
      sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
535
      if (sp->timecnt > TZ_MAX_TIMES)
536
	return -1;
537
      sp->ttis[0].tt_gmtoff = -dstoffset;
538
      sp->ttis[0].tt_isdst = 1;
539
      sp->ttis[0].tt_abbrind = stdlen + 1;
540
      sp->ttis[1].tt_gmtoff = -stdoffset;
541
      sp->ttis[1].tt_isdst = 0;
542
      sp->ttis[1].tt_abbrind = 0;
543
      atp = sp->ats;
544
      typep = sp->types;
545
      janfirst = 0;
546
      for (year = EPOCH_YEAR; year <= 2037; ++year)
547
      {
548
	starttime = transtime(janfirst, year, &start,
549
			      stdoffset);
550
	endtime = transtime(janfirst, year, &end,
551
			    dstoffset);
552
	if (starttime > endtime)
553
	{
554
	  *atp++ = endtime;
555
	  *typep++ = 1;		/* DST ends */
556
	  *atp++ = starttime;
557
	  *typep++ = 0;		/* DST begins */
558
	}
559
	else
560
	{
561
	  *atp++ = starttime;
562
	  *typep++ = 0;		/* DST begins */
563
	  *atp++ = endtime;
564
	  *typep++ = 1;		/* DST ends */
565
	}
566
	janfirst +=
567
	  year_lengths[isleap(year)] * SECSPERDAY;
568
      }
569
    }
570
    else
571
    {
572
      int sawstd;
573
      int sawdst;
574
      long stdfix;
575
      long dstfix;
576
      long oldfix;
577
      int isdst;
578
      int i;
579
 
580
      if (*name != '\0')
581
	return -1;
582
      if (load_result != 0)
583
	return -1;
584
      /*
585
       ** Compute the difference between the real and
586
       ** prototype standard and summer time offsets
587
       ** from GMT, and put the real standard and summer
588
       ** time offsets into the rules in place of the
589
       ** prototype offsets.
590
       */
591
      sawstd = FALSE;
592
      sawdst = FALSE;
593
      stdfix = 0;
594
      dstfix = 0;
595
      for (i = 0; i < sp->typecnt; ++i)
596
      {
597
	if (sp->ttis[i].tt_isdst)
598
	{
599
	  oldfix = dstfix;
600
	  dstfix =
601
	    sp->ttis[i].tt_gmtoff + dstoffset;
602
	  if (sawdst && (oldfix != dstfix))
603
	    return -1;
604
	  sp->ttis[i].tt_gmtoff = -dstoffset;
605
	  sp->ttis[i].tt_abbrind = stdlen + 1;
606
	  sawdst = TRUE;
607
	}
608
	else
609
	{
610
	  oldfix = stdfix;
611
	  stdfix =
612
	    sp->ttis[i].tt_gmtoff + stdoffset;
613
	  if (sawstd && (oldfix != stdfix))
614
	    return -1;
615
	  sp->ttis[i].tt_gmtoff = -stdoffset;
616
	  sp->ttis[i].tt_abbrind = 0;
617
	  sawstd = TRUE;
618
	}
619
      }
620
      /*
621
       ** Make sure we have both standard and summer time.
622
       */
623
      if (!sawdst || !sawstd)
624
	return -1;
625
      /*
626
       ** Now correct the transition times by shifting
627
       ** them by the difference between the real and
628
       ** prototype offsets.  Note that this difference
629
       ** can be different in standard and summer time;
630
       ** the prototype probably has a 1-hour difference
631
       ** between standard and summer time, but a different
632
       ** difference can be specified in TZ.
633
       */
634
      isdst = FALSE; /* we start in standard time */
635
      for (i = 0; i < sp->timecnt; ++i)
636
      {
637
	const struct ttinfo * ttisp;
638
 
639
	/*
640
	 ** If summer time is in effect, and the
641
	 ** transition time was not specified as
642
	 ** standard time, add the summer time
643
	 ** offset to the transition time;
644
	 ** otherwise, add the standard time offset
645
	 ** to the transition time.
646
	 */
647
	ttisp = &sp->ttis[sp->types[i]];
648
	sp->ats[i] +=
649
	  (isdst && !ttisp->tt_ttisstd) ?
650
	    dstfix : stdfix;
651
	isdst = ttisp->tt_isdst;
652
      }
653
    }
654
  }
655
  else
656
  {
657
    dstlen = 0;
658
    sp->typecnt = 1;		/* only standard time */
659
    sp->timecnt = 0;
660
    sp->ttis[0].tt_gmtoff = -stdoffset;
661
    sp->ttis[0].tt_isdst = 0;
662
    sp->ttis[0].tt_abbrind = 0;
663
  }
664
  sp->charcnt = stdlen + 1;
665
  if (dstlen != 0)
666
    sp->charcnt += dstlen + 1;
667
  if (sp->charcnt > sizeof sp->chars)
668
    return -1;
669
  cp = sp->chars;
670
  (void) strncpy(cp, stdname, stdlen);
671
  cp += stdlen;
672
  *cp++ = '\0';
673
  if (dstlen != 0)
674
  {
675
    (void) strncpy(cp, dstname, dstlen);
676
    *(cp + dstlen) = '\0';
677
  }
678
  return 0;
679
}
680
 
681
static void
682
gmtload(struct state * const sp)
683
{
684
  if (tzload(GMT, sp) != 0)
685
    (void) tzparse(GMT, sp, TRUE);
686
}
687
 
688
void
689
tzset(void)
690
{
691
  const char * name;
692
 
693
  name = getenv("TZ");
694
  if (name == NULL)
695
  {
696
    tzsetwall();
697
    return;
698
  }
699
  lcl_is_set = TRUE;
700
#ifdef ALL_STATE
701
  if (lclptr == NULL)
702
  {
703
    lclptr = (struct state *) malloc(sizeof *lclptr);
704
    if (lclptr == NULL)
705
    {
706
      settzname();		/* all we can do */
707
      return;
708
    }
709
  }
710
#endif /* defined ALL_STATE */
711
  if (*name == '\0')
712
  {
713
    /*
714
     ** User wants it fast rather than right.
715
     */
716
    lclptr->leapcnt = 0;	/* so, we're off a little */
717
    lclptr->timecnt = 0;
718
    lclptr->ttis[0].tt_gmtoff = 0;
719
    lclptr->ttis[0].tt_abbrind = 0;
720
    (void) strcpy(lclptr->chars, GMT);
721
  }
722
  else if (tzload(name, lclptr) != 0)
723
    if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
724
      gmtload(lclptr);
725
  settzname();
726
}
727
 
728
void
729
tzsetwall(void)
730
{
731
  lcl_is_set = TRUE;
732
#ifdef ALL_STATE
733
  if (lclptr == NULL)
734
  {
735
    lclptr = (struct state *) malloc(sizeof *lclptr);
736
    if (lclptr == NULL)
737
    {
738
      settzname();		/* all we can do */
739
      return;
740
    }
741
  }
742
#endif /* defined ALL_STATE */
743
  if (tzload((char *) NULL, lclptr) != 0)
744
    gmtload(lclptr);
745
  settzname();
746
}
747
 
748
/*
749
** The easy way to behave "as if no library function calls" localtime
750
** is to not call it--so we drop its guts into "localsub", which can be
751
** freely called.  (And no, the PANS doesn't require the above behavior--
752
** but it *is* desirable.)
753
**
754
** The unused offset argument is for the benefit of mktime variants.
755
*/
756
 
757
/*ARGSUSED*/
758
static void
759
localsub(const time_t * const timep, const long offset, struct tm * const tmp)
760
{
761
  const struct state * sp;
762
  const struct ttinfo * ttisp;
763
  int i;
764
  const time_t t = *timep;
765
 
766
  if (!lcl_is_set)
767
    tzset();
768
  sp = lclptr;
769
#ifdef ALL_STATE
770
  if (sp == NULL)
771
  {
772
    gmtsub(timep, offset, tmp);
773
    return;
774
  }
775
#endif /* defined ALL_STATE */
776
  if (sp->timecnt == 0 || t < sp->ats[0])
777
  {
778
    i = 0;
779
    while (sp->ttis[i].tt_isdst)
780
      if (++i >= sp->typecnt)
781
      {
782
	i = 0;
783
	break;
784
      }
785
  }
786
  else
787
  {
788
    for (i = 1; i < sp->timecnt; ++i)
789
      if (t < sp->ats[i])
790
	break;
791
    i = sp->types[i - 1];
792
  }
793
  ttisp = &sp->ttis[i];
794
  /*
795
   ** To get (wrong) behavior that's compatible with System V Release 2.0
796
   ** you'd replace the statement below with
797
   ** t += ttisp->tt_gmtoff;
798
   ** timesub(&t, 0L, sp, tmp);
799
   */
800
  timesub(&t, ttisp->tt_gmtoff, sp, tmp);
801
  tmp->tm_isdst = ttisp->tt_isdst;
802
  tzname[tmp->tm_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *);
803
  tmp->tm_zone = unconst(&sp->chars[ttisp->tt_abbrind], char *);
804
}
805
 
806
struct tm *
807
localtime(const time_t * const timep)
808
{
809
  static struct tm tm;
810
 
811
  localsub(timep, 0L, &tm);
812
  return &tm;
813
}
814
 
815
/*
816
** gmtsub is to gmtime as localsub is to localtime.
817
*/
818
 
819
static void
820
gmtsub(const time_t * const timep, const long offset, struct tm * const tmp)
821
{
822
  if (!gmt_is_set)
823
  {
824
    gmt_is_set = TRUE;
825
#ifdef ALL_STATE
826
    gmtptr = (struct state *) malloc(sizeof *gmtptr);
827
    if (gmtptr != NULL)
828
#endif /* defined ALL_STATE */
829
      gmtload(gmtptr);
830
  }
831
  timesub(timep, offset, gmtptr, tmp);
832
  /*
833
   ** Could get fancy here and deliver something such as
834
   ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
835
   ** but this is no time for a treasure hunt.
836
   */
837
  if (offset != 0)
838
    tmp->tm_zone = WILDABBR;
839
  else
840
  {
841
#ifdef ALL_STATE
842
    if (gmtptr == NULL)
843
      tmp->TM_ZONE = GMT;
844
    else
845
      tmp->TM_ZONE = gmtptr->chars;
846
#endif /* defined ALL_STATE */
847
#ifndef ALL_STATE
848
    tmp->tm_zone = gmtptr->chars;
849
#endif /* State Farm */
850
  }
851
}
852
 
853
struct tm *
854
gmtime(const time_t * const timep)
855
{
856
  static struct tm tm;
857
 
858
  gmtsub(timep, 0L, &tm);
859
  return &tm;
860
}
861
 
862
static void
863
timesub(const time_t * const timep, const long offset, const struct state * const sp, struct tm * const tmp)
864
{
865
  const struct lsinfo * lp;
866
  long days;
867
  long rem;
868
  int y;
869
  int yleap;
870
  const int * ip;
871
  long corr;
872
  int hit;
873
  int i;
874
 
875
  corr = 0;
876
  hit = FALSE;
877
#ifdef ALL_STATE
878
  i = (sp == NULL) ? 0 : sp->leapcnt;
879
#endif /* defined ALL_STATE */
880
#ifndef ALL_STATE
881
  i = sp->leapcnt;
882
#endif /* State Farm */
883
  while (--i >= 0)
884
  {
885
    lp = &sp->lsis[i];
886
    if (*timep >= lp->ls_trans)
887
    {
888
      if (*timep == lp->ls_trans)
889
	hit = ((i == 0 && lp->ls_corr > 0) ||
890
	       lp->ls_corr > sp->lsis[i - 1].ls_corr);
891
      corr = lp->ls_corr;
892
      break;
893
    }
894
  }
895
  days = *timep / SECSPERDAY;
896
  rem = *timep % SECSPERDAY;
897
#ifdef mc68k
898
  if (*timep == 0x80000000)
899
  {
900
    /*
901
     ** A 3B1 muffs the division on the most negative number.
902
     */
903
    days = -24855;
904
    rem = -11648;
905
  }
906
#endif /* mc68k */
907
  rem += (offset - corr);
908
  while (rem < 0)
909
  {
910
    rem += SECSPERDAY;
911
    --days;
912
  }
913
  while (rem >= SECSPERDAY)
914
  {
915
    rem -= SECSPERDAY;
916
    ++days;
917
  }
918
  tmp->tm_hour = (int) (rem / SECSPERHOUR);
919
  rem = rem % SECSPERHOUR;
920
  tmp->tm_min = (int) (rem / SECSPERMIN);
921
  tmp->tm_sec = (int) (rem % SECSPERMIN);
922
  if (hit)
923
    /*
924
     ** A positive leap second requires a special
925
     ** representation.  This uses "... ??:59:60".
926
     */
927
    ++(tmp->tm_sec);
928
  tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
929
  if (tmp->tm_wday < 0)
930
    tmp->tm_wday += DAYSPERWEEK;
931
  y = EPOCH_YEAR;
932
  if (days >= 0)
933
    for ( ; ; )
934
    {
935
      yleap = isleap(y);
936
      if (days < (long) year_lengths[yleap])
937
	break;
938
      ++y;
939
      days = days - (long) year_lengths[yleap];
940
    }
941
  else
942
    do {
943
    --y;
944
    yleap = isleap(y);
945
    days = days + (long) year_lengths[yleap];
946
  } while (days < 0);
947
  tmp->tm_year = y - TM_YEAR_BASE;
948
  tmp->tm_yday = (int) days;
949
  ip = mon_lengths[yleap];
950
  for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
951
    days = days - (long) ip[tmp->tm_mon];
952
  tmp->tm_mday = (int) (days + 1);
953
  tmp->tm_isdst = 0;
954
  tmp->tm_gmtoff = offset;
955
}
956
 
957
/*
958
** A la X3J11
959
*/
960
 
961
char *
962
asctime(const struct tm *timeptr)
963
{
964
  static const char wday_name[DAYSPERWEEK][3] = {
965
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
966
  };
967
  static const char mon_name[MONSPERYEAR][3] = {
968
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
969
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
970
  };
971
  static char result[26];
972
 
973
  (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
974
		 wday_name[timeptr->tm_wday],
975
		 mon_name[timeptr->tm_mon],
976
		 timeptr->tm_mday, timeptr->tm_hour,
977
		 timeptr->tm_min, timeptr->tm_sec,
978
		 TM_YEAR_BASE + timeptr->tm_year);
979
  return result;
980
}
981
 
982
char *
983
ctime(const time_t * const timep)
984
{
985
  return asctime(localtime(timep));
986
}
987
 
988
/*
989
** Adapted from code provided by Robert Elz, who writes:
990
**	The "best" way to do mktime I think is based on an idea of Bob
991
**	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
992
**	It does a binary search of the time_t space.  Since time_t's are
993
**	just 32 bits, its a max of 32 iterations (even at 64 bits it
994
**	would still be very reasonable).
995
*/
996
 
997
#ifndef WRONG
998
#define WRONG	(-1)
999
#endif /* !defined WRONG */
1000
 
1001
static void
1002
normalize(int * const tensptr, int * const unitsptr, const int base)
1003
{
1004
  if (*unitsptr >= base)
1005
  {
1006
    *tensptr += *unitsptr / base;
1007
    *unitsptr %= base;
1008
  }
1009
  else if (*unitsptr < 0)
1010
  {
1011
    --*tensptr;
1012
    *unitsptr += base;
1013
    if (*unitsptr < 0)
1014
    {
1015
      *tensptr -= 1 + (-*unitsptr) / base;
1016
      *unitsptr = base - (-*unitsptr) % base;
1017
    }
1018
  }
1019
}
1020
 
1021
static int
1022
tmcomp(const struct tm * const atmp, const struct tm * const btmp)
1023
{
1024
  int result;
1025
 
1026
  if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1027
      (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1028
      (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1029
      (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1030
      (result = (atmp->tm_min - btmp->tm_min)) == 0)
1031
    result = atmp->tm_sec - btmp->tm_sec;
1032
  return result;
1033
}
1034
 
1035
static time_t
1036
time2(struct tm *tmp, void (*const funcp)(const time_t *const,const long,struct tm *), const long offset, int * const okayp)
1037
{
1038
  const struct state * sp;
1039
  int dir;
1040
  int bits;
1041
  int i, j ;
1042
  int saved_seconds;
1043
  time_t newt;
1044
  time_t t;
1045
  struct tm yourtm, mytm;
1046
 
1047
  *okayp = FALSE;
1048
  yourtm = *tmp;
1049
  if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
1050
    normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
1051
  normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
1052
  normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
1053
  normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
1054
  while (yourtm.tm_mday <= 0)
1055
  {
1056
    --yourtm.tm_year;
1057
    yourtm.tm_mday +=
1058
      year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1059
  }
1060
  for ( ; ; )
1061
  {
1062
    i = mon_lengths[isleap(yourtm.tm_year +
1063
			   TM_YEAR_BASE)][yourtm.tm_mon];
1064
    if (yourtm.tm_mday <= i)
1065
      break;
1066
    yourtm.tm_mday -= i;
1067
    if (++yourtm.tm_mon >= MONSPERYEAR)
1068
    {
1069
      yourtm.tm_mon = 0;
1070
      ++yourtm.tm_year;
1071
    }
1072
  }
1073
  saved_seconds = yourtm.tm_sec;
1074
  yourtm.tm_sec = 0;
1075
  /*
1076
   ** Calculate the number of magnitude bits in a time_t
1077
   ** (this works regardless of whether time_t is
1078
   ** signed or unsigned, though lint complains if unsigned).
1079
   */
1080
  for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1081
    ;
1082
  /*
1083
   ** If time_t is signed, then 0 is the median value,
1084
   ** if time_t is unsigned, then 1 << bits is median.
1085
   */
1086
  t = (time_t) 1 << bits;
1087
  for ( ; ; )
1088
  {
1089
    (*funcp)(&t, offset, &mytm);
1090
    dir = tmcomp(&mytm, &yourtm);
1091
    if (dir != 0)
1092
    {
1093
      if (bits-- < 0)
1094
	return WRONG;
1095
      if (bits < 0)
1096
	--t;
1097
      else if (dir > 0)
1098
	t -= (time_t) 1 << bits;
1099
      else t += (time_t) 1 << bits;
1100
      continue;
1101
    }
1102
    if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1103
      break;
1104
    /*
1105
     ** Right time, wrong type.
1106
     ** Hunt for right time, right type.
1107
     ** It's okay to guess wrong since the guess
1108
     ** gets checked.
1109
     */
1110
    sp = (const struct state *)
1111
      ((funcp == localsub) ? lclptr : gmtptr);
1112
#ifdef ALL_STATE
1113
    if (sp == NULL)
1114
      return WRONG;
1115
#endif /* defined ALL_STATE */
1116
    for (i = 0; i < sp->typecnt; ++i)
1117
    {
1118
      if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1119
	continue;
1120
      for (j = 0; j < sp->typecnt; ++j)
1121
      {
1122
	if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1123
	  continue;
1124
	newt = t + sp->ttis[j].tt_gmtoff -
1125
	  sp->ttis[i].tt_gmtoff;
1126
	(*funcp)(&newt, offset, &mytm);
1127
	if (tmcomp(&mytm, &yourtm) != 0)
1128
	  continue;
1129
	if (mytm.tm_isdst != yourtm.tm_isdst)
1130
	  continue;
1131
	/*
1132
	 ** We have a match.
1133
	 */
1134
	t = newt;
1135
	goto label;
1136
      }
1137
    }
1138
    return WRONG;
1139
  }
1140
 label:
1141
  t += saved_seconds;
1142
  (*funcp)(&t, offset, tmp);
1143
  *okayp = TRUE;
1144
  return t;
1145
}
1146
 
1147
static time_t
1148
time1(struct tm * const tmp, void (*const funcp)(const time_t * const, const long, struct tm *), const long offset)
1149
{
1150
  time_t t;
1151
  const struct state * sp;
1152
  int samei, otheri;
1153
  int okay;
1154
 
1155
  if (tmp->tm_isdst > 1)
1156
    tmp->tm_isdst = 1;
1157
  t = time2(tmp, funcp, offset, &okay);
1158
  if (okay || tmp->tm_isdst < 0)
1159
    return t;
1160
  /*
1161
   ** We're supposed to assume that somebody took a time of one type
1162
   ** and did some math on it that yielded a "struct tm" that's bad.
1163
   ** We try to divine the type they started from and adjust to the
1164
   ** type they need.
1165
   */
1166
  sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
1167
#ifdef ALL_STATE
1168
  if (sp == NULL)
1169
    return WRONG;
1170
#endif /* defined ALL_STATE */
1171
  for (samei = 0; samei < sp->typecnt; ++samei)
1172
  {
1173
    if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1174
      continue;
1175
    for (otheri = 0; otheri < sp->typecnt; ++otheri)
1176
    {
1177
      if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1178
	continue;
1179
      tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1180
	sp->ttis[samei].tt_gmtoff;
1181
      tmp->tm_isdst = !tmp->tm_isdst;
1182
      t = time2(tmp, funcp, offset, &okay);
1183
      if (okay)
1184
	return t;
1185
      tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1186
	sp->ttis[samei].tt_gmtoff;
1187
      tmp->tm_isdst = !tmp->tm_isdst;
1188
    }
1189
  }
1190
  return WRONG;
1191
}
1192
 
1193
time_t
1194
mktime(struct tm * tmp)
1195
{
1196
  return time1(tmp, localsub, 0L);
1197
}