/* * 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. */ /* * These functions are for dumping all the parsed Zones and Rules to * files, to be compared with the output of vzic-dump.pl to check our parsing * code is OK. Some of the functions are also used for producing debugging * output. */ #include #include #include #include "vzic.h" #include "vzic-dump.h" static void dump_add_rule (char *name, GArray *rule_array, GPtrArray *name_array); static int dump_compare_strings (const void *arg1, const void *arg2); void dump_zone_data (GArray *zone_data, char *filename) { static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; FILE *fp; ZoneData *zone; ZoneLineData *zone_line; int i, j; gboolean output_month, output_day, output_time; fp = fopen (filename, "w"); if (!fp) { fprintf (stderr, "Couldn't create file: %s\n", filename); exit (1); } for (i = 0; i < zone_data->len; i++) { zone = &g_array_index (zone_data, ZoneData, i); fprintf (fp, "Zone\t%s\t", zone->zone_name); for (j = 0; j < zone->zone_line_data->len; j++) { zone_line = &g_array_index (zone->zone_line_data, ZoneLineData, j); if (j != 0) fprintf (fp, "\t\t\t"); fprintf (fp, "%s\t", dump_time (zone_line->stdoff_seconds, TIME_WALL, FALSE)); if (zone_line->rules) fprintf (fp, "%s\t", zone_line->rules); else if (zone_line->save_seconds != 0) fprintf (fp, "%s\t", dump_time (zone_line->save_seconds, TIME_WALL, FALSE)); else fprintf (fp, "-\t"); fprintf (fp, "%s\t", zone_line->format ? zone_line->format : "-"); if (zone_line->until_set) { fprintf (fp, "%s\t", dump_year (zone_line->until_year)); output_month = output_day = output_time = FALSE; if (zone_line->until_time_code != TIME_WALL || zone_line->until_time_seconds != 0) output_month = output_day = output_time = TRUE; else if (zone_line->until_day_code != DAY_SIMPLE || zone_line->until_day_number != 1) output_month = output_day = TRUE; else if (zone_line->until_month != 0) output_month = TRUE; if (output_month) fprintf (fp, "%s", months[zone_line->until_month]); fprintf (fp, "\t"); if (output_day) fprintf (fp, "%s", dump_day_coded (zone_line->until_day_code, zone_line->until_day_number, zone_line->until_day_weekday)); fprintf (fp, "\t"); if (output_time) fprintf (fp, "%s", dump_time (zone_line->until_time_seconds, zone_line->until_time_code, FALSE)); } else { fprintf (fp, "\t\t\t"); } fprintf (fp, "\n"); } } fclose (fp); } void dump_rule_data (GHashTable *rule_data, char *filename) { FILE *fp; GPtrArray *name_array; GArray *rule_array; int i; char *name; fp = fopen (filename, "w"); if (!fp) { fprintf (stderr, "Couldn't create file: %s\n", filename); exit (1); } /* We need to sort the rules by their names, so they are in the same order as the Perl output. So we place all the names in a temporary GPtrArray, sort it, then output them. */ name_array = g_ptr_array_new (); g_hash_table_foreach (rule_data, (GHFunc) dump_add_rule, name_array); qsort (name_array->pdata, name_array->len, sizeof (char*), dump_compare_strings); for (i = 0; i < name_array->len; i++) { name = g_ptr_array_index (name_array, i); rule_array = g_hash_table_lookup (rule_data, name); if (!rule_array) { fprintf (stderr, "Couldn't access rules: %s\n", name); exit (1); } dump_rule_array (name, rule_array, fp); } g_ptr_array_free (name_array, TRUE); fclose (fp); } static void dump_add_rule (char *name, GArray *rule_array, GPtrArray *name_array) { g_ptr_array_add (name_array, name); } static int dump_compare_strings (const void *arg1, const void *arg2) { char **a, **b; a = (char**) arg1; b = (char**) arg2; return strcmp (*a, *b); } void dump_rule_array (char *name, GArray *rule_array, FILE *fp) { static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; RuleData *rule; int i; #if 0 fprintf (fp, "\n# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S"); #endif for (i = 0; i < rule_array->len; i++) { rule = &g_array_index (rule_array, RuleData, i); fprintf (fp, "Rule\t%s\t%s\t", name, dump_year (rule->from_year)); if (rule->to_year == rule->from_year) fprintf (fp, "only\t"); else fprintf (fp, "%s\t", dump_year (rule->to_year)); fprintf (fp, "%s\t", rule->type ? rule->type : "-"); fprintf (fp, "%s\t", months[rule->in_month]); fprintf (fp, "%s\t", dump_day_coded (rule->on_day_code, rule->on_day_number, rule->on_day_weekday)); fprintf (fp, "%s\t", dump_time (rule->at_time_seconds, rule->at_time_code, FALSE)); fprintf (fp, "%s\t", dump_time (rule->save_seconds, TIME_WALL, TRUE)); fprintf (fp, "%s", rule->letter_s ? rule->letter_s : "-"); fprintf (fp, "\n"); } } char* dump_time (int seconds, TimeCode time_code, gboolean use_zero) { static char buffer[256], *sign; int hours, minutes; char *code; if (time_code == TIME_STANDARD) code = "s"; else if (time_code == TIME_UNIVERSAL) code = "u"; else code = ""; if (seconds < 0) { seconds = -seconds; sign = "-"; } else { sign = ""; } hours = seconds / 3600; minutes = (seconds % 3600) / 60; seconds = seconds % 60; if (use_zero && hours == 0 && minutes == 0 && seconds == 0) return "0"; else if (seconds == 0) sprintf (buffer, "%s%i:%02i%s", sign, hours, minutes, code); else sprintf (buffer, "%s%i:%02i:%02i%s", sign, hours, minutes, seconds, code); return buffer; } char* dump_day_coded (DayCode day_code, int day_number, int day_weekday) { static char buffer[256]; static char *weekdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; switch (day_code) { case DAY_SIMPLE: sprintf (buffer, "%i", day_number); break; case DAY_WEEKDAY_ON_OR_AFTER: sprintf (buffer, "%s>=%i", weekdays[day_weekday], day_number); break; case DAY_WEEKDAY_ON_OR_BEFORE: sprintf (buffer, "%s<=%i", weekdays[day_weekday], day_number); break; case DAY_LAST_WEEKDAY: sprintf (buffer, "last%s", weekdays[day_weekday]); break; default: fprintf (stderr, "Invalid day code: %i\n", day_code); exit (1); } return buffer; } char* dump_year (int year) { static char buffer[256]; if (year == YEAR_MINIMUM) return "min"; if (year == YEAR_MAXIMUM) return "max"; sprintf (buffer, "%i", year); return buffer; } void dump_time_zone_names (GList *names, char *output_dir, GHashTable *zones_hash) { char filename[PATHNAME_BUFFER_SIZE], *zone_name, *zone_name_in_hash = NULL; char strings_filename[PATHNAME_BUFFER_SIZE]; FILE *fp, *strings_fp = NULL; GList *elem; ZoneDescription *zone_desc; sprintf (filename, "%s/zones.tab", output_dir); sprintf (strings_filename, "%s/zones.h", output_dir); fp = fopen (filename, "w"); if (!fp) { fprintf (stderr, "Couldn't create file: %s\n", filename); exit (1); } if (VzicDumpZoneTranslatableStrings) { strings_fp = fopen (strings_filename, "w"); if (!strings_fp) { fprintf (stderr, "Couldn't create file: %s\n", strings_filename); exit (1); } } names = g_list_sort (names, (GCompareFunc) strcmp); elem = names; while (elem) { zone_name = (char*) elem->data; zone_desc = g_hash_table_lookup (zones_hash, zone_name); /* SPECIAL CASES: These timezones are links from other zones and are almost exactly the same - they are basically there so users can find them a bit easier. But they don't have entries in the zone.tab file, so we use the entry from the timezone linked from. */ if (!zone_desc) { if (!strcmp (zone_name, "America/Indiana/Indianapolis")) zone_name_in_hash = "America/Indianapolis"; else if (!strcmp (zone_name, "America/Kentucky/Louisville")) zone_name_in_hash = "America/Louisville"; else if (!strcmp (zone_name, "Asia/Istanbul")) zone_name_in_hash = "Europe/Istanbul"; else if (!strcmp (zone_name, "Europe/Nicosia")) zone_name_in_hash = "Asia/Nicosia"; if (zone_name_in_hash) zone_desc = g_hash_table_lookup (zones_hash, zone_name_in_hash); } if (zone_desc) { fprintf (fp, "%+04i%02i%02i %+04i%02i%02i %s\n", zone_desc->latitude[0], zone_desc->latitude[1], zone_desc->latitude[2], zone_desc->longitude[0], zone_desc->longitude[1], zone_desc->longitude[2], zone_name); } else { g_print ("Zone description not found for: %s\n", zone_name); fprintf (fp, "%s\n", zone_name); } if (VzicDumpZoneTranslatableStrings) { #if 0 char zone_name_buffer[1024], *src, *dest; for (src = zone_name, dest = zone_name_buffer; *src; src++, dest++) *dest = (*src == '_') ? ' ' : *src; *dest = '\0'; #endif fprintf (strings_fp, "N_(\"%s\");\n", zone_name); } elem = elem->next; } fclose (fp); if (VzicDumpZoneTranslatableStrings) fclose (strings_fp); }