]> git.saurik.com Git - apple/system_cmds.git/blame - zic.tproj/zic.c
system_cmds-805.250.2.tar.gz
[apple/system_cmds.git] / zic.tproj / zic.c
CommitLineData
887d5eed
A
1/*
2** This file is in the public domain, so clarified as of
3** 2006-07-17 by Arthur David Olson.
4*/
5
6static const char elsieid[] = "@(#)zic.c 8.22";
2fc1e207
A
7
8#ifndef lint
887d5eed
A
9static const char rcsid[] =
10 "$FreeBSD: head/contrib/tzcode/zic/zic.c 214411 2010-10-27 07:14:46Z edwin $";
2fc1e207 11#endif /* not lint */
1815bff5
A
12
13#include "private.h"
1815bff5 14#include "tzfile.h"
2fc1e207
A
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
887d5eed
A
21#define ZIC_VERSION '2'
22
23typedef 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
2fc1e207 29#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
1815bff5
A
30
31/*
32** On some ancient hosts, predicates like `isspace(C)' are defined
887d5eed 33** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
1815bff5 34** which says they are defined only if C == ((unsigned char) C) || C == EOF.
2fc1e207 35** Neither the C Standard nor POSIX require that `isascii' exist.
1815bff5
A
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
887d5eed
A
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
1815bff5
A
49struct 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;
887d5eed
A
57 int r_lowasnum;
58 int r_hiwasnum;
1815bff5
A
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) */
887d5eed 75 zic_t r_temp; /* used in outzone */
1815bff5
A
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
86struct 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;
887d5eed 101 zic_t z_untiltime;
1815bff5
A
102};
103
887d5eed
A
104static void addtt(zic_t starttime, int type);
105static int addtype(long gmtoff, const char * abbr, int isdst,
106 int ttisstd, int ttisgmt);
107static void leapadd(zic_t t, int positive, int rolling, int count);
108static void adjleap(void);
109static void associate(void);
110static int ciequal(const char * ap, const char * bp);
111static void convert(long val, char * buf);
112static void convert64(zic_t val, char * buf);
113static void dolink(const char * fromfield, const char * tofield);
114static void doabbr(char * abbr, const char * format,
115 const char * letters, int isdst, int doquotes);
116static void eat(const char * name, int num);
117static void eats(const char * name, int num,
118 const char * rname, int rnum);
119static long eitol(int i);
120static void error(const char * message);
121static char ** getfields(char * buf);
122static long gethms(const char * string, const char * errstrng,
123 int signable);
124static void infile(const char * filename);
125static void inleap(char ** fields, int nfields);
126static void inlink(char ** fields, int nfields);
127static void inrule(char ** fields, int nfields);
128static int inzcont(char ** fields, int nfields);
129static int inzone(char ** fields, int nfields);
130static int inzsub(char ** fields, int nfields, int iscont);
131static int is32(zic_t x);
132static int itsabbr(const char * abbr, const char * word);
133static int itsdir(const char * name);
134static int lowerit(int c);
135static char * memcheck(char * tocheck);
136static int mkdirs(char * filename);
137static void newabbr(const char * abbr);
138static long oadd(long t1, long t2);
139static void outzone(const struct zone * zp, int ntzones);
140static void puttzcode(long code, FILE * fp);
141static void puttzcode64(zic_t code, FILE * fp);
142static int rcomp(const void * leftp, const void * rightp);
143static zic_t rpytime(const struct rule * rp, int wantedy);
144static void rulesub(struct rule * rp,
1815bff5
A
145 const char * loyearp, const char * hiyearp,
146 const char * typep, const char * monthp,
887d5eed
A
147 const char * dayp, const char * timep);
148static int stringoffset(char * result, long offset);
149static int stringrule(char * result, const struct rule * rp,
150 long dstoff, long gmtoff);
151static void stringzone(char * result,
152 const struct zone * zp, int ntzones);
153static void setboundaries(void);
154static void setgroup(gid_t *flag, const char *name);
155static void setuser(uid_t *flag, const char *name);
156static zic_t tadd(zic_t t1, long t2);
157static void usage(FILE *stream, int status);
158static void writezone(const char * name, const char * string);
159static int yearistype(int year, const char * type);
1815bff5
A
160
161static int charcnt;
162static int errors;
163static const char * filename;
164static int leapcnt;
887d5eed
A
165static int leapseen;
166static int leapminyear;
167static int leapmaxyear;
1815bff5 168static int linenum;
887d5eed
A
169static int max_abbrvar_len;
170static int max_format_len;
171static zic_t max_time;
1815bff5 172static int max_year;
887d5eed 173static zic_t min_time;
1815bff5 174static int min_year;
887d5eed 175static zic_t min_time;
1815bff5
A
176static int noise;
177static const char * rfilename;
178static int rlinenum;
1815bff5
A
179static int timecnt;
180static 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
263static struct rule * rules;
264static int nrules; /* number of rules */
265
266static struct zone * zones;
267static int nzones; /* number of zones */
268
269struct link {
270 const char * l_filename;
271 int l_linenum;
272 const char * l_from;
273 const char * l_to;
274};
275
276static struct link * links;
277static int nlinks;
278
279struct lookup {
280 const char * l_word;
281 const int l_value;
282};
283
887d5eed
A
284static struct lookup const * byword(const char * string,
285 const struct lookup * lp);
1815bff5
A
286
287static 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
295static 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
311static 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
322static 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
333static struct lookup const begin_years[] = {
334 { "minimum", YR_MINIMUM },
335 { "maximum", YR_MAXIMUM },
336 { NULL, 0 }
337};
338
339static struct lookup const end_years[] = {
340 { "minimum", YR_MINIMUM },
341 { "maximum", YR_MAXIMUM },
342 { "only", YR_ONLY },
343 { NULL, 0 }
344};
345
346static struct lookup const leap_types[] = {
347 { "Rolling", TRUE },
348 { "Stationary", FALSE },
349 { NULL, 0 }
350};
351
352static 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
357static const int len_years[2] = {
358 DAYSPERNYEAR, DAYSPERLYEAR
359};
360
361static struct attype {
887d5eed 362 zic_t at;
1815bff5
A
363 unsigned char type;
364} attypes[TZ_MAX_TIMES];
365static long gmtoffs[TZ_MAX_TYPES];
366static char isdsts[TZ_MAX_TYPES];
367static unsigned char abbrinds[TZ_MAX_TYPES];
368static char ttisstds[TZ_MAX_TYPES];
369static char ttisgmts[TZ_MAX_TYPES];
370static char chars[TZ_MAX_CHARS];
887d5eed 371static zic_t trans[TZ_MAX_LEAPS];
1815bff5
A
372static long corr[TZ_MAX_LEAPS];
373static char roll[TZ_MAX_LEAPS];
374
375/*
376** Memory allocation.
377*/
378
379static char *
887d5eed
A
380memcheck(ptr)
381char * const ptr;
1815bff5 382{
2fc1e207
A
383 if (ptr == NULL)
384 errx(EXIT_FAILURE, _("memory exhausted"));
1815bff5
A
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
1815bff5 397static void
887d5eed
A
398eats(name, num, rname, rnum)
399const char * const name;
400const int num;
401const char * const rname;
402const int rnum;
1815bff5
A
403{
404 filename = name;
405 linenum = num;
406 rfilename = rname;
407 rlinenum = rnum;
408}
409
410static void
887d5eed
A
411eat(name, num)
412const char * const name;
413const int num;
1815bff5
A
414{
415 eats(name, num, (char *) NULL, -1);
416}
417
418static void
887d5eed
A
419error(string)
420const char * const string;
1815bff5
A
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
436static void
887d5eed
A
437warning(string)
438const char * const string;
1815bff5
A
439{
440 char * cp;
441
2fc1e207 442 cp = ecpyalloc(_("warning: "));
1815bff5 443 cp = ecatalloc(cp, string);
2fc1e207 444 error(cp);
1815bff5
A
445 ifree(cp);
446 --errors;
447}
448
449static void
887d5eed
A
450usage(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\
456Report bugs to tz@elsie.nci.nih.gov.\n"));
457 exit(status);
1815bff5
A
458}
459
460static const char * psxrules;
461static const char * lcltime;
462static const char * directory;
463static const char * leapsec;
464static const char * yitcommand;
2fc1e207
A
465static int Dflag;
466static uid_t uflag = (uid_t)-1;
467static gid_t gflag = (gid_t)-1;
468static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH
469 | S_IWUSR);
1815bff5
A
470
471int
887d5eed
A
472main(argc, argv)
473int argc;
474char * argv[];
1815bff5 475{
887d5eed
A
476 register int i;
477 register int j;
478 register int c;
1815bff5
A
479
480#ifdef unix
481 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
482#endif /* defined unix */
887d5eed
A
483#if HAVE_GETTEXT
484 (void) setlocale(LC_ALL, "");
1815bff5
A
485#ifdef TZ_DOMAINDIR
486 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
487#endif /* defined TEXTDOMAINDIR */
488 (void) textdomain(TZ_DOMAIN);
887d5eed
A
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 }
2fc1e207
A
495 for (i = 1; i < argc; ++i)
496 if (strcmp(argv[i], "--version") == 0) {
497 errx(EXIT_SUCCESS, "%s", elsieid);
887d5eed
A
498 } else if (strcmp(argv[i], "--help") == 0) {
499 usage(stdout, EXIT_SUCCESS);
2fc1e207
A
500 }
501 while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
1815bff5
A
502 switch (c) {
503 default:
887d5eed 504 usage(stderr, EXIT_FAILURE);
2fc1e207
A
505 case 'D':
506 Dflag = 1;
507 break;
1815bff5
A
508 case 'd':
509 if (directory == NULL)
510 directory = optarg;
2fc1e207
A
511 else
512 errx(EXIT_FAILURE,
513_("more than one -d option specified"));
514 break;
515 case 'g':
516 setgroup(&gflag, optarg);
1815bff5
A
517 break;
518 case 'l':
519 if (lcltime == NULL)
520 lcltime = optarg;
2fc1e207
A
521 else
522 errx(EXIT_FAILURE,
523_("more than one -l option specified"));
1815bff5 524 break;
2fc1e207
A
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 }
1815bff5
A
535 case 'p':
536 if (psxrules == NULL)
537 psxrules = optarg;
2fc1e207
A
538 else
539 errx(EXIT_FAILURE,
540_("more than one -p option specified"));
541 break;
542 case 'u':
543 setuser(&uflag, optarg);
1815bff5
A
544 break;
545 case 'y':
546 if (yitcommand == NULL)
547 yitcommand = optarg;
2fc1e207
A
548 else
549 errx(EXIT_FAILURE,
550_("more than one -y option specified"));
1815bff5
A
551 break;
552 case 'L':
553 if (leapsec == NULL)
554 leapsec = optarg;
2fc1e207
A
555 else
556 errx(EXIT_FAILURE,
557_("more than one -L option specified"));
1815bff5
A
558 break;
559 case 'v':
560 noise = TRUE;
561 break;
562 case 's':
887d5eed 563 (void) printf("zic: -s ignored\n");
1815bff5
A
564 break;
565 }
566 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
887d5eed 567 usage(stderr, EXIT_FAILURE); /* usage message by request */
1815bff5
A
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)
887d5eed 583 exit(EXIT_FAILURE);
1815bff5
A
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 */
2fc1e207
A
596 for (i = 0; i < nlinks; ++i) {
597 eat(links[i].l_filename, links[i].l_linenum);
1815bff5 598 dolink(links[i].l_from, links[i].l_to);
887d5eed
A
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"));
2fc1e207
A
604 }
605 if (lcltime != NULL) {
606 eat("command line", 1);
1815bff5 607 dolink(lcltime, TZDEFAULT);
2fc1e207
A
608 }
609 if (psxrules != NULL) {
610 eat("command line", 1);
1815bff5 611 dolink(psxrules, TZDEFRULES);
2fc1e207 612 }
1815bff5
A
613 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
614}
615
616static void
887d5eed
A
617dolink(fromfield, tofield)
618const char * const fromfield;
619const char * const tofield;
1815bff5 620{
887d5eed
A
621 register char * fromname;
622 register char * toname;
1815bff5 623
887d5eed
A
624 if (fromfield[0] == '/')
625 fromname = ecpyalloc(fromfield);
1815bff5
A
626 else {
627 fromname = ecpyalloc(directory);
628 fromname = ecatalloc(fromname, "/");
887d5eed 629 fromname = ecatalloc(fromname, fromfield);
1815bff5 630 }
887d5eed
A
631 if (tofield[0] == '/')
632 toname = ecpyalloc(tofield);
1815bff5
A
633 else {
634 toname = ecpyalloc(directory);
635 toname = ecatalloc(toname, "/");
887d5eed 636 toname = ecatalloc(toname, tofield);
1815bff5
A
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) {
2fc1e207
A
645 int result;
646
1815bff5 647 if (mkdirs(toname) != 0)
887d5eed 648 exit(EXIT_FAILURE);
1815bff5 649
2fc1e207 650 result = link(fromname, toname);
887d5eed 651#if HAVE_SYMLINK
2fc1e207 652 if (result != 0 &&
887d5eed
A
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)
2fc1e207 668warning(_("hard link failed, symbolic link used"));
887d5eed 669 ifree(symlinkcontents);
2fc1e207 670 }
887d5eed 671#endif /* HAVE_SYMLINK */
2fc1e207
A
672 if (result != 0) {
673 err(EXIT_FAILURE, _("can't link from %s to %s"),
674 fromname, toname);
1815bff5
A
675 }
676 }
677 ifree(fromname);
678 ifree(toname);
679}
680
887d5eed 681#define TIME_T_BITS_IN_FILE 64
1815bff5
A
682
683static void
887d5eed 684setboundaries (void)
1815bff5 685{
887d5eed
A
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);
1815bff5
A
692}
693
694static int
887d5eed
A
695itsdir(name)
696const char * const name;
1815bff5 697{
887d5eed
A
698 register char * myname;
699 register int accres;
1815bff5
A
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
716static int
887d5eed
A
717rcomp(cp1, cp2)
718const void * cp1;
719const void * cp2;
1815bff5
A
720{
721 return strcmp(((const struct rule *) cp1)->r_name,
722 ((const struct rule *) cp2)->r_name);
723}
724
725static void
887d5eed 726associate(void)
1815bff5 727{
887d5eed
A
728 register struct zone * zp;
729 register struct rule * rp;
730 register int base, out;
731 register int i, j;
1815bff5
A
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"),
887d5eed 788 TRUE);
1815bff5
A
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)
887d5eed 798 exit(EXIT_FAILURE);
1815bff5
A
799}
800
801static void
887d5eed
A
802infile(name)
803const char * name;
1815bff5 804{
887d5eed
A
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];
1815bff5
A
813
814 if (strcmp(name, "-") == 0) {
815 name = _("standard input");
816 fp = stdin;
2fc1e207
A
817 } else if ((fp = fopen(name, "r")) == NULL)
818 err(EXIT_FAILURE, _("can't open %s"), name);
1815bff5
A
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"));
887d5eed 827 exit(EXIT_FAILURE);
1815bff5
A
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)
2fc1e207
A
861 warnx(
862_("leap line in non leap seconds file %s"), name);
1815bff5
A
863 else inleap(fields, nfields);
864 wantcont = FALSE;
865 break;
866 default: /* "cannot happen" */
2fc1e207
A
867 errx(EXIT_FAILURE,
868_("panic: invalid l_value %d"), lp->l_value);
1815bff5
A
869 }
870 }
871 ifree((char *) fields);
872 }
2fc1e207
A
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);
1815bff5
A
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
889static long
887d5eed
A
890gethms(string, errstring, signable)
891const char * string;
892const char * const errstring;
893const int signable;
1815bff5 894{
887d5eed
A
895 long hh;
896 int mm, ss, sign;
1815bff5
A
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;
887d5eed 906 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
1815bff5 907 mm = ss = 0;
887d5eed 908 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
1815bff5 909 ss = 0;
887d5eed 910 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
1815bff5
A
911 &hh, &mm, &ss) != 3) {
912 error(errstring);
913 return 0;
914 }
887d5eed 915 if (hh < 0 ||
1815bff5 916 mm < 0 || mm >= MINSPERHOUR ||
887d5eed 917 ss < 0 || ss > SECSPERMIN) {
1815bff5
A
918 error(errstring);
919 return 0;
920 }
887d5eed
A
921 if (LONG_MAX / SECSPERHOUR < hh) {
922 error(_("time overflow"));
923 return 0;
924 }
925 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
2fc1e207 926 warning(_("24:00 not handled by pre-1998 versions of zic"));
887d5eed
A
927 if (noise && (hh > HOURSPERDAY ||
928 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
929warning(_("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)));
1815bff5
A
932}
933
934static void
887d5eed
A
935inrule(fields, nfields)
936register char ** const fields;
937const int nfields;
1815bff5
A
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]);
887d5eed
A
956 if (max_abbrvar_len < strlen(r.r_abbrvar))
957 max_abbrvar_len = strlen(r.r_abbrvar);
1815bff5
A
958 rules = (struct rule *) (void *) erealloc((char *) rules,
959 (int) ((nrules + 1) * sizeof *rules));
960 rules[nrules++] = r;
961}
962
963static int
887d5eed
A
964inzone(fields, nfields)
965register char ** const fields;
966const int nfields;
1815bff5 967{
887d5eed 968 register int i;
1815bff5
A
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
1008static int
887d5eed
A
1009inzcont(fields, nfields)
1010register char ** const fields;
1011const int nfields;
1815bff5
A
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
1020static int
887d5eed
A
1021inzsub(fields, nfields, iscont)
1022register char ** const fields;
1023const int nfields;
1024const int iscont;
1815bff5 1025{
887d5eed 1026 register char * cp;
1815bff5 1027 static struct zone z;
887d5eed
A
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;
1815bff5
A
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;
2fc1e207 1054 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1815bff5
A
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]);
887d5eed
A
1063 if (max_format_len < strlen(z.z_format))
1064 max_format_len = strlen(z.z_format);
1815bff5
A
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) {
887d5eed
A
1085 error(_(
1086"Zone continuation line end time is not after end time of previous line"
1087 ));
1815bff5
A
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
1101static void
887d5eed
A
1102inleap(fields, nfields)
1103register char ** const fields;
1104const int nfields;
1815bff5 1105{
887d5eed
A
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;
1815bff5
A
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) {
887d5eed
A
1120 /*
1121 ** Leapin' Lizards!
1122 */
1123 error(_("invalid leaping year"));
1124 return;
1815bff5 1125 }
887d5eed
A
1126 if (!leapseen || leapmaxyear < year)
1127 leapmaxyear = year;
1128 if (!leapseen || leapminyear > year)
1129 leapminyear = year;
1130 leapseen = TRUE;
1815bff5
A
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));
887d5eed 1160 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1815bff5
A
1161 error(_("time before zero"));
1162 return;
1163 }
2fc1e207
A
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"));
1815bff5
A
1170 return;
1171 }
887d5eed 1172 t = (zic_t) dayoff * SECSPERDAY;
1815bff5
A
1173 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1174 cp = fields[LP_CORR];
1175 {
887d5eed
A
1176 register int positive;
1177 int count;
1815bff5
A
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) {
887d5eed
A
1196 error(_(
1197 "illegal Rolling/Stationary field on Leap line"
1198 ));
1815bff5
A
1199 return;
1200 }
1201 leapadd(tadd(t, tod), positive, lp->l_value, count);
1202 }
1203}
1204
1205static void
887d5eed
A
1206inlink(fields, nfields)
1207register char ** const fields;
1208const int nfields;
1815bff5
A
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
1233static void
887d5eed
A
1234rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1235register struct rule * const rp;
1236const char * const loyearp;
1237const char * const hiyearp;
1238const char * const typep;
1239const char * const monthp;
1240const char * const dayp;
1241const char * const timep;
1815bff5 1242{
887d5eed
A
1243 register const struct lookup * lp;
1244 register const char * cp;
1245 register char * dp;
1246 register char * ep;
1815bff5
A
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';
2fc1e207 1268 break;
1815bff5
A
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);
887d5eed
A
1285 rp->r_lowasnum = lp == NULL;
1286 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1815bff5
A
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" */
2fc1e207
A
1294 errx(EXIT_FAILURE,
1295 _("panic: invalid l_value %d"), lp->l_value);
1815bff5
A
1296 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1297 error(_("invalid starting year"));
1298 return;
1299 }
1300 cp = hiyearp;
887d5eed
A
1301 lp = byword(cp, end_years);
1302 rp->r_hiwasnum = lp == NULL;
1303 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1815bff5
A
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" */
2fc1e207
A
1314 errx(EXIT_FAILURE,
1315 _("panic: invalid l_value %d"), lp->l_value);
1815bff5
A
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
1380static void
887d5eed
A
1381convert(val, buf)
1382const long val;
1383char * const buf;
1815bff5 1384{
887d5eed
A
1385 register int i;
1386 register int shift;
1815bff5
A
1387
1388 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1389 buf[i] = val >> shift;
1390}
1391
1392static void
887d5eed
A
1393convert64(val, buf)
1394const zic_t val;
1395char * 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
1404static void
1405puttzcode(val, fp)
1406const long val;
1407FILE * const fp;
1815bff5
A
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
887d5eed
A
1415static void
1416puttzcode64(val, fp)
1417const zic_t val;
1418FILE * 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
1815bff5 1426static int
887d5eed
A
1427atcomp(avp, bvp)
1428const void * avp;
1429const void * bvp;
1815bff5 1430{
887d5eed
A
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
1437static int
1438is32(x)
1439const zic_t x;
1440{
1441 return INT32_MIN <= x && x <= INT32_MAX;
1815bff5
A
1442}
1443
1444static void
887d5eed
A
1445writezone(name, string)
1446const char * const name;
1447const char * const string;
1815bff5 1448{
887d5eed
A
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];
1815bff5
A
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;
2fc1e207
A
1475 while (fromi < timecnt && attypes[fromi].at < min_time)
1476 ++fromi;
1815bff5 1477 if (isdsts[0] == 0)
2fc1e207 1478 while (fromi < timecnt && attypes[fromi].type == 0)
1815bff5
A
1479 ++fromi; /* handled by default rule */
1480 for ( ; fromi < timecnt; ++fromi) {
887d5eed
A
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;
1815bff5
A
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 }
887d5eed
A
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 }
1815bff5
A
1532 fullname = erealloc(fullname,
1533 (int) (strlen(directory) + 1 + strlen(name) + 1));
1534 (void) sprintf(fullname, "%s/%s", directory, name);
2fc1e207 1535
1815bff5 1536 /*
2fc1e207
A
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);
1815bff5 1541
1815bff5
A
1542 if ((fp = fopen(fullname, "wb")) == NULL) {
1543 if (mkdirs(fullname) != 0)
887d5eed 1544 exit(EXIT_FAILURE);
2fc1e207
A
1545 if ((fp = fopen(fullname, "wb")) == NULL)
1546 err(EXIT_FAILURE, _("can't create %s"), fullname);
1815bff5 1547 }
887d5eed
A
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;
1815bff5 1624 }
887d5eed
A
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;
1815bff5 1659 }
887d5eed
A
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);
2fc1e207
A
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);
1815bff5
A
1748}
1749
1750static void
887d5eed
A
1751doabbr(abbr, format, letters, isdst, doquotes)
1752char * const abbr;
1753const char * const format;
1754const char * const letters;
1755const int isdst;
1756const int doquotes;
1815bff5 1757{
887d5eed
A
1758 register char * cp;
1759 register char * slashp;
1760 register int len;
1761
1762 slashp = strchr(format, '/');
1763 if (slashp == NULL) {
1815bff5
A
1764 if (letters == NULL)
1765 (void) strcpy(abbr, format);
1766 else (void) sprintf(abbr, format, letters);
887d5eed
A
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
1791static void
1792updateminmax(x)
1793const int x;
1794{
1795 if (min_year > x)
1796 min_year = x;
1797 if (max_year < x)
1798 max_year = x;
1799}
1800
1801static int
1802stringoffset(result, offset)
1803char * result;
1804long 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
1833static int
1834stringrule(result, rp, dstoff, gmtoff)
1835char * result;
1836const struct rule * const rp;
1837const long dstoff;
1838const 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;
1815bff5 1884 }
887d5eed 1885 return 0;
1815bff5
A
1886}
1887
1888static void
887d5eed
A
1889stringzone(result, zpfirst, zonecount)
1890char * result;
1891const struct zone * const zpfirst;
1892const int zonecount;
1815bff5 1893{
887d5eed
A
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}
1815bff5 1970
887d5eed
A
1971static void
1972outzone(zpfirst, zonecount)
1973const struct zone * const zpfirst;
1974const 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);
1815bff5
A
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 /*
887d5eed 2008 ** Thanks to Earl Chew
1815bff5
A
2009 ** for noting the need to unconditionally initialize startttisstd.
2010 */
2011 startttisstd = FALSE;
2012 startttisgmt = FALSE;
887d5eed
A
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
2037wp = 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;
1815bff5 2059 for (i = 0; i < zonecount; ++i) {
2fc1e207
A
2060 /*
2061 ** A guess that may well be corrected later.
2062 */
2063 stdoff = 0;
1815bff5
A
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,
887d5eed 2076 (char *) NULL, stdoff != 0, FALSE);
1815bff5
A
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;
2fc1e207 2083 } else if (stdoff != 0)
1815bff5
A
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 ( ; ; ) {
887d5eed
A
2103 register int k;
2104 register zic_t jtime, ktime;
2105 register long offset;
1815bff5
A
2106
2107 INITIALIZE(ktime);
2108 if (useuntil) {
2109 /*
2fc1e207 2110 ** Turn untiltime into UTC
1815bff5
A
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,
887d5eed
A
2161 rp->r_stdoff != 0,
2162 FALSE);
1815bff5
A
2163 continue;
2164 }
2165 if (*startbuf == '\0' &&
887d5eed
A
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);
1815bff5
A
2174 }
2175 }
2176 eats(zp->z_filename, zp->z_linenum,
2177 rp->r_filename, rp->r_linenum);
887d5eed
A
2178 doabbr(ab, zp->z_format, rp->r_abbrvar,
2179 rp->r_stdoff != 0, FALSE);
1815bff5 2180 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
887d5eed 2181 type = addtype(offset, ab, rp->r_stdoff != 0,
1815bff5
A
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')
2194error(_("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 }
887d5eed
A
2214 writezone(zpfirst->z_name, envvar);
2215 ifree(startbuf);
2216 ifree(ab);
2217 ifree(envvar);
1815bff5
A
2218}
2219
2220static void
887d5eed
A
2221addtt(starttime, type)
2222const zic_t starttime;
2223int type;
1815bff5 2224{
2fc1e207
A
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;
887d5eed 2234 charcnt = strlen(chars) + 1;
2fc1e207
A
2235 typecnt = 1;
2236 timecnt = 0;
2237 type = 0;
2238 }
1815bff5
A
2239 if (timecnt >= TZ_MAX_TIMES) {
2240 error(_("too many transitions?!"));
887d5eed 2241 exit(EXIT_FAILURE);
1815bff5
A
2242 }
2243 attypes[timecnt].at = starttime;
2244 attypes[timecnt].type = type;
2245 ++timecnt;
2246}
2247
2248static int
887d5eed
A
2249addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2250const long gmtoff;
2251const char * const abbr;
2252const int isdst;
2253const int ttisstd;
2254const int ttisgmt;
1815bff5 2255{
887d5eed 2256 register int i, j;
1815bff5
A
2257
2258 if (isdst != TRUE && isdst != FALSE) {
2259 error(_("internal error - addtype called with bad isdst"));
887d5eed 2260 exit(EXIT_FAILURE);
1815bff5
A
2261 }
2262 if (ttisstd != TRUE && ttisstd != FALSE) {
2263 error(_("internal error - addtype called with bad ttisstd"));
887d5eed 2264 exit(EXIT_FAILURE);
1815bff5
A
2265 }
2266 if (ttisgmt != TRUE && ttisgmt != FALSE) {
2267 error(_("internal error - addtype called with bad ttisgmt"));
887d5eed 2268 exit(EXIT_FAILURE);
1815bff5
A
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"));
887d5eed
A
2287 exit(EXIT_FAILURE);
2288 }
2289 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2290 error(_("UTC offset out of range"));
2291 exit(EXIT_FAILURE);
1815bff5
A
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
2308static void
887d5eed
A
2309leapadd(t, positive, rolling, count)
2310const zic_t t;
2311const int positive;
2312const int rolling;
2313int count;
1815bff5 2314{
887d5eed 2315 register int i, j;
1815bff5
A
2316
2317 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2318 error(_("too many leap seconds"));
887d5eed 2319 exit(EXIT_FAILURE);
1815bff5
A
2320 }
2321 for (i = 0; i < leapcnt; ++i)
2322 if (t <= trans[i]) {
2323 if (t == trans[i]) {
2324 error(_("repeated leap second moment"));
887d5eed 2325 exit(EXIT_FAILURE);
1815bff5
A
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
2342static void
887d5eed 2343adjleap(void)
1815bff5 2344{
887d5eed
A
2345 register int i;
2346 register long last = 0;
1815bff5
A
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
2357static int
887d5eed
A
2358yearistype(year, type)
2359const int year;
2360const char * const type;
1815bff5
A
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);
2fc1e207
A
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);
1815bff5 2378 for ( ; ; )
887d5eed 2379 exit(EXIT_FAILURE);
1815bff5
A
2380}
2381
2382static int
887d5eed
A
2383lowerit(a)
2384int a;
1815bff5
A
2385{
2386 a = (unsigned char) a;
2387 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2388}
2389
2390static int
887d5eed
A
2391ciequal(ap, bp) /* case-insensitive equality */
2392register const char * ap;
2393register const char * bp;
1815bff5
A
2394{
2395 while (lowerit(*ap) == lowerit(*bp++))
2396 if (*ap++ == '\0')
2397 return TRUE;
2398 return FALSE;
2399}
2400
2401static int
887d5eed
A
2402itsabbr(abbr, word)
2403register const char * abbr;
2404register const char * word;
1815bff5
A
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
2417static const struct lookup *
887d5eed
A
2418byword(word, table)
2419register const char * const word;
2420register const struct lookup * const table;
1815bff5 2421{
887d5eed
A
2422 register const struct lookup * foundlp;
2423 register const struct lookup * lp;
1815bff5
A
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)
2fc1e207 2438 if (itsabbr(word, lp->l_word)) {
1815bff5
A
2439 if (foundlp == NULL)
2440 foundlp = lp;
2441 else return NULL; /* multiple inexact matches */
2fc1e207 2442 }
1815bff5
A
2443 return foundlp;
2444}
2445
2446static char **
887d5eed
A
2447getfields(cp)
2448register char * cp;
1815bff5 2449{
887d5eed
A
2450 register char * dp;
2451 register char ** array;
2452 register int nsubs;
1815bff5
A
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 ( ; ; ) {
887d5eed
A
2460 while (isascii((unsigned char) *cp) &&
2461 isspace((unsigned char) *cp))
2462 ++cp;
1815bff5
A
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;
ef8ad44b
A
2472 else {
2473 error(_("odd number of quotation marks"));
2474 exit(EXIT_FAILURE);
2475 }
1815bff5
A
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
2486static long
887d5eed
A
2487oadd(t1, t2)
2488const long t1;
2489const long t2;
1815bff5 2490{
887d5eed 2491 register long t;
1815bff5
A
2492
2493 t = t1 + t2;
2494 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2495 error(_("time overflow"));
887d5eed 2496 exit(EXIT_FAILURE);
1815bff5
A
2497 }
2498 return t;
2499}
2500
887d5eed
A
2501static zic_t
2502tadd(t1, t2)
2503const zic_t t1;
2504const long t2;
1815bff5 2505{
887d5eed 2506 register zic_t t;
1815bff5
A
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"));
887d5eed 2515 exit(EXIT_FAILURE);
1815bff5
A
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
887d5eed
A
2525static zic_t
2526rpytime(rp, wantedy)
2527register const struct rule * const rp;
2528register const int wantedy;
1815bff5 2529{
887d5eed
A
2530 register int y, m, i;
2531 register long dayoff; /* with a nod to Margaret O. */
2532 register zic_t t;
1815bff5
A
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"));
887d5eed 2562 exit(EXIT_FAILURE);
1815bff5
A
2563 }
2564 }
2565 --i;
2566 dayoff = oadd(dayoff, eitol(i));
2567 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
887d5eed 2568 register long wday;
1815bff5
A
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]) {
2fc1e207 2595 if (noise)
887d5eed
A
2596 warning(_("rule goes past start/end of month--\
2597will not work with pre-2004 versions of zic"));
1815bff5
A
2598 }
2599 }
2fc1e207
A
2600 if (dayoff < min_time / SECSPERDAY)
2601 return min_time;
2602 if (dayoff > max_time / SECSPERDAY)
2603 return max_time;
887d5eed 2604 t = (zic_t) dayoff * SECSPERDAY;
1815bff5
A
2605 return tadd(t, rp->r_tod);
2606}
2607
2608static void
887d5eed
A
2609newabbr(string)
2610const char * const string;
1815bff5 2611{
887d5eed 2612 register int i;
1815bff5 2613
887d5eed
A
2614 if (strcmp(string, GRANDPARENTED) != 0) {
2615 register const char * cp;
2616 register char * wp;
2617
2618 /*
2619 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2620 ** optionally followed by a + or - and a number from 1 to 14.
2621 */
2622 cp = string;
2623 wp = NULL;
2624 while (isascii((unsigned char) *cp) &&
2625 isalpha((unsigned char) *cp))
2626 ++cp;
2627 if (cp - string == 0)
2628wp = _("time zone abbreviation lacks alphabetic at start");
2629 if (noise && cp - string > 3)
2630wp = _("time zone abbreviation has more than 3 alphabetics");
2631 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2632wp = _("time zone abbreviation has too many alphabetics");
2633 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2634 ++cp;
2635 if (isascii((unsigned char) *cp) &&
2636 isdigit((unsigned char) *cp))
2637 if (*cp++ == '1' &&
2638 *cp >= '0' && *cp <= '4')
2639 ++cp;
2640 }
2641 if (*cp != '\0')
2642wp = _("time zone abbreviation differs from POSIX standard");
2643 if (wp != NULL) {
2644 wp = ecpyalloc(wp);
2645 wp = ecatalloc(wp, " (");
2646 wp = ecatalloc(wp, string);
2647 wp = ecatalloc(wp, ")");
2648 warning(wp);
2649 ifree(wp);
2650 }
2651 }
2652 i = strlen(string) + 1;
1815bff5
A
2653 if (charcnt + i > TZ_MAX_CHARS) {
2654 error(_("too many, or too long, time zone abbreviations"));
887d5eed 2655 exit(EXIT_FAILURE);
1815bff5
A
2656 }
2657 (void) strcpy(&chars[charcnt], string);
2658 charcnt += eitol(i);
2659}
2660
2661static int
887d5eed
A
2662mkdirs(argname)
2663char * argname;
1815bff5 2664{
887d5eed
A
2665 register char * name;
2666 register char * cp;
1815bff5 2667
2fc1e207 2668 if (argname == NULL || *argname == '\0' || Dflag)
1815bff5
A
2669 return 0;
2670 cp = name = ecpyalloc(argname);
2671 while ((cp = strchr(cp + 1, '/')) != 0) {
2672 *cp = '\0';
2673#ifndef unix
2674 /*
2675 ** DOS drive specifier?
2676 */
2677 if (isalpha((unsigned char) name[0]) &&
2678 name[1] == ':' && name[2] == '\0') {
2679 *cp = '/';
2680 continue;
2681 }
2682#endif /* !defined unix */
2683 if (!itsdir(name)) {
2684 /*
2685 ** It doesn't seem to exist, so we try to create it.
2fc1e207
A
2686 ** Creation may fail because of the directory being
2687 ** created by some other multiprocessor, so we get
2688 ** to do extra checking.
1815bff5 2689 */
2fc1e207
A
2690 if (mkdir(name, MKDIR_UMASK) != 0
2691 && (errno != EEXIST || !itsdir(name))) {
2692 warn(_("can't create directory %s"), name);
1815bff5
A
2693 ifree(name);
2694 return -1;
2695 }
2696 }
2697 *cp = '/';
2698 }
2699 ifree(name);
2700 return 0;
2701}
2702
2703static long
887d5eed
A
2704eitol(i)
2705const int i;
1815bff5
A
2706{
2707 long l;
2708
2709 l = i;
2fc1e207
A
2710 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2711 errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
1815bff5
A
2712 return l;
2713}
2714
2fc1e207
A
2715#include <grp.h>
2716#include <pwd.h>
2717
2718static void
887d5eed
A
2719setgroup(flag, name)
2720 gid_t *flag;
2721 const char *name;
2fc1e207
A
2722{
2723 struct group *gr;
2724
2725 if (*flag != (gid_t)-1)
2726 errx(EXIT_FAILURE, _("multiple -g flags specified"));
2727
2728 gr = getgrnam(name);
2729 if (gr == 0) {
2730 char *ep;
2731 unsigned long ul;
2732
2733 ul = strtoul(name, &ep, 10);
2734 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
887d5eed 2735 *flag = ul;
2fc1e207
A
2736 return;
2737 }
2738 errx(EXIT_FAILURE, _("group `%s' not found"), name);
2739 }
2740 *flag = gr->gr_gid;
2741}
2742
2743static void
887d5eed
A
2744setuser(flag, name)
2745 uid_t *flag;
2746 const char *name;
2fc1e207
A
2747{
2748 struct passwd *pw;
2749
2750 if (*flag != (gid_t)-1)
2751 errx(EXIT_FAILURE, _("multiple -u flags specified"));
2752
2753 pw = getpwnam(name);
2754 if (pw == 0) {
2755 char *ep;
2756 unsigned long ul;
2757
2758 ul = strtoul(name, &ep, 10);
2759 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
887d5eed 2760 *flag = ul;
2fc1e207
A
2761 return;
2762 }
2763 errx(EXIT_FAILURE, _("user `%s' not found"), name);
2764 }
2765 *flag = pw->pw_uid;
2766}
2767
1815bff5 2768/*
2fc1e207 2769** UNIX was a registered trademark of The Open Group in 2003.
1815bff5 2770*/