PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/App/UnxUtilsSrc/unxutils/sh-utils-1.13/lib/getdate.y

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