/contrib/cvs/lib/getdate.y

https://bitbucket.org/freebsd/freebsd-head/ · Happy · 1030 lines · 932 code · 98 blank · 0 comment · 0 complexity · 6da8fc316142897e122f354cc9ae8427 MD5 · raw file

  1. %{
  2. /*
  3. ** Originally written by Steven M. Bellovin <smb@research.att.com> while
  4. ** at the University of North Carolina at Chapel Hill. Later tweaked by
  5. ** a couple of people on Usenet. Completely overhauled by Rich $alz
  6. ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  7. **
  8. ** This grammar has 10 shift/reduce conflicts.
  9. **
  10. ** This code is in the public domain and has no copyright.
  11. */
  12. /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
  13. /* SUPPRESS 288 on yyerrlab *//* Label unused */
  14. #ifdef HAVE_CONFIG_H
  15. #if defined (emacs) || defined (CONFIG_BROKETS)
  16. #include <config.h>
  17. #else
  18. #include "config.h"
  19. #endif
  20. #endif
  21. /* Since the code of getdate.y is not included in the Emacs executable
  22. itself, there is no need to #define static in this file. Even if
  23. the code were included in the Emacs executable, it probably
  24. wouldn't do any harm to #undef it here; this will only cause
  25. problems if we try to write to a static variable, which I don't
  26. think this code needs to do. */
  27. #ifdef emacs
  28. #undef static
  29. #endif
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. /* The code at the top of get_date which figures out the offset of the
  33. current time zone checks various CPP symbols to see if special
  34. tricks are need, but defaults to using the gettimeofday system call.
  35. Include <sys/time.h> if that will be used. */
  36. #if defined(vms)
  37. # include <types.h>
  38. #else /* defined(vms) */
  39. # include <sys/types.h>
  40. #endif /* !defined(vms) */
  41. # include "xtime.h"
  42. #if defined (STDC_HEADERS) || defined (USG)
  43. #include <string.h>
  44. #endif
  45. /* Some old versions of bison generate parsers that use bcopy.
  46. That loses on systems that don't provide the function, so we have
  47. to redefine it here. */
  48. #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
  49. #define bcopy(from, to, len) memcpy ((to), (from), (len))
  50. #endif
  51. #if defined (STDC_HEADERS)
  52. #include <stdlib.h>
  53. #endif
  54. /* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
  55. releases):
  56. We don't want to mess with all the portability hassles of alloca.
  57. In particular, most (all?) versions of bison will use alloca in
  58. their parser. If bison works on your system (e.g. it should work
  59. with gcc), then go ahead and use it, but the more general solution
  60. is to use byacc instead of bison, which should generate a portable
  61. parser. I played with adding "#define alloca dont_use_alloca", to
  62. give an error if the parser generator uses alloca (and thus detect
  63. unportable getdate.c's), but that seems to cause as many problems
  64. as it solves. */
  65. extern struct tm *gmtime();
  66. extern struct tm *localtime();
  67. #define yyparse getdate_yyparse
  68. #define yylex getdate_yylex
  69. #define yyerror getdate_yyerror
  70. static int yyparse ();
  71. static int yylex ();
  72. static int yyerror ();
  73. #define EPOCH 1970
  74. #define HOUR(x) ((time_t)(x) * 60)
  75. #define SECSPERDAY (24L * 60L * 60L)
  76. /*
  77. ** An entry in the lexical lookup table.
  78. */
  79. typedef struct _TABLE {
  80. char *name;
  81. int type;
  82. time_t value;
  83. } TABLE;
  84. /*
  85. ** Daylight-savings mode: on, off, or not yet known.
  86. */
  87. typedef enum _DSTMODE {
  88. DSTon, DSToff, DSTmaybe
  89. } DSTMODE;
  90. /*
  91. ** Meridian: am, pm, or 24-hour style.
  92. */
  93. typedef enum _MERIDIAN {
  94. MERam, MERpm, MER24
  95. } MERIDIAN;
  96. /*
  97. ** Global variables. We could get rid of most of these by using a good
  98. ** union as the yacc stack. (This routine was originally written before
  99. ** yacc had the %union construct.) Maybe someday; right now we only use
  100. ** the %union very rarely.
  101. */
  102. static char *yyInput;
  103. static DSTMODE yyDSTmode;
  104. static time_t yyDayOrdinal;
  105. static time_t yyDayNumber;
  106. static int yyHaveDate;
  107. static int yyHaveDay;
  108. static int yyHaveRel;
  109. static int yyHaveTime;
  110. static int yyHaveZone;
  111. static time_t yyTimezone;
  112. static time_t yyDay;
  113. static time_t yyHour;
  114. static time_t yyMinutes;
  115. static time_t yyMonth;
  116. static time_t yySeconds;
  117. static time_t yyYear;
  118. static MERIDIAN yyMeridian;
  119. static time_t yyRelMonth;
  120. static time_t yyRelSeconds;
  121. %}
  122. %union {
  123. time_t Number;
  124. enum _MERIDIAN Meridian;
  125. }
  126. %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  127. %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  128. %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  129. %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
  130. %type <Meridian> tMERIDIAN o_merid
  131. %%
  132. spec : /* NULL */
  133. | spec item
  134. ;
  135. item : time {
  136. yyHaveTime++;
  137. }
  138. | zone {
  139. yyHaveZone++;
  140. }
  141. | date {
  142. yyHaveDate++;
  143. }
  144. | day {
  145. yyHaveDay++;
  146. }
  147. | rel {
  148. yyHaveRel++;
  149. }
  150. | cvsstamp {
  151. yyHaveTime++;
  152. yyHaveDate++;
  153. yyHaveZone++;
  154. }
  155. | number
  156. ;
  157. cvsstamp: tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER {
  158. yyYear = $1;
  159. if (yyYear < 100) yyYear += 1900;
  160. yyMonth = $3;
  161. yyDay = $5;
  162. yyHour = $7;
  163. yyMinutes = $9;
  164. yySeconds = $11;
  165. yyDSTmode = DSToff;
  166. yyTimezone = 0;
  167. }
  168. ;
  169. time : tUNUMBER tMERIDIAN {
  170. yyHour = $1;
  171. yyMinutes = 0;
  172. yySeconds = 0;
  173. yyMeridian = $2;
  174. }
  175. | tUNUMBER ':' tUNUMBER o_merid {
  176. yyHour = $1;
  177. yyMinutes = $3;
  178. yySeconds = 0;
  179. yyMeridian = $4;
  180. }
  181. | tUNUMBER ':' tUNUMBER tSNUMBER {
  182. yyHour = $1;
  183. yyMinutes = $3;
  184. yyMeridian = MER24;
  185. yyDSTmode = DSToff;
  186. yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  187. }
  188. | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  189. yyHour = $1;
  190. yyMinutes = $3;
  191. yySeconds = $5;
  192. yyMeridian = $6;
  193. }
  194. | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  195. yyHour = $1;
  196. yyMinutes = $3;
  197. yySeconds = $5;
  198. yyMeridian = MER24;
  199. yyDSTmode = DSToff;
  200. yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  201. }
  202. ;
  203. zone : tZONE {
  204. yyTimezone = $1;
  205. yyDSTmode = DSToff;
  206. }
  207. | tDAYZONE {
  208. yyTimezone = $1;
  209. yyDSTmode = DSTon;
  210. }
  211. |
  212. tZONE tDST {
  213. yyTimezone = $1;
  214. yyDSTmode = DSTon;
  215. }
  216. ;
  217. day : tDAY {
  218. yyDayOrdinal = 1;
  219. yyDayNumber = $1;
  220. }
  221. | tDAY ',' {
  222. yyDayOrdinal = 1;
  223. yyDayNumber = $1;
  224. }
  225. | tUNUMBER tDAY {
  226. yyDayOrdinal = $1;
  227. yyDayNumber = $2;
  228. }
  229. ;
  230. date : tUNUMBER '/' tUNUMBER {
  231. yyMonth = $1;
  232. yyDay = $3;
  233. }
  234. | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  235. if ($1 >= 100) {
  236. yyYear = $1;
  237. yyMonth = $3;
  238. yyDay = $5;
  239. } else {
  240. yyMonth = $1;
  241. yyDay = $3;
  242. yyYear = $5;
  243. }
  244. }
  245. | tUNUMBER tSNUMBER tSNUMBER {
  246. /* ISO 8601 format. yyyy-mm-dd. */
  247. yyYear = $1;
  248. yyMonth = -$2;
  249. yyDay = -$3;
  250. }
  251. | tUNUMBER tMONTH tSNUMBER {
  252. /* e.g. 17-JUN-1992. */
  253. yyDay = $1;
  254. yyMonth = $2;
  255. yyYear = -$3;
  256. }
  257. | tMONTH tUNUMBER {
  258. yyMonth = $1;
  259. yyDay = $2;
  260. }
  261. | tMONTH tUNUMBER ',' tUNUMBER {
  262. yyMonth = $1;
  263. yyDay = $2;
  264. yyYear = $4;
  265. }
  266. | tUNUMBER tMONTH {
  267. yyMonth = $2;
  268. yyDay = $1;
  269. }
  270. | tUNUMBER tMONTH tUNUMBER {
  271. yyMonth = $2;
  272. yyDay = $1;
  273. yyYear = $3;
  274. }
  275. ;
  276. rel : relunit tAGO {
  277. yyRelSeconds = -yyRelSeconds;
  278. yyRelMonth = -yyRelMonth;
  279. }
  280. | relunit
  281. ;
  282. relunit : tUNUMBER tMINUTE_UNIT {
  283. yyRelSeconds += $1 * $2 * 60L;
  284. }
  285. | tSNUMBER tMINUTE_UNIT {
  286. yyRelSeconds += $1 * $2 * 60L;
  287. }
  288. | tMINUTE_UNIT {
  289. yyRelSeconds += $1 * 60L;
  290. }
  291. | tSNUMBER tSEC_UNIT {
  292. yyRelSeconds += $1;
  293. }
  294. | tUNUMBER tSEC_UNIT {
  295. yyRelSeconds += $1;
  296. }
  297. | tSEC_UNIT {
  298. yyRelSeconds++;
  299. }
  300. | tSNUMBER tMONTH_UNIT {
  301. yyRelMonth += $1 * $2;
  302. }
  303. | tUNUMBER tMONTH_UNIT {
  304. yyRelMonth += $1 * $2;
  305. }
  306. | tMONTH_UNIT {
  307. yyRelMonth += $1;
  308. }
  309. ;
  310. number : tUNUMBER {
  311. if (yyHaveTime && yyHaveDate && !yyHaveRel)
  312. yyYear = $1;
  313. else {
  314. if($1>10000) {
  315. yyHaveDate++;
  316. yyDay= ($1)%100;
  317. yyMonth= ($1/100)%100;
  318. yyYear = $1/10000;
  319. }
  320. else {
  321. yyHaveTime++;
  322. if ($1 < 100) {
  323. yyHour = $1;
  324. yyMinutes = 0;
  325. }
  326. else {
  327. yyHour = $1 / 100;
  328. yyMinutes = $1 % 100;
  329. }
  330. yySeconds = 0;
  331. yyMeridian = MER24;
  332. }
  333. }
  334. }
  335. ;
  336. o_merid : /* NULL */ {
  337. $$ = MER24;
  338. }
  339. | tMERIDIAN {
  340. $$ = $1;
  341. }
  342. ;
  343. %%
  344. /* Month and day table. */
  345. static TABLE const MonthDayTable[] = {
  346. { "january", tMONTH, 1 },
  347. { "february", tMONTH, 2 },
  348. { "march", tMONTH, 3 },
  349. { "april", tMONTH, 4 },
  350. { "may", tMONTH, 5 },
  351. { "june", tMONTH, 6 },
  352. { "july", tMONTH, 7 },
  353. { "august", tMONTH, 8 },
  354. { "september", tMONTH, 9 },
  355. { "sept", tMONTH, 9 },
  356. { "october", tMONTH, 10 },
  357. { "november", tMONTH, 11 },
  358. { "december", tMONTH, 12 },
  359. { "sunday", tDAY, 0 },
  360. { "monday", tDAY, 1 },
  361. { "tuesday", tDAY, 2 },
  362. { "tues", tDAY, 2 },
  363. { "wednesday", tDAY, 3 },
  364. { "wednes", tDAY, 3 },
  365. { "thursday", tDAY, 4 },
  366. { "thur", tDAY, 4 },
  367. { "thurs", tDAY, 4 },
  368. { "friday", tDAY, 5 },
  369. { "saturday", tDAY, 6 },
  370. { NULL }
  371. };
  372. /* Time units table. */
  373. static TABLE const UnitsTable[] = {
  374. { "year", tMONTH_UNIT, 12 },
  375. { "month", tMONTH_UNIT, 1 },
  376. { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
  377. { "week", tMINUTE_UNIT, 7 * 24 * 60 },
  378. { "day", tMINUTE_UNIT, 1 * 24 * 60 },
  379. { "hour", tMINUTE_UNIT, 60 },
  380. { "minute", tMINUTE_UNIT, 1 },
  381. { "min", tMINUTE_UNIT, 1 },
  382. { "second", tSEC_UNIT, 1 },
  383. { "sec", tSEC_UNIT, 1 },
  384. { NULL }
  385. };
  386. /* Assorted relative-time words. */
  387. static TABLE const OtherTable[] = {
  388. { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
  389. { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
  390. { "today", tMINUTE_UNIT, 0 },
  391. { "now", tMINUTE_UNIT, 0 },
  392. { "last", tUNUMBER, -1 },
  393. { "this", tMINUTE_UNIT, 0 },
  394. { "next", tUNUMBER, 2 },
  395. { "first", tUNUMBER, 1 },
  396. /* { "second", tUNUMBER, 2 }, */
  397. { "third", tUNUMBER, 3 },
  398. { "fourth", tUNUMBER, 4 },
  399. { "fifth", tUNUMBER, 5 },
  400. { "sixth", tUNUMBER, 6 },
  401. { "seventh", tUNUMBER, 7 },
  402. { "eighth", tUNUMBER, 8 },
  403. { "ninth", tUNUMBER, 9 },
  404. { "tenth", tUNUMBER, 10 },
  405. { "eleventh", tUNUMBER, 11 },
  406. { "twelfth", tUNUMBER, 12 },
  407. { "ago", tAGO, 1 },
  408. { NULL }
  409. };
  410. /* The timezone table. */
  411. /* Some of these are commented out because a time_t can't store a float. */
  412. static TABLE const TimezoneTable[] = {
  413. { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
  414. { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
  415. { "utc", tZONE, HOUR( 0) },
  416. { "wet", tZONE, HOUR( 0) }, /* Western European */
  417. { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
  418. { "wat", tZONE, HOUR( 1) }, /* West Africa */
  419. { "at", tZONE, HOUR( 2) }, /* Azores */
  420. #if 0
  421. /* For completeness. BST is also British Summer, and GST is
  422. * also Guam Standard. */
  423. { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
  424. { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
  425. #endif
  426. #if 0
  427. { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
  428. { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
  429. { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
  430. #endif
  431. { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
  432. { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
  433. { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
  434. { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
  435. { "cst", tZONE, HOUR( 6) }, /* Central Standard */
  436. { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
  437. { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
  438. { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
  439. { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
  440. { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
  441. { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
  442. { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
  443. { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
  444. { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
  445. { "cat", tZONE, HOUR(10) }, /* Central Alaska */
  446. { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
  447. { "nt", tZONE, HOUR(11) }, /* Nome */
  448. { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
  449. { "cet", tZONE, -HOUR(1) }, /* Central European */
  450. { "met", tZONE, -HOUR(1) }, /* Middle European */
  451. { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
  452. { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
  453. { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
  454. { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
  455. { "fwt", tZONE, -HOUR(1) }, /* French Winter */
  456. { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
  457. { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
  458. { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
  459. #if 0
  460. { "it", tZONE, -HOUR(3.5) },/* Iran */
  461. #endif
  462. { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
  463. { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
  464. #if 0
  465. { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
  466. #endif
  467. { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
  468. #if 0
  469. /* For completeness. NST is also Newfoundland Stanard, and SST is
  470. * also Swedish Summer. */
  471. { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
  472. { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
  473. #endif /* 0 */
  474. { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
  475. { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
  476. #if 0
  477. { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  478. #endif
  479. { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
  480. { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
  481. #if 0
  482. { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
  483. { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
  484. #endif
  485. { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
  486. { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
  487. { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
  488. { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
  489. { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
  490. { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
  491. { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
  492. { NULL }
  493. };
  494. /* Military timezone table. */
  495. static TABLE const MilitaryTable[] = {
  496. { "a", tZONE, HOUR( 1) },
  497. { "b", tZONE, HOUR( 2) },
  498. { "c", tZONE, HOUR( 3) },
  499. { "d", tZONE, HOUR( 4) },
  500. { "e", tZONE, HOUR( 5) },
  501. { "f", tZONE, HOUR( 6) },
  502. { "g", tZONE, HOUR( 7) },
  503. { "h", tZONE, HOUR( 8) },
  504. { "i", tZONE, HOUR( 9) },
  505. { "k", tZONE, HOUR( 10) },
  506. { "l", tZONE, HOUR( 11) },
  507. { "m", tZONE, HOUR( 12) },
  508. { "n", tZONE, HOUR(- 1) },
  509. { "o", tZONE, HOUR(- 2) },
  510. { "p", tZONE, HOUR(- 3) },
  511. { "q", tZONE, HOUR(- 4) },
  512. { "r", tZONE, HOUR(- 5) },
  513. { "s", tZONE, HOUR(- 6) },
  514. { "t", tZONE, HOUR(- 7) },
  515. { "u", tZONE, HOUR(- 8) },
  516. { "v", tZONE, HOUR(- 9) },
  517. { "w", tZONE, HOUR(-10) },
  518. { "x", tZONE, HOUR(-11) },
  519. { "y", tZONE, HOUR(-12) },
  520. { "z", tZONE, HOUR( 0) },
  521. { NULL }
  522. };
  523. /* ARGSUSED */
  524. static int
  525. yyerror(s)
  526. char *s;
  527. {
  528. return 0;
  529. }
  530. static time_t
  531. ToSeconds(Hours, Minutes, Seconds, Meridian)
  532. time_t Hours;
  533. time_t Minutes;
  534. time_t Seconds;
  535. MERIDIAN Meridian;
  536. {
  537. if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  538. return -1;
  539. switch (Meridian) {
  540. case MER24:
  541. if (Hours < 0 || Hours > 23)
  542. return -1;
  543. return (Hours * 60L + Minutes) * 60L + Seconds;
  544. case MERam:
  545. if (Hours < 1 || Hours > 12)
  546. return -1;
  547. if (Hours == 12)
  548. Hours = 0;
  549. return (Hours * 60L + Minutes) * 60L + Seconds;
  550. case MERpm:
  551. if (Hours < 1 || Hours > 12)
  552. return -1;
  553. if (Hours == 12)
  554. Hours = 0;
  555. return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  556. default:
  557. abort ();
  558. }
  559. /* NOTREACHED */
  560. }
  561. /* Year is either
  562. * A negative number, which means to use its absolute value (why?)
  563. * A number from 0 to 99, which means a year from 1900 to 1999, or
  564. * The actual year (>=100). */
  565. static time_t
  566. Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  567. time_t Month;
  568. time_t Day;
  569. time_t Year;
  570. time_t Hours;
  571. time_t Minutes;
  572. time_t Seconds;
  573. MERIDIAN Meridian;
  574. DSTMODE DSTmode;
  575. {
  576. static int DaysInMonth[12] = {
  577. 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  578. };
  579. time_t tod;
  580. time_t Julian;
  581. int i;
  582. if (Year < 0)
  583. Year = -Year;
  584. if (Year < 69)
  585. Year += 2000;
  586. else if (Year < 100)
  587. Year += 1900;
  588. DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  589. ? 29 : 28;
  590. /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
  591. I'm too lazy to try to check for time_t overflow in another way. */
  592. if (Year < EPOCH || Year > 2038
  593. || Month < 1 || Month > 12
  594. /* Lint fluff: "conversion from long may lose accuracy" */
  595. || Day < 1 || Day > DaysInMonth[(int)--Month])
  596. /* FIXME:
  597. * It would be nice to set a global error string here.
  598. * "February 30 is not a valid date" is much more informative than
  599. * "Can't parse date/time: 100 months" when the user input was
  600. * "100 months" and addition resolved that to February 30, for
  601. * example. See rcs2-7 in src/sanity.sh for more. */
  602. return -1;
  603. for (Julian = Day - 1, i = 0; i < Month; i++)
  604. Julian += DaysInMonth[i];
  605. for (i = EPOCH; i < Year; i++)
  606. Julian += 365 + (i % 4 == 0);
  607. Julian *= SECSPERDAY;
  608. Julian += yyTimezone * 60L;
  609. if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  610. return -1;
  611. Julian += tod;
  612. if (DSTmode == DSTon
  613. || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
  614. Julian -= 60 * 60;
  615. return Julian;
  616. }
  617. static time_t
  618. DSTcorrect(Start, Future)
  619. time_t Start;
  620. time_t Future;
  621. {
  622. time_t StartDay;
  623. time_t FutureDay;
  624. StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  625. FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  626. return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  627. }
  628. static time_t
  629. RelativeDate(Start, DayOrdinal, DayNumber)
  630. time_t Start;
  631. time_t DayOrdinal;
  632. time_t DayNumber;
  633. {
  634. struct tm *tm;
  635. time_t now;
  636. now = Start;
  637. tm = localtime(&now);
  638. now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  639. now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  640. return DSTcorrect(Start, now);
  641. }
  642. static time_t
  643. RelativeMonth(Start, RelMonth)
  644. time_t Start;
  645. time_t RelMonth;
  646. {
  647. struct tm *tm;
  648. time_t Month;
  649. time_t Year;
  650. if (RelMonth == 0)
  651. return 0;
  652. tm = localtime(&Start);
  653. Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
  654. Year = Month / 12;
  655. Month = Month % 12 + 1;
  656. return DSTcorrect(Start,
  657. Convert(Month, (time_t)tm->tm_mday, Year,
  658. (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  659. MER24, DSTmaybe));
  660. }
  661. static int
  662. LookupWord(buff)
  663. char *buff;
  664. {
  665. register char *p;
  666. register char *q;
  667. register const TABLE *tp;
  668. int i;
  669. int abbrev;
  670. /* Make it lowercase. */
  671. for (p = buff; *p; p++)
  672. if (isupper(*p))
  673. *p = tolower(*p);
  674. if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  675. yylval.Meridian = MERam;
  676. return tMERIDIAN;
  677. }
  678. if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  679. yylval.Meridian = MERpm;
  680. return tMERIDIAN;
  681. }
  682. /* See if we have an abbreviation for a month. */
  683. if (strlen(buff) == 3)
  684. abbrev = 1;
  685. else if (strlen(buff) == 4 && buff[3] == '.') {
  686. abbrev = 1;
  687. buff[3] = '\0';
  688. }
  689. else
  690. abbrev = 0;
  691. for (tp = MonthDayTable; tp->name; tp++) {
  692. if (abbrev) {
  693. if (strncmp(buff, tp->name, 3) == 0) {
  694. yylval.Number = tp->value;
  695. return tp->type;
  696. }
  697. }
  698. else if (strcmp(buff, tp->name) == 0) {
  699. yylval.Number = tp->value;
  700. return tp->type;
  701. }
  702. }
  703. for (tp = TimezoneTable; tp->name; tp++)
  704. if (strcmp(buff, tp->name) == 0) {
  705. yylval.Number = tp->value;
  706. return tp->type;
  707. }
  708. if (strcmp(buff, "dst") == 0)
  709. return tDST;
  710. for (tp = UnitsTable; tp->name; tp++)
  711. if (strcmp(buff, tp->name) == 0) {
  712. yylval.Number = tp->value;
  713. return tp->type;
  714. }
  715. /* Strip off any plural and try the units table again. */
  716. i = strlen(buff) - 1;
  717. if (buff[i] == 's') {
  718. buff[i] = '\0';
  719. for (tp = UnitsTable; tp->name; tp++)
  720. if (strcmp(buff, tp->name) == 0) {
  721. yylval.Number = tp->value;
  722. return tp->type;
  723. }
  724. buff[i] = 's'; /* Put back for "this" in OtherTable. */
  725. }
  726. for (tp = OtherTable; tp->name; tp++)
  727. if (strcmp(buff, tp->name) == 0) {
  728. yylval.Number = tp->value;
  729. return tp->type;
  730. }
  731. /* Military timezones. */
  732. if (buff[1] == '\0' && isalpha(*buff)) {
  733. for (tp = MilitaryTable; tp->name; tp++)
  734. if (strcmp(buff, tp->name) == 0) {
  735. yylval.Number = tp->value;
  736. return tp->type;
  737. }
  738. }
  739. /* Drop out any periods and try the timezone table again. */
  740. for (i = 0, p = q = buff; *q; q++)
  741. if (*q != '.')
  742. *p++ = *q;
  743. else
  744. i++;
  745. *p = '\0';
  746. if (i)
  747. for (tp = TimezoneTable; tp->name; tp++)
  748. if (strcmp(buff, tp->name) == 0) {
  749. yylval.Number = tp->value;
  750. return tp->type;
  751. }
  752. return tID;
  753. }
  754. static int
  755. yylex()
  756. {
  757. register char c;
  758. register char *p;
  759. char buff[20];
  760. int Count;
  761. int sign;
  762. for ( ; ; ) {
  763. while (isspace(*yyInput))
  764. yyInput++;
  765. if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  766. if (c == '-' || c == '+') {
  767. sign = c == '-' ? -1 : 1;
  768. if (!isdigit(*++yyInput))
  769. /* skip the '-' sign */
  770. continue;
  771. }
  772. else
  773. sign = 0;
  774. for (yylval.Number = 0; isdigit(c = *yyInput++); )
  775. yylval.Number = 10 * yylval.Number + c - '0';
  776. yyInput--;
  777. if (sign < 0)
  778. yylval.Number = -yylval.Number;
  779. return sign ? tSNUMBER : tUNUMBER;
  780. }
  781. if (isalpha(c)) {
  782. for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  783. if (p < &buff[sizeof buff - 1])
  784. *p++ = c;
  785. *p = '\0';
  786. yyInput--;
  787. return LookupWord(buff);
  788. }
  789. if (c != '(')
  790. return *yyInput++;
  791. Count = 0;
  792. do {
  793. c = *yyInput++;
  794. if (c == '\0')
  795. return c;
  796. if (c == '(')
  797. Count++;
  798. else if (c == ')')
  799. Count--;
  800. } while (Count > 0);
  801. }
  802. }
  803. #define TM_YEAR_ORIGIN 1900
  804. /* Yield A - B, measured in seconds. */
  805. static long
  806. difftm (a, b)
  807. struct tm *a, *b;
  808. {
  809. int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
  810. int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
  811. int days = (
  812. /* difference in day of year */
  813. a->tm_yday - b->tm_yday
  814. /* + intervening leap days */
  815. + ((ay >> 2) - (by >> 2))
  816. - (ay/100 - by/100)
  817. + ((ay/100 >> 2) - (by/100 >> 2))
  818. /* + difference in years * 365 */
  819. + (long)(ay-by) * 365
  820. );
  821. return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
  822. + (a->tm_min - b->tm_min))
  823. + (a->tm_sec - b->tm_sec));
  824. }
  825. time_t
  826. get_date(p, now)
  827. char *p;
  828. struct timeb *now;
  829. {
  830. struct tm *tm, gmt;
  831. struct timeb ftz;
  832. time_t Start;
  833. time_t tod;
  834. time_t nowtime;
  835. yyInput = p;
  836. if (now == NULL) {
  837. struct tm *gmt_ptr;
  838. now = &ftz;
  839. (void)time (&nowtime);
  840. gmt_ptr = gmtime (&nowtime);
  841. if (gmt_ptr != NULL)
  842. {
  843. /* Make a copy, in case localtime modifies *tm (I think
  844. that comment now applies to *gmt_ptr, but I am too
  845. lazy to dig into how gmtime and locatime allocate the
  846. structures they return pointers to). */
  847. gmt = *gmt_ptr;
  848. }
  849. if (! (tm = localtime (&nowtime)))
  850. return -1;
  851. if (gmt_ptr != NULL)
  852. ftz.timezone = difftm (&gmt, tm) / 60;
  853. else
  854. /* We are on a system like VMS, where the system clock is
  855. in local time and the system has no concept of timezones.
  856. Hopefully we can fake this out (for the case in which the
  857. user specifies no timezone) by just saying the timezone
  858. is zero. */
  859. ftz.timezone = 0;
  860. if(tm->tm_isdst)
  861. ftz.timezone += 60;
  862. }
  863. else
  864. {
  865. nowtime = now->time;
  866. }
  867. tm = localtime(&nowtime);
  868. yyYear = tm->tm_year + 1900;
  869. yyMonth = tm->tm_mon + 1;
  870. yyDay = tm->tm_mday;
  871. yyTimezone = now->timezone;
  872. yyDSTmode = DSTmaybe;
  873. yyHour = 0;
  874. yyMinutes = 0;
  875. yySeconds = 0;
  876. yyMeridian = MER24;
  877. yyRelSeconds = 0;
  878. yyRelMonth = 0;
  879. yyHaveDate = 0;
  880. yyHaveDay = 0;
  881. yyHaveRel = 0;
  882. yyHaveTime = 0;
  883. yyHaveZone = 0;
  884. if (yyparse()
  885. || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  886. return -1;
  887. if (yyHaveDate || yyHaveTime || yyHaveDay) {
  888. Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  889. yyMeridian, yyDSTmode);
  890. if (Start < 0)
  891. return -1;
  892. }
  893. else {
  894. Start = nowtime;
  895. if (!yyHaveRel)
  896. Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  897. }
  898. Start += yyRelSeconds;
  899. Start += RelativeMonth(Start, yyRelMonth);
  900. if (yyHaveDay && !yyHaveDate) {
  901. tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  902. Start += tod;
  903. }
  904. /* Have to do *something* with a legitimate -1 so it's distinguishable
  905. * from the error return value. (Alternately could set errno on error.) */
  906. return Start == -1 ? 0 : Start;
  907. }
  908. #if defined(TEST)
  909. /* ARGSUSED */
  910. int
  911. main(ac, av)
  912. int ac;
  913. char *av[];
  914. {
  915. char buff[128];
  916. time_t d;
  917. (void)printf("Enter date, or blank line to exit.\n\t> ");
  918. (void)fflush(stdout);
  919. while (gets(buff) && buff[0]) {
  920. d = get_date(buff, (struct timeb *)NULL);
  921. if (d == -1)
  922. (void)printf("Bad format - couldn't convert.\n");
  923. else
  924. (void)printf("%s", ctime(&d));
  925. (void)printf("\t> ");
  926. (void)fflush(stdout);
  927. }
  928. exit(0);
  929. /* NOTREACHED */
  930. }
  931. #endif /* defined(TEST) */