/usr.bin/calendar/parsedata.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1076 lines · 860 code · 95 blank · 121 comment · 289 complexity · 5aa8229c0bda6508a69c457f54a3476c MD5 · raw file

  1. /*-
  2. * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <ctype.h>
  30. #include <math.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <err.h>
  35. #include "calendar.h"
  36. static char *showflags(int flags);
  37. static int isonlydigits(char *s, int nostar);
  38. static const char *getmonthname(int i);
  39. static int checkmonth(char *s, size_t *len, size_t *offset, const char **month);
  40. static const char *getdayofweekname(int i);
  41. static int checkdayofweek(char *s, size_t *len, size_t *offset, const char **dow);
  42. static int indextooffset(char *s);
  43. static int parseoffset(char *s);
  44. static char *floattoday(int year, double f);
  45. static char *floattotime(double f);
  46. /*
  47. * Expected styles:
  48. *
  49. * Date ::= Month . ' ' . DayOfMonth |
  50. * Month . ' ' . DayOfWeek . ModifierIndex |
  51. * Month . '/' . DayOfMonth |
  52. * Month . '/' . DayOfWeek . ModifierIndex |
  53. * DayOfMonth . ' ' . Month |
  54. * DayOfMonth . '/' . Month |
  55. * DayOfWeek . ModifierIndex . ' ' .Month |
  56. * DayOfWeek . ModifierIndex . '/' .Month |
  57. * DayOfWeek . ModifierIndex |
  58. * SpecialDay . ModifierOffset
  59. *
  60. * Month ::= MonthName | MonthNumber | '*'
  61. * MonthNumber ::= '0' ... '9' | '00' ... '09' | '10' ... '12'
  62. * MonthName ::= MonthNameShort | MonthNameLong
  63. * MonthNameLong ::= 'January' ... 'December'
  64. * MonthNameShort ::= 'Jan' ... 'Dec' | 'Jan.' ... 'Dec.'
  65. *
  66. * DayOfWeek ::= DayOfWeekShort | DayOfWeekLong
  67. * DayOfWeekShort ::= 'Mon' .. 'Sun'
  68. * DayOfWeekLong ::= 'Monday' .. 'Sunday'
  69. * DayOfMonth ::= '0' ... '9' | '00' ... '09' | '10' ... '29' |
  70. * '30' ... '31' | '*'
  71. *
  72. * ModifierOffset ::= '' | '+' . ModifierNumber | '-' . ModifierNumber
  73. * ModifierNumber ::= '0' ... '9' | '00' ... '99' | '000' ... '299' |
  74. * '300' ... '359' | '360' ... '365'
  75. * ModifierIndex ::= 'Second' | 'Third' | 'Fourth' | 'Fifth' |
  76. * 'First' | 'Last'
  77. *
  78. * SpecialDay ::= 'Easter' | 'Paskha' | 'ChineseNewYear'
  79. *
  80. */
  81. static int
  82. determinestyle(char *date, int *flags,
  83. char *month, int *imonth, char *dayofmonth, int *idayofmonth,
  84. char *dayofweek, int *idayofweek, char *modifieroffset,
  85. char *modifierindex, char *specialday, char *year, int *iyear)
  86. {
  87. char *p, *p1, *p2, *py;
  88. const char *dow, *pmonth;
  89. char pold;
  90. size_t len, offset;
  91. *flags = F_NONE;
  92. *month = '\0';
  93. *imonth = 0;
  94. *year = '\0';
  95. *iyear = 0;
  96. *dayofmonth = '\0';
  97. *idayofmonth = 0;
  98. *dayofweek = '\0';
  99. *idayofweek = 0;
  100. *modifieroffset = '\0';
  101. *modifierindex = '\0';
  102. *specialday = '\0';
  103. #define CHECKSPECIAL(s1, s2, lens2, type) \
  104. if (s2 != NULL && strncmp(s1, s2, lens2) == 0) { \
  105. *flags |= F_SPECIALDAY; \
  106. *flags |= type; \
  107. *flags |= F_VARIABLE; \
  108. if (strlen(s1) == lens2) { \
  109. strcpy(specialday, s1); \
  110. return (1); \
  111. } \
  112. strncpy(specialday, s1, lens2); \
  113. specialday[lens2] = '\0'; \
  114. strcpy(modifieroffset, s1 + lens2); \
  115. *flags |= F_MODIFIEROFFSET; \
  116. return (1); \
  117. }
  118. if ((p = strchr(date, ' ')) == NULL) {
  119. if ((p = strchr(date, '/')) == NULL) {
  120. CHECKSPECIAL(date, STRING_CNY, strlen(STRING_CNY),
  121. F_CNY);
  122. CHECKSPECIAL(date, ncny.name, ncny.len, F_CNY);
  123. CHECKSPECIAL(date, STRING_NEWMOON,
  124. strlen(STRING_NEWMOON), F_NEWMOON);
  125. CHECKSPECIAL(date, nnewmoon.name, nnewmoon.len,
  126. F_NEWMOON);
  127. CHECKSPECIAL(date, STRING_FULLMOON,
  128. strlen(STRING_FULLMOON), F_FULLMOON);
  129. CHECKSPECIAL(date, nfullmoon.name, nfullmoon.len,
  130. F_FULLMOON);
  131. CHECKSPECIAL(date, STRING_PASKHA,
  132. strlen(STRING_PASKHA), F_PASKHA);
  133. CHECKSPECIAL(date, npaskha.name, npaskha.len, F_PASKHA);
  134. CHECKSPECIAL(date, STRING_EASTER,
  135. strlen(STRING_EASTER), F_EASTER);
  136. CHECKSPECIAL(date, neaster.name, neaster.len, F_EASTER);
  137. CHECKSPECIAL(date, STRING_MAREQUINOX,
  138. strlen(STRING_MAREQUINOX), F_MAREQUINOX);
  139. CHECKSPECIAL(date, nmarequinox.name, nmarequinox.len,
  140. F_SEPEQUINOX);
  141. CHECKSPECIAL(date, STRING_SEPEQUINOX,
  142. strlen(STRING_SEPEQUINOX), F_SEPEQUINOX);
  143. CHECKSPECIAL(date, nsepequinox.name, nsepequinox.len,
  144. F_SEPEQUINOX);
  145. CHECKSPECIAL(date, STRING_JUNSOLSTICE,
  146. strlen(STRING_JUNSOLSTICE), F_JUNSOLSTICE);
  147. CHECKSPECIAL(date, njunsolstice.name, njunsolstice.len,
  148. F_JUNSOLSTICE);
  149. CHECKSPECIAL(date, STRING_DECSOLSTICE,
  150. strlen(STRING_DECSOLSTICE), F_DECSOLSTICE);
  151. CHECKSPECIAL(date, ndecsolstice.name, ndecsolstice.len,
  152. F_DECSOLSTICE);
  153. if (checkdayofweek(date, &len, &offset, &dow) != 0) {
  154. *flags |= F_DAYOFWEEK;
  155. *flags |= F_VARIABLE;
  156. *idayofweek = offset;
  157. if (strlen(date) == len) {
  158. strcpy(dayofweek, date);
  159. return (1);
  160. }
  161. strncpy(dayofweek, date, len);
  162. dayofweek[len] = '\0';
  163. strcpy(modifierindex, date + len);
  164. *flags |= F_MODIFIERINDEX;
  165. return (1);
  166. }
  167. if (isonlydigits(date, 1)) {
  168. /* Assume month number only */
  169. *flags |= F_MONTH;
  170. *imonth = (int)strtol(date, (char **)NULL, 10);
  171. strcpy(month, getmonthname(*imonth));
  172. return(1);
  173. }
  174. return (0);
  175. }
  176. }
  177. /*
  178. * AFTER this, leave by goto-ing to "allfine" or "fail" to restore the
  179. * original data in `date'.
  180. */
  181. pold = *p;
  182. *p = 0;
  183. p1 = date;
  184. p2 = p + 1;
  185. /* Now p2 points to the next field and p1 to the first field */
  186. if ((py = strchr(p2, '/')) != NULL) {
  187. /* We have a year in the string. Now this is getting tricky */
  188. strcpy(year, p1);
  189. *iyear = (int)strtol(year, NULL, 10);
  190. p1 = p2;
  191. p2 = py + 1;
  192. *py = 0;
  193. *flags |= F_YEAR;
  194. }
  195. /*
  196. printf("p1: %s\n", p1);
  197. printf("p2: %s\n", p2);
  198. printf("year: %s\n", year);
  199. */
  200. /* Check if there is a month-string in the date */
  201. if ((checkmonth(p1, &len, &offset, &pmonth) != 0)
  202. || (checkmonth(p2, &len, &offset, &pmonth) != 0 && (p2 = p1))) {
  203. /* p2 is the non-month part */
  204. *flags |= F_MONTH;
  205. *imonth = offset;
  206. strcpy(month, getmonthname(offset));
  207. if (isonlydigits(p2, 1)) {
  208. strcpy(dayofmonth, p2);
  209. *idayofmonth = (int)strtol(p2, (char **)NULL, 10);
  210. *flags |= F_DAYOFMONTH;
  211. goto allfine;
  212. }
  213. if (strcmp(p2, "*") == 0) {
  214. *flags |= F_ALLDAY;
  215. goto allfine;
  216. }
  217. if (checkdayofweek(p2, &len, &offset, &dow) != 0) {
  218. *flags |= F_DAYOFWEEK;
  219. *flags |= F_VARIABLE;
  220. *idayofweek = offset;
  221. strcpy(dayofweek, getdayofweekname(offset));
  222. if (strlen(p2) == len)
  223. goto allfine;
  224. strcpy(modifierindex, p2 + len);
  225. *flags |= F_MODIFIERINDEX;
  226. goto allfine;
  227. }
  228. goto fail;
  229. }
  230. /* Check if there is an every-day or every-month in the string */
  231. if ((strcmp(p1, "*") == 0 && isonlydigits(p2, 1))
  232. || (strcmp(p2, "*") == 0 && isonlydigits(p1, 1) && (p2 = p1))) {
  233. int d;
  234. *flags |= F_ALLMONTH;
  235. *flags |= F_DAYOFMONTH;
  236. d = (int)strtol(p2, (char **)NULL, 10);
  237. *idayofmonth = d;
  238. sprintf(dayofmonth, "%d", d);
  239. goto allfine;
  240. }
  241. /* Month as a number, then a weekday */
  242. if (isonlydigits(p1, 1)
  243. && checkdayofweek(p2, &len, &offset, &dow) != 0) {
  244. int d;
  245. *flags |= F_MONTH;
  246. *flags |= F_DAYOFWEEK;
  247. *flags |= F_VARIABLE;
  248. *idayofweek = offset;
  249. d = (int)strtol(p1, (char **)NULL, 10);
  250. *imonth = d;
  251. strcpy(month, getmonthname(d));
  252. strcpy(dayofweek, getdayofweekname(offset));
  253. if (strlen(p2) == len)
  254. goto allfine;
  255. strcpy(modifierindex, p2 + len);
  256. *flags |= F_MODIFIERINDEX;
  257. goto allfine;
  258. }
  259. /* If both the month and date are specified as numbers */
  260. if (isonlydigits(p1, 1) && isonlydigits(p2, 0)) {
  261. /* Now who wants to be this ambigious? :-( */
  262. int m, d;
  263. if (strchr(p2, '*') != NULL)
  264. *flags |= F_VARIABLE;
  265. m = (int)strtol(p1, (char **)NULL, 10);
  266. d = (int)strtol(p2, (char **)NULL, 10);
  267. *flags |= F_MONTH;
  268. *flags |= F_DAYOFMONTH;
  269. if (m > 12) {
  270. *imonth = d;
  271. *idayofmonth = m;
  272. strcpy(month, getmonthname(d));
  273. sprintf(dayofmonth, "%d", m);
  274. } else {
  275. *imonth = m;
  276. *idayofmonth = d;
  277. strcpy(month, getmonthname(m));
  278. sprintf(dayofmonth, "%d", d);
  279. }
  280. goto allfine;
  281. }
  282. /* FALLTHROUGH */
  283. fail:
  284. *p = pold;
  285. return (0);
  286. allfine:
  287. *p = pold;
  288. return (1);
  289. }
  290. static void
  291. remember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
  292. int dd, char *extra)
  293. {
  294. static int warned = 0;
  295. if (*rememberindex >= MAXCOUNT - 1) {
  296. if (warned == 0)
  297. warnx("Index > %d, ignored", MAXCOUNT);
  298. warned++;
  299. return;
  300. }
  301. y[*rememberindex] = yy;
  302. m[*rememberindex] = mm;
  303. d[*rememberindex] = dd;
  304. if (extra != NULL)
  305. strcpy(ed[*rememberindex], extra);
  306. else
  307. ed[*rememberindex][0] = '\0';
  308. *rememberindex += 1;
  309. }
  310. static void
  311. debug_determinestyle(int dateonly, char *date, int flags, char *month,
  312. int imonth, char *dayofmonth, int idayofmonth, char *dayofweek,
  313. int idayofweek, char *modifieroffset, char *modifierindex, char *specialday,
  314. char *year, int iyear)
  315. {
  316. if (dateonly != 0) {
  317. printf("-------\ndate: |%s|\n", date);
  318. if (dateonly == 1)
  319. return;
  320. }
  321. printf("flags: %x - %s\n", flags, showflags(flags));
  322. if (modifieroffset[0] != '\0')
  323. printf("modifieroffset: |%s|\n", modifieroffset);
  324. if (modifierindex[0] != '\0')
  325. printf("modifierindex: |%s|\n", modifierindex);
  326. if (year[0] != '\0')
  327. printf("year: |%s| (%d)\n", year, iyear);
  328. if (month[0] != '\0')
  329. printf("month: |%s| (%d)\n", month, imonth);
  330. if (dayofmonth[0] != '\0')
  331. printf("dayofmonth: |%s| (%d)\n", dayofmonth, idayofmonth);
  332. if (dayofweek[0] != '\0')
  333. printf("dayofweek: |%s| (%d)\n", dayofweek, idayofweek);
  334. if (specialday[0] != '\0')
  335. printf("specialday: |%s|\n", specialday);
  336. }
  337. struct yearinfo {
  338. int year;
  339. int ieaster, ipaskha, firstcnyday;
  340. double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
  341. double ffullmooncny[MAXMOONS], fnewmooncny[MAXMOONS];
  342. int ichinesemonths[MAXMOONS];
  343. double equinoxdays[2], solsticedays[2];
  344. int *mondays;
  345. struct yearinfo *next;
  346. };
  347. /*
  348. * Possible date formats include any combination of:
  349. * 3-charmonth (January, Jan, Jan)
  350. * 3-charweekday (Friday, Monday, mon.)
  351. * numeric month or day (1, 2, 04)
  352. *
  353. * Any character may separate them, or they may not be separated. Any line,
  354. * following a line that is matched, that starts with "whitespace", is shown
  355. * along with the matched line.
  356. */
  357. int
  358. parsedaymonth(char *date, int *yearp, int *monthp, int *dayp, int *flags,
  359. char **edp)
  360. {
  361. char month[100], dayofmonth[100], dayofweek[100], modifieroffset[100];
  362. char syear[100];
  363. char modifierindex[100], specialday[100];
  364. int idayofweek = -1, imonth = -1, idayofmonth = -1, iyear = -1;
  365. int year, remindex;
  366. int d, m, dow, rm, rd, offset;
  367. char *ed;
  368. int retvalsign = 1;
  369. static struct yearinfo *years, *yearinfo;
  370. /*
  371. * CONVENTION
  372. *
  373. * Month: 1-12
  374. * Monthname: Jan .. Dec
  375. * Day: 1-31
  376. * Weekday: Mon .. Sun
  377. *
  378. */
  379. *flags = 0;
  380. if (debug)
  381. debug_determinestyle(1, date, *flags, month, imonth,
  382. dayofmonth, idayofmonth, dayofweek, idayofweek,
  383. modifieroffset, modifierindex, specialday, syear, iyear);
  384. if (determinestyle(date, flags, month, &imonth, dayofmonth,
  385. &idayofmonth, dayofweek, &idayofweek, modifieroffset,
  386. modifierindex, specialday, syear, &iyear) == 0) {
  387. if (debug)
  388. printf("Failed!\n");
  389. return (0);
  390. }
  391. if (debug)
  392. debug_determinestyle(0, date, *flags, month, imonth,
  393. dayofmonth, idayofmonth, dayofweek, idayofweek,
  394. modifieroffset, modifierindex, specialday, syear, iyear);
  395. remindex = 0;
  396. for (year = year1; year <= year2; year++) {
  397. int lflags = *flags;
  398. /* If the year is specified, only do it if it is this year! */
  399. if ((lflags & F_YEAR) != 0)
  400. if (iyear != year)
  401. continue;
  402. lflags &= ~F_YEAR;
  403. /* Get important dates for this year */
  404. yearinfo = years;
  405. while (yearinfo != NULL) {
  406. if (yearinfo->year == year)
  407. break;
  408. yearinfo = yearinfo -> next;
  409. }
  410. if (yearinfo == NULL) {
  411. yearinfo = (struct yearinfo *)calloc(1,
  412. sizeof(struct yearinfo));
  413. if (yearinfo == NULL)
  414. errx(1, "Unable to allocate more years");
  415. yearinfo->year = year;
  416. yearinfo->next = years;
  417. years = yearinfo;
  418. yearinfo->mondays = mondaytab[isleap(year)];
  419. yearinfo->ieaster = easter(year);
  420. yearinfo->ipaskha = paskha(year);
  421. fpom(year, UTCOffset, yearinfo->ffullmoon,
  422. yearinfo->fnewmoon);
  423. fpom(year, UTCOFFSET_CNY, yearinfo->ffullmooncny,
  424. yearinfo->fnewmooncny);
  425. fequinoxsolstice(year, UTCOffset,
  426. yearinfo->equinoxdays, yearinfo->solsticedays);
  427. /*
  428. * CNY: Match day with sun longitude at 330` with new
  429. * moon
  430. */
  431. yearinfo->firstcnyday = calculatesunlongitude30(year,
  432. UTCOFFSET_CNY, yearinfo->ichinesemonths);
  433. for (m = 0; yearinfo->fnewmooncny[m] >= 0; m++) {
  434. if (yearinfo->fnewmooncny[m] >
  435. yearinfo->firstcnyday) {
  436. yearinfo->firstcnyday =
  437. floor(yearinfo->fnewmooncny[m - 1]);
  438. break;
  439. }
  440. }
  441. }
  442. /* Same day every year */
  443. if (lflags == (F_MONTH | F_DAYOFMONTH)) {
  444. if (!remember_ymd(year, imonth, idayofmonth))
  445. continue;
  446. remember(&remindex, yearp, monthp, dayp, edp,
  447. year, imonth, idayofmonth, NULL);
  448. continue;
  449. }
  450. /* XXX Same day every year, but variable */
  451. if (lflags == (F_MONTH | F_DAYOFMONTH | F_VARIABLE)) {
  452. if (!remember_ymd(year, imonth, idayofmonth))
  453. continue;
  454. remember(&remindex, yearp, monthp, dayp, edp,
  455. year, imonth, idayofmonth, NULL);
  456. continue;
  457. }
  458. /* Same day every month */
  459. if (lflags == (F_ALLMONTH | F_DAYOFMONTH)) {
  460. for (m = 1; m <= 12; m++) {
  461. if (!remember_ymd(year, m, idayofmonth))
  462. continue;
  463. remember(&remindex, yearp, monthp, dayp, edp,
  464. year, m, idayofmonth, NULL);
  465. }
  466. continue;
  467. }
  468. /* Every day of a month */
  469. if (lflags == (F_ALLDAY | F_MONTH)) {
  470. for (d = 1; d <= yearinfo->mondays[imonth]; d++) {
  471. if (!remember_ymd(year, imonth, d))
  472. continue;
  473. remember(&remindex, yearp, monthp, dayp, edp,
  474. year, imonth, d, NULL);
  475. }
  476. continue;
  477. }
  478. /* One day of every month */
  479. if (lflags == (F_ALLMONTH | F_DAYOFWEEK)) {
  480. for (m = 1; m <= 12; m++) {
  481. if (!remember_ymd(year, m, idayofmonth))
  482. continue;
  483. remember(&remindex, yearp, monthp, dayp, edp,
  484. year, m, idayofmonth, NULL);
  485. }
  486. continue;
  487. }
  488. /* Every dayofweek of the year */
  489. if (lflags == (F_DAYOFWEEK | F_VARIABLE)) {
  490. dow = first_dayofweek_of_year(year);
  491. d = (idayofweek - dow + 8) % 7;
  492. while (d <= 366) {
  493. if (remember_yd(year, d, &rm, &rd))
  494. remember(&remindex,
  495. yearp, monthp, dayp, edp,
  496. year, rm, rd, NULL);
  497. d += 7;
  498. }
  499. continue;
  500. }
  501. /* Every so-manied dayofweek of every month of the year */
  502. if (lflags == (F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
  503. offset = indextooffset(modifierindex);
  504. for (m = 0; m < 12; m++) {
  505. dow = first_dayofweek_of_month(year, m);
  506. d = (idayofweek - dow + 8) % 7;
  507. d += (offset - 1) * 7;
  508. if (remember_ymd(year, m, d)) {
  509. remember(&remindex,
  510. yearp, monthp, dayp, edp,
  511. year, m, d, NULL);
  512. continue;
  513. }
  514. }
  515. continue;
  516. }
  517. /* A certain dayofweek of a month */
  518. if (lflags ==
  519. (F_MONTH | F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
  520. offset = indextooffset(modifierindex);
  521. dow = first_dayofweek_of_month(year, imonth);
  522. d = (idayofweek - dow + 8) % 7;
  523. if (offset > 0) {
  524. while (d <= yearinfo->mondays[imonth]) {
  525. if (--offset == 0
  526. && remember_ymd(year, imonth, d)) {
  527. remember(&remindex,
  528. yearp, monthp, dayp, edp,
  529. year, imonth, d, NULL);
  530. continue;
  531. }
  532. d += 7;
  533. }
  534. continue;
  535. }
  536. if (offset < 0) {
  537. while (d <= yearinfo->mondays[imonth])
  538. d += 7;
  539. while (offset != 0) {
  540. offset++;
  541. d -= 7;
  542. }
  543. if (remember_ymd(year, imonth, d))
  544. remember(&remindex,
  545. yearp, monthp, dayp, edp,
  546. year, imonth, d, NULL);
  547. continue;
  548. }
  549. continue;
  550. }
  551. /* Every dayofweek of the month */
  552. if (lflags == (F_DAYOFWEEK | F_MONTH | F_VARIABLE)) {
  553. dow = first_dayofweek_of_month(year, imonth);
  554. d = (idayofweek - dow + 8) % 7;
  555. while (d <= yearinfo->mondays[imonth]) {
  556. if (remember_ymd(year, imonth, d))
  557. remember(&remindex,
  558. yearp, monthp, dayp, edp,
  559. year, imonth, d, NULL);
  560. d += 7;
  561. }
  562. continue;
  563. }
  564. /* Easter */
  565. if ((lflags & ~F_MODIFIEROFFSET) ==
  566. (F_SPECIALDAY | F_VARIABLE | F_EASTER)) {
  567. offset = 0;
  568. if ((lflags & F_MODIFIEROFFSET) != 0)
  569. offset = parseoffset(modifieroffset);
  570. if (remember_yd(year, yearinfo->ieaster + offset,
  571. &rm, &rd))
  572. remember(&remindex, yearp, monthp, dayp, edp,
  573. year, rm, rd, NULL);
  574. continue;
  575. }
  576. /* Paskha */
  577. if ((lflags & ~F_MODIFIEROFFSET) ==
  578. (F_SPECIALDAY | F_VARIABLE | F_PASKHA)) {
  579. offset = 0;
  580. if ((lflags & F_MODIFIEROFFSET) != 0)
  581. offset = parseoffset(modifieroffset);
  582. if (remember_yd(year, yearinfo->ipaskha + offset,
  583. &rm, &rd))
  584. remember(&remindex, yearp, monthp, dayp, edp,
  585. year, rm, rd, NULL);
  586. continue;
  587. }
  588. /* Chinese New Year */
  589. if ((lflags & ~F_MODIFIEROFFSET) ==
  590. (F_SPECIALDAY | F_VARIABLE | F_CNY)) {
  591. offset = 0;
  592. if ((lflags & F_MODIFIEROFFSET) != 0)
  593. offset = parseoffset(modifieroffset);
  594. if (remember_yd(year, yearinfo->firstcnyday + offset,
  595. &rm, &rd))
  596. remember(&remindex, yearp, monthp, dayp, edp,
  597. year, rm, rd, NULL);
  598. continue;
  599. }
  600. /* FullMoon */
  601. if ((lflags & ~F_MODIFIEROFFSET) ==
  602. (F_SPECIALDAY | F_VARIABLE | F_FULLMOON)) {
  603. int i;
  604. offset = 0;
  605. if ((lflags & F_MODIFIEROFFSET) != 0)
  606. offset = parseoffset(modifieroffset);
  607. for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
  608. if (remember_yd(year,
  609. floor(yearinfo->ffullmoon[i]) + offset,
  610. &rm, &rd)) {
  611. ed = floattotime(
  612. yearinfo->ffullmoon[i]);
  613. remember(&remindex,
  614. yearp, monthp, dayp, edp,
  615. year, rm, rd, ed);
  616. }
  617. }
  618. continue;
  619. }
  620. /* NewMoon */
  621. if ((lflags & ~F_MODIFIEROFFSET) ==
  622. (F_SPECIALDAY | F_VARIABLE | F_NEWMOON)) {
  623. int i;
  624. offset = 0;
  625. if ((lflags & F_MODIFIEROFFSET) != 0)
  626. offset = parseoffset(modifieroffset);
  627. for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
  628. if (remember_yd(year,
  629. floor(yearinfo->fnewmoon[i]) + offset,
  630. &rm, &rd)) {
  631. ed = floattotime(yearinfo->fnewmoon[i]);
  632. remember(&remindex,
  633. yearp, monthp, dayp, edp,
  634. year, rm, rd, ed);
  635. }
  636. }
  637. continue;
  638. }
  639. /* (Mar|Sep)Equinox */
  640. if ((lflags & ~F_MODIFIEROFFSET) ==
  641. (F_SPECIALDAY | F_VARIABLE | F_MAREQUINOX)) {
  642. offset = 0;
  643. if ((lflags & F_MODIFIEROFFSET) != 0)
  644. offset = parseoffset(modifieroffset);
  645. if (remember_yd(year, yearinfo->equinoxdays[0] + offset,
  646. &rm, &rd)) {
  647. ed = floattotime(yearinfo->equinoxdays[0]);
  648. remember(&remindex, yearp, monthp, dayp, edp,
  649. year, rm, rd, ed);
  650. }
  651. continue;
  652. }
  653. if ((lflags & ~F_MODIFIEROFFSET) ==
  654. (F_SPECIALDAY | F_VARIABLE | F_SEPEQUINOX)) {
  655. offset = 0;
  656. if ((lflags & F_MODIFIEROFFSET) != 0)
  657. offset = parseoffset(modifieroffset);
  658. if (remember_yd(year, yearinfo->equinoxdays[1] + offset,
  659. &rm, &rd)) {
  660. ed = floattotime(yearinfo->equinoxdays[1]);
  661. remember(&remindex, yearp, monthp, dayp, edp,
  662. year, rm, rd, ed);
  663. }
  664. continue;
  665. }
  666. /* (Jun|Dec)Solstice */
  667. if ((lflags & ~F_MODIFIEROFFSET) ==
  668. (F_SPECIALDAY | F_VARIABLE | F_JUNSOLSTICE)) {
  669. offset = 0;
  670. if ((lflags & F_MODIFIEROFFSET) != 0)
  671. offset = parseoffset(modifieroffset);
  672. if (remember_yd(year,
  673. yearinfo->solsticedays[0] + offset, &rm, &rd)) {
  674. ed = floattotime(yearinfo->solsticedays[0]);
  675. remember(&remindex, yearp, monthp, dayp, edp,
  676. year, rm, rd, ed);
  677. }
  678. continue;
  679. }
  680. if ((lflags & ~F_MODIFIEROFFSET) ==
  681. (F_SPECIALDAY | F_VARIABLE | F_DECSOLSTICE)) {
  682. offset = 0;
  683. if ((lflags & F_MODIFIEROFFSET) != 0)
  684. offset = parseoffset(modifieroffset);
  685. if (remember_yd(year,
  686. yearinfo->solsticedays[1] + offset, &rm, &rd)) {
  687. ed = floattotime(yearinfo->solsticedays[1]);
  688. remember(&remindex, yearp, monthp, dayp, edp,
  689. year, rm, rd, ed);
  690. }
  691. continue;
  692. }
  693. if (debug) {
  694. printf("Unprocessed:\n");
  695. debug_determinestyle(2, date, lflags, month, imonth,
  696. dayofmonth, idayofmonth, dayofweek, idayofweek,
  697. modifieroffset, modifierindex, specialday, syear,
  698. iyear);
  699. }
  700. retvalsign = -1;
  701. }
  702. if (retvalsign == -1)
  703. return (-remindex - 1);
  704. else
  705. return (remindex);
  706. }
  707. static char *
  708. showflags(int flags)
  709. {
  710. static char s[1000];
  711. s[0] = '\0';
  712. if ((flags & F_YEAR) != 0)
  713. strcat(s, "year ");
  714. if ((flags & F_MONTH) != 0)
  715. strcat(s, "month ");
  716. if ((flags & F_DAYOFWEEK) != 0)
  717. strcat(s, "dayofweek ");
  718. if ((flags & F_DAYOFMONTH) != 0)
  719. strcat(s, "dayofmonth ");
  720. if ((flags & F_MODIFIERINDEX) != 0)
  721. strcat(s, "modifierindex ");
  722. if ((flags & F_MODIFIEROFFSET) != 0)
  723. strcat(s, "modifieroffset ");
  724. if ((flags & F_SPECIALDAY) != 0)
  725. strcat(s, "specialday ");
  726. if ((flags & F_ALLMONTH) != 0)
  727. strcat(s, "allmonth ");
  728. if ((flags & F_ALLDAY) != 0)
  729. strcat(s, "allday ");
  730. if ((flags & F_VARIABLE) != 0)
  731. strcat(s, "variable ");
  732. if ((flags & F_CNY) != 0)
  733. strcat(s, "chinesenewyear ");
  734. if ((flags & F_PASKHA) != 0)
  735. strcat(s, "paskha ");
  736. if ((flags & F_EASTER) != 0)
  737. strcat(s, "easter ");
  738. if ((flags & F_FULLMOON) != 0)
  739. strcat(s, "fullmoon ");
  740. if ((flags & F_NEWMOON) != 0)
  741. strcat(s, "newmoon ");
  742. if ((flags & F_MAREQUINOX) != 0)
  743. strcat(s, "marequinox ");
  744. if ((flags & F_SEPEQUINOX) != 0)
  745. strcat(s, "sepequinox ");
  746. if ((flags & F_JUNSOLSTICE) != 0)
  747. strcat(s, "junsolstice ");
  748. if ((flags & F_DECSOLSTICE) != 0)
  749. strcat(s, "decsolstice ");
  750. return s;
  751. }
  752. static const char *
  753. getmonthname(int i)
  754. {
  755. if (i <= 0 || i > 12)
  756. return ("");
  757. if (nmonths[i - 1].len != 0 && nmonths[i - 1].name != NULL)
  758. return (nmonths[i - 1].name);
  759. return (months[i - 1]);
  760. }
  761. static int
  762. checkmonth(char *s, size_t *len, size_t *offset, const char **month)
  763. {
  764. struct fixs *n;
  765. int i;
  766. for (i = 0; fnmonths[i].name != NULL; i++) {
  767. n = fnmonths + i;
  768. if (strncasecmp(s, n->name, n->len) == 0) {
  769. *len = n->len;
  770. *month = n->name;
  771. *offset = i + 1;
  772. return (1);
  773. }
  774. }
  775. for (i = 0; nmonths[i].name != NULL; i++) {
  776. n = nmonths + i;
  777. if (strncasecmp(s, n->name, n->len) == 0) {
  778. *len = n->len;
  779. *month = n->name;
  780. *offset = i + 1;
  781. return (1);
  782. }
  783. }
  784. for (i = 0; fmonths[i] != NULL; i++) {
  785. *len = strlen(fmonths[i]);
  786. if (strncasecmp(s, fmonths[i], *len) == 0) {
  787. *month = fmonths[i];
  788. *offset = i + 1;
  789. return (1);
  790. }
  791. }
  792. for (i = 0; months[i] != NULL; i++) {
  793. if (strncasecmp(s, months[i], 3) == 0) {
  794. *len = 3;
  795. *month = months[i];
  796. *offset = i + 1;
  797. return (1);
  798. }
  799. }
  800. return (0);
  801. }
  802. static const char *
  803. getdayofweekname(int i)
  804. {
  805. if (ndays[i].len != 0 && ndays[i].name != NULL)
  806. return (ndays[i].name);
  807. return (days[i]);
  808. }
  809. static int
  810. checkdayofweek(char *s, size_t *len, size_t *offset, const char **dow)
  811. {
  812. struct fixs *n;
  813. int i;
  814. for (i = 0; fndays[i].name != NULL; i++) {
  815. n = fndays + i;
  816. if (strncasecmp(s, n->name, n->len) == 0) {
  817. *len = n->len;
  818. *dow = n->name;
  819. *offset = i;
  820. return (1);
  821. }
  822. }
  823. for (i = 0; ndays[i].name != NULL; i++) {
  824. n = ndays + i;
  825. if (strncasecmp(s, n->name, n->len) == 0) {
  826. *len = n->len;
  827. *dow = n->name;
  828. *offset = i;
  829. return (1);
  830. }
  831. }
  832. for (i = 0; fdays[i] != NULL; i++) {
  833. *len = strlen(fdays[i]);
  834. if (strncasecmp(s, fdays[i], *len) == 0) {
  835. *dow = fdays[i];
  836. *offset = i;
  837. return (1);
  838. }
  839. }
  840. for (i = 0; days[i] != NULL; i++) {
  841. if (strncasecmp(s, days[i], 3) == 0) {
  842. *len = 3;
  843. *dow = days[i];
  844. *offset = i;
  845. return (1);
  846. }
  847. }
  848. return (0);
  849. }
  850. static int
  851. isonlydigits(char *s, int nostar)
  852. {
  853. int i;
  854. for (i = 0; s[i] != '\0'; i++) {
  855. if (nostar == 0 && s[i] == '*' && s[i + 1] == '\0')
  856. return 1;
  857. if (!isdigit((unsigned char)s[i]))
  858. return (0);
  859. }
  860. return (1);
  861. }
  862. static int
  863. indextooffset(char *s)
  864. {
  865. int i;
  866. struct fixs *n;
  867. if (s[0] == '+' || s[0] == '-') {
  868. char ss[9];
  869. for (i = -100; i < 100; i++) {
  870. sprintf(ss, "%s%d", (i > 0) ? "+" : "", i);
  871. if (strcmp(ss, s) == 0)
  872. return (i);
  873. }
  874. return (0);
  875. }
  876. for (i = 0; i < 6; i++) {
  877. if (strcasecmp(s, sequences[i]) == 0) {
  878. if (i == 5)
  879. return (-1);
  880. return (i + 1);
  881. }
  882. }
  883. for (i = 0; i < 6; i++) {
  884. n = nsequences + i;
  885. if (n->len == 0)
  886. continue;
  887. if (strncasecmp(s, n->name, n->len) == 0) {
  888. if (i == 5)
  889. return (-1);
  890. return (i + 1);
  891. }
  892. }
  893. return (0);
  894. }
  895. static int
  896. parseoffset(char *s)
  897. {
  898. return strtol(s, NULL, 10);
  899. }
  900. static char *
  901. floattotime(double f)
  902. {
  903. static char buf[100];
  904. int hh, mm, ss, i;
  905. f -= floor(f);
  906. i = f * SECSPERDAY;
  907. hh = i / SECSPERHOUR;
  908. i %= SECSPERHOUR;
  909. mm = i / SECSPERMINUTE;
  910. i %= SECSPERMINUTE;
  911. ss = i;
  912. sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
  913. return (buf);
  914. }
  915. static char *
  916. floattoday(int year, double f)
  917. {
  918. static char buf[100];
  919. int i, m, d, hh, mm, ss;
  920. int *cumdays = cumdaytab[isleap(year)];
  921. for (i = 0; 1 + cumdays[i] < f; i++)
  922. ;
  923. m = --i;
  924. d = floor(f - 1 - cumdays[i]);
  925. f -= floor(f);
  926. i = f * SECSPERDAY;
  927. hh = i / SECSPERHOUR;
  928. i %= SECSPERHOUR;
  929. mm = i / SECSPERMINUTE;
  930. i %= SECSPERMINUTE;
  931. ss = i;
  932. sprintf(buf, "%02d-%02d %02d:%02d:%02d", m, d, hh, mm, ss);
  933. return (buf);
  934. }
  935. void
  936. dodebug(char *what)
  937. {
  938. int year;
  939. printf("UTCOffset: %g\n", UTCOffset);
  940. printf("eastlongitude: %d\n", EastLongitude);
  941. if (strcmp(what, "moon") == 0) {
  942. double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
  943. int i;
  944. for (year = year1; year <= year2; year++) {
  945. fpom(year, UTCOffset, ffullmoon, fnewmoon);
  946. printf("Full moon %d:\t", year);
  947. for (i = 0; ffullmoon[i] >= 0; i++) {
  948. printf("%g (%s) ", ffullmoon[i],
  949. floattoday(year, ffullmoon[i]));
  950. }
  951. printf("\nNew moon %d:\t", year);
  952. for (i = 0; fnewmoon[i] >= 0; i++) {
  953. printf("%g (%s) ", fnewmoon[i],
  954. floattoday(year, fnewmoon[i]));
  955. }
  956. printf("\n");
  957. }
  958. return;
  959. }
  960. if (strcmp(what, "sun") == 0) {
  961. double equinoxdays[2], solsticedays[2];
  962. for (year = year1; year <= year2; year++) {
  963. printf("Sun in %d:\n", year);
  964. fequinoxsolstice(year, UTCOffset, equinoxdays,
  965. solsticedays);
  966. printf("e[0] - %g (%s)\n",
  967. equinoxdays[0],
  968. floattoday(year, equinoxdays[0]));
  969. printf("e[1] - %g (%s)\n",
  970. equinoxdays[1],
  971. floattoday(year, equinoxdays[1]));
  972. printf("s[0] - %g (%s)\n",
  973. solsticedays[0],
  974. floattoday(year, solsticedays[0]));
  975. printf("s[1] - %g (%s)\n",
  976. solsticedays[1],
  977. floattoday(year, solsticedays[1]));
  978. }
  979. return;
  980. }
  981. }