# 2.11BSD#431 - /usr/src/share/zoneinfo/zic.c

##### Functions

    main              X

##### Macros

    BUFSIZ            X
    DC_DOM            X
    DC_DOWGEQ         X
    DC_DOWLEQ         X
    FALSE             X
    LC_LINK           X
    LC_RULE           X
    LC_ZONE           X
    LDAYS_PER_WEEK    X
    LF_FROM           X
    LF_TO             X
    LINK_FIELDS       X
    RF_ABBRVAR        X
    RF_COMMAND        X
    RF_DAY            X
    RF_HIYEAR         X
    RF_LOYEAR         X
    RF_MONTH          X
    RF_NAME           X
    RF_STDOFF         X
    RF_TOD            X
    RULE_FIELDS       X
    TRUE              X
    YR_MAXIMUM        X
    YR_MINIMUM        X
    YR_ONLY           X
    ZFC_FORMAT        X
    ZFC_GMTOFF        X
    ZFC_RULE          X
    ZFC_UNTILDAY      X
    ZFC_UNTILMONTH    X
    ZFC_UNTILTIME     X
    ZFC_UNTILYEAR     X
    ZF_FORMAT         X
    ZF_GMTOFF         X
    ZF_NAME           X
    ZF_RULE           X
    ZF_UNTILDAY       X
    ZF_UNTILMONTH     X
    ZF_UNTILTIME      X
    ZF_UNTILYEAR      X
    ZONEC_MAXFIELDS   X
    ZONEC_MINFIELDS   X
    ZONE_MAXFIELDS    X
    ZONE_MINFIELDS    X
    ecpyalloc         X
    emalloc           X
    erealloc          X

##### struct's

    link              X
    lookup            X
    rule              X
    zone              X

       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

- in line 31, 1083, 1165, 1175

addtype defined in line 1205; used 4 times

- in line 32, 1080, 1165, 1173

associate defined in line 504; used 2 times

- in line 33, 410

byword defined in line 1300; used 7 times

- in line 210, 596, 856, 881, 901, 950, 969

ciequal defined in line 1274; used 3 times

- in line 35, 587, 1314

eat defined in line 320; used 3 times

- in line 538, 575, 1077

eats defined in line 309; used 4 times

- in line 324, 1095, 1130, 1168

eitol defined in line 1527; used 14 times

- in line 36, 672-674(4), 1023-1025(3), 1422-1426(2), 1439-1444(2), 1455, 1505

error defined in line 327; used 36 times

- in line 545, 580, 598, 631, 663, 669, 684-688(2), 711, 718, 729, 740, 781, 802, 823-831(3), 857, 896, 919, 930, 937, 966-970(2), 978, 1197, 1226, 1261, 1352, 1372, 1391, 1434, 1468, 1475, 1487, 1501

getfields defined in line 1328; used 2 times

- in line 39, 584

gethms defined in line 642; used 5 times

- in line 40, 539, 693, 778, 876

infile defined in line 552; used 2 times

- in line 41, 407

inlink defined in line 816; used 2 times

- in line 42, 608

inrule defined in line 677; used 2 times

- in line 43, 601

inzcont defined in line 735; used 2 times

- in line 44, 594

inzone defined in line 703; used 2 times

- in line 45, 605

inzsub defined in line 746; used 3 times

- in line 46, 732, 743

isabbr defined in line 1285; used 1 times

- in line 1321

lowerit defined in line 1268; used 8 times

- in line 48, 865, 1279(2), 1290(2), 1296(2)

main defined in line 357; never used
memcheck defined in line 290; used 3 times

- in line 301-303(3)

mkdirs defined in line 1508; used 2 times

- in line 53, 1014

newabbr defined in line 1493; used 2 times

- in line 54, 1236

nondunlink defined in line 474; used 3 times

- in line 56, 428, 437

oadd defined in line 1363; used 11 times

- in line 57, 1080, 1117, 1134, 1154, 1172, 1422-1426(2), 1439, 1457-1462(2)

outzone defined in line 1045; used 2 times

- in line 58, 417

puttzcode defined in line 984; used 5 times

- in line 1023-1032(5)

rcomp defined in line 495; used 1 times

- in line 513

rpytime defined in line 1402; used 3 times

- in line 62, 798, 1101

rulesub defined in line 843; used 3 times

- in line 63, 694, 791

setboundaries defined in line 448; used 2 times

- in line 64, 401

tadd defined in line 1378; used 5 times

- in line 65, 1118, 1139, 1184, 1490

usage defined in line 345; used 2 times

- in line 371, 397

writezone defined in line 998; used 1 times

- in line 1187

yearistype defined in line 1242; used 2 times

- in line 69, 1099

#### Defined variables

abbrinds defined in line 283; used 3 times

- in line 1034, 1218, 1237

ats defined in line 279; used 2 times

- in line 1027, 1200

begin_years defined in line 257; used 1 times

- in line 881

charcnt defined in line 34; used 9 times

- in line 1025, 1036-1037(2), 1067, 1232-1235(2), 1500-1505(3)

chars defined in line 284; used 5 times

- in line 1037(2), 1218, 1233, 1504

directory defined in line 355; used 9 times

- in line 373-374(2), 398-399(2), 422-424(2), 1006-1012(3)

end_years defined in line 263; used 1 times

- in line 901

errors defined in line 37; used 4 times

- in line 342, 408, 445, 548

filename defined in line 38; used 8 times

- in line 314, 337, 622-627(2), 691, 776, 789, 834

gmtoffs defined in line 281; used 4 times

- in line 1032, 1185, 1217, 1229

isdsts defined in line 282; used 3 times

- in line 1033, 1217, 1230

lasts defined in line 246; used 1 times

- in line 950

lcltime defined in line 354; used 6 times

- in line 383-384(2), 436-440(3), 714

len_months defined in line 270; used 4 times

- in line 953, 977, 1425, 1467

len_years defined in line 275; used 2 times

- in line 1416-1420(2)

line_codes defined in line 212; used 1 times

- in line 596

linenum defined in line 47; used 6 times

- in line 315, 337, 692, 777, 790, 835

links defined in line 202; used 10 times

- in line 405, 428-432(5), 838-840(4)

max_time defined in line 49; used 11 times

- in line 458-467(6), 799, 1137, 1385-1386(2), 1484

max_year defined in line 50; used 9 times

- in line 467, 886, 894-897(2), 906, 917, 927-928(2), 1086

min_time defined in line 51; used 9 times

- in line 457-466(3), 800, 1136, 1387-1388(2), 1474, 1486

min_year defined in line 52; used 10 times

- in line 466, 883, 894, 903, 917-926(5), 1086

mon_names defined in line 219; used 1 times

- in line 856

nlinks defined in line 203; used 3 times

- in line 427, 839-840(2)

noise defined in line 55; used 3 times

- in line 393, 895, 918

nrules defined in line 172; used 6 times

- in line 512-513(2), 519-521(2), 699-700(2)

nzones defined in line 193; used 10 times

- in line 411-415(2), 514, 524, 532, 721, 799-801(2), 807-808(2)

progname defined in line 59; used 20 times

- in line 295, 350(2), 367, 378, 388, 423, 431, 440, 569, 614, 621-626(2), 891, 914, 1008, 1017, 1039, 1263, 1535

rfilename defined in line 60; used 3 times

- in line 316, 338-340(2)

rlinenum defined in line 61; used 2 times

- in line 317, 340

rules defined in line 171; used 9 times

- in line 404, 513(2), 520-522(2), 698-700(4)

timecnt defined in line 66; used 13 times

- in line 1023-1030(4), 1065, 1174, 1185, 1194-1202(6)

tt_signed defined in line 67; used 3 times

- in line 456-460(2), 1472

typecnt defined in line 68; used 6 times

- in line 1024, 1031, 1066, 1216, 1225, 1238

types defined in line 280; used 5 times

- in line 1029(2), 1185, 1194, 1201

wday_names defined in line 235; used 1 times

- in line 969

zones defined in line 192; used 15 times

- in line 403, 415-417(2), 515, 525, 533, 722-728(4), 801-808(5)

#### Defined struct's

link defined in line 195; used 8 times

- in line 202(2), 405(2), 820(2), 838(2)

lookup defined in line 205; used 26 times

- in line 210-212(4), 219(2), 235(2), 246(2), 257(2), 263(2), 559(2), 853(2), 1300-1306(8)

rule defined in line 131; used 24 times

- in line 171(2), 185-188(4), 404(2), 500-501(4), 508(2), 681(2), 698(2), 845(2), 1050(2), 1404(2)

zone defined in line 174; used 14 times

- in line 192(2), 403(2), 507(2), 751(2), 806(2), 1047-1049(4)

#### Defined macros

BUFSIZ defined in line 15; used 6 times

- in line 14, 563, 1004, 1060, 1107, 1246

DC_DOM defined in line 159; used 2 times

- in line 961-963(2)

DC_DOWGEQ defined in line 160; used 3 times

- in line 958, 1440, 1456

DC_DOWLEQ defined in line 161; used 4 times

- in line 951-956(2), 1431, 1440

FALSE defined in line 20; used 20 times

- in line 456, 573, 602, 609, 712, 719, 730-732(2), 741, 782, 803, 861, 871-876(2), 1148, 1166, 1260, 1282, 1291-1295(2)

LC_LINK defined in line 77; used 1 times

- in line 215

LC_RULE defined in line 75; used 1 times

- in line 213

LC_ZONE defined in line 76; used 1 times

- in line 214

LDAYS_PER_WEEK defined in line 1443; used 5 times

- in line 1449-1458(4), 1464

LF_FROM defined in line 127; used 2 times

- in line 826, 836

LF_TO defined in line 128; used 2 times

- in line 830, 837

LINK_FIELDS defined in line 129; used 1 times

- in line 822

RF_ABBRVAR defined in line 120; used 1 times

- in line 697

RF_COMMAND defined in line 115; used 1 times

- in line 694

RF_DAY defined in line 117; used 1 times

- in line 695

RF_HIYEAR defined in line 114; used 1 times

- in line 694

RF_LOYEAR defined in line 113; used 1 times

- in line 694

RF_MONTH defined in line 116; used 1 times

- in line 695

RF_NAME defined in line 112; used 2 times

- in line 687, 696

RF_STDOFF defined in line 119; used 1 times

- in line 693

RF_TOD defined in line 118; used 1 times

- in line 695

RULE_FIELDS defined in line 121; used 1 times

- in line 683

TRUE defined in line 19; used 12 times

- in line 18, 393, 460, 539, 693, 743, 778, 867, 1250, 1258, 1281, 1297

YR_MAXIMUM defined in line 168; used 2 times

- in line 259, 265

YR_MINIMUM defined in line 167; used 2 times

- in line 258, 264

YR_ONLY defined in line 169; used 1 times

- in line 266

ZFC_FORMAT defined in line 100; used 1 times

- in line 760

ZFC_GMTOFF defined in line 98; used 1 times

- in line 758

ZFC_RULE defined in line 99; used 1 times

- in line 759

ZFC_UNTILDAY defined in line 103; used 1 times

- in line 763

ZFC_UNTILMONTH defined in line 102; used 1 times

- in line 762

ZFC_UNTILTIME defined in line 104; used 1 times

- in line 764

ZFC_UNTILYEAR defined in line 101; used 1 times

- in line 761

ZF_FORMAT defined in line 86; used 1 times

- in line 769

ZF_GMTOFF defined in line 84; used 1 times

- in line 767

ZF_NAME defined in line 83; used 4 times

- in line 714, 723-726(2), 774

ZF_RULE defined in line 85; used 1 times

- in line 768

ZF_UNTILDAY defined in line 89; used 1 times

- in line 772

ZF_UNTILMONTH defined in line 88; used 1 times

- in line 771

ZF_UNTILTIME defined in line 90; used 1 times

- in line 773

ZF_UNTILYEAR defined in line 87; used 1 times

- in line 770

ZONEC_MAXFIELDS defined in line 106; used 1 times

- in line 739

ZONEC_MINFIELDS defined in line 105; used 1 times

- in line 739

ZONE_MAXFIELDS defined in line 92; used 1 times

- in line 710

ZONE_MINFIELDS defined in line 91; used 1 times

- in line 710

ecpyalloc defined in line 303; used 8 times

- in line 696-697(2), 774, 785-786(2), 836-837(2), 940

emalloc defined in line 301; used 4 times

- in line 403-405(3), 1338

erealloc defined in line 302; used 3 times

- in line 698, 806, 838

Last modified: 1987-03-31 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 5553 |