diff --git a/usr.sbin/tzsetup/baseline b/usr.sbin/tzsetup/baseline --- a/usr.sbin/tzsetup/baseline +++ b/usr.sbin/tzsetup/baseline @@ -19,10 +19,10 @@ Antarctica:Antarctica/Palmer Antarctica:Antarctica/Rothera Antarctica:Antarctica/Troll - Asia:Asia/Urumqi - Pacific:Pacific/Auckland - Pacific:Pacific/Port_Moresby - Asia:Asia/Riyadh + Antarctica:Asia/Urumqi + Antarctica:Pacific/Auckland + Antarctica:Pacific/Port_Moresby + Antarctica:Asia/Riyadh AG:Antigua and Barbuda America:America/Puerto_Rico AR:Argentina @@ -159,13 +159,13 @@ Asia:Asia/Shanghai Asia:Asia/Urumqi CX:Christmas Island - Asia:Asia/Bangkok + Indian:Asia/Bangkok CC:Cocos (Keeling) Islands - Asia:Asia/Yangon + Indian:Asia/Yangon CO:Colombia America:America/Bogota KM:Comoros - Africa:Africa/Nairobi + Indian:Africa/Nairobi CG:Congo Africa:Africa/Lagos CD:Congo, Democratic Republic of the @@ -280,7 +280,7 @@ HU:Hungary Europe:Europe/Budapest IS:Iceland - Africa:Africa/Abidjan + Atlantic:Africa/Abidjan IN:India Asia:Asia/Kolkata ID:Indonesia @@ -353,7 +353,7 @@ MK:Macedonia (the former Yugoslav Republic of) Europe:Europe/Belgrade MG:Madagascar - Africa:Africa/Nairobi + Indian:Africa/Nairobi MW:Malawi Africa:Africa/Maputo MY:Malaysia @@ -375,7 +375,7 @@ MU:Mauritius Indian:Indian/Mauritius YT:Mayotte - Africa:Africa/Nairobi + Indian:Africa/Nairobi MX:Mexico America:America/Mexico_City America:America/Cancun @@ -507,7 +507,7 @@ BL:Saint Barthélemy America:America/Puerto_Rico SH:Saint Helena Ascension and Tristan da Cunha - Africa:Africa/Abidjan + Atlantic:Africa/Abidjan KN:Saint Kitts and Nevis America:America/Puerto_Rico LC:Saint Lucia @@ -563,7 +563,7 @@ SR:Suriname America:America/Paramaribo SJ:Svalbard and Jan Mayen - Europe:Europe/Berlin + Arctic:Europe/Berlin SE:Sweden Europe:Europe/Berlin CH:Switzerland diff --git a/usr.sbin/tzsetup/tzsetup.c b/usr.sbin/tzsetup/tzsetup.c --- a/usr.sbin/tzsetup/tzsetup.c +++ b/usr.sbin/tzsetup/tzsetup.c @@ -157,8 +157,7 @@ static int confirm_zone(const char *filename); static int continent_country_menu(dialogMenuItem *); -static int set_zone_multi(dialogMenuItem *); -static int set_zone_whole_country(dialogMenuItem *); +static int set_zone(dialogMenuItem *); static int set_zone_menu(dialogMenuItem *); static int set_zone_utc(void); @@ -167,7 +166,7 @@ int nitems; }; -static struct continent africa, america, antarctica, asia, atlantic; +static struct continent africa, america, antarctica, arctic, asia, atlantic; static struct continent australia, europe, indian, pacific, utc; static struct continent_names { @@ -177,6 +176,7 @@ { "Africa", &africa }, { "America", &america }, { "Antarctica", &antarctica }, + { "Arctic", &arctic }, { "Asia", &asia }, { "Atlantic", &atlantic }, { "Australia", &australia }, @@ -187,26 +187,27 @@ }; static struct continent_items { - char prompt[2]; + char prompt[3]; char title[30]; } continent_items[] = { { "1", "Africa" }, { "2", "America -- North and South" }, { "3", "Antarctica" }, - { "4", "Asia" }, - { "5", "Atlantic Ocean" }, - { "6", "Australia" }, - { "7", "Europe" }, - { "8", "Indian Ocean" }, - { "9", "Pacific Ocean" }, - { "0", "UTC" } + { "4", "Arctic Ocean" }, + { "5", "Asia" }, + { "6", "Atlantic Ocean" }, + { "7", "Australia" }, + { "8", "Europe" }, + { "9", "Indian Ocean" }, + { "10", "Pacific Ocean" }, + { "11", "UTC" } }; #define NCONTINENTS \ (int)((sizeof(continent_items)) / (sizeof(continent_items[0]))) static dialogMenuItem continents[NCONTINENTS]; -#define OCEANP(x) ((x) == 4 || (x) == 7 || (x) == 8) +#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) static int continent_country_menu(dialogMenuItem *continent) @@ -219,10 +220,6 @@ if (strcmp(continent->title, "UTC") == 0) return (set_zone_utc()); - /* Short cut -- if there's only one country, don't post a menu. */ - if (contp->nitems == 1) - return (contp->menu[0].fire(&contp->menu[0])); - /* It's amazing how much good grammar really matters... */ if (!isocean) { snprintf(title, sizeof(title), "Countries in %s", @@ -239,14 +236,30 @@ } static struct continent * -find_continent(const char *name) +find_continent(int lineno, const char *name) { + char *cname, *cp; int i; + /* + * Both normal (the ones in zone filename, e.g. Europe/Andorra) and + * override (e.g. Atlantic/) entries should contain '/'. + */ + cp = strdup(name); + if (cp == NULL) + err(1, "strdup"); + cname = strsep(&cp, "/"); + if (cp == NULL) + errx(1, "%s:%d: invalid entry `%s'", path_zonetab, lineno, + cname); + for (i = 0; i < NCONTINENTS; i++) - if (strcmp(name, continent_names[i].name) == 0) + if (strcmp(cname, continent_names[i].name) == 0) { + free(cname); return (continent_names[i].continent); - return (0); + } + + errx(1, "%s:%d: continent `%s' unknown", path_zonetab, lineno, cname); } static const char * @@ -264,10 +277,9 @@ char *name; char *tlc; int nzones; - char *filename; /* use iff nzones < 0 */ - struct continent *continent; /* use iff nzones < 0 */ - TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ - dialogMenuItem *submenu; /* use iff nzones > 0 */ + struct continent *override; /* continent override */ + TAILQ_HEAD(, zone) zones; + dialogMenuItem *submenu; }; struct zone { @@ -346,56 +358,50 @@ fclose(fp); } -static void -add_zone_to_country(int lineno, const char *tlc, const char *descr, - const char *file, struct continent *cont) +static struct country * +find_country(int lineno, const char *tlc) { - struct zone *zp; struct country *cp; - if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') + if (strlen(tlc) != 2 || + tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') errx(1, "%s:%d: country code `%s' invalid", path_zonetab, lineno, tlc); cp = &countries[CODE2INT(tlc)]; - if (cp->name == 0) + if (cp->name == NULL) errx(1, "%s:%d: country code `%s' unknown", path_zonetab, lineno, tlc); - if (descr) { - if (cp->nzones < 0) - errx(1, "%s:%d: conflicting zone definition", - path_zonetab, lineno); + return (cp); +} + +static void +add_zone_to_country(int lineno, struct country *cp, const char *descr, + const char *file, struct continent *cont) +{ + struct zone *zp; - zp = malloc(sizeof(*zp)); - if (zp == NULL) - errx(1, "malloc(%zu)", sizeof(*zp)); + zp = malloc(sizeof(*zp)); + if (zp == NULL) + errx(1, "malloc(%zu)", sizeof(*zp)); - if (cp->nzones == 0) - TAILQ_INIT(&cp->zones); + if (cp->nzones == 0) + TAILQ_INIT(&cp->zones); + if (descr != NULL) { zp->descr = strdup(descr); if (zp->descr == NULL) errx(1, "malloc failed"); - zp->filename = strdup(file); - if (zp->filename == NULL) - errx(1, "malloc failed"); - zp->continent = cont; - TAILQ_INSERT_TAIL(&cp->zones, zp, link); - cp->nzones++; } else { - if (cp->nzones > 0) - errx(1, "%s:%d: zone must have description", - path_zonetab, lineno); - if (cp->nzones < 0) - errx(1, "%s:%d: zone multiply defined", - path_zonetab, lineno); - cp->nzones = -1; - cp->filename = strdup(file); - if (cp->filename == NULL) - errx(1, "malloc failed"); - cp->continent = cont; + zp->descr = NULL; } + zp->filename = strdup(file); + if (zp->filename == NULL) + errx(1, "malloc failed"); + zp->continent = cp->override != NULL ? cp->override : cont; + TAILQ_INSERT_TAIL(&cp->zones, zp, link); + cp->nzones++; } /* @@ -432,54 +438,79 @@ static void read_zones(void) { - char contbuf[16]; FILE *fp; struct continent *cont; - size_t len, contlen; - char *line, *country_list, *tlc, *file, *descr, *p; + struct country *cp; + size_t len; + char *line, *country_list, *tlc, *file, *descr; int lineno; + bool pass1; fp = fopen(path_zonetab, "r"); if (!fp) err(1, "%s", path_zonetab); - lineno = 0; + pass1 = true; +again: + lineno = 0; while ((line = fgetln(fp, &len)) != NULL) { lineno++; if (line[len - 1] != '\n') errx(1, "%s:%d: invalid format", path_zonetab, lineno); line[len - 1] = '\0'; - if (line[0] == '#') - continue; - country_list = strsep(&line, "\t"); - /* coord = */ strsep(&line, "\t"); /* Unused */ - file = strsep(&line, "\t"); - /* get continent portion from continent/country */ - p = strchr(file, '/'); - if (p == NULL) - errx(1, "%s:%d: invalid zone name `%s'", path_zonetab, - lineno, file); - contlen = p - file + 1; /* trailing nul */ - if (contlen > sizeof(contbuf)) - errx(1, "%s:%d: continent name in zone name `%s' too long", - path_zonetab, lineno, file); - strlcpy(contbuf, file, contlen); - cont = find_continent(contbuf); - if (!cont) - errx(1, "%s:%d: invalid region `%s'", path_zonetab, - lineno, contbuf); - - descr = (line != NULL && *line != '\0') ? line : NULL; - - while (country_list != NULL) { - tlc = strsep(&country_list, ","); - if (strlen(tlc) != 2) - errx(1, "%s:%d: invalid country code `%s'", - path_zonetab, lineno, tlc); - add_zone_to_country(lineno, tlc, descr, file, cont); + if (pass1) { + /* + * First pass: collect overrides, only looking for + * single continent ones for the moment. + * + * zone1970.tab introduced continent overrides in the + * following format: + * + * #@TLC[,TLC...]CONTINENT/[,CONTINENT/...] + */ + if (strncmp(line, "#@", strlen("#@")) != 0) + continue; + line += 2; + country_list = strsep(&line, "\t"); + /* Skip multi-continent overrides */ + if (strchr(line, ',') != NULL) + continue; + cont = find_continent(lineno, line); + /* Parse and store overrides */ + while (country_list != NULL) { + tlc = strsep(&country_list, ","); + cp = find_country(lineno, tlc); + cp->override = cont; + } + } else { + /* Second pass: parse actual data */ + if (line[0] == '#') + continue; + + country_list = strsep(&line, "\t"); + /* coord = */ strsep(&line, "\t"); /* Unused */ + file = strsep(&line, "\t"); + cont = find_continent(lineno, file); + descr = (line != NULL && *line != '\0') ? line : NULL; + + while (country_list != NULL) { + tlc = strsep(&country_list, ","); + cp = find_country(lineno, tlc); + add_zone_to_country(lineno, cp, descr, file, + cont); + } } } + + if (pass1) { + pass1 = false; + errno = 0; + rewind(fp); + if (errno != 0) + err(1, "failed to rewind %s", path_zonetab); + goto again; + } fclose(fp); } @@ -492,14 +523,9 @@ for (cp = countries; cp->name != NULL; cp++) { printf("%s:%s\n", cp->tlc, cp->name); - if (cp->nzones < 0) { - cont = find_continent_name(cp->continent); - printf(" %s:%s\n", cont, cp->filename); - } else { - TAILQ_FOREACH(zp, &cp->zones, link) { - cont = find_continent_name(zp->continent); - printf(" %s:%s\n", cont, zp->filename); - } + TAILQ_FOREACH(zp, &cp->zones, link) { + cont = find_continent_name(zp->continent); + printf(" %s:%s\n", cont, zp->filename); } } } @@ -522,18 +548,14 @@ for (cp = countries; cp->name; cp++) { if (cp->nzones == 0) continue; - if (cp->nzones < 0) { - cp->continent->nitems++; - } else { - TAILQ_FOREACH(zp, &cp->zones, link) { - cont = zp->continent; - for (zp2 = TAILQ_FIRST(&cp->zones); - zp2->continent != cont; - zp2 = TAILQ_NEXT(zp2, link)) - ; - if (zp2 == zp) - zp->continent->nitems++; - } + TAILQ_FOREACH(zp, &cp->zones, link) { + cont = zp->continent; + for (zp2 = TAILQ_FIRST(&cp->zones); + zp2->continent != cont; + zp2 = TAILQ_NEXT(zp2, link)) + ; + if (zp2 == zp) + zp->continent->nitems++; } } @@ -564,41 +586,32 @@ for (cp = countries; cp->name; cp++) { if (cp->nzones == 0) continue; - if (cp->nzones < 0) { - dmi = &cp->continent->menu[cp->continent->nitems]; + cp->submenu = malloc(cp->nzones * sizeof(*dmi)); + if (cp->submenu == 0) + errx(1, "malloc for submenu"); + cp->nzones = 0; + TAILQ_FOREACH(zp, &cp->zones, link) { + cont = zp->continent; + dmi = &cp->submenu[cp->nzones]; + memset(dmi, 0, sizeof(*dmi)); + asprintf(&dmi->prompt, "%d", ++cp->nzones); + dmi->title = zp->descr; + dmi->fire = set_zone; + dmi->data = zp; + + for (zp2 = TAILQ_FIRST(&cp->zones); + zp2->continent != cont; + zp2 = TAILQ_NEXT(zp2, link)) + ; + if (zp2 != zp) + continue; + + dmi = &cont->menu[cont->nitems]; memset(dmi, 0, sizeof(*dmi)); - asprintf(&dmi->prompt, "%d", ++cp->continent->nitems); + asprintf(&dmi->prompt, "%d", ++cont->nitems); dmi->title = cp->name; - dmi->fire = set_zone_whole_country; + dmi->fire = set_zone_menu; dmi->data = cp; - } else { - cp->submenu = malloc(cp->nzones * sizeof(*dmi)); - if (cp->submenu == 0) - errx(1, "malloc for submenu"); - cp->nzones = 0; - TAILQ_FOREACH(zp, &cp->zones, link) { - cont = zp->continent; - dmi = &cp->submenu[cp->nzones]; - memset(dmi, 0, sizeof(*dmi)); - asprintf(&dmi->prompt, "%d", ++cp->nzones); - dmi->title = zp->descr; - dmi->fire = set_zone_multi; - dmi->data = zp; - - for (zp2 = TAILQ_FIRST(&cp->zones); - zp2->continent != cont; - zp2 = TAILQ_NEXT(zp2, link)) - ; - if (zp2 != zp) - continue; - - dmi = &cont->menu[cont->nitems]; - memset(dmi, 0, sizeof(*dmi)); - asprintf(&dmi->prompt, "%d", ++cont->nitems); - dmi->title = cp->name; - dmi->fire = set_zone_menu; - dmi->data = cp; - } } } } @@ -610,6 +623,10 @@ struct country *cp = dmi->data; int rv; + /* Short cut -- if there's only one zone, don't post a menu. */ + if (cp->nzones == 1) + return (cp->submenu[0].fire(&cp->submenu[0])); + snprintf(title, sizeof(title), "%s Time Zones", cp->name); snprintf(prompt, sizeof(prompt), "Select a zone which observes the same time as your locality."); @@ -646,7 +663,7 @@ } static int -set_zone_multi(dialogMenuItem *dmi) +set_zone(dialogMenuItem *dmi) { struct zone *zp = dmi->data; int rv; @@ -658,19 +675,6 @@ return (rv); } -static int -set_zone_whole_country(dialogMenuItem *dmi) -{ - struct country *cp = dmi->data; - int rv; - - if (!confirm_zone(cp->filename)) - return (DITEM_FAILURE | DITEM_RECREATE); - - rv = install_zoneinfo(cp->filename); - return (rv); -} - #endif static void message_zoneinfo_file(const char *title, char *prompt)