misc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /*
  2. * misc - data and miscellaneous routines
  3. */
  4. /* $Id$ */
  5. #include <ctype.h>
  6. #include <time.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #if defined(__BSD4_2)
  10. extern int _gettimeofday(struct timeval *tp, struct timezone *tzp);
  11. #elif !defined(_POSIX_SOURCE) && !defined(__USG)
  12. #if !defined(_MINIX) /* MINIX has no ftime() */
  13. struct timeb {
  14. long time;
  15. unsigned short millitm;
  16. short timezone;
  17. short dstflag;
  18. };
  19. void _ftime(struct timeb *bp);
  20. #endif
  21. #endif
  22. #include "loc_time.h"
  23. #define RULE_LEN 120
  24. #define TZ_LEN 10
  25. /* Make sure that the strings do not end up in ROM.
  26. * These strings probably contain the wrong value, and we cannot obtain the
  27. * right value from the system. TZ is the only help.
  28. */
  29. static char ntstr[TZ_LEN + 1] = "GMT"; /* string for normal time */
  30. static char dststr[TZ_LEN + 1] = "GDT"; /* string for daylight saving */
  31. long _timezone = 0;
  32. long _dst_off = 60 * 60;
  33. int _daylight = 0;
  34. char *_tzname[2] = {ntstr, dststr};
  35. #if defined(__USG) || defined(_POSIX_SOURCE)
  36. char *tzname[2] = {ntstr, dststr};
  37. #if defined(__USG)
  38. long timezone = 0;
  39. int daylight = 0;
  40. #endif
  41. #endif
  42. static struct dsttype {
  43. char ds_type; /* Unknown, Julian, Zero-based or M */
  44. int ds_date[3]; /* months, weeks, days */
  45. long ds_sec; /* usually 02:00:00 */
  46. } dststart = { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
  47. , dstend = { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
  48. const char *_days[] = {
  49. "Sunday", "Monday", "Tuesday", "Wednesday",
  50. "Thursday", "Friday", "Saturday"
  51. };
  52. const char *_months[] = {
  53. "January", "February", "March",
  54. "April", "May", "June",
  55. "July", "August", "September",
  56. "October", "November", "December"
  57. };
  58. const int _ytab[2][12] = {
  59. { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  60. { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  61. };
  62. #if !defined(_POSIX_SOURCE) && !defined(__USG)
  63. #define USE_TABLE 1
  64. #endif
  65. #if USE_TABLE
  66. static int usetable = 1;
  67. typedef struct table {
  68. const char *tz_name;
  69. const int daylight;
  70. const long zoneoffset;
  71. } TABLE;
  72. #define HOUR(x) ((x) * 60*60)
  73. static TABLE TimezoneTable[] = {
  74. {"GMT", 0, HOUR(0) }, /* Greenwich Mean */
  75. {"BST", 60*60, HOUR(0) }, /* British Summer */
  76. {"WAT", 0, HOUR(1) }, /* West Africa */
  77. {"AT", 0, HOUR(2) }, /* Azores */
  78. {"BST", 0, HOUR(3) }, /* Brazil Standard */
  79. {"NFT", 0, HOUR(3.5) }, /* Newfoundland */
  80. {"NDT", 60*60, HOUR(3.5) }, /* Newfoundland Daylight */
  81. {"AST", 0, HOUR(4) }, /* Atlantic Standard */
  82. {"ADT", 60*60, HOUR(4) }, /* Atlantic Daylight */
  83. {"EST", 0, HOUR(5) }, /* Eastern Standard */
  84. {"EDT", 60*60, HOUR(5) }, /* Eastern Daylight */
  85. {"CST", 0, HOUR(6) }, /* Central Standard */
  86. {"CDT", 60*60, HOUR(6) }, /* Central Daylight */
  87. {"MST", 0, HOUR(7) }, /* Mountain Standard */
  88. {"MDT", 60*60, HOUR(7) }, /* Mountain Daylight */
  89. {"PST", 0, HOUR(8) }, /* Pacific Standard */
  90. {"PDT", 60*60, HOUR(8) }, /* Pacific Daylight */
  91. {"YST", 0, HOUR(9) }, /* Yukon Standard */
  92. {"YDT", 60*60, HOUR(9) }, /* Yukon Daylight */
  93. {"HST", 0, HOUR(10) }, /* Hawaii Standard */
  94. {"HDT", 60*60, HOUR(10) }, /* Hawaii Daylight */
  95. {"NT", 0, HOUR(11) }, /* Nome */
  96. {"IDLW", 0, HOUR(12) }, /* International Date Line West */
  97. {"MET", 0, -HOUR(1) }, /* Middle European */
  98. {"MDT", 60*60, -HOUR(1) }, /* Middle European Summer */
  99. {"EET", 0, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
  100. {"BT", 0, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
  101. {"IT", 0, -HOUR(3.5) }, /* Iran */
  102. {"ZP4", 0, -HOUR(4) }, /* USSR Zone 3 */
  103. {"ZP5", 0, -HOUR(5) }, /* USSR Zone 4 */
  104. {"IST", 0, -HOUR(5.5) }, /* Indian Standard */
  105. {"ZP6", 0, -HOUR(6) }, /* USSR Zone 5 */
  106. {"NST", 0, -HOUR(6.5) }, /* North Sumatra */
  107. {"SST", 0, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
  108. {"WAST", 0, -HOUR(7) }, /* West Australian Standard */
  109. {"WADT", 60*60, -HOUR(7) }, /* West Australian Daylight */
  110. {"JT", 0, -HOUR(7.5) }, /* Java (3pm in Cronusland!) */
  111. {"CCT", 0, -HOUR(8) }, /* China Coast, USSR Zone 7 */
  112. {"JST", 0, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
  113. {"CAST", 0, -HOUR(9.5) }, /* Central Australian Standard */
  114. {"CADT", 60*60, -HOUR(9.5) }, /* Central Australian Daylight */
  115. {"EAST", 0, -HOUR(10) }, /* Eastern Australian Standard */
  116. {"EADT", 60*60, -HOUR(10) }, /* Eastern Australian Daylight */
  117. {"NZT", 0, -HOUR(12) }, /* New Zealand */
  118. {"NZDT", 60*60, -HOUR(12) }, /* New Zealand Daylight */
  119. { NULL, 0, 0 }
  120. };
  121. /*
  122. * The function ZoneFromTable() searches the table for the current
  123. * timezone. It saves the last one found in ntstr or dststr, depending on
  124. * wheter the name is for daylight-saving-time or not.
  125. * Both ntstr and dststr are TZ_LEN + 1 chars.
  126. */
  127. static void
  128. ZoneFromTable(long timezone)
  129. {
  130. register TABLE *tptr = TimezoneTable;
  131. while (tptr->tz_name != NULL) {
  132. if (tptr->zoneoffset == timezone) {
  133. if (tptr->daylight == 0) {
  134. strncpy(ntstr,tptr->tz_name, TZ_LEN);
  135. ntstr[TZ_LEN] = '\0';
  136. } else {
  137. strncpy(dststr,tptr->tz_name, TZ_LEN);
  138. dststr[TZ_LEN] = '\0';
  139. }
  140. }
  141. tptr++;
  142. }
  143. }
  144. #endif /* USE_TABLE */
  145. static const char *
  146. parseZoneName(register char *buf, register const char *p)
  147. {
  148. register int n = 0;
  149. if (*p == ':') return NULL;
  150. while (*p && !isdigit(*p) && *p != ',' && *p != '-' && *p != '+') {
  151. if (n < TZ_LEN)
  152. *buf++ = *p;
  153. p++;
  154. n++;
  155. }
  156. if (n < 3) return NULL; /* error */
  157. *buf = '\0';
  158. return p;
  159. }
  160. static const char *
  161. parseTime(register long *tm, const char *p, register struct dsttype *dst)
  162. {
  163. register int n = 0;
  164. register const char *q = p;
  165. char ds_type = (dst ? dst->ds_type : '\0');
  166. if (dst) dst->ds_type = 'U';
  167. *tm = 0;
  168. while(*p >= '0' && *p <= '9') {
  169. n = 10 * n + (*p++ - '0');
  170. }
  171. if (q == p) return NULL; /* "The hour shall be required" */
  172. if (n < 0 || n >= 24) return NULL;
  173. *tm = n * 60 * 60;
  174. if (*p == ':') {
  175. p++;
  176. n = 0;
  177. while(*p >= '0' && *p <= '9') {
  178. n = 10 * n + (*p++ - '0');
  179. }
  180. if (q == p) return NULL; /* format error */
  181. if (n < 0 || n >= 60) return NULL;
  182. *tm += n * 60;
  183. if (*p == ':') {
  184. p++;
  185. n = 0;
  186. while(*p >= '0' && *p <= '9') {
  187. n = 10 * n + (*p++ - '0');
  188. }
  189. if (q == p) return NULL; /* format error */
  190. if (n < 0 || n >= 60) return NULL;
  191. *tm += n;
  192. }
  193. }
  194. if (dst) {
  195. dst->ds_type = ds_type;
  196. dst->ds_sec = *tm;
  197. }
  198. return p;
  199. }
  200. static const char *
  201. parseDate(register char *buf, register const char *p, struct dsttype *dstinfo)
  202. {
  203. register const char *q;
  204. register int n = 0;
  205. int cnt = 0;
  206. const int bnds[3][2] = { { 1, 12 },
  207. { 1, 5 },
  208. { 0, 6}
  209. };
  210. char ds_type;
  211. if (*p != 'M') {
  212. if (*p == 'J') {
  213. *buf++ = *p++;
  214. ds_type = 'J';
  215. }
  216. else ds_type = 'Z';
  217. q = p;
  218. while(*p >= '0' && *p <= '9') {
  219. n = 10 * n + (*p - '0');
  220. *buf++ = *p++;
  221. }
  222. if (q == p) return NULL; /* format error */
  223. if (n < (ds_type == 'J') || n > 365) return NULL;
  224. dstinfo->ds_type = ds_type;
  225. dstinfo->ds_date[0] = n;
  226. return p;
  227. }
  228. ds_type = 'M';
  229. do {
  230. *buf++ = *p++;
  231. q = p;
  232. n = 0;
  233. while(*p >= '0' && *p <= '9') {
  234. n = 10 * n + (*p - '0');
  235. *buf++ = *p++;
  236. }
  237. if (q == p) return NULL; /* format error */
  238. if (n < bnds[cnt][0] || n > bnds[cnt][1]) return NULL;
  239. dstinfo->ds_date[cnt] = n;
  240. cnt++;
  241. } while (cnt < 3 && *p == '.');
  242. if (cnt != 3) return NULL;
  243. *buf = '\0';
  244. dstinfo->ds_type = ds_type;
  245. return p;
  246. }
  247. static const char *
  248. parseRule(register char *buf, register const char *p)
  249. {
  250. long tim;
  251. register const char *q;
  252. if (!(p = parseDate(buf, p, &dststart))) return NULL;
  253. buf += strlen(buf);
  254. if (*p == '/') {
  255. q = ++p;
  256. if (!(p = parseTime(&tim, p, &dststart))) return NULL;
  257. while( p != q) *buf++ = *q++;
  258. }
  259. if (*p != ',') return NULL;
  260. p++;
  261. if (!(p = parseDate(buf, p, &dstend))) return NULL;
  262. buf += strlen(buf);
  263. if (*p == '/') {
  264. q = ++p;
  265. if (!(p = parseTime(&tim, p, &dstend))) return NULL;
  266. while(*buf++ = *q++);
  267. }
  268. if (*p) return NULL;
  269. return p;
  270. }
  271. /* The following routine parses timezone information in POSIX-format. For
  272. * the requirements, see IEEE Std 1003.1-1988 section 8.1.1.
  273. * The function returns as soon as it spots an error.
  274. */
  275. static void
  276. parseTZ(const char *p)
  277. {
  278. long tz, dst = 60 * 60, sign = 1;
  279. static char lastTZ[2 * RULE_LEN];
  280. static char buffer[RULE_LEN];
  281. if (!p) return;
  282. #if USE_TABLE
  283. usetable = 0;
  284. #endif
  285. if (*p == ':') {
  286. /*
  287. * According to POSIX, this is implementation defined.
  288. * Since it depends on the particular operating system, we
  289. * can do nothing.
  290. */
  291. return;
  292. }
  293. if (!strcmp(lastTZ, p)) return; /* nothing changed */
  294. *_tzname[0] = '\0';
  295. *_tzname[1] = '\0';
  296. dststart.ds_type = 'U';
  297. dststart.ds_sec = 2 * 60 * 60;
  298. dstend.ds_type = 'U';
  299. dstend.ds_sec = 2 * 60 * 60;
  300. if (strlen(p) > 2 * RULE_LEN) return;
  301. strcpy(lastTZ, p);
  302. if (!(p = parseZoneName(buffer, p))) return;
  303. if (*p == '-') {
  304. sign = -1;
  305. p++;
  306. } else if (*p == '+') p++;
  307. if (!(p = parseTime(&tz, p, NULL))) return;
  308. tz *= sign;
  309. _timezone = tz;
  310. strncpy(_tzname[0], buffer, TZ_LEN);
  311. if (!(_daylight = (*p != '\0'))) return;
  312. buffer[0] = '\0';
  313. if (!(p = parseZoneName(buffer, p))) return;
  314. strncpy(_tzname[1], buffer, TZ_LEN);
  315. buffer[0] = '\0';
  316. if (*p && (*p != ','))
  317. if (!(p = parseTime(&dst, p, NULL))) return;
  318. _dst_off = dst; /* dst was initialized to 1 hour */
  319. if (*p) {
  320. if (*p != ',') return;
  321. p++;
  322. if (strlen(p) > RULE_LEN) return;
  323. if (!(p = parseRule(buffer, p))) return;
  324. }
  325. }
  326. void
  327. _tzset(void)
  328. {
  329. #if defined(__BSD4_2)
  330. struct timeval tv;
  331. struct timezone tz;
  332. _gettimeofday(&tv, &tz);
  333. _daylight = tz.tz_dsttime;
  334. _timezone = tz.tz_minuteswest * 60L;
  335. #elif !defined(_POSIX_SOURCE) && !defined(__USG)
  336. #if !defined(_MINIX) /* MINIX has no ftime() */
  337. struct timeb tim;
  338. _ftime(&tim);
  339. _timezone = tim.timezone * 60L;
  340. _daylight = tim.dstflag;
  341. #endif
  342. #endif /* !_POSIX_SOURCE && !__USG */
  343. parseTZ(getenv("TZ")); /* should go inside #if */
  344. #if defined(__USG) || defined(_POSIX_SOURCE)
  345. tzname[0] = _tzname[0];
  346. tzname[1] = _tzname[1];
  347. #if defined(__USG)
  348. timezone = _timezone;
  349. daylight = _daylight;
  350. #endif
  351. #endif /* __USG || _POSIX_SOURCE */
  352. }
  353. static int
  354. last_sunday(register int day, register struct tm *timep)
  355. {
  356. int first = FIRSTSUNDAY(timep);
  357. if (day >= 58 && LEAPYEAR(YEAR0 + timep->tm_year)) day++;
  358. if (day < first) return first;
  359. return day - (day - first) % 7;
  360. }
  361. static int
  362. date_of(register struct dsttype *dst, struct tm *timep)
  363. {
  364. int leap = LEAPYEAR(YEAR0 + timep->tm_year);
  365. int firstday, tmpday;
  366. register int day, month;
  367. if (dst->ds_type != 'M') {
  368. return dst->ds_date[0] -
  369. (dst->ds_type == 'J'
  370. && leap
  371. && dst->ds_date[0] < 58);
  372. }
  373. day = 0;
  374. month = 1;
  375. while (month < dst->ds_date[0]) {
  376. day += _ytab[leap][month - 1];
  377. month++;
  378. }
  379. firstday = (day + FIRSTDAYOF(timep)) % 7;
  380. tmpday = day;
  381. day += (dst->ds_date[2] - firstday + 7) % 7
  382. + 7 * (dst->ds_date[1] - 1);
  383. if (day >= tmpday + _ytab[leap][month]) day -= 7;
  384. return day;
  385. }
  386. /*
  387. * The default dst transitions are those for Western Europe (except Great
  388. * Britain).
  389. */
  390. unsigned
  391. _dstget(register struct tm *timep)
  392. {
  393. int begindst, enddst;
  394. register struct dsttype *dsts = &dststart, *dste = &dstend;
  395. int do_dst = 0;
  396. if (_daylight == -1)
  397. _tzset();
  398. timep->tm_isdst = _daylight;
  399. if (!_daylight) return 0;
  400. if (dsts->ds_type != 'U')
  401. begindst = date_of(dsts, timep);
  402. else begindst = last_sunday(89, timep); /* last Sun before Apr */
  403. if (dste->ds_type != 'U')
  404. enddst = date_of(dste, timep);
  405. else enddst = last_sunday(272, timep); /* last Sun in Sep */
  406. /* assume begindst != enddst (otherwise it would be no use) */
  407. if (begindst < enddst) { /* northern hemisphere */
  408. if (timep->tm_yday > begindst && timep->tm_yday < enddst)
  409. do_dst = 1;
  410. } else { /* southern hemisphere */
  411. if (timep->tm_yday > begindst || timep->tm_yday < enddst)
  412. do_dst = 1;
  413. }
  414. if (!do_dst
  415. && (timep->tm_yday == begindst || timep->tm_yday == enddst)) {
  416. long dsttranssec; /* transition when day is this old */
  417. long cursec;
  418. if (timep->tm_yday == begindst)
  419. dsttranssec = dsts->ds_sec;
  420. else dsttranssec = dste->ds_sec;
  421. cursec = ((timep->tm_hour * 60) + timep->tm_min) * 60L
  422. + timep->tm_sec;
  423. if ((timep->tm_yday == begindst && cursec >= dsttranssec)
  424. || (timep->tm_yday == enddst && cursec < dsttranssec))
  425. do_dst = 1;
  426. }
  427. #if USE_TABLE
  428. if (usetable) ZoneFromTable(_timezone);
  429. #endif
  430. if (do_dst) return _dst_off;
  431. timep->tm_isdst = 0;
  432. return 0;
  433. }