322 lines
8.5 KiB
C
322 lines
8.5 KiB
C
/*
|
|
* Vzic - a program to convert Olson timezone database files into VZTIMEZONE
|
|
* files compatible with the iCalendar specification (RFC2445).
|
|
*
|
|
* Copyright (C) 2000-2001 Ximian, Inc.
|
|
* Copyright (C) 2003 Damon Chaplin.
|
|
*
|
|
* Author: Damon Chaplin <damon@gnome.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "vzic.h"
|
|
#include "vzic-parse.h"
|
|
#include "vzic-dump.h"
|
|
#include "vzic-output.h"
|
|
|
|
|
|
/*
|
|
* Global command-line options.
|
|
*/
|
|
|
|
/* By default we output Outlook-compatible output. If --pure is used we
|
|
output pure output, with no changes to be compatible with Outlook. */
|
|
gboolean VzicPureOutput = FALSE;
|
|
|
|
gboolean VzicDumpOutput = FALSE;
|
|
gboolean VzicDumpChanges = FALSE;
|
|
gboolean VzicDumpZoneNamesAndCoords = TRUE;
|
|
gboolean VzicDumpZoneTranslatableStrings= TRUE;
|
|
gboolean VzicNoRRules = FALSE;
|
|
gboolean VzicNoRDates = FALSE;
|
|
char* VzicOutputDir = "zoneinfo";
|
|
char* VzicUrlPrefix = NULL;
|
|
char* VzicOlsonDir = OLSON_DIR;
|
|
|
|
GList* VzicTimeZoneNames = NULL;
|
|
|
|
static void convert_olson_file (char *olson_file);
|
|
|
|
static void usage (void);
|
|
|
|
static void free_zone_data (GArray *zone_data);
|
|
static void free_rule_array (gpointer key,
|
|
gpointer value,
|
|
gpointer data);
|
|
static void free_link_data (gpointer key,
|
|
gpointer value,
|
|
gpointer data);
|
|
|
|
|
|
int
|
|
main (int argc,
|
|
char *argv[])
|
|
{
|
|
int i;
|
|
char directory[PATHNAME_BUFFER_SIZE];
|
|
char filename[PATHNAME_BUFFER_SIZE];
|
|
GHashTable *zones_hash;
|
|
|
|
/*
|
|
* Command-Line Option Parsing.
|
|
*/
|
|
for (i = 1; i < argc; i++) {
|
|
/*
|
|
* User Options.
|
|
*/
|
|
|
|
/* --pure: Output the perfect VCALENDAR data, which Outlook won't parse
|
|
as it has problems with certain iCalendar constructs. */
|
|
if (!strcmp (argv[i], "--pure"))
|
|
VzicPureOutput = TRUE;
|
|
|
|
/* --output-dir: specify where to output all the files beneath. The
|
|
default is the current directory. */
|
|
else if (argc > i + 1 && !strcmp (argv[i], "--output-dir"))
|
|
VzicOutputDir = argv[++i];
|
|
|
|
/* --url-prefix: Used as the base for the TZURL property in each
|
|
VTIMEZONE. The default is to not output TZURL properties. */
|
|
else if (argc > i + 1 && !strcmp (argv[i], "--url-prefix")) {
|
|
int length;
|
|
VzicUrlPrefix = argv[++i];
|
|
/* remove the trailing '/' if there is one */
|
|
length = strlen (VzicUrlPrefix);
|
|
if (VzicUrlPrefix[length - 1] == '/')
|
|
VzicUrlPrefix[length - 1] = '\0';
|
|
}
|
|
|
|
else if (argc > i + 1 && !strcmp (argv[i], "--olson-dir")) {
|
|
VzicOlsonDir = argv[++i];
|
|
}
|
|
|
|
/*
|
|
* Debugging Options.
|
|
*/
|
|
|
|
/* --dump: Dump the Rule and Zone data that we parsed from the Olson
|
|
timezone files. This is used to test the parsing code. */
|
|
else if (!strcmp (argv[i], "--dump"))
|
|
VzicDumpOutput = TRUE;
|
|
|
|
/* --dump-changes: Dumps a list of times when each timezone changed,
|
|
and the new local time offset from UTC. */
|
|
else if (!strcmp (argv[i], "--dump-changes"))
|
|
VzicDumpChanges = TRUE;
|
|
|
|
/* --no-rrules: Don't output RRULE properties in the VTIMEZONEs. Instead
|
|
it will just output RDATEs for each year up to a certain year. */
|
|
else if (!strcmp (argv[i], "--no-rrules"))
|
|
VzicNoRRules = TRUE;
|
|
|
|
/* --no-rdates: Don't output multiple RDATEs in a single VTIMEZONE
|
|
component. Instead they will be output separately. */
|
|
else if (!strcmp (argv[i], "--no-rdates"))
|
|
VzicNoRDates = TRUE;
|
|
|
|
else
|
|
usage ();
|
|
}
|
|
|
|
/*
|
|
* Create any necessary directories.
|
|
*/
|
|
ensure_directory_exists (VzicOutputDir);
|
|
|
|
if (VzicDumpOutput) {
|
|
/* Create the directories for the dump output, if they don't exist. */
|
|
sprintf (directory, "%s/ZonesVzic", VzicOutputDir);
|
|
ensure_directory_exists (directory);
|
|
sprintf (directory, "%s/RulesVzic", VzicOutputDir);
|
|
ensure_directory_exists (directory);
|
|
}
|
|
|
|
if (VzicDumpChanges) {
|
|
/* Create the directory for the changes output, if it doesn't exist. */
|
|
sprintf (directory, "%s/ChangesVzic", VzicOutputDir);
|
|
ensure_directory_exists (directory);
|
|
}
|
|
|
|
/*
|
|
* Convert the Olson timezone files.
|
|
*/
|
|
convert_olson_file ("africa");
|
|
convert_olson_file ("antarctica");
|
|
convert_olson_file ("asia");
|
|
convert_olson_file ("australasia");
|
|
convert_olson_file ("europe");
|
|
convert_olson_file ("northamerica");
|
|
convert_olson_file ("southamerica");
|
|
|
|
/* These are backwards-compatability and weird stuff. */
|
|
#if 0
|
|
convert_olson_file ("backward");
|
|
convert_olson_file ("etcetera");
|
|
convert_olson_file ("leapseconds");
|
|
convert_olson_file ("pacificnew");
|
|
convert_olson_file ("solar87");
|
|
convert_olson_file ("solar88");
|
|
convert_olson_file ("solar89");
|
|
#endif
|
|
|
|
/* This doesn't really do anything and it messes up vzic-dump.pl so we
|
|
don't bother. */
|
|
#if 0
|
|
convert_olson_file ("factory");
|
|
#endif
|
|
|
|
/* This is old System V stuff, which we don't currently support since it
|
|
uses 'min' as a Rule FROM value which messes up our algorithm, making
|
|
it too slow and use too much memory. */
|
|
#if 0
|
|
convert_olson_file ("systemv");
|
|
#endif
|
|
|
|
/* Output the timezone names and coordinates in a zone.tab file, and
|
|
the translatable strings to feed to gettext. */
|
|
if (VzicDumpZoneNamesAndCoords) {
|
|
sprintf (filename, "%s/zone.tab", VzicOlsonDir);
|
|
zones_hash = parse_zone_tab (filename);
|
|
|
|
dump_time_zone_names (VzicTimeZoneNames, VzicOutputDir, zones_hash);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
convert_olson_file (char *olson_file)
|
|
{
|
|
char input_filename[PATHNAME_BUFFER_SIZE];
|
|
GArray *zone_data;
|
|
GHashTable *rule_data, *link_data;
|
|
char dump_filename[PATHNAME_BUFFER_SIZE];
|
|
ZoneData *zone;
|
|
int i, max_until_year;
|
|
|
|
sprintf (input_filename, "%s/%s", VzicOlsonDir, olson_file);
|
|
|
|
parse_olson_file (input_filename, &zone_data, &rule_data, &link_data,
|
|
&max_until_year);
|
|
|
|
if (VzicDumpOutput) {
|
|
sprintf (dump_filename, "%s/ZonesVzic/%s", VzicOutputDir, olson_file);
|
|
dump_zone_data (zone_data, dump_filename);
|
|
|
|
sprintf (dump_filename, "%s/RulesVzic/%s", VzicOutputDir, olson_file);
|
|
dump_rule_data (rule_data, dump_filename);
|
|
}
|
|
|
|
output_vtimezone_files (VzicOutputDir, zone_data, rule_data, link_data,
|
|
max_until_year);
|
|
|
|
free_zone_data (zone_data);
|
|
g_hash_table_foreach (rule_data, free_rule_array, NULL);
|
|
g_hash_table_destroy (rule_data);
|
|
g_hash_table_foreach (link_data, free_link_data, NULL);
|
|
g_hash_table_destroy (link_data);
|
|
}
|
|
|
|
|
|
static void
|
|
usage (void)
|
|
{
|
|
fprintf (stderr, "Usage: vzic [--dump] [--dump-changes] [--no-rrules] [--no-rdates] [--pure] [--output-dir <directory>] [--url-prefix <url>] [--olson-dir <directory>]\n");
|
|
|
|
exit (1);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Functions to free the data structures.
|
|
*/
|
|
|
|
static void
|
|
free_zone_data (GArray *zone_data)
|
|
{
|
|
ZoneData *zone;
|
|
ZoneLineData *zone_line;
|
|
int i, j;
|
|
|
|
for (i = 0; i < zone_data->len; i++) {
|
|
zone = &g_array_index (zone_data, ZoneData, i);
|
|
|
|
g_free (zone->zone_name);
|
|
|
|
for (j = 0; j < zone->zone_line_data->len; j++) {
|
|
zone_line = &g_array_index (zone->zone_line_data, ZoneLineData, j);
|
|
|
|
g_free (zone_line->rules);
|
|
g_free (zone_line->format);
|
|
}
|
|
|
|
g_array_free (zone->zone_line_data, TRUE);
|
|
}
|
|
|
|
g_array_free (zone_data, TRUE);
|
|
}
|
|
|
|
|
|
static void
|
|
free_rule_array (gpointer key,
|
|
gpointer value,
|
|
gpointer data)
|
|
{
|
|
char *name = key;
|
|
GArray *rule_array = value;
|
|
RuleData *rule;
|
|
int i;
|
|
|
|
for (i = 0; i < rule_array->len; i++) {
|
|
rule = &g_array_index (rule_array, RuleData, i);
|
|
|
|
if (!rule->is_shallow_copy) {
|
|
g_free (rule->type);
|
|
g_free (rule->letter_s);
|
|
}
|
|
}
|
|
|
|
g_array_free (rule_array, TRUE);
|
|
|
|
g_free (name);
|
|
}
|
|
|
|
|
|
static void
|
|
free_link_data (gpointer key,
|
|
gpointer value,
|
|
gpointer data)
|
|
{
|
|
GList *link = data;
|
|
|
|
g_free (key);
|
|
|
|
while (link) {
|
|
g_free (link->data);
|
|
link = link->next;
|
|
}
|
|
|
|
g_list_free (data);
|
|
}
|
|
|