/* * 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 * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #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 ] [--url-prefix ] [--olson-dir ]\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); }