1: /*
   2:  *	@(#)zic.c	1.1 zic.c 3/4/87
   3:  */
   4: 
   5: #include "stdio.h"
   6: #include "ctype.h"
   7: #include "sys/types.h"
   8: #include "sys/stat.h"
   9: #include "sys/file.h"
  10: #include "strings.h"
  11: #include "time.h"
  12: #include "tzfile.h"
  13: 
  14: #ifndef BUFSIZ
  15: #define BUFSIZ  1024
  16: #endif
  17: 
  18: #ifndef TRUE
  19: #define TRUE    1
  20: #define FALSE   0
  21: #endif
  22: 
  23: extern char *   icpyalloc();
  24: extern char *   imalloc();
  25: extern char *   irealloc();
  26: extern char *   optarg;
  27: extern int  optind;
  28: extern char *   scheck();
  29: extern char *   sprintf();
  30: 
  31: static      addtt();
  32: static      addtype();
  33: static      associate();
  34: static int  charcnt;
  35: static      ciequal();
  36: static long eitol();
  37: static int  errors;
  38: static char *   filename;
  39: static char **  getfields();
  40: static long gethms();
  41: static      infile();
  42: static      inlink();
  43: static      inrule();
  44: static      inzcont();
  45: static      inzone();
  46: static      inzsub();
  47: static int  linenum;
  48: static      lowerit();
  49: static time_t   max_time;
  50: static int  max_year;
  51: static time_t   min_time;
  52: static int  min_year;
  53: static      mkdirs();
  54: static      newabbr();
  55: static int  noise;
  56: static      nondunlink();
  57: static long oadd();
  58: static      outzone();
  59: static char *   progname;
  60: static char *   rfilename;
  61: static int  rlinenum;
  62: static time_t   rpytime();
  63: static      rulesub();
  64: static      setboundaries();
  65: static time_t   tadd();
  66: static int  timecnt;
  67: static int  tt_signed;
  68: static int  typecnt;
  69: static      yearistype();
  70: 
  71: /*
  72: ** Line codes.
  73: */
  74: 
  75: #define LC_RULE     0
  76: #define LC_ZONE     1
  77: #define LC_LINK     2
  78: 
  79: /*
  80: ** Which fields are which on a Zone line.
  81: */
  82: 
  83: #define ZF_NAME     1
  84: #define ZF_GMTOFF   2
  85: #define ZF_RULE     3
  86: #define ZF_FORMAT   4
  87: #define ZF_UNTILYEAR    5
  88: #define ZF_UNTILMONTH   6
  89: #define ZF_UNTILDAY 7
  90: #define ZF_UNTILTIME    8
  91: #define ZONE_MINFIELDS  5
  92: #define ZONE_MAXFIELDS  9
  93: 
  94: /*
  95: ** Which fields are which on a Zone continuation line.
  96: */
  97: 
  98: #define ZFC_GMTOFF  0
  99: #define ZFC_RULE    1
 100: #define ZFC_FORMAT  2
 101: #define ZFC_UNTILYEAR   3
 102: #define ZFC_UNTILMONTH  4
 103: #define ZFC_UNTILDAY    5
 104: #define ZFC_UNTILTIME   6
 105: #define ZONEC_MINFIELDS 3
 106: #define ZONEC_MAXFIELDS 7
 107: 
 108: /*
 109: ** Which files are which on a Rule line.
 110: */
 111: 
 112: #define RF_NAME     1
 113: #define RF_LOYEAR   2
 114: #define RF_HIYEAR   3
 115: #define RF_COMMAND  4
 116: #define RF_MONTH    5
 117: #define RF_DAY      6
 118: #define RF_TOD      7
 119: #define RF_STDOFF   8
 120: #define RF_ABBRVAR  9
 121: #define RULE_FIELDS 10
 122: 
 123: /*
 124: ** Which fields are which on a Link line.
 125: */
 126: 
 127: #define LF_FROM     1
 128: #define LF_TO       2
 129: #define LINK_FIELDS 3
 130: 
 131: struct rule {
 132:     char *  r_filename;
 133:     int r_linenum;
 134:     char *  r_name;
 135: 
 136:     int r_loyear;   /* for example, 1986 */
 137:     int r_hiyear;   /* for example, 1986 */
 138:     char *  r_yrtype;
 139: 
 140:     int r_month;    /* 0..11 */
 141: 
 142:     int r_dycode;   /* see below */
 143:     int r_dayofmonth;
 144:     int r_wday;
 145: 
 146:     long    r_tod;      /* time from midnight */
 147:     int r_todisstd; /* above is standard time if TRUE */
 148:                 /* above is wall clock time if FALSE */
 149:     long    r_stdoff;   /* offset from standard time */
 150:     char *  r_abbrvar;  /* variable part of time zone abbreviation */
 151: 
 152:     int r_todo;     /* a rule to do (used in outzone) */
 153:     time_t  r_temp;     /* used in outzone */
 154: };
 155: 
 156: /*
 157: **	r_dycode		r_dayofmonth	r_wday
 158: */
 159: #define DC_DOM      0   /* 1..31 */ /* unused */
 160: #define DC_DOWGEQ   1   /* 1..31 */ /* 0..6 (Sun..Sat) */
 161: #define DC_DOWLEQ   2   /* 1..31 */ /* 0..6 (Sun..Sat) */
 162: 
 163: /*
 164: ** Year synonyms.
 165: */
 166: 
 167: #define YR_MINIMUM  0
 168: #define YR_MAXIMUM  1
 169: #define YR_ONLY     2
 170: 
 171: static struct rule *    rules;
 172: static int      nrules; /* number of rules */
 173: 
 174: struct zone {
 175:     char *      z_filename;
 176:     int     z_linenum;
 177: 
 178:     char *      z_name;
 179:     long        z_gmtoff;
 180:     char *      z_rule;
 181:     char *      z_format;
 182: 
 183:     long        z_stdoff;
 184: 
 185:     struct rule *   z_rules;
 186:     int     z_nrules;
 187: 
 188:     struct rule z_untilrule;
 189:     time_t      z_untiltime;
 190: };
 191: 
 192: static struct zone *    zones;
 193: static int      nzones; /* number of zones */
 194: 
 195: struct link {
 196:     char *      l_filename;
 197:     int     l_linenum;
 198:     char *      l_from;
 199:     char *      l_to;
 200: };
 201: 
 202: static struct link *    links;
 203: static int      nlinks;
 204: 
 205: struct lookup {
 206:     char *      l_word;
 207:     int     l_value;
 208: };
 209: 
 210: static struct lookup *  byword();
 211: 
 212: static struct lookup    line_codes[] = {
 213:     "Rule",     LC_RULE,
 214:     "Zone",     LC_ZONE,
 215:     "Link",     LC_LINK,
 216:     NULL,       0
 217: };
 218: 
 219: static struct lookup    mon_names[] = {
 220:     "January",  TM_JANUARY,
 221:     "February", TM_FEBRUARY,
 222:     "March",    TM_MARCH,
 223:     "April",    TM_APRIL,
 224:     "May",      TM_MAY,
 225:     "June",     TM_JUNE,
 226:     "July",     TM_JULY,
 227:     "August",   TM_AUGUST,
 228:     "September",    TM_SEPTEMBER,
 229:     "October",  TM_OCTOBER,
 230:     "November", TM_NOVEMBER,
 231:     "December", TM_DECEMBER,
 232:     NULL,       0
 233: };
 234: 
 235: static struct lookup    wday_names[] = {
 236:     "Sunday",   TM_SUNDAY,
 237:     "Monday",   TM_MONDAY,
 238:     "Tuesday",  TM_TUESDAY,
 239:     "Wednesday",    TM_WEDNESDAY,
 240:     "Thursday", TM_THURSDAY,
 241:     "Friday",   TM_FRIDAY,
 242:     "Saturday", TM_SATURDAY,
 243:     NULL,       0
 244: };
 245: 
 246: static struct lookup    lasts[] = {
 247:     "last-Sunday",      TM_SUNDAY,
 248:     "last-Monday",      TM_MONDAY,
 249:     "last-Tuesday",     TM_TUESDAY,
 250:     "last-Wednesday",   TM_WEDNESDAY,
 251:     "last-Thursday",    TM_THURSDAY,
 252:     "last-Friday",      TM_FRIDAY,
 253:     "last-Saturday",    TM_SATURDAY,
 254:     NULL,           0
 255: };
 256: 
 257: static struct lookup    begin_years[] = {
 258:     "minimum",      YR_MINIMUM,
 259:     "maximum",      YR_MAXIMUM,
 260:     NULL,           0
 261: };
 262: 
 263: static struct lookup    end_years[] = {
 264:     "minimum",      YR_MINIMUM,
 265:     "maximum",      YR_MAXIMUM,
 266:     "only",         YR_ONLY,
 267:     NULL,           0
 268: };
 269: 
 270: static int  len_months[2][MONS_PER_YEAR] = {
 271:     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
 272:     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 273: };
 274: 
 275: static int  len_years[2] = {
 276:     DAYS_PER_NYEAR, DAYS_PER_LYEAR
 277: };
 278: 
 279: static time_t       ats[TZ_MAX_TIMES];
 280: static unsigned char    types[TZ_MAX_TIMES];
 281: static long     gmtoffs[TZ_MAX_TYPES];
 282: static char     isdsts[TZ_MAX_TYPES];
 283: static char     abbrinds[TZ_MAX_TYPES];
 284: static char     chars[TZ_MAX_CHARS];
 285: 
 286: /*
 287: ** Memory allocation.
 288: */
 289: 
 290: static char *
 291: memcheck(ptr)
 292: char *  ptr;
 293: {
 294:     if (ptr == NULL) {
 295:         perror(progname);
 296:         exit(1);
 297:     }
 298:     return ptr;
 299: }
 300: 
 301: #define emalloc(size)       memcheck(imalloc(size))
 302: #define erealloc(ptr, size) memcheck(irealloc(ptr, size))
 303: #define ecpyalloc(ptr)      memcheck(icpyalloc(ptr))
 304: 
 305: /*
 306: ** Error handling.
 307: */
 308: 
 309: static
 310: eats(name, num, rname, rnum)
 311: char *  name;
 312: char *  rname;
 313: {
 314:     filename = name;
 315:     linenum = num;
 316:     rfilename = rname;
 317:     rlinenum = rnum;
 318: }
 319: 
 320: static
 321: eat(name, num)
 322: char *  name;
 323: {
 324:     eats(name, num, (char *) NULL, -1);
 325: }
 326: 
 327: static
 328: error(string)
 329: char *  string;
 330: {
 331:     /*
 332: 	** Match the format of "cc" to allow sh users to
 333: 	** 	zic ... 2>&1 | error -t "*" -v
 334: 	** on BSD systems.
 335: 	*/
 336:     (void) fprintf(stderr, "\"%s\", line %d: %s",
 337:         filename, linenum, string);
 338:     if (rfilename != NULL)
 339:         (void) fprintf(stderr, " (rule from \"%s\", line %d)",
 340:             rfilename, rlinenum);
 341:     (void) fprintf(stderr, "\n");
 342:     ++errors;
 343: }
 344: 
 345: static
 346: usage()
 347: {
 348:     (void) fprintf(stderr,
 349: "%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n",
 350:         progname, progname);
 351:     exit(1);
 352: }
 353: 
 354: static char *   lcltime = NULL;
 355: static char *   directory = NULL;
 356: 
 357: main(argc, argv)
 358: int argc;
 359: char *  argv[];
 360: {
 361:     register int    i, j;
 362:     register int    c;
 363: 
 364: #ifdef unix
 365:     umask(umask(022) | 022);
 366: #endif
 367:     progname = argv[0];
 368:     while ((c = getopt(argc, argv, "d:l:v")) != EOF)
 369:         switch (c) {
 370:             default:
 371:                 usage();
 372:             case 'd':
 373:                 if (directory == NULL)
 374:                     directory = optarg;
 375:                 else {
 376:                     (void) fprintf(stderr,
 377: "%s: More than one -d option specified\n",
 378:                         progname);
 379:                     exit(1);
 380:                 }
 381:                 break;
 382:             case 'l':
 383:                 if (lcltime == NULL)
 384:                     lcltime = optarg;
 385:                 else {
 386:                     (void) fprintf(stderr,
 387: "%s: More than one -l option specified\n",
 388:                         progname);
 389:                     exit(1);
 390:                 }
 391:                 break;
 392:             case 'v':
 393:                 noise = TRUE;
 394:                 break;
 395:         }
 396:     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
 397:         usage();    /* usage message by request */
 398:     if (directory == NULL)
 399:         directory = TZDIR;
 400: 
 401:     setboundaries();
 402: 
 403:     zones = (struct zone *) emalloc(0);
 404:     rules = (struct rule *) emalloc(0);
 405:     links = (struct link *) emalloc(0);
 406:     for (i = optind; i < argc; ++i)
 407:         infile(argv[i]);
 408:     if (errors)
 409:         exit(1);
 410:     associate();
 411:     for (i = 0; i < nzones; i = j) {
 412:         /*
 413: 		 * Find the next non-continuation zone entry.
 414: 		 */
 415:         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
 416:             ;
 417:         outzone(&zones[i], j - i);
 418:     }
 419:     /*
 420: 	** We'll take the easy way out on this last part.
 421: 	*/
 422:     if (chdir(directory) != 0) {
 423:         (void) fprintf(stderr, "%s: Can't chdir to ", progname);
 424:         perror(directory);
 425:         exit(1);
 426:     }
 427:     for (i = 0; i < nlinks; ++i) {
 428:         nondunlink(links[i].l_to);
 429:         if (link(links[i].l_from, links[i].l_to) != 0) {
 430:             (void) fprintf(stderr, "%s: Can't link %s to ",
 431:                 progname, links[i].l_from);
 432:             perror(links[i].l_to);
 433:             exit(1);
 434:         }
 435:     }
 436:     if (lcltime != NULL) {
 437:         nondunlink(TZDEFAULT);
 438:         if (link(lcltime, TZDEFAULT) != 0) {
 439:             (void) fprintf(stderr, "%s: Can't link %s to ",
 440:                 progname, lcltime);
 441:             perror(TZDEFAULT);
 442:             exit(1);
 443:         }
 444:     }
 445:     exit((errors == 0) ? 0 : 1);
 446: }
 447: 
 448: static
 449: setboundaries()
 450: {
 451:     register time_t     bit;
 452: 
 453:     for (bit = 1; bit > 0; bit <<= 1)
 454:         ;
 455:     if (bit == 0) {     /* time_t is an unsigned type */
 456:         tt_signed = FALSE;
 457:         min_time = 0;
 458:         max_time = ~(time_t) 0;
 459:     } else {
 460:         tt_signed = TRUE;
 461:         min_time = bit;
 462:         max_time = bit;
 463:         ++max_time;
 464:         max_time = -max_time;
 465:     }
 466:     min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
 467:     max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
 468: }
 469: 
 470: /*
 471: ** We get to be careful here since there's a fair chance of root running us.
 472: */
 473: 
 474: static
 475: nondunlink(name)
 476: char *  name;
 477: {
 478:     struct stat s;
 479: 
 480:     if (stat(name, &s) != 0)
 481:         return;
 482:     if ((s.st_mode & S_IFMT) == S_IFDIR)
 483:         return;
 484:     (void) unlink(name);
 485: }
 486: 
 487: /*
 488: ** Associate sets of rules with zones.
 489: */
 490: 
 491: /*
 492: ** Sort by rule name.
 493: */
 494: 
 495: static
 496: rcomp(cp1, cp2)
 497: char *  cp1;
 498: char *  cp2;
 499: {
 500:     return strcmp(((struct rule *) cp1)->r_name,
 501:         ((struct rule *) cp2)->r_name);
 502: }
 503: 
 504: static
 505: associate()
 506: {
 507:     register struct zone *  zp;
 508:     register struct rule *  rp;
 509:     register int        base, out;
 510:     register int        i;
 511: 
 512:     if (nrules != 0)
 513:         (void) qsort((char *) rules, nrules, sizeof *rules, rcomp);
 514:     for (i = 0; i < nzones; ++i) {
 515:         zp = &zones[i];
 516:         zp->z_rules = NULL;
 517:         zp->z_nrules = 0;
 518:     }
 519:     for (base = 0; base < nrules; base = out) {
 520:         rp = &rules[base];
 521:         for (out = base + 1; out < nrules; ++out)
 522:             if (strcmp(rp->r_name, rules[out].r_name) != 0)
 523:                 break;
 524:         for (i = 0; i < nzones; ++i) {
 525:             zp = &zones[i];
 526:             if (strcmp(zp->z_rule, rp->r_name) != 0)
 527:                 continue;
 528:             zp->z_rules = rp;
 529:             zp->z_nrules = out - base;
 530:         }
 531:     }
 532:     for (i = 0; i < nzones; ++i) {
 533:         zp = &zones[i];
 534:         if (zp->z_nrules == 0) {
 535:             /*
 536: 			** Maybe we have a local standard time offset.
 537: 			*/
 538:             eat(zp->z_filename, zp->z_linenum);
 539:             zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
 540:             /*
 541: 			** Note, though, that if there's no rule,
 542: 			** a '%s' in the format is a bad thing.
 543: 			*/
 544:             if (index(zp->z_format, '%') != 0)
 545:                 error("%s in ruleless zone");
 546:         }
 547:     }
 548:     if (errors)
 549:         exit(1);
 550: }
 551: 
 552: static
 553: infile(name)
 554: char *  name;
 555: {
 556:     register FILE *         fp;
 557:     register char **        fields;
 558:     register char *         cp;
 559:     register struct lookup *    lp;
 560:     register int            nfields;
 561:     register int            wantcont;
 562:     register int            num;
 563:     char                buf[BUFSIZ];
 564: 
 565:     if (strcmp(name, "-") == 0) {
 566:         name = "standard input";
 567:         fp = stdin;
 568:     } else if ((fp = fopen(name, "r")) == NULL) {
 569:         (void) fprintf(stderr, "%s: Can't open ", progname);
 570:         perror(name);
 571:         exit(1);
 572:     }
 573:     wantcont = FALSE;
 574:     for (num = 1; ; ++num) {
 575:         eat(name, num);
 576:         if (fgets(buf, sizeof buf, fp) != buf)
 577:             break;
 578:         cp = index(buf, '\n');
 579:         if (cp == NULL) {
 580:             error("line too long");
 581:             exit(1);
 582:         }
 583:         *cp = '\0';
 584:         fields = getfields(buf);
 585:         nfields = 0;
 586:         while (fields[nfields] != NULL) {
 587:             if (ciequal(fields[nfields], "-"))
 588:                 fields[nfields] = "";
 589:             ++nfields;
 590:         }
 591:         if (nfields == 0) {
 592:             /* nothing to do */
 593:         } else if (wantcont) {
 594:             wantcont = inzcont(fields, nfields);
 595:         } else {
 596:             lp = byword(fields[0], line_codes);
 597:             if (lp == NULL)
 598:                 error("input line of unknown type");
 599:             else switch ((int) (lp->l_value)) {
 600:                 case LC_RULE:
 601:                     inrule(fields, nfields);
 602:                     wantcont = FALSE;
 603:                     break;
 604:                 case LC_ZONE:
 605:                     wantcont = inzone(fields, nfields);
 606:                     break;
 607:                 case LC_LINK:
 608:                     inlink(fields, nfields);
 609:                     wantcont = FALSE;
 610:                     break;
 611:                 default:    /* "cannot happen" */
 612:                     (void) fprintf(stderr,
 613: "%s: panic: Invalid l_value %d\n",
 614:                         progname, lp->l_value);
 615:                     exit(1);
 616:             }
 617:         }
 618:         free((char *) fields);
 619:     }
 620:     if (ferror(fp)) {
 621:         (void) fprintf(stderr, "%s: Error reading ", progname);
 622:         perror(filename);
 623:         exit(1);
 624:     }
 625:     if (fp != stdin && fclose(fp)) {
 626:         (void) fprintf(stderr, "%s: Error closing ", progname);
 627:         perror(filename);
 628:         exit(1);
 629:     }
 630:     if (wantcont)
 631:         error("expected continuation line not found");
 632: }
 633: 
 634: /*
 635: ** Convert a string of one of the forms
 636: **	h	-h 	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
 637: ** into a number of seconds.
 638: ** A null string maps to zero.
 639: ** Call error with errstring and return zero on errors.
 640: */
 641: 
 642: static long
 643: gethms(string, errstring, signable)
 644: char *  string;
 645: char *  errstring;
 646: {
 647:     int hh, mm, ss, sign;
 648: 
 649:     if (string == NULL || *string == '\0')
 650:         return 0;
 651:     if (!signable)
 652:         sign = 1;
 653:     else if (*string == '-') {
 654:         sign = -1;
 655:         ++string;
 656:     } else  sign = 1;
 657:     if (sscanf(string, scheck(string, "%d"), &hh) == 1)
 658:         mm = ss = 0;
 659:     else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
 660:         ss = 0;
 661:     else if (sscanf(string, scheck(string, "%d:%d:%d"),
 662:         &hh, &mm, &ss) != 3) {
 663:             error(errstring);
 664:             return 0;
 665:     }
 666:     if (hh < 0 || hh >= HOURS_PER_DAY ||
 667:         mm < 0 || mm >= MINS_PER_HOUR ||
 668:         ss < 0 || ss >= SECS_PER_MIN) {
 669:             error(errstring);
 670:             return 0;
 671:     }
 672:     return eitol(sign) *
 673:         (eitol(hh * MINS_PER_HOUR + mm) *
 674:         eitol(SECS_PER_MIN) + eitol(ss));
 675: }
 676: 
 677: static
 678: inrule(fields, nfields)
 679: register char **    fields;
 680: {
 681:     struct rule r;
 682: 
 683:     if (nfields != RULE_FIELDS) {
 684:         error("wrong number of fields on Rule line");
 685:         return;
 686:     }
 687:     if (*fields[RF_NAME] == '\0') {
 688:         error("nameless rule");
 689:         return;
 690:     }
 691:     r.r_filename = filename;
 692:     r.r_linenum = linenum;
 693:     r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
 694:     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
 695:         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
 696:     r.r_name = ecpyalloc(fields[RF_NAME]);
 697:     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
 698:     rules = (struct rule *) erealloc((char *) rules,
 699:         (nrules + 1) * sizeof *rules);
 700:     rules[nrules++] = r;
 701: }
 702: 
 703: static
 704: inzone(fields, nfields)
 705: register char **    fields;
 706: {
 707:     register int    i;
 708:     char        buf[132];
 709: 
 710:     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
 711:         error("wrong number of fields on Zone line");
 712:         return FALSE;
 713:     }
 714:     if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
 715:         (void) sprintf(buf,
 716:             "\"Zone %s\" line and -l option are mutually exclusive",
 717:             TZDEFAULT);
 718:         error(buf);
 719:         return FALSE;
 720:     }
 721:     for (i = 0; i < nzones; ++i)
 722:         if (zones[i].z_name != NULL &&
 723:             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
 724:                 (void) sprintf(buf,
 725: "duplicate zone name %s (file \"%s\", line %d)",
 726:                     fields[ZF_NAME],
 727:                     zones[i].z_filename,
 728:                     zones[i].z_linenum);
 729:                 error(buf);
 730:                 return FALSE;
 731:         }
 732:     return inzsub(fields, nfields, FALSE);
 733: }
 734: 
 735: static
 736: inzcont(fields, nfields)
 737: register char **    fields;
 738: {
 739:     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
 740:         error("wrong number of fields on Zone continuation line");
 741:         return FALSE;
 742:     }
 743:     return inzsub(fields, nfields, TRUE);
 744: }
 745: 
 746: static
 747: inzsub(fields, nfields, iscont)
 748: register char **    fields;
 749: {
 750:     register char * cp;
 751:     struct zone z;
 752:     register int    i_gmtoff, i_rule, i_format;
 753:     register int    i_untilyear, i_untilmonth;
 754:     register int    i_untilday, i_untiltime;
 755:     register int    hasuntil;
 756: 
 757:     if (iscont) {
 758:         i_gmtoff = ZFC_GMTOFF;
 759:         i_rule = ZFC_RULE;
 760:         i_format = ZFC_FORMAT;
 761:         i_untilyear = ZFC_UNTILYEAR;
 762:         i_untilmonth = ZFC_UNTILMONTH;
 763:         i_untilday = ZFC_UNTILDAY;
 764:         i_untiltime = ZFC_UNTILTIME;
 765:         z.z_name = NULL;
 766:     } else {
 767:         i_gmtoff = ZF_GMTOFF;
 768:         i_rule = ZF_RULE;
 769:         i_format = ZF_FORMAT;
 770:         i_untilyear = ZF_UNTILYEAR;
 771:         i_untilmonth = ZF_UNTILMONTH;
 772:         i_untilday = ZF_UNTILDAY;
 773:         i_untiltime = ZF_UNTILTIME;
 774:         z.z_name = ecpyalloc(fields[ZF_NAME]);
 775:     }
 776:     z.z_filename = filename;
 777:     z.z_linenum = linenum;
 778:     z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
 779:     if ((cp = index(fields[i_format], '%')) != 0) {
 780:         if (*++cp != 's' || index(cp, '%') != 0) {
 781:             error("invalid abbreviation format");
 782:             return FALSE;
 783:         }
 784:     }
 785:     z.z_rule = ecpyalloc(fields[i_rule]);
 786:     z.z_format = ecpyalloc(fields[i_format]);
 787:     hasuntil = nfields > i_untilyear;
 788:     if (hasuntil) {
 789:         z.z_untilrule.r_filename = filename;
 790:         z.z_untilrule.r_linenum = linenum;
 791:         rulesub(&z.z_untilrule,
 792:             fields[i_untilyear],
 793:             "only",
 794:             "",
 795:             (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
 796:             (nfields > i_untilday) ? fields[i_untilday] : "1",
 797:             (nfields > i_untiltime) ? fields[i_untiltime] : "0");
 798:         z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
 799:         if (iscont && nzones > 0 && z.z_untiltime < max_time &&
 800:             z.z_untiltime > min_time &&
 801:             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
 802: error("Zone continuation line end time is not after end time of previous line");
 803:             return FALSE;
 804:         }
 805:     }
 806:     zones = (struct zone *) erealloc((char *) zones,
 807:         (nzones + 1) * sizeof *zones);
 808:     zones[nzones++] = z;
 809:     /*
 810: 	** If there was an UNTIL field on this line,
 811: 	** there's more information about the zone on the next line.
 812: 	*/
 813:     return hasuntil;
 814: }
 815: 
 816: static
 817: inlink(fields, nfields)
 818: register char **    fields;
 819: {
 820:     struct link l;
 821: 
 822:     if (nfields != LINK_FIELDS) {
 823:         error("wrong number of fields on Link line");
 824:         return;
 825:     }
 826:     if (*fields[LF_FROM] == '\0') {
 827:         error("blank FROM field on Link line");
 828:         return;
 829:     }
 830:     if (*fields[LF_TO] == '\0') {
 831:         error("blank TO field on Link line");
 832:         return;
 833:     }
 834:     l.l_filename = filename;
 835:     l.l_linenum = linenum;
 836:     l.l_from = ecpyalloc(fields[LF_FROM]);
 837:     l.l_to = ecpyalloc(fields[LF_TO]);
 838:     links = (struct link *) erealloc((char *) links,
 839:         (nlinks + 1) * sizeof *links);
 840:     links[nlinks++] = l;
 841: }
 842: 
 843: static
 844: rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
 845: register struct rule *  rp;
 846: char *          loyearp;
 847: char *          hiyearp;
 848: char *          typep;
 849: char *          monthp;
 850: char *          dayp;
 851: char *          timep;
 852: {
 853:     register struct lookup *    lp;
 854:     register char *         cp;
 855: 
 856:     if ((lp = byword(monthp, mon_names)) == NULL) {
 857:         error("invalid month name");
 858:         return;
 859:     }
 860:     rp->r_month = lp->l_value;
 861:     rp->r_todisstd = FALSE;
 862:     cp = timep;
 863:     if (*cp != '\0') {
 864:         cp += strlen(cp) - 1;
 865:         switch (lowerit(*cp)) {
 866:             case 's':
 867:                 rp->r_todisstd = TRUE;
 868:                 *cp = '\0';
 869:                 break;
 870:             case 'w':
 871:                 rp->r_todisstd = FALSE;
 872:                 *cp = '\0';
 873:                 break;
 874:         }
 875:     }
 876:     rp->r_tod = gethms(timep, "invalid time of day", FALSE);
 877:     /*
 878: 	** Year work.
 879: 	*/
 880:     cp = loyearp;
 881:     if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
 882:         case YR_MINIMUM:
 883:             rp->r_loyear = min_year;
 884:             break;
 885:         case YR_MAXIMUM:
 886:             rp->r_loyear = max_year;
 887:             break;
 888:         default:    /* "cannot happen" */
 889:             (void) fprintf(stderr,
 890:                 "%s: panic: Invalid l_value %d\n",
 891:                 progname, lp->l_value);
 892:             exit(1);
 893:     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
 894:         rp->r_loyear < min_year || rp->r_loyear > max_year) {
 895:             if (noise)
 896:                 error("invalid starting year");
 897:             if (rp->r_loyear > max_year)
 898:                 return;
 899:     }
 900:     cp = hiyearp;
 901:     if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
 902:         case YR_MINIMUM:
 903:             rp->r_hiyear = min_year;
 904:             break;
 905:         case YR_MAXIMUM:
 906:             rp->r_hiyear = max_year;
 907:             break;
 908:         case YR_ONLY:
 909:             rp->r_hiyear = rp->r_loyear;
 910:             break;
 911:         default:    /* "cannot happen" */
 912:             (void) fprintf(stderr,
 913:                 "%s: panic: Invalid l_value %d\n",
 914:                 progname, lp->l_value);
 915:             exit(1);
 916:     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
 917:         rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
 918:             if (noise)
 919:                 error("invalid ending year");
 920:             if (rp->r_hiyear < min_year)
 921:                 return;
 922:     }
 923:     if (rp->r_hiyear < min_year)
 924:         return;
 925:     if (rp->r_loyear < min_year)
 926:         rp->r_loyear = min_year;
 927:     if (rp->r_hiyear > max_year)
 928:         rp->r_hiyear = max_year;
 929:     if (rp->r_loyear > rp->r_hiyear) {
 930:         error("starting year greater than ending year");
 931:         return;
 932:     }
 933:     if (*typep == '\0')
 934:         rp->r_yrtype = NULL;
 935:     else {
 936:         if (rp->r_loyear == rp->r_hiyear) {
 937:             error("typed single year");
 938:             return;
 939:         }
 940:         rp->r_yrtype = ecpyalloc(typep);
 941:     }
 942:     /*
 943: 	** Day work.
 944: 	** Accept things such as:
 945: 	**	1
 946: 	**	last-Sunday
 947: 	**	Sun<=20
 948: 	**	Sun>=7
 949: 	*/
 950:     if ((lp = byword(dayp, lasts)) != NULL) {
 951:         rp->r_dycode = DC_DOWLEQ;
 952:         rp->r_wday = lp->l_value;
 953:         rp->r_dayofmonth = len_months[1][rp->r_month];
 954:     } else {
 955:         if ((cp = index(dayp, '<')) != 0)
 956:             rp->r_dycode = DC_DOWLEQ;
 957:         else if ((cp = index(dayp, '>')) != 0)
 958:             rp->r_dycode = DC_DOWGEQ;
 959:         else {
 960:             cp = dayp;
 961:             rp->r_dycode = DC_DOM;
 962:         }
 963:         if (rp->r_dycode != DC_DOM) {
 964:             *cp++ = 0;
 965:             if (*cp++ != '=') {
 966:                 error("invalid day of month");
 967:                 return;
 968:             }
 969:             if ((lp = byword(dayp, wday_names)) == NULL) {
 970:                 error("invalid weekday name");
 971:                 return;
 972:             }
 973:             rp->r_wday = lp->l_value;
 974:         }
 975:         if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
 976:             rp->r_dayofmonth <= 0 ||
 977:             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
 978:                 error("invalid day of month");
 979:                 return;
 980:         }
 981:     }
 982: }
 983: 
 984: static
 985: puttzcode(val, fp)
 986: long    val;
 987: FILE *  fp;
 988: {
 989:     register int    c;
 990:     register int    shift;
 991: 
 992:     for (shift = 24; shift >= 0; shift -= 8) {
 993:         c = val >> shift;
 994:         (void) putc(c, fp);
 995:     }
 996: }
 997: 
 998: static
 999: writezone(name)
1000: char *  name;
1001: {
1002:     register FILE *     fp;
1003:     register int        i;
1004:     char            fullname[BUFSIZ];
1005: 
1006:     if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
1007:         (void) fprintf(stderr,
1008:             "%s: File name %s/%s too long\n", progname,
1009:             directory, name);
1010:         exit(1);
1011:     }
1012:     (void) sprintf(fullname, "%s/%s", directory, name);
1013:     if ((fp = fopen(fullname, "w")) == NULL) {
1014:         if (mkdirs(fullname) != 0)
1015:             exit(1);
1016:         if ((fp = fopen(fullname, "w")) == NULL) {
1017:             (void) fprintf(stderr, "%s: Can't create ", progname);
1018:             perror(fullname);
1019:             exit(1);
1020:         }
1021:     }
1022:     (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0);
1023:     puttzcode(eitol(timecnt), fp);
1024:     puttzcode(eitol(typecnt), fp);
1025:     puttzcode(eitol(charcnt), fp);
1026:     for (i = 0; i < timecnt; ++i)
1027:         puttzcode((long) ats[i], fp);
1028:     if (timecnt > 0)
1029:         (void) fwrite((char *) types, sizeof types[0],
1030:             (int) timecnt, fp);
1031:     for (i = 0; i < typecnt; ++i) {
1032:         puttzcode((long) gmtoffs[i], fp);
1033:         (void) putc(isdsts[i], fp);
1034:         (void) putc(abbrinds[i], fp);
1035:     }
1036:     if (charcnt != 0)
1037:         (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp);
1038:     if (ferror(fp) || fclose(fp)) {
1039:         (void) fprintf(stderr, "%s: Write error on ", progname);
1040:         perror(fullname);
1041:         exit(1);
1042:     }
1043: }
1044: 
1045: static
1046: outzone(zpfirst, zonecount)
1047: struct zone *   zpfirst;
1048: {
1049:     register struct zone *      zp;
1050:     register struct rule *      rp;
1051:     register int            i, j;
1052:     register int            usestart, useuntil;
1053:     register time_t         starttime, untiltime;
1054:     register long           gmtoff;
1055:     register long           stdoff;
1056:     register int            year;
1057:     register long           startoff;
1058:     register int            startisdst;
1059:     register int            type;
1060:     char                startbuf[BUFSIZ];
1061: 
1062:     /*
1063: 	** Now. . .finally. . .generate some useful data!
1064: 	*/
1065:     timecnt = 0;
1066:     typecnt = 0;
1067:     charcnt = 0;
1068:     /*
1069: 	** Two guesses. . .the second may well be corrected later.
1070: 	*/
1071:     gmtoff = zpfirst->z_gmtoff;
1072:     stdoff = 0;
1073:     for (i = 0; i < zonecount; ++i) {
1074:         usestart = i > 0;
1075:         useuntil = i < (zonecount - 1);
1076:         zp = &zpfirst[i];
1077:         eat(zp->z_filename, zp->z_linenum);
1078:         startisdst = -1;
1079:         if (zp->z_nrules == 0) {
1080:             type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
1081:                 zp->z_format, zp->z_stdoff != 0);
1082:             if (usestart)
1083:                 addtt(starttime, type);
1084:             gmtoff = zp->z_gmtoff;
1085:             stdoff = zp->z_stdoff;
1086:         } else for (year = min_year; year <= max_year; ++year) {
1087:             if (useuntil && year > zp->z_untilrule.r_hiyear)
1088:                 break;
1089:             /*
1090: 			** Mark which rules to do in the current year.
1091: 			** For those to do, calculate rpytime(rp, year);
1092: 			*/
1093:             for (j = 0; j < zp->z_nrules; ++j) {
1094:                 rp = &zp->z_rules[j];
1095:                 eats(zp->z_filename, zp->z_linenum,
1096:                     rp->r_filename, rp->r_linenum);
1097:                 rp->r_todo = year >= rp->r_loyear &&
1098:                         year <= rp->r_hiyear &&
1099:                         yearistype(year, rp->r_yrtype);
1100:                 if (rp->r_todo)
1101:                     rp->r_temp = rpytime(rp, year);
1102:             }
1103:             for ( ; ; ) {
1104:                 register int    k;
1105:                 register time_t jtime, ktime;
1106:                 register long   offset;
1107:                 char        buf[BUFSIZ];
1108: 
1109:                 if (useuntil) {
1110:                     /*
1111: 					** Turn untiltime into GMT
1112: 					** assuming the current gmtoff and
1113: 					** stdoff values.
1114: 					*/
1115:                     offset = gmtoff;
1116:                     if (!zp->z_untilrule.r_todisstd)
1117:                         offset = oadd(offset, stdoff);
1118:                     untiltime = tadd(zp->z_untiltime,
1119:                         -offset);
1120:                 }
1121:                 /*
1122: 				** Find the rule (of those to do, if any)
1123: 				** that takes effect earliest in the year.
1124: 				*/
1125:                 k = -1;
1126:                 for (j = 0; j < zp->z_nrules; ++j) {
1127:                     rp = &zp->z_rules[j];
1128:                     if (!rp->r_todo)
1129:                         continue;
1130:                     eats(zp->z_filename, zp->z_linenum,
1131:                         rp->r_filename, rp->r_linenum);
1132:                     offset = gmtoff;
1133:                     if (!rp->r_todisstd)
1134:                         offset = oadd(offset, stdoff);
1135:                     jtime = rp->r_temp;
1136:                     if (jtime == min_time ||
1137:                         jtime == max_time)
1138:                             continue;
1139:                     jtime = tadd(jtime, -offset);
1140:                     if (k < 0 || jtime < ktime) {
1141:                         k = j;
1142:                         ktime = jtime;
1143:                     }
1144:                 }
1145:                 if (k < 0)
1146:                     break;  /* go on to next year */
1147:                 rp = &zp->z_rules[k];
1148:                 rp->r_todo = FALSE;
1149:                 if (useuntil && ktime >= untiltime)
1150:                     break;
1151:                 if (usestart) {
1152:                     if (ktime < starttime) {
1153:                         stdoff = rp->r_stdoff;
1154:                         startoff = oadd(zp->z_gmtoff,
1155:                             rp->r_stdoff);
1156:                         (void) sprintf(startbuf,
1157:                             zp->z_format,
1158:                             rp->r_abbrvar);
1159:                         startisdst =
1160:                             rp->r_stdoff != 0;
1161:                         continue;
1162:                     }
1163:                     if (ktime != starttime &&
1164:                         startisdst >= 0)
1165: addtt(starttime, addtype(startoff, startbuf, startisdst));
1166:                     usestart = FALSE;
1167:                 }
1168:                 eats(zp->z_filename, zp->z_linenum,
1169:                     rp->r_filename, rp->r_linenum);
1170:                 (void) sprintf(buf, zp->z_format,
1171:                     rp->r_abbrvar);
1172:                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1173:                 type = addtype(offset, buf, rp->r_stdoff != 0);
1174:                 if (timecnt != 0 || rp->r_stdoff != 0)
1175:                     addtt(ktime, type);
1176:                 gmtoff = zp->z_gmtoff;
1177:                 stdoff = rp->r_stdoff;
1178:             }
1179:         }
1180:         /*
1181: 		** Now we may get to set starttime for the next zone line.
1182: 		*/
1183:         if (useuntil)
1184:             starttime = tadd(zp->z_untiltime,
1185:                 -gmtoffs[types[timecnt - 1]]);
1186:     }
1187:     writezone(zpfirst->z_name);
1188: }
1189: 
1190: static
1191: addtt(starttime, type)
1192: time_t  starttime;
1193: {
1194:     if (timecnt != 0 && type == types[timecnt - 1])
1195:         return; /* easy enough! */
1196:     if (timecnt >= TZ_MAX_TIMES) {
1197:         error("too many transitions?!");
1198:         exit(1);
1199:     }
1200:     ats[timecnt] = starttime;
1201:     types[timecnt] = type;
1202:     ++timecnt;
1203: }
1204: 
1205: static
1206: addtype(gmtoff, abbr, isdst)
1207: long    gmtoff;
1208: char *  abbr;
1209: {
1210:     register int    i, j;
1211: 
1212:     /*
1213: 	** See if there's already an entry for this zone type.
1214: 	** If so, just return its index.
1215: 	*/
1216:     for (i = 0; i < typecnt; ++i) {
1217:         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1218:             strcmp(abbr, &chars[abbrinds[i]]) == 0)
1219:                 return i;
1220:     }
1221:     /*
1222: 	** There isn't one; add a new one, unless there are already too
1223: 	** many.
1224: 	*/
1225:     if (typecnt >= TZ_MAX_TYPES) {
1226:         error("too many local time types");
1227:         exit(1);
1228:     }
1229:     gmtoffs[i] = gmtoff;
1230:     isdsts[i] = isdst;
1231: 
1232:     for (j = 0; j < charcnt; ++j)
1233:         if (strcmp(&chars[j], abbr) == 0)
1234:             break;
1235:     if (j == charcnt)
1236:         newabbr(abbr);
1237:     abbrinds[i] = j;
1238:     ++typecnt;
1239:     return i;
1240: }
1241: 
1242: static
1243: yearistype(year, type)
1244: char *  type;
1245: {
1246:     char    buf[BUFSIZ];
1247:     int result;
1248: 
1249:     if (type == NULL || *type == '\0')
1250:         return TRUE;
1251:     if (strcmp(type, "uspres") == 0)
1252:         return (year % 4) == 0;
1253:     if (strcmp(type, "nonpres") == 0)
1254:         return (year % 4) != 0;
1255:     (void) sprintf(buf, "yearistype %d %s", year, type);
1256:     result = system(buf);
1257:     if (result == 0)
1258:         return TRUE;
1259:     if (result == 1 << 8)
1260:         return FALSE;
1261:     error("Wild result from command execution");
1262:     (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
1263:         progname, buf, result);
1264:     for ( ; ; )
1265:         exit(1);
1266: }
1267: 
1268: static
1269: lowerit(a)
1270: {
1271:     return (isascii(a) && isupper(a)) ? tolower(a) : a;
1272: }
1273: 
1274: static
1275: ciequal(ap, bp)     /* case-insensitive equality */
1276: register char * ap;
1277: register char * bp;
1278: {
1279:     while (lowerit(*ap) == lowerit(*bp++))
1280:         if (*ap++ == '\0')
1281:             return TRUE;
1282:     return FALSE;
1283: }
1284: 
1285: static
1286: isabbr(abbr, word)
1287: register char * abbr;
1288: register char * word;
1289: {
1290:     if (lowerit(*abbr) != lowerit(*word))
1291:         return FALSE;
1292:     ++word;
1293:     while (*++abbr != '\0')
1294:         do if (*word == '\0')
1295:             return FALSE;
1296:                 while (lowerit(*word++) != lowerit(*abbr));
1297:     return TRUE;
1298: }
1299: 
1300: static struct lookup *
1301: byword(word, table)
1302: register char *         word;
1303: register struct lookup *    table;
1304: {
1305:     register struct lookup *    foundlp;
1306:     register struct lookup *    lp;
1307: 
1308:     if (word == NULL || table == NULL)
1309:         return NULL;
1310:     /*
1311: 	** Look for exact match.
1312: 	*/
1313:     for (lp = table; lp->l_word != NULL; ++lp)
1314:         if (ciequal(word, lp->l_word))
1315:             return lp;
1316:     /*
1317: 	** Look for inexact match.
1318: 	*/
1319:     foundlp = NULL;
1320:     for (lp = table; lp->l_word != NULL; ++lp)
1321:         if (isabbr(word, lp->l_word))
1322:             if (foundlp == NULL)
1323:                 foundlp = lp;
1324:             else    return NULL;    /* multiple inexact matches */
1325:     return foundlp;
1326: }
1327: 
1328: static char **
1329: getfields(cp)
1330: register char * cp;
1331: {
1332:     register char *     dp;
1333:     register char **    array;
1334:     register int        nsubs;
1335: 
1336:     if (cp == NULL)
1337:         return NULL;
1338:     array = (char **) emalloc((strlen(cp) + 1) * sizeof *array);
1339:     nsubs = 0;
1340:     for ( ; ; ) {
1341:         while (isascii(*cp) && isspace(*cp))
1342:             ++cp;
1343:         if (*cp == '\0' || *cp == '#')
1344:             break;
1345:         array[nsubs++] = dp = cp;
1346:         do {
1347:             if ((*dp = *cp++) != '"')
1348:                 ++dp;
1349:             else while ((*dp = *cp++) != '"')
1350:                 if (*dp != '\0')
1351:                     ++dp;
1352:                 else    error("Odd number of quotation marks");
1353:         } while (*cp != '\0' && *cp != '#' &&
1354:             (!isascii(*cp) || !isspace(*cp)));
1355:         if (isascii(*cp) && isspace(*cp))
1356:             ++cp;
1357:         *dp = '\0';
1358:     }
1359:     array[nsubs] = NULL;
1360:     return array;
1361: }
1362: 
1363: static long
1364: oadd(t1, t2)
1365: long    t1;
1366: long    t2;
1367: {
1368:     register long   t;
1369: 
1370:     t = t1 + t2;
1371:     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1372:         error("time overflow");
1373:         exit(1);
1374:     }
1375:     return t;
1376: }
1377: 
1378: static time_t
1379: tadd(t1, t2)
1380: time_t  t1;
1381: long    t2;
1382: {
1383:     register time_t t;
1384: 
1385:     if (t1 == max_time && t2 > 0)
1386:         return max_time;
1387:     if (t1 == min_time && t2 < 0)
1388:         return min_time;
1389:     t = t1 + t2;
1390:     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1391:         error("time overflow");
1392:         exit(1);
1393:     }
1394:     return t;
1395: }
1396: 
1397: /*
1398: ** Given a rule, and a year, compute the date - in seconds since January 1,
1399: ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1400: */
1401: 
1402: static time_t
1403: rpytime(rp, wantedy)
1404: register struct rule *  rp;
1405: register int        wantedy;
1406: {
1407:     register int    y, m, i;
1408:     register long   dayoff;         /* with a nod to Margaret O. */
1409:     register time_t t;
1410: 
1411:     dayoff = 0;
1412:     m = TM_JANUARY;
1413:     y = EPOCH_YEAR;
1414:     while (wantedy != y) {
1415:         if (wantedy > y) {
1416:             i = len_years[isleap(y)];
1417:             ++y;
1418:         } else {
1419:             --y;
1420:             i = -len_years[isleap(y)];
1421:         }
1422:         dayoff = oadd(dayoff, eitol(i));
1423:     }
1424:     while (m != rp->r_month) {
1425:         i = len_months[isleap(y)][m];
1426:         dayoff = oadd(dayoff, eitol(i));
1427:         ++m;
1428:     }
1429:     i = rp->r_dayofmonth;
1430:     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1431:         if (rp->r_dycode == DC_DOWLEQ)
1432:             --i;
1433:         else {
1434:             error("use of 2/29 in non leap-year");
1435:             exit(1);
1436:         }
1437:     }
1438:     --i;
1439:     dayoff = oadd(dayoff, eitol(i));
1440:     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1441:         register long   wday;
1442: 
1443: #define LDAYS_PER_WEEK  ((long) DAYS_PER_WEEK)
1444:         wday = eitol(EPOCH_WDAY);
1445:         /*
1446: 		** Don't trust mod of negative numbers.
1447: 		*/
1448:         if (dayoff >= 0)
1449:             wday = (wday + dayoff) % LDAYS_PER_WEEK;
1450:         else {
1451:             wday -= ((-dayoff) % LDAYS_PER_WEEK);
1452:             if (wday < 0)
1453:                 wday += LDAYS_PER_WEEK;
1454:         }
1455:         while (wday != eitol(rp->r_wday))
1456:             if (rp->r_dycode == DC_DOWGEQ) {
1457:                 dayoff = oadd(dayoff, (long) 1);
1458:                 if (++wday >= LDAYS_PER_WEEK)
1459:                     wday = 0;
1460:                 ++i;
1461:             } else {
1462:                 dayoff = oadd(dayoff, (long) -1);
1463:                 if (--wday < 0)
1464:                     wday = LDAYS_PER_WEEK;
1465:                 --i;
1466:             }
1467:         if (i < 0 || i >= len_months[isleap(y)][m]) {
1468:             error("no day in month matches rule");
1469:             exit(1);
1470:         }
1471:     }
1472:     if (dayoff < 0 && !tt_signed) {
1473:         if (wantedy == rp->r_loyear)
1474:             return min_time;
1475:         error("time before zero");
1476:         exit(1);
1477:     }
1478:     t = (time_t) dayoff * SECS_PER_DAY;
1479:     /*
1480: 	** Cheap overflow check.
1481: 	*/
1482:     if (t / SECS_PER_DAY != dayoff) {
1483:         if (wantedy == rp->r_hiyear)
1484:             return max_time;
1485:         if (wantedy == rp->r_loyear)
1486:             return min_time;
1487:         error("time overflow");
1488:         exit(1);
1489:     }
1490:     return tadd(t, rp->r_tod);
1491: }
1492: 
1493: static
1494: newabbr(string)
1495: char *  string;
1496: {
1497:     register int    i;
1498: 
1499:     i = strlen(string) + 1;
1500:     if (charcnt + i >= TZ_MAX_CHARS) {
1501:         error("too many, or too long, time zone abbreviations");
1502:         exit(1);
1503:     }
1504:     (void) strcpy(&chars[charcnt], string);
1505:     charcnt += eitol(i);
1506: }
1507: 
1508: static
1509: mkdirs(name)
1510: char *  name;
1511: {
1512:     register char * cp;
1513: 
1514:     if ((cp = name) == NULL || *cp == '\0')
1515:         return 0;
1516:     while ((cp = index(cp + 1,'/')) != 0) {
1517:         *cp = '\0';
1518:         if (access(name,F_OK) && mkdir(name,0755)) {
1519:             perror(name);
1520:             return -1;
1521:         }
1522:         *cp = '/';
1523:     }
1524:     return 0;
1525: }
1526: 
1527: static long
1528: eitol(i)
1529: {
1530:     long    l;
1531: 
1532:     l = i;
1533:     if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
1534:         (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
1535:             progname, i);
1536:         exit(1);
1537:     }
1538:     return l;
1539: }
1540: 
1541: /*
1542: ** UNIX is a registered trademark of AT&T.
1543: */

Defined functions

addtt defined in line 1190; used 4 times
addtype defined in line 1205; used 4 times
associate defined in line 504; used 2 times
byword defined in line 1300; used 7 times
ciequal defined in line 1274; used 3 times
eat defined in line 320; used 3 times
eats defined in line 309; used 4 times
eitol defined in line 1527; used 14 times
error defined in line 327; used 36 times
getfields defined in line 1328; used 2 times
gethms defined in line 642; used 5 times
infile defined in line 552; used 2 times
inlink defined in line 816; used 2 times
inrule defined in line 677; used 2 times
inzcont defined in line 735; used 2 times
inzone defined in line 703; used 2 times
inzsub defined in line 746; used 3 times
isabbr defined in line 1285; used 1 times
lowerit defined in line 1268; used 8 times
main defined in line 357; never used
memcheck defined in line 290; used 3 times
mkdirs defined in line 1508; used 2 times
newabbr defined in line 1493; used 2 times
nondunlink defined in line 474; used 3 times
oadd defined in line 1363; used 11 times
outzone defined in line 1045; used 2 times
puttzcode defined in line 984; used 5 times
rcomp defined in line 495; used 1 times
rpytime defined in line 1402; used 3 times
rulesub defined in line 843; used 3 times
setboundaries defined in line 448; used 2 times
tadd defined in line 1378; used 5 times
usage defined in line 345; used 2 times
writezone defined in line 998; used 1 times
yearistype defined in line 1242; used 2 times

Defined variables

abbrinds defined in line 283; used 3 times
ats defined in line 279; used 2 times
begin_years defined in line 257; used 1 times
charcnt defined in line 34; used 9 times
chars defined in line 284; used 5 times
directory defined in line 355; used 9 times
end_years defined in line 263; used 1 times
errors defined in line 37; used 4 times
filename defined in line 38; used 8 times
gmtoffs defined in line 281; used 4 times
isdsts defined in line 282; used 3 times
lasts defined in line 246; used 1 times
lcltime defined in line 354; used 6 times
len_months defined in line 270; used 4 times
len_years defined in line 275; used 2 times
line_codes defined in line 212; used 1 times
linenum defined in line 47; used 6 times
links defined in line 202; used 10 times
max_time defined in line 49; used 11 times
max_year defined in line 50; used 9 times
min_time defined in line 51; used 9 times
min_year defined in line 52; used 10 times
mon_names defined in line 219; used 1 times
nlinks defined in line 203; used 3 times
noise defined in line 55; used 3 times
nrules defined in line 172; used 6 times
nzones defined in line 193; used 10 times
progname defined in line 59; used 20 times
rfilename defined in line 60; used 3 times
rlinenum defined in line 61; used 2 times
rules defined in line 171; used 9 times
timecnt defined in line 66; used 13 times
tt_signed defined in line 67; used 3 times
typecnt defined in line 68; used 6 times
types defined in line 280; used 5 times
wday_names defined in line 235; used 1 times
zones defined in line 192; used 15 times

Defined struct's

link defined in line 195; used 8 times
lookup defined in line 205; used 26 times
rule defined in line 131; used 24 times
zone defined in line 174; used 14 times

Defined macros

BUFSIZ defined in line 15; used 6 times
DC_DOM defined in line 159; used 2 times
DC_DOWGEQ defined in line 160; used 3 times
DC_DOWLEQ defined in line 161; used 4 times
FALSE defined in line 20; used 20 times
LC_LINK defined in line 77; used 1 times
LC_RULE defined in line 75; used 1 times
LC_ZONE defined in line 76; used 1 times
LDAYS_PER_WEEK defined in line 1443; used 5 times
LF_FROM defined in line 127; used 2 times
LF_TO defined in line 128; used 2 times
LINK_FIELDS defined in line 129; used 1 times
RF_ABBRVAR defined in line 120; used 1 times
RF_COMMAND defined in line 115; used 1 times
RF_DAY defined in line 117; used 1 times
RF_HIYEAR defined in line 114; used 1 times
RF_LOYEAR defined in line 113; used 1 times
RF_MONTH defined in line 116; used 1 times
RF_NAME defined in line 112; used 2 times
RF_STDOFF defined in line 119; used 1 times
RF_TOD defined in line 118; used 1 times
RULE_FIELDS defined in line 121; used 1 times
TRUE defined in line 19; used 12 times
YR_MAXIMUM defined in line 168; used 2 times
YR_MINIMUM defined in line 167; used 2 times
YR_ONLY defined in line 169; used 1 times
ZFC_FORMAT defined in line 100; used 1 times
ZFC_GMTOFF defined in line 98; used 1 times
ZFC_RULE defined in line 99; used 1 times
ZFC_UNTILDAY defined in line 103; used 1 times
ZFC_UNTILMONTH defined in line 102; used 1 times
ZFC_UNTILTIME defined in line 104; used 1 times
ZFC_UNTILYEAR defined in line 101; used 1 times
ZF_FORMAT defined in line 86; used 1 times
ZF_GMTOFF defined in line 84; used 1 times
ZF_NAME defined in line 83; used 4 times
ZF_RULE defined in line 85; used 1 times
ZF_UNTILDAY defined in line 89; used 1 times
ZF_UNTILMONTH defined in line 88; used 1 times
ZF_UNTILTIME defined in line 90; used 1 times
ZF_UNTILYEAR defined in line 87; used 1 times
ZONEC_MAXFIELDS defined in line 106; used 1 times
ZONEC_MINFIELDS defined in line 105; used 1 times
ZONE_MAXFIELDS defined in line 92; used 1 times
ZONE_MINFIELDS defined in line 91; used 1 times
ecpyalloc defined in line 303; used 8 times
emalloc defined in line 301; used 4 times
erealloc defined in line 302; used 3 times
Last modified: 1987-03-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 9073
Valid CSS Valid XHTML 1.0 Strict