misc.c 12 KB

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