]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - contrib/tzcode/zic/zic.c
Merge r307359 from stable/10:
[FreeBSD/releng/10.1.git] / contrib / tzcode / zic / zic.c
1 /*
2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
4 */
5
6 static const char       elsieid[] = "@(#)zic.c  8.22";
7
8 #ifndef lint
9 static const char rcsid[] =
10   "$FreeBSD$";
11 #endif /* not lint */
12
13 #include "private.h"
14 #include "tzfile.h"
15 #include <err.h>
16 #include <locale.h>
17 #include <sys/stat.h>                   /* for umask manifest constants */
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #define ZIC_VERSION     '2'
22
23 typedef int_fast64_t    zic_t;
24
25 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
26 #define ZIC_MAX_ABBR_LEN_WO_WARN        6
27 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
28
29 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
30
31 /*
32 ** On some ancient hosts, predicates like `isspace(C)' are defined
33 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
34 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
35 ** Neither the C Standard nor POSIX require that `isascii' exist.
36 ** For portability, we check both ancient and modern requirements.
37 ** If isascii is not defined, the isascii check succeeds trivially.
38 */
39 #include "ctype.h"
40 #ifndef isascii
41 #define isascii(x) 1
42 #endif
43
44 #define OFFSET_STRLEN_MAXIMUM   (7 + INT_STRLEN_MAXIMUM(long))
45 #define RULE_STRLEN_MAXIMUM     8       /* "Mdd.dd.d" */
46
47 #define end(cp) (strchr((cp), '\0'))
48
49 struct rule {
50         const char *    r_filename;
51         int             r_linenum;
52         const char *    r_name;
53
54         int             r_loyear;       /* for example, 1986 */
55         int             r_hiyear;       /* for example, 1986 */
56         const char *    r_yrtype;
57         int             r_lowasnum;
58         int             r_hiwasnum;
59
60         int             r_month;        /* 0..11 */
61
62         int             r_dycode;       /* see below */
63         int             r_dayofmonth;
64         int             r_wday;
65
66         long            r_tod;          /* time from midnight */
67         int             r_todisstd;     /* above is standard time if TRUE */
68                                         /* or wall clock time if FALSE */
69         int             r_todisgmt;     /* above is GMT if TRUE */
70                                         /* or local time if FALSE */
71         long            r_stdoff;       /* offset from standard time */
72         const char *    r_abbrvar;      /* variable part of abbreviation */
73
74         int             r_todo;         /* a rule to do (used in outzone) */
75         zic_t           r_temp;         /* used in outzone */
76 };
77
78 /*
79 **      r_dycode                r_dayofmonth    r_wday
80 */
81
82 #define DC_DOM          0       /* 1..31 */     /* unused */
83 #define DC_DOWGEQ       1       /* 1..31 */     /* 0..6 (Sun..Sat) */
84 #define DC_DOWLEQ       2       /* 1..31 */     /* 0..6 (Sun..Sat) */
85
86 struct zone {
87         const char *    z_filename;
88         int             z_linenum;
89
90         const char *    z_name;
91         long            z_gmtoff;
92         const char *    z_rule;
93         const char *    z_format;
94
95         long            z_stdoff;
96
97         struct rule *   z_rules;
98         int             z_nrules;
99
100         struct rule     z_untilrule;
101         zic_t           z_untiltime;
102 };
103
104 static void     addtt(zic_t starttime, int type);
105 static int      addtype(long gmtoff, const char * abbr, int isdst,
106                                 int ttisstd, int ttisgmt);
107 static void     leapadd(zic_t t, int positive, int rolling, int count);
108 static void     adjleap(void);
109 static void     associate(void);
110 static int      ciequal(const char * ap, const char * bp);
111 static void     convert(long val, char * buf);
112 static void     convert64(zic_t val, char * buf);
113 static void     dolink(const char * fromfield, const char * tofield);
114 static void     doabbr(char * abbr, const char * format,
115                         const char * letters, int isdst, int doquotes);
116 static void     eat(const char * name, int num);
117 static void     eats(const char * name, int num,
118                         const char * rname, int rnum);
119 static long     eitol(int i);
120 static void     error(const char * message);
121 static char **  getfields(char * buf);
122 static long     gethms(const char * string, const char * errstrng,
123                         int signable);
124 static void     infile(const char * filename);
125 static void     inleap(char ** fields, int nfields);
126 static void     inlink(char ** fields, int nfields);
127 static void     inrule(char ** fields, int nfields);
128 static int      inzcont(char ** fields, int nfields);
129 static int      inzone(char ** fields, int nfields);
130 static int      inzsub(char ** fields, int nfields, int iscont);
131 static int      is32(zic_t x);
132 static int      itsabbr(const char * abbr, const char * word);
133 static int      itsdir(const char * name);
134 static int      lowerit(int c);
135 static char *   memcheck(char * tocheck);
136 static int      mkdirs(char * filename);
137 static void     newabbr(const char * abbr);
138 static long     oadd(long t1, long t2);
139 static void     outzone(const struct zone * zp, int ntzones);
140 static void     puttzcode(long code, FILE * fp);
141 static void     puttzcode64(zic_t code, FILE * fp);
142 static int      rcomp(const void * leftp, const void * rightp);
143 static zic_t    rpytime(const struct rule * rp, int wantedy);
144 static void     rulesub(struct rule * rp,
145                         const char * loyearp, const char * hiyearp,
146                         const char * typep, const char * monthp,
147                         const char * dayp, const char * timep);
148 static int      stringoffset(char * result, long offset);
149 static int      stringrule(char * result, const struct rule * rp,
150                         long dstoff, long gmtoff);
151 static void     stringzone(char * result,
152                         const struct zone * zp, int ntzones);
153 static void     setboundaries(void);
154 static void     setgroup(gid_t *flag, const char *name);
155 static void     setuser(uid_t *flag, const char *name);
156 static zic_t    tadd(zic_t t1, long t2);
157 static void     usage(FILE *stream, int status);
158 static void     writezone(const char * name, const char * string);
159 static int      yearistype(int year, const char * type);
160
161 static int              charcnt;
162 static int              errors;
163 static const char *     filename;
164 static int              leapcnt;
165 static int              leapseen;
166 static int              leapminyear;
167 static int              leapmaxyear;
168 static int              linenum;
169 static int              max_abbrvar_len;
170 static int              max_format_len;
171 static zic_t            max_time;
172 static int              max_year;
173 static zic_t            min_time;
174 static int              min_year;
175 static zic_t            min_time;
176 static int              noise;
177 static const char *     rfilename;
178 static int              rlinenum;
179 static int              timecnt;
180 static int              typecnt;
181
182 /*
183 ** Line codes.
184 */
185
186 #define LC_RULE         0
187 #define LC_ZONE         1
188 #define LC_LINK         2
189 #define LC_LEAP         3
190
191 /*
192 ** Which fields are which on a Zone line.
193 */
194
195 #define ZF_NAME         1
196 #define ZF_GMTOFF       2
197 #define ZF_RULE         3
198 #define ZF_FORMAT       4
199 #define ZF_TILYEAR      5
200 #define ZF_TILMONTH     6
201 #define ZF_TILDAY       7
202 #define ZF_TILTIME      8
203 #define ZONE_MINFIELDS  5
204 #define ZONE_MAXFIELDS  9
205
206 /*
207 ** Which fields are which on a Zone continuation line.
208 */
209
210 #define ZFC_GMTOFF      0
211 #define ZFC_RULE        1
212 #define ZFC_FORMAT      2
213 #define ZFC_TILYEAR     3
214 #define ZFC_TILMONTH    4
215 #define ZFC_TILDAY      5
216 #define ZFC_TILTIME     6
217 #define ZONEC_MINFIELDS 3
218 #define ZONEC_MAXFIELDS 7
219
220 /*
221 ** Which files are which on a Rule line.
222 */
223
224 #define RF_NAME         1
225 #define RF_LOYEAR       2
226 #define RF_HIYEAR       3
227 #define RF_COMMAND      4
228 #define RF_MONTH        5
229 #define RF_DAY          6
230 #define RF_TOD          7
231 #define RF_STDOFF       8
232 #define RF_ABBRVAR      9
233 #define RULE_FIELDS     10
234
235 /*
236 ** Which fields are which on a Link line.
237 */
238
239 #define LF_FROM         1
240 #define LF_TO           2
241 #define LINK_FIELDS     3
242
243 /*
244 ** Which fields are which on a Leap line.
245 */
246
247 #define LP_YEAR         1
248 #define LP_MONTH        2
249 #define LP_DAY          3
250 #define LP_TIME         4
251 #define LP_CORR         5
252 #define LP_ROLL         6
253 #define LEAP_FIELDS     7
254
255 /*
256 ** Year synonyms.
257 */
258
259 #define YR_MINIMUM      0
260 #define YR_MAXIMUM      1
261 #define YR_ONLY         2
262
263 static struct rule *    rules;
264 static int              nrules; /* number of rules */
265
266 static struct zone *    zones;
267 static int              nzones; /* number of zones */
268
269 struct link {
270         const char *    l_filename;
271         int             l_linenum;
272         const char *    l_from;
273         const char *    l_to;
274 };
275
276 static struct link *    links;
277 static int              nlinks;
278
279 struct lookup {
280         const char *    l_word;
281         const int       l_value;
282 };
283
284 static struct lookup const *    byword(const char * string,
285                                         const struct lookup * lp);
286
287 static struct lookup const      line_codes[] = {
288         { "Rule",       LC_RULE },
289         { "Zone",       LC_ZONE },
290         { "Link",       LC_LINK },
291         { "Leap",       LC_LEAP },
292         { NULL,         0}
293 };
294
295 static struct lookup const      mon_names[] = {
296         { "January",    TM_JANUARY },
297         { "February",   TM_FEBRUARY },
298         { "March",      TM_MARCH },
299         { "April",      TM_APRIL },
300         { "May",        TM_MAY },
301         { "June",       TM_JUNE },
302         { "July",       TM_JULY },
303         { "August",     TM_AUGUST },
304         { "September",  TM_SEPTEMBER },
305         { "October",    TM_OCTOBER },
306         { "November",   TM_NOVEMBER },
307         { "December",   TM_DECEMBER },
308         { NULL,         0 }
309 };
310
311 static struct lookup const      wday_names[] = {
312         { "Sunday",     TM_SUNDAY },
313         { "Monday",     TM_MONDAY },
314         { "Tuesday",    TM_TUESDAY },
315         { "Wednesday",  TM_WEDNESDAY },
316         { "Thursday",   TM_THURSDAY },
317         { "Friday",     TM_FRIDAY },
318         { "Saturday",   TM_SATURDAY },
319         { NULL,         0 }
320 };
321
322 static struct lookup const      lasts[] = {
323         { "last-Sunday",        TM_SUNDAY },
324         { "last-Monday",        TM_MONDAY },
325         { "last-Tuesday",       TM_TUESDAY },
326         { "last-Wednesday",     TM_WEDNESDAY },
327         { "last-Thursday",      TM_THURSDAY },
328         { "last-Friday",        TM_FRIDAY },
329         { "last-Saturday",      TM_SATURDAY },
330         { NULL,                 0 }
331 };
332
333 static struct lookup const      begin_years[] = {
334         { "minimum",    YR_MINIMUM },
335         { "maximum",    YR_MAXIMUM },
336         { NULL,         0 }
337 };
338
339 static struct lookup const      end_years[] = {
340         { "minimum",    YR_MINIMUM },
341         { "maximum",    YR_MAXIMUM },
342         { "only",       YR_ONLY },
343         { NULL,         0 }
344 };
345
346 static struct lookup const      leap_types[] = {
347         { "Rolling",    TRUE },
348         { "Stationary", FALSE },
349         { NULL,         0 }
350 };
351
352 static const int        len_months[2][MONSPERYEAR] = {
353         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
354         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
355 };
356
357 static const int        len_years[2] = {
358         DAYSPERNYEAR, DAYSPERLYEAR
359 };
360
361 static struct attype {
362         zic_t           at;
363         unsigned char   type;
364 }                       attypes[TZ_MAX_TIMES];
365 static long             gmtoffs[TZ_MAX_TYPES];
366 static char             isdsts[TZ_MAX_TYPES];
367 static unsigned char    abbrinds[TZ_MAX_TYPES];
368 static char             ttisstds[TZ_MAX_TYPES];
369 static char             ttisgmts[TZ_MAX_TYPES];
370 static char             chars[TZ_MAX_CHARS];
371 static zic_t            trans[TZ_MAX_LEAPS];
372 static long             corr[TZ_MAX_LEAPS];
373 static char             roll[TZ_MAX_LEAPS];
374
375 /*
376 ** Memory allocation.
377 */
378
379 static char *
380 memcheck(ptr)
381 char * const    ptr;
382 {
383         if (ptr == NULL)
384                 errx(EXIT_FAILURE, _("memory exhausted"));
385         return ptr;
386 }
387
388 #define emalloc(size)           memcheck(imalloc(size))
389 #define erealloc(ptr, size)     memcheck(irealloc((ptr), (size)))
390 #define ecpyalloc(ptr)          memcheck(icpyalloc(ptr))
391 #define ecatalloc(oldp, newp)   memcheck(icatalloc((oldp), (newp)))
392
393 /*
394 ** Error handling.
395 */
396
397 static void
398 eats(name, num, rname, rnum)
399 const char * const      name;
400 const int               num;
401 const char * const      rname;
402 const int               rnum;
403 {
404         filename = name;
405         linenum = num;
406         rfilename = rname;
407         rlinenum = rnum;
408 }
409
410 static void
411 eat(name, num)
412 const char * const      name;
413 const int               num;
414 {
415         eats(name, num, (char *) NULL, -1);
416 }
417
418 static void
419 error(string)
420 const char * const      string;
421 {
422         /*
423         ** Match the format of "cc" to allow sh users to
424         **      zic ... 2>&1 | error -t "*" -v
425         ** on BSD systems.
426         */
427         (void) fprintf(stderr, _("\"%s\", line %d: %s"),
428                 filename, linenum, string);
429         if (rfilename != NULL)
430                 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
431                         rfilename, rlinenum);
432         (void) fprintf(stderr, "\n");
433         ++errors;
434 }
435
436 static void
437 warning(string)
438 const char * const      string;
439 {
440         char *  cp;
441
442         cp = ecpyalloc(_("warning: "));
443         cp = ecatalloc(cp, string);
444         error(cp);
445         ifree(cp);
446         --errors;
447 }
448
449 static void
450 usage(FILE *stream, int status)
451   {
452         (void) fprintf(stream, _("usage is zic \
453 [ --version ] [--help] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
454 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
455 \n\
456 Report bugs to tz@elsie.nci.nih.gov.\n"));
457         exit(status);
458 }
459
460 static const char *     psxrules;
461 static const char *     lcltime;
462 static const char *     directory;
463 static const char *     leapsec;
464 static const char *     yitcommand;
465 static int              Dflag;
466 static uid_t            uflag = (uid_t)-1;
467 static gid_t            gflag = (gid_t)-1;
468 static mode_t           mflag = (S_IRUSR | S_IRGRP | S_IROTH
469                                  | S_IWUSR);
470
471 int
472 main(argc, argv)
473 int     argc;
474 char *  argv[];
475 {
476         register int    i;
477         register int    j;
478         register int    c;
479
480 #ifdef unix
481         (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
482 #endif /* defined unix */
483 #if HAVE_GETTEXT
484         (void) setlocale(LC_ALL, "");
485 #ifdef TZ_DOMAINDIR
486         (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
487 #endif /* defined TEXTDOMAINDIR */
488         (void) textdomain(TZ_DOMAIN);
489 #endif /* HAVE_GETTEXT */
490         if (TYPE_BIT(zic_t) < 64) {
491                 (void) fprintf(stderr, "zic: %s\n",
492                         _("wild compilation-time specification of zic_t"));
493                 exit(EXIT_FAILURE);
494         }
495         for (i = 1; i < argc; ++i)
496                 if (strcmp(argv[i], "--version") == 0) {
497                         errx(EXIT_SUCCESS, "%s", elsieid);
498                 } else if (strcmp(argv[i], "--help") == 0) {
499                         usage(stdout, EXIT_SUCCESS);
500                 }
501         while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
502                 switch (c) {
503                         default:
504                                 usage(stderr, EXIT_FAILURE);
505                         case 'D':
506                                 Dflag = 1;
507                                 break;
508                         case 'd':
509                                 if (directory == NULL)
510                                         directory = optarg;
511                                 else
512                                         errx(EXIT_FAILURE,
513 _("more than one -d option specified"));
514                                 break;
515                         case 'g':
516                                 setgroup(&gflag, optarg);
517                                 break;
518                         case 'l':
519                                 if (lcltime == NULL)
520                                         lcltime = optarg;
521                                 else
522                                         errx(EXIT_FAILURE,
523 _("more than one -l option specified"));
524                                 break;
525                         case 'm':
526                         {
527                                 void *set = setmode(optarg);
528                                 if (set == NULL)
529                                         errx(EXIT_FAILURE,
530 _("invalid file mode"));
531                                 mflag = getmode(set, mflag);
532                                 free(set);
533                                 break;
534                         }
535                         case 'p':
536                                 if (psxrules == NULL)
537                                         psxrules = optarg;
538                                 else
539                                         errx(EXIT_FAILURE,
540 _("more than one -p option specified"));
541                                 break;
542                         case 'u':
543                                 setuser(&uflag, optarg);
544                                 break;
545                         case 'y':
546                                 if (yitcommand == NULL)
547                                         yitcommand = optarg;
548                                 else
549                                         errx(EXIT_FAILURE,
550 _("more than one -y option specified"));
551                                 break;
552                         case 'L':
553                                 if (leapsec == NULL)
554                                         leapsec = optarg;
555                                 else
556                                         errx(EXIT_FAILURE,
557 _("more than one -L option specified"));
558                                 break;
559                         case 'v':
560                                 noise = TRUE;
561                                 break;
562                         case 's':
563                                 (void) printf("zic: -s ignored\n");
564                                 break;
565                 }
566         if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
567                 usage(stderr, EXIT_FAILURE);    /* usage message by request */
568         if (directory == NULL)
569                 directory = TZDIR;
570         if (yitcommand == NULL)
571                 yitcommand = "yearistype";
572
573         setboundaries();
574
575         if (optind < argc && leapsec != NULL) {
576                 infile(leapsec);
577                 adjleap();
578         }
579
580         for (i = optind; i < argc; ++i)
581                 infile(argv[i]);
582         if (errors)
583                 exit(EXIT_FAILURE);
584         associate();
585         for (i = 0; i < nzones; i = j) {
586                 /*
587                 ** Find the next non-continuation zone entry.
588                 */
589                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
590                         continue;
591                 outzone(&zones[i], j - i);
592         }
593         /*
594         ** Make links.
595         */
596         for (i = 0; i < nlinks; ++i) {
597                 eat(links[i].l_filename, links[i].l_linenum);
598                 dolink(links[i].l_from, links[i].l_to);
599                 if (noise)
600                         for (j = 0; j < nlinks; ++j)
601                                 if (strcmp(links[i].l_to,
602                                         links[j].l_from) == 0)
603                                                 warning(_("link to link"));
604         }
605         if (lcltime != NULL) {
606                 eat("command line", 1);
607                 dolink(lcltime, TZDEFAULT);
608         }
609         if (psxrules != NULL) {
610                 eat("command line", 1);
611                 dolink(psxrules, TZDEFRULES);
612         }
613         return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
614 }
615
616 static void
617 dolink(fromfield, tofield)
618 const char * const      fromfield;
619 const char * const      tofield;
620 {
621         register char * fromname;
622         register char * toname;
623
624         if (fromfield[0] == '/')
625                 fromname = ecpyalloc(fromfield);
626         else {
627                 fromname = ecpyalloc(directory);
628                 fromname = ecatalloc(fromname, "/");
629                 fromname = ecatalloc(fromname, fromfield);
630         }
631         if (tofield[0] == '/')
632                 toname = ecpyalloc(tofield);
633         else {
634                 toname = ecpyalloc(directory);
635                 toname = ecatalloc(toname, "/");
636                 toname = ecatalloc(toname, tofield);
637         }
638         /*
639         ** We get to be careful here since
640         ** there's a fair chance of root running us.
641         */
642         if (!itsdir(toname))
643                 (void) remove(toname);
644         if (link(fromname, toname) != 0) {
645                 int     result;
646
647                 if (mkdirs(toname) != 0)
648                         exit(EXIT_FAILURE);
649
650                 result = link(fromname, toname);
651 #if HAVE_SYMLINK
652                 if (result != 0 &&
653                         access(fromname, F_OK) == 0 &&
654                         !itsdir(fromname)) {
655                                 const char *s = tofield;
656                                 register char * symlinkcontents = NULL;
657                                 while ((s = strchr(s+1, '/')) != NULL)
658                                         symlinkcontents =
659                                                 ecatalloc(symlinkcontents,
660                                                 "../");
661                                 symlinkcontents =
662                                         ecatalloc(symlinkcontents,
663                                         fromname);
664                                 result =
665                                         symlink(symlinkcontents,
666                                         toname);
667                                 if (result == 0)
668 warning(_("hard link failed, symbolic link used"));
669                                 ifree(symlinkcontents);
670                 }
671 #endif /* HAVE_SYMLINK */
672                 if (result != 0) {
673                         err(EXIT_FAILURE, _("can't link from %s to %s"),
674                             fromname, toname);
675                 }
676         }
677         ifree(fromname);
678         ifree(toname);
679 }
680
681 #define TIME_T_BITS_IN_FILE     64
682
683 static void
684 setboundaries (void)
685 {
686         register int    i;
687
688         min_time = -1;
689         for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
690                 min_time *= 2;
691         max_time = -(min_time + 1);
692 }
693
694 static int
695 itsdir(name)
696 const char * const      name;
697 {
698         register char * myname;
699         register int    accres;
700
701         myname = ecpyalloc(name);
702         myname = ecatalloc(myname, "/.");
703         accres = access(myname, F_OK);
704         ifree(myname);
705         return accres == 0;
706 }
707
708 /*
709 ** Associate sets of rules with zones.
710 */
711
712 /*
713 ** Sort by rule name.
714 */
715
716 static int
717 rcomp(cp1, cp2)
718 const void *    cp1;
719 const void *    cp2;
720 {
721         return strcmp(((const struct rule *) cp1)->r_name,
722                 ((const struct rule *) cp2)->r_name);
723 }
724
725 static void
726 associate(void)
727 {
728         register struct zone *  zp;
729         register struct rule *  rp;
730         register int            base, out;
731         register int            i, j;
732
733         if (nrules != 0) {
734                 (void) qsort((void *) rules, (size_t) nrules,
735                         (size_t) sizeof *rules, rcomp);
736                 for (i = 0; i < nrules - 1; ++i) {
737                         if (strcmp(rules[i].r_name,
738                                 rules[i + 1].r_name) != 0)
739                                         continue;
740                         if (strcmp(rules[i].r_filename,
741                                 rules[i + 1].r_filename) == 0)
742                                         continue;
743                         eat(rules[i].r_filename, rules[i].r_linenum);
744                         warning(_("same rule name in multiple files"));
745                         eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
746                         warning(_("same rule name in multiple files"));
747                         for (j = i + 2; j < nrules; ++j) {
748                                 if (strcmp(rules[i].r_name,
749                                         rules[j].r_name) != 0)
750                                                 break;
751                                 if (strcmp(rules[i].r_filename,
752                                         rules[j].r_filename) == 0)
753                                                 continue;
754                                 if (strcmp(rules[i + 1].r_filename,
755                                         rules[j].r_filename) == 0)
756                                                 continue;
757                                 break;
758                         }
759                         i = j - 1;
760                 }
761         }
762         for (i = 0; i < nzones; ++i) {
763                 zp = &zones[i];
764                 zp->z_rules = NULL;
765                 zp->z_nrules = 0;
766         }
767         for (base = 0; base < nrules; base = out) {
768                 rp = &rules[base];
769                 for (out = base + 1; out < nrules; ++out)
770                         if (strcmp(rp->r_name, rules[out].r_name) != 0)
771                                 break;
772                 for (i = 0; i < nzones; ++i) {
773                         zp = &zones[i];
774                         if (strcmp(zp->z_rule, rp->r_name) != 0)
775                                 continue;
776                         zp->z_rules = rp;
777                         zp->z_nrules = out - base;
778                 }
779         }
780         for (i = 0; i < nzones; ++i) {
781                 zp = &zones[i];
782                 if (zp->z_nrules == 0) {
783                         /*
784                         ** Maybe we have a local standard time offset.
785                         */
786                         eat(zp->z_filename, zp->z_linenum);
787                         zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
788                                 TRUE);
789                         /*
790                         ** Note, though, that if there's no rule,
791                         ** a '%s' in the format is a bad thing.
792                         */
793                         if (strchr(zp->z_format, '%') != 0)
794                                 error(_("%s in ruleless zone"));
795                 }
796         }
797         if (errors)
798                 exit(EXIT_FAILURE);
799 }
800
801 static void
802 infile(name)
803 const char *    name;
804 {
805         register FILE *                 fp;
806         register char **                fields;
807         register char *                 cp;
808         register const struct lookup *  lp;
809         register int                    nfields;
810         register int                    wantcont;
811         register int                    num;
812         char                            buf[BUFSIZ];
813
814         if (strcmp(name, "-") == 0) {
815                 name = _("standard input");
816                 fp = stdin;
817         } else if ((fp = fopen(name, "r")) == NULL)
818                 err(EXIT_FAILURE, _("can't open %s"), name);
819         wantcont = FALSE;
820         for (num = 1; ; ++num) {
821                 eat(name, num);
822                 if (fgets(buf, (int) sizeof buf, fp) != buf)
823                         break;
824                 cp = strchr(buf, '\n');
825                 if (cp == NULL) {
826                         error(_("line too long"));
827                         exit(EXIT_FAILURE);
828                 }
829                 *cp = '\0';
830                 fields = getfields(buf);
831                 nfields = 0;
832                 while (fields[nfields] != NULL) {
833                         static char     nada;
834
835                         if (strcmp(fields[nfields], "-") == 0)
836                                 fields[nfields] = &nada;
837                         ++nfields;
838                 }
839                 if (nfields == 0) {
840                         /* nothing to do */
841                 } else if (wantcont) {
842                         wantcont = inzcont(fields, nfields);
843                 } else {
844                         lp = byword(fields[0], line_codes);
845                         if (lp == NULL)
846                                 error(_("input line of unknown type"));
847                         else switch ((int) (lp->l_value)) {
848                                 case LC_RULE:
849                                         inrule(fields, nfields);
850                                         wantcont = FALSE;
851                                         break;
852                                 case LC_ZONE:
853                                         wantcont = inzone(fields, nfields);
854                                         break;
855                                 case LC_LINK:
856                                         inlink(fields, nfields);
857                                         wantcont = FALSE;
858                                         break;
859                                 case LC_LEAP:
860                                         if (name != leapsec)
861                                                 warnx(
862 _("leap line in non leap seconds file %s"), name);
863                                         else    inleap(fields, nfields);
864                                         wantcont = FALSE;
865                                         break;
866                                 default:        /* "cannot happen" */
867                                         errx(EXIT_FAILURE,
868 _("panic: invalid l_value %d"), lp->l_value);
869                         }
870                 }
871                 ifree((char *) fields);
872         }
873         if (ferror(fp))
874                 errx(EXIT_FAILURE, _("error reading %s"), filename);
875         if (fp != stdin && fclose(fp))
876                 err(EXIT_FAILURE, _("error closing %s"), filename);
877         if (wantcont)
878                 error(_("expected continuation line not found"));
879 }
880
881 /*
882 ** Convert a string of one of the forms
883 **      h       -h      hh:mm   -hh:mm  hh:mm:ss        -hh:mm:ss
884 ** into a number of seconds.
885 ** A null string maps to zero.
886 ** Call error with errstring and return zero on errors.
887 */
888
889 static long
890 gethms(string, errstring, signable)
891 const char *            string;
892 const char * const      errstring;
893 const int               signable;
894 {
895         long    hh;
896         int     mm, ss, sign;
897
898         if (string == NULL || *string == '\0')
899                 return 0;
900         if (!signable)
901                 sign = 1;
902         else if (*string == '-') {
903                 sign = -1;
904                 ++string;
905         } else  sign = 1;
906         if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
907                 mm = ss = 0;
908         else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
909                 ss = 0;
910         else if (sscanf(string, scheck(string, "%ld:%d:%d"),
911                 &hh, &mm, &ss) != 3) {
912                         error(errstring);
913                         return 0;
914         }
915         if (hh < 0 ||
916                 mm < 0 || mm >= MINSPERHOUR ||
917                 ss < 0 || ss > SECSPERMIN) {
918                         error(errstring);
919                         return 0;
920         }
921         if (LONG_MAX / SECSPERHOUR < hh) {
922                 error(_("time overflow"));
923                 return 0;
924         }
925         if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
926                 warning(_("24:00 not handled by pre-1998 versions of zic"));
927         if (noise && (hh > HOURSPERDAY ||
928                 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
929 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
930         return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
931                     eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
932 }
933
934 static void
935 inrule(fields, nfields)
936 register char ** const  fields;
937 const int               nfields;
938 {
939         static struct rule      r;
940
941         if (nfields != RULE_FIELDS) {
942                 error(_("wrong number of fields on Rule line"));
943                 return;
944         }
945         if (*fields[RF_NAME] == '\0') {
946                 error(_("nameless rule"));
947                 return;
948         }
949         r.r_filename = filename;
950         r.r_linenum = linenum;
951         r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
952         rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
953                 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
954         r.r_name = ecpyalloc(fields[RF_NAME]);
955         r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
956         if (max_abbrvar_len < strlen(r.r_abbrvar))
957                 max_abbrvar_len = strlen(r.r_abbrvar);
958         rules = (struct rule *) (void *) erealloc((char *) rules,
959                 (int) ((nrules + 1) * sizeof *rules));
960         rules[nrules++] = r;
961 }
962
963 static int
964 inzone(fields, nfields)
965 register char ** const  fields;
966 const int               nfields;
967 {
968         register int    i;
969         static char *   buf;
970
971         if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
972                 error(_("wrong number of fields on Zone line"));
973                 return FALSE;
974         }
975         if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
976                 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
977                 (void) sprintf(buf,
978 _("\"Zone %s\" line and -l option are mutually exclusive"),
979                         TZDEFAULT);
980                 error(buf);
981                 return FALSE;
982         }
983         if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
984                 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
985                 (void) sprintf(buf,
986 _("\"Zone %s\" line and -p option are mutually exclusive"),
987                         TZDEFRULES);
988                 error(buf);
989                 return FALSE;
990         }
991         for (i = 0; i < nzones; ++i)
992                 if (zones[i].z_name != NULL &&
993                         strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
994                                 buf = erealloc(buf, (int) (132 +
995                                         strlen(fields[ZF_NAME]) +
996                                         strlen(zones[i].z_filename)));
997                                 (void) sprintf(buf,
998 _("duplicate zone name %s (file \"%s\", line %d)"),
999                                         fields[ZF_NAME],
1000                                         zones[i].z_filename,
1001                                         zones[i].z_linenum);
1002                                 error(buf);
1003                                 return FALSE;
1004                 }
1005         return inzsub(fields, nfields, FALSE);
1006 }
1007
1008 static int
1009 inzcont(fields, nfields)
1010 register char ** const  fields;
1011 const int               nfields;
1012 {
1013         if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1014                 error(_("wrong number of fields on Zone continuation line"));
1015                 return FALSE;
1016         }
1017         return inzsub(fields, nfields, TRUE);
1018 }
1019
1020 static int
1021 inzsub(fields, nfields, iscont)
1022 register char ** const  fields;
1023 const int               nfields;
1024 const int               iscont;
1025 {
1026         register char *         cp;
1027         static struct zone      z;
1028         register int            i_gmtoff, i_rule, i_format;
1029         register int            i_untilyear, i_untilmonth;
1030         register int            i_untilday, i_untiltime;
1031         register int            hasuntil;
1032
1033         if (iscont) {
1034                 i_gmtoff = ZFC_GMTOFF;
1035                 i_rule = ZFC_RULE;
1036                 i_format = ZFC_FORMAT;
1037                 i_untilyear = ZFC_TILYEAR;
1038                 i_untilmonth = ZFC_TILMONTH;
1039                 i_untilday = ZFC_TILDAY;
1040                 i_untiltime = ZFC_TILTIME;
1041                 z.z_name = NULL;
1042         } else {
1043                 i_gmtoff = ZF_GMTOFF;
1044                 i_rule = ZF_RULE;
1045                 i_format = ZF_FORMAT;
1046                 i_untilyear = ZF_TILYEAR;
1047                 i_untilmonth = ZF_TILMONTH;
1048                 i_untilday = ZF_TILDAY;
1049                 i_untiltime = ZF_TILTIME;
1050                 z.z_name = ecpyalloc(fields[ZF_NAME]);
1051         }
1052         z.z_filename = filename;
1053         z.z_linenum = linenum;
1054         z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1055         if ((cp = strchr(fields[i_format], '%')) != 0) {
1056                 if (*++cp != 's' || strchr(cp, '%') != 0) {
1057                         error(_("invalid abbreviation format"));
1058                         return FALSE;
1059                 }
1060         }
1061         z.z_rule = ecpyalloc(fields[i_rule]);
1062         z.z_format = ecpyalloc(fields[i_format]);
1063         if (max_format_len < strlen(z.z_format))
1064                 max_format_len = strlen(z.z_format);
1065         hasuntil = nfields > i_untilyear;
1066         if (hasuntil) {
1067                 z.z_untilrule.r_filename = filename;
1068                 z.z_untilrule.r_linenum = linenum;
1069                 rulesub(&z.z_untilrule,
1070                         fields[i_untilyear],
1071                         "only",
1072                         "",
1073                         (nfields > i_untilmonth) ?
1074                         fields[i_untilmonth] : "Jan",
1075                         (nfields > i_untilday) ? fields[i_untilday] : "1",
1076                         (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1077                 z.z_untiltime = rpytime(&z.z_untilrule,
1078                         z.z_untilrule.r_loyear);
1079                 if (iscont && nzones > 0 &&
1080                         z.z_untiltime > min_time &&
1081                         z.z_untiltime < max_time &&
1082                         zones[nzones - 1].z_untiltime > min_time &&
1083                         zones[nzones - 1].z_untiltime < max_time &&
1084                         zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1085                                 error(_(
1086 "Zone continuation line end time is not after end time of previous line"
1087                                         ));
1088                                 return FALSE;
1089                 }
1090         }
1091         zones = (struct zone *) (void *) erealloc((char *) zones,
1092                 (int) ((nzones + 1) * sizeof *zones));
1093         zones[nzones++] = z;
1094         /*
1095         ** If there was an UNTIL field on this line,
1096         ** there's more information about the zone on the next line.
1097         */
1098         return hasuntil;
1099 }
1100
1101 static void
1102 inleap(fields, nfields)
1103 register char ** const  fields;
1104 const int               nfields;
1105 {
1106         register const char *           cp;
1107         register const struct lookup *  lp;
1108         register int                    i, j;
1109         int                             year, month, day;
1110         long                            dayoff, tod;
1111         zic_t                           t;
1112
1113         if (nfields != LEAP_FIELDS) {
1114                 error(_("wrong number of fields on Leap line"));
1115                 return;
1116         }
1117         dayoff = 0;
1118         cp = fields[LP_YEAR];
1119         if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1120                 /*
1121                 ** Leapin' Lizards!
1122                 */
1123                 error(_("invalid leaping year"));
1124                 return;
1125         }
1126         if (!leapseen || leapmaxyear < year)
1127                 leapmaxyear = year;
1128         if (!leapseen || leapminyear > year)
1129                 leapminyear = year;
1130         leapseen = TRUE;
1131         j = EPOCH_YEAR;
1132         while (j != year) {
1133                 if (year > j) {
1134                         i = len_years[isleap(j)];
1135                         ++j;
1136                 } else {
1137                         --j;
1138                         i = -len_years[isleap(j)];
1139                 }
1140                 dayoff = oadd(dayoff, eitol(i));
1141         }
1142         if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1143                 error(_("invalid month name"));
1144                 return;
1145         }
1146         month = lp->l_value;
1147         j = TM_JANUARY;
1148         while (j != month) {
1149                 i = len_months[isleap(year)][j];
1150                 dayoff = oadd(dayoff, eitol(i));
1151                 ++j;
1152         }
1153         cp = fields[LP_DAY];
1154         if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1155                 day <= 0 || day > len_months[isleap(year)][month]) {
1156                         error(_("invalid day of month"));
1157                         return;
1158         }
1159         dayoff = oadd(dayoff, eitol(day - 1));
1160         if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1161                 error(_("time before zero"));
1162                 return;
1163         }
1164         if (dayoff < min_time / SECSPERDAY) {
1165                 error(_("time too small"));
1166                 return;
1167         }
1168         if (dayoff > max_time / SECSPERDAY) {
1169                 error(_("time too large"));
1170                 return;
1171         }
1172         t = (zic_t) dayoff * SECSPERDAY;
1173         tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1174         cp = fields[LP_CORR];
1175         {
1176                 register int    positive;
1177                 int             count;
1178
1179                 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1180                         positive = FALSE;
1181                         count = 1;
1182                 } else if (strcmp(cp, "--") == 0) {
1183                         positive = FALSE;
1184                         count = 2;
1185                 } else if (strcmp(cp, "+") == 0) {
1186                         positive = TRUE;
1187                         count = 1;
1188                 } else if (strcmp(cp, "++") == 0) {
1189                         positive = TRUE;
1190                         count = 2;
1191                 } else {
1192                         error(_("illegal CORRECTION field on Leap line"));
1193                         return;
1194                 }
1195                 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1196                         error(_(
1197                                 "illegal Rolling/Stationary field on Leap line"
1198                                 ));
1199                         return;
1200                 }
1201                 leapadd(tadd(t, tod), positive, lp->l_value, count);
1202         }
1203 }
1204
1205 static void
1206 inlink(fields, nfields)
1207 register char ** const  fields;
1208 const int               nfields;
1209 {
1210         struct link     l;
1211
1212         if (nfields != LINK_FIELDS) {
1213                 error(_("wrong number of fields on Link line"));
1214                 return;
1215         }
1216         if (*fields[LF_FROM] == '\0') {
1217                 error(_("blank FROM field on Link line"));
1218                 return;
1219         }
1220         if (*fields[LF_TO] == '\0') {
1221                 error(_("blank TO field on Link line"));
1222                 return;
1223         }
1224         l.l_filename = filename;
1225         l.l_linenum = linenum;
1226         l.l_from = ecpyalloc(fields[LF_FROM]);
1227         l.l_to = ecpyalloc(fields[LF_TO]);
1228         links = (struct link *) (void *) erealloc((char *) links,
1229                 (int) ((nlinks + 1) * sizeof *links));
1230         links[nlinks++] = l;
1231 }
1232
1233 static void
1234 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1235 register struct rule * const    rp;
1236 const char * const              loyearp;
1237 const char * const              hiyearp;
1238 const char * const              typep;
1239 const char * const              monthp;
1240 const char * const              dayp;
1241 const char * const              timep;
1242 {
1243         register const struct lookup *  lp;
1244         register const char *           cp;
1245         register char *                 dp;
1246         register char *                 ep;
1247
1248         if ((lp = byword(monthp, mon_names)) == NULL) {
1249                 error(_("invalid month name"));
1250                 return;
1251         }
1252         rp->r_month = lp->l_value;
1253         rp->r_todisstd = FALSE;
1254         rp->r_todisgmt = FALSE;
1255         dp = ecpyalloc(timep);
1256         if (*dp != '\0') {
1257                 ep = dp + strlen(dp) - 1;
1258                 switch (lowerit(*ep)) {
1259                         case 's':       /* Standard */
1260                                 rp->r_todisstd = TRUE;
1261                                 rp->r_todisgmt = FALSE;
1262                                 *ep = '\0';
1263                                 break;
1264                         case 'w':       /* Wall */
1265                                 rp->r_todisstd = FALSE;
1266                                 rp->r_todisgmt = FALSE;
1267                                 *ep = '\0';
1268                                 break;
1269                         case 'g':       /* Greenwich */
1270                         case 'u':       /* Universal */
1271                         case 'z':       /* Zulu */
1272                                 rp->r_todisstd = TRUE;
1273                                 rp->r_todisgmt = TRUE;
1274                                 *ep = '\0';
1275                                 break;
1276                 }
1277         }
1278         rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1279         ifree(dp);
1280         /*
1281         ** Year work.
1282         */
1283         cp = loyearp;
1284         lp = byword(cp, begin_years);
1285         rp->r_lowasnum = lp == NULL;
1286         if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1287                 case YR_MINIMUM:
1288                         rp->r_loyear = INT_MIN;
1289                         break;
1290                 case YR_MAXIMUM:
1291                         rp->r_loyear = INT_MAX;
1292                         break;
1293                 default:        /* "cannot happen" */
1294                         errx(EXIT_FAILURE,
1295                                 _("panic: invalid l_value %d"), lp->l_value);
1296         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1297                 error(_("invalid starting year"));
1298                 return;
1299         }
1300         cp = hiyearp;
1301         lp = byword(cp, end_years);
1302         rp->r_hiwasnum = lp == NULL;
1303         if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1304                 case YR_MINIMUM:
1305                         rp->r_hiyear = INT_MIN;
1306                         break;
1307                 case YR_MAXIMUM:
1308                         rp->r_hiyear = INT_MAX;
1309                         break;
1310                 case YR_ONLY:
1311                         rp->r_hiyear = rp->r_loyear;
1312                         break;
1313                 default:        /* "cannot happen" */
1314                         errx(EXIT_FAILURE,
1315                                 _("panic: invalid l_value %d"), lp->l_value);
1316         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1317                 error(_("invalid ending year"));
1318                 return;
1319         }
1320         if (rp->r_loyear > rp->r_hiyear) {
1321                 error(_("starting year greater than ending year"));
1322                 return;
1323         }
1324         if (*typep == '\0')
1325                 rp->r_yrtype = NULL;
1326         else {
1327                 if (rp->r_loyear == rp->r_hiyear) {
1328                         error(_("typed single year"));
1329                         return;
1330                 }
1331                 rp->r_yrtype = ecpyalloc(typep);
1332         }
1333         /*
1334         ** Day work.
1335         ** Accept things such as:
1336         **      1
1337         **      last-Sunday
1338         **      Sun<=20
1339         **      Sun>=7
1340         */
1341         dp = ecpyalloc(dayp);
1342         if ((lp = byword(dp, lasts)) != NULL) {
1343                 rp->r_dycode = DC_DOWLEQ;
1344                 rp->r_wday = lp->l_value;
1345                 rp->r_dayofmonth = len_months[1][rp->r_month];
1346         } else {
1347                 if ((ep = strchr(dp, '<')) != 0)
1348                         rp->r_dycode = DC_DOWLEQ;
1349                 else if ((ep = strchr(dp, '>')) != 0)
1350                         rp->r_dycode = DC_DOWGEQ;
1351                 else {
1352                         ep = dp;
1353                         rp->r_dycode = DC_DOM;
1354                 }
1355                 if (rp->r_dycode != DC_DOM) {
1356                         *ep++ = 0;
1357                         if (*ep++ != '=') {
1358                                 error(_("invalid day of month"));
1359                                 ifree(dp);
1360                                 return;
1361                         }
1362                         if ((lp = byword(dp, wday_names)) == NULL) {
1363                                 error(_("invalid weekday name"));
1364                                 ifree(dp);
1365                                 return;
1366                         }
1367                         rp->r_wday = lp->l_value;
1368                 }
1369                 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1370                         rp->r_dayofmonth <= 0 ||
1371                         (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1372                                 error(_("invalid day of month"));
1373                                 ifree(dp);
1374                                 return;
1375                 }
1376         }
1377         ifree(dp);
1378 }
1379
1380 static void
1381 convert(val, buf)
1382 const long      val;
1383 char * const    buf;
1384 {
1385         register int    i;
1386         register int    shift;
1387
1388         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1389                 buf[i] = val >> shift;
1390 }
1391
1392 static void
1393 convert64(val, buf)
1394 const zic_t     val;
1395 char * const    buf;
1396 {
1397         register int    i;
1398         register int    shift;
1399
1400         for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1401                 buf[i] = val >> shift;
1402 }
1403
1404 static void
1405 puttzcode(val, fp)
1406 const long      val;
1407 FILE * const    fp;
1408 {
1409         char    buf[4];
1410
1411         convert(val, buf);
1412         (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1413 }
1414
1415 static void
1416 puttzcode64(val, fp)
1417 const zic_t     val;
1418 FILE * const    fp;
1419 {
1420         char    buf[8];
1421
1422         convert64(val, buf);
1423         (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1424 }
1425
1426 static int
1427 atcomp(avp, bvp)
1428 const void *    avp;
1429 const void *    bvp;
1430 {
1431         const zic_t     a = ((const struct attype *) avp)->at;
1432         const zic_t     b = ((const struct attype *) bvp)->at;
1433
1434         return (a < b) ? -1 : (a > b);
1435 }
1436
1437 static int
1438 is32(x)
1439 const zic_t     x;
1440 {
1441         return INT32_MIN <= x && x <= INT32_MAX;
1442 }
1443
1444 static void
1445 writezone(name, string)
1446 const char * const      name;
1447 const char * const      string;
1448 {
1449         register FILE *                 fp;
1450         register int                    i, j;
1451         register int                    leapcnt32, leapi32;
1452         register int                    timecnt32, timei32;
1453         register int                    pass;
1454         static char *                   fullname;
1455         static const struct tzhead      tzh0;
1456         static struct tzhead            tzh;
1457         zic_t                           ats[TZ_MAX_TIMES];
1458         unsigned char                   types[TZ_MAX_TIMES];
1459
1460         /*
1461         ** Sort.
1462         */
1463         if (timecnt > 1)
1464                 (void) qsort((void *) attypes, (size_t) timecnt,
1465                         (size_t) sizeof *attypes, atcomp);
1466         /*
1467         ** Optimize.
1468         */
1469         {
1470                 int     fromi;
1471                 int     toi;
1472
1473                 toi = 0;
1474                 fromi = 0;
1475                 while (fromi < timecnt && attypes[fromi].at < min_time)
1476                         ++fromi;
1477                 if (isdsts[0] == 0)
1478                         while (fromi < timecnt && attypes[fromi].type == 0)
1479                                 ++fromi;        /* handled by default rule */
1480                 for ( ; fromi < timecnt; ++fromi) {
1481                         if (toi != 0 && ((attypes[fromi].at +
1482                                 gmtoffs[attypes[toi - 1].type]) <=
1483                                 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1484                                 : attypes[toi - 2].type]))) {
1485                                         attypes[toi - 1].type =
1486                                                 attypes[fromi].type;
1487                                         continue;
1488                         }
1489                         if (toi == 0 ||
1490                                 attypes[toi - 1].type != attypes[fromi].type)
1491                                         attypes[toi++] = attypes[fromi];
1492                 }
1493                 timecnt = toi;
1494         }
1495         /*
1496         ** Transfer.
1497         */
1498         for (i = 0; i < timecnt; ++i) {
1499                 ats[i] = attypes[i].at;
1500                 types[i] = attypes[i].type;
1501         }
1502         /*
1503         ** Correct for leap seconds.
1504         */
1505         for (i = 0; i < timecnt; ++i) {
1506                 j = leapcnt;
1507                 while (--j >= 0)
1508                         if (ats[i] > trans[j] - corr[j]) {
1509                                 ats[i] = tadd(ats[i], corr[j]);
1510                                 break;
1511                         }
1512         }
1513         /*
1514         ** Figure out 32-bit-limited starts and counts.
1515         */
1516         timecnt32 = timecnt;
1517         timei32 = 0;
1518         leapcnt32 = leapcnt;
1519         leapi32 = 0;
1520         while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1521                 --timecnt32;
1522         while (timecnt32 > 0 && !is32(ats[timei32])) {
1523                 --timecnt32;
1524                 ++timei32;
1525         }
1526         while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1527                 --leapcnt32;
1528         while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1529                 --leapcnt32;
1530                 ++leapi32;
1531         }
1532         fullname = erealloc(fullname,
1533                 (int) (strlen(directory) + 1 + strlen(name) + 1));
1534         (void) sprintf(fullname, "%s/%s", directory, name);
1535
1536         /*
1537          * Remove old file, if any, to snap links.
1538          */
1539         if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
1540                 err(EXIT_FAILURE, _("can't remove %s"), fullname);
1541
1542         if ((fp = fopen(fullname, "wb")) == NULL) {
1543                 if (mkdirs(fullname) != 0)
1544                         exit(EXIT_FAILURE);
1545                 if ((fp = fopen(fullname, "wb")) == NULL)
1546                         err(EXIT_FAILURE, _("can't create %s"), fullname);
1547         }
1548         for (pass = 1; pass <= 2; ++pass) {
1549                 register int    thistimei, thistimecnt;
1550                 register int    thisleapi, thisleapcnt;
1551                 register int    thistimelim, thisleaplim;
1552                 int             writetype[TZ_MAX_TIMES];
1553                 int             typemap[TZ_MAX_TYPES];
1554                 register int    thistypecnt;
1555                 char            thischars[TZ_MAX_CHARS];
1556                 char            thischarcnt;
1557                 int             indmap[TZ_MAX_CHARS];
1558
1559                 if (pass == 1) {
1560                         thistimei = timei32;
1561                         thistimecnt = timecnt32;
1562                         thisleapi = leapi32;
1563                         thisleapcnt = leapcnt32;
1564                 } else {
1565                         thistimei = 0;
1566                         thistimecnt = timecnt;
1567                         thisleapi = 0;
1568                         thisleapcnt = leapcnt;
1569                 }
1570                 thistimelim = thistimei + thistimecnt;
1571                 thisleaplim = thisleapi + thisleapcnt;
1572                 for (i = 0; i < typecnt; ++i)
1573                         writetype[i] = thistimecnt == timecnt;
1574                 if (thistimecnt == 0) {
1575                         /*
1576                         ** No transition times fall in the current
1577                         ** (32- or 64-bit) window.
1578                         */
1579                         if (typecnt != 0)
1580                                 writetype[typecnt - 1] = TRUE;
1581                 } else {
1582                         for (i = thistimei - 1; i < thistimelim; ++i)
1583                                 if (i >= 0)
1584                                         writetype[types[i]] = TRUE;
1585                         /*
1586                         ** For America/Godthab and Antarctica/Palmer
1587                         */
1588                         if (thistimei == 0)
1589                                 writetype[0] = TRUE;
1590                 }
1591 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1592                 /*
1593                 ** For some pre-2011 systems: if the last-to-be-written
1594                 ** standard (or daylight) type has an offset different from the
1595                 ** most recently used offset,
1596                 ** append an (unused) copy of the most recently used type
1597                 ** (to help get global "altzone" and "timezone" variables
1598                 ** set correctly).
1599                 */
1600                 {
1601                         register int    mrudst, mrustd, hidst, histd, type;
1602
1603                         hidst = histd = mrudst = mrustd = -1;
1604                         for (i = thistimei; i < thistimelim; ++i)
1605                                 if (isdsts[types[i]])
1606                                         mrudst = types[i];
1607                                 else    mrustd = types[i];
1608                         for (i = 0; i < typecnt; ++i)
1609                                 if (writetype[i]) {
1610                                         if (isdsts[i])
1611                                                 hidst = i;
1612                                         else    histd = i;
1613                                 }
1614                         if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1615                                 gmtoffs[hidst] != gmtoffs[mrudst]) {
1616                                         isdsts[mrudst] = -1;
1617                                         type = addtype(gmtoffs[mrudst],
1618                                                 &chars[abbrinds[mrudst]],
1619                                                 TRUE,
1620                                                 ttisstds[mrudst],
1621                                                 ttisgmts[mrudst]);
1622                                         isdsts[mrudst] = TRUE;
1623                                         writetype[type] = TRUE;
1624                         }
1625                         if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1626                                 gmtoffs[histd] != gmtoffs[mrustd]) {
1627                                         isdsts[mrustd] = -1;
1628                                         type = addtype(gmtoffs[mrustd],
1629                                                 &chars[abbrinds[mrustd]],
1630                                                 FALSE,
1631                                                 ttisstds[mrustd],
1632                                                 ttisgmts[mrustd]);
1633                                         isdsts[mrustd] = FALSE;
1634                                         writetype[type] = TRUE;
1635                         }
1636                 }
1637 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1638                 thistypecnt = 0;
1639                 for (i = 0; i < typecnt; ++i)
1640                         typemap[i] = writetype[i] ?  thistypecnt++ : -1;
1641                 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1642                         indmap[i] = -1;
1643                 thischarcnt = 0;
1644                 for (i = 0; i < typecnt; ++i) {
1645                         register char * thisabbr;
1646
1647                         if (!writetype[i])
1648                                 continue;
1649                         if (indmap[abbrinds[i]] >= 0)
1650                                 continue;
1651                         thisabbr = &chars[abbrinds[i]];
1652                         for (j = 0; j < thischarcnt; ++j)
1653                                 if (strcmp(&thischars[j], thisabbr) == 0)
1654                                         break;
1655                         if (j == thischarcnt) {
1656                                 (void) strcpy(&thischars[(int) thischarcnt],
1657                                         thisabbr);
1658                                 thischarcnt += strlen(thisabbr) + 1;
1659                         }
1660                         indmap[abbrinds[i]] = j;
1661                 }
1662 #define DO(field)       (void) fwrite((void *) tzh.field, \
1663                                 (size_t) sizeof tzh.field, (size_t) 1, fp)
1664                 tzh = tzh0;
1665                 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1666                 tzh.tzh_version[0] = ZIC_VERSION;
1667                 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1668                 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1669                 convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1670                 convert(eitol(thistimecnt), tzh.tzh_timecnt);
1671                 convert(eitol(thistypecnt), tzh.tzh_typecnt);
1672                 convert(eitol(thischarcnt), tzh.tzh_charcnt);
1673                 DO(tzh_magic);
1674                 DO(tzh_version);
1675                 DO(tzh_reserved);
1676                 DO(tzh_ttisgmtcnt);
1677                 DO(tzh_ttisstdcnt);
1678                 DO(tzh_leapcnt);
1679                 DO(tzh_timecnt);
1680                 DO(tzh_typecnt);
1681                 DO(tzh_charcnt);
1682 #undef DO
1683                 for (i = thistimei; i < thistimelim; ++i)
1684                         if (pass == 1)
1685                                 puttzcode((long) ats[i], fp);
1686                         else    puttzcode64(ats[i], fp);
1687                 for (i = thistimei; i < thistimelim; ++i) {
1688                         unsigned char   uc;
1689
1690                         uc = typemap[types[i]];
1691                         (void) fwrite((void *) &uc,
1692                                 (size_t) sizeof uc,
1693                                 (size_t) 1,
1694                                 fp);
1695                 }
1696                 for (i = 0; i < typecnt; ++i)
1697                         if (writetype[i]) {
1698                                 puttzcode(gmtoffs[i], fp);
1699                                 (void) putc(isdsts[i], fp);
1700                                 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1701                         }
1702                 if (thischarcnt != 0)
1703                         (void) fwrite((void *) thischars,
1704                                 (size_t) sizeof thischars[0],
1705                                 (size_t) thischarcnt, fp);
1706                 for (i = thisleapi; i < thisleaplim; ++i) {
1707                         register zic_t  todo;
1708
1709                         if (roll[i]) {
1710                                 if (timecnt == 0 || trans[i] < ats[0]) {
1711                                         j = 0;
1712                                         while (isdsts[j])
1713                                                 if (++j >= typecnt) {
1714                                                         j = 0;
1715                                                         break;
1716                                                 }
1717                                 } else {
1718                                         j = 1;
1719                                         while (j < timecnt &&
1720                                                 trans[i] >= ats[j])
1721                                                         ++j;
1722                                         j = types[j - 1];
1723                                 }
1724                                 todo = tadd(trans[i], -gmtoffs[j]);
1725                         } else  todo = trans[i];
1726                         if (pass == 1)
1727                                 puttzcode((long) todo, fp);
1728                         else    puttzcode64(todo, fp);
1729                         puttzcode(corr[i], fp);
1730                 }
1731                 for (i = 0; i < typecnt; ++i)
1732                         if (writetype[i])
1733                                 (void) putc(ttisstds[i], fp);
1734                 for (i = 0; i < typecnt; ++i)
1735                         if (writetype[i])
1736                                 (void) putc(ttisgmts[i], fp);
1737         }
1738         (void) fprintf(fp, "\n%s\n", string);
1739         if (ferror(fp) || fclose(fp))
1740                 errx(EXIT_FAILURE, _("error writing %s"), fullname);
1741         if (chmod(fullname, mflag) < 0)
1742                 err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
1743                     fullname, (unsigned)mflag);
1744         if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
1745             && chown(fullname, uflag, gflag) < 0)
1746                 err(EXIT_FAILURE, _("cannot change ownership of %s"), 
1747                     fullname);
1748 }
1749
1750 static void
1751 doabbr(abbr, format, letters, isdst, doquotes)
1752 char * const            abbr;
1753 const char * const      format;
1754 const char * const      letters;
1755 const int               isdst;
1756 const int               doquotes;
1757 {
1758         register char * cp;
1759         register char * slashp;
1760         register int    len;
1761
1762         slashp = strchr(format, '/');
1763         if (slashp == NULL) {
1764                 if (letters == NULL)
1765                         (void) strcpy(abbr, format);
1766                 else    (void) sprintf(abbr, format, letters);
1767         } else if (isdst) {
1768                 (void) strcpy(abbr, slashp + 1);
1769         } else {
1770                 if (slashp > format)
1771                         (void) strncpy(abbr, format,
1772                                 (unsigned) (slashp - format));
1773                 abbr[slashp - format] = '\0';
1774         }
1775         if (!doquotes)
1776                 return;
1777         for (cp = abbr; *cp != '\0'; ++cp)
1778                 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1779                         strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1780                                 break;
1781         len = strlen(abbr);
1782         if (len > 0 && *cp == '\0')
1783                 return;
1784         abbr[len + 2] = '\0';
1785         abbr[len + 1] = '>';
1786         for ( ; len > 0; --len)
1787                 abbr[len] = abbr[len - 1];
1788         abbr[0] = '<';
1789 }
1790
1791 static void
1792 updateminmax(x)
1793 const int       x;
1794 {
1795         if (min_year > x)
1796                 min_year = x;
1797         if (max_year < x)
1798                 max_year = x;
1799 }
1800
1801 static int
1802 stringoffset(result, offset)
1803 char *  result;
1804 long    offset;
1805 {
1806         register int    hours;
1807         register int    minutes;
1808         register int    seconds;
1809
1810         result[0] = '\0';
1811         if (offset < 0) {
1812                 (void) strcpy(result, "-");
1813                 offset = -offset;
1814         }
1815         seconds = offset % SECSPERMIN;
1816         offset /= SECSPERMIN;
1817         minutes = offset % MINSPERHOUR;
1818         offset /= MINSPERHOUR;
1819         hours = offset;
1820         if (hours >= HOURSPERDAY) {
1821                 result[0] = '\0';
1822                 return -1;
1823         }
1824         (void) sprintf(end(result), "%d", hours);
1825         if (minutes != 0 || seconds != 0) {
1826                 (void) sprintf(end(result), ":%02d", minutes);
1827                 if (seconds != 0)
1828                         (void) sprintf(end(result), ":%02d", seconds);
1829         }
1830         return 0;
1831 }
1832
1833 static int
1834 stringrule(result, rp, dstoff, gmtoff)
1835 char *                          result;
1836 const struct rule * const       rp;
1837 const long                      dstoff;
1838 const long                      gmtoff;
1839 {
1840         register long   tod;
1841
1842         result = end(result);
1843         if (rp->r_dycode == DC_DOM) {
1844                 register int    month, total;
1845
1846                 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1847                         return -1;
1848                 total = 0;
1849                 for (month = 0; month < rp->r_month; ++month)
1850                         total += len_months[0][month];
1851                 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1852         } else {
1853                 register int    week;
1854
1855                 if (rp->r_dycode == DC_DOWGEQ) {
1856                         week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1857                         if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
1858                                 return -1;
1859                 } else if (rp->r_dycode == DC_DOWLEQ) {
1860                         if (rp->r_dayofmonth == len_months[1][rp->r_month])
1861                                 week = 5;
1862                         else {
1863                                 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1864                                 if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
1865                                         return -1;
1866                         }
1867                 } else  return -1;      /* "cannot happen" */
1868                 (void) sprintf(result, "M%d.%d.%d",
1869                         rp->r_month + 1, week, rp->r_wday);
1870         }
1871         tod = rp->r_tod;
1872         if (rp->r_todisgmt)
1873                 tod += gmtoff;
1874         if (rp->r_todisstd && rp->r_stdoff == 0)
1875                 tod += dstoff;
1876         if (tod < 0) {
1877                 result[0] = '\0';
1878                 return -1;
1879         }
1880         if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1881                 (void) strcat(result, "/");
1882                 if (stringoffset(end(result), tod) != 0)
1883                         return -1;
1884         }
1885         return 0;
1886 }
1887
1888 static void
1889 stringzone(result, zpfirst, zonecount)
1890 char *                          result;
1891 const struct zone * const       zpfirst;
1892 const int                       zonecount;
1893 {
1894         register const struct zone *    zp;
1895         register struct rule *          rp;
1896         register struct rule *          stdrp;
1897         register struct rule *          dstrp;
1898         register int                    i;
1899         register const char *           abbrvar;
1900
1901         result[0] = '\0';
1902         zp = zpfirst + zonecount - 1;
1903         stdrp = dstrp = NULL;
1904         for (i = 0; i < zp->z_nrules; ++i) {
1905                 rp = &zp->z_rules[i];
1906                 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1907                         continue;
1908                 if (rp->r_yrtype != NULL)
1909                         continue;
1910                 if (rp->r_stdoff == 0) {
1911                         if (stdrp == NULL)
1912                                 stdrp = rp;
1913                         else    return;
1914                 } else {
1915                         if (dstrp == NULL)
1916                                 dstrp = rp;
1917                         else    return;
1918                 }
1919         }
1920         if (stdrp == NULL && dstrp == NULL) {
1921                 /*
1922                 ** There are no rules running through "max".
1923                 ** Let's find the latest rule.
1924                 */
1925                 for (i = 0; i < zp->z_nrules; ++i) {
1926                         rp = &zp->z_rules[i];
1927                         if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1928                                 (rp->r_hiyear == stdrp->r_hiyear &&
1929                                 rp->r_month > stdrp->r_month))
1930                                         stdrp = rp;
1931                 }
1932                 if (stdrp != NULL && stdrp->r_stdoff != 0)
1933                         return; /* We end up in DST (a POSIX no-no). */
1934                 /*
1935                 ** Horrid special case: if year is 2037,
1936                 ** presume this is a zone handled on a year-by-year basis;
1937                 ** do not try to apply a rule to the zone.
1938                 */
1939                 if (stdrp != NULL && stdrp->r_hiyear == 2037)
1940                         return;
1941         }
1942         if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1943                 return;
1944         abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1945         doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
1946         if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1947                 result[0] = '\0';
1948                 return;
1949         }
1950         if (dstrp == NULL)
1951                 return;
1952         doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
1953         if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
1954                 if (stringoffset(end(result),
1955                         -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1956                                 result[0] = '\0';
1957                                 return;
1958                 }
1959         (void) strcat(result, ",");
1960         if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1961                 result[0] = '\0';
1962                 return;
1963         }
1964         (void) strcat(result, ",");
1965         if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1966                 result[0] = '\0';
1967                 return;
1968         }
1969 }
1970
1971 static void
1972 outzone(zpfirst, zonecount)
1973 const struct zone * const       zpfirst;
1974 const int                       zonecount;
1975 {
1976         register const struct zone *    zp;
1977         register struct rule *          rp;
1978         register int                    i, j;
1979         register int                    usestart, useuntil;
1980         register zic_t                  starttime, untiltime;
1981         register long                   gmtoff;
1982         register long                   stdoff;
1983         register int                    year;
1984         register long                   startoff;
1985         register int                    startttisstd;
1986         register int                    startttisgmt;
1987         register int                    type;
1988         register char *                 startbuf;
1989         register char *                 ab;
1990         register char *                 envvar;
1991         register int                    max_abbr_len;
1992         register int                    max_envvar_len;
1993
1994         max_abbr_len = 2 + max_format_len + max_abbrvar_len;
1995         max_envvar_len = 2 * max_abbr_len + 5 * 9;
1996         startbuf = emalloc(max_abbr_len + 1);
1997         ab = emalloc(max_abbr_len + 1);
1998         envvar = emalloc(max_envvar_len + 1);
1999         INITIALIZE(untiltime);
2000         INITIALIZE(starttime);
2001         /*
2002         ** Now. . .finally. . .generate some useful data!
2003         */
2004         timecnt = 0;
2005         typecnt = 0;
2006         charcnt = 0;
2007         /*
2008         ** Thanks to Earl Chew
2009         ** for noting the need to unconditionally initialize startttisstd.
2010         */
2011         startttisstd = FALSE;
2012         startttisgmt = FALSE;
2013         min_year = max_year = EPOCH_YEAR;
2014         if (leapseen) {
2015                 updateminmax(leapminyear);
2016                 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
2017         }
2018         for (i = 0; i < zonecount; ++i) {
2019                 zp = &zpfirst[i];
2020                 if (i < zonecount - 1)
2021                         updateminmax(zp->z_untilrule.r_loyear);
2022                 for (j = 0; j < zp->z_nrules; ++j) {
2023                         rp = &zp->z_rules[j];
2024                         if (rp->r_lowasnum)
2025                                 updateminmax(rp->r_loyear);
2026                         if (rp->r_hiwasnum)
2027                                 updateminmax(rp->r_hiyear);
2028                 }
2029         }
2030         /*
2031         ** Generate lots of data if a rule can't cover all future times.
2032         */
2033         stringzone(envvar, zpfirst, zonecount);
2034         if (noise && envvar[0] == '\0') {
2035                 register char * wp;
2036
2037 wp = ecpyalloc(_("no POSIX environment variable for zone"));
2038                 wp = ecatalloc(wp, " ");
2039                 wp = ecatalloc(wp, zpfirst->z_name);
2040                 warning(wp);
2041                 ifree(wp);
2042         }
2043         if (envvar[0] == '\0') {
2044                 if (min_year >= INT_MIN + YEARSPERREPEAT)
2045                         min_year -= YEARSPERREPEAT;
2046                 else    min_year = INT_MIN;
2047                 if (max_year <= INT_MAX - YEARSPERREPEAT)
2048                         max_year += YEARSPERREPEAT;
2049                 else    max_year = INT_MAX;
2050         }
2051         /*
2052         ** For the benefit of older systems,
2053         ** generate data from 1900 through 2037.
2054         */
2055         if (min_year > 1900)
2056                 min_year = 1900;
2057         if (max_year < 2037)
2058                 max_year = 2037;
2059         for (i = 0; i < zonecount; ++i) {
2060                 /*
2061                 ** A guess that may well be corrected later.
2062                 */
2063                 stdoff = 0;
2064                 zp = &zpfirst[i];
2065                 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2066                 useuntil = i < (zonecount - 1);
2067                 if (useuntil && zp->z_untiltime <= min_time)
2068                         continue;
2069                 gmtoff = zp->z_gmtoff;
2070                 eat(zp->z_filename, zp->z_linenum);
2071                 *startbuf = '\0';
2072                 startoff = zp->z_gmtoff;
2073                 if (zp->z_nrules == 0) {
2074                         stdoff = zp->z_stdoff;
2075                         doabbr(startbuf, zp->z_format,
2076                                 (char *) NULL, stdoff != 0, FALSE);
2077                         type = addtype(oadd(zp->z_gmtoff, stdoff),
2078                                 startbuf, stdoff != 0, startttisstd,
2079                                 startttisgmt);
2080                         if (usestart) {
2081                                 addtt(starttime, type);
2082                                 usestart = FALSE;
2083                         } else if (stdoff != 0)
2084                                 addtt(min_time, type);
2085                 } else for (year = min_year; year <= max_year; ++year) {
2086                         if (useuntil && year > zp->z_untilrule.r_hiyear)
2087                                 break;
2088                         /*
2089                         ** Mark which rules to do in the current year.
2090                         ** For those to do, calculate rpytime(rp, year);
2091                         */
2092                         for (j = 0; j < zp->z_nrules; ++j) {
2093                                 rp = &zp->z_rules[j];
2094                                 eats(zp->z_filename, zp->z_linenum,
2095                                         rp->r_filename, rp->r_linenum);
2096                                 rp->r_todo = year >= rp->r_loyear &&
2097                                                 year <= rp->r_hiyear &&
2098                                                 yearistype(year, rp->r_yrtype);
2099                                 if (rp->r_todo)
2100                                         rp->r_temp = rpytime(rp, year);
2101                         }
2102                         for ( ; ; ) {
2103                                 register int    k;
2104                                 register zic_t  jtime, ktime;
2105                                 register long   offset;
2106
2107                                 INITIALIZE(ktime);
2108                                 if (useuntil) {
2109                                         /*
2110                                         ** Turn untiltime into UTC
2111                                         ** assuming the current gmtoff and
2112                                         ** stdoff values.
2113                                         */
2114                                         untiltime = zp->z_untiltime;
2115                                         if (!zp->z_untilrule.r_todisgmt)
2116                                                 untiltime = tadd(untiltime,
2117                                                         -gmtoff);
2118                                         if (!zp->z_untilrule.r_todisstd)
2119                                                 untiltime = tadd(untiltime,
2120                                                         -stdoff);
2121                                 }
2122                                 /*
2123                                 ** Find the rule (of those to do, if any)
2124                                 ** that takes effect earliest in the year.
2125                                 */
2126                                 k = -1;
2127                                 for (j = 0; j < zp->z_nrules; ++j) {
2128                                         rp = &zp->z_rules[j];
2129                                         if (!rp->r_todo)
2130                                                 continue;
2131                                         eats(zp->z_filename, zp->z_linenum,
2132                                                 rp->r_filename, rp->r_linenum);
2133                                         offset = rp->r_todisgmt ? 0 : gmtoff;
2134                                         if (!rp->r_todisstd)
2135                                                 offset = oadd(offset, stdoff);
2136                                         jtime = rp->r_temp;
2137                                         if (jtime == min_time ||
2138                                                 jtime == max_time)
2139                                                         continue;
2140                                         jtime = tadd(jtime, -offset);
2141                                         if (k < 0 || jtime < ktime) {
2142                                                 k = j;
2143                                                 ktime = jtime;
2144                                         }
2145                                 }
2146                                 if (k < 0)
2147                                         break;  /* go on to next year */
2148                                 rp = &zp->z_rules[k];
2149                                 rp->r_todo = FALSE;
2150                                 if (useuntil && ktime >= untiltime)
2151                                         break;
2152                                 stdoff = rp->r_stdoff;
2153                                 if (usestart && ktime == starttime)
2154                                         usestart = FALSE;
2155                                 if (usestart) {
2156                                         if (ktime < starttime) {
2157                                                 startoff = oadd(zp->z_gmtoff,
2158                                                         stdoff);
2159                                                 doabbr(startbuf, zp->z_format,
2160                                                         rp->r_abbrvar,
2161                                                         rp->r_stdoff != 0,
2162                                                         FALSE);
2163                                                 continue;
2164                                         }
2165                                         if (*startbuf == '\0' &&
2166                                                 startoff == oadd(zp->z_gmtoff,
2167                                                 stdoff)) {
2168                                                         doabbr(startbuf,
2169                                                                 zp->z_format,
2170                                                                 rp->r_abbrvar,
2171                                                                 rp->r_stdoff !=
2172                                                                 0,
2173                                                                 FALSE);
2174                                         }
2175                                 }
2176                                 eats(zp->z_filename, zp->z_linenum,
2177                                         rp->r_filename, rp->r_linenum);
2178                                 doabbr(ab, zp->z_format, rp->r_abbrvar,
2179                                         rp->r_stdoff != 0, FALSE);
2180                                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2181                                 type = addtype(offset, ab, rp->r_stdoff != 0,
2182                                         rp->r_todisstd, rp->r_todisgmt);
2183                                 addtt(ktime, type);
2184                         }
2185                 }
2186                 if (usestart) {
2187                         if (*startbuf == '\0' &&
2188                                 zp->z_format != NULL &&
2189                                 strchr(zp->z_format, '%') == NULL &&
2190                                 strchr(zp->z_format, '/') == NULL)
2191                                         (void) strcpy(startbuf, zp->z_format);
2192                         eat(zp->z_filename, zp->z_linenum);
2193                         if (*startbuf == '\0')
2194 error(_("can't determine time zone abbreviation to use just after until time"));
2195                         else    addtt(starttime,
2196                                         addtype(startoff, startbuf,
2197                                                 startoff != zp->z_gmtoff,
2198                                                 startttisstd,
2199                                                 startttisgmt));
2200                 }
2201                 /*
2202                 ** Now we may get to set starttime for the next zone line.
2203                 */
2204                 if (useuntil) {
2205                         startttisstd = zp->z_untilrule.r_todisstd;
2206                         startttisgmt = zp->z_untilrule.r_todisgmt;
2207                         starttime = zp->z_untiltime;
2208                         if (!startttisstd)
2209                                 starttime = tadd(starttime, -stdoff);
2210                         if (!startttisgmt)
2211                                 starttime = tadd(starttime, -gmtoff);
2212                 }
2213         }
2214         writezone(zpfirst->z_name, envvar);
2215         ifree(startbuf);
2216         ifree(ab);
2217         ifree(envvar);
2218 }
2219
2220 static void
2221 addtt(starttime, type)
2222 const zic_t     starttime;
2223 int             type;
2224 {
2225         if (starttime <= min_time ||
2226                 (timecnt == 1 && attypes[0].at < min_time)) {
2227                 gmtoffs[0] = gmtoffs[type];
2228                 isdsts[0] = isdsts[type];
2229                 ttisstds[0] = ttisstds[type];
2230                 ttisgmts[0] = ttisgmts[type];
2231                 if (abbrinds[type] != 0)
2232                         (void) strcpy(chars, &chars[abbrinds[type]]);
2233                 abbrinds[0] = 0;
2234                 charcnt = strlen(chars) + 1;
2235                 typecnt = 1;
2236                 timecnt = 0;
2237                 type = 0;
2238         }
2239         if (timecnt >= TZ_MAX_TIMES) {
2240                 error(_("too many transitions?!"));
2241                 exit(EXIT_FAILURE);
2242         }
2243         attypes[timecnt].at = starttime;
2244         attypes[timecnt].type = type;
2245         ++timecnt;
2246 }
2247
2248 static int
2249 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2250 const long              gmtoff;
2251 const char * const      abbr;
2252 const int               isdst;
2253 const int               ttisstd;
2254 const int               ttisgmt;
2255 {
2256         register int    i, j;
2257
2258         if (isdst != TRUE && isdst != FALSE) {
2259                 error(_("internal error - addtype called with bad isdst"));
2260                 exit(EXIT_FAILURE);
2261         }
2262         if (ttisstd != TRUE && ttisstd != FALSE) {
2263                 error(_("internal error - addtype called with bad ttisstd"));
2264                 exit(EXIT_FAILURE);
2265         }
2266         if (ttisgmt != TRUE && ttisgmt != FALSE) {
2267                 error(_("internal error - addtype called with bad ttisgmt"));
2268                 exit(EXIT_FAILURE);
2269         }
2270         /*
2271         ** See if there's already an entry for this zone type.
2272         ** If so, just return its index.
2273         */
2274         for (i = 0; i < typecnt; ++i) {
2275                 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2276                         strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2277                         ttisstd == ttisstds[i] &&
2278                         ttisgmt == ttisgmts[i])
2279                                 return i;
2280         }
2281         /*
2282         ** There isn't one; add a new one, unless there are already too
2283         ** many.
2284         */
2285         if (typecnt >= TZ_MAX_TYPES) {
2286                 error(_("too many local time types"));
2287                 exit(EXIT_FAILURE);
2288         }
2289         if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2290                 error(_("UTC offset out of range"));
2291                 exit(EXIT_FAILURE);
2292         }
2293         gmtoffs[i] = gmtoff;
2294         isdsts[i] = isdst;
2295         ttisstds[i] = ttisstd;
2296         ttisgmts[i] = ttisgmt;
2297
2298         for (j = 0; j < charcnt; ++j)
2299                 if (strcmp(&chars[j], abbr) == 0)
2300                         break;
2301         if (j == charcnt)
2302                 newabbr(abbr);
2303         abbrinds[i] = j;
2304         ++typecnt;
2305         return i;
2306 }
2307
2308 static void
2309 leapadd(t, positive, rolling, count)
2310 const zic_t     t;
2311 const int       positive;
2312 const int       rolling;
2313 int             count;
2314 {
2315         register int    i, j;
2316
2317         if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2318                 error(_("too many leap seconds"));
2319                 exit(EXIT_FAILURE);
2320         }
2321         for (i = 0; i < leapcnt; ++i)
2322                 if (t <= trans[i]) {
2323                         if (t == trans[i]) {
2324                                 error(_("repeated leap second moment"));
2325                                 exit(EXIT_FAILURE);
2326                         }
2327                         break;
2328                 }
2329         do {
2330                 for (j = leapcnt; j > i; --j) {
2331                         trans[j] = trans[j - 1];
2332                         corr[j] = corr[j - 1];
2333                         roll[j] = roll[j - 1];
2334                 }
2335                 trans[i] = t;
2336                 corr[i] = positive ? 1L : eitol(-count);
2337                 roll[i] = rolling;
2338                 ++leapcnt;
2339         } while (positive && --count != 0);
2340 }
2341
2342 static void
2343 adjleap(void)
2344 {
2345         register int    i;
2346         register long   last = 0;
2347
2348         /*
2349         ** propagate leap seconds forward
2350         */
2351         for (i = 0; i < leapcnt; ++i) {
2352                 trans[i] = tadd(trans[i], last);
2353                 last = corr[i] += last;
2354         }
2355 }
2356
2357 static int
2358 yearistype(year, type)
2359 const int               year;
2360 const char * const      type;
2361 {
2362         static char *   buf;
2363         int             result;
2364
2365         if (type == NULL || *type == '\0')
2366                 return TRUE;
2367         buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
2368         (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
2369         result = system(buf);
2370         if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2371                 case 0:
2372                         return TRUE;
2373                 case 1:
2374                         return FALSE;
2375         }
2376         error(_("wild result from command execution"));
2377         warnx(_("command was '%s', result was %d"), buf, result);
2378         for ( ; ; )
2379                 exit(EXIT_FAILURE);
2380 }
2381
2382 static int
2383 lowerit(a)
2384 int     a;
2385 {
2386         a = (unsigned char) a;
2387         return (isascii(a) && isupper(a)) ? tolower(a) : a;
2388 }
2389
2390 static int
2391 ciequal(ap, bp)         /* case-insensitive equality */
2392 register const char *   ap;
2393 register const char *   bp;
2394 {
2395         while (lowerit(*ap) == lowerit(*bp++))
2396                 if (*ap++ == '\0')
2397                         return TRUE;
2398         return FALSE;
2399 }
2400
2401 static int
2402 itsabbr(abbr, word)
2403 register const char *   abbr;
2404 register const char *   word;
2405 {
2406         if (lowerit(*abbr) != lowerit(*word))
2407                 return FALSE;
2408         ++word;
2409         while (*++abbr != '\0')
2410                 do {
2411                         if (*word == '\0')
2412                                 return FALSE;
2413                 } while (lowerit(*word++) != lowerit(*abbr));
2414         return TRUE;
2415 }
2416
2417 static const struct lookup *
2418 byword(word, table)
2419 register const char * const             word;
2420 register const struct lookup * const    table;
2421 {
2422         register const struct lookup *  foundlp;
2423         register const struct lookup *  lp;
2424
2425         if (word == NULL || table == NULL)
2426                 return NULL;
2427         /*
2428         ** Look for exact match.
2429         */
2430         for (lp = table; lp->l_word != NULL; ++lp)
2431                 if (ciequal(word, lp->l_word))
2432                         return lp;
2433         /*
2434         ** Look for inexact match.
2435         */
2436         foundlp = NULL;
2437         for (lp = table; lp->l_word != NULL; ++lp)
2438                 if (itsabbr(word, lp->l_word)) {
2439                         if (foundlp == NULL)
2440                                 foundlp = lp;
2441                         else    return NULL;    /* multiple inexact matches */
2442                 }
2443         return foundlp;
2444 }
2445
2446 static char **
2447 getfields(cp)
2448 register char * cp;
2449 {
2450         register char *         dp;
2451         register char **        array;
2452         register int            nsubs;
2453
2454         if (cp == NULL)
2455                 return NULL;
2456         array = (char **) (void *)
2457                 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
2458         nsubs = 0;
2459         for ( ; ; ) {
2460                 while (isascii((unsigned char) *cp) &&
2461                         isspace((unsigned char) *cp))
2462                                 ++cp;
2463                 if (*cp == '\0' || *cp == '#')
2464                         break;
2465                 array[nsubs++] = dp = cp;
2466                 do {
2467                         if ((*dp = *cp++) != '"')
2468                                 ++dp;
2469                         else while ((*dp = *cp++) != '"')
2470                                 if (*dp != '\0')
2471                                         ++dp;
2472                                 else {
2473                                         error(_("odd number of quotation marks"));
2474                                         exit(EXIT_FAILURE);
2475                                 }
2476                 } while (*cp != '\0' && *cp != '#' &&
2477                         (!isascii(*cp) || !isspace((unsigned char) *cp)));
2478                 if (isascii(*cp) && isspace((unsigned char) *cp))
2479                         ++cp;
2480                 *dp = '\0';
2481         }
2482         array[nsubs] = NULL;
2483         return array;
2484 }
2485
2486 static long
2487 oadd(t1, t2)
2488 const long      t1;
2489 const long      t2;
2490 {
2491         register long   t;
2492
2493         t = t1 + t2;
2494         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2495                 error(_("time overflow"));
2496                 exit(EXIT_FAILURE);
2497         }
2498         return t;
2499 }
2500
2501 static zic_t
2502 tadd(t1, t2)
2503 const zic_t     t1;
2504 const long      t2;
2505 {
2506         register zic_t  t;
2507
2508         if (t1 == max_time && t2 > 0)
2509                 return max_time;
2510         if (t1 == min_time && t2 < 0)
2511                 return min_time;
2512         t = t1 + t2;
2513         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2514                 error(_("time overflow"));
2515                 exit(EXIT_FAILURE);
2516         }
2517         return t;
2518 }
2519
2520 /*
2521 ** Given a rule, and a year, compute the date - in seconds since January 1,
2522 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2523 */
2524
2525 static zic_t
2526 rpytime(rp, wantedy)
2527 register const struct rule * const      rp;
2528 register const int                      wantedy;
2529 {
2530         register int    y, m, i;
2531         register long   dayoff;                 /* with a nod to Margaret O. */
2532         register zic_t  t;
2533
2534         if (wantedy == INT_MIN)
2535                 return min_time;
2536         if (wantedy == INT_MAX)
2537                 return max_time;
2538         dayoff = 0;
2539         m = TM_JANUARY;
2540         y = EPOCH_YEAR;
2541         while (wantedy != y) {
2542                 if (wantedy > y) {
2543                         i = len_years[isleap(y)];
2544                         ++y;
2545                 } else {
2546                         --y;
2547                         i = -len_years[isleap(y)];
2548                 }
2549                 dayoff = oadd(dayoff, eitol(i));
2550         }
2551         while (m != rp->r_month) {
2552                 i = len_months[isleap(y)][m];
2553                 dayoff = oadd(dayoff, eitol(i));
2554                 ++m;
2555         }
2556         i = rp->r_dayofmonth;
2557         if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2558                 if (rp->r_dycode == DC_DOWLEQ)
2559                         --i;
2560                 else {
2561                         error(_("use of 2/29 in non leap-year"));
2562                         exit(EXIT_FAILURE);
2563                 }
2564         }
2565         --i;
2566         dayoff = oadd(dayoff, eitol(i));
2567         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2568                 register long   wday;
2569
2570 #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
2571                 wday = eitol(EPOCH_WDAY);
2572                 /*
2573                 ** Don't trust mod of negative numbers.
2574                 */
2575                 if (dayoff >= 0)
2576                         wday = (wday + dayoff) % LDAYSPERWEEK;
2577                 else {
2578                         wday -= ((-dayoff) % LDAYSPERWEEK);
2579                         if (wday < 0)
2580                                 wday += LDAYSPERWEEK;
2581                 }
2582                 while (wday != eitol(rp->r_wday))
2583                         if (rp->r_dycode == DC_DOWGEQ) {
2584                                 dayoff = oadd(dayoff, (long) 1);
2585                                 if (++wday >= LDAYSPERWEEK)
2586                                         wday = 0;
2587                                 ++i;
2588                         } else {
2589                                 dayoff = oadd(dayoff, (long) -1);
2590                                 if (--wday < 0)
2591                                         wday = LDAYSPERWEEK - 1;
2592                                 --i;
2593                         }
2594                 if (i < 0 || i >= len_months[isleap(y)][m]) {
2595                         if (noise)
2596                                 warning(_("rule goes past start/end of month--\
2597 will not work with pre-2004 versions of zic"));
2598                 }
2599         }
2600         if (dayoff < min_time / SECSPERDAY)
2601                 return min_time;
2602         if (dayoff > max_time / SECSPERDAY)
2603                 return max_time;
2604         t = (zic_t) dayoff * SECSPERDAY;
2605         return tadd(t, rp->r_tod);
2606 }
2607
2608 static void
2609 newabbr(string)
2610 const char * const      string;
2611 {
2612         register int    i;
2613
2614         if (strcmp(string, GRANDPARENTED) != 0) {
2615                 register const char *   cp;
2616                 register char *         wp;
2617
2618                 cp = string;
2619                 wp = NULL;
2620                 while (isascii((unsigned char) *cp) &&
2621                         (isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+'))
2622                                 ++cp;
2623                 if (noise && cp - string > 3)
2624 wp = _("time zone abbreviation has more than 3 characters");
2625                 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2626 wp = _("time zone abbreviation has too many characters");
2627                 if (*cp != '\0')
2628 wp = _("time zone abbreviation differs from POSIX standard");
2629                 if (wp != NULL) {
2630                         wp = ecpyalloc(wp);
2631                         wp = ecatalloc(wp, " (");
2632                         wp = ecatalloc(wp, string);
2633                         wp = ecatalloc(wp, ")");
2634                         warning(wp);
2635                         ifree(wp);
2636                 }
2637         }
2638         i = strlen(string) + 1;
2639         if (charcnt + i > TZ_MAX_CHARS) {
2640                 error(_("too many, or too long, time zone abbreviations"));
2641                 exit(EXIT_FAILURE);
2642         }
2643         (void) strcpy(&chars[charcnt], string);
2644         charcnt += eitol(i);
2645 }
2646
2647 static int
2648 mkdirs(argname)
2649 char *          argname;
2650 {
2651         register char * name;
2652         register char * cp;
2653
2654         if (argname == NULL || *argname == '\0' || Dflag)
2655                 return 0;
2656         cp = name = ecpyalloc(argname);
2657         while ((cp = strchr(cp + 1, '/')) != 0) {
2658                 *cp = '\0';
2659 #ifndef unix
2660                 /*
2661                 ** DOS drive specifier?
2662                 */
2663                 if (isalpha((unsigned char) name[0]) &&
2664                         name[1] == ':' && name[2] == '\0') {
2665                                 *cp = '/';
2666                                 continue;
2667                 }
2668 #endif /* !defined unix */
2669                 if (!itsdir(name)) {
2670                         /*
2671                         ** It doesn't seem to exist, so we try to create it.
2672                         ** Creation may fail because of the directory being
2673                         ** created by some other multiprocessor, so we get
2674                         ** to do extra checking.
2675                         */
2676                         if (mkdir(name, MKDIR_UMASK) != 0
2677                                 && (errno != EEXIST || !itsdir(name))) {
2678                                 warn(_("can't create directory %s"), name);
2679                                 ifree(name);
2680                                 return -1;
2681                         }
2682                 }
2683                 *cp = '/';
2684         }
2685         ifree(name);
2686         return 0;
2687 }
2688
2689 static long
2690 eitol(i)
2691 const int       i;
2692 {
2693         long    l;
2694
2695         l = i;
2696         if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2697                 errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
2698         return l;
2699 }
2700
2701 #include <grp.h>
2702 #include <pwd.h>
2703
2704 static void
2705 setgroup(flag, name)
2706         gid_t *flag;
2707         const char *name;
2708 {
2709         struct group *gr;
2710
2711         if (*flag != (gid_t)-1)
2712                 errx(EXIT_FAILURE, _("multiple -g flags specified"));
2713
2714         gr = getgrnam(name);
2715         if (gr == 0) {
2716                 char *ep;
2717                 unsigned long ul;
2718
2719                 ul = strtoul(name, &ep, 10);
2720                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2721                         *flag = ul;
2722                         return;
2723                 }
2724                 errx(EXIT_FAILURE, _("group `%s' not found"), name);
2725         }
2726         *flag = gr->gr_gid;
2727 }
2728
2729 static void
2730 setuser(flag, name)
2731         uid_t *flag;
2732         const char *name;
2733 {
2734         struct passwd *pw;
2735
2736         if (*flag != (gid_t)-1)
2737                 errx(EXIT_FAILURE, _("multiple -u flags specified"));
2738
2739         pw = getpwnam(name);
2740         if (pw == 0) {
2741                 char *ep;
2742                 unsigned long ul;
2743
2744                 ul = strtoul(name, &ep, 10);
2745                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2746                         *flag = ul;
2747                         return;
2748                 }
2749                 errx(EXIT_FAILURE, _("user `%s' not found"), name);
2750         }
2751         *flag = pw->pw_uid;
2752 }
2753
2754 /*
2755 ** UNIX was a registered trademark of The Open Group in 2003.
2756 */