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