📄 zic.c
字号:
}static voidassociate(){ register struct zone * zp; register struct rule * rp; register int base, out; register int i; if (nrules != 0) (void) qsort((void *) rules, (size_t) nrules, (size_t) sizeof *rules, rcomp); for (i = 0; i < nzones; ++i) { zp = &zones[i]; zp->z_rules = NULL; zp->z_nrules = 0; } for (base = 0; base < nrules; base = out) { rp = &rules[base]; for (out = base + 1; out < nrules; ++out) if (strcmp(rp->r_name, rules[out].r_name) != 0) break; for (i = 0; i < nzones; ++i) { zp = &zones[i]; if (strcmp(zp->z_rule, rp->r_name) != 0) continue; zp->z_rules = rp; zp->z_nrules = out - base; } } for (i = 0; i < nzones; ++i) { zp = &zones[i]; if (zp->z_nrules == 0) { /* ** Maybe we have a local standard time offset. */ eat(zp->z_filename, zp->z_linenum); zp->z_stdoff = gethms((char *)zp->z_rule, "unruly zone", TRUE); /* ** Note, though, that if there's no rule, ** a '%s' in the format is a bad thing. */ if (strchr(zp->z_format, '%') != 0) error("%s in ruleless zone"); } } if (errors) (void) exit(EXIT_FAILURE);}static voidinfile(name)const char * name;{ register FILE * fp; register char ** fields; register char * cp; register const struct lookup * lp; register int nfields; register int wantcont; register int num; char buf[BUFSIZ]; if (strcmp(name, "-") == 0) { name = "standard input"; fp = stdin; } else if ((fp = fopen(name, "r")) == NULL) { (void) fprintf(stderr, "%s: Can't open ", progname); (void) perror(name); (void) exit(EXIT_FAILURE); } wantcont = FALSE; for (num = 1; ; ++num) { eat(name, num); if (fgets(buf, (int) sizeof buf, fp) != buf) break; cp = strchr(buf, '\n'); if (cp == NULL) { error("line too long"); (void) exit(EXIT_FAILURE); } *cp = '\0'; fields = getfields(buf); nfields = 0; while (fields[nfields] != NULL) { if (ciequal(fields[nfields], "-")) fields[nfields] = ""; ++nfields; } if (nfields == 0) { /* nothing to do */ } else if (wantcont) { wantcont = inzcont(fields, nfields); } else { lp = byword(fields[0], line_codes); if (lp == NULL) error("input line of unknown type"); else switch ((int) (lp->l_value)) { case LC_RULE: inrule(fields, nfields); wantcont = FALSE; break; case LC_ZONE: wantcont = inzone(fields, nfields); break; case LC_LINK: inlink(fields, nfields); wantcont = FALSE; break; case LC_LEAP: if (name != leapsec) (void) fprintf(stderr,"%s: Leap line in non leap seconds file %s\n", progname, name); else inleap(fields, nfields); wantcont = FALSE; break; default: /* "cannot happen" */ (void) fprintf(stderr,"%s: panic: Invalid l_value %d\n", progname, lp->l_value); (void) exit(EXIT_FAILURE); } } ifree((char *) fields); } if (ferror(fp)) { (void) fprintf(stderr, "%s: Error reading ", progname); (void) perror(filename); (void) exit(EXIT_FAILURE); } if (fp != stdin && fclose(fp)) { (void) fprintf(stderr, "%s: Error closing ", progname); (void) perror(filename); (void) exit(EXIT_FAILURE); } if (wantcont) error("expected continuation line not found");}/*** Convert a string of one of the forms** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss** into a number of seconds.** A null string maps to zero.** Call error with errstring and return zero on errors.*/static longgethms(string, errstring, signable)char * string;const char * const errstring;const int signable;{ int hh, mm, ss, sign; if (string == NULL || *string == '\0') return 0; if (!signable) sign = 1; else if (*string == '-') { sign = -1; ++string; } else sign = 1; if (sscanf(string, scheck(string, "%d"), &hh) == 1) mm = ss = 0; else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) ss = 0; else if (sscanf(string, scheck(string, "%d:%d:%d"), &hh, &mm, &ss) != 3) { error(errstring); return 0; } if (hh < 0 || hh >= HOURSPERDAY || mm < 0 || mm >= MINSPERHOUR || ss < 0 || ss > SECSPERMIN) { error(errstring); return 0; } return eitol(sign) * (eitol(hh * MINSPERHOUR + mm) * eitol(SECSPERMIN) + eitol(ss));}static voidinrule(fields, nfields)register char ** const fields;const int nfields;{ static struct rule r; if (nfields != RULE_FIELDS) { error("wrong number of fields on Rule line"); return; } if (*fields[RF_NAME] == '\0') { error("nameless rule"); return; } r.r_filename = filename; r.r_linenum = linenum; r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); r.r_name = ecpyalloc(fields[RF_NAME]); r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); rules = (struct rule *) erealloc((char *) rules, (int) ((nrules + 1) * sizeof *rules)); rules[nrules++] = r;}static intinzone(fields, nfields)register char ** const fields;const int nfields;{ register int i; char buf[132]; if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { error("wrong number of fields on Zone line"); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { (void) sprintf(buf, "\"Zone %s\" line and -l option are mutually exclusive", TZDEFAULT); error(buf); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { (void) sprintf(buf, "\"Zone %s\" line and -p option are mutually exclusive", TZDEFRULES); error(buf); return FALSE; } for (i = 0; i < nzones; ++i) if (zones[i].z_name != NULL && strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { (void) sprintf(buf,"duplicate zone name %s (file \"%s\", line %d)", fields[ZF_NAME], zones[i].z_filename, zones[i].z_linenum); error(buf); return FALSE; } return inzsub(fields, nfields, FALSE);}static intinzcont(fields, nfields)register char ** const fields;const int nfields;{ if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { error("wrong number of fields on Zone continuation line"); return FALSE; } return inzsub(fields, nfields, TRUE);}static intinzsub(fields, nfields, iscont)register char ** const fields;const int nfields;const int iscont;{ register char * cp; static struct zone z; register int i_gmtoff, i_rule, i_format; register int i_untilyear, i_untilmonth; register int i_untilday, i_untiltime; register int hasuntil; if (iscont) { i_gmtoff = ZFC_GMTOFF; i_rule = ZFC_RULE; i_format = ZFC_FORMAT; i_untilyear = ZFC_TILYEAR; i_untilmonth = ZFC_TILMONTH; i_untilday = ZFC_TILDAY; i_untiltime = ZFC_TILTIME; z.z_name = NULL; } else { i_gmtoff = ZF_GMTOFF; i_rule = ZF_RULE; i_format = ZF_FORMAT; i_untilyear = ZF_TILYEAR; i_untilmonth = ZF_TILMONTH; i_untilday = ZF_TILDAY; i_untiltime = ZF_TILTIME; z.z_name = ecpyalloc(fields[ZF_NAME]); } z.z_filename = filename; z.z_linenum = linenum; z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); if ((cp = strchr(fields[i_format], '%')) != 0) { if (*++cp != 's' || strchr(cp, '%') != 0) { error("invalid abbreviation format"); return FALSE; } } z.z_rule = ecpyalloc(fields[i_rule]); z.z_format = ecpyalloc(fields[i_format]); hasuntil = nfields > i_untilyear; if (hasuntil) { z.z_untilrule.r_filename = filename; z.z_untilrule.r_linenum = linenum; rulesub(&z.z_untilrule, fields[i_untilyear], "only", "", (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", (nfields > i_untilday) ? fields[i_untilday] : "1", (nfields > i_untiltime) ? fields[i_untiltime] : "0"); z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); if (iscont && nzones > 0 && z.z_untiltime < max_time && z.z_untiltime > min_time && zones[nzones - 1].z_untiltime >= z.z_untiltime) {error("Zone continuation line end time is not after end time of previous line"); return FALSE; } } zones = (struct zone *) erealloc((char *) zones, (int) ((nzones + 1) * sizeof *zones)); zones[nzones++] = z; /* ** If there was an UNTIL field on this line, ** there's more information about the zone on the next line. */ return hasuntil;}static voidinleap(fields, nfields)register char ** const fields;const int nfields;{ register const char * cp; register const struct lookup * lp; register int i, j; int year, month, day; long dayoff, tod; time_t t; if (nfields != LEAP_FIELDS) { error("wrong number of fields on Leap line"); return; } dayoff = 0; cp = fields[LP_YEAR]; if (sscanf((char *)cp, scheck(cp, "%d"), &year) != 1 || year < min_year || year > max_year) { /* * Leapin' Lizards! */ error("invalid leaping year"); return; } j = EPOCH_YEAR; while (j != year) { if (year > j) { i = len_years[isleap(j)]; ++j; } else { --j; i = -len_years[isleap(j)]; } dayoff = oadd(dayoff, eitol(i)); } if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { error("invalid month name"); return; } month = lp->l_value; j = TM_JANUARY; while (j != month) { i = len_months[isleap(year)][j]; dayoff = oadd(dayoff, eitol(i)); ++j; } cp = fields[LP_DAY]; if (sscanf((char *)cp, scheck(cp, "%d"), &day) != 1 || day <= 0 || day > len_months[isleap(year)][month]) { error("invalid day of month"); return; } dayoff = oadd(dayoff, eitol(day - 1)); if (dayoff < 0 && !tt_signed) { error("time before zero"); return; } t = (time_t) dayoff * SECSPERDAY; /* ** Cheap overflow check. */ if (t / SECSPERDAY != dayoff) { error("time overflow"); return; } tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); cp = fields[LP_CORR]; if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) { /* infile() turned "-" into "" */ error("illegal CORRECTION field on Leap line"); return; } if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { error("illegal Rolling/Stationary field on Leap line"); return; } addleap(tadd(t, tod), *cp == '+', lp->l_value);}static voidinlink(fields, nfields)register char ** const fields;const int nfields;{ struct link l; if (nfields != LINK_FIELDS) { error("wrong number of fields on Link line"); return; } if (*fields[LF_FROM] == '\0') { error("blank FROM field on Link line"); return; } if (*fields[LF_TO] == '\0') { error("blank TO field on Link line"); return; } l.l_filename = filename; l.l_linenum = linenum; l.l_from = ecpyalloc(fields[LF_FROM]); l.l_to = ecpyalloc(fields[LF_TO]); links = (struct link *) erealloc((char *) links, (int) ((nlinks + 1) * sizeof *links)); links[nlinks++] = l;}static voidrulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)register struct rule * const rp;char * const loyearp;char * const hiyearp;char * const typep;char * const monthp;char * const dayp;char * const timep;{ register struct lookup const * lp; register char * cp; if ((lp = byword(monthp, mon_names)) == NULL) { error("invalid month name"); return; } rp->r_month = lp->l_value; rp->r_todisstd = FALSE; cp = timep; if (*cp != '\0') { cp += strlen(cp) - 1; switch (lowerit(*cp)) { case 's': rp->r_todisstd = TRUE; *cp = '\0'; break; case 'w': rp->r_todisstd = FALSE; *cp = '\0'; break; } } rp->r_tod = gethms(timep, "invalid time of day", FALSE); /* ** Year work. */ cp = loyearp; if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: rp->r_loyear = min_year; break; case YR_MAXIMUM: rp->r_loyear = max_year; break; default: /* "cannot happen" */ (void) fprintf(stderr, "%s: panic: Invalid l_value %d\n", progname, lp->l_value); (void) exit(EXIT_FAILURE); } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 || rp->r_loyear < min_year || rp->r_loyear > max_year) { if (noise) error("invalid starting year"); if (rp->r_loyear > max_year) return; } cp = hiyearp; if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: rp->r_hiyear = min_year; break; case YR_MAXIMUM: rp->r_hiyear = max_year; break; case YR_ONLY: rp->r_hiyear = rp->r_loyear; break; default: /* "cannot happen" */ (void) fprintf(stderr, "%s: panic: Invalid l_value %d\n", progname, lp->l_value); (void) exit(EXIT_FAILURE); } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 || rp->r_hiyear < min_year || rp->r_hiyear > max_year) { if (noise) error("invalid ending year"); if (rp->r_hiyear < min_year) return; } if (rp->r_hiyear < min_year) return; if (rp->r_loyear < min_year) rp->r_loyear = min_year; if (rp->r_hiyear > max_year) rp->r_hiyear = max_year; if (rp->r_loyear > rp->r_hiyear) { error("starting year greater than ending year"); return; } if (*typep == '\0') rp->r_yrtype = NULL; else { if (rp->r_loyear == rp->r_hiyear) { error("typed single year"); return; } rp->r_yrtype = ecpyalloc(typep); } /* ** Day work. ** Accept things such as: ** 1 ** last-Sunday ** Sun<=20 ** Sun>=7 */ if ((lp = byword(dayp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { if ((cp = strchr(dayp, '<')) != 0) rp->r_dycode = DC_DOWLEQ; else if ((cp = strchr(dayp, '>')) != 0) rp->r_dycode = DC_DOWGEQ; else { cp = dayp; rp->r_dycode = DC_DOM; } if (rp->r_dycode != DC_DOM) { *cp++ = 0; if (*cp++ != '=') { error("invalid day of month"); return; } if ((lp = byword(dayp, wday_names)) == NULL) { error("invalid weekday name"); return; } rp->r_wday = lp->l_value; } if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || rp->r_dayofmonth <= 0 || (rp->r_dayofmonth > len_months[1][rp->r_month])) { error("invalid day of month"); return; } }}static voidconvert(val, buf)const long val;char * const buf;{ register int i; register long shift; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) buf[i] = val >> shift;}static voidputtzcode(val, fp)const long val;FILE * const fp;{ char buf[4]; convert(val, buf); (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);}static voidwritezone(name)const char * const name;{ register FILE * fp; register int i, j; char fullname[BUFSIZ]; static struct tzhead tzh; if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) { (void) fprintf(stderr, "%s: File name %s/%s too long\n", progname, directory, name); (void) exit(EXIT_FAILURE); } (void) sprintf(fullname, "%s/%s", directory, name); if ((fp = fopen(fullname, "wb")) == NULL) { if (mkdirs(fullname) != 0) (void) exit(EXIT_FAILURE); if ((fp = fopen(fullname, "wb")) == NULL) { (void) fprintf(stderr, "%s: Can't create ", progname);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -