newlib-cygwin/winsup/utils/tzset.c

149 lines
3.9 KiB
C

/* tzset.c: Convert current Windows timezone to POSIX timezone information.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
#include <wchar.h>
#include <locale.h>
#include <getopt.h>
#include <cygwin/version.h>
#include <windows.h>
/* The auto-generated tzmap.h contains the mapping table from Windows timezone
and country per ISO 3166-1 to POSIX timezone. For more info, see the file
itself. */
#include "tzmap.h"
#define TZMAP_SIZE (sizeof tzmap / sizeof tzmap[0])
static struct option longopts[] =
{
{"help", no_argument, NULL, 'h' },
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
static char opts[] = "hV";
static void __attribute__ ((__noreturn__))
usage (FILE *stream)
{
fprintf (stream, ""
"Usage: %1$s [OPTION]\n"
"\n"
"Print POSIX-compatible timezone ID from current Windows timezone setting\n"
"\n"
"Options:\n"
" -h, --help output usage information and exit.\n"
" -V, --version output version information and exit.\n"
"\n"
"Use %1$s to set your TZ variable. In POSIX-compatible shells like bash,\n"
"dash, mksh, or zsh:\n"
"\n"
" export TZ=$(%1$s)\n"
"\n"
"In csh-compatible shells like tcsh:\n"
"\n"
" setenv TZ `%1$s`\n"
"\n", program_invocation_short_name);
exit (stream == stdout ? 0 : 1);
};
static void
print_version ()
{
printf ("tzset (cygwin) %d.%d.%d\n"
"POSIX-timezone generator\n"
"Copyright (C) 2012 - %s Cygwin Authors\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
CYGWIN_VERSION_DLL_MAJOR / 1000,
CYGWIN_VERSION_DLL_MAJOR % 1000,
CYGWIN_VERSION_DLL_MINOR,
strrchr (__DATE__, ' ') + 1);
}
int
main (int argc, char **argv)
{
DYNAMIC_TIME_ZONE_INFORMATION tz;
WCHAR country[10], *spc;
GEOID geo;
int opt, idx, gotit = -1;
setlocale (LC_ALL, "");
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
switch (opt)
{
case 'h':
usage (stdout);
case 'V':
print_version ();
return 0;
default:
fprintf (stderr, "Try `%s --help' for more information.\n",
program_invocation_short_name);
return 1;
}
if (optind < argc)
usage (stderr);
if (GetDynamicTimeZoneInformation (&tz) == TIME_ZONE_ID_INVALID)
return 1;
/* We fetch the current Geo-location of the user and convert it to an
ISO 3166-1 compatible nation code. */
*country = L'\0';
geo = GetUserGeoID (GEOCLASS_NATION);
if (geo != GEOID_NOT_AVAILABLE)
GetGeoInfoW (geo, GEO_ISO2, country, sizeof country / sizeof (*country), 0);
/* If, for some reason, the Geo-location isn't available, we use the locale
setting instead. */
if (!*country)
GetLocaleInfoW (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME,
country, sizeof country);
/* Now iterate over the mapping table and find the right entry. */
for (idx = 0; idx < TZMAP_SIZE; ++idx)
{
if (!wcscasecmp (tz.TimeZoneKeyName, tzmap[idx].win_tzkey))
{
if (gotit < 0)
gotit = idx;
if (!wcscasecmp (country, tzmap[idx].country))
break;
}
else if (gotit >= 0)
{
idx = gotit;
break;
}
}
if (idx >= TZMAP_SIZE)
{
if (gotit < 0)
{
fprintf (stderr,
"%s: can't find matching POSIX timezone for "
"Windows timezone \"%ls\"\n",
program_invocation_short_name, tz.TimeZoneKeyName);
return 1;
}
idx = gotit;
}
/* Got one. Print it.
Note: The tzmap array is in the R/O data section on x86_64. Don't
try to overwrite the space, as the code did originally. */
spc = wcschr (tzmap[idx].posix_tzid, L' ');
if (!spc)
spc = wcschr (tzmap[idx].posix_tzid, L'\0');
printf ("%.*ls\n", (int) (spc - tzmap[idx].posix_tzid), tzmap[idx].posix_tzid);
return 0;
}