summaryrefslogtreecommitdiffstats
path: root/libkcal/libical/vzic-1.3/test-vzic.c
diff options
context:
space:
mode:
Diffstat (limited to 'libkcal/libical/vzic-1.3/test-vzic.c')
-rw-r--r--libkcal/libical/vzic-1.3/test-vzic.c422
1 files changed, 422 insertions, 0 deletions
diff --git a/libkcal/libical/vzic-1.3/test-vzic.c b/libkcal/libical/vzic-1.3/test-vzic.c
new file mode 100644
index 000000000..9da1abe1b
--- /dev/null
+++ b/libkcal/libical/vzic-1.3/test-vzic.c
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+/*
+ * test-vzic.c - test vzic + libical against mktime() and friends.
+ *
+ * Note that when we output VCALENDAR data compatible with Outlook the
+ * results aren't all correct.
+ *
+ * We have to modify some RRULEs which makes these timezones incorrect:
+ *
+ * Africa/Cairo
+ * America/Godthab
+ * America/Santiago
+ * Antarctica/Palmer
+ * Asia/Baghdad
+ * Asia/Damascus
+ * Asia/Jerusalem
+ *
+ * Also, we can only output one RDATE or a pair of RRULEs which may make some
+ * other timezones incorrect sometimes (e.g. if they change).
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <ical.h>
+/*#include <evolution/ical.h>*/
+
+#define CHANGES_MAX_YEAR 2030
+
+/* These are the years between which we test against the Unix timezone
+ functions, inclusive. When using 'vzic --pure' you can test the full
+ range from 1970 to 2037 and it should match against mktime() etc.
+ (assuming you are using the same Olson timezone data for both).
+
+ But when using VTIMEZONE's that are compatible with Outlook, it is only
+ worth testing times in the future. There will be lots of differences in
+ the past, since we can't include any historical changes in the files. */
+#if 1
+#define DUMP_START_YEAR 2003
+#define DUMP_END_YEAR 2037
+#else
+#define DUMP_START_YEAR 1970
+#define DUMP_END_YEAR 2037
+#endif
+
+/* The maximum size of any complete pathname. */
+#define PATHNAME_BUFFER_SIZE 1024
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+int VzicDumpChanges = FALSE;
+
+/* We output beneath the current directory for now. */
+char *directory = "test-output";
+
+static void usage (void);
+static int parse_zone_name (char *name,
+ char **directory,
+ char **subdirectory,
+ char **filename);
+static void ensure_directory_exists (char *directory);
+static void dump_local_times (icaltimezone *zone,
+ FILE *fp);
+
+
+int main(int argc, char* argv[])
+{
+ icalarray *zones;
+ icaltimezone *zone;
+ char *zone_directory, *zone_subdirectory, *zone_filename, *location;
+ char output_directory[PATHNAME_BUFFER_SIZE];
+ char filename[PATHNAME_BUFFER_SIZE];
+ FILE *fp;
+ int i;
+ int skipping = TRUE;
+
+ /*
+ * Command-Line Option Parsing.
+ */
+ for (i = 1; i < argc; i++) {
+ /* --dump-changes: Dumps a list of times when each timezone changed,
+ and the new local time offset from UTC. */
+ if (!strcmp (argv[i], "--dump-changes"))
+ VzicDumpChanges = TRUE;
+
+ else
+ usage ();
+ }
+
+
+ zones = icaltimezone_get_builtin_timezones ();
+
+ ensure_directory_exists (directory);
+
+ for (i = 0; i < zones->num_elements; i++) {
+ zone = icalarray_element_at (zones, i);
+
+ location = icaltimezone_get_location (zone);
+
+#if 0
+ /* Use this to start at a certain zone. */
+ if (skipping && strcmp (location, "America/Boise"))
+ continue;
+#endif
+
+ skipping = FALSE;
+
+ /* Use this to only output data for certain timezones. */
+#if 0
+ if (strcmp (location, "America/Cancun")
+ && strcmp (location, "Asia/Baku")
+ && strcmp (location, "Asia/Nicosia")
+ && strcmp (location, "Asia/Novosibirsk")
+ && strcmp (location, "Asia/Samarkand")
+ && strcmp (location, "Asia/Tashkent")
+ && strcmp (location, "Asia/Tbilisi")
+ && strcmp (location, "Asia/Yerevan")
+ && strcmp (location, "Australia/Broken_Hill")
+ && strcmp (location, "Europe/Simferopol")
+ && strcmp (location, "Europe/Tallinn")
+ && strcmp (location, "Europe/Zaporozhye")
+ )
+ continue;
+#endif
+
+#if 0
+ printf ("%s\n", location);
+#endif
+
+ parse_zone_name (location, &zone_directory, &zone_subdirectory,
+ &zone_filename);
+
+ sprintf (output_directory, "%s/%s", directory, zone_directory);
+ ensure_directory_exists (output_directory);
+ sprintf (filename, "%s/%s", output_directory, zone_filename);
+
+ if (zone_subdirectory) {
+ sprintf (output_directory, "%s/%s/%s", directory, zone_directory,
+ zone_subdirectory);
+ ensure_directory_exists (output_directory);
+ sprintf (filename, "%s/%s", output_directory, zone_filename);
+ }
+
+ fp = fopen (filename, "w");
+ if (!fp) {
+ fprintf (stderr, "Couldn't create file: %s\n", filename);
+ exit (1);
+ }
+
+ /* We can run 2 different tests - output all changes for each zone, or
+ test against mktime()/localtime(). Should have a command-line option
+ or something. */
+ if (VzicDumpChanges)
+ icaltimezone_dump_changes (zone, CHANGES_MAX_YEAR, fp);
+ else
+ dump_local_times (zone, fp);
+
+ if (ferror (fp)) {
+ fprintf (stderr, "Error writing file: %s\n", filename);
+ exit (1);
+ }
+
+ fclose (fp);
+ }
+
+ return 0;
+}
+
+
+static void
+usage (void)
+{
+ fprintf (stderr, "Usage: test-vzic [--dump-changes]\n");
+
+ exit (1);
+}
+
+
+/* This checks that the Zone name only uses the characters in [-+_/a-zA-Z0-9],
+ and outputs a warning if it isn't. */
+static int
+parse_zone_name (char *name,
+ char **directory,
+ char **subdirectory,
+ char **filename)
+{
+ static int invalid_zone_num = 1;
+
+ char *p, ch, *first_slash_pos = NULL, *second_slash_pos = NULL;
+ int invalid = FALSE;
+
+ for (p = name; (ch = *p) != 0; p++) {
+ if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')
+ && (ch < '0' || ch > '9') && ch != '/' && ch != '_'
+ && ch != '-' && ch != '+') {
+ fprintf (stderr, "Warning: Unusual Zone name: %s\n", name);
+ invalid = TRUE;
+ break;
+ }
+
+ if (ch == '/') {
+ if (!first_slash_pos) {
+ first_slash_pos = p;
+ } else if (!second_slash_pos) {
+ second_slash_pos = p;
+ } else {
+ fprintf (stderr, "Warning: More than 2 '/' characters in Zone name: %s\n", name);
+ invalid = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!first_slash_pos) {
+ fprintf (stderr, "No '/' character in Zone name: %s. Skipping.\n", name);
+ return FALSE;
+ }
+
+ if (invalid) {
+ fprintf (stderr, "Invalid zone name: %s\n", name);
+ exit (0);
+ } else {
+ *first_slash_pos = '\0';
+ *directory = icalmemory_strdup (name);
+ *first_slash_pos = '/';
+
+ if (second_slash_pos) {
+ *second_slash_pos = '\0';
+ *subdirectory = icalmemory_strdup (first_slash_pos + 1);
+ *second_slash_pos = '/';
+
+ *filename = icalmemory_strdup (second_slash_pos + 1);
+ } else {
+ *subdirectory = NULL;
+ *filename = icalmemory_strdup (first_slash_pos + 1);
+ }
+ }
+}
+
+
+static void
+ensure_directory_exists (char *directory)
+{
+ struct stat filestat;
+
+ if (stat (directory, &filestat) != 0) {
+ /* If the directory doesn't exist, try to create it. */
+ if (errno == ENOENT) {
+ if (mkdir (directory, 0777) != 0) {
+ fprintf (stderr, "Can't create directory: %s\n", directory);
+ exit (1);
+ }
+ } else {
+ fprintf (stderr, "Error calling stat() on directory: %s\n", directory);
+ exit (1);
+ }
+ } else if (!S_ISDIR (filestat.st_mode)) {
+ fprintf (stderr, "Can't create directory, already exists: %s\n",
+ directory);
+ exit (1);
+ }
+}
+
+
+static void
+dump_local_times (icaltimezone *zone, FILE *fp)
+{
+ static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ icaltimezone *utc_timezone;
+ struct icaltimetype tt, tt_copy;
+ struct tm tm, local_tm;
+ time_t t;
+ char tzstring[256], *location;
+ int last_year_output = 0;
+ int total_error = 0, total_error2 = 0;
+
+ utc_timezone = icaltimezone_get_utc_timezone ();
+
+ /* This is our UTC time that we will use to iterate over the period. */
+ tt.year = DUMP_START_YEAR;
+ tt.month = 1;
+ tt.day = 1;
+ tt.hour = 0;
+ tt.minute = 0;
+ tt.second = 0;
+ tt.is_utc = 0;
+ tt.is_date = 0;
+ tt.zone = "";
+
+ tm.tm_year = tt.year - 1900;
+ tm.tm_mon = tt.month - 1;
+ tm.tm_mday = tt.day;
+ tm.tm_hour = tt.hour;
+ tm.tm_min = tt.minute;
+ tm.tm_sec = tt.second;
+ tm.tm_isdst = -1;
+
+ /* Convert it to a time_t by saying it is in UTC. */
+ putenv ("TZ=UTC");
+ t = mktime (&tm);
+
+ location = icaltimezone_get_location (zone);
+ sprintf (tzstring, "TZ=%s", location);
+
+ /*printf ("Zone: %s\n", location);*/
+ putenv (tzstring);
+
+ /* Loop around converting the UTC time to local time, outputting it, and
+ then adding on 15 minutes to the UTC time. */
+ while (tt.year <= DUMP_END_YEAR) {
+ if (tt.year > last_year_output) {
+ last_year_output = tt.year;
+#if 0
+ printf (" %i\n", last_year_output);
+ fprintf (fp, " %i\n", last_year_output);
+#endif
+ }
+
+#if 1
+ /* First use the Unix functions. */
+ /* Now convert it to a local time in the given timezone. */
+ local_tm = *localtime (&t);
+#endif
+
+#if 1
+ /* Now use libical. */
+ tt_copy = tt;
+ icaltimezone_convert_time (&tt_copy, utc_timezone, zone);
+#endif
+
+#if 1
+ if (local_tm.tm_year + 1900 != tt_copy.year
+ || local_tm.tm_mon + 1 != tt_copy.month
+ || local_tm.tm_mday != tt_copy.day
+ || local_tm.tm_hour != tt_copy.hour
+ || local_tm.tm_min != tt_copy.minute
+ || local_tm.tm_sec != tt_copy.second) {
+
+ /* The error format is:
+
+ ERROR: Original-UTC-Time Local-Time-From-mktime Local-Time-From-Libical
+
+ */
+
+ total_error++;
+
+ fprintf (fp, "ERROR:%2i %s %04i %2i:%02i:%02i UTC",
+ tt.day, months[tt.month - 1], tt.year,
+ tt.hour, tt.minute, tt.second);
+ fprintf (fp, " ->%2i %s %04i %2i:%02i:%02i",
+ local_tm.tm_mday, months[local_tm.tm_mon],
+ local_tm.tm_year + 1900,
+ local_tm.tm_hour, local_tm.tm_min, local_tm.tm_sec);
+ fprintf (fp, " Us:%2i %s %04i %2i:%02i:%02i\n",
+ tt_copy.day, months[tt_copy.month - 1], tt_copy.year,
+ tt_copy.hour, tt_copy.minute, tt_copy.second);
+ }
+#endif
+
+ /* Now convert it back, and check we get the original time. */
+ icaltimezone_convert_time (&tt_copy, zone, utc_timezone);
+ if (tt.year != tt_copy.year
+ || tt.month != tt_copy.month
+ || tt.day != tt_copy.day
+ || tt.hour != tt_copy.hour
+ || tt.minute != tt_copy.minute
+ || tt.second != tt_copy.second) {
+
+ total_error2++;
+
+ fprintf (fp, "ERROR 2: %2i %s %04i %2i:%02i:%02i UTC",
+ tt.day, months[tt.month - 1], tt.year,
+ tt.hour, tt.minute, tt.second);
+ fprintf (fp, " Us:%2i %s %04i %2i:%02i:%02i UTC\n",
+ tt_copy.day, months[tt_copy.month - 1], tt_copy.year,
+ tt_copy.hour, tt_copy.minute, tt_copy.second);
+ }
+
+
+ /* Increment the time. */
+ icaltime_adjust (&tt, 0, 0, 15, 0);
+
+ /* We assume leap seconds are not included in time_t values, which should
+ be true on POSIX systems. */
+ t += 15 * 60;
+ }
+
+ printf ("Zone: %40s Errors: %i (%i)\n", icaltimezone_get_location (zone),
+ total_error, total_error2);
+}