CUBRID Engine  latest
tz_compile.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * tz_compile.c : Functions for parsing and compiling IANA's timezone files
21  */
22 #include "config.h"
23 #include <stdio.h>
24 #include <assert.h>
25 
26 #include "tz_support.h"
27 
28 #include "authenticate.h"
29 #include "porting.h"
30 #include "byte_order.h"
31 #include "utility.h"
32 #include "db_date.h"
33 #include "environment_variable.h"
34 #include "chartype.h"
35 #include "error_manager.h"
36 
37 #include "memory_alloc.h"
38 
39 #include "tz_compile.h"
40 #include "xml_parser.h"
41 #include "crypt_opfunc.h"
42 #include "db_query.h"
43 #include "dbtype.h"
44 
45 #if defined (SA_MODE)
46 #include "db.h"
47 #endif /* SA_MODE */
48 
49 #if defined (SUPPRESS_STRLEN_WARNING)
50 #define strlen(s1) ((int) strlen(s1))
51 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
52 
53 #define TZ_FILENAME_MAX_LEN 17
54 #define TZ_MAX_LINE_LEN 512
55 #define TZ_OFFRULE_PREFIX_TAB_COUNT 3
56 
57 #define TZ_COORDINATES_MAX_SIZE 16
58 #define TZ_COMMENTS_MAX_SIZE 92
59 #define TZ_RULE_LETTER_ABBREV_MAX_SIZE 8
60 #define TZ_RULE_TYPE_MAX_SIZE 4
61 
62 #if defined(_WIN32) || defined(WINDOWS) || defined(WIN64)
63 #define PATH_PARTIAL_TIMEZONES_FILE "timezones\\tzlib\\timezones.c"
64 #else
65 #define PATH_PARTIAL_TIMEZONES_FILE "timezones/tzlib/timezones.c"
66 #endif
67 
68 /*
69  * Data structures
70  */
71 typedef enum
72 {
73  /* file types */
74  TZF_COUNTRIES = 0, /* tabbed country list (ISO3166) */
75  TZF_ZONES, /* tabbed time zones */
76  TZF_RULES, /* daylight saving rules */
77  TZF_BACKWARD, /* time zone aliases for backward compatibility */
78 #if defined(WINDOWS)
79  TZF_LEAP, /* leap data (leap seconds) */
80  TZF_WINDOWS_IANA_ZONES_MAP
81 #else
82  TZF_LEAP
83 #endif
84 } TZ_FILE_TYPE;
85 
88 {
89  TZ_FILE_TYPE type; /* type of tz file contents */
90  char name[TZ_FILENAME_MAX_LEN]; /* file name */
91 };
92 
93 /* The list of files from IANA's timezone database, in alphabetical order,
94  * with attached description flags. This list is necessary for detecting file
95  * addition or removal to/from future TZ releases by IANA. The reference for
96  * building this list is IANA's tzdata2013b.tar.gz, released on 11 March 2013.
97  * Visit http://www.iana.org/time-zones for the latest release.
98  * NOTE: the array below is sorted by type. This order is used in
99  * timezone_data_load(), so it must be preserved.
100  */
101 static const TZ_FILE_DESCRIPTOR tz_Files[] = {
102  {TZF_COUNTRIES, "iso3166.tab"},
103  {TZF_ZONES, "zone.tab"},
104  {TZF_RULES, "africa"},
105  {TZF_RULES, "antarctica"},
106  {TZF_RULES, "asia"},
107  {TZF_RULES, "australasia"},
108  {TZF_RULES, "europe"},
109  {TZF_RULES, "northamerica"},
110  {TZF_RULES, "southamerica"},
111  {TZF_RULES, "etcetera"},
112  {TZF_RULES, "pacificnew"},
113  {TZF_BACKWARD, "backward"},
114  {TZF_LEAP, "leapseconds"},
115 #if defined(WINDOWS)
116  {TZF_LEAP, "leapseconds"},
117  {TZF_WINDOWS_IANA_ZONES_MAP, "windowsZones.xml"}
118 #else
119  {TZF_LEAP, "leapseconds"}
120 #endif
121 };
122 
123 static int tz_File_count = DIM (tz_Files);
124 
127 {
128  int id; /* this is not read, but assigned after reading all tz data */
130  char full_name[TZ_COUNTRY_NAME_SIZE];
131  bool is_used;
132 };
133 
134 typedef struct tz_raw_link TZ_RAW_LINK;
136 {
138  char alias[TZ_GENERIC_NAME_SIZE];
139  int zone_id; /* this is not read, but assigned after reading all tz data */
140 };
141 
144 {
145  int gmt_off; /* time offset from UTC, in seconds */
146  unsigned short until_year;
147  unsigned char until_mon; /* 0 - 11 */
148  unsigned char until_day; /* 0 - 27,30 */
149  unsigned char until_hour;
150  unsigned char until_min;
151  unsigned char until_sec;
152  char ds_ruleset_name[TZ_DS_RULESET_NAME_SIZE];
153  char format[TZ_MAX_FORMAT_SIZE];
154  TZ_TIME_TYPE until_time_type; /* type for until: standard, wall, UTC */
155  TZ_UNTIL_FLAG until_flag; /* true if no ending time is specified; false otherwise */
156 };
157 
160 {
163  int id; /* this is not read, but assigned after reading all tz data */
164  int country_id; /* parent country ID */
166  char **aliases;
167  char clone_of[TZ_GENERIC_NAME_SIZE]; /* timezone from where to use rules and settings */
170  char coordinates[TZ_COORDINATES_MAX_SIZE];
171  char full_name[TZ_GENERIC_NAME_SIZE];
172  char comments[TZ_COMMENTS_MAX_SIZE];
173 };
174 
175 /* TZ_DS_RULE is the representation of a daylight saving rule and tells
176  * when and how the DS event occurs */
179 {
180  short from_year;
181  short to_year; /* TZ_MAX_YEAR if column value is "max" e.g. up to now */
182  char type[TZ_RULE_TYPE_MAX_SIZE]; /* always '-'; kept for possible future extensions */
183  unsigned char in_month; /* month when the daylight saving event occurs valid values : 0 - 11 */
184  TZ_DS_CHANGE_ON change_on; /* day of month, fixed or relative */
185  int at_time; /* time when DS event occurs */
186  TZ_TIME_TYPE at_time_type; /* type for at_time: local, absolute etc. */
187  int save_time; /* amount of time saved, in seconds */
188  /* letter(s) to be used in the time zone string ID */
189  char letter_abbrev[TZ_RULE_LETTER_ABBREV_MAX_SIZE];
190 };
191 
194 {
198  bool is_used;
199 };
200 
203 {
205  char current_file[PATH_MAX];
206 };
207 
208 /*
209  * TZ_RAW_DATA is a structure for holding the information read from the files
210  * found in IANA's timezone database. After fully loading and interpreting the
211  * data, time zone information will be processed, optimized and moved to a new
212  * structure (TZ_DATA) to be used at runtime. (incl. TZ shared library)
213  */
214 typedef struct tz_raw_data TZ_RAW_DATA;
216 {
228 };
229 
232 {
234  int len;
236 };
237 
238 #define TZ_CAL_ABBREV_SIZE 4
239 static const char MONTH_NAMES_ABBREV[TZ_MON_COUNT][TZ_CAL_ABBREV_SIZE] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
240  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
241 };
243  { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
244 
245 #define STR_SKIP_LEADING_SPACES(str) \
246  while ((str) != NULL && *(str) == ' ') \
247  { \
248  (str)++; \
249  }
250 
251 /*
252  * Time zone errors. For a more flexible error reporting feature, CUBRID's
253  * error codes are not used inside the timezone feature. Instead, internal
254  * custom errors are used, and are handled only in one place (when exiting)
255  */
256 #ifndef NO_ERROR
257 #define NO_ERROR 0
258 #endif
259 
260 #define TZC_ERR_GENERIC -1
261 #define TZC_ERR_INVALID_PACKAGE -2
262 #define TZC_ERR_BAD_TZ_LINK -3
263 #define TZC_ERR_OUT_OF_MEMORY -4
264 #define TZC_ERR_INVALID_VALUE -5
265 #define TZC_ERR_INVALID_TIME -6
266 #define TZC_ERR_ZONE_RULE_UNORDERED -7
267 #define TZC_ERR_INVALID_DATETIME -8
268 #define TZC_ERR_INVALID_DS_RULE -9
269 #define TZC_ERR_CANT_READ_VALUE -10
270 #define TZC_ERR_PARSING_FAILED -11
271 #define TZC_ERR_DS_INVALID_DATE -12
272 #define TZC_ERR_FILE_NOT_ACCESSIBLE -13
273 #define TZC_ERR_INVALID_COUNTRY -14
274 #define TZC_ERR_INVALID_ZONE -15
275 #define TZC_ERR_ADD_ZONE -16
276 #define TZC_ERR_LINKING_TRUE_ZONES -17
277 #define TZC_ERR_LAST_ERROR -18
278 
279 static const char *tzc_Err_messages[] = {
280  /* NO_ERROR */
281  "",
282  /* TZC_ERR_GENERIC */
283  "Error encountered when %s %s!",
284  /* TZC_ERR_INVALID_PACKAGE */
285  "Invalid timezone package! File %s not found in folder %s.",
286  /* TZC_ERR_BAD_TZ_LINK */
287  "Invalid link definition (s1: %s, s2: %s). " "Format error or invalid data encountered.",
288  /* TZC_ERR_OUT_OF_MEMORY */
289  "Memory exhausted when allocating %d items of type '%s'.",
290  /* TZC_ERR_INVALID_VALUE */
291  "Invalid %s. Value %s is empty or invalid.",
292  /* TZC_ERR_INVALID_TIME */
293  "Invalid or empty time value %s found in %s.",
294  /* TZC_ERR_ZONE_RULE_UNORDERED */
295  "Timezone offset rules are not fully sorted. Rule %s is out of order. %s",
296  /* TZC_ERR_INVALID_DATETIME */
297  "Invalid datetime value %s found in %s.",
298  /* TZC_ERR_INVALID_DS_RULE */
299  "Invalid daylight saving rule found: %s %s",
300  /* TZC_ERR_CANT_READ_VALUE */
301  "Unable to read %s value. Context: %s.",
302  /* TZC_ERR_PARSING_FAILED */
303  "Error encountered when parsing %. Context: %s.",
304  /* TZC_ERR_DS_INVALID_DATE */
305  "Invalid %d. The resulting date is not valid in the given context (%s).",
306  /* TZC_ERR_FILE_NOT_ACCESSIBLE */
307  "The file at %s is missing or not accessible for %s.",
308  /* TZC_ERR_INVALID_COUNTRY */
309  "Invalid line for country definition:%s. %s",
310  /* TZC_ERR_INVALID_ZONE */
311  "Invalid line for zone definition. Line: %s. Values: %s",
312  /* TZC_ERR_ADD_ZONE */
313  "Error encountered when adding zone %s %s",
314  /* TZC_ERR_LINKING_TRUE_ZONES */
315  "Error! Found a link between %s and %s, which are fully defined timezones."
316 };
317 
319 
320 extern const char *tz_timezone_names[];
321 extern const TZ_COUNTRY tz_countries[];
322 
323 #define LOG_TZC_SET_CURRENT_CONTEXT(tzd_raw, f, l) \
324  do { \
325  strcpy (tzd_raw->context.current_file, f); \
326  tzd_raw->context.current_line = l; \
327  } while (0)
328 
329 #define TZC_ERR_MSG_MAX_SIZE 512
330 
331 #define TZC_CONTEXT(tzd_raw) (&((tzd_raw)->context))
332 
333 #define TZC_LOG_ERROR_1ARG(context, err_code, s1) \
334  tzc_log_error ((context), (err_code), (s1), "")
335 
336 #define TZC_LOG_ERROR_2ARG(context, err_code, s1, s2) \
337  tzc_log_error ((context), (err_code), (s1), (s2))
338 
339 #define DUPLICATE_STR(a, b) \
340  do { \
341  (a) = strdup((b)); \
342  if((a) == NULL) { \
343  err_status = ER_OUT_OF_VIRTUAL_MEMORY; \
344  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, (size_t) 0); \
345  goto exit; \
346  } \
347 } while (0)
348 
349 #define INIT_COUNTRY(dst, src) \
350  do { \
351  strcpy ((dst)->code, (src)->code); \
352  strcpy ((dst)->full_name, (src)->full_name); \
353  } while (0)
354 
355 #define PRINT_STRING_TO_C_FILE(fp, val, len) \
356  do { \
357  int istr; \
358  fprintf (fp, "\""); \
359  for (istr = 0; istr < len; istr++) \
360  { \
361  fprintf (fp, "\\x%02X", (unsigned char) val[istr]); \
362  } \
363  fprintf (fp, "\""); \
364  } while (0)
365 
366 #define PRINT_STRING_VAR_TO_C_FILE(fp, valname, val) \
367  do { \
368  fprintf (fp, "\n" SHLIB_EXPORT_PREFIX "const char " valname "[] = "); \
369  PRINT_STRING_TO_C_FILE (fp, val, strlen (val)); \
370  fprintf (fp, ";\n"); \
371  } while (0);
372 
373 #define BUF_PUT_INT32(buf,v) \
374  do { \
375  unsigned int nv = htonl(v); \
376  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[3]; \
377  buf = (char *) (buf) + 1; \
378  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[2]; \
379  buf = (char *) (buf) + 1; \
380  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[1]; \
381  buf = (char *) (buf) + 1; \
382  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[0]; \
383  buf = (char *) (buf) + 1; \
384  } while (0)
385 
386 #define BUF_PUT_INT16(buf,v) \
387  do { \
388  unsigned short nv = htons(v); \
389  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[1];\
390  buf = (char *) (buf) + 1; \
391  *((unsigned char *) (buf)) = ((unsigned char *) &nv)[0];\
392  buf = (char *) (buf) + 1; \
393  } while (0)
394 
395 static int tzc_check_new_package_validity (const char *input_folder);
396 static int tzc_load_countries (TZ_RAW_DATA * tzd_raw, const char *input_folder);
397 static int tzc_load_zone_names (TZ_RAW_DATA * tzd_raw, const char *input_folder);
398 static int tzc_load_rule_file (TZ_RAW_DATA * tzd_raw, const int file_index, const char *input_folder);
399 static int tzc_load_backward_zones (TZ_RAW_DATA * tzd_raw, const char *input_folder);
400 static int tzc_load_leap_secs (TZ_RAW_DATA * tzd_raw, const char *input_folder);
401 static int tzc_get_zone (const TZ_RAW_DATA * tzd_raw, const char *zone_name, TZ_RAW_ZONE_INFO ** zone);
402 static int tzc_add_zone (const char *zone, const char *coord, const char *code, const char *comments,
403  TZ_RAW_DATA * tzd_raw, TZ_RAW_ZONE_INFO ** new_zone);
404 static int tzc_add_link (TZ_RAW_DATA * tzd_raw, const char *zone, const char *alias);
405 static int tzc_add_offset_rule (TZ_RAW_ZONE_INFO * zone, char *rule_text);
406 static int tzc_add_leap_sec (TZ_RAW_DATA * tzd_raw, int year, int month, int day, unsigned char hour, unsigned char min,
407  unsigned char sec, bool corr_minus, bool leap_is_rolling);
408 static int tzc_read_time_type (const char *str, const char **next, TZ_TIME_TYPE * time_type);
409 static int tzc_add_ds_rule (TZ_RAW_DATA * tzd_raw, char *rule_text);
410 static int tzc_parse_ds_change_on (TZ_RAW_DS_RULE * dest, const char *str);
411 static bool tzc_is_valid_date (const int day, const int month, const int year_start, const int year_end);
412 static int tzc_get_ds_ruleset_by_name (const TZ_DS_RULESET * ds_rulesets, int ds_ruleset_count, const char *ruleset);
413 
414 static void tzc_free_raw_data (TZ_RAW_DATA * tzd_raw);
415 
416 static int tzc_check_links_raw_data (TZ_RAW_DATA * tzd_raw);
417 static void tzc_sort_raw_data (TZ_RAW_DATA * tzd_raw);
418 static void tzc_index_raw_data (TZ_RAW_DATA * tzd_raw);
419 static int tzc_index_raw_data_w_static (TZ_RAW_DATA * tzd_raw, const TZ_GEN_TYPE mode);
420 static int tzc_index_raw_subdata (TZ_RAW_DATA * tzd_raw, const TZ_GEN_TYPE mode);
421 static int compare_ints (const void *a, const void *b);
422 
423 static int tzc_compile_data (TZ_RAW_DATA * tzd_raw, TZ_DATA * tzd);
424 static int tzc_compile_ds_rules (TZ_RAW_DATA * tzd_raw, TZ_DATA * tzd);
425 
426 static int str_to_offset_rule_until (TZ_RAW_OFFSET_RULE * offset_rule, char *str);
427 static int str_month_to_int (const char *month, int *month_num, const char **str_next);
428 static int str_day_to_int (const char *str_in, int *day_num, const char **str_next);
429 static int str_read_day_var (const char *str, const int month, int *type, int *day, int *bound, const char **str_next);
430 
431 static int comp_func_raw_countries (const void *arg1, const void *arg2);
432 static int comp_func_raw_zones (const void *arg1, const void *arg2);
433 static int comp_func_raw_links (const void *arg1, const void *arg2);
434 static int comp_func_raw_offset_rules (const void *arg1, const void *arg2);
435 static int comp_func_raw_ds_rulesets (const void *arg1, const void *arg2);
436 static int comp_func_raw_ds_rules (const void *arg1, const void *arg2);
437 static int comp_func_tz_names (const void *arg1, const void *arg2);
438 
439 static void print_seconds_as_time_hms_var (int seconds);
440 
441 static void tzc_get_timezones_dot_c_filepath (size_t size, char *timezones_dot_c_file_path);
442 static int tzc_export_timezone_dot_c (const TZ_DATA * tzd, const char *tz_C_filepath);
443 
444 static int tzc_load_raw_data (TZ_RAW_DATA * tzd_raw, const char *input_folder);
445 static int tzc_import_old_data (TZ_RAW_DATA * tzd_raw, const TZ_GEN_TYPE mode);
446 static int tzc_del_unused_raw_data (TZ_RAW_DATA * tzd_raw);
447 static int tzc_index_data (TZ_RAW_DATA * tzd_raw, const TZ_GEN_TYPE mode);
448 static void tzc_free_tz_data (TZ_DATA * tzd, bool full);
449 
450 static void tzc_build_filepath (char *path, size_t size, const char *dir, const char *filename);
451 static void trim_comments_whitespaces (char *str);
452 
453 static int tzc_get_timezone_aliases (const TZ_DATA * tzd, const int zone_id, int **aliases, int *alias_count);
454 static void tzc_dump_one_offset_rule (const TZ_DATA * tzd, const TZ_OFFSET_RULE * offset_rule);
455 static void tzc_dump_ds_ruleset (const TZ_DATA * tzd, const int ruleset_id);
456 
457 static void tzc_log_error (const TZ_RAW_CONTEXT * context, const int code, const char *msg1, const char *msg2);
458 
459 static void tzc_summary (TZ_RAW_DATA * tzd_raw, TZ_DATA * tzd);
460 
461 static int tzc_find_timezone_names (const TZ_DATA * tzd, const char *timezone_name);
462 static int tzc_find_country_names (const TZ_COUNTRY * countries, const int country_count, const char *country_name);
463 static bool comp_ds_rules (const TZ_DS_RULE * rule1, const TZ_DS_RULE * rule2);
464 static bool comp_offset_rules (const TZ_OFFSET_RULE * rule1, const TZ_OFFSET_RULE * rule2);
465 static int copy_offset_rule (TZ_OFFSET_RULE * dst, const TZ_DATA * tzd, const int index);
466 static int init_ds_ruleset (TZ_DS_RULESET * dst_ruleset, const TZ_DATA * tzd, const int index, const int start);
467 static int copy_ds_rule (TZ_DS_RULE * dst, const TZ_DATA * tzd, const int index);
468 static int tz_data_partial_clone (char **timezone_names, TZ_TIMEZONE * timezones, TZ_NAME * names, const TZ_DATA * tzd);
469 static int init_tz_name (TZ_NAME * dst, TZ_NAME * src);
470 #if defined(SA_MODE)
471 static int tzc_extend (TZ_DATA * tzd);
472 static int tzc_update (TZ_DATA * tzd, const char *database_name);
473 #endif
475 static int get_day_of_week_for_raw_rule (const TZ_RAW_DS_RULE * rule, const int year);
476 #if defined (SA_MODE)
477 static int execute_query (const char *str, DB_QUERY_RESULT ** result);
478 #endif /* defined (SA_MODE) */
479 
480 #if defined(WINDOWS)
481 static int comp_func_tz_windows_zones (const void *arg1, const void *arg2);
482 static int xml_start_mapZone (void *data, const char **attr);
483 
484 static int tzc_load_windows_iana_map (TZ_DATA * tz_data, const char *input_folder);
485 
486 XML_ELEMENT_DEF windows_zones_elem_supplementalData = { "supplementalData", 1, NULL,
487  NULL, NULL
488 };
489 
490 XML_ELEMENT_DEF windows_zones_elem_windowsZones = { "supplementalData windowsZones", 2, NULL,
491  NULL, NULL
492 };
493 
494 XML_ELEMENT_DEF windows_zones_elem_mapTimezones = { "supplementalData windowsZones mapTimezones", 3, NULL,
495  NULL, NULL
496 };
497 
498 XML_ELEMENT_DEF windows_zones_elem_mapZone = { "supplementalData windowsZones mapTimezones mapZone", 4,
499  (ELEM_START_FUNC) & xml_start_mapZone,
500  NULL, NULL
501 };
502 
503 XML_ELEMENT_DEF *windows_zones_elements[] = {
504  &windows_zones_elem_supplementalData,
505  &windows_zones_elem_windowsZones,
506  &windows_zones_elem_mapTimezones,
507  &windows_zones_elem_mapZone
508 };
509 #endif
510 
511 /*
512  * tz_build_filepath () - concat a folder path and a file name to obtain a
513  * full file path
514  * Returns:
515  * path(in/out): preallocated string where to store the full file path
516  * size (in): size in bytes of th preallocated string
517  * dir(in): folder part of the output full path
518  * filename(in): file name part of the output full file path
519  */
520 static void
521 tzc_build_filepath (char *path, size_t size, const char *dir, const char *filename)
522 {
523  assert (path != NULL && size > 0);
524  assert (dir != NULL);
525  assert (filename != NULL);
526 
527 #if !defined(WINDOWS)
528  if (snprintf (path, size - 1, "%s/%s", dir, filename) < 0)
529  {
530  assert_release (false);
531  }
532 #else
533  if (snprintf (path, size - 1, "%s\\%s", dir, filename) < 0)
534  {
535  assert_release (false);
536  }
537 #endif
538 }
539 
540 /*
541  * trim_comments_whitespaces() - remove whitespaces and comments found at the
542  * end of a string. In this context, the
543  * whitespaces to be removed are spaces, tabs and
544  * the 0x0a character. Comments are identified as a
545  * substring starting with '#' and stretching until
546  * the end of the string/line.
547  * Returns:
548  * str(in/out): string from where to remove the whitespaces described above.
549  *
550  */
551 static void
553 {
554  int i, str_len = 0;
555  char *sharp = NULL;
556 
557  if (IS_EMPTY_STR (str))
558  {
559  return;
560  }
561 
562  sharp = strchr (str, '#');
563  if (sharp != NULL)
564  {
565  *sharp = 0;
566  }
567 
568  str_len = strlen (str);
569  for (i = str_len - 1; i >= 0 && char_isspace (str[i]); i--)
570  {
571  str[i] = 0;
572  }
573 }
574 
575 /*
576  * tzc_check_new_package_validity() - match the above list of files to the
577  * list of files found in the input folder
578  * Returns: 0(NO_ERROR) if the file lists are the same, TZ_ERR_INVALID_PACKAGE
579  * if the input folder is missing any of the files marked above as
580  * TZ_RULES, TZ_ZONES, TZ_COUNTRIES, TZ_BACKWARD or TZ_LEAP_DATA
581  * input_folder(in): path to the input folder
582  */
583 static int
584 tzc_check_new_package_validity (const char *input_folder)
585 {
586  int err_status = NO_ERROR;
587  FILE *fp;
588  int i;
589  char temp_path[PATH_MAX];
590 
591  for (i = 0; i < tz_File_count && err_status == NO_ERROR; i++)
592  {
593  tzc_build_filepath (temp_path, sizeof (temp_path), input_folder, tz_Files[i].name);
594 
595  fp = fopen_ex (temp_path, "rb");
596  if (fp == NULL)
597  {
598  err_status = TZC_ERR_INVALID_PACKAGE;
599  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_PACKAGE, tz_Files[i].name, input_folder);
600  goto exit;
601  }
602  else
603  {
604  fclose (fp);
605  fp = NULL;
606  }
607  }
608 exit:
609  return err_status;
610 }
611 
612 #if defined (SA_MODE)
613 /*
614  * timezone_compile_data() - loads data from all relevant tz files into
615  * temporary structures, reorganizes & optimizes data
616  * and generates TZ specific files
617  * Returns: NO_ERROR if successful, internal error code otherwise
618  * input_folder(in): path to the input folder containing timezone data
619  * tz_gen_type(in): control flag (type of TZ build/gen to perform)
620  * database_name(in): database name for which to do data migration if an update is necessary, if it is NULL
621  * then data migration will be done for all the databases
622  * timezones_dot_c_filepath(in): path for timezones.c output file. if NULL, it will be saved in default path (in CUBRID install
623  * folder).
624  * checksum(out): new checksum to write in the database when extend option is used
625  */
626 int
627 timezone_compile_data (const char *input_folder, const TZ_GEN_TYPE tz_gen_type, char *database_name,
628  const char *timezones_dot_c_filepath, char *checksum)
629 {
630  int err_status = NO_ERROR;
631  TZ_RAW_DATA tzd_raw;
632  TZ_DATA tzd;
633  bool write_checksum = false;
634  char default_output_file_path[PATH_MAX] = { 0 };
635 
636  memset (&tzd, 0, sizeof (tzd));
637  memset (&tzd_raw, 0, sizeof (tzd_raw));
638 
639  err_status = tzc_check_new_package_validity (input_folder);
640  if (err_status != NO_ERROR)
641  {
642  goto exit;
643  }
644 
645  /* load raw data */
646  err_status = tzc_load_raw_data (&tzd_raw, input_folder);
647  if (err_status != NO_ERROR)
648  {
649  goto exit;
650  }
651 
652  /* load old data */
653  err_status = tzc_import_old_data (&tzd_raw, tz_gen_type);
654  if (err_status != NO_ERROR)
655  {
656  goto exit;
657  }
658 
659  err_status = tzc_del_unused_raw_data (&tzd_raw);
660  if (err_status != NO_ERROR)
661  {
662  goto exit;
663  }
664 
665  tzc_sort_raw_data (&tzd_raw);
666 
667  err_status = tzc_index_data (&tzd_raw, tz_gen_type);
668  if (err_status != NO_ERROR)
669  {
670  goto exit;
671  }
672 
673  err_status = tzc_compile_data (&tzd_raw, &tzd);
674  if (err_status != NO_ERROR)
675  {
676  goto exit;
677  }
678 
679 #if defined(WINDOWS)
680  /* load windows_iana_map */
681  err_status = tzc_load_windows_iana_map (&tzd, input_folder);
682  if (err_status != NO_ERROR)
683  {
684  /* failed to load file */
685  goto exit;
686  }
687 #endif
688 
689  if (tz_gen_type == TZ_GEN_TYPE_EXTEND)
690  {
691  write_checksum = true;
692  err_status = tzc_extend (&tzd);
693  if (err_status != NO_ERROR)
694  {
695  /* In this case a data migration is needed because the data could not
696  * be made backward compatible
697  */
698  if (err_status == ER_TZ_COMPILE_ERROR)
699  {
700  err_status = tzc_update (&tzd, database_name);
701  if (err_status != NO_ERROR)
702  {
703  goto exit;
704  }
705  }
706  else
707  {
708  goto exit;
709  }
710  }
711  }
712 
713  err_status = tzc_compute_timezone_checksum (&tzd, tz_gen_type);
714  if (err_status != NO_ERROR)
715  {
716  goto exit;
717  }
718 
719  if (timezones_dot_c_filepath == NULL)
720  {
721  tzc_get_timezones_dot_c_filepath (sizeof (default_output_file_path), default_output_file_path);
722  timezones_dot_c_filepath = default_output_file_path;
723  }
724  err_status = tzc_export_timezone_dot_c (&tzd, timezones_dot_c_filepath);
725  if (err_status != NO_ERROR)
726  {
727  goto exit;
728  }
729 
730  if (write_checksum == true)
731  {
732  strcpy (checksum, tzd.checksum);
733  }
734 
735  tzc_summary (&tzd_raw, &tzd);
736 
737 exit:
738  tzc_free_raw_data (&tzd_raw);
739  tzc_free_tz_data (&tzd, true);
740 
741  return err_status;
742 }
743 #endif
744 
745 /*
746  * tzc_free_tz_data () - frees members of a TZ_DATA* structure
747  * Returns:
748  * tzd(in/out): timezone data to free
749  */
750 static void
751 tzc_free_tz_data (TZ_DATA * tzd, bool full)
752 {
753  int i;
754 
755  if (tzd->countries != NULL)
756  {
757  free (tzd->countries);
758  }
759  if (tzd->timezones != NULL)
760  {
761  free (tzd->timezones);
762  }
763  if (tzd->timezone_names != NULL)
764  {
765  for (i = 0; i < tzd->timezone_count; i++)
766  {
767  if (tzd->timezone_names[i] != NULL)
768  {
769  free (tzd->timezone_names[i]);
770  }
771  }
772  free (tzd->timezone_names);
773  }
774  if (tzd->offset_rules != NULL)
775  {
776  for (i = 0; i < tzd->offset_rule_count; i++)
777  {
778  if (tzd->offset_rules[i].std_format != NULL)
779  {
780  free ((void *) (tzd->offset_rules[i].std_format));
781  }
782  if (tzd->offset_rules[i].save_format != NULL)
783  {
784  free ((void *) (tzd->offset_rules[i].save_format));
785  }
786  if (tzd->offset_rules[i].var_format != NULL)
787  {
788  free ((void *) (tzd->offset_rules[i].var_format));
789  }
790  }
791  free (tzd->offset_rules);
792  }
793  if (tzd->names != NULL)
794  {
795  for (i = 0; i < tzd->name_count; i++)
796  {
797  if (tzd->names[i].name != NULL)
798  {
799  free ((void *) (tzd->names[i].name));
800  }
801  }
802  free (tzd->names);
803  }
804 
805  if (tzd->ds_rulesets != NULL)
806  {
807  for (i = 0; i < tzd->ds_ruleset_count; i++)
808  {
809  if (tzd->ds_rulesets[i].ruleset_name != NULL)
810  {
811  free ((void *) (tzd->ds_rulesets[i].ruleset_name));
812  }
813  if (tzd->ds_rulesets[i].default_abrev != NULL)
814  {
815  free ((void *) (tzd->ds_rulesets[i].default_abrev));
816  }
817  }
818  free (tzd->ds_rulesets);
819  }
820  if (tzd->ds_rules != NULL)
821  {
822  for (i = 0; i < tzd->ds_rule_count; i++)
823  {
824  if (tzd->ds_rules[i].letter_abbrev != NULL)
825  {
826  free ((void *) (tzd->ds_rules[i].letter_abbrev));
827  }
828  }
829  free (tzd->ds_rules);
830  }
831  if (full == true)
832  {
833  if (tzd->ds_leap_sec != NULL)
834  {
835  free (tzd->ds_leap_sec);
836  }
837 #if defined(WINDOWS)
838  if (tzd->windows_iana_map != NULL)
839  {
840  free (tzd->windows_iana_map);
841  }
842 #endif
843  }
844 
845  memset (&tzd, 0, sizeof (tzd));
846 }
847 
848 /*
849  * tzc_load_raw_data() - loads data from all relevant tz files into
850  * temporary structures
851  * Returns: NO_ERROR if successful, internal error code otherwise
852  * tzd_raw(out): loaded timezone data
853  * input_folder(in): path to the input folder containing timezone data
854  */
855 static int
856 tzc_load_raw_data (TZ_RAW_DATA * tzd_raw, const char *input_folder)
857 {
858  int err_status = NO_ERROR;
859  int i;
860 
861  /* load countries */
862  err_status = tzc_load_countries (tzd_raw, input_folder);
863  if (err_status != NO_ERROR)
864  {
865  /* failed to load country file */
866  goto exit;
867  }
868 
869  /* load zones */
870  err_status = tzc_load_zone_names (tzd_raw, input_folder);
871  if (err_status != NO_ERROR)
872  {
873  /* failed to load zone file */
874  goto exit;
875  }
876  /* load zones (from the file names "backward" ) */
877  err_status = tzc_load_backward_zones (tzd_raw, input_folder);
878  if (err_status != NO_ERROR)
879  {
880  /* failed to load file */
881  goto exit;
882  }
883 
884  /* load daylight saving rules, zone aliases and zone offset information */
885  for (i = 0; i < tz_File_count; i++)
886  {
887  if (tz_Files[i].type != TZF_RULES)
888  {
889  continue;
890  }
891  err_status = tzc_load_rule_file (tzd_raw, i, input_folder);
892  if (err_status != NO_ERROR)
893  {
894  goto exit;
895  }
896  }
897 
898  /* load leap seconds */
899  err_status = tzc_load_leap_secs (tzd_raw, input_folder);
900  if (err_status != NO_ERROR)
901  {
902  /* failed to load file */
903  goto exit;
904  }
905 
906  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, "", -1);
907 
908  err_status = tzc_check_links_raw_data (tzd_raw);
909  if (err_status != NO_ERROR)
910  {
911  goto exit;
912  }
913 
914 exit:
915  return err_status;
916 }
917 
918 /*
919  * tzc_import_old_data () - this function reads the existing timezone data and
920  * decides which data should be kept. The data to be kept
921  * consists of certain IDs, timezones and their
922  * associated offset rules and daylight saving rules.
923  * Choosing the data to keep is done based on the input
924  * parameter 'mode'.
925  * Returns: 0 (NO_ERROR) if success, error code otherwise
926  * tzd_raw(in/out) :raw timezone structure where to partially load the data to
927  * mode(in): loading mode e.g. new, update or extend
928  */
929 static int
931 {
932  int err_status = NO_ERROR;
933 
934  if (mode == TZ_GEN_TYPE_NEW)
935  {
936  /* nothing to do */
937  return NO_ERROR;
938  }
939 
940  return err_status;
941 }
942 
943 /*
944  * tzc_del_unused_raw_data () - cleans up the loaded raw timezone data and
945  * removes any unused information, such as daylight
946  * saving rules and rulesets
947  * Returns: 0 (NO_ERROR) if success, error code otherwise
948  * tzd_raw(out): raw timezone data structure to cleanup
949  */
950 static int
952 {
953  int err_status = NO_ERROR;
954  int i, j, k;
955  bool found = false;
956  TZ_RAW_DS_RULESET *ruleset = NULL;
957  TZ_RAW_ZONE_INFO *zone = NULL;
958  TZ_RAW_OFFSET_RULE *offset_rule = NULL;
959 
960  /* mark unused rulesets */
961  for (i = 0; i < tzd_raw->ruleset_count; i++)
962  {
963  ruleset = &(tzd_raw->ds_rulesets[i]);
964  found = false;
965  for (j = 0; j < tzd_raw->zone_count && !found; j++)
966  {
967  zone = &(tzd_raw->zones[j]);
968  for (k = 0; k < zone->offset_rule_count && !found; k++)
969  {
970  offset_rule = &(zone->offset_rules[k]);
971  if (strcmp (offset_rule->ds_ruleset_name, ruleset->name) == 0)
972  {
973  ruleset->is_used = true;
974  found = true;
975  }
976  }
977  }
978  }
979 
980  /* remove unused rulesets */
981  i = 0;
982  while (i < tzd_raw->ruleset_count)
983  {
984  if (tzd_raw->ds_rulesets[i].is_used == false)
985  {
986  if (i < tzd_raw->ruleset_count - 1)
987  {
988  free (tzd_raw->ds_rulesets[i].rules);
989  memcpy (&(tzd_raw->ds_rulesets[i]), &(tzd_raw->ds_rulesets[tzd_raw->ruleset_count - 1]),
990  sizeof (TZ_RAW_DS_RULESET));
991  }
992  /* decrease count; tzd_raw->rulesets will be realloc'ed below */
993  tzd_raw->ruleset_count--;
994  }
995  else
996  {
997  i++;
998  }
999  }
1000 
1001  assert (tzd_raw->ruleset_count > 0);
1002 
1003  /* realloc rulesets, in case some rulesets were removed above */
1004  ruleset = (TZ_RAW_DS_RULESET *) realloc (tzd_raw->ds_rulesets, tzd_raw->ruleset_count * sizeof (TZ_RAW_DS_RULESET));
1005  if (ruleset == NULL)
1006  {
1007  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1008 
1009  sprintf (err_msg, "%d", tzd_raw->ruleset_count);
1010  err_status = TZC_ERR_OUT_OF_MEMORY;
1011  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_DS_RULESET");
1012  goto exit;
1013  }
1014  tzd_raw->ds_rulesets = ruleset;
1015 
1016 exit:
1017  return err_status;
1018 }
1019 
1020 /*
1021  * tzc_index_data () - build IDs for all time zone data
1022  * Returns: 0(NO_ERROR) if success, error code otherwise
1023  * tzd_raw (in/out): working timezone data structure
1024  * mode(in): control flag
1025  */
1026 static int
1028 {
1029  int err_status = NO_ERROR;
1030  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1031 
1032  if (mode == TZ_GEN_TYPE_NEW || mode == TZ_GEN_TYPE_EXTEND)
1033  {
1034  tzc_index_raw_data (tzd_raw);
1035  }
1036  else
1037  {
1038  snprintf (err_msg, sizeof (err_msg) - 1, "UPDATE OPTION NOT IMPLEMENTED!");
1040  err_status = ER_TZ_COMPILE_ERROR;
1041  goto exit;
1042  }
1043 
1044  err_status = tzc_index_raw_subdata (tzd_raw, mode);
1045  if (err_status != NO_ERROR)
1046  {
1047  goto exit;
1048  }
1049 
1050 exit:
1051  return err_status;
1052 }
1053 
1054 /*
1055  * tzc_load_countries() - loads the list of countries from the files marked
1056  * as TZ_COUNTRIES type (e.g. iso3166.tab)
1057  * Returns: NO_ERROR(0) if success, error code or -1 otherwise
1058  * tzd_raw(out): timezone data structure to hold the loaded information
1059  * input_folder(in): folder containing IANA's timezone database
1060  */
1061 static int
1062 tzc_load_countries (TZ_RAW_DATA * tzd_raw, const char *input_folder)
1063 {
1064  int err_status = NO_ERROR;
1065  int i, file_index = -1;
1066  char country_filepath[PATH_MAX] = { 0 };
1067  char str[256];
1068  char *str_country_name;
1069  FILE *fp = NULL;
1070  TZ_RAW_COUNTRY *temp_tz_country = NULL;
1071 
1072  for (i = 0; i < tz_File_count; i++)
1073  {
1074  if (tz_Files[i].type == TZF_COUNTRIES)
1075  {
1076  /* Only one file containing country data is allowed */
1077  assert (file_index == -1);
1078  file_index = i;
1079  }
1080  }
1081  /* the list of files is hardcoded above, so if a file with TZ_COUNTRY flag is not found in tz_Files, code fixes are
1082  * needed */
1083  assert (file_index != -1);
1084 
1085  tzc_build_filepath (country_filepath, sizeof (country_filepath), input_folder, tz_Files[file_index].name);
1086  fp = fopen_ex (country_filepath, "rt");
1087  if (fp == NULL)
1088  {
1089  /* file not found or not accessible */
1090  err_status = TZC_ERR_FILE_NOT_ACCESSIBLE;
1091  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_FILE_NOT_ACCESSIBLE, country_filepath, "read");
1092  goto exit;
1093  }
1094 
1095  tzd_raw->country_count = 0;
1096  tzd_raw->countries = NULL;
1097 
1098  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, tz_Files[file_index].name, 0);
1099 
1100  while (fgets (str, sizeof (str), fp))
1101  {
1102  tzd_raw->context.current_line++;
1103 
1105 
1106  if (IS_EMPTY_STR (str))
1107  {
1108  continue;
1109  }
1110 
1111  str_country_name = strchr (str, '\t');
1112  if (str_country_name == NULL || strlen (str_country_name + 1) == 0
1113  || str_country_name - str != TZ_COUNTRY_CODE_LEN)
1114  {
1115  /* data formatting error on line <line_count> */
1116  err_status = TZC_ERR_INVALID_COUNTRY;
1118  goto exit;
1119  }
1120 
1121  temp_tz_country =
1122  (TZ_RAW_COUNTRY *) realloc (tzd_raw->countries, (tzd_raw->country_count + 1) * sizeof (TZ_RAW_COUNTRY));
1123  if (temp_tz_country == NULL)
1124  {
1125  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1126 
1127  sprintf (err_msg, "%d", tzd_raw->country_count + 1);
1128  err_status = TZC_ERR_OUT_OF_MEMORY;
1129  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_COUNTRY");
1130  goto exit;
1131  }
1132  tzd_raw->countries = temp_tz_country;
1133 
1134  /* grasp the newly added item */
1135  temp_tz_country = &(tzd_raw->countries[tzd_raw->country_count]);
1136  tzd_raw->country_count++;
1137  memset (temp_tz_country, 0, sizeof (temp_tz_country[0]));
1138  /* store parsed data */
1139  memcpy (temp_tz_country->code, str, TZ_COUNTRY_CODE_LEN);
1140  strncpy_bufsize (temp_tz_country->full_name, str_country_name + 1);
1141  temp_tz_country->id = -1;
1142  }
1143 
1144 exit:
1145  if (fp != NULL)
1146  {
1147  fclose (fp);
1148  }
1149 
1150  return err_status;
1151 }
1152 
1153 /*
1154  * tzc_load_zones() - loads the list of countries from the files marked
1155  * as TZ_ZONES type (e.g. zone.tab)
1156  * Returns: 0 (NO_ERROR) if success, error code or -1 otherwise
1157  * tzd_raw(out): timezone data structure to hold the loaded information
1158  * input_folder(in): folder containing IANA's timezone database
1159  */
1160 static int
1161 tzc_load_zone_names (TZ_RAW_DATA * tzd_raw, const char *input_folder)
1162 {
1163  int err_status = NO_ERROR;
1164  int i, file_index = -1;
1165  char zone_filepath[PATH_MAX] = { 0 };
1166  char str[256];
1167  FILE *fp = NULL;
1168  TZ_RAW_ZONE_INFO *temp_zone_info = NULL;
1169  char *col_code, *col_coord, *col_tz_name, *col_comments;
1170 
1171  col_code = col_coord = col_tz_name = col_comments = NULL;
1172 
1173  for (i = 0; i < tz_File_count; i++)
1174  {
1175  if (tz_Files[i].type == TZF_ZONES)
1176  {
1177  /* Only one file containing zone data is allowed */
1178  assert (file_index == -1);
1179  file_index = i;
1180  }
1181  }
1182  /* the list of files is hardcoded above, so if a file with TZ_COUNTRY flag is not found in tz_Files, code fixes are
1183  * needed */
1184  assert (file_index != -1);
1185 
1186  tzc_build_filepath (zone_filepath, sizeof (zone_filepath), input_folder, tz_Files[file_index].name);
1187  fp = fopen_ex (zone_filepath, "rt");
1188  if (fp == NULL)
1189  {
1190  /* file not found or not accessible */
1191  err_status = TZC_ERR_FILE_NOT_ACCESSIBLE;
1192  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_FILE_NOT_ACCESSIBLE, zone_filepath, "read");
1193  goto exit;
1194  }
1195 
1196  tzd_raw->zone_count = 0;
1197  tzd_raw->zones = NULL;
1198 
1199  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, tz_Files[file_index].name, 0);
1200 
1201  while (fgets (str, sizeof (str), fp))
1202  {
1203  tzd_raw->context.current_line++;
1204 
1206 
1207 
1208  if (IS_EMPTY_STR (str))
1209  {
1210  continue;
1211  }
1212 
1213  col_code = strtok (str, "\t");
1214  col_coord = strtok (NULL, "\t");
1215  col_tz_name = strtok (NULL, "\t");
1216  col_comments = strtok (NULL, "\t");
1217 
1218  assert (col_code != NULL && col_coord != NULL && col_tz_name != NULL);
1219 
1220  if (col_code == NULL || strlen (col_code) != 2 || IS_EMPTY_STR (col_coord) || IS_EMPTY_STR (col_tz_name))
1221  {
1222  /* data formatting error on line <line_count> */
1223  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
1224 
1225  sprintf (temp_msg, "code: %s, coordinates: %s, name: %s, comments: %s", col_code == NULL ? "null" : col_code,
1226  col_coord == NULL ? "null" : col_coord, col_tz_name == NULL ? "null" : col_tz_name,
1227  col_comments == NULL ? "null/empty" : col_comments);
1228  err_status = TZC_ERR_INVALID_ZONE;
1229  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_ZONE, str, temp_msg);
1230  goto exit;
1231  }
1232 
1233  /* new zone found, expand data structure and store it */
1234  err_status = tzc_add_zone (col_tz_name, col_code, col_coord, col_comments, tzd_raw, &temp_zone_info);
1235  if (err_status != NO_ERROR)
1236  {
1237  goto exit;
1238  }
1239  }
1240 
1241 exit:
1242  if (fp != NULL)
1243  {
1244  fclose (fp);
1245  }
1246 
1247  return err_status;
1248 }
1249 
1250 /*
1251  * tzc_load_rule_files() - loads the data from the files marked as TZ_RULES
1252  * (e.g. europe, asia etc.)
1253  * Returns: 0 (NO_ERROR) if success, error code or -1 otherwise
1254  * tzd_raw(out): timezone data structure to hold the loaded information
1255  * file_index(in): index in tz_Files file list for the file to be loaded
1256  * input_folder(in): folder containing IANA's timezone database
1257  *
1258  * NOTE: tz_load_rules() must be called after tz_load_zones(), because it
1259  * needs the data structures and loaded data created by tz_load_zones()
1260  */
1261 static int
1262 tzc_load_rule_file (TZ_RAW_DATA * tzd_raw, const int file_index, const char *input_folder)
1263 {
1264  int err_status = NO_ERROR;
1265  char filepath[PATH_MAX] = { 0 };
1266  char str[TZ_MAX_LINE_LEN] = { 0 };
1267  FILE *fp = NULL;
1268  char *entry_type_str = NULL;
1269  TZ_RAW_ZONE_INFO *last_zone = NULL;
1270  char *next_token = NULL;
1271  bool check_zone = false;
1272 
1273  assert (tzd_raw != NULL);
1274  assert (input_folder != NULL);
1275  assert (file_index > 0 && file_index < tz_File_count);
1276  assert (tz_Files[file_index].type == TZF_RULES);
1277 
1278  tzc_build_filepath (filepath, sizeof (filepath), input_folder, tz_Files[file_index].name);
1279  fp = fopen_ex (filepath, "rt");
1280  if (fp == NULL)
1281  {
1282  /* file not found or not accessible */
1283  err_status = TZC_ERR_FILE_NOT_ACCESSIBLE;
1285  goto exit;
1286  }
1287 
1288  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, tz_Files[file_index].name, 0);
1289 
1290  while (fgets (str, sizeof (str), fp))
1291  {
1292  tzd_raw->context.current_line++;
1293 
1295 
1296  if (strlen (str) < TZ_OFFRULE_PREFIX_TAB_COUNT)
1297  {
1298  continue;
1299  }
1300 
1301  if (check_zone)
1302  {
1303  if (str[0] == '\t' && str[1] == '\t' && str[2] == '\t')
1304  {
1305  err_status = tzc_add_offset_rule (last_zone, str + 3);
1306  if (err_status != NO_ERROR)
1307  {
1308  goto exit;
1309  }
1310  continue;
1311  }
1312  else
1313  {
1314  check_zone = false;
1315  }
1316  }
1317 
1318  entry_type_str = strtok (str, " \t");
1319 
1320  if (strcmp (entry_type_str, "Link") == 0)
1321  {
1322  char *zone_name = NULL, *alias = NULL;
1323 
1324  zone_name = strtok (NULL, " \t");
1325  alias = strtok (NULL, "\t");
1326  if (IS_EMPTY_STR (zone_name) || IS_EMPTY_STR (alias))
1327  {
1328  /* error, empty or misformed line */
1329  err_status = TZC_ERR_BAD_TZ_LINK;
1330  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_BAD_TZ_LINK, zone_name, alias);
1331  goto exit;
1332  }
1333 
1334  err_status = tzc_add_link (tzd_raw, zone_name, alias);
1335  if (err_status != NO_ERROR)
1336  {
1337  goto exit;
1338  }
1339  continue;
1340  }
1341  else if (strcmp (entry_type_str, "Zone") == 0)
1342  {
1343  next_token = strtok (NULL, " \t");
1344  if (IS_EMPTY_STR (next_token))
1345  {
1346  err_status = TZC_ERR_INVALID_VALUE;
1347  TZC_LOG_ERROR_1ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_VALUE, "timezone name");
1348  goto exit;
1349  }
1350  err_status = tzc_get_zone (tzd_raw, next_token, &last_zone);
1351  if (err_status != NO_ERROR)
1352  {
1353  /* some timezones (such as WET, CET, MET, EET) are not listed in the zone file, but are included in the
1354  * rule files (ex.: europe file) in zone rules; they need to be added to the list of zones */
1355  err_status = tzc_add_zone (next_token, NULL, NULL, NULL, tzd_raw, &last_zone);
1356  if (err_status != NO_ERROR)
1357  {
1358  goto exit;
1359  }
1360  }
1361  if (last_zone == NULL)
1362  {
1363  /* zones should have already been fully loaded */
1364  err_status = TZC_ERR_ADD_ZONE;
1365  TZC_LOG_ERROR_1ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_ADD_ZONE, next_token);
1366  goto exit;
1367  }
1368 
1369  err_status = tzc_add_offset_rule (last_zone, next_token + strlen (next_token) + 1);
1370  if (err_status != NO_ERROR)
1371  {
1372  goto exit;
1373  }
1374  check_zone = true;
1375  }
1376  else if (strcmp (entry_type_str, "Rule") == 0)
1377  {
1378  err_status = tzc_add_ds_rule (tzd_raw, str + strlen (entry_type_str) + 1);
1379  if (err_status != NO_ERROR)
1380  {
1381  goto exit;
1382  }
1383  }
1384  else
1385  {
1386  /* non-empty line, which is not a comment, nor a valid zone/rule/link definition */
1387  assert (false);
1388  }
1389  /* reset line buffer */
1390  memset (str, 0, TZ_MAX_LINE_LEN);
1391  }
1392 
1393 exit:
1394  if (fp != NULL)
1395  {
1396  fclose (fp);
1397  }
1398 
1399  return err_status;
1400 }
1401 
1402 /*
1403  * tzc_load_backward_zones() - loads the "backward" file containing links
1404  * between obsolete (more or less) zone names and their current
1405  * names
1406  * Returns: 0 (NO_ERROR) if success, error code or -1 otherwise
1407  * tzd_raw(out): timezone data structure to hold the loaded information
1408  * input_folder(in): folder containing IANA's timezone database
1409  *
1410  * NOTE: the "backward" file is actually usefull, because most SQL samples
1411  * found online sometimes use old zone names.
1412  */
1413 static int
1414 tzc_load_backward_zones (TZ_RAW_DATA * tzd_raw, const char *input_folder)
1415 {
1416  int err_status = NO_ERROR;
1417  int i, file_index = -1;
1418  char filepath[PATH_MAX] = { 0 };
1419  char str[TZ_MAX_LINE_LEN] = { 0 };
1420  FILE *fp = NULL;
1421  char *entry_type_str = NULL;
1422  char *next_token = NULL, *zone_name = NULL, *alias = NULL;
1423 
1424  assert (tzd_raw != NULL);
1425  assert (input_folder != NULL);
1426 
1427  for (i = 0; i < tz_File_count; i++)
1428  {
1429  if (tz_Files[i].type == TZF_BACKWARD)
1430  {
1431  file_index = i;
1432  break;
1433  }
1434  }
1435  assert (file_index != -1);
1436 
1437  tzc_build_filepath (filepath, sizeof (filepath), input_folder, tz_Files[file_index].name);
1438  fp = fopen_ex (filepath, "rt");
1439  if (fp == NULL)
1440  {
1441  /* file not found or not accessible */
1442  err_status = TZC_ERR_FILE_NOT_ACCESSIBLE;
1444  goto exit;
1445  }
1446 
1447  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, tz_Files[file_index].name, 0);
1448 
1449  while (fgets (str, sizeof (str), fp))
1450  {
1451  tzd_raw->context.current_line++;
1452 
1454 
1455  if (IS_EMPTY_STR (str))
1456  {
1457  continue;
1458  }
1459 
1460  entry_type_str = strtok (str, "\t");
1461 
1462  assert (entry_type_str != NULL && strcmp (entry_type_str, "Link") == 0);
1463 
1464  next_token = str + strlen (entry_type_str) + 1;
1465  zone_name = strtok (next_token, "\t");
1466 
1467  if (IS_EMPTY_STR (zone_name))
1468  {
1469  err_status = TZC_ERR_BAD_TZ_LINK;
1470  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_BAD_TZ_LINK, zone_name, "<alias not parsed yet>");
1471  goto exit;
1472  }
1473  next_token = zone_name + strlen (zone_name) + 1;
1474  while (*next_token == '\t')
1475  {
1476  next_token++;
1477  }
1478  alias = strtok (next_token, "\t");
1479  if (IS_EMPTY_STR (alias))
1480  {
1481  err_status = TZC_ERR_BAD_TZ_LINK;
1482  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_BAD_TZ_LINK, zone_name, alias);
1483  goto exit;
1484  }
1485  err_status = tzc_add_link (tzd_raw, zone_name, alias);
1486  if (err_status != NO_ERROR)
1487  {
1488  goto exit;
1489  }
1490  /* reset line buffer */
1491  memset (str, 0, TZ_MAX_LINE_LEN);
1492  }
1493 
1494 exit:
1495  if (fp != NULL)
1496  {
1497  fclose (fp);
1498  }
1499 
1500  return err_status;
1501 }
1502 
1503 /*
1504  * tzc_load_leap_secs() - loads the "leapseconds" file containing leap
1505  * second information (date of occurence, type, etc.)
1506  * Returns: 0 (NO_ERROR) if success, error code or -1 otherwise
1507  * tzd_raw(out): timezone data structure to hold the loaded information
1508  * input_folder(in): folder containing IANA's timezone database
1509  */
1510 static int
1511 tzc_load_leap_secs (TZ_RAW_DATA * tzd_raw, const char *input_folder)
1512 {
1513  int err_status = NO_ERROR;
1514  int i, file_index = -1, leap_year, leap_month_num, leap_day_num;
1515  int leap_time_h, leap_time_m, leap_time_s;
1516  char filepath[PATH_MAX] = { 0 };
1517  char str[TZ_MAX_LINE_LEN] = { 0 };
1518  FILE *fp = NULL;
1519  const char *next_token, *str_next, *entry_type_str;
1520  bool leap_corr_minus = false;
1521  bool leap_is_rolling = false;
1522 
1523  assert (tzd_raw != NULL);
1524  assert (input_folder != NULL);
1525 
1526  next_token = str_next = entry_type_str = NULL;
1527  leap_year = leap_month_num = leap_day_num = -1;
1528  leap_time_h = leap_time_m = leap_time_s = -1;
1529 
1530  for (i = 0; i < tz_File_count; i++)
1531  {
1532  if (tz_Files[i].type == TZF_LEAP)
1533  {
1534  file_index = i;
1535  break;
1536  }
1537  }
1538  assert (file_index != -1);
1539 
1540  tzc_build_filepath (filepath, sizeof (filepath), input_folder, tz_Files[file_index].name);
1541  fp = fopen_ex (filepath, "rt");
1542  if (fp == NULL)
1543  {
1544  /* file not found or not accessible */
1545  err_status = TZC_ERR_FILE_NOT_ACCESSIBLE;
1547  goto exit;
1548  }
1549 
1550  tzd_raw->leap_sec_count = 0;
1551  tzd_raw->leap_sec = NULL;
1552 
1553  LOG_TZC_SET_CURRENT_CONTEXT (tzd_raw, tz_Files[file_index].name, 0);
1554 
1555  while (fgets (str, sizeof (str), fp))
1556  {
1557  const char *str_end;
1558  tzd_raw->context.current_line++;
1560 
1561  if (IS_EMPTY_STR (str))
1562  {
1563  continue;
1564  }
1565 
1566  str_end = str + strlen (str);
1567 
1568  entry_type_str = strtok (str, "\t");
1569  assert (entry_type_str != NULL && strcmp (entry_type_str, "Leap") == 0);
1570 
1571  next_token = strtok (NULL, "\t");
1572  if (tz_str_read_number (next_token, str_end, true, false, &leap_year, &str_next) != NO_ERROR)
1573  {
1574  err_status = TZC_ERR_INVALID_VALUE;
1576  next_token == NULL ? "" : next_token);
1577  goto exit;
1578  }
1579 
1580  next_token = strtok (NULL, "\t");
1581  if (str_month_to_int (next_token, &leap_month_num, &str_next) != NO_ERROR)
1582  {
1583  err_status = TZC_ERR_INVALID_VALUE;
1585  next_token == NULL ? "" : next_token);
1586  goto exit;
1587  }
1588 
1589  next_token = strtok (NULL, "\t");
1590  if (tz_str_read_number (next_token, str_end, true, false, &leap_day_num, &str_next) != NO_ERROR)
1591  {
1592  err_status = TZC_ERR_INVALID_VALUE;
1594  next_token == NULL ? "" : next_token);
1595  goto exit;
1596  }
1597 
1598  next_token = strtok (NULL, "\t");
1599  if (tz_str_read_time (next_token, str_end, false, true, &leap_time_h, &leap_time_m, &leap_time_s, &str_next) !=
1600  NO_ERROR)
1601  {
1602  err_status = TZC_ERR_INVALID_VALUE;
1604  next_token == NULL ? "" : next_token);
1605  goto exit;
1606  }
1607 
1608  next_token = strtok (NULL, "\t");
1609  if (strlen (next_token) != 1 || ((*next_token != '+') && (*next_token != '-')))
1610  {
1611  err_status = TZC_ERR_INVALID_VALUE;
1612  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_VALUE, "correction",
1613  next_token == NULL ? "" : next_token);
1614  goto exit;
1615  }
1616  if (*next_token == '-')
1617  {
1618  leap_corr_minus = true;
1619  }
1620 
1621  next_token = strtok (NULL, "\t");
1622  if (strlen (next_token) != 1 || ((*next_token != 'R') && (*next_token != 'S')))
1623  {
1624  err_status = TZC_ERR_INVALID_VALUE;
1625  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_VALUE, "leap second type",
1626  next_token == NULL ? "" : next_token);
1627  goto exit;
1628  }
1629  if (*next_token == 'R')
1630  {
1631  leap_is_rolling = true;
1632  }
1633 
1634  if (tzc_add_leap_sec (tzd_raw, leap_year, leap_month_num, leap_day_num, leap_time_h, leap_time_m, leap_time_s,
1635  leap_corr_minus, leap_is_rolling) != NO_ERROR)
1636  {
1637  err_status = TZC_ERR_INVALID_VALUE;
1638  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_VALUE, "leap second data", "line");
1639  goto exit;
1640  }
1641  }
1642 
1643 exit:
1644  if (fp != NULL)
1645  {
1646  fclose (fp);
1647  }
1648 
1649  return err_status;
1650 }
1651 
1652 /*
1653  * tzc_add_link() - adds a link (zone alias) to the list of links in the
1654  * raw timezone data structure
1655  * Returns: error code if failure, 0 (NO_ERROR) otherwise
1656  * tzd_raw(out): timezone data structure where to store the new link
1657  * zone(in): zone name for the link to be created
1658  * alias(in): zone alias for the link to be created
1659  */
1660 static int
1661 tzc_add_link (TZ_RAW_DATA * tzd_raw, const char *zone, const char *alias)
1662 {
1663  TZ_RAW_LINK *temp_link;
1664  int err_status = NO_ERROR;
1665 
1666  assert (tzd_raw != NULL);
1667  assert (!IS_EMPTY_STR (zone) && !IS_EMPTY_STR (alias));
1668 
1669  /* add link to the link list */
1670  assert (tzd_raw->link_count >= 0);
1671 
1672  temp_link = (TZ_RAW_LINK *) realloc (tzd_raw->links, (tzd_raw->link_count + 1) * sizeof (TZ_RAW_LINK));
1673 
1674  if (temp_link == NULL)
1675  {
1676  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1677 
1678  sprintf (err_msg, "%d", tzd_raw->link_count + 1);
1679  err_status = TZC_ERR_OUT_OF_MEMORY;
1680  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_LINK");
1681  goto exit;
1682  }
1683 
1684  tzd_raw->links = temp_link;
1685  temp_link = &(tzd_raw->links[tzd_raw->link_count]);
1686  tzd_raw->link_count++;
1687  memset (temp_link, 0, sizeof (temp_link[0]));
1688 
1689  strcpy (temp_link->name, zone);
1690  strcpy (temp_link->alias, alias);
1691 
1692 exit:
1693  return err_status;
1694 }
1695 
1696 /*
1697  * tzc_add_leap_sec() - adds leap second info to the raw timezone structure
1698  * Returns: error code if failure, 0 (NO_ERROR) otherwise
1699  * year(in), month(in), day(in): parts of the date when leap second occurs
1700  * time(in): time (number of seconds since 00:00) of day when leap sec occurs
1701  * corr_minus(in): true if leap second correction is negative, true if '+'
1702  * leap_is_rolling(in): true if given time is local, false if UTC
1703  * tzd_raw(in/out): timezone data structure where to store the new link
1704  */
1705 static int
1706 tzc_add_leap_sec (TZ_RAW_DATA * tzd_raw, int year, int month, int day, unsigned char hour, unsigned char min,
1707  unsigned char sec, bool corr_minus, bool leap_is_rolling)
1708 {
1709  TZ_LEAP_SEC *temp_leap_sec;
1710  int err_status = NO_ERROR;
1711 
1712  assert (tzd_raw != NULL);
1713 
1714  /* add leap second to the leap second list */
1715  assert (tzd_raw->leap_sec_count >= 0);
1716 
1717  temp_leap_sec = (TZ_LEAP_SEC *) realloc (tzd_raw->leap_sec, (tzd_raw->leap_sec_count + 1) * sizeof (TZ_LEAP_SEC));
1718 
1719  if (temp_leap_sec == NULL)
1720  {
1721  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1722 
1723  sprintf (err_msg, "%d", tzd_raw->leap_sec_count + 1);
1724  err_status = TZC_ERR_OUT_OF_MEMORY;
1725  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_LEAP_SEC");
1726  goto exit;
1727  }
1728 
1729  tzd_raw->leap_sec = temp_leap_sec;
1730  temp_leap_sec = &(tzd_raw->leap_sec[tzd_raw->leap_sec_count]);
1731  tzd_raw->leap_sec_count++;
1732  memset (temp_leap_sec, 0, sizeof (temp_leap_sec[0]));
1733 
1734  /* set data */
1735  temp_leap_sec->year = (unsigned short) year;
1736  temp_leap_sec->month = (unsigned char) month;
1737  temp_leap_sec->day = (unsigned char) day;
1738 
1739  if (hour != 23 || min != 59 || sec != 60)
1740  {
1741  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1742  sprintf (err_msg, "%d", tzd_raw->leap_sec_count + 1);
1743  err_status = TZC_ERR_INVALID_TIME;
1744  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_TIME, err_msg, "TZ_RAW_LEAP_SEC");
1745  goto exit;
1746  }
1747  temp_leap_sec->corr_negative = (unsigned char) (corr_minus ? 1 : 0);
1748  temp_leap_sec->is_rolling = (unsigned char) (leap_is_rolling ? 1 : 0);
1749 
1750 exit:
1751  return err_status;
1752 }
1753 
1754 /*
1755  * tzc_add_zone() - adds a zone to the list of timezones in the raw
1756  * timezone data structure
1757  * Returns: 0 (NO_ERROR) if success, error code if failure
1758  * zone(in): name of the timezone to add
1759  * code (in): code of the time zone to add
1760  * coord(in): coordinates of the timezone to add
1761  * comments(in): comments for the timezone to add
1762  * tzd_raw(in/out): raw timezone data structure where to add the timezone to
1763  * new_zone(out): pointer to the newly added timezone
1764  */
1765 static int
1766 tzc_add_zone (const char *zone, const char *code, const char *coord, const char *comments, TZ_RAW_DATA * tzd_raw,
1767  TZ_RAW_ZONE_INFO ** new_zone)
1768 {
1769  TZ_RAW_ZONE_INFO *temp_zone_info = NULL;
1770  int err_status = NO_ERROR;
1771 
1772  assert (tzd_raw != NULL);
1773  assert (!IS_EMPTY_STR (zone));
1774 
1775  *new_zone = NULL;
1776 
1777  temp_zone_info = (TZ_RAW_ZONE_INFO *) realloc (tzd_raw->zones, (tzd_raw->zone_count + 1) * sizeof (TZ_RAW_ZONE_INFO));
1778 
1779  if (temp_zone_info == NULL)
1780  {
1781  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1782 
1783  sprintf (err_msg, "%d", tzd_raw->zone_count + 1);
1784  err_status = TZC_ERR_OUT_OF_MEMORY;
1785  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_ZONE_INFO");
1786  goto exit;
1787  }
1788  tzd_raw->zones = temp_zone_info;
1789 
1790  /* grasp the newly added item */
1791  temp_zone_info = &(tzd_raw->zones[tzd_raw->zone_count]);
1792  tzd_raw->zone_count++;
1793  memset (temp_zone_info, 0, sizeof (temp_zone_info[0]));
1794 
1795  /* store the parsed data */
1796  if (code != NULL)
1797  {
1798  strcpy (temp_zone_info->code, code);
1799  }
1800  else
1801  {
1802  temp_zone_info->code[0] = '\0';
1803  }
1804  if (coord != NULL)
1805  {
1806  strcpy (temp_zone_info->coordinates, coord);
1807  }
1808  else
1809  {
1810  temp_zone_info->coordinates[0] = '\0';
1811  }
1812 
1813  strcpy (temp_zone_info->full_name, zone);
1814 
1815  if (comments != NULL)
1816  {
1817  strcpy (temp_zone_info->comments, comments);
1818  }
1819  else
1820  {
1821  temp_zone_info->comments[0] = '\0';
1822  }
1823 
1824  temp_zone_info->id = -1;
1825 
1826  *new_zone = temp_zone_info;
1827 exit:
1828  return err_status;
1829 }
1830 
1831 /*
1832  * tzc_get_zone() - parse the input string to get a zone name and
1833  * searches for it in the already loaded zones from the
1834  * TZ_RAW_DATA variable tzd_raw.
1835  * Returns: 0 (NO_ERROR) if zone found, -1 otherwise
1836  * tzd_raw(in/out): raw timezone data structure where to search the zone in
1837  * zone_name(in): name of the timezone to search for
1838  * zone (out): reference to the timezone found
1839  */
1840 static int
1841 tzc_get_zone (const TZ_RAW_DATA * tzd_raw, const char *zone_name, TZ_RAW_ZONE_INFO ** zone)
1842 {
1843  int i;
1844 
1845  assert (tzd_raw != NULL);
1846 
1847  for (i = 0; i < tzd_raw->zone_count; i++)
1848  {
1849  if (strcmp (tzd_raw->zones[i].full_name, zone_name) == 0)
1850  {
1851  *zone = &(tzd_raw->zones[i]);
1852  return NO_ERROR;
1853  }
1854  }
1855  *zone = NULL;
1856 
1857  return TZC_ERR_GENERIC;
1858 }
1859 
1860 /*
1861  * tzc_add_offset_rule() - parse the input string as an offset rule for a
1862  * timezone and attach it to the specified timezone
1863  * Returns: 0 (NO_ERROR) if success, or negative code if an error occurs
1864  * zone(out): raw timezone information structure where to store the parsed
1865  * offset rule
1866  * rule_text(in): string to parse as an offset rule
1867  */
1868 static int
1869 tzc_add_offset_rule (TZ_RAW_ZONE_INFO * zone, char *rule_text)
1870 {
1871  char *gmt_off = NULL, *rules = NULL, *format = NULL, *until = NULL;
1872  int err_status = NO_ERROR;
1873  TZ_RAW_OFFSET_RULE *temp_rule = NULL;
1874  const char *str_dummy = NULL;
1875  char *rule_text_end;
1876  int gmt_off_num = 0;
1877  bool is_numeric_gmt_off = false;
1878 
1879  assert (zone != NULL);
1880 
1881  rule_text_end = rule_text + strlen (rule_text);
1882 
1883  gmt_off = strtok (rule_text, "\t ");
1884 
1885  if (IS_EMPTY_STR (gmt_off))
1886  {
1887  err_status = TZC_ERR_INVALID_VALUE;
1888  TZC_LOG_ERROR_1ARG (NULL, TZC_ERR_INVALID_VALUE, "zone offset");
1889  goto exit;
1890  }
1891 
1892  /* some offset rules have the GMTOFF column '0' instead of a valid time value in the format hh:mm */
1893  if (strcmp (gmt_off, "0") == 0)
1894  {
1895  is_numeric_gmt_off = true;
1896  gmt_off_num = 0;
1897  }
1898  else if (strchr (gmt_off, ':') == NULL)
1899  {
1900  /* string might not be a GMT offset rule; check if it's a number */
1901  err_status = tz_str_read_number (gmt_off, rule_text_end, true, true, &gmt_off_num, &str_dummy);
1902  if (err_status != NO_ERROR)
1903  {
1904  err_status = TZC_ERR_INVALID_VALUE;
1905  goto exit;
1906  }
1907  is_numeric_gmt_off = true;
1908  }
1909  rules = strtok (NULL, " \t");
1910  format = strtok (NULL, " \t");
1911 
1912  if (IS_EMPTY_STR (rules) || IS_EMPTY_STR (format))
1913  {
1914  err_status = TZC_ERR_INVALID_VALUE;
1915  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_VALUE, "ruleset name or format",
1916  IS_EMPTY_STR (rules) ? (IS_EMPTY_STR (format) ? "" : format) : rules);
1917  goto exit;
1918  }
1919  until = strtok (NULL, "\t");
1920 
1921  if (zone->offset_rule_count != 0 && zone->offset_rules[zone->offset_rule_count - 1].until_flag == UNTIL_INFINITE)
1922  {
1923  /* last existing rule still applies, no new rules are allowed after this one */
1924  err_status = TZC_ERR_ZONE_RULE_UNORDERED;
1926  goto exit;
1927  }
1928 
1929  temp_rule =
1930  (TZ_RAW_OFFSET_RULE *) realloc (zone->offset_rules, (zone->offset_rule_count + 1) * sizeof (TZ_RAW_OFFSET_RULE));
1931 
1932  if (temp_rule == NULL)
1933  {
1934  char err_msg[TZC_ERR_MSG_MAX_SIZE];
1935 
1936  sprintf (err_msg, "%d", zone->offset_rule_count + 1);
1937  err_status = TZC_ERR_OUT_OF_MEMORY;
1938  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_OFFSET_RULE");
1939  goto exit;
1940  }
1941 
1942  zone->offset_rules = temp_rule;
1943  temp_rule = &(zone->offset_rules[zone->offset_rule_count]);
1944  zone->offset_rule_count++;
1945  memset (temp_rule, 0, sizeof (temp_rule[0]));
1946 
1947  if (is_numeric_gmt_off)
1948  {
1949  temp_rule->gmt_off = gmt_off_num * 3600;
1950  }
1951  else
1952  {
1953  err_status = tz_str_to_seconds (gmt_off, rule_text_end, &(temp_rule->gmt_off), &str_dummy, false);
1954  if (err_status != NO_ERROR)
1955  {
1956  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_TIME, gmt_off, "tz offset rule");
1957  goto exit;
1958  }
1959  }
1960 
1961  assert (strlen (rules) < TZ_DS_RULESET_NAME_SIZE && strlen (format) < TZ_MAX_FORMAT_SIZE);
1962 
1963  strcpy (temp_rule->ds_ruleset_name, rules);
1964  strcpy (temp_rule->format, format);
1965 
1966  if (str_to_offset_rule_until (temp_rule, until) != NO_ERROR)
1967  {
1968  goto exit;
1969  }
1970 
1971 exit:
1972  return err_status;
1973 }
1974 
1975 /*
1976  * tzc_read_time_type() -
1977  *
1978  * Returns: 0 (NO_ERROR) if success, or negative code if an error occurs
1979  * tzd_raw(in/out): raw timezone data structure
1980  * rule_text(in): string to parse as a daylight saving rule
1981  */
1982 static int
1983 tzc_read_time_type (const char *str, const char **next, TZ_TIME_TYPE * time_type)
1984 {
1985  assert (time_type != NULL);
1986  assert (next != NULL);
1987 
1988  switch (*str)
1989  {
1990  case 's':
1991  /* local standard time (different from wall clock time when observing daylight saving time) */
1992  *time_type = TZ_TIME_TYPE_LOCAL_STD;
1993  break;
1994  case 'g':
1995  case 'u':
1996  case 'z':
1997  /* g/u/z stand for GMT/UTC/Zulu which are the same thing */
1998  *time_type = TZ_TIME_TYPE_UTC;
1999  break;
2000  case 'w':
2001  case '\0':
2002  /* wall clock time (including daylight savings, if any). This is the default, if no suffix is used. */
2003  *time_type = TZ_TIME_TYPE_LOCAL_WALL;
2004  break;
2005  default:
2006  /* No other suffixes are allowed, so this should never be hit */
2007  return TZC_ERR_GENERIC;
2008  break;
2009  }
2010 
2011  *next = (char *) str + 1;
2012 
2013  return NO_ERROR;
2014 }
2015 
2016 /*
2017  * tzc_add_ds_rule() - parse the input string as a daylight saving rule and
2018  * append it to the rule set identified by the rule name
2019  * Returns: 0 (NO_ERROR) if success, or negative code if an error occurs
2020  * tzd_raw(in/out): raw timezone data structure
2021  * rule_text(in): string to parse as a daylight saving rule
2022  */
2023 static int
2024 tzc_add_ds_rule (TZ_RAW_DATA * tzd_raw, char *rule_text)
2025 {
2026  int i, val_read;
2027  int err_status = NO_ERROR;
2028  TZ_RAW_DS_RULESET *ds_ruleset = NULL;
2029  TZ_RAW_DS_RULE *ds_rule = NULL;
2030  char *col_name, *col_from, *col_to, *col_type, *col_in, *col_on, *col_at;
2031  char *col_save, *col_letters;
2032  const char *str_cursor = NULL;
2033  const char *rule_text_end;
2034 
2035  assert (tzd_raw != NULL);
2036 
2037  rule_text_end = rule_text + strlen (rule_text);
2038 
2039  col_name = strtok (rule_text, " \t");
2040  col_from = strtok (NULL, " \t");
2041  col_to = strtok (NULL, " \t");
2042  col_type = strtok (NULL, " \t");
2043  col_in = strtok (NULL, " \t");
2044  col_on = strtok (NULL, " \t");
2045  col_at = strtok (NULL, " \t");
2046  col_save = strtok (NULL, " \t");
2047  col_letters = strtok (NULL, " \t");
2048 
2049  /* all tokens above must be at least one character long */
2050  if (IS_EMPTY_STR (col_name) || IS_EMPTY_STR (col_from) || IS_EMPTY_STR (col_to) || IS_EMPTY_STR (col_type)
2051  || IS_EMPTY_STR (col_in) || IS_EMPTY_STR (col_on) || IS_EMPTY_STR (col_at) || IS_EMPTY_STR (col_save)
2052  || IS_EMPTY_STR (col_letters))
2053  {
2054  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
2055 
2056  sprintf (temp_msg,
2057  "NAME: '%s', FROM: '%s', TO: '%s', TYPE: '%s', "
2058  "IN: '%s', ON: '%s', AT: '%s', SAVE: '%s', LETTER/S: '%s'", col_name == NULL ? "" : col_name,
2059  col_from == NULL ? "" : col_from, col_to == NULL ? "" : col_to, col_type == NULL ? "" : col_type,
2060  col_in == NULL ? "" : col_in, col_on == NULL ? "" : col_on, col_at == NULL ? "" : col_at,
2061  col_save == NULL ? "" : col_save, col_letters == NULL ? "" : col_letters);
2062  err_status = TZC_ERR_INVALID_DS_RULE;
2064  goto exit;
2065  }
2066 
2067  STR_SKIP_LEADING_SPACES (col_name);
2068  STR_SKIP_LEADING_SPACES (col_from);
2069  STR_SKIP_LEADING_SPACES (col_to);
2070  STR_SKIP_LEADING_SPACES (col_type);
2071  STR_SKIP_LEADING_SPACES (col_in);
2072  STR_SKIP_LEADING_SPACES (col_on);
2073  STR_SKIP_LEADING_SPACES (col_at);
2074  STR_SKIP_LEADING_SPACES (col_save);
2075  STR_SKIP_LEADING_SPACES (col_letters);
2076 
2077  /* find a rule set with the same name as the rule */
2078  for (i = 0; i < tzd_raw->ruleset_count; i++)
2079  {
2080  if (strcmp (tzd_raw->ds_rulesets[i].name, col_name) == 0)
2081  {
2082  ds_ruleset = &(tzd_raw->ds_rulesets[i]);
2083  break;
2084  }
2085  }
2086 
2087  if (ds_ruleset == NULL)
2088  {
2089  /* no rule set with the designated name was found; create one */
2090  ds_ruleset =
2091  (TZ_RAW_DS_RULESET *) realloc (tzd_raw->ds_rulesets, (tzd_raw->ruleset_count + 1) * sizeof (TZ_RAW_DS_RULESET));
2092 
2093  if (ds_ruleset == NULL)
2094  {
2095  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2096 
2097  sprintf (err_msg, "%d", tzd_raw->ruleset_count + 1);
2098  err_status = TZC_ERR_OUT_OF_MEMORY;
2099  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_DS_RULESET");
2100  goto exit;
2101  }
2102 
2103  tzd_raw->ds_rulesets = ds_ruleset;
2104  ds_ruleset = &(tzd_raw->ds_rulesets[tzd_raw->ruleset_count]);
2105  tzd_raw->ruleset_count++;
2106  memset (ds_ruleset, 0, sizeof (ds_ruleset[0]));
2107  strcpy (ds_ruleset->name, col_name);
2108  ds_ruleset->is_used = false;
2109  }
2110 
2111  /* add the daylight saving rule to the rule set (found or created) */
2112  ds_rule = (TZ_RAW_DS_RULE *) realloc (ds_ruleset->rules, (ds_ruleset->rule_count + 1) * sizeof (TZ_RAW_DS_RULE));
2113 
2114  if (ds_rule == NULL)
2115  {
2116  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2117 
2118  sprintf (err_msg, "%d", ds_ruleset->rule_count + 1);
2119  err_status = TZC_ERR_OUT_OF_MEMORY;
2120  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_DS_RULE");
2121  goto exit;
2122  }
2123 
2124  ds_ruleset->rules = ds_rule;
2125  ds_rule = &(ds_ruleset->rules[ds_ruleset->rule_count]);
2126  ds_ruleset->rule_count++;
2127  memset (ds_rule, 0, sizeof (ds_rule[0]));
2128 
2129  /* process and save data into the new TZ_RULE item */
2130  val_read = 0;
2131  /* process and store "FROM" year */
2132  if (tz_str_read_number (col_from, rule_text_end, true, false, &val_read, &str_cursor) != NO_ERROR)
2133  {
2134  err_status = TZC_ERR_CANT_READ_VALUE;
2135  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "year", col_from);
2136  goto exit;
2137  }
2138  ds_rule->from_year = (short) val_read;
2139 
2140  /* process and store "TO" year; if field value is "only", copy "FROM" */
2141  if (strcmp (col_to, "only") == 0)
2142  {
2143  ds_rule->to_year = ds_rule->from_year;
2144  }
2145  else if (strcmp (col_to, "max") == 0)
2146  {
2147  ds_rule->to_year = TZ_MAX_YEAR;
2148  }
2149  else if (tz_str_read_number (col_to, rule_text_end, true, false, &val_read, &str_cursor) != NO_ERROR)
2150  {
2151  err_status = TZC_ERR_CANT_READ_VALUE;
2152  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "year", col_to);
2153  goto exit;
2154  }
2155  else
2156  {
2157  ds_rule->to_year = (short) val_read;
2158  }
2159 
2160  assert (col_type == NULL || strlen (col_type) < TZ_RULE_TYPE_MAX_SIZE);
2161  strcpy (ds_rule->type, col_type);
2162 
2163  /* process and store month ("IN") */
2164  if (str_month_to_int (col_in, &val_read, &str_cursor) != NO_ERROR)
2165  {
2166  err_status = TZC_ERR_CANT_READ_VALUE;
2167  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "month", col_in);
2168  goto exit;
2169  }
2170  if (val_read < TZ_MON_JAN || val_read > TZ_MON_DEC)
2171  {
2172  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
2173 
2174  sprintf (temp_msg, "found value: %d", val_read);
2175  err_status = TZC_ERR_INVALID_VALUE;
2176  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_VALUE, "month value", temp_msg);
2177  goto exit;
2178  }
2179  ds_rule->in_month = (unsigned char) val_read;
2180 
2181  err_status = tzc_parse_ds_change_on (ds_rule, col_on);
2182  if (err_status != NO_ERROR)
2183  {
2184  goto exit;
2185  }
2186 
2187  /* some daylight saving rules use "0" instead of "0:00" in the AT column */
2188  if (strcmp (col_at, "0") == 0)
2189  {
2190  val_read = 0;
2191  }
2192  else if (tz_str_to_seconds (col_at, rule_text_end, &val_read, &str_cursor, false) != NO_ERROR)
2193  {
2194  err_status = TZC_ERR_CANT_READ_VALUE;
2195  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "AT column", col_at);
2196  goto exit;
2197  }
2198  ds_rule->at_time = val_read;
2199 
2200  err_status = tzc_read_time_type (str_cursor, &str_cursor, &(ds_rule->at_time_type));
2201  if (err_status != NO_ERROR)
2202  {
2203  return err_status;
2204  }
2205 
2206  /* In a daylight saving rule, the "Save" column is either 0 or 1 hour, given as a one char string ("0" or "1"), or an
2207  * amount of time specified as hh:mm. So first check if col_save == "<one_char>" */
2208  if (strlen (col_save) == 1)
2209  {
2210  if (tz_str_read_number (col_save, rule_text_end, true, false, &val_read, &str_cursor) != NO_ERROR)
2211  {
2212  err_status = TZC_ERR_CANT_READ_VALUE;
2213  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "SAVE column", col_save);
2214  goto exit;
2215  }
2216  val_read *= 3600;
2217  }
2218  else if (tz_str_to_seconds (col_save, rule_text_end, &val_read, &str_cursor, false) != NO_ERROR)
2219  {
2220  err_status = TZC_ERR_CANT_READ_VALUE;
2221  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_CANT_READ_VALUE, "SAVE column", col_save);
2222  goto exit;
2223  }
2224  ds_rule->save_time = val_read;
2225  strcpy (ds_rule->letter_abbrev, col_letters);
2226 
2227 exit:
2228  return err_status;
2229 }
2230 
2231 /*
2232  * tzc_parse_ds_change_on() - parse the string corresponding to the "ON"
2233  * column in a daylight saving rule, and store
2234  * data in the destination TZ_DS_CHANGE_ON variable
2235  * Returns: 0 (NO_ERROR) if success, error code otherwise
2236  * dest(out): destination variable where to store the parsed data
2237  * str(in): input string to parse
2238  *
2239  * NOTE: The input string can be of the following forms: "21" (plain number),
2240  * "Sun>=16", "lastSun" or other variations using other week days.
2241  */
2242 static int
2243 tzc_parse_ds_change_on (TZ_RAW_DS_RULE * dest, const char *str)
2244 {
2245  int err_status = NO_ERROR;
2246  int day_num = 0; /* day of week or day of month, depending on the context */
2247  int type = -1, bound = -1;
2248  const char *str_cursor = NULL;
2249 
2250  assert (str != NULL && strlen (str) > 0);
2251  assert (dest->in_month <= TZ_MON_DEC);
2252 
2253  str_cursor = str;
2254 
2255  err_status = str_read_day_var (str, dest->in_month, &type, &day_num, &bound, &str_cursor);
2256  if (err_status != NO_ERROR)
2257  {
2258  goto exit;
2259  }
2260 
2261  /* need to validate the day found; check if it is a valid value, according to the year(s) and month already read into
2262  * the input TZ_RAW_DS_RULE dest parameter */
2263  if (type == TZ_DS_TYPE_FIXED)
2264  {
2265  int upper_year;
2266 
2267  if (day_num < 0 || day_num > 30)
2268  {
2269  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
2270 
2271  sprintf (temp_msg, "found value: %d", day_num);
2272  err_status = TZC_ERR_DS_INVALID_DATE;
2273  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "day of month", temp_msg);
2274  goto exit;
2275  }
2276 
2277  upper_year = (dest->to_year == TZ_MAX_YEAR) ? dest->from_year : dest->to_year;
2278 
2279  if (!tzc_is_valid_date (day_num, dest->in_month, dest->from_year, upper_year + 1))
2280  {
2281  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
2282 
2283  sprintf (temp_msg, "Day: %d, Month: %d, Year: %d", day_num, dest->in_month, dest->from_year);
2284  err_status = TZC_ERR_DS_INVALID_DATE;
2285  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "day of month", temp_msg);
2286  goto exit;
2287  }
2288 
2289  /* This is a fixed day of month, store it as such */
2291  dest->change_on.day_of_month = (unsigned char) day_num;
2292  dest->change_on.day_of_week = TZ_WEEK_DAY_COUNT; /* invalid value */
2293  }
2294  else if (type == TZ_DS_TYPE_VAR_SMALLER)
2295  {
2297  dest->change_on.day_of_month = (unsigned char) bound;
2298  dest->change_on.day_of_week = (unsigned char) day_num;
2299  }
2300  else if (type == TZ_DS_TYPE_VAR_GREATER)
2301  {
2303  dest->change_on.day_of_month = (unsigned char) bound;
2304  dest->change_on.day_of_week = (unsigned char) day_num;
2305  }
2306  else
2307  {
2308  assert (false);
2309  }
2310 
2311 exit:
2312  return err_status;
2313 }
2314 
2315 /*
2316  * tzc_is_valid_date () - check if a given date (day and month) is valid for
2317  * all the year values in a given range [year_start, year_end)
2318  * Returns: true if valid, false otherwise
2319  * day(int): day of month (0 to 27/28/29/30)
2320  * month(in): month (0-11)
2321  * year_start(in): starting year for the range
2322  * year_end(in): ending year for the range
2323 */
2324 static bool
2325 tzc_is_valid_date (const int day, const int month, const int year_start, const int year_end)
2326 {
2327  int year;
2328 
2329  if (day < 0 || day > 30 || month < TZ_MON_JAN || month > TZ_MON_DEC || year_start < 0 || year_end <= year_start
2330  || year_end > TZ_MAX_YEAR)
2331  {
2332  return false;
2333  }
2334 
2335  if (month == TZ_MON_FEB)
2336  {
2337  for (year = year_start; year < year_end; year++)
2338  {
2339  if (day >= (IS_LEAP_YEAR (year) ? 29 : 28))
2340  {
2341  return false;
2342  }
2343  }
2344  }
2345  else
2346  {
2347  if (day >= DAYS_IN_MONTH (month))
2348  {
2349  return false;
2350  }
2351  }
2352 
2353  return true;
2354 }
2355 
2356 /*
2357  * tzc_free_raw_data() - frees the structures used when loading the timezone
2358  * data from the input folder
2359  * Returns:
2360  * tzd_raw(in/out): time zone bulk data structure to free
2361  */
2362 static void
2364 {
2365  int i, j;
2366 
2367  if (tzd_raw == NULL)
2368  {
2369  return;
2370  }
2371  if (tzd_raw->countries != NULL)
2372  {
2373  free_and_init (tzd_raw->countries);
2374  }
2375  if (tzd_raw->links != NULL)
2376  {
2377  free_and_init (tzd_raw->links);
2378  }
2379  if (tzd_raw->ds_rulesets != NULL)
2380  {
2381  for (i = 0; i < tzd_raw->ruleset_count; i++)
2382  {
2383  free_and_init (tzd_raw->ds_rulesets[i].rules);
2384  }
2385  free_and_init (tzd_raw->ds_rulesets);
2386  }
2387  if (tzd_raw->zones != NULL)
2388  {
2389  TZ_RAW_ZONE_INFO *zone = NULL;
2390 
2391  for (i = 0; i < tzd_raw->zone_count; i++)
2392  {
2393  zone = &(tzd_raw->zones[i]);
2394 
2395  free_and_init (zone->offset_rules);
2396 
2397  for (j = 0; j < zone->alias_count; j++)
2398  {
2399  if (zone->aliases[j] != NULL)
2400  {
2401  free_and_init (zone->aliases[j]);
2402  }
2403  }
2404  free_and_init (zone->aliases);
2405  }
2406 
2407  free_and_init (tzd_raw->zones);
2408  }
2409  if (tzd_raw->leap_sec != NULL)
2410  {
2411  free_and_init (tzd_raw->leap_sec);
2412  }
2413 }
2414 
2415 /*
2416  * tzc_check_links_raw_data () - go through TZ_RAW_DATA.links and check if
2417  * there is an actual link between two existing timezones
2418  * (both defined in zone.tab) which should share the same
2419  * time settings e.g. rules are defined for one timezone
2420  * but not the other.
2421  * Returns: 0 (NO_ERROR) if success, error code otherwise
2422  * tzd_raw(in/out): time zone bulk data structure to free
2423  *
2424  * NOTE: an example of such a link between two timezones is
2425  * 'Link Europe/Zurich Europe/Busingen'; Both zones are defined in
2426  * zone.tab, but GMT offset rules are defined only for Europe/Zurich;
2427  * in this case, the 'Link' described above is not a simple alias, but a
2428  * cloning rule.
2429  */
2430 static int
2432 {
2433  int err_status = NO_ERROR;
2434  int i, j, tz_name_index, tz_alias_index;
2435  TZ_RAW_LINK *tz_link;
2436  TZ_RAW_ZONE_INFO *tz_zone;
2437 
2438  for (i = 0; i < tzd_raw->link_count; i++)
2439  {
2440  tz_link = &(tzd_raw->links[i]);
2441  tz_name_index = -1;
2442  tz_alias_index = -1;
2443  for (j = 0; j < tzd_raw->zone_count && (tz_name_index == -1 || tz_alias_index == -1); j++)
2444  {
2445  tz_zone = &(tzd_raw->zones[j]);
2446  if (strcmp (tz_zone->full_name, tz_link->name) == 0)
2447  {
2448  tz_name_index = j;
2449  assert (tz_name_index != tz_alias_index);
2450  }
2451  if (strcmp (tz_zone->full_name, tz_link->alias) == 0)
2452  {
2453  tz_alias_index = j;
2454  assert (tz_name_index != tz_alias_index);
2455  }
2456  }
2457 
2458  if (tz_name_index != -1 && tz_alias_index != -1)
2459  {
2460  /* Both zone name and alias from this 'Link' rule are timezones; Check which one does not have any attached
2461  * rules and mark it as sharing the other one's rules */
2462  bool remove_link = false;
2463  tz_zone = &(tzd_raw->zones[tz_name_index]);
2464  if (tz_zone->offset_rule_count > 0)
2465  {
2466  assert (tzd_raw->zones[tz_alias_index].offset_rule_count == 0);
2467  strcpy (tzd_raw->zones[tz_alias_index].clone_of, tz_zone->full_name);
2468  remove_link = true;
2469  }
2470  else if (tzd_raw->zones[tz_alias_index].offset_rule_count > 0)
2471  {
2472  assert (tz_zone->offset_rule_count == 0);
2473  strcpy (tz_zone->clone_of, tzd_raw->zones[tz_alias_index].full_name);
2474  remove_link = true;
2475  }
2476  else
2477  {
2478  /* fatal error; can't have two fully defined timezones with a 'Link' rule defined between them */
2479  assert (false);
2480  err_status = TZC_ERR_LINKING_TRUE_ZONES;
2482  goto exit;
2483  }
2484  if (remove_link)
2485  {
2486  if (i < tzd_raw->link_count - 1)
2487  {
2488  tz_link = &(tzd_raw->links[i]);
2489  strcpy (tz_link->alias, tzd_raw->links[tzd_raw->link_count - 1].alias);
2490  strcpy (tz_link->name, tzd_raw->links[tzd_raw->link_count - 1].name);
2491  }
2492  if (tzd_raw->link_count > 1)
2493  {
2494  tz_link = (TZ_RAW_LINK *) realloc (tzd_raw->links, (tzd_raw->link_count - 1) * sizeof (TZ_RAW_LINK));
2495  if (tz_link == NULL)
2496  {
2497  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2498 
2499  sprintf (err_msg, "%d", tzd_raw->link_count - 1);
2500  err_status = TZC_ERR_OUT_OF_MEMORY;
2501  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_RAW_LINK");
2502  goto exit;
2503  }
2504  tzd_raw->links = tz_link;
2505  }
2506  else if (tzd_raw->link_count == 1)
2507  {
2508  assert (i == 0);
2509  free (tzd_raw->links);
2510  tzd_raw->links = NULL;
2511  }
2512  tzd_raw->link_count--;
2513  /* the element at index i changed, i needs to be decreased so the next loop will analyze the new link at
2514  * index i */
2515  if (i > 0)
2516  {
2517  i--;
2518  }
2519  }
2520  }
2521  }
2522 
2523 exit:
2524  return err_status;
2525 }
2526 
2527 /*
2528  * tzc_sort_raw_data () - perform some sorting on the information stored
2529  * inside the parameter of the TZ_RAW_DATA type
2530  * Returns:
2531  * tzd_raw(in/out): time zone bulk data structure to sort
2532  *
2533  * NOTE: tz_optimize_raw_data should be called immediately after or at the end
2534  * of the bulk data loader (timezone_load_data) in order to optimize the
2535  * loaded information for further operations. The most important
2536  * operation that requires optimized data is checking for differences
2537  * when compiling the timezone data library using another version of
2538  * IANA's timezone DB (newer or older) and properly identifying those
2539  * differences.
2540  */
2541 static void
2543 {
2544  int i;
2545  TZ_RAW_DS_RULESET *rs = NULL;
2546 
2547  /* sort countries by name */
2548  qsort (tzd_raw->countries, tzd_raw->country_count, sizeof (TZ_RAW_COUNTRY), comp_func_raw_countries);
2549 
2550  /* sort zones by name */
2551  qsort (tzd_raw->zones, tzd_raw->zone_count, sizeof (TZ_RAW_ZONE_INFO), comp_func_raw_zones);
2552 
2553  /* sort zone aliases by name (aliases = links & backward links) */
2554  qsort (tzd_raw->links, tzd_raw->link_count, sizeof (TZ_RAW_LINK), comp_func_raw_links);
2555 
2556  /* sort offset rules by date */
2557  for (i = 0; i < tzd_raw->zone_count; i++)
2558  {
2559  qsort (tzd_raw->zones[i].offset_rules, tzd_raw->zones[i].offset_rule_count, sizeof (TZ_RAW_OFFSET_RULE),
2561  }
2562 
2563  /* sort DS rulesets by name */
2564  qsort (tzd_raw->ds_rulesets, tzd_raw->ruleset_count, sizeof (TZ_RAW_DS_RULESET), comp_func_raw_ds_rulesets);
2565 
2566  /* sort DS rules (in each set) by starting year */
2567  for (i = 0; i < tzd_raw->ruleset_count; i++)
2568  {
2569  rs = &(tzd_raw->ds_rulesets[i]);
2570  qsort (rs->rules, rs->rule_count, sizeof (TZ_RAW_DS_RULE), comp_func_raw_ds_rules);
2571  }
2572 }
2573 
2574 /*
2575  * tzc_index_raw_data - index the information identified as being higher in
2576  * the hierarchy of the raw timezone data
2577  * Returns:
2578  * tzd_raw(in): raw time zone data to process
2579  */
2580 static void
2582 {
2583  int i;
2584 
2585  /* countries should have been already sorted with tz_sort_raw_data */
2586  for (i = 0; i < tzd_raw->country_count; i++)
2587  {
2588  tzd_raw->countries[i].id = i;
2589  tzd_raw->countries[i].is_used = true;
2590  }
2591  for (i = 0; i < tzd_raw->zone_count; i++)
2592  {
2593  tzd_raw->zones[i].id = i;
2594  tzd_raw->zones[i].clone_of_id = -1;
2595  }
2596 }
2597 
2598 /*
2599  * tzc_index_raw_data_w_static - index the information identified as being
2600  * higher in the hierarchy of the raw timezone data with
2601  * respect to the hardcoded ID arrays from timezone_list.c
2602  * Returns: 0 (NO_ERROR) if success, error code if something goes wrong
2603  * tzd_raw(in/out): raw time zone data to process
2604  * mode(in): control flag (type of activity to perform)
2605  *
2606  * NOTE: call this after tz_index_raw_data (which sorts the important data)
2607  */
2608 static int
2610 {
2611  int i, cur_id;
2612  int err_status = NO_ERROR;
2613 
2614  /* set all IDs to -1, and is_used to FALSE (where needed) */
2615  for (i = 0; i < tzd_raw->country_count; i++)
2616  {
2617  tzd_raw->countries[i].id = -1;
2618  tzd_raw->countries[i].is_used = false; /* explicitly initialize all */
2619  }
2620  for (i = 0; i < tzd_raw->zone_count; i++)
2621  {
2622  tzd_raw->zones[i].id = -1;
2623  tzd_raw->zones[i].clone_of_id = -1;
2624  }
2625  for (i = 0; i < tzd_raw->ruleset_count; i++)
2626  {
2627  tzd_raw->ds_rulesets[i].is_used = false; /* explicitly initialize all */
2628  }
2629 
2630  /* implementation */
2631  /* compute country IDs */
2632  cur_id = -1;
2633  for (i = 0; i < tzd_raw->country_count; i++)
2634  {
2635  if (cur_id < tzd_raw->countries[i].id)
2636  {
2637  cur_id = tzd_raw->countries[i].id;
2638  }
2639  }
2640  for (i = 0; i < tzd_raw->country_count; i++)
2641  {
2642  if (tzd_raw->countries[i].id == -1)
2643  {
2644  tzd_raw->countries[i].id = ++cur_id;
2645  }
2646  }
2647 
2648  /* compute timezone IDs, with respect to the existing tz ID list */
2649  cur_id = -1;
2650  for (i = 0; i < tzd_raw->zone_count; i++)
2651  {
2652  if (cur_id < tzd_raw->zones[i].id)
2653  {
2654  cur_id = tzd_raw->zones[i].id;
2655  }
2656  }
2657  /* leave IDs to -1 for zones not found in the predefined TIMEZONES array */
2658  for (i = 0; i < tzd_raw->zone_count; i++)
2659  {
2660  if (tzd_raw->zones[i].id == -1)
2661  {
2662  tzd_raw->zones[i].id = ++cur_id;
2663  }
2664  }
2665 
2666  return err_status;
2667 }
2668 
2669 /*
2670  * tzc_index_raw_subdata - compute indexes for rulesets and update ruleset_id
2671  * for offset rules (e.g. index the data not processed
2672  * by tzc_index_raw_data/tzc_index_raw_data_w_static)
2673  * Returns: 0 (NO_ERROR) if success, error code if something goes wrong
2674  * tzd_raw(in): raw time zone data to process
2675  * mode(in): control flag (type of activity to perform)
2676  *
2677  * NOTE: call this after tz_index_raw_data / tz_index_raw_subdata
2678  */
2679 static int
2681 {
2682  int i, j, found_id;
2683  int err_status = NO_ERROR;
2684  char *alias = NULL;
2685  char **temp_aliases = NULL;
2686 
2687  /* compute country_id for all timezones */
2688  for (i = 0; i < tzd_raw->zone_count; i++)
2689  {
2690  found_id = -1;
2691  for (j = 0; j < tzd_raw->country_count; j++)
2692  {
2693  if (!tzd_raw->countries[j].is_used)
2694  {
2695  continue;
2696  }
2697  if (strcmp (tzd_raw->zones[i].code, tzd_raw->countries[j].code) == 0)
2698  {
2699  found_id = tzd_raw->countries[j].id;
2700  break;
2701  }
2702  }
2703 
2704  tzd_raw->zones[i].country_id = found_id;
2705  }
2706 
2707  /* Match aliases to the corresponding timezones */
2708  for (i = 0; i < tzd_raw->link_count; i++)
2709  {
2710  TZ_RAW_ZONE_INFO *zone = NULL;
2711  TZ_RAW_LINK *link = &(tzd_raw->links[i]);
2712  /* search for the corresponding timezone */
2713  found_id = -1;
2714  alias = NULL;
2715 
2716  for (j = 0; j < tzd_raw->zone_count && alias == NULL; j++)
2717  {
2718  zone = &(tzd_raw->zones[j]);
2719  if (strcmp (link->alias, zone->full_name) == 0)
2720  {
2721  alias = link->name;
2722  break;
2723  }
2724  else if (strcmp (link->name, zone->full_name) == 0)
2725  {
2726  alias = link->alias;
2727  break;
2728  }
2729  }
2730 
2731  assert (alias != NULL);
2732 
2733  /* put the found alias into the corresponding TZ_RAW_ZONE_INFO */
2734  temp_aliases = (char **) realloc (zone->aliases, (zone->alias_count + 1) * sizeof (char *));
2735 
2736  if (temp_aliases == NULL)
2737  {
2738  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2739 
2740  sprintf (err_msg, "%d", zone->alias_count + 1);
2741  err_status = TZC_ERR_OUT_OF_MEMORY;
2742  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "char *");
2743  goto exit;
2744  }
2745 
2746  zone->aliases = temp_aliases;
2747  zone->aliases[zone->alias_count] = strdup (alias);
2748 
2749  if (zone->aliases[zone->alias_count] == NULL)
2750  {
2751  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2752 
2753  sprintf (err_msg, "%d", zone->alias_count + 1);
2754  err_status = TZC_ERR_OUT_OF_MEMORY;
2755  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "char *");
2756  goto exit;
2757  }
2758 
2759  zone->alias_count++;
2760  }
2761 
2762  /* for timezones which clone other time zone settings, compute cloned ID */
2763  for (i = 0; i < tzd_raw->zone_count; i++)
2764  {
2765  TZ_RAW_ZONE_INFO *zone = NULL;
2766  TZ_RAW_ZONE_INFO *zone_search = NULL;
2767  zone = &(tzd_raw->zones[i]);
2768  if (strlen (zone->clone_of) == 0)
2769  {
2770  continue;
2771  }
2772  /* search for the zone with the name zone->clone_of, and get its ID */
2773  for (j = 0; j < tzd_raw->zone_count; j++)
2774  {
2775  zone_search = &(tzd_raw->zones[j]);
2776  if (strcmp (zone->clone_of, zone_search->full_name) == 0)
2777  {
2778  zone->clone_of_id = zone_search->id;
2779  }
2780  }
2781  }
2782 
2783  if (mode == TZ_GEN_TYPE_UPDATE)
2784  {
2785  /* TODO: if a zone is renamed, create/update an alias for it, to keep the old name found in the predefined
2786  * TIMEZONE array */
2787  assert (false);
2788  }
2789  else
2790  {
2791  assert (mode == TZ_GEN_TYPE_NEW || mode == TZ_GEN_TYPE_EXTEND);
2792  /* do nothing */
2793  }
2794 
2795 exit:
2796  return err_status;
2797 }
2798 
2799 static int
2800 compare_ints (const void *a, const void *b)
2801 {
2802  if (*((int *) a) == *((int *) b))
2803  {
2804  return 0;
2805  }
2806  else if (*((int *) a) < *((int *) b))
2807  {
2808  return -1;
2809  }
2810 
2811  return 1;
2812 }
2813 
2814 /*
2815  * tzc_check_ds_ruleset - Checks the validity of the daylight saving time
2816  * ruleset
2817  * tzd(in): timezone data
2818  * ds_rule_set(in): day-light saving time ruleset
2819  * ds_changes_cnt(out): total number of daylight saving time changes between
2820  * the start year and the end year
2821  * Return: error or no error
2822  */
2823 static int
2824 tzc_check_ds_ruleset (const TZ_DATA * tzd, const TZ_DS_RULESET * ds_rule_set, int *ds_changes_cnt)
2825 {
2826 #define ABS(i) ((i) >= 0 ? (i) : -(i))
2827 #define MAX_DS_CHANGES_YEAR 1000
2828  int start_year, end_year, year;
2829  int i;
2830  int all_ds_changes_julian_date[MAX_DS_CHANGES_YEAR];
2831  int last_ds_change_julian_date;
2832 
2833  start_year = TZ_MAX_YEAR;
2834  end_year = 0;
2835  *ds_changes_cnt = 0;
2836 
2837  for (i = 0; i < ds_rule_set->count; i++)
2838  {
2839  TZ_DS_RULE *ds_rule;
2840 
2841  ds_rule = &(tzd->ds_rules[i + ds_rule_set->index_start]);
2842 
2843  if (ds_rule->from_year < start_year)
2844  {
2845  start_year = ds_rule->from_year;
2846  }
2847 
2848  if (ds_rule->to_year > end_year && ds_rule->to_year != TZ_MAX_YEAR)
2849  {
2850  end_year = ds_rule->to_year;
2851  }
2852  }
2853 
2854  if (end_year == 0)
2855  {
2856  end_year = start_year;
2857  }
2858  end_year = end_year + 1;
2859 
2860  if (end_year < 2038)
2861  {
2862  end_year = 2038;
2863  }
2864 
2865  /* check how many times a DS change occurs in a year */
2866  for (year = start_year; year < end_year; year++)
2867  {
2868  int count = 0;
2869 
2870  for (i = 0; i < ds_rule_set->count; i++)
2871  {
2872  TZ_DS_RULE *ds_rule;
2873  int ds_change_julian_date, first_day_year_julian, last_day_year_julian;
2874 
2875  ds_rule = &(tzd->ds_rules[i + ds_rule_set->index_start]);
2876 
2877  if (year >= ds_rule->from_year && year <= ds_rule->to_year)
2878  {
2879  count++;
2880  }
2881 
2882  if (year + 1 < ds_rule->from_year || year - 1 > ds_rule->to_year)
2883  {
2884  continue;
2885  }
2886 
2887  if ((year < ds_rule->from_year && ds_rule->in_month > TZ_MON_JAN)
2888  || (year > ds_rule->to_year && ds_rule->in_month < TZ_MON_DEC))
2889  {
2890  continue;
2891  }
2892 
2893  if (tz_get_ds_change_julian_date_diff (0, ds_rule, year, &ds_change_julian_date, NULL) != NO_ERROR)
2894  {
2895  return ER_FAILED;
2896  }
2897 
2898  assert (*ds_changes_cnt < MAX_DS_CHANGES_YEAR);
2899  all_ds_changes_julian_date[(*ds_changes_cnt)++] = ds_change_julian_date;
2900 
2901  first_day_year_julian = julian_encode (1, 1, year);
2902  last_day_year_julian = julian_encode (31, 12, year);
2903 
2904  if (ABS (ds_change_julian_date - first_day_year_julian) <= 1
2905  || ABS (ds_change_julian_date - last_day_year_julian) <= 1)
2906  {
2907  printf ("DS ruleset: %s, Year: %d, Change on : %s \n", ds_rule_set->ruleset_name, year,
2908  MONTH_NAMES_ABBREV[ds_rule->in_month]);
2909  }
2910  }
2911 
2912  if (count > 2)
2913  {
2914  printf ("DS ruleset: %s, Year: %d, found %d matching rules\n", ds_rule_set->ruleset_name, year, count);
2915  }
2916  }
2917 
2918  qsort (all_ds_changes_julian_date, *ds_changes_cnt, sizeof (int), compare_ints);
2919  last_ds_change_julian_date = all_ds_changes_julian_date[0];
2920  for (i = 1; i < *ds_changes_cnt; i++)
2921  {
2922  int date_diff;
2923  int month1, day1, year1;
2924  int month2, day2, year2;
2925 
2926  date_diff = all_ds_changes_julian_date[i] - last_ds_change_julian_date;
2927  assert (date_diff > 0);
2928 
2929  if (date_diff < 30)
2930  {
2931  julian_decode (last_ds_change_julian_date, &month1, &day1, &year1, NULL);
2932  julian_decode (all_ds_changes_julian_date[i], &month2, &day2, &year2, NULL);
2933  printf ("DS ruleset: %s, DS change after %d days, Date1: %d-%d-%d," "Date1: %d-%d-%d\n",
2934  ds_rule_set->ruleset_name, date_diff, day1, month1, year1, day2, month2, year2);
2935  }
2936  }
2937 
2938  printf ("Ruleset %s , total changes : %d (%d - %d)\n", ds_rule_set->ruleset_name, *ds_changes_cnt, start_year,
2939  end_year);
2940  return NO_ERROR;
2941 #undef ABS
2942 }
2943 
2944 /*
2945  * tzc_compile_data - process the raw data loaded from IANA's timezone
2946  * database files and put it into a TZ_DATA structure
2947  * to be later written into a compilable C file
2948  *
2949  * Returns: 0 (NO_ERROR) if success, error code if failure
2950  * tzd_raw(in): raw data to process
2951  * tzd(out): variable where to store the processed data
2952  */
2953 static int
2955 {
2956  int i, j, err_status = NO_ERROR;
2957  int alias_count, offset_rule_id;
2958 
2959  assert (tzd != NULL);
2960 
2961  /* countries */
2962  assert (tzd->countries == NULL);
2963  tzd->countries = (TZ_COUNTRY *) malloc (tzd_raw->country_count * sizeof (tzd->countries[0]));
2964  if (tzd->countries == NULL)
2965  {
2966  char err_msg[TZC_ERR_MSG_MAX_SIZE];
2967 
2968  sprintf (err_msg, "%d", tzd_raw->country_count);
2969  err_status = TZC_ERR_OUT_OF_MEMORY;
2970  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_COUNTRY");
2971  goto exit;
2972  }
2973  tzd->country_count = tzd_raw->country_count;
2974  memset (tzd->countries, 0, tzd->country_count * sizeof (tzd->countries[0]));
2975  for (i = 0; i < tzd->country_count; i++)
2976  {
2978 
2979  assert (tzd_raw->countries[i].id == i);
2980  tz_country = &(tzd->countries[i]);
2981 
2982  strcpy (tz_country->code, tzd_raw->countries[i].code);
2983  strcpy (tz_country->full_name, tzd_raw->countries[i].full_name);
2984  }
2985 
2986  err_status = tzc_compile_ds_rules (tzd_raw, tzd);
2987  if (err_status != NO_ERROR)
2988  {
2989  goto exit;
2990  }
2991 
2992  /* timezones and associated offset rules */
2993  tzd->timezones = NULL;
2994  tzd->timezone_names = NULL;
2995  tzd->names = NULL;
2996  tzd->timezone_count = tzd_raw->zone_count;
2997 
2998  tzd->timezones = (TZ_TIMEZONE *) malloc (tzd->timezone_count * sizeof (tzd->timezones[0]));
2999  if (tzd->timezones == NULL)
3000  {
3001  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3002 
3003  sprintf (err_msg, "%d", tzd->timezone_count);
3004  err_status = TZC_ERR_OUT_OF_MEMORY;
3005  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_TIMEZONE");
3006  goto exit;
3007  }
3008  memset (tzd->timezones, 0, tzd->timezone_count * sizeof (tzd->timezones[0]));
3009 
3010  /* count total number of offset rules */
3011  for (i = 0; i < tzd_raw->zone_count; i++)
3012  {
3013  tzd->offset_rule_count += tzd_raw->zones[i].offset_rule_count;
3014  }
3015 
3016  tzd->offset_rules = (TZ_OFFSET_RULE *) malloc (tzd->offset_rule_count * sizeof (tzd->offset_rules[0]));
3017  if (tzd->offset_rules == NULL)
3018  {
3019  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3020 
3021  sprintf (err_msg, "%d", tzd->offset_rule_count);
3022  err_status = TZC_ERR_OUT_OF_MEMORY;
3023  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_OFFSET_RULE");
3024  goto exit;
3025  }
3026  offset_rule_id = 0;
3027 
3028  memset (tzd->offset_rules, 0, tzd->offset_rule_count * sizeof (tzd->offset_rules[0]));
3029 
3030  for (i = 0; i < tzd_raw->zone_count; i++)
3031  {
3032  TZ_TIMEZONE *tz_zone = &(tzd->timezones[tzd_raw->zones[i].id]);
3033  TZ_RAW_ZONE_INFO *tz_raw_zone = &(tzd_raw->zones[i]);
3034 
3035  tz_zone->country_id = tz_raw_zone->country_id;
3036  tz_zone->zone_id = tz_raw_zone->id;
3037 
3038  tz_zone->gmt_off_rule_start = offset_rule_id;
3039  tz_zone->gmt_off_rule_count = tz_raw_zone->offset_rule_count;
3040 
3041  if (tz_zone->gmt_off_rule_count == 0)
3042  {
3043  /* if zone is an alias continue */
3044  if (tz_raw_zone->clone_of_id != -1)
3045  {
3046  continue;
3047  }
3048  /* else stop building the timezone library */
3049  else
3050  {
3051  err_status = TZC_ERR_INVALID_ZONE;
3052  TZC_LOG_ERROR_1ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_INVALID_ZONE, "Empty zone");
3053  goto exit;
3054  }
3055  }
3056 
3057  for (j = 0; j < tz_zone->gmt_off_rule_count; j++)
3058  {
3059  TZ_OFFSET_RULE *offrule = &(tzd->offset_rules[offset_rule_id]);
3060  TZ_RAW_OFFSET_RULE *raw_offrule = &(tz_raw_zone->offset_rules[j]);
3061 
3062  if (strstr (raw_offrule->format, "%s") != NULL)
3063  {
3064  offrule->var_format = strdup (raw_offrule->format);
3065  if (offrule->var_format == NULL)
3066  {
3067  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3068 
3069  sprintf (err_msg, "%d", strlen (raw_offrule->format));
3070  err_status = TZC_ERR_OUT_OF_MEMORY;
3071  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3072  goto exit;
3073  }
3074  offrule->std_format = NULL;
3075  offrule->save_format = NULL;
3076  }
3077  else
3078  {
3079  char *save_format;
3080 
3081  save_format = strchr (raw_offrule->format, '/');
3082  /* already checked by TZ parser */
3083  if (save_format != NULL)
3084  {
3085  *save_format = '\0';
3086  save_format++;
3087  }
3088 
3089  offrule->std_format = strdup (raw_offrule->format);
3090  if (offrule->std_format == NULL)
3091  {
3092  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3093 
3094  sprintf (err_msg, "%d", strlen (raw_offrule->format));
3095  err_status = TZC_ERR_OUT_OF_MEMORY;
3096  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3097  goto exit;
3098  }
3099 
3100  if (save_format != NULL)
3101  {
3102  offrule->save_format = strdup (save_format);
3103  if (offrule->save_format == NULL)
3104  {
3105  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3106 
3107  sprintf (err_msg, "%d", strlen (save_format));
3108  err_status = TZC_ERR_OUT_OF_MEMORY;
3109  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3110  goto exit;
3111  }
3112  }
3113  else
3114  {
3115  offrule->save_format = NULL;
3116  }
3117 
3118  offrule->var_format = NULL;
3119  }
3120 
3121  offrule->gmt_off = raw_offrule->gmt_off;
3122  offrule->until_flag = raw_offrule->until_flag;
3123  offrule->until_year = raw_offrule->until_year;
3124  offrule->until_mon = raw_offrule->until_mon;
3125  offrule->until_day = raw_offrule->until_day;
3126  offrule->until_hour = raw_offrule->until_hour;
3127  offrule->until_min = raw_offrule->until_min;
3128  offrule->until_sec = raw_offrule->until_sec;
3129  offrule->until_time_type = raw_offrule->until_time_type;
3130 
3131  /* seek ds ruleset metadata using string identifier raw-offrule->rules */
3132  offrule->ds_ruleset =
3134  if (offrule->ds_ruleset == -1)
3135  {
3136  const char *dummy = NULL;
3137  /* raw_offrule->rules is not an identifier of a ruleset; check if it is '-' or time offset */
3138  offrule->ds_type = DS_TYPE_FIXED;
3139  if (strcmp (raw_offrule->ds_ruleset_name, "-") == 0)
3140  {
3141  offrule->ds_ruleset = 0;
3142  }
3143  else if (tz_str_to_seconds (raw_offrule->ds_ruleset_name,
3144  raw_offrule->ds_ruleset_name + strlen (raw_offrule->ds_ruleset_name),
3145  &(offrule->ds_ruleset), &dummy, false) != NO_ERROR)
3146  {
3147  err_status = TZC_ERR_INVALID_TIME;
3148  goto exit;
3149  }
3150  }
3151  else
3152  {
3153  offrule->ds_type = DS_TYPE_RULESET_ID;
3154  }
3155  offset_rule_id++;
3156  }
3157  }
3158 
3159  /* check cloned zones and properly set their offset rule references; NOTE: this can be done only after exporting all
3160  * zones and offset rules */
3161  for (i = 0; i < tzd_raw->zone_count; i++)
3162  {
3163  TZ_TIMEZONE *tz_zone_clone = &(tzd->timezones[tzd_raw->zones[i].id]);
3164  TZ_TIMEZONE *tz_zone_original = NULL;
3165  TZ_RAW_ZONE_INFO *tz_raw_zone = &(tzd_raw->zones[i]);
3166 
3167  if (tz_raw_zone->clone_of_id == -1)
3168  {
3169  continue;
3170  }
3171 
3172  tz_zone_original = &(tzd->timezones[tz_raw_zone->clone_of_id]);
3173  tz_zone_clone->gmt_off_rule_start = tz_zone_original->gmt_off_rule_start;
3174  tz_zone_clone->gmt_off_rule_count = tz_zone_original->gmt_off_rule_count;
3175  }
3176 
3177  /* put aliases & timezone names into sorted arrays */
3178 
3179  /* build timezone_names */
3180  tzd->timezone_names = (char **) malloc (tzd->timezone_count * sizeof (tzd->timezone_names[0]));
3181  if (tzd->timezone_names == NULL)
3182  {
3183  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3184 
3185  sprintf (err_msg, "%d", tzd->timezone_count);
3186  err_status = TZC_ERR_OUT_OF_MEMORY;
3187  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "char *");
3188  goto exit;
3189  }
3190  memset (tzd->timezone_names, 0, tzd->timezone_count * sizeof (tzd->timezone_names[0]));
3191  for (i = 0; i < tzd_raw->zone_count; i++)
3192  {
3193  int zone_id = tzd_raw->zones[i].id;
3194  assert (!IS_EMPTY_STR (tzd_raw->zones[i].full_name));
3195  tzd->timezone_names[zone_id] = strdup (tzd_raw->zones[i].full_name);
3196  if (tzd->timezone_names[zone_id] == NULL)
3197  {
3198  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3199 
3200  sprintf (err_msg, "%d", strlen (tzd_raw->zones[i].full_name));
3201  err_status = TZC_ERR_OUT_OF_MEMORY;
3202  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3203  goto exit;
3204  }
3205  }
3206  /* build tzd->names */
3207  alias_count = 0;
3208  for (i = 0; i < tzd_raw->zone_count; i++)
3209  {
3210  alias_count += tzd_raw->zones[i].alias_count;
3211  }
3212  tzd->name_count = alias_count + tzd->timezone_count;
3213  tzd->names = (TZ_NAME *) malloc (tzd->name_count * sizeof (TZ_NAME));
3214  if (tzd->names == NULL)
3215  {
3216  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3217 
3218  sprintf (err_msg, "%d", tzd->name_count);
3219  err_status = TZC_ERR_OUT_OF_MEMORY;
3220  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_NAME");
3221  goto exit;
3222  }
3223  memset (tzd->names, 0, tzd->name_count * sizeof (tzd->names[0]));
3224  /* put timezone names first */
3225  for (i = 0; i < tzd->timezone_count; i++)
3226  {
3227  tzd->names[i].is_alias = 0;
3228  assert (tzd->timezones[i].zone_id == i);
3229  tzd->names[i].zone_id = i;
3230  tzd->names[i].name = strdup (tzd->timezone_names[i]);
3231  if (tzd->names[i].name == NULL)
3232  {
3233  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3234 
3235  sprintf (err_msg, "%d", strlen (tzd->timezone_names[i]));
3236  err_status = TZC_ERR_OUT_OF_MEMORY;
3237  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3238  goto exit;
3239  }
3240  }
3241 
3242  /* put aliases */
3243  offset_rule_id = tzd->timezone_count;
3244  for (i = 0; i < tzd_raw->zone_count; i++)
3245  {
3246  TZ_RAW_ZONE_INFO *tz_raw_zone = &(tzd_raw->zones[i]);
3247  if (tz_raw_zone->alias_count == 0)
3248  {
3249  continue;
3250  }
3251  for (j = 0; j < tz_raw_zone->alias_count; j++)
3252  {
3253  tzd->names[offset_rule_id].is_alias = 1;
3254  assert (tz_raw_zone->id != -1);
3255  tzd->names[offset_rule_id].zone_id = tz_raw_zone->id;
3256  assert (!IS_EMPTY_STR (tz_raw_zone->aliases[j]));
3257  tzd->names[offset_rule_id].name = strdup (tz_raw_zone->aliases[j]);
3258  if (tzd->names[offset_rule_id].name == NULL)
3259  {
3260  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3261 
3262  sprintf (err_msg, "%d", strlen (tz_raw_zone->aliases[j]));
3263  err_status = TZC_ERR_OUT_OF_MEMORY;
3264  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3265  goto exit;
3266  }
3267  offset_rule_id++;
3268  }
3269  }
3270  /* sort zone timezone names/aliases */
3271  qsort (tzd->names, tzd->name_count, sizeof (TZ_NAME), comp_func_tz_names);
3272 
3273  {
3274  int total_ds_changes = 0;
3275  int max_ds_changes = 0;
3276  for (i = 0; i < tzd->ds_ruleset_count; i++)
3277  {
3278  int ds_changes = 0;
3279  (void) tzc_check_ds_ruleset (tzd, &(tzd->ds_rulesets[i]), &ds_changes);
3280 
3281  if (ds_changes > max_ds_changes)
3282  {
3283  max_ds_changes = ds_changes;
3284  }
3285  total_ds_changes += ds_changes;
3286  }
3287  printf ("Total DS changes: %d; maximum changes in a ruleset :%d\n", total_ds_changes, max_ds_changes);
3288  }
3289 
3290  /* build leap second list */
3291  tzd->ds_leap_sec_count = tzd_raw->leap_sec_count;
3292  tzd->ds_leap_sec = (TZ_LEAP_SEC *) malloc (tzd->ds_leap_sec_count * sizeof (tzd->ds_leap_sec[0]));
3293 
3294  if (tzd->ds_leap_sec == NULL)
3295  {
3296  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3297 
3298  sprintf (err_msg, "%d", tzd->ds_leap_sec_count);
3299  err_status = TZC_ERR_OUT_OF_MEMORY;
3300  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_DS_LEAP_SEC *");
3301  goto exit;
3302  }
3303  memcpy (tzd->ds_leap_sec, tzd_raw->leap_sec, tzd_raw->leap_sec_count * sizeof (TZ_LEAP_SEC));
3304 exit:
3305  return err_status;
3306 }
3307 
3308 /*
3309  * tzc_compile_ds_rules() - take the raw daylight saving rules and place them
3310  * into the output TZ_DATA variable, from where they
3311  * will be later exported into a source file (to be
3312  * compiled into the timezone shared library/object)
3313  * Returns: 0(NO_ERROR) if success, error code otherwise
3314  * tzd_raw(in): raw data to process
3315  * tzd(out): variable where to store the processed data
3316  */
3317 static int
3319 {
3320  int err_status = NO_ERROR;
3321  int i, j, cur_rule_index = 0;
3322  TZ_DS_RULESET *ruleset;
3323  TZ_DS_RULE *rule;
3324  TZ_RAW_DS_RULE *rule_raw;
3325 
3326  assert (tzd->ds_rules == NULL);
3327  assert (tzd->ds_rulesets == NULL);
3328 
3329  /* compute total number of daylight saving rules */
3330  tzd->ds_rule_count = 0;
3331  for (i = 0; i < tzd_raw->ruleset_count; i++)
3332  {
3333  tzd->ds_rule_count += tzd_raw->ds_rulesets[i].rule_count;
3334  }
3335 
3336  tzd->ds_rules = (TZ_DS_RULE *) malloc (tzd->ds_rule_count * sizeof (TZ_DS_RULE));
3337  if (tzd->ds_rules == NULL)
3338  {
3339  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3340 
3341  sprintf (err_msg, "%d", tzd->ds_rule_count);
3342  err_status = TZC_ERR_OUT_OF_MEMORY;
3343  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_DS_RULE");
3344  goto exit;
3345  }
3346 
3347  /* alloc ruleset array */
3348  tzd->ds_ruleset_count = tzd_raw->ruleset_count;
3349  tzd->ds_rulesets = (TZ_DS_RULESET *) malloc (tzd->ds_ruleset_count * sizeof (TZ_DS_RULESET));
3350  if (tzd->ds_rulesets == NULL)
3351  {
3352  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3353 
3354  sprintf (err_msg, "%d", tzd->ds_ruleset_count);
3355  err_status = TZC_ERR_OUT_OF_MEMORY;
3356  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_DS_RULESET");
3357  goto exit;
3358  }
3359 
3360  memset (tzd->ds_rules, 0, tzd->ds_rule_count * sizeof (tzd->ds_rules[0]));
3361  memset (tzd->ds_rulesets, 0, tzd->ds_ruleset_count * sizeof (tzd->ds_rulesets[0]));
3362 
3363  for (i = 0; i < tzd->ds_ruleset_count; i++)
3364  {
3365  int to_year_max = 0;
3366  bool has_default_abbrev = true;
3367  const char *prev_letter_abbrev = NULL;
3368 
3369  ruleset = &(tzd->ds_rulesets[i]);
3370  ruleset->index_start = cur_rule_index;
3371  ruleset->count = tzd_raw->ds_rulesets[i].rule_count;
3372  ruleset->ruleset_name = strdup (tzd_raw->ds_rulesets[i].name);
3373  if (ruleset->ruleset_name == NULL)
3374  {
3375  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3376 
3377  sprintf (err_msg, "%d", strlen (tzd_raw->ds_rulesets[i].name));
3378  err_status = TZC_ERR_OUT_OF_MEMORY;
3379  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3380  goto exit;
3381  }
3382 
3383  for (j = 0; j < ruleset->count; j++)
3384  {
3385  rule = &(tzd->ds_rules[cur_rule_index]);
3386  rule_raw = &(tzd_raw->ds_rulesets[i].rules[j]);
3387 
3388  rule->at_time = rule_raw->at_time;
3389  rule->at_time_type = rule_raw->at_time_type;
3390  memcpy (&(rule->change_on), &(rule_raw->change_on), sizeof (TZ_DS_CHANGE_ON));
3391  rule->from_year = rule_raw->from_year;
3392  rule->in_month = rule_raw->in_month;
3393  rule->letter_abbrev = strdup (rule_raw->letter_abbrev);
3394  if (rule->letter_abbrev == NULL)
3395  {
3396  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3397 
3398  sprintf (err_msg, "%d", strlen (rule_raw->letter_abbrev));
3399  err_status = TZC_ERR_OUT_OF_MEMORY;
3400  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3401  goto exit;
3402  }
3403  if (has_default_abbrev == true && rule_raw->save_time == 0)
3404  {
3405  /* common single letter abbreviation having daylight save time zero (common standard time) */
3406  if (strlen (rule->letter_abbrev) > 1
3407  || (prev_letter_abbrev != NULL && strcmp (rule->letter_abbrev, prev_letter_abbrev) != 0))
3408  {
3409  has_default_abbrev = false;
3410  }
3411  else
3412  {
3413  prev_letter_abbrev = (char *) rule->letter_abbrev;
3414  }
3415  }
3416 
3417  rule->save_time = rule_raw->save_time;
3418  rule->to_year = rule_raw->to_year;
3419  if (rule->to_year > to_year_max)
3420  {
3421  to_year_max = rule->to_year;
3422  }
3423 
3424  cur_rule_index++;
3425  }
3426 
3427  const char empty[2] = { '-', 0 };
3428  if (has_default_abbrev == true && prev_letter_abbrev != NULL)
3429  {
3430  ruleset->default_abrev = strdup (prev_letter_abbrev);
3431  }
3432  else
3433  {
3434  prev_letter_abbrev = empty;
3435  ruleset->default_abrev = strdup (empty);
3436  }
3437  if (ruleset->default_abrev == NULL)
3438  {
3439  char err_msg[TZC_ERR_MSG_MAX_SIZE];
3440 
3441  sprintf (err_msg, "%d", strlen (prev_letter_abbrev));
3442  err_status = TZC_ERR_OUT_OF_MEMORY;
3443  TZC_LOG_ERROR_2ARG (TZC_CONTEXT (tzd_raw), TZC_ERR_OUT_OF_MEMORY, err_msg, "char");
3444  goto exit;
3445  }
3446  ruleset->to_year_max = to_year_max;
3447  }
3448 
3449 exit:
3450  return err_status;
3451 }
3452 
3453 /*
3454  * str_to_offset_rule_until() - parses a string representing the date (and
3455  * maybe time) until an offset rule was in effect, and
3456  * put the components into the corresponding members of
3457  * a TZ_OFFSET_RULE output parameter
3458  * Returns: 0 (NO_ERROR) if success, negative code if an error occurs
3459  * offset_rule(out): the offset rule where to save the date/time parts
3460  * str(in): string to parse
3461  * NOTE: str may be in the following forms: empty/NULL, "1912", "1903 Mar",
3462  * "1979 Oct 14", "1975 Nov 25 2:00".
3463  */
3464 static int
3466 {
3467  const char *str_cursor;
3468  const char *str_next;
3469  const char *str_end;
3470  int val_read = 0;
3471  int type = -1, day = -1, bound = -1;
3472  int hour = 0, min = 0, sec = 0;
3473  int err_status = NO_ERROR;
3474 
3475  assert (offset_rule != NULL);
3476 
3477  if (IS_EMPTY_STR (str))
3478  {
3479  offset_rule->until_flag = UNTIL_INFINITE;
3481  return NO_ERROR;
3482  }
3483 
3484  str_end = str + strlen (str);
3485 
3486  str_cursor = strtok (str, " ");
3487  if (tz_str_read_number (str_cursor, str_end, true, false, &val_read, &str_next) != NO_ERROR && val_read > 0
3488  && val_read < TZ_MAX_YEAR)
3489  {
3490  err_status = TZC_ERR_CANT_READ_VALUE;
3491  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "UNTIL (year)", str_cursor);
3492  goto exit;
3493  }
3494  else
3495  {
3496  offset_rule->until_year = (unsigned short) val_read;
3497  offset_rule->until_mon = 0;
3498  offset_rule->until_day = 0;
3499  offset_rule->until_hour = 0;
3500  offset_rule->until_min = 0;
3501  offset_rule->until_sec = 0;
3502  }
3503 
3504  offset_rule->until_flag = UNTIL_EXPLICIT;
3506 
3507  /* read month */
3508  str_cursor = strtok (NULL, " ");
3509  if (IS_EMPTY_STR (str_cursor))
3510  {
3511  /* no more tokens; exit with NO_ERROR */
3512  return NO_ERROR;
3513  }
3514  if (str_month_to_int (str_cursor, &val_read, &str_next) != NO_ERROR)
3515  {
3516  err_status = TZC_ERR_CANT_READ_VALUE;
3517  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "UNTIL month", str_cursor);
3518  goto exit;
3519  }
3520  if (val_read < TZ_MON_JAN || val_read > TZ_MON_DEC)
3521  {
3522  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3523 
3524  sprintf (temp_msg, "%d", val_read);
3525  err_status = TZC_ERR_INVALID_VALUE;
3526  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_VALUE, "UNTIL month value", temp_msg);
3527  goto exit;
3528  }
3529  offset_rule->until_mon = (unsigned char) val_read;
3530 
3531  /* read day of month */
3532  str_cursor = strtok (NULL, " ");
3533  if (IS_EMPTY_STR (str_cursor))
3534  {
3535  /* no more tokens; exit with NO_ERROR */
3536  err_status = NO_ERROR;
3537  goto exit;
3538  }
3539 
3540  /* Some offset rules have the column UNTIL='1992 Sep lastSat 23:00' or '2012 Apr Sun>=1 4:00', instead of a fixed
3541  * date/time value. This is a special case, and needs to be transformed into a fixed date. */
3542  err_status = str_read_day_var (str_cursor, offset_rule->until_mon, &type, &day, &bound, &str_next);
3543  if (err_status != NO_ERROR)
3544  {
3545  goto exit;
3546  }
3547  if (type == TZ_DS_TYPE_FIXED)
3548  {
3549  if (!tzc_is_valid_date (day, offset_rule->until_mon, offset_rule->until_year, offset_rule->until_year + 1))
3550  {
3551  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3552 
3553  sprintf (temp_msg, "Day: %d, Month: %d, Year: %d", day, offset_rule->until_mon, offset_rule->until_year);
3554  err_status = TZC_ERR_DS_INVALID_DATE;
3555  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "day of month (UNTIL)", temp_msg);
3556  goto exit;
3557  }
3558  }
3559  else if (type == TZ_DS_TYPE_VAR_GREATER)
3560  {
3561  int month_day = tz_get_first_weekday_around_date (offset_rule->until_year,
3562  offset_rule->until_mon, day, bound,
3563  false);
3564 
3565  if (!tzc_is_valid_date (month_day, offset_rule->until_mon, offset_rule->until_year, offset_rule->until_year + 1))
3566  {
3567  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3568 
3569  sprintf (temp_msg, "Day: %d, Month: %d, Year: %d", month_day, offset_rule->until_mon,
3570  offset_rule->until_year);
3571  err_status = TZC_ERR_DS_INVALID_DATE;
3572  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "day of month (UNTIL)", temp_msg);
3573  goto exit;
3574  }
3575 
3576  day = month_day;
3577  }
3578  else if (type == TZ_DS_TYPE_VAR_SMALLER)
3579  {
3580  int month_day;
3581 
3582  if (bound > 27)
3583  {
3584  int max_days_in_month;
3585 
3586  if (offset_rule->until_mon == TZ_MON_FEB)
3587  {
3588  max_days_in_month = (IS_LEAP_YEAR (offset_rule->until_year) ? 29 : 28);
3589  }
3590  else
3591  {
3592  max_days_in_month = DAYS_IN_MONTH (offset_rule->until_mon);
3593  }
3594 
3595  bound = max_days_in_month - 1;
3596  }
3597 
3598  month_day = tz_get_first_weekday_around_date (offset_rule->until_year, offset_rule->until_mon, day, bound, true);
3599 
3600  if (!tzc_is_valid_date (month_day, offset_rule->until_mon, offset_rule->until_year, offset_rule->until_year + 1))
3601  {
3602  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3603 
3604  sprintf (temp_msg, "Day: %d, Month: %d, Year: %d", month_day, offset_rule->until_mon,
3605  offset_rule->until_year);
3606  err_status = TZC_ERR_DS_INVALID_DATE;
3607  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "day of month (UNTIL)", temp_msg);
3608  goto exit;
3609  }
3610 
3611  day = month_day;
3612  }
3613  else
3614  {
3615  assert (false);
3616  err_status = TZC_ERR_DS_INVALID_DATE;
3617  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_DS_INVALID_DATE, "value for UNTIL", str);
3618  goto exit;
3619  }
3620  offset_rule->until_day = (unsigned char) day;
3621 
3622  /* read time */
3623  str_cursor = strtok (NULL, " ");
3624  if (IS_EMPTY_STR (str_cursor))
3625  {
3626  /* no more tokens; exit with NO_ERROR */
3627  err_status = NO_ERROR;
3628  goto exit;
3629  }
3630 
3631  if (tz_str_read_time (str_cursor, str_end, false, false, &hour, &min, &sec, &str_next) != NO_ERROR)
3632  {
3633  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3634 
3635  sprintf (temp_msg, "[hour: %d, min: %d, sec: %d]", hour, min, sec);
3636  err_status = TZC_ERR_INVALID_TIME;
3637  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_TIME, temp_msg, "UNTIL column");
3638  goto exit;
3639  }
3640 
3641  str_cursor = str_next;
3642  err_status = tzc_read_time_type (str_cursor, &str_cursor, &(offset_rule->until_time_type));
3643  if (err_status != NO_ERROR)
3644  {
3645  return err_status;
3646  }
3647 
3648  offset_rule->until_hour = (unsigned char) hour;
3649  offset_rule->until_min = (unsigned char) min;
3650  offset_rule->until_sec = (unsigned char) sec;
3651 
3652 exit:
3653  return err_status;
3654 }
3655 
3656 /*
3657  * str_month_to_int() - get the corresponding integer value of a 3 letter
3658  * month abbreviation
3659  * Returns: 0 (NO_ERROR) if success, error code otherwise
3660  * month(in): string to parse
3661  * month_num(out): numeric value for found month
3662  * str_next(out): char pointer to the remaining string after parsing month
3663  */
3664 static int
3665 str_month_to_int (const char *str_in, int *month_num, const char **str_next)
3666 {
3667  int i;
3668  const char *str;
3669 
3670  assert (!IS_EMPTY_STR (str_in));
3671 
3672  str = str_in;
3673 
3674  /* strip leading spaces and tabs */
3675  while (*str != '\0' && char_isspace (*str))
3676  {
3677  str++;
3678  }
3679 
3680  if (strlen (str) < (int) sizeof (MONTH_NAMES_ABBREV[0]) - 1)
3681  {
3682  /* not enough characters to work with; exit with error */
3683  return TZC_ERR_INVALID_VALUE;
3684  }
3685 
3686  for (i = 0; i < TZ_MON_COUNT; i++)
3687  {
3688  if (strncasecmp (MONTH_NAMES_ABBREV[i], str, sizeof (MONTH_NAMES_ABBREV[0]) - 1) == 0)
3689  {
3690  break;
3691  }
3692  }
3693  if (i >= TZ_MON_COUNT)
3694  {
3695  /* month abbreviation not valid, or an error occured */
3696  return TZC_ERR_INVALID_VALUE;
3697  }
3698 
3699  *month_num = i;
3700  *str_next = str + sizeof (MONTH_NAMES_ABBREV[0]) - 1;
3701 
3702  return NO_ERROR;
3703 }
3704 
3705 /*
3706  * str_day_to_int() - get the corresponding integer value of a 3 letter
3707  * week day abbreviation (0=Sunday, 6=Saturday)
3708  * Returns: negative code if error, 0 (NO_ERROR) if success
3709  * str_in(in): string to parse
3710  * day_num(out): numeric value for found day
3711  * str_next(out): char pointer to the remaining string after parsing day
3712  */
3713 static int
3714 str_day_to_int (const char *str_in, int *day_num, const char **str_next)
3715 {
3716  int i;
3717  const char *str;
3718  int err_status = NO_ERROR;
3719 
3720  assert (!IS_EMPTY_STR (str_in));
3721 
3722  str = str_in;
3723 
3724  /* skip leading spaces and tabs */
3725  while (*str != '\0' && char_isspace (*str))
3726  {
3727  str++;
3728  }
3729 
3730  if (strlen (str) < (int) sizeof (DAY_NAMES_ABBREV[0]) - 1)
3731  {
3732  /* not enough characters to work with; exit with error */
3733  *day_num = -1;
3734  err_status = TZC_ERR_INVALID_VALUE;
3735  goto exit;
3736  }
3737 
3738  for (i = 0; i < TZ_WEEK_DAY_COUNT; i++)
3739  {
3740  if (strncasecmp (DAY_NAMES_ABBREV[i], str, sizeof (DAY_NAMES_ABBREV[0]) - 1) == 0)
3741  {
3742  break;
3743  }
3744  }
3745  if (i >= TZ_WEEK_DAY_COUNT)
3746  {
3747  /* month abbreviation not valid, or an error occured; set day_num to -1 and exit with -1 */
3748  *day_num = -1;
3749  err_status = TZC_ERR_INVALID_VALUE;
3750  goto exit;
3751  }
3752 
3753  *day_num = i;
3754  *str_next = str + sizeof (DAY_NAMES_ABBREV[0]) - 1;
3755 
3756 exit:
3757 
3758  return err_status;
3759 }
3760 
3761 /*
3762  * str_read_day_var() - parse the input string as a specification for a day of
3763  * the month. The input string may be of the following
3764  * forms:
3765  * '21' (e.g. a day of the month)
3766 * 'lastFri' (e.g. 'lastWEEKDAY')
3767 * 'Sun>=1' (e.g. WEEKDAY>=NUMBER)
3768 *
3769  * Returns: 0(NO_ERROR) if success, error code otherwise
3770  * str(in): input string to parse
3771  * month(in): month in which this day is
3772  * type(out): type of bound (see enum TZ_DS_TYPE)
3773  * day(out): day value as numeric (0 based index value)
3774  * bound(out): numeric bound for day (0 based index value)
3775  * str_next(out): pointer to the remaining string after parsing the day rule
3776  */
3777 static int
3778 str_read_day_var (const char *str, const int month, int *type, int *day, int *bound, const char **str_next)
3779 {
3780  int err_status = NO_ERROR;
3781  int day_num;
3782  char str_last[5] = "last";
3783  const char *str_cursor;
3784  const char *str_end;
3785  const int days_of_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
3786 
3787  assert (str != NULL);
3788 
3789  *str_next = str;
3790 
3791  str_end = str + strlen (str);
3792 
3793  /* initialize output parameters */
3794  *type = -1;
3795  *day = -1;
3796  *bound = -1;
3797 
3798  /* try reading a number */
3799  if (tz_str_read_number (str, str_end, false, false, &day_num, str_next) != NO_ERROR)
3800  {
3801  err_status = TZC_ERR_CANT_READ_VALUE;
3802  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "day numeric", str);
3803  goto exit;
3804  }
3805  if (*str_next != str)
3806  {
3807  /* This is a fixed day of month, store it as such */
3808  *type = TZ_DS_TYPE_FIXED;
3809  *day = day_num - 1;
3810  goto exit;
3811  }
3812 
3813  /* no number was read; check if str starts with "last" */
3814  if (strncmp (str, str_last, strlen (str_last)) == 0)
3815  {
3816  str_cursor = str + strlen (str_last);
3817  if (str_day_to_int (str_cursor, &day_num, str_next) != NO_ERROR)
3818  {
3819  err_status = TZC_ERR_CANT_READ_VALUE;
3820  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "day string", str_cursor);
3821  goto exit;
3822  }
3823  if (day_num < TZ_WEEK_DAY_SUN || day_num > TZ_WEEK_DAY_SAT)
3824  {
3825  char temp_msg[TZC_ERR_MSG_MAX_SIZE] = { 0 };
3826 
3827  sprintf (temp_msg, "%d", day_num);
3828  err_status = TZC_ERR_INVALID_VALUE;
3829  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_INVALID_VALUE, "day string value", temp_msg);
3830  goto exit;
3831  }
3832  *type = TZ_DS_TYPE_VAR_SMALLER;
3833  *day = day_num;
3834  /* last valid month day from 0 - 30 */
3835  *bound = days_of_month[month] - 1;
3836 
3837  goto exit;
3838  }
3839 
3840  /* string was not a number, nor "last<Weekday>"; therefore it must be something like Sun>=3 */
3841  str_cursor = str;
3842  if (str_day_to_int (str_cursor, &day_num, &str_cursor) != NO_ERROR)
3843  {
3844  err_status = TZC_ERR_CANT_READ_VALUE;
3845  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "day string", str_cursor);
3846  goto exit;
3847  }
3848  assert (*(str_cursor + 1) == '=');
3849  if (*str_cursor == '>')
3850  {
3851  *type = TZ_DS_TYPE_VAR_GREATER;
3852  }
3853  else if (*str_cursor == '<')
3854  {
3855  *type = TZ_DS_TYPE_VAR_SMALLER;
3856  }
3857  else
3858  {
3859  assert (false);
3860  err_status = TZC_ERR_GENERIC;
3861  goto exit;
3862  }
3863 
3864  str_cursor += 2; /* skip the '>=' operator */
3865 
3866  *day = day_num;
3867  if (tz_str_read_number (str_cursor, str_end, true, false, &day_num, &str_cursor) != NO_ERROR)
3868  {
3869  err_status = TZC_ERR_CANT_READ_VALUE;
3870  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_CANT_READ_VALUE, "day string", str_cursor);
3871  goto exit;
3872  }
3873  *bound = day_num - 1;
3874 
3875 exit:
3876  return err_status;
3877 }
3878 
3879 /*
3880  * comp_func_raw_countries - comparison function between country entries, used
3881  * when optimizing TZ raw data
3882  * Returns: -1 if arg1<arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
3883  * arg1(in): first value to compare
3884  * arg2(in): second value to compare
3885  * Note: comparing two TZ_RAW_COUNTRY values means comparing their full_name
3886  * members.
3887  */
3888 static int
3889 comp_func_raw_countries (const void *arg1, const void *arg2)
3890 {
3891  TZ_RAW_COUNTRY *c1, *c2;
3892 
3893  assert (arg1 != NULL && arg2 != NULL);
3894 
3895  c1 = (TZ_RAW_COUNTRY *) arg1;
3896  c2 = (TZ_RAW_COUNTRY *) arg2;
3897 
3898  assert (!IS_EMPTY_STR (c1->full_name) && !IS_EMPTY_STR (c2->full_name));
3899 
3900  if (c1->id == -1 && c2->id == -1)
3901  {
3902  return strcmp (c1->full_name, c2->full_name);
3903  }
3904 
3905  assert (c1->id != c2->id);
3906 
3907  if (c1->id != -1 && c2->id != -1)
3908  {
3909  return (c1->id < c2->id) ? -1 : 1;
3910  }
3911 
3912  if (c1->id != -1)
3913  {
3914  return -1;
3915  }
3916 
3917  return 1;
3918 }
3919 
3920 /*
3921  * comp_func_raw_zones - comparison function between zone entries, used when
3922  * optimizing TZ raw data
3923  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
3924  * arg1(in): first value to compare
3925  * arg2(in): second value to compare
3926  * Note: comparing two TZ_RAW_ZONE_INFO values means comparing their full_name
3927  * members.
3928  */
3929 static int
3930 comp_func_raw_zones (const void *arg1, const void *arg2)
3931 {
3932  TZ_RAW_ZONE_INFO *zone1, *zone2;
3933 
3934  assert (arg1 != NULL && arg2 != NULL);
3935 
3936  zone1 = (TZ_RAW_ZONE_INFO *) arg1;
3937  zone2 = (TZ_RAW_ZONE_INFO *) arg2;
3938 
3939  assert (!IS_EMPTY_STR (zone1->full_name) && !IS_EMPTY_STR (zone2->full_name));
3940 
3941  if (zone1->id == -1 && zone2->id == -1)
3942  {
3943  return strcmp (zone1->full_name, zone2->full_name);
3944  }
3945 
3946  assert (zone1->id != zone2->id);
3947 
3948  if (zone1->id != -1 && zone2->id != -1)
3949  {
3950  return (zone1->id < zone2->id) ? -1 : 1;
3951  }
3952 
3953  if (zone1->id > -1)
3954  {
3955  return -1;
3956  }
3957 
3958  return 1;
3959 }
3960 
3961 /*
3962  * comp_func_raw_links - comparison function between link entries, used when
3963  * optimizing TZ raw data
3964  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
3965  * arg1(in): first value to compare
3966  * arg2(in): second value to compare
3967  * Note: comparing two TZ_RAW_ZONE_INFO values means comparing their alias
3968  * members. The TZ links need to be ordered by alias, not by the
3969  * full_name of the corresponding timezone.
3970  */
3971 static int
3972 comp_func_raw_links (const void *arg1, const void *arg2)
3973 {
3974  TZ_RAW_LINK *link1, *link2;
3975 
3976  assert (arg1 != NULL && arg2 != NULL);
3977 
3978  link1 = (TZ_RAW_LINK *) arg1;
3979  link2 = (TZ_RAW_LINK *) arg2;
3980 
3981  assert (!IS_EMPTY_STR (link1->alias) && !IS_EMPTY_STR (link2->alias));
3982 
3983  return strcmp (link1->alias, link2->alias);
3984 }
3985 
3986 /*
3987  * comp_func_raw_offset_rules - comparison function between offset rules, used
3988  * when optimizing TZ raw data
3989  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
3990  * arg1(in): first value to compare
3991  * arg2(in): second value to compare
3992  * Note: comparing two TZ_RAW_OFFSET_RULE values means comparing their ending
3993  * datetime value.
3994  */
3995 static int
3996 comp_func_raw_offset_rules (const void *arg1, const void *arg2)
3997 {
3998  TZ_RAW_OFFSET_RULE *rule1, *rule2;
3999  int r1_until, r2_until;
4000 
4001  assert (arg1 != NULL && arg2 != NULL);
4002 
4003  rule1 = (TZ_RAW_OFFSET_RULE *) arg1;
4004  rule2 = (TZ_RAW_OFFSET_RULE *) arg2;
4005 
4006  if (rule1->until_flag == UNTIL_INFINITE)
4007  {
4008  assert (rule2->until_flag != UNTIL_INFINITE);
4009  return 1;
4010  }
4011  else if (rule2->until_flag == UNTIL_INFINITE)
4012  {
4013  return -1;
4014  }
4015 
4016  r1_until = julian_encode (rule1->until_mon, rule1->until_day, rule1->until_year);
4017  r2_until = julian_encode (rule2->until_mon, rule2->until_day, rule2->until_year);
4018 
4019  if (r1_until == r2_until)
4020  {
4021  /* both dates are equal; compare time (reuse r1_until and r2_until we should not have two offset changes in the
4022  * same date */
4023  assert (false);
4024 
4025  r1_until = (rule1->until_hour * 60 + rule1->until_min) * 60 + rule1->until_sec;
4026  r2_until = (rule2->until_hour * 60 + rule2->until_min) * 60 + rule2->until_sec;
4027  }
4028 
4029  if (r1_until < r2_until)
4030  {
4031  return -1;
4032  }
4033  else if (r1_until > r2_until)
4034  {
4035  return 1;
4036  }
4037  assert (false); /* can't have two time-overlapping offset rules */
4038 
4039  return 0;
4040 }
4041 
4042 /*
4043  * comp_func_raw_ds_rulesets - comparison function between daylight saving
4044  * rulesets, used when optimizing TZ raw data.
4045  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
4046  * arg1(in): first value to compare
4047  * arg2(in): second value to compare
4048  * Note: comparing two TZ_RAW_DS_RULE_SET values means comparing their name
4049  * members.
4050  */
4051 static int
4052 comp_func_raw_ds_rulesets (const void *arg1, const void *arg2)
4053 {
4054  TZ_RAW_DS_RULESET *rs1, *rs2;
4055 
4056  assert (arg1 != NULL && arg2 != NULL);
4057 
4058  rs1 = (TZ_RAW_DS_RULESET *) arg1;
4059  rs2 = (TZ_RAW_DS_RULESET *) arg2;
4060 
4061  assert (!IS_EMPTY_STR (rs1->name) && !IS_EMPTY_STR (rs2->name));
4062 
4063  return strcmp (rs1->name, rs2->name);
4064 }
4065 
4066 /*
4067  * get_day_of_week_for_raw_rule - Returns the day in which the ds_rule applies
4068  *
4069  * Returns: the day
4070  * rule(in): daylight saving rule
4071  * year(in): year in which to apply rule
4072  */
4073 static int
4074 get_day_of_week_for_raw_rule (const TZ_RAW_DS_RULE * rule, const int year)
4075 {
4076  int ds_rule_day;
4077  int ds_rule_month = rule->in_month;
4078 
4079  if (rule->change_on.type == TZ_DS_TYPE_FIXED)
4080  {
4081  ds_rule_day = rule->change_on.day_of_month;
4082  }
4083  else
4084  {
4085  int ds_rule_weekday, day_month_bound;
4086  bool before = (rule->change_on.type == TZ_DS_TYPE_VAR_SMALLER) ? true : false;
4087 
4088  ds_rule_weekday = rule->change_on.day_of_week;
4089  day_month_bound = rule->change_on.day_of_month;
4090 
4091  ds_rule_day = tz_get_first_weekday_around_date (year, ds_rule_month, ds_rule_weekday, day_month_bound, before);
4092  }
4093 
4094  return ds_rule_day;
4095 }
4096 
4097 /*
4098  * comp_func_raw_ds_rules - comparison function between daylight saving
4099  * rules, used when optimizing TZ raw data.
4100  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
4101  * arg1(in): first value to compare
4102  * arg2(in): second value to compare
4103  * Note: comparing two TZ_RAW_DS_RULE values means comparing their starting
4104  * year.
4105  */
4106 static int
4107 comp_func_raw_ds_rules (const void *arg1, const void *arg2)
4108 {
4109  TZ_RAW_DS_RULE *rule1, *rule2;
4110  int day1, day2;
4111 
4112  assert (arg1 != NULL && arg2 != NULL);
4113 
4114  rule1 = (TZ_RAW_DS_RULE *) arg1;
4115  rule2 = (TZ_RAW_DS_RULE *) arg2;
4116 
4117  if (rule1->from_year < rule2->from_year)
4118  {
4119  return -1;
4120  }
4121  else if (rule1->from_year > rule2->from_year)
4122  {
4123  return 1;
4124  }
4125 
4126  if (rule1->in_month != rule2->in_month)
4127  {
4128  return rule1->in_month < rule2->in_month ? -1 : 1;
4129  }
4130 
4131  day1 = get_day_of_week_for_raw_rule (rule1, rule1->from_year);
4132  day2 = get_day_of_week_for_raw_rule (rule2, rule2->from_year);
4133 
4134  return day1 < day2 ? -1 : 1;
4135 }
4136 
4137 /*
4138  * comp_func_tz_names - comparison function between two TZ_NAME values
4139  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
4140  * arg1(in): first value to compare
4141  * arg2(in): second value to compare
4142  */
4143 static int
4144 comp_func_tz_names (const void *arg1, const void *arg2)
4145 {
4146  TZ_NAME *name1, *name2;
4147 
4148  assert (arg1 != NULL && arg2 != NULL);
4149 
4150  name1 = (TZ_NAME *) arg1;
4151  name2 = (TZ_NAME *) arg2;
4152 
4153  assert (!IS_EMPTY_STR (name1->name) && !IS_EMPTY_STR (name2->name));
4154 
4155  return strcmp (name1->name, name2->name);
4156 }
4157 
4158 /*
4159  * print_seconds_as_time_hms_var () - takes a signed number of seconds and
4160  * prints it to stdout in [-]hh:mm[:ss] format
4161  * Returns:
4162  * seconds(in): number of seconds to print as hh:mm[:ss]
4163  */
4164 static void
4166 {
4167  if (seconds < 0)
4168  {
4169  printf ("-");
4170  seconds = -seconds;
4171  }
4172  printf ("%02d", (int) (seconds / 3600));
4173  seconds %= 3600;
4174  printf (":%02d", (int) (seconds / 60));
4175  seconds %= 60;
4176  if (seconds > 0)
4177  {
4178  printf (":%02d", seconds);
4179  }
4180 }
4181 
4182 /*
4183  * tzc_get_timezones_dot_c_filepath () - get path to timezones.c file in the CUBRID install folder
4184  *
4185  * size (in) : maximum name size
4186  * timezones_dot_c_file_path (out) : output file path
4187  */
4188 static void
4189 tzc_get_timezones_dot_c_filepath (size_t size, char *timezones_dot_c_file_path)
4190 {
4191  char tz_cub_path[PATH_MAX] = { 0 };
4192 
4193  envvar_cubrid_dir (tz_cub_path, sizeof (tz_cub_path));
4194  tzc_build_filepath (timezones_dot_c_file_path, size, tz_cub_path, PATH_PARTIAL_TIMEZONES_FILE);
4195 }
4196 
4197 /*
4198  * tzc_export_timezone_dot_c () - saves all timezone data into a C source
4199  * file to be later compiled into a shared library
4200  * Returns: always NO_ERROR
4201  * tzd(in): timezone data
4202  * tz_C_filepath(in): timezones.c file path
4203  */
4204 static int
4205 tzc_export_timezone_dot_c (const TZ_DATA * tzd, const char *timezones_dot_c_filepath)
4206 {
4207  int err_status = NO_ERROR;
4208  TZ_OFFSET_RULE *offrule = NULL;
4209  int i;
4210  TZ_DS_RULE *rule = NULL;
4211  TZ_LEAP_SEC *leap_sec = NULL;
4212  FILE *fp;
4213 
4214  fp = fopen_ex (timezones_dot_c_filepath, "wt");
4215  if (fp == NULL)
4216  {
4217  err_status = TZC_ERR_GENERIC;
4218  goto exit;
4219  }
4220 
4221 #if defined(WINDOWS)
4222  fprintf (fp, "#include <stdio.h>\n");
4223 #else
4224  fprintf (fp, "#include <stddef.h>\n");
4225 #endif
4226  fprintf (fp, "#include \"timezone_lib_common.h\"\n\n");
4227 
4228  /* countries */
4229  fprintf (fp, "%s const int tz_country_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->country_count);
4230  fprintf (fp, "%s const TZ_COUNTRY tz_countries[] = {\n", SHLIB_EXPORT_PREFIX);
4231  for (i = 0; i < tzd->country_count; i++)
4232  {
4233  fprintf (fp, "\t{\"%s\", \"%s\"}%s\n", tzd->countries[i].code, tzd->countries[i].full_name,
4234  (i == tzd->country_count - 1) ? "" : ",");
4235  }
4236  fprintf (fp, "};\n\n");
4237 
4238  /* timezone names */
4239  fprintf (fp, "%s const char *tz_timezone_names[] = {\n", SHLIB_EXPORT_PREFIX);
4240  for (i = 0; i < tzd->timezone_count; i++)
4241  {
4242  fprintf (fp, "\t\"%s\"%s\n", tzd->timezone_names[i], (i == tzd->timezone_count - 1 ? "" : ","));
4243  }
4244  fprintf (fp, "};\n\n");
4245 
4246  /* timezones */
4247  fprintf (fp, "%s const int timezone_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->timezone_count);
4248  fprintf (fp, "%s const TZ_TIMEZONE timezones[] = {\n", SHLIB_EXPORT_PREFIX);
4249  for (i = 0; i < tzd->timezone_count; i++)
4250  {
4251  fprintf (fp, "\t{%d, %d, %d, %d}%s\n", tzd->timezones[i].zone_id, tzd->timezones[i].country_id,
4253  (i == tzd->timezone_count - 1) ? "" : ",");
4254  }
4255  fprintf (fp, "};\n\n");
4256 
4257  /* NOTE: timezone names are not exported into the shared library, but into a separate C file, to be included into
4258  * CUBRID */
4259 
4260  /* offset rule array */
4261  fprintf (fp, "%s const int offset_rule_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->offset_rule_count);
4262  fprintf (fp, "%s const TZ_OFFSET_RULE offset_rules[] = {\n", SHLIB_EXPORT_PREFIX);
4263  for (i = 0; i < tzd->offset_rule_count; i++)
4264  {
4265  int julian_date;
4266  offrule = &(tzd->offset_rules[i]);
4267 
4268  julian_date = julian_encode (1 + offrule->until_mon, 1 + offrule->until_day, offrule->until_year);
4269 
4270  fprintf (fp, "\t{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ", offrule->gmt_off, offrule->ds_ruleset,
4271  offrule->until_year, offrule->until_mon, offrule->until_day, offrule->until_hour, offrule->until_min,
4272  offrule->until_sec, offrule->until_time_type, offrule->until_flag, offrule->ds_type, julian_date);
4273 
4274  if (offrule->std_format == NULL)
4275  {
4276  fprintf (fp, "NULL, ");
4277  }
4278  else
4279  {
4280  fprintf (fp, "\"%s\", ", offrule->std_format);
4281  }
4282 
4283  if (offrule->save_format == NULL)
4284  {
4285  fprintf (fp, "NULL, ");
4286  }
4287  else
4288  {
4289  fprintf (fp, "\"%s\", ", offrule->save_format);
4290  }
4291 
4292  if (offrule->var_format == NULL)
4293  {
4294  fprintf (fp, "NULL }");
4295  }
4296  else
4297  {
4298  fprintf (fp, "\"%s\" }", offrule->var_format);
4299  }
4300 
4301  if (i < tzd->offset_rule_count - 1)
4302  {
4303  fprintf (fp, ",\n");
4304  }
4305  }
4306  fprintf (fp, "};\n\n");
4307 
4308  /* tz names (timezone names and aliases) */
4309  fprintf (fp, "%s const int tz_name_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->name_count);
4310  fprintf (fp, "%s const TZ_NAME tz_names[] = {\n", SHLIB_EXPORT_PREFIX);
4311  for (i = 0; i < tzd->name_count; i++)
4312  {
4313  fprintf (fp, "\t{%d, \"%s\", %d}%s\n", tzd->names[i].zone_id, tzd->names[i].name, tzd->names[i].is_alias,
4314  (i == tzd->name_count - 1) ? "" : ",");
4315  }
4316  fprintf (fp, "};\n\n");
4317 
4318  /* daylight saving rulesets */
4319  fprintf (fp, "%s const int ds_ruleset_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->ds_ruleset_count);
4320  fprintf (fp, "%s const TZ_DS_RULESET ds_rulesets[] = {\n", SHLIB_EXPORT_PREFIX);
4321  for (i = 0; i < tzd->ds_ruleset_count; i++)
4322  {
4323  fprintf (fp, "\t{%d, %d, \"%s\", %d, \"%s\"}%s\n", tzd->ds_rulesets[i].index_start, tzd->ds_rulesets[i].count,
4325  (i == tzd->ds_ruleset_count - 1) ? "" : ",");
4326  }
4327  fprintf (fp, "};\n\n");
4328 
4329  /* daylight saving rules */
4330  fprintf (fp, "%s const int ds_rule_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->ds_rule_count);
4331  fprintf (fp, "%s const TZ_DS_RULE ds_rules[] = {\n", SHLIB_EXPORT_PREFIX);
4332  for (i = 0; i < tzd->ds_rule_count; i++)
4333  {
4334  rule = &(tzd->ds_rules[i]);
4335  fprintf (fp, "\t{%d, %d, %d, {%d, %d, %d}, %d, %d, %d, \"%s\"}%s\n", rule->from_year, rule->to_year,
4336  rule->in_month, rule->change_on.type, rule->change_on.day_of_month, rule->change_on.day_of_week,
4337  rule->at_time, rule->at_time_type, rule->save_time, rule->letter_abbrev,
4338  (i == tzd->ds_rule_count - 1) ? "" : ",");
4339  }
4340  fprintf (fp, "};\n\n");
4341 
4342  /* leap seconds */
4343  fprintf (fp, "%s const int ds_leap_sec_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->ds_leap_sec_count);
4344  fprintf (fp, "%s const TZ_LEAP_SEC ds_leap_sec[] = {\n", SHLIB_EXPORT_PREFIX);
4345  for (i = 0; i < tzd->ds_leap_sec_count; i++)
4346  {
4347  leap_sec = &(tzd->ds_leap_sec[i]);
4348  fprintf (fp, "\t{%d, %d, %d, %d, %d}%s\n", leap_sec->year, leap_sec->month, leap_sec->day,
4349  leap_sec->corr_negative, leap_sec->is_rolling, (i == tzd->ds_leap_sec_count - 1) ? "" : ",");
4350  }
4351  fprintf (fp, "};\n\n");
4352 
4353 #if defined(WINDOWS)
4354  /* windows iana map */
4355  fprintf (fp, "%s const int windows_iana_map_count = %d;\n", SHLIB_EXPORT_PREFIX, tzd->windows_iana_map_count);
4356  fprintf (fp, "%s const TZ_WINDOWS_IANA_MAP windows_iana_map[] = {\n", SHLIB_EXPORT_PREFIX);
4357 
4358  for (i = 0; i < tzd->windows_iana_map_count; i++)
4359  {
4360  fprintf (fp, "\t{\"%s\", \"%s\", %d}%s\n", tzd->windows_iana_map[i].windows_zone,
4361  tzd->windows_iana_map[i].territory, tzd->windows_iana_map[i].iana_zone_id,
4362  (i == tzd->windows_iana_map_count - 1) ? "" : ",");
4363  }
4364  fprintf (fp, "};\n\n");
4365 #endif
4366 
4367  PRINT_STRING_VAR_TO_C_FILE (fp, "tz_timezone_checksum", tzd->checksum);
4368 
4369  if (fp)
4370  {
4371  fclose (fp);
4372  }
4373 
4374 exit:
4375  return err_status;
4376 }
4377 
4378 /*
4379  * tzc_get_ds_ruleset_by_name() - returns the ID/index of a ruleset having the
4380  * specified name
4381  * Returns: ID of the ruleset with the given name, or -1 if not found
4382  * tzd(in): time zone data where to search
4383  * ruleset(in): ruleset name to search for
4384  */
4385 static int
4386 tzc_get_ds_ruleset_by_name (const TZ_DS_RULESET * ds_rulesets, int ds_ruleset_count, const char *ruleset)
4387 {
4388  int ruleset_id = -1;
4389  int index_bot, index_top;
4390  int cmp_res;
4391 
4392  index_bot = 0;
4393  index_top = ds_ruleset_count - 1;
4394 
4395  while (index_bot <= index_top)
4396  {
4397  ruleset_id = (index_bot + index_top) / 2;
4398  cmp_res = strcmp (ruleset, ds_rulesets[ruleset_id].ruleset_name);
4399  if (cmp_res == 0)
4400  {
4401  return ruleset_id;
4402  }
4403  else if (cmp_res < 0)
4404  {
4405  index_top = ruleset_id - 1;
4406  }
4407  else
4408  {
4409  index_bot = ruleset_id + 1;
4410  }
4411  }
4412 
4413  return -1;
4414 }
4415 
4416 /*
4417  * tzc_get_timezone_aliases() - returns the list of names for a given timezone
4418  * Returns: ID of the ruleset with the given name, or -1 if not found
4419  * tzd(in): time zone data where to search
4420  * zone_id(in): timezone ID for which the aliases must be fetched
4421  * aliases(out): list of indexes of aliases/names for the given timezone ID
4422  * alias_count(out): number of aliases for the given timezone
4423  */
4424 static int
4425 tzc_get_timezone_aliases (const TZ_DATA * tzd, const int zone_id, int **aliases, int *alias_count)
4426 {
4427  int i, err_status = NO_ERROR;
4428  int *temp_array = NULL;
4429 
4430  assert (*aliases == NULL);
4431 
4432  *aliases = NULL;
4433  *alias_count = 0;
4434 
4435  for (i = 0; i < tzd->name_count; i++)
4436  {
4437  if (zone_id == tzd->names[i].zone_id && tzd->names[i].is_alias == 1)
4438  {
4439  /* name/alias found for the given timezone ID */
4440  temp_array = (int *) realloc (*aliases, ((*alias_count) + 1) * sizeof (int));
4441  if (temp_array == NULL)
4442  {
4443  char err_msg[TZC_ERR_MSG_MAX_SIZE];
4444 
4445  sprintf (err_msg, "%d", (*alias_count) + 1);
4446  err_status = TZC_ERR_OUT_OF_MEMORY;
4447  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "int");
4448  goto exit;
4449  }
4450  *aliases = temp_array;
4451  (*aliases)[*alias_count] = i;
4452  (*alias_count)++;
4453  }
4454  }
4455 
4456 exit:
4457  return err_status;
4458 }
4459 
4460 /*
4461  * tzc_dump_one_offset_rule () - dump a single offset rule
4462  * Returns:
4463  * offset_rule(in): the offset rule to dump
4464  */
4465 static void
4466 tzc_dump_one_offset_rule (const TZ_DATA * tzd, const TZ_OFFSET_RULE * offset_rule)
4467 {
4468  /* print GMTOFF column */
4469  print_seconds_as_time_hms_var (offset_rule->gmt_off);
4470 
4471  printf ("\t");
4472 
4473  /* print RULES column */
4474  if (offset_rule->ds_type == DS_TYPE_RULESET_ID)
4475  {
4476  assert (offset_rule->ds_ruleset >= 0 && offset_rule->ds_ruleset < tzd->ds_ruleset_count);
4477  printf ("%s", tzd->ds_rulesets[offset_rule->ds_ruleset].ruleset_name);
4478  }
4479  else
4480  {
4481  if (offset_rule->ds_ruleset == 0)
4482  {
4483  printf ("-");
4484  }
4485  else
4486  {
4488  }
4489  }
4490 
4491  /* print FORMAT column */
4492  if (offset_rule->var_format != NULL)
4493  {
4494  assert (offset_rule->std_format == NULL && offset_rule->save_format == NULL);
4495  printf ("\t%s", offset_rule->var_format);
4496  }
4497  else
4498  {
4499  assert (offset_rule->std_format != NULL);
4500  printf ("\t%s", offset_rule->std_format);
4501  if (offset_rule->save_format != NULL)
4502  {
4503  printf ("/%s", offset_rule->save_format);
4504  }
4505  }
4506 
4507  /* print UNTIL column */
4508  if (offset_rule->until_year != 0)
4509  {
4510  printf ("\t%d", offset_rule->until_year);
4511  if (offset_rule->until_mon != TZ_MON_COUNT)
4512  {
4513  printf (" %s", MONTH_NAMES_ABBREV[offset_rule->until_mon]);
4514  if (offset_rule->until_day != 0)
4515  {
4516  printf (" %d", offset_rule->until_day + 1);
4517  }
4518  }
4519  }
4520  printf ("\t");
4521 
4522  if (offset_rule->until_hour + offset_rule->until_min + offset_rule->until_sec > 0)
4523  {
4524  printf ("\t%02d:%02d", offset_rule->until_hour, offset_rule->until_min);
4525  if (offset_rule->until_sec > 0)
4526  {
4527  printf (":%02d", offset_rule->until_sec);
4528  }
4529  }
4530 }
4531 
4532 /*
4533  * tzc_dump_ds_ruleset () - dump daylight saving rules from a specified
4534  * ruleset
4535  * Returns:
4536  * tzd(in): loaded timezone data
4537  * ruleset_id(in): ID of the ruleset to dump
4538  */
4539 static void
4540 tzc_dump_ds_ruleset (const TZ_DATA * tzd, const int ruleset_id)
4541 {
4542  TZ_DS_RULESET *ruleset;
4543  TZ_DS_RULE *rule;
4544  int i, start_index, end_index;
4545 
4546  assert (ruleset_id >= 0 && ruleset_id < tzd->ds_ruleset_count);
4547 
4548  ruleset = &(tzd->ds_rulesets[ruleset_id]);
4549  printf ("\nDaylight saving ruleset : %s", ruleset->ruleset_name);
4550 
4551  start_index = ruleset->index_start;
4552  end_index = start_index + ruleset->count;
4553 
4554  for (i = start_index; i < end_index; i++)
4555  {
4556  rule = &(tzd->ds_rules[i]);
4557  /* print NAME and FROM columns */
4558  printf ("\nRule\t%s\t%d\t", ruleset->ruleset_name, rule->from_year);
4559  /* print TO column */
4560  if (rule->to_year == TZ_MAX_YEAR)
4561  {
4562  printf ("max\t");
4563  }
4564  else if (rule->to_year == rule->from_year)
4565  {
4566  printf ("only\t");
4567  }
4568  else
4569  {
4570  assert (rule->to_year > rule->from_year);
4571  printf ("%d\t", rule->to_year);
4572  }
4573  /* NOTE: TYPE column is '-' for all rules at this time, so we just print a '-' */
4574  printf ("-\t");
4575 
4576  /* print IN column */
4577  assert (rule->in_month < 12);
4578  printf ("%s\t", MONTH_NAMES_ABBREV[rule->in_month]);
4579 
4580  /* print ON column */
4581  switch (rule->change_on.type)
4582  {
4583  case TZ_DS_TYPE_FIXED:
4584  printf ("%d", rule->change_on.day_of_month + 1);
4585  break;
4587  printf ("%s>=%d", DAY_NAMES_ABBREV[rule->change_on.day_of_week], rule->change_on.day_of_month + 1);
4588  break;
4590  printf ("%s<=%d", DAY_NAMES_ABBREV[rule->change_on.day_of_week], rule->change_on.day_of_month + 1);
4591  break;
4592  default:
4593  assert (false);
4594  break;
4595  }
4596  printf ("\t");
4597 
4598  /* print AT column */
4600  printf ("\t");
4601 
4602  /* print SAVE column */
4604  printf ("\t");
4605 
4606  /* print LETTERS column */
4607  printf ("%s", rule->letter_abbrev);
4608  }
4609 }
4610 
4611 /*
4612  * tzc_dump_summary () - dump timezone general information
4613  * Returns:
4614  * tzd(in): timezone data
4615  */
4616 void
4618 {
4619  assert (tzd != NULL);
4620 
4621  printf ("\n Summary");
4622  printf ("\n No. of countries: %d", tzd->country_count);
4623  printf ("\n No. of timezones: %d", tzd->timezone_count);
4624  printf ("\n No. of aliases: %d", tzd->name_count - tzd->timezone_count);
4625  printf ("\n No. of offset rules: %d", tzd->offset_rule_count);
4626  printf ("\n No. of daylight saving rulesets: %d", tzd->ds_ruleset_count);
4627  printf ("\n No. of daylight saving rules: %d", tzd->ds_rule_count);
4628  printf ("\n No. of leap seconds: %d", tzd->ds_leap_sec_count);
4629 }
4630 
4631 /*
4632  * tzc_dump_countries () - dump the list of countries
4633  * Returns:
4634  * tzd(in): timezone data
4635  */
4636 void
4638 {
4639  int i;
4640 
4641  assert (tzd != NULL);
4642 
4643  for (i = 0; i < tzd->country_count; i++)
4644  {
4645  printf ("%s %s\n", tzd->countries[i].code, tzd->countries[i].full_name);
4646  }
4647 }
4648 
4649 /*
4650  * tzc_dump_timezones () - dump the list of timezones
4651  * Returns:
4652  * tzd(in): timezone data
4653  */
4654 void
4656 {
4657  int i;
4658 
4659  assert (tzd != NULL);
4660 
4661  for (i = 0; i < tzd->timezone_count; i++)
4662  {
4663  printf ("%5d. %s\n", i, tzd->timezone_names[i]);
4664  }
4665 }
4666 
4667 /*
4668  * tzc_dump_one_timezone () - dump all information related to a given timezone
4669  * Returns:
4670  * tzd(in): timezone data
4671  * zone_id(in): ID of the timezone for which to dump information
4672  */
4673 void
4674 tzc_dump_one_timezone (const TZ_DATA * tzd, const int zone_id)
4675 {
4676  int err_status = NO_ERROR;
4677  int i, j;
4678  int *zone_aliases = NULL;
4679  int *ds_rulesets_used = NULL;
4680  int count_ds_rulesets_used = 0;
4681  int *temp_int_array;
4682  int alias_count = 0, start_index = 0;
4683  bool is_first = true, found;
4684  TZ_TIMEZONE *zone = NULL;
4685  TZ_OFFSET_RULE *offset_rule = NULL;
4686 
4687  assert (tzd != NULL);
4688 
4689  printf (" Zone name: %s\n", tzd->timezone_names[zone_id]);
4690 
4691  err_status = tzc_get_timezone_aliases (tzd, zone_id, &zone_aliases, &alias_count);
4692 
4693  if (err_status != NO_ERROR)
4694  {
4695  goto exit;
4696  }
4697  if (alias_count > 0)
4698  {
4699  printf (" Aliases (%d): ", alias_count);
4700  }
4701  for (j = 0; j < alias_count; j++)
4702  {
4703  TZ_NAME *tz_name = &(tzd->names[zone_aliases[j]]);
4704 
4705  if (!is_first)
4706  {
4707  printf (", ");
4708  }
4709  else
4710  {
4711  is_first = false;
4712  }
4713  printf ("%s", tz_name->name);
4714  }
4715  if (alias_count > 0)
4716  {
4717  printf ("\n");
4718  }
4719 
4720  zone = &(tzd->timezones[zone_id]);
4721  start_index = zone->gmt_off_rule_start;
4722 
4723  /* dump offset rules, and also build the list of DS rulesets to be dumped */
4724  printf ("\n Offset rule index: %d, count: %d", zone->gmt_off_rule_start, zone->gmt_off_rule_count);
4725  if (zone->gmt_off_rule_count > 0)
4726  {
4727  printf ("\n Offset rules: \n");
4728  }
4729  for (i = 0; i < zone->gmt_off_rule_count; i++)
4730  {
4731  offset_rule = &(tzd->offset_rules[start_index + i]);
4732  tzc_dump_one_offset_rule (tzd, offset_rule);
4733  printf ("\n");
4734 
4735  if (offset_rule->ds_type == DS_TYPE_FIXED)
4736  {
4737  continue;
4738  }
4739 
4740  /* search for the ruleset id */
4741  found = false;
4742  for (j = 0; j < count_ds_rulesets_used && !found; j++)
4743  {
4744  if (ds_rulesets_used[j] == offset_rule->ds_ruleset)
4745  {
4746  found = true;
4747  }
4748  }
4749 
4750  if (!found)
4751  {
4752  temp_int_array =
4753  (int *) realloc (ds_rulesets_used, (count_ds_rulesets_used + 1) * sizeof (ds_rulesets_used[0]));
4754  if (temp_int_array == NULL)
4755  {
4756  printf ("\nOUT OF MEMORY!\n");
4757  goto exit;
4758  }
4759  ds_rulesets_used = temp_int_array;
4760  ds_rulesets_used[count_ds_rulesets_used] = offset_rule->ds_ruleset;
4761  count_ds_rulesets_used++;
4762  }
4763  }
4764 
4765  printf ("\n Found %d daylight saving ruleset(s) used by offset rules\n", count_ds_rulesets_used);
4766  for (i = 0; i < count_ds_rulesets_used; i++)
4767  {
4768  tzc_dump_ds_ruleset (tzd, ds_rulesets_used[i]);
4769  }
4770 
4771 exit:
4772  if (ds_rulesets_used != NULL)
4773  {
4774  free (ds_rulesets_used);
4775  }
4776  if (zone_aliases != NULL)
4777  {
4778  free (zone_aliases);
4779  }
4780 }
4781 
4782 /*
4783  * tzc_dump_leap_sec () - dump the list of leap seconds
4784  * Returns:
4785  * tzd(in): timezone data
4786  */
4787 void
4789 {
4790  int i;
4791  TZ_LEAP_SEC *leap_sec;
4792 
4793  assert (tzd != NULL);
4794 
4795  printf ("\n# Leap\tYEAR\tMONTH\tDAY\tHH:MM:SS\tCORR\tR/S\n");
4796 
4797  for (i = 0; i < tzd->ds_leap_sec_count; i++)
4798  {
4799  leap_sec = &(tzd->ds_leap_sec[i]);
4800  printf ("Leap\t%d\t%s\t%d\t%d:%d:%d\t%s\t%s\n", leap_sec->year, MONTH_NAMES_ABBREV[leap_sec->month],
4801  leap_sec->day, 23, 59, 60, (leap_sec->corr_negative ? "-" : "+"), (leap_sec->is_rolling ? "R" : "S"));
4802  }
4803 }
4804 
4805 /*
4806  * tzc_log_error () - log timezone compiler error
4807  * Returns:
4808  * context(in): timezone compiler error context
4809  * code(in): error code
4810  * msg1(in): first string replacement for error message
4811  * msg2(in): second string replacement for error message
4812  */
4813 static void
4814 tzc_log_error (const TZ_RAW_CONTEXT * context, const int code, const char *msg1, const char *msg2)
4815 {
4816  char err_msg[TZC_ERR_MSG_MAX_SIZE];
4817  char err_msg_temp[TZC_ERR_MSG_MAX_SIZE];
4818 
4819  assert (code <= 0 && -(code) < tzc_Err_message_count);
4820  *err_msg = '\0';
4821  *err_msg_temp = '\0';
4822 
4823  if (context != NULL && !IS_EMPTY_STR (context->current_file) && context->current_line != -1)
4824  {
4825  snprintf_dots_truncate (err_msg_temp, sizeof (err_msg_temp) - 1, " (file %s, line %d)", context->current_file,
4826  context->current_line);
4827  }
4828  strcat (err_msg, err_msg_temp);
4829 
4830  *err_msg_temp = '\0';
4831  snprintf_dots_truncate (err_msg_temp, sizeof (err_msg_temp), tzc_Err_messages[-code], msg1, msg2);
4832  strcat (err_msg, err_msg_temp);
4833  strcat (err_msg, "\n");
4834 
4836 }
4837 
4838 static void
4839 tzc_summary (TZ_RAW_DATA * tzd_raw, TZ_DATA * tzd)
4840 {
4841  int i, j;
4842  int max_len, temp_len;
4843  int max_len2, temp_len2;
4844  int max_len3;
4845 
4846  printf ("\n");
4847  printf (" COUNTRY MAX NAME LEN: ");
4848  max_len = 0;
4849  for (i = 0; i < tzd_raw->country_count; i++)
4850  {
4851  temp_len = strlen (tzd_raw->countries[i].full_name);
4852  if (temp_len > max_len)
4853  {
4854  max_len = temp_len;
4855  }
4856  }
4857  printf ("%d\n", max_len);
4858 
4859  printf (" DS RULES & RULESETS\n");
4860  max_len = 0;
4861  max_len2 = 0;
4862  for (i = 0; i < tzd_raw->ruleset_count; i++)
4863  {
4864  TZ_RAW_DS_RULESET *ds_ruleset = &(tzd_raw->ds_rulesets[i]);
4865 
4866  temp_len = strlen (ds_ruleset->name);
4867  if (temp_len > max_len)
4868  {
4869  max_len = temp_len;
4870  }
4871 
4872  for (j = 0; j < ds_ruleset->rule_count; j++)
4873  {
4874  TZ_RAW_DS_RULE *rule = &(ds_ruleset->rules[j]);
4875  temp_len = strlen (rule->letter_abbrev);
4876  if (temp_len > max_len2)
4877  {
4878  max_len2 = temp_len;
4879  }
4880  }
4881  }
4882  printf (" DS RULESET MAX NAME LEN: %d\n", max_len);
4883  printf (" DS RULE MAX LETTER_ABBREV LEN: %d\n\n", max_len2);
4884 
4885  printf (" TIMEZONE\n");
4886  max_len = 0;
4887  max_len2 = 0;
4888  max_len3 = 0;
4889  for (i = 0; i < tzd_raw->zone_count; i++)
4890  {
4891  temp_len = strlen (tzd_raw->zones[i].full_name);
4892  if (temp_len > max_len)
4893  {
4894  max_len = temp_len;
4895  }
4896  if (tzd_raw->zones[i].comments != NULL)
4897  {
4898  temp_len = strlen (tzd_raw->zones[i].comments);
4899  if (temp_len > max_len2)
4900  {
4901  max_len2 = temp_len;
4902  }
4903  }
4904  if (tzd_raw->zones[i].coordinates != NULL)
4905  {
4906  temp_len = strlen (tzd_raw->zones[i].coordinates);
4907  if (temp_len > max_len3)
4908  {
4909  max_len3 = temp_len;
4910  }
4911  }
4912  }
4913  printf (" MAX NAME LEN: %d", max_len);
4914  printf (" MAX comments LEN: %d", max_len2);
4915  printf (" MAX coordinates LEN: %d\n", max_len3);
4916 
4917  printf (" TZ_NAMES (timezone names and aliases) MAX NAME LEN: ");
4918  max_len = 0;
4919  for (i = 0; i < tzd->name_count; i++)
4920  {
4921  temp_len = strlen (tzd->names[i].name);
4922  if (temp_len > max_len)
4923  {
4924  max_len = temp_len;
4925  }
4926  }
4927  printf ("%d\n", max_len);
4928 
4929  printf (" TZ_RW_LINKS : \n");
4930  max_len = 0;
4931  max_len2 = 0;
4932  for (i = 0; i < tzd_raw->link_count; i++)
4933  {
4934  temp_len = strlen (tzd_raw->links[i].name);
4935  if (temp_len > max_len)
4936  {
4937  max_len = temp_len;
4938  }
4939  temp_len2 = strlen (tzd_raw->links[i].alias);
4940  if (temp_len2 > max_len2)
4941  {
4942  max_len2 = temp_len2;
4943  }
4944  }
4945  printf (" MAX NAME LEN: %d", max_len);
4946  printf (" MAX ALIAS LEN: %d\n", max_len2);
4947 
4948 
4949  printf (" TZ_RAW_OFFSET_RULES : \n");
4950  max_len = 0;
4951  max_len2 = 0;
4952  for (i = 0; i < tzd_raw->zone_count; i++)
4953  {
4954  TZ_RAW_ZONE_INFO *zone = &(tzd_raw->zones[i]);
4955  for (j = 0; j < zone->offset_rule_count; j++)
4956  {
4957  TZ_RAW_OFFSET_RULE *offrule = &(zone->offset_rules[j]);
4958 
4959  temp_len = strlen (offrule->ds_ruleset_name);
4960  if (temp_len > max_len)
4961  {
4962  max_len = temp_len;
4963  }
4964  temp_len = strlen (offrule->format);
4965  if (temp_len > max_len2)
4966  {
4967  max_len2 = temp_len;
4968  }
4969  }
4970  }
4971  printf (" MAX rules LEN: %d", max_len);
4972  printf (" MAX format LEN: %d\n", max_len2);
4973 }
4974 
4975 #if defined(WINDOWS)
4976 /*
4977  * comp_func_tz_windows_zones - comparison function between two
4978  * TZ_WINDOWS_IANA_MAP values
4979  * Returns: -1 if arg1 < arg2, 0 if arg1 = arg2, 1 if arg1 > arg2
4980  * arg1(in): first value to compare
4981  * arg2(in): second value to compare
4982  */
4983 static int
4984 comp_func_tz_windows_zones (const void *arg1, const void *arg2)
4985 {
4986  TZ_WINDOWS_IANA_MAP *map1, *map2;
4987  int ret;
4988 
4989  assert (arg1 != NULL && arg2 != NULL);
4990 
4991  map1 = (TZ_WINDOWS_IANA_MAP *) arg1;
4992  map2 = (TZ_WINDOWS_IANA_MAP *) arg2;
4993 
4995  && !IS_EMPTY_STR (map2->territory));
4996 
4997  ret = strcmp (map1->windows_zone, map2->windows_zone);
4998  if (ret != 0)
4999  {
5000  return ret;
5001  }
5002  return strcmp (map1->territory, map2->territory);
5003 }
5004 
5005 /*
5006  * xml_start_mapZone() - extracts from a mapZone tag the Windows timezone name
5007  * and IANA timezone name
5008  *
5009  * Returns: 0 parser OK, non-zero value if parser NOK
5010  * data(in): user data
5011  * attr(in): array of pairs for XML attribute and value (strings) of current
5012  * element
5013  */
5014 static int
5015 xml_start_mapZone (void *data, const char **attr)
5016 {
5017  XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
5018  TZ_DATA *tz = NULL;
5019  char *windows_zone = NULL;
5020  char *iana_zone = NULL;
5021  char *territory = NULL;
5022  TZ_WINDOWS_IANA_MAP *temp;
5023  int len_windows_zone;
5024  int len_territory;
5025  int iana_zone_id = -1;
5026  int i;
5027 
5028  assert (data != NULL);
5029  tz = (TZ_DATA *) XML_USER_DATA (pd);
5030 
5031  if (xml_get_att_value (attr, "other", &windows_zone) == 0 && xml_get_att_value (attr, "territory", &territory) == 0
5032  && xml_get_att_value (attr, "type", &iana_zone) == 0)
5033  {
5034  assert (windows_zone != NULL && territory != NULL && iana_zone != NULL);
5035 
5036  if (tz->windows_iana_map != NULL
5037  && strcmp (windows_zone, tz->windows_iana_map[tz->windows_iana_map_count - 1].windows_zone) == 0)
5038  {
5039  return 0;
5040  }
5041 
5042  temp =
5043  (TZ_WINDOWS_IANA_MAP *) realloc (tz->windows_iana_map,
5044  (tz->windows_iana_map_count + 1) * sizeof (TZ_WINDOWS_IANA_MAP));
5045  if (temp == NULL)
5046  {
5047  char err_msg[TZC_ERR_MSG_MAX_SIZE];
5048  sprintf (err_msg, "%d", tz->windows_iana_map_count + 1);
5049  TZC_LOG_ERROR_2ARG (NULL, TZC_ERR_OUT_OF_MEMORY, err_msg, "TZ_WINDOWS_IANA_MAP");
5050  return -1;
5051  }
5052 
5053  len_windows_zone = strlen (windows_zone);
5054  len_territory = strlen (territory);
5055  if (len_windows_zone > TZ_WINDOWS_ZONE_NAME_SIZE || len_territory > TZ_COUNTRY_CODE_SIZE)
5056  {
5057  TZC_LOG_ERROR_1ARG (NULL, TZC_ERR_INVALID_VALUE, "TZ_WINDOWS_IANA_MAP");
5058  if (temp != nullptr)
5059  {
5060  free (temp);
5061  }
5062  return -1;
5063  }
5064 
5065  memmove (temp[tz->windows_iana_map_count].windows_zone, windows_zone, len_windows_zone);
5066  temp[tz->windows_iana_map_count].windows_zone[len_windows_zone] = '\0';
5067  memmove (temp[tz->windows_iana_map_count].territory, territory, len_territory);
5068  temp[tz->windows_iana_map_count].territory[len_territory] = '\0';
5069 
5070  for (i = 0; i < tz->name_count; i++)
5071  {
5072  if (strcmp (iana_zone, tz->names[i].name) == 0)
5073  {
5074  iana_zone_id = tz->names[i].zone_id;
5075  break;
5076  }
5077  }
5078 
5079  temp[tz->windows_iana_map_count].iana_zone_id = iana_zone_id;
5080  tz->windows_iana_map = temp;
5081  tz->windows_iana_map_count++;
5082  return 0;
5083  }
5084  return 1;
5085 }
5086 
5087 /*
5088  * tzc_load_windows_iana_map() - loads the data from the file marked as
5089  * TZF_LIBC_IANA_ZONES_MAP
5090  *
5091  * Returns: 0 (NO_ERROR) if success, error code or -1 otherwise
5092  * tz_data(out): timezone data structure to hold the loaded information
5093  * input_folder(in): folder containing IANA's timezone database
5094  *
5095  */
5096 static int
5097 tzc_load_windows_iana_map (TZ_DATA * tz_data, const char *input_folder)
5098 {
5099  int err_status = NO_ERROR, i;
5100  char filepath[PATH_MAX] = { 0 };
5101  char str[TZ_MAX_LINE_LEN] = { 0 };
5102  XML_PARSER_DATA windows_zones_parser;
5103 
5104  assert (tz_data != NULL);
5105  assert (input_folder != NULL);
5106 
5107  for (i = 0; i < tz_File_count; i++)
5108  {
5109  if (tz_Files[i].type == TZF_WINDOWS_IANA_ZONES_MAP)
5110  {
5111  break;
5112  }
5113  }
5114 
5115  assert (i < tz_File_count);
5116  tzc_build_filepath (filepath, sizeof (filepath), input_folder, tz_Files[i].name);
5117 
5118  tz_data->windows_iana_map_count = 0;
5119  tz_data->windows_iana_map = NULL;
5120  windows_zones_parser.ud = tz_data;
5121 
5122  windows_zones_parser.xml_parser =
5123  xml_init_parser (&windows_zones_parser, filepath, "UTF-8", windows_zones_elements,
5124  sizeof (windows_zones_elements) / sizeof (XML_ELEMENT_DEF *));
5125 
5126  if (windows_zones_parser.xml_parser == NULL)
5127  {
5128  err_status = ER_TZ_COMPILE_ERROR;
5129  goto exit;
5130  }
5131 
5132  xml_parser_exec (&windows_zones_parser);
5133  /* sort windows zone names */
5134  qsort (tz_data->windows_iana_map, tz_data->windows_iana_map_count, sizeof (TZ_WINDOWS_IANA_MAP),
5135  comp_func_tz_windows_zones);
5136 
5137 exit:
5138  xml_destroy_parser (&windows_zones_parser);
5139  return err_status;
5140 }
5141 #endif
5142 
5143 /*
5144  * tzc_find_timezone_names() - returns 1 if the timezone name was found
5145  * or 0 otherwise
5146  * Returns: 1 if the timezone name was found or 0 otherwise
5147  * tzd(in): time zone data where to search
5148  * timezone_name(in): timezone name to search for
5149  */
5150 static int
5151 tzc_find_timezone_names (const TZ_DATA * tzd, const char *timezone_name)
5152 {
5153  int index_bot, index_top;
5154  int cmp_res;
5155 
5156  index_bot = 0;
5157  index_top = tzd->name_count - 1;
5158 
5159  while (index_bot <= index_top)
5160  {
5161  int mid = index_bot + (index_top - index_bot) / 2;
5162  cmp_res = strcmp (timezone_name, tzd->names[mid].name);
5163  if (cmp_res == 0)
5164  {
5165  return tzd->names[mid].zone_id;
5166  }
5167  else if (cmp_res < 0)
5168  {
5169  index_top = mid - 1;
5170  }
5171  else
5172  {
5173  index_bot = mid + 1;
5174  }
5175  }
5176 
5177  return -1;
5178 }
5179 
5180 /*
5181  * tzc_find_country_names() - returns 1 if the country name was found
5182  * or 0 otherwise
5183  * Returns: 1 if the country name was found or 0 otherwise
5184  * countries(in): vector of countries where to search
5185  * country_count(in): number of elements of countries vector
5186  * country_name (in) : name of the country to search for
5187  */
5188 static int
5189 tzc_find_country_names (const TZ_COUNTRY * countries, const int country_count, const char *country_name)
5190 {
5191  int index_bot, index_top;
5192  int cmp_res;
5193 
5194  index_bot = 0;
5195  index_top = country_count - 1;
5196 
5197  while (index_bot <= index_top)
5198  {
5199  int mid = index_bot + (index_top - index_bot) / 2;
5200 
5201  cmp_res = strcmp (country_name, countries[mid].full_name);
5202  if (cmp_res == 0)
5203  {
5204  return mid;
5205  }
5206  else if (cmp_res < 0)
5207  {
5208  index_top = mid - 1;
5209  }
5210  else
5211  {
5212  index_bot = mid + 1;
5213  }
5214  }
5215 
5216  return -1;
5217 }
5218 
5219 /*
5220  * comp_ds_rules() - equality function for two daylight saving rules
5221  *
5222  * Returns: true if the rules are identical or false otherwise
5223  * rule1(in): first daylight saving rule
5224  * rule2(in): second daylight saving rule
5225  */
5226 static bool
5227 comp_ds_rules (const TZ_DS_RULE * rule1, const TZ_DS_RULE * rule2)
5228 {
5229  if (rule1->at_time != rule2->at_time || rule1->change_on.day_of_month != rule2->change_on.day_of_month
5230  || rule1->change_on.day_of_week != rule2->change_on.day_of_week || rule1->change_on.type != rule2->change_on.type
5231  || rule1->from_year != rule2->from_year || rule1->to_year != rule2->to_year || rule1->in_month != rule2->in_month
5232  || rule1->save_time != rule2->save_time)
5233  {
5234  return false;
5235  }
5236  return true;
5237 }
5238 
5239 /*
5240  * comp_offset_rules() - equality function for two offset rules
5241  *
5242  * Returns: true if the rules are identical or false otherwise
5243  * rule1(in): first offset rule
5244  * rule2(in): second offset rule
5245  */
5246 static bool
5247 comp_offset_rules (const TZ_OFFSET_RULE * rule1, const TZ_OFFSET_RULE * rule2)
5248 {
5249  if (rule1->gmt_off != rule2->gmt_off || rule1->until_sec != rule2->until_sec || rule1->until_min != rule2->until_min
5250  || rule1->until_hour != rule2->until_hour || rule1->until_day != rule2->until_day
5251  || rule1->until_mon != rule2->until_mon || rule1->until_year != rule2->until_year)
5252  {
5253  return false;
5254  }
5255  return true;
5256 }
5257 
5258 /*
5259  * copy_offset_rule() - copies in dst the offset rule in tzd at position index
5260  * in the offset rule array
5261  *
5262  * Returns: error or no error
5263  * dst(in/out): destination offset rule
5264  * tzd(in): timezone data
5265  * index(in): index of the source offset rule in tzd
5266  */
5267 static int
5268 copy_offset_rule (TZ_OFFSET_RULE * dst, const TZ_DATA * tzd, const int index)
5269 {
5270  int err_status = NO_ERROR;
5271 
5272  *dst = tzd->offset_rules[index];
5273  dst->julian_date = julian_encode (1 + tzd->offset_rules[index].until_mon,
5274  1 + tzd->offset_rules[index].until_day, tzd->offset_rules[index].until_year);
5275  if (tzd->offset_rules[index].std_format != NULL)
5276  {
5277  DUPLICATE_STR (dst->std_format, tzd->offset_rules[index].std_format);
5278  }
5279  else
5280  {
5281  dst->std_format = NULL;
5282  }
5283 
5284  if (tzd->offset_rules[index].save_format != NULL)
5285  {
5286  DUPLICATE_STR (dst->save_format, tzd->offset_rules[index].save_format);
5287  }
5288  else
5289  {
5290  dst->save_format = NULL;
5291  }
5292 
5293  if (tzd->offset_rules[index].var_format != NULL)
5294  {
5295  DUPLICATE_STR (dst->var_format, tzd->offset_rules[index].var_format);
5296  }
5297  else
5298  {
5299  dst->var_format = NULL;
5300  }
5301 
5302 exit:
5303  return err_status;
5304 }
5305 
5306 /*
5307  * init_ds_ruleset() - initializes the members of dst_ruleset
5308  *
5309  * Returns: error or no error
5310  * dst_ruleset(in/out): destination ds ruleset
5311  * tzd(in): timezone data
5312  * index(in): index of the ds ruleset in the tzd ds_ruleset array
5313  * start(in): start of the ds ruleset
5314  */
5315 static int
5316 init_ds_ruleset (TZ_DS_RULESET * dst_ruleset, const TZ_DATA * tzd, const int index, const int start)
5317 {
5318  int err_status = NO_ERROR;
5319 
5320  dst_ruleset->count = tzd->ds_rulesets[index].count;
5321  DUPLICATE_STR (dst_ruleset->ruleset_name, tzd->ds_rulesets[index].ruleset_name);
5322  dst_ruleset->index_start = start;
5323  dst_ruleset->to_year_max = tzd->ds_rulesets[index].to_year_max;
5324  DUPLICATE_STR (dst_ruleset->default_abrev, tzd->ds_rulesets[index].default_abrev);
5325 
5326 exit:
5327  return err_status;
5328 }
5329 
5330 /*
5331  * copy_ds_rule() - copies in dst the daylight saving rule in tzd at
5332  * position index in the daylight saving rule array
5333  *
5334  * Returns: error or no error
5335  * dst(in/out): destination daylight saving rule
5336  * tzd(in): timezone data
5337  * index(in): index of the source daylight saving rule in tzd
5338  */
5339 static int
5340 copy_ds_rule (TZ_DS_RULE * dst, const TZ_DATA * tzd, const int index)
5341 {
5342  int err_status = NO_ERROR;
5343 
5344  *dst = tzd->ds_rules[index];
5345  if (tzd->ds_rules[index].letter_abbrev != NULL)
5346  {
5347  DUPLICATE_STR (dst->letter_abbrev, tzd->ds_rules[index].letter_abbrev);
5348  }
5349  else
5350  {
5351  dst->letter_abbrev = NULL;
5352  }
5353 
5354 exit:
5355  return err_status;
5356 }
5357 
5358 /*
5359  * tz_data_partial_clone() - copies timezone data from tzd into
5360  * the three data structures
5361  *
5362  * Returns: error or no error
5363  * timezone_names(in/out): timezone names without aliases
5364  * timezones(in/out): timezones
5365  * names(in/out): timezone names including aliases
5366  * tzd(in): timezone data
5367  */
5368 static int
5369 tz_data_partial_clone (char **timezone_names, TZ_TIMEZONE * timezones, TZ_NAME * names, const TZ_DATA * tzd)
5370 {
5371  int i, err_status = NO_ERROR;
5372 
5373  for (i = 0; i < tzd->timezone_count; i++)
5374  {
5375  DUPLICATE_STR (timezone_names[i], tzd->timezone_names[i]);
5376  }
5377 
5378  memcpy (timezones, tzd->timezones, tzd->timezone_count * sizeof (TZ_TIMEZONE));
5379 
5380  memcpy (names, tzd->names, tzd->name_count * sizeof (TZ_NAME));
5381  for (i = 0; i < tzd->name_count; i++)
5382  {
5383  DUPLICATE_STR (names[i].name, tzd->names[i].name);
5384  }
5385 
5386 exit:
5387  return err_status;
5388 }
5389 
5390 /*
5391  * init_tz_name() - copies the members of src into dst
5392  *
5393  * Returns: error or no error
5394  * dst(in/out): destination tz_name
5395  * src(in): source tz_name
5396  */
5397 static int
5399 {
5400  int err_status = NO_ERROR;
5401 
5402  dst->is_alias = src->is_alias;
5403  DUPLICATE_STR (dst->name, src->name);
5404  dst->zone_id = src->zone_id;
5405 
5406 exit:
5407  return err_status;
5408 }
5409 
5410 #if defined (SA_MODE)
5411 /*
5412  * tzc_extend() - Does a merge between the new timezone data and
5413  * the old timezone data in order to maintain backward
5414  * compatibility with the timezone data present in the
5415  * database. If the data could not be made backward
5416  * compatible a message is printed
5417  *
5418  * Returns: error or no error
5419  * tzd (in/out): new timezone library data that needs to be merged with
5420  * the old timezone library data
5421  */
5422 static int
5423 tzc_extend (TZ_DATA * tzd)
5424 {
5425  int err_status = NO_ERROR;
5426  TZ_DATA old_tzd;
5427  TZ_TIMEZONE *all_timezones = NULL, *timezones, *old_timezones;
5428  TZ_NAME *names, *all_names = NULL, *old_names;
5429  int i, j, k, l;
5430  int all_timezones_count = 0;
5431  int all_timezones_and_aliases_count = 0;
5432  char **all_timezone_names = NULL;
5433  int start_timezones, start_names, start;
5434  int gmt_off_rule_start, prev_gmt_off_rule_start;
5435  char *timezone_name;
5436  int zone_id;
5437  TZ_OFFSET_RULE *all_offset_rules = NULL;
5438  int all_offset_rule_count = 0;
5439  int start_gmt_old, start_gmt_new;
5440  int all_ds_ruleset_count = 0;
5441  int ruleset_id;
5442  char *mark_ruleset = NULL;
5443  TZ_DS_RULESET *all_ds_rulesets = NULL;
5444  int prev_start_ds_rule = 0, start_ds_rule = 0;
5445  TZ_DS_RULE *all_ds_rules = NULL;
5446  int all_ds_rule_count = 0;
5447  int comp_res;
5448  TZ_DATA *tzd_or_old_tzd = NULL;
5449  const char *ruleset_name;
5450  bool is_compat = true;
5451  int start_ds_ruleset_old = 0, start_ds_ruleset_new = 0;
5452  const TZ_DS_RULE *old_ds_rule = NULL;
5453  const TZ_DS_RULE *new_ds_rule = NULL;
5454  int all_country_count = 0;
5455  TZ_COUNTRY *all_countries = NULL;
5456  char *country_name = NULL;
5457  int country_id;
5458  int temp_zone_id;
5459  bool found_duplicate = false;
5460  OFFSET_RULE_INTERVAL *old_tzd_offset_rule_map = NULL;
5461  OFFSET_RULE_INTERVAL *tzd_offset_rule_map = NULL;
5462  int old_tzd_map_count = 0, tzd_map_count = 0;
5463  int find_idx = -1;
5464  int cnt;
5465  char timezone_library_path[PATH_MAX] = { 0 };
5466 
5467  /* First load the data structures from the old library and after that do the update */
5468 
5469  envvar_libdir_file (timezone_library_path, PATH_MAX, LIB_TZ_NAME);
5470 
5471  err_status = tz_load_with_library_path (&old_tzd, timezone_library_path);
5472  if (err_status != NO_ERROR)
5473  {
5474  goto exit;
5475  }
5476 
5477  names = tzd->names;
5478  for (i = 0; i < tzd->name_count; i++)
5479  {
5480  if (tzc_find_timezone_names (&old_tzd, names[i].name) == -1)
5481  {
5482  if (names[i].is_alias == 0)
5483  {
5484  all_timezones_count++;
5485  }
5486  all_timezones_and_aliases_count++;
5487  }
5488  }
5489  all_timezones_count += old_tzd.timezone_count;
5490  all_timezones_and_aliases_count += old_tzd.name_count;
5491 
5492  /* Count the number of new added countries */
5493  for (i = 0; i < tzd->country_count; i++)
5494  {
5495  int country_id = tzc_find_country_names (old_tzd.countries, old_tzd.country_count,
5496  tzd->countries[i].full_name);
5497 
5498  if (country_id == -1)
5499  {
5500  all_country_count++;
5501  }
5502  }
5503  all_country_count += old_tzd.country_count;
5504 
5505  all_countries = (TZ_COUNTRY *) calloc (all_country_count, sizeof (TZ_COUNTRY));
5506  if (all_countries == NULL)
5507  {
5508  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5509  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_country_count * sizeof (TZ_COUNTRY));
5510  goto exit;
5511  }
5512 
5513  all_timezone_names = (char **) calloc (all_timezones_count, sizeof (char *));
5514  if (all_timezone_names == NULL)
5515  {
5516  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5517  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_timezones_count * sizeof (char *));
5518  goto exit;
5519  }
5520 
5521  all_timezones = (TZ_TIMEZONE *) calloc (all_timezones_count, sizeof (TZ_TIMEZONE));
5522  if (all_timezones == NULL)
5523  {
5524  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5525  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_timezones_count * sizeof (TZ_TIMEZONE));
5526  goto exit;
5527  }
5528 
5529  all_names = (TZ_NAME *) calloc (all_timezones_and_aliases_count, sizeof (TZ_NAME));
5530  if (all_names == NULL)
5531  {
5532  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5533  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_timezones_and_aliases_count * sizeof (TZ_NAME));
5534  goto exit;
5535  }
5536 
5537  old_tzd_offset_rule_map = (OFFSET_RULE_INTERVAL *) calloc (old_tzd.timezone_count, sizeof (OFFSET_RULE_INTERVAL));
5538 
5539  if (old_tzd_offset_rule_map == NULL)
5540  {
5541  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5542  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, old_tzd.timezone_count * sizeof (OFFSET_RULE_INTERVAL));
5543  goto exit;
5544  }
5545 
5546  tzd_offset_rule_map = (OFFSET_RULE_INTERVAL *) calloc (tzd->timezone_count, sizeof (OFFSET_RULE_INTERVAL));
5547 
5548  if (tzd_offset_rule_map == NULL)
5549  {
5550  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5551  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, tzd->timezone_count * sizeof (OFFSET_RULE_INTERVAL));
5552  goto exit;
5553  }
5554 
5555  mark_ruleset = (char *) calloc (old_tzd.ds_ruleset_count, sizeof (char));
5556 
5557  if (mark_ruleset == NULL)
5558  {
5559  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5560  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, old_tzd.ds_ruleset_count * sizeof (char));
5561  goto exit;
5562  }
5563 
5564  err_status = tz_data_partial_clone (all_timezone_names, all_timezones, all_names, &old_tzd);
5565  if (err_status != NO_ERROR)
5566  {
5567  goto exit;
5568  }
5569 
5570  /* Add the new countries */
5571  i = 0, j = 0, k = 0;
5572  while (i < old_tzd.country_count && j < tzd->country_count)
5573  {
5574  comp_res = strcmp (old_tzd.countries[i].full_name, tzd->countries[j].full_name);
5575 
5576  if (comp_res == 0)
5577  {
5578  INIT_COUNTRY (&all_countries[k], &tzd->countries[j]);
5579  i++;
5580  j++;
5581  }
5582  else if (comp_res < 0)
5583  {
5584  INIT_COUNTRY (&all_countries[k], &old_tzd.countries[i]);
5585  i++;
5586  }
5587  else
5588  {
5589  INIT_COUNTRY (&all_countries[k], &tzd->countries[j]);
5590  j++;
5591  }
5592  k++;
5593  }
5594 
5595  while (i < old_tzd.country_count)
5596  {
5597  INIT_COUNTRY (&all_countries[k], &old_tzd.countries[i]);
5598  i++;
5599  k++;
5600  }
5601 
5602  while (j < tzd->country_count)
5603  {
5604  INIT_COUNTRY (&all_countries[k], &tzd->countries[j]);
5605  j++;
5606  k++;
5607  }
5608 
5609  assert (k == all_country_count);
5610 
5611  /* Add the new timezones */
5612  timezones = tzd->timezones;
5613  start_timezones = old_tzd.timezone_count;
5614  start_names = old_tzd.name_count;
5615 
5616  for (i = 0; i < tzd->name_count; i++)
5617  {
5618  zone_id = tzc_find_timezone_names (&old_tzd, names[i].name);
5619  if (zone_id == -1)
5620  {
5621  err_status = init_tz_name (&all_names[start_names], &names[i]);
5622  if (err_status != NO_ERROR)
5623  {
5624  goto exit;
5625  }
5626  if (names[i].is_alias == 0)
5627  {
5628  DUPLICATE_STR (all_timezone_names[start_timezones], names[i].name);
5629  all_timezones[start_timezones] = timezones[names[i].zone_id];
5630  all_timezones[start_timezones].zone_id = start_timezones;
5631  all_names[start_names].zone_id = start_timezones;
5632  start_timezones++;
5633  }
5634  start_names++;
5635  if (is_compat == true)
5636  {
5637  is_compat = false;
5638  }
5639  }
5640  }
5641 
5642  /* Now fix the zone ids for the alias timezones */
5643  for (i = old_tzd.name_count; i < all_timezones_and_aliases_count; i++)
5644  {
5645  if (all_names[i].is_alias == 1)
5646  {
5647  timezone_name = tzd->timezone_names[all_names[i].zone_id];
5648  zone_id = tzc_find_timezone_names (&old_tzd, timezone_name);
5649 
5650  if (zone_id != -1)
5651  {
5652  all_names[i].zone_id = zone_id;
5653  }
5654  /* We have an alias pointing to a new timezone */
5655  else
5656  {
5657  for (j = old_tzd.timezone_count; j < all_timezones_count; j++)
5658  {
5659  if (strcmp (timezone_name, all_timezone_names[j]) == 0)
5660  {
5661  all_names[i].zone_id = j;
5662  break;
5663  }
5664  }
5665  }
5666  }
5667  }
5668 
5669  for (i = 0; i < all_timezones_count; i++)
5670  {
5671  found_duplicate = false;
5672  zone_id = tzc_find_timezone_names (tzd, all_timezone_names[i]);
5673 
5674  if (zone_id == -1)
5675  {
5676  /* Go back and search for duplicate intervals in the old timezone library */
5677  for (j = i - 1; j >= 0; j--)
5678  {
5679  temp_zone_id = tzc_find_timezone_names (tzd, all_timezone_names[j]);
5680  if (temp_zone_id == -1 && all_timezones[i].gmt_off_rule_start == all_timezones[j].gmt_off_rule_start
5681  && all_timezones[i].gmt_off_rule_count == all_timezones[j].gmt_off_rule_count)
5682  {
5683  found_duplicate = true;
5684  break;
5685  }
5686  }
5687  if (found_duplicate == true)
5688  {
5689  continue;
5690  }
5691  all_offset_rule_count += all_timezones[i].gmt_off_rule_count;
5692  }
5693  else
5694  {
5695  /* Go back and search for duplicate intervals in the tzd timezone library */
5696  for (j = i - 1; j >= 0; j--)
5697  {
5698  temp_zone_id = tzc_find_timezone_names (tzd, all_timezone_names[j]);
5699 
5700  if (temp_zone_id != -1
5701  && timezones[zone_id].gmt_off_rule_start == timezones[temp_zone_id].gmt_off_rule_start
5702  && timezones[zone_id].gmt_off_rule_count == timezones[temp_zone_id].gmt_off_rule_count)
5703  {
5704  found_duplicate = true;
5705  break;
5706  }
5707  }
5708  if (found_duplicate == true)
5709  {
5710  continue;
5711  }
5712 
5713  all_offset_rule_count += timezones[zone_id].gmt_off_rule_count;
5714  }
5715  }
5716 
5717  all_offset_rules = (TZ_OFFSET_RULE *) calloc (all_offset_rule_count, sizeof (TZ_OFFSET_RULE));
5718  if (all_offset_rules == NULL)
5719  {
5720  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5721  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_offset_rule_count * sizeof (TZ_OFFSET_RULE));
5722  goto exit;
5723  }
5724 
5725  gmt_off_rule_start = 0;
5726 
5727  /* Add the new offset rules, fix the old ones and do a check for backward compatibility */
5728 
5729  /* Use the old_tzd_offset_rule_map and the tzd_offset_rule_map arrays to filter out duplicate offset rule intervals.
5730  * For each timezone we check if its offset rule interval was previously found. If it was, we use the mapped start of
5731  * the interval in the new timezone library. If not, we map the old start of the interval to the new one in the new
5732  * timezone library. */
5733 
5734  for (i = 0; i < all_timezones_count; i++)
5735  {
5736  prev_gmt_off_rule_start = gmt_off_rule_start;
5737  all_timezones[i].gmt_off_rule_start = gmt_off_rule_start;
5738  find_idx = -1;
5739  country_name = NULL;
5740  zone_id = tzc_find_timezone_names (tzd, all_timezone_names[i]);
5741 
5742  if (zone_id == -1)
5743  {
5744  if (old_tzd.timezones[i].country_id != -1)
5745  {
5746  country_name = old_tzd.countries[old_tzd.timezones[i].country_id].full_name;
5747  }
5748  start = old_tzd.timezones[i].gmt_off_rule_start;
5749  cnt = old_tzd.timezones[i].gmt_off_rule_count;
5750 
5751  for (j = 0; j < old_tzd_map_count; j++)
5752  {
5753  if (old_tzd_offset_rule_map[j].original_offset_rule_start == start
5754  && old_tzd_offset_rule_map[j].len == cnt)
5755  {
5756  find_idx = j;
5757  break;
5758  }
5759  }
5760 
5761  if (find_idx == -1)
5762  {
5763  old_tzd_offset_rule_map[old_tzd_map_count].original_offset_rule_start = start;
5764  old_tzd_offset_rule_map[old_tzd_map_count].len = cnt;
5765  old_tzd_offset_rule_map[old_tzd_map_count++].final_offset_rule_start = gmt_off_rule_start;
5766  gmt_off_rule_start += cnt;
5767  }
5768  else
5769  {
5770  all_timezones[i].gmt_off_rule_start = old_tzd_offset_rule_map[find_idx].final_offset_rule_start;
5771  }
5772  }
5773  else
5774  {
5775  if (tzd->timezones[zone_id].country_id != -1)
5776  {
5777  country_name = tzd->countries[tzd->timezones[zone_id].country_id].full_name;
5778  }
5779  all_timezones[i].gmt_off_rule_count = timezones[zone_id].gmt_off_rule_count;
5780  start = timezones[zone_id].gmt_off_rule_start;
5781  cnt = timezones[zone_id].gmt_off_rule_count;
5782 
5783  for (j = 0; j < tzd_map_count; j++)
5784  {
5785  if (tzd_offset_rule_map[j].original_offset_rule_start == start && tzd_offset_rule_map[j].len == cnt)
5786  {
5787  find_idx = j;
5788  break;
5789  }
5790  }
5791 
5792  if (find_idx == -1)
5793  {
5794  tzd_offset_rule_map[tzd_map_count].original_offset_rule_start = start;
5795  tzd_offset_rule_map[tzd_map_count].len = cnt;
5796  tzd_offset_rule_map[tzd_map_count++].final_offset_rule_start = gmt_off_rule_start;
5797  gmt_off_rule_start += cnt;
5798  }
5799  else
5800  {
5801  all_timezones[i].gmt_off_rule_start = tzd_offset_rule_map[find_idx].final_offset_rule_start;
5802  }
5803 
5804  if (i < old_tzd.timezone_count)
5805  {
5806  if (old_tzd.timezones[i].gmt_off_rule_count != timezones[zone_id].gmt_off_rule_count)
5807  {
5808  is_compat = false;
5809  }
5810  else
5811  {
5812  start_gmt_old = old_tzd.timezones[i].gmt_off_rule_start;
5813  start_gmt_new = tzd->timezones[zone_id].gmt_off_rule_start;
5814  for (j = start_gmt_old; j < start_gmt_old + old_tzd.timezones[i].gmt_off_rule_count; j++)
5815  {
5816  int tzd_offset_rule_idx = start_gmt_new + j - start_gmt_old;
5817 
5818  if (old_tzd.offset_rules[j].ds_type != tzd->offset_rules[tzd_offset_rule_idx].ds_type)
5819  {
5820  is_compat = false;
5821  break;
5822  }
5823 
5824  if (old_tzd.offset_rules[j].ds_type != DS_TYPE_FIXED)
5825  {
5826  if (strcmp (old_tzd.ds_rulesets[old_tzd.offset_rules[j].ds_ruleset].ruleset_name,
5827  tzd->ds_rulesets[tzd->offset_rules[tzd_offset_rule_idx].ds_ruleset].ruleset_name)
5828  != 0)
5829  {
5830  is_compat = false;
5831  break;
5832  }
5833  }
5834  else
5835  {
5836  if (old_tzd.offset_rules[j].ds_ruleset != tzd->offset_rules[tzd_offset_rule_idx].ds_ruleset)
5837  {
5838  is_compat = false;
5839  break;
5840  }
5841  }
5842  if (comp_offset_rules (&old_tzd.offset_rules[j], &tzd->offset_rules[tzd_offset_rule_idx]) ==
5843  false)
5844  {
5845  is_compat = false;
5846  break;
5847  }
5848  }
5849  }
5850  }
5851  }
5852 
5853  /* Fix the country ids in the new timezone vector */
5854  if (country_name != NULL)
5855  {
5856  country_id = tzc_find_country_names (all_countries, all_country_count, country_name);
5857  }
5858  else
5859  {
5860  country_id = -1;
5861  }
5862  all_timezones[i].country_id = country_id;
5863 
5864  if (find_idx == -1)
5865  {
5866  for (j = prev_gmt_off_rule_start; j < gmt_off_rule_start; j++)
5867  {
5868  int offset_rule_index = start + j - prev_gmt_off_rule_start;
5869  if (zone_id == -1)
5870  {
5871  err_status = copy_offset_rule (&all_offset_rules[j], &old_tzd, offset_rule_index);
5872 
5873  if (err_status != NO_ERROR)
5874  {
5875  goto exit;
5876  }
5877 
5878  if (old_tzd.offset_rules[offset_rule_index].ds_type != DS_TYPE_FIXED)
5879  {
5880  mark_ruleset[old_tzd.offset_rules[offset_rule_index].ds_ruleset] = 1;
5881  }
5882  }
5883  else
5884  {
5885  err_status = copy_offset_rule (&all_offset_rules[j], tzd, offset_rule_index);
5886  if (err_status != NO_ERROR)
5887  {
5888  goto exit;
5889  }
5890  }
5891  }
5892  }
5893  }
5894 
5895  for (i = 0; i < old_tzd.ds_ruleset_count; i++)
5896  {
5897  ruleset_id =
5899  if (ruleset_id == -1 && mark_ruleset[i] == 1)
5900  {
5901  all_ds_ruleset_count++;
5902  all_ds_rule_count += old_tzd.ds_rulesets[i].count;
5903  }
5904  }
5905  all_ds_ruleset_count += tzd->ds_ruleset_count;
5906  all_ds_rule_count += tzd->ds_rule_count;
5907 
5908  all_ds_rulesets = (TZ_DS_RULESET *) calloc (all_ds_ruleset_count, sizeof (TZ_DS_RULESET));
5909  if (all_ds_rulesets == NULL)
5910  {
5911  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5912  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_ds_ruleset_count * sizeof (TZ_DS_RULESET));
5913  goto exit;
5914  }
5915 
5916  all_ds_rules = (TZ_DS_RULE *) calloc (all_ds_rule_count, sizeof (TZ_DS_RULE));
5917  if (all_ds_rules == NULL)
5918  {
5919  err_status = ER_OUT_OF_VIRTUAL_MEMORY;
5920  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 1, all_ds_rule_count * sizeof (TZ_DS_RULE));
5921  goto exit;
5922  }
5923 
5924  /* Do a merge between old timezone library ds_rulesets and current timezone library */
5925 
5926  i = 0, j = 0, k = 0;
5927  while (i < old_tzd.ds_ruleset_count && j < tzd->ds_ruleset_count)
5928  {
5929  prev_start_ds_rule = start_ds_rule;
5930  tzd_or_old_tzd = NULL;
5931  comp_res = strcmp (old_tzd.ds_rulesets[i].ruleset_name, tzd->ds_rulesets[j].ruleset_name);
5932  if (comp_res == 0)
5933  {
5934  start_ds_rule += tzd->ds_rulesets[j].count;
5935  err_status = init_ds_ruleset (&all_ds_rulesets[k], tzd, j, prev_start_ds_rule);
5936  if (err_status != NO_ERROR)
5937  {
5938  goto exit;
5939  }
5940  tzd_or_old_tzd = tzd;
5941  start = tzd->ds_rulesets[j].index_start;
5942  if (old_tzd.ds_rulesets[i].count != tzd->ds_rulesets[j].count)
5943  {
5944  is_compat = false;
5945  }
5946  i++;
5947  j++;
5948  }
5949  else if (comp_res < 0)
5950  {
5951  if (mark_ruleset[i] == 1)
5952  {
5953  start_ds_rule += old_tzd.ds_rulesets[i].count;
5954  err_status = init_ds_ruleset (&all_ds_rulesets[k], &old_tzd, i, prev_start_ds_rule);
5955  if (err_status != NO_ERROR)
5956  {
5957  goto exit;
5958  }
5959  tzd_or_old_tzd = &old_tzd;
5960  start = old_tzd.ds_rulesets[i].index_start;
5961  }
5962  i++;
5963  }
5964  /* This is a new ruleset, we will set its index start later */
5965  else
5966  {
5967  err_status = init_ds_ruleset (&all_ds_rulesets[k], tzd, j, -tzd->ds_rulesets[j].index_start);
5968  if (err_status != NO_ERROR)
5969  {
5970  goto exit;
5971  }
5972  j++;
5973  }
5974  if (comp_res >= 0 || (comp_res < 0 && mark_ruleset[i - 1] == 1))
5975  {
5976  k++;
5977  }
5978 
5979  /* Now copy the daylight saving rules also and do backward compatibility checking */
5980  if (tzd_or_old_tzd != NULL)
5981  {
5982  if (comp_res == 0 && old_tzd.ds_rulesets[i - 1].count == tzd->ds_rulesets[j - 1].count)
5983  {
5984  start_ds_ruleset_old = old_tzd.ds_rulesets[i - 1].index_start;
5985  start_ds_ruleset_new = tzd->ds_rulesets[j - 1].index_start;
5986  }
5987  for (l = prev_start_ds_rule; l < start_ds_rule; l++)
5988  {
5989  err_status = copy_ds_rule (&all_ds_rules[l], tzd_or_old_tzd, start + l - prev_start_ds_rule);
5990  if (err_status != NO_ERROR)
5991  {
5992  goto exit;
5993  }
5994 
5995  /* Do backward compatibility checking */
5996  if (comp_res == 0 && old_tzd.ds_rulesets[i - 1].count == tzd->ds_rulesets[j - 1].count)
5997  {
5998  old_ds_rule = &old_tzd.ds_rules[start_ds_ruleset_old + l - prev_start_ds_rule];
5999  new_ds_rule = &tzd->ds_rules[start_ds_ruleset_new + l - prev_start_ds_rule];
6000  if (comp_ds_rules (old_ds_rule, new_ds_rule) == false)
6001  {
6002  is_compat = false;
6003  }
6004  }
6005  }
6006  }
6007  }
6008 
6009  /* Now copy the remaining rules */
6010  while (i < old_tzd.ds_ruleset_count)
6011  {
6012  prev_start_ds_rule = start_ds_rule;
6013 
6014  if (mark_ruleset[i] == 1)
6015  {
6016  start_ds_rule += old_tzd.ds_rulesets[i].count;
6017  err_status = init_ds_ruleset (&all_ds_rulesets[k], &old_tzd, i, prev_start_ds_rule);
6018  if (err_status != NO_ERROR)
6019  {
6020  goto exit;
6021  }
6022  start = old_tzd.ds_rulesets[i].index_start;
6023  k++;
6024  }
6025 
6026  for (l = prev_start_ds_rule; l < start_ds_rule; l++)
6027  {
6028  err_status = copy_ds_rule (&all_ds_rules[l], &old_tzd, start + l - prev_start_ds_rule);
6029  if (err_status != NO_ERROR)
6030  {
6031  goto exit;
6032  }
6033  }
6034  i++;
6035  }
6036 
6037  while (j < tzd->ds_ruleset_count)
6038  {
6039  err_status = init_ds_ruleset (&all_ds_rulesets[k], tzd, j, -tzd->ds_rulesets[j].index_start);
6040  if (err_status != NO_ERROR)
6041  {
6042  goto exit;
6043  }
6044  j++;
6045  k++;
6046  }
6047 
6048  /* Now copy the new daylight saving rules that were added in the current timezone library */
6049  assert (k == all_ds_ruleset_count);
6050  for (i = 0; i < all_ds_ruleset_count; i++)
6051  {
6052  if (all_ds_rulesets[i].index_start < 0)
6053  {
6054  prev_start_ds_rule = start_ds_rule;
6055  start = -all_ds_rulesets[i].index_start;
6056  all_ds_rulesets[i].index_start = prev_start_ds_rule;
6057  start_ds_rule += all_ds_rulesets[i].count;
6058 
6059  /* Now copy the new daylight saving rules to the end */
6060  for (j = prev_start_ds_rule; j < start_ds_rule; j++)
6061  {
6062  err_status = copy_ds_rule (&all_ds_rules[j], tzd, start + j - prev_start_ds_rule);
6063  if (err_status != NO_ERROR)
6064  {
6065  goto exit;
6066  }
6067  }
6068  }
6069  }
6070 
6071  /* Now we need to fix the ds_ruleset index in the offset rules */
6072  for (i = 0; i < all_timezones_count; i++)
6073  {
6074  zone_id = tzc_find_timezone_names (tzd, all_timezone_names[i]);
6075 
6076  if (zone_id == -1)
6077  {
6078  start = old_tzd.timezones[i].gmt_off_rule_start;
6079  tzd_or_old_tzd = &old_tzd;
6080  }
6081  else
6082  {
6083  start = timezones[zone_id].gmt_off_rule_start;
6084  tzd_or_old_tzd = tzd;
6085  }
6086 
6087  for (j = 0; j < all_timezones[i].gmt_off_rule_count; j++)
6088  {
6089  int tzd_or_old_tzd_ds_ruleset = tzd_or_old_tzd->offset_rules[start + j].ds_ruleset;
6090 
6091  if (tzd_or_old_tzd->offset_rules[start + j].ds_type != DS_TYPE_FIXED)
6092  {
6093  ruleset_name = tzd_or_old_tzd->ds_rulesets[tzd_or_old_tzd_ds_ruleset].ruleset_name;
6094  }
6095  else
6096  {
6097  ruleset_name = NULL;
6098  }
6099 
6100  if (ruleset_name != NULL)
6101  {
6102  ruleset_id = tzc_get_ds_ruleset_by_name (all_ds_rulesets, all_ds_ruleset_count, ruleset_name);
6103  all_offset_rules[all_timezones[i].gmt_off_rule_start + j].ds_ruleset = ruleset_id;
6104  }
6105  }
6106  }
6107 
6108  qsort (all_names, all_timezones_and_aliases_count, sizeof (TZ_NAME), comp_func_tz_names);
6109 
6110 exit:
6111  /* Free all data structures except for the windows zone map data structure and the leap seconds array */
6112 
6113  tzc_free_tz_data (tzd, false);
6114  if (mark_ruleset != NULL)
6115  {
6116  free_and_init (mark_ruleset);
6117  }
6118  if (old_tzd_offset_rule_map != NULL)
6119  {
6120  free_and_init (old_tzd_offset_rule_map);
6121  }
6122  if (tzd_offset_rule_map != NULL)
6123  {
6124  free_and_init (tzd_offset_rule_map);
6125  }
6126 
6127  /* Now use the new data structures */
6128  tzd->countries = all_countries;
6129  tzd->country_count = all_country_count;
6130  tzd->timezone_names = all_timezone_names;
6131  tzd->timezones = all_timezones;
6132  tzd->timezone_count = all_timezones_count;
6133  tzd->names = all_names;
6134  tzd->name_count = all_timezones_and_aliases_count;
6135  tzd->offset_rules = all_offset_rules;
6136  tzd->offset_rule_count = all_offset_rule_count;
6137  tzd->ds_rulesets = all_ds_rulesets;
6138  tzd->ds_ruleset_count = all_ds_ruleset_count;
6139  tzd->ds_rules = all_ds_rules;
6140  tzd->ds_rule_count = all_ds_rule_count;
6141 
6142  if (err_status == NO_ERROR)
6143  {
6144  old_names = old_tzd.names;
6145  old_timezones = old_tzd.timezones;
6146  names = tzd->names;
6147  timezones = tzd->timezones;
6148 
6149  for (i = 0; i < ZONE_MAX; i++)
6150  {
6151  tz_Is_backward_compatible_timezone[i] = true;
6152  }
6153 
6154  for (i = 0; i < old_tzd.name_count; i++)
6155  {
6156  int tzd_zone_id;
6157  int old_start, old_count;
6158  int new_start, new_count;
6159 
6160  tzd_zone_id = tzc_find_timezone_names (tzd, old_names[i].name);
6161 
6162  /* This should not ever happen */
6163  assert (tzd_zone_id != -1);
6164 
6165  if (old_timezones[old_names[i].zone_id].gmt_off_rule_count != timezones[tzd_zone_id].gmt_off_rule_count)
6166  {
6167  tz_Is_backward_compatible_timezone[i] = false;
6168  continue;
6169  }
6170 
6171  old_start = old_timezones[old_names[i].zone_id].gmt_off_rule_start;
6172  new_start = timezones[tzd_zone_id].gmt_off_rule_start;
6173  old_count = old_timezones[old_names[i].zone_id].gmt_off_rule_count;
6174  new_count = timezones[tzd_zone_id].gmt_off_rule_count;
6175 
6176  for (j = old_start, k = new_start; j < old_start + old_count && k < new_start + new_count; j++, k++)
6177  {
6178  TZ_OFFSET_RULE rule1, rule2;
6179 
6180  rule1 = old_tzd.offset_rules[j];
6181  rule2 = tzd->offset_rules[k];
6182 
6183  if (rule1.ds_type != rule2.ds_type)
6184  {
6185  tz_Is_backward_compatible_timezone[i] = false;
6186  break;
6187  }
6188 
6189  if (comp_offset_rules (&rule1, &rule2) == false)
6190  {
6191  tz_Is_backward_compatible_timezone[i] = false;
6192  break;
6193  }
6194 
6195  if (rule1.ds_type != DS_TYPE_FIXED)
6196  {
6197  int ds_rule1_count = old_tzd.ds_rulesets[rule1.ds_ruleset].count;
6198  int ds_rule2_count = tzd->ds_rulesets[rule2.ds_ruleset].count;
6199  int ds_rule1_start = old_tzd.ds_rulesets[rule1.ds_ruleset].index_start;
6200  int ds_rule2_start = tzd->ds_rulesets[rule2.ds_ruleset].index_start;
6201  int rule1_index = ds_rule1_start;
6202  int rule2_index = ds_rule2_start;
6203 
6204  if (strcmp (old_tzd.ds_rulesets[rule1.ds_ruleset].ruleset_name,
6205  tzd->ds_rulesets[rule2.ds_ruleset].ruleset_name) != 0)
6206  {
6207  tz_Is_backward_compatible_timezone[i] = false;
6208  break;
6209  }
6210 
6211  if (ds_rule1_count != ds_rule2_count)
6212  {
6213  tz_Is_backward_compatible_timezone[i] = false;
6214  break;
6215  }
6216 
6217  while ((rule1_index < ds_rule1_start + ds_rule1_count)
6218  && (rule2_index < ds_rule2_start + ds_rule2_count))
6219  {
6220  TZ_DS_RULE ds_rule1 = old_tzd.ds_rules[rule1_index];
6221  TZ_DS_RULE ds_rule2 = tzd->ds_rules[rule2_index];
6222 
6223  if (comp_ds_rules (&ds_rule1, &ds_rule2) == false)
6224  {
6225  break;
6226  }
6227  rule1_index++, rule2_index++;
6228  }
6229 
6230  if (rule1_index < ds_rule1_start + ds_rule1_count)
6231  {
6232  tz_Is_backward_compatible_timezone[i] = false;
6233  break;
6234  }
6235  }
6236  else if (rule1.ds_ruleset != rule2.ds_ruleset)
6237  {
6238  tz_Is_backward_compatible_timezone[i] = false;
6239  break;
6240  }
6241  }
6242  }
6243 
6244  if (is_compat == false)
6245  {
6246  printf ("Updating data in the tables containing timezone data types...\n");
6247  err_status = ER_TZ_COMPILE_ERROR;
6248  }
6249  }
6250 
6251  return err_status;
6252 }
6253 #endif
6254 
6255 /*
6256  * tzc_compute_timezone_checksum() - Computes an MD5 for the timezone data
6257  * structures
6258  * Returns:
6259  * tzd (in/out): timezone library
6260  * type(in): tells which make_tz mode was used
6261  */
6262 static int
6264 {
6265  char *input_buf;
6266  int size = 0;
6267  int i;
6268  int error = NO_ERROR;
6269  char *buf;
6270 
6271  for (i = 0; i < tzd->country_count; i++)
6272  {
6273  size += sizeof (tzd->countries[i].code);
6274  size += sizeof (tzd->countries[i].full_name);
6275  }
6276 
6277  for (i = 0; i < tzd->timezone_count; i++)
6278  {
6279  size += sizeof (tzd->timezones[i].country_id);
6280  size += sizeof (tzd->timezones[i].gmt_off_rule_count);
6281  size += sizeof (tzd->timezones[i].gmt_off_rule_start);
6282  size += sizeof (tzd->timezones[i].zone_id);
6283  }
6284 
6285  for (i = 0; i < tzd->timezone_count; i++)
6286  {
6287  size += strlen (tzd->timezone_names[i]);
6288  }
6289 
6290  for (i = 0; i < tzd->offset_rule_count; i++)
6291  {
6292  size += sizeof (tzd->offset_rules[i].gmt_off);
6293  size += sizeof (tzd->offset_rules[i].ds_ruleset);
6294  size += sizeof (tzd->offset_rules[i].until_year);
6295  size += sizeof (tzd->offset_rules[i].until_mon);
6296  size += sizeof (tzd->offset_rules[i].until_day);
6297  size += sizeof (tzd->offset_rules[i].until_hour);
6298  size += sizeof (tzd->offset_rules[i].until_min);
6299  size += sizeof (tzd->offset_rules[i].until_sec);
6300  size += sizeof (tzd->offset_rules[i].until_time_type);
6301  size += sizeof (tzd->offset_rules[i].until_flag);
6302  size += sizeof (tzd->offset_rules[i].ds_type);
6303  size += sizeof (tzd->offset_rules[i].julian_date);
6304  if (tzd->offset_rules[i].std_format != NULL)
6305  {
6306  size += strlen (tzd->offset_rules[i].std_format);
6307  }
6308  if (tzd->offset_rules[i].save_format != NULL)
6309  {
6310  size += strlen (tzd->offset_rules[i].save_format);
6311  }
6312  if (tzd->offset_rules[i].var_format != NULL)
6313  {
6314  size += strlen (tzd->offset_rules[i].var_format);
6315  }
6316  }
6317 
6318  for (i = 0; i < tzd->name_count; i++)
6319  {
6320  size += sizeof (tzd->names[i].is_alias);
6321  size += sizeof (tzd->names[i].zone_id);
6322  size += strlen (tzd->names[i].name);
6323  }
6324 
6325  for (i = 0; i < tzd->ds_ruleset_count; i++)
6326  {
6327  size += sizeof (tzd->ds_rulesets[i].count);
6328  size += sizeof (tzd->ds_rulesets[i].index_start);
6329  size += strlen (tzd->ds_rulesets[i].ruleset_name);
6330  }
6331 
6332  for (i = 0; i < tzd->ds_rule_count; i++)
6333  {
6334  size += sizeof (tzd->ds_rules[i].from_year);
6335  size += sizeof (tzd->ds_rules[i].to_year);
6336  size += sizeof (tzd->ds_rules[i].in_month);
6337  size += sizeof (tzd->ds_rules[i].change_on);
6338  size += sizeof (tzd->ds_rules[i].at_time);
6339  size += sizeof (tzd->ds_rules[i].at_time_type);
6340  size += sizeof (tzd->ds_rules[i].save_time);
6341  if (tzd->ds_rules[i].letter_abbrev != NULL)
6342  {
6343  size += strlen (tzd->ds_rules[i].letter_abbrev);
6344  }
6345  }
6346 
6347  for (i = 0; i < tzd->ds_leap_sec_count; i++)
6348  {
6349  size += sizeof (tzd->ds_leap_sec[i].corr_negative);
6350  size += sizeof (tzd->ds_leap_sec[i].day);
6351  size += sizeof (tzd->ds_leap_sec[i].is_rolling);
6352  size += sizeof (tzd->ds_leap_sec[i].month);
6353  size += sizeof (tzd->ds_leap_sec[i].year);
6354  }
6355 
6356  input_buf = (char *) calloc (size, sizeof (char));
6357  if (input_buf == NULL)
6358  {
6359  error = ER_OUT_OF_VIRTUAL_MEMORY;
6360  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
6361  return error;
6362  }
6363 
6364  buf = input_buf;
6365 
6366  for (i = 0; i < tzd->country_count; i++)
6367  {
6368  memcpy (buf, tzd->countries[i].code, sizeof (tzd->countries[i].code));
6369  buf += sizeof (tzd->countries[i].code);
6370  memcpy (buf, tzd->countries[i].full_name, sizeof (tzd->countries[i].full_name));
6371  buf += sizeof (tzd->countries[i].full_name);
6372  }
6373 
6374  for (i = 0; i < tzd->timezone_count; i++)
6375  {
6376  BUF_PUT_INT32 (buf, tzd->timezones[i].country_id);
6379  BUF_PUT_INT32 (buf, tzd->timezones[i].zone_id);
6380  }
6381 
6382  for (i = 0; i < tzd->timezone_count; i++)
6383  {
6384  memcpy (buf, tzd->timezone_names[i], strlen (tzd->timezone_names[i]));
6385  buf += strlen (tzd->timezone_names[i]);
6386  }
6387 
6388  for (i = 0; i < tzd->offset_rule_count; i++)
6389  {
6390  BUF_PUT_INT32 (buf, tzd->offset_rules[i].gmt_off);
6391  BUF_PUT_INT32 (buf, tzd->offset_rules[i].ds_ruleset);
6392  BUF_PUT_INT16 (buf, tzd->offset_rules[i].until_year);
6393  memcpy (buf, &tzd->offset_rules[i].until_mon, sizeof (tzd->offset_rules[i].until_mon));
6394  buf += sizeof (tzd->offset_rules[i].until_mon);
6395  memcpy (buf, &tzd->offset_rules[i].until_day, sizeof (tzd->offset_rules[i].until_day));
6396  buf += sizeof (tzd->offset_rules[i].until_day);
6397  memcpy (buf, &tzd->offset_rules[i].until_hour, sizeof (tzd->offset_rules[i].until_hour));
6398  buf += sizeof (tzd->offset_rules[i].until_hour);
6399  memcpy (buf, &tzd->offset_rules[i].until_min, sizeof (tzd->offset_rules[i].until_min));
6400  buf += sizeof (tzd->offset_rules[i].until_min);
6401  memcpy (buf, &tzd->offset_rules[i].until_sec, sizeof (tzd->offset_rules[i].until_sec));
6402  buf += sizeof (tzd->offset_rules[i].until_sec);
6404  BUF_PUT_INT32 (buf, tzd->offset_rules[i].until_flag);
6405  BUF_PUT_INT32 (buf, tzd->offset_rules[i].ds_type);
6406  BUF_PUT_INT32 (buf, tzd->offset_rules[i].julian_date);
6407  if (tzd->offset_rules[i].std_format != NULL)
6408  {
6409  memcpy (buf, tzd->offset_rules[i].std_format, strlen (tzd->offset_rules[i].std_format));
6410  buf += strlen (tzd->offset_rules[i].std_format);
6411  }
6412  if (tzd->offset_rules[i].save_format != NULL)
6413  {
6414  memcpy (buf, tzd->offset_rules[i].save_format, strlen (tzd->offset_rules[i].save_format));
6415  buf += strlen (tzd->offset_rules[i].save_format);
6416  }
6417  if (tzd->offset_rules[i].var_format != NULL)
6418  {
6419  memcpy (buf, tzd->offset_rules[i].var_format, strlen (tzd->offset_rules[i].var_format));
6420  buf += strlen (tzd->offset_rules[i].var_format);
6421  }
6422  }
6423 
6424  for (i = 0; i < tzd->name_count; i++)
6425  {
6426  memcpy (buf, &tzd->names[i].is_alias, sizeof (tzd->names[i].is_alias));
6427  buf += sizeof (tzd->names[i].is_alias);
6428  BUF_PUT_INT32 (buf, tzd->names[i].zone_id);
6429  memcpy (buf, tzd->names[i].name, strlen (tzd->names[i].name));
6430  buf += strlen (tzd->names[i].name);
6431  }
6432 
6433  for (i = 0; i < tzd->ds_ruleset_count; i++)
6434  {
6435  BUF_PUT_INT32 (buf, tzd->ds_rulesets[i].count);
6436  BUF_PUT_INT32 (buf, tzd->ds_rulesets[i].index_start);
6437  memcpy (buf, tzd->ds_rulesets[i].ruleset_name, strlen (tzd->ds_rulesets[i].ruleset_name));
6438  buf += strlen (tzd->ds_rulesets[i].ruleset_name);
6439  }
6440 
6441  for (i = 0; i < tzd->ds_rule_count; i++)
6442  {
6443  BUF_PUT_INT16 (buf, tzd->ds_rules[i].from_year);
6444  BUF_PUT_INT16 (buf, tzd->ds_rules[i].to_year);
6445  memcpy (buf, &tzd->ds_rules[i].in_month, sizeof (tzd->ds_rules[i].in_month));
6446  buf += sizeof (tzd->ds_rules[i].in_month);
6447  BUF_PUT_INT32 (buf, tzd->ds_rules[i].change_on.type);
6448  memcpy (buf, &tzd->ds_rules[i].change_on.day_of_month, sizeof (tzd->ds_rules[i].change_on.day_of_month));
6449  buf += sizeof (tzd->ds_rules[i].change_on.day_of_month);
6450  memcpy (buf, &tzd->ds_rules[i].change_on.day_of_week, sizeof (tzd->ds_rules[i].change_on.day_of_week));
6451  buf += sizeof (tzd->ds_rules[i].change_on.day_of_week);
6452  BUF_PUT_INT32 (buf, tzd->ds_rules[i].at_time);
6453  BUF_PUT_INT32 (buf, tzd->ds_rules[i].at_time_type);
6454  BUF_PUT_INT32 (buf, tzd->ds_rules[i].save_time);
6455  if (tzd->ds_rules[i].letter_abbrev != NULL)
6456  {
6457  memcpy (buf, tzd->ds_rules[i].letter_abbrev, strlen (tzd->ds_rules[i].letter_abbrev));
6458  buf += strlen (tzd->ds_rules[i].letter_abbrev);
6459  }
6460  }
6461 
6462  for (i = 0; i < tzd->ds_leap_sec_count; i++)
6463  {
6464  memcpy (buf, &tzd->ds_leap_sec[i].corr_negative, sizeof (tzd->ds_leap_sec[i].corr_negative));
6465  buf += sizeof (tzd->ds_leap_sec[i].corr_negative);
6466  memcpy (buf, &tzd->ds_leap_sec[i].day, sizeof (tzd->ds_leap_sec[i].day));
6467  buf += sizeof (tzd->ds_leap_sec[i].day);
6468  memcpy (buf, &tzd->ds_leap_sec[i].is_rolling, sizeof (tzd->ds_leap_sec[i].is_rolling));
6469  buf += sizeof (tzd->ds_leap_sec[i].is_rolling);
6470  memcpy (buf, &tzd->ds_leap_sec[i].month, sizeof (tzd->ds_leap_sec[i].month));
6471  BUF_PUT_INT16 (buf, tzd->ds_leap_sec[i].year);
6472  }
6473 
6474  memset (tzd->checksum, 0, sizeof (tzd->checksum));
6475  error = crypt_md5_buffer_hex (input_buf, size, tzd->checksum);
6476 
6477  free (input_buf);
6478  return error;
6479 }
6480 
6481 #if defined (SA_MODE)
6482 /*
6483  * execute_query() - Execute the query given by str
6484  *
6485  * Return: error or no error
6486  * str (in): query string
6487  * result (out): query result
6488  *
6489  */
6490 static int
6491 execute_query (const char *str, DB_QUERY_RESULT ** result)
6492 {
6493  DB_SESSION *session = NULL;
6494  STATEMENT_ID stmt_id;
6495  int error = NO_ERROR;
6496 
6497  session = db_open_buffer (str);
6498  if (session == NULL)
6499  {
6500  assert (er_errid () != NO_ERROR);
6501  error = er_errid ();
6502  goto exit;
6503  }
6504 
6505  stmt_id = db_compile_statement (session);
6506  if (stmt_id < 0)
6507  {
6508  assert (er_errid () != NO_ERROR);
6509  error = er_errid ();
6510  goto exit;
6511  }
6512 
6513  error = db_execute_statement_local (session, stmt_id, result);
6514 
6515 exit:
6516  if (session != NULL)
6517  {
6518  db_close_session (session);
6519  }
6520 
6521  return error;
6522 }
6523 
6524 /*
6525  * tzc_update() - Do a data migration in case that tzc_extend fails
6526  *
6527  * Returns: error or no error
6528  * tzd (in): Timezone library used to the data migration
6529  * database_name(in): Database name for which to do data migration or NULL if data migration should be done
6530  * for all the databases
6531  */
6532 static int
6533 tzc_update (TZ_DATA * tzd, const char *database_name)
6534 {
6535 #define TABLE_NAME_MAX_SIZE 256
6536 #define QUERY_BUF_MAX_SIZE 4096
6537 
6538  char query_buf[2 * QUERY_BUF_MAX_SIZE];
6539  char update_query[QUERY_BUF_MAX_SIZE];
6540  char where_query[QUERY_BUF_MAX_SIZE];
6541  DB_QUERY_RESULT *result1, *result2, *result3;
6542  DB_VALUE value1, value2, value3;
6543  int error = NO_ERROR;
6544  DB_INFO *dir = NULL;
6545  DB_INFO *db_info_p = NULL;
6546  bool need_db_shutdown = false;
6547  const char *program_name = "extend";
6548  const char *table_name = NULL;
6549  bool is_first_column = true;
6550  bool has_timezone_column;
6551 
6555  db_login ("DBA", NULL);
6556 
6557  tz_Compare_datetimetz_tz_id = true;
6558  tz_Compare_timestamptz_tz_id = true;
6559 
6560  /* Read the directory with the databases names */
6561  error = cfg_read_directory (&dir, false);
6562  if (error != NO_ERROR)
6563  {
6564  goto exit;
6565  }
6566 
6567  /* Iterate through all the databases */
6568  for (db_info_p = dir; db_info_p != NULL; db_info_p = db_info_p->next)
6569  {
6570  if (database_name != NULL && strcmp (db_info_p->name, database_name) != 0)
6571  {
6572  continue;
6573  }
6574 
6575  printf ("Opening database %s\n", db_info_p->name);
6576  /* Open the database */
6577  error = db_restart (program_name, TRUE, db_info_p->name);
6578  if (error != NO_ERROR)
6579  {
6580  printf ("Error while opening database %s\n", db_info_p->name);
6581  need_db_shutdown = true;
6582  goto exit;
6583  }
6584  printf ("Updating database %s...\n", db_info_p->name);
6585 
6586  memset (query_buf, 0, sizeof (query_buf));
6587  strcat (query_buf, "show tables");
6588 
6589  error = execute_query (query_buf, &result1);
6590  if (error < 0)
6591  {
6592  printf ("Error while executing show tables query\n");
6593  need_db_shutdown = true;
6594  goto exit;
6595  }
6596 
6597  /* First get the names for the tables in the database */
6598  while (db_query_next_tuple (result1) == DB_CURSOR_SUCCESS)
6599  {
6600  error = db_query_get_tuple_value (result1, 0, &value1);
6601  if (error != NO_ERROR)
6602  {
6603  db_query_end (result1);
6604  need_db_shutdown = true;
6605  goto exit;
6606  }
6607 
6608  if (error == NO_ERROR)
6609  {
6610  if (DB_IS_NULL (&value1))
6611  {
6612  need_db_shutdown = true;
6613  goto exit;
6614  }
6615  else
6616  {
6617  char table_name_buf[TABLE_NAME_MAX_SIZE];
6618 
6619  /* First get the name of the table */
6620  table_name = db_get_string (&value1);
6621 
6622  memset (query_buf, 0, sizeof (query_buf));
6623  memset (table_name_buf, 0, sizeof (table_name_buf));
6624  strcat (table_name_buf, "'");
6625  strcat (table_name_buf, table_name);
6626  strcat (table_name_buf, "'");
6627 
6628  snprintf (query_buf, sizeof (query_buf) - 1,
6629  "select attr_name, data_type from _db_attribute where class_of.class_name = %s",
6630  table_name_buf);
6631  error = execute_query (query_buf, &result2);
6632  if (error < 0)
6633  {
6634  printf ("Error while listing column names and types for table %s\n", table_name);
6635  need_db_shutdown = true;
6636  goto exit;
6637  }
6638  printf ("Updating table %s...\n", table_name);
6639 
6640  /* We are going to make an update query for each table which includes a timezone column like:
6641  * UPDATE [t] SET [tzc1] = CONV_TZ([tzc1]), [tzc2] = CONV_TZ([tzc2]) ...
6642  * WHERE [tzc1] != CONV_TZ([tzc1]) OR [tzc2] != CONV_TZ([tzc2]) ... ;
6643  */
6644  memset (query_buf, 0, sizeof (query_buf));
6645  memset (update_query, 0, sizeof (update_query));
6646  memset (where_query, 0, sizeof (where_query));
6647 
6648  strcpy (update_query, "UPDATE [");
6649  strcat (update_query, table_name);
6650  strcat (update_query, "] SET ");
6651  strcpy (where_query, " WHERE ");
6652 
6653  is_first_column = true;
6654  has_timezone_column = false;
6655 
6656  printf ("We will update the following columns:\n");
6657  while (db_query_next_tuple (result2) == DB_CURSOR_SUCCESS)
6658  {
6659  const char *column_name = NULL;
6660  int column_type = 0;
6661 
6662  /* Get the column name */
6663  error = db_query_get_tuple_value (result2, 0, &value2);
6664  if (error != NO_ERROR)
6665  {
6666  db_query_end (result2);
6667  need_db_shutdown = true;
6668  goto exit;
6669  }
6670 
6671  /* Get the column type */
6672  error = db_query_get_tuple_value (result2, 1, &value3);
6673  if (error != NO_ERROR)
6674  {
6675  db_query_end (result2);
6676  need_db_shutdown = true;
6677  goto exit;
6678  }
6679 
6680  assert (DB_VALUE_TYPE (&value2) == DB_TYPE_STRING);
6681  assert (DB_VALUE_TYPE (&value3) == DB_TYPE_INTEGER);
6682  column_name = db_get_string (&value2);
6683  column_type = db_get_int (&value3);
6684 
6685  /* Now do the update if the datatype is of timezone type */
6686  if (column_type == DB_TYPE_DATETIMETZ || column_type == DB_TYPE_DATETIMELTZ
6687  || column_type == DB_TYPE_TIMESTAMPTZ || column_type == DB_TYPE_TIMESTAMPLTZ)
6688  {
6689  has_timezone_column = true;
6690 
6691  if (is_first_column == true)
6692  {
6693  is_first_column = false;
6694  }
6695  else
6696  {
6697  strcat (update_query, ", ");
6698  strcat (where_query, " OR ");
6699  }
6700 
6701  strcat (update_query, "[");
6702  strcat (update_query, column_name);
6703  strcat (update_query, "]");
6704  strcat (update_query, "=");
6705  strcat (update_query, "conv_tz([");
6706  strcat (update_query, column_name);
6707  strcat (update_query, "])");
6708 
6709  strcat (where_query, "[");
6710  strcat (where_query, column_name);
6711  strcat (where_query, "]");
6712  strcat (where_query, "!=");
6713  strcat (where_query, "conv_tz([");
6714  strcat (where_query, column_name);
6715  strcat (where_query, "])");
6716 
6717  printf ("%s ", column_name);
6718  }
6719  }
6720  printf ("\n");
6721  db_query_end (result2);
6722 
6723  /* If we have at least a column that is of timezone data type then execute the query */
6724  if (has_timezone_column == true)
6725  {
6726  strcpy (query_buf, update_query);
6727  strcat (query_buf, where_query);
6728 
6729  error = execute_query (query_buf, &result3);
6730  if (error < 0)
6731  {
6732  printf ("Error while updating table %s\n", table_name);
6734  need_db_shutdown = true;
6735  goto exit;
6736  }
6737  db_query_end (result3);
6738  }
6739  printf ("Finished updating table %s\n", table_name);
6740  }
6741  }
6742  }
6743  db_query_end (result1);
6744 
6746  printf ("Finished updating database %s\n", db_info_p->name);
6747  printf ("Shutting down database %s...\n", db_info_p->name);
6748  db_shutdown ();
6749  }
6750 
6751  error = NO_ERROR;
6752 
6753 exit:
6754  if (dir != NULL)
6755  {
6756  cfg_free_directory (dir);
6757  }
6758  if (need_db_shutdown == true)
6759  {
6760  db_shutdown ();
6761  }
6762 
6763  tz_Compare_datetimetz_tz_id = false;
6764  tz_Compare_timestamptz_tz_id = false;
6765 
6766  return error;
6767 
6768 #undef TABLE_NAME_MAX_SIZE
6769 #undef QUERY_BUF_MAX_SIZE
6770 }
6771 #endif
int julian_encode(int m, int d, int y)
Definition: db_date.c:113
int char_isspace(int c)
Definition: chartype.c:109
#define TZC_LOG_ERROR_1ARG(context, err_code, s1)
Definition: tz_compile.c:333
#define TZC_CONTEXT(tzd_raw)
Definition: tz_compile.c:331
#define TZ_RULE_LETTER_ABBREV_MAX_SIZE
Definition: tz_compile.c:59
static int tzc_check_ds_ruleset(const TZ_DATA *tzd, const TZ_DS_RULESET *ds_rule_set, int *ds_changes_cnt)
Definition: tz_compile.c:2824
int db_execute_statement_local(DB_SESSION *session, int stmt, DB_QUERY_RESULT **result)
Definition: db_vdb.c:2939
TZ_DS_RULESET * ds_rulesets
static int tzc_add_leap_sec(TZ_RAW_DATA *tzd_raw, int year, int month, int day, unsigned char hour, unsigned char min, unsigned char sec, bool corr_minus, bool leap_is_rolling)
Definition: tz_compile.c:1706
#define TZ_OFFRULE_PREFIX_TAB_COUNT
Definition: tz_compile.c:55
#define DUPLICATE_STR(a, b)
Definition: tz_compile.c:339
char full_name[TZ_COUNTRY_NAME_SIZE]
Definition: tz_compile.c:130
#define NO_ERROR
Definition: error_code.h:46
static int tzc_index_data(TZ_RAW_DATA *tzd_raw, const TZ_GEN_TYPE mode)
Definition: tz_compile.c:1027
#define TRUE
Definition: broker_admin.c:49
const char * name
static int comp_func_raw_ds_rulesets(const void *arg1, const void *arg2)
Definition: tz_compile.c:4052
static int tzc_get_ds_ruleset_by_name(const TZ_DS_RULESET *ds_rulesets, int ds_ruleset_count, const char *ruleset)
Definition: tz_compile.c:4386
void db_set_client_type(int client_type)
Definition: db_admin.c:495
TZ_RAW_DS_RULE * rules
Definition: tz_compile.c:196
static int comp_func_raw_links(const void *arg1, const void *arg2)
Definition: tz_compile.c:3972
#define ZONE_MAX
Definition: tz_support.h:87
static int comp_func_raw_zones(const void *arg1, const void *arg2)
Definition: tz_compile.c:3930
unsigned char until_hour
#define TZC_ERR_INVALID_PACKAGE
Definition: tz_compile.c:261
static int tzc_import_old_data(TZ_RAW_DATA *tzd_raw, const TZ_GEN_TYPE mode)
Definition: tz_compile.c:930
void tzc_dump_countries(const TZ_DATA *tzd)
Definition: tz_compile.c:4637
unsigned char in_month
Definition: tz_compile.c:183
static int tzc_add_zone(const char *zone, const char *coord, const char *code, const char *comments, TZ_RAW_DATA *tzd_raw, TZ_RAW_ZONE_INFO **new_zone)
Definition: tz_compile.c:1766
#define TZC_ERR_LAST_ERROR
Definition: tz_compile.c:277
struct tz_windows_iana_map TZ_WINDOWS_IANA_MAP
unsigned char month
int db_login(const char *name, const char *password)
Definition: db_admin.c:804
const char * var_format
static int copy_ds_rule(TZ_DS_RULE *dst, const TZ_DATA *tzd, const int index)
Definition: tz_compile.c:5340
int execute_query(const XASL_ID *xasl_id, QUERY_ID *query_idp, int var_cnt, const DB_VALUE *varptr, QFILE_LIST_ID **list_idp, QUERY_FLAG flag, CACHE_TIME *clt_cache_time, CACHE_TIME *srv_cache_time)
Definition: query_cl.c:105
void tzc_dump_leap_sec(const TZ_DATA *tzd)
Definition: tz_compile.c:4788
static bool comp_offset_rules(const TZ_OFFSET_RULE *rule1, const TZ_OFFSET_RULE *rule2)
Definition: tz_compile.c:5247
static int tzc_load_backward_zones(TZ_RAW_DATA *tzd_raw, const char *input_folder)
Definition: tz_compile.c:1414
void tzc_dump_one_timezone(const TZ_DATA *tzd, const int zone_id)
Definition: tz_compile.c:4674
char code[TZ_COUNTRY_CODE_SIZE]
static int tzc_compute_timezone_checksum(TZ_DATA *tzd, TZ_GEN_TYPE type)
Definition: tz_compile.c:6263
int db_get_int(const DB_VALUE *value)
#define ER_FAILED
Definition: error_code.h:47
#define AU_DISABLE_PASSWORDS
Definition: authenticate.h:140
static bool comp_ds_rules(const TZ_DS_RULE *rule1, const TZ_DS_RULE *rule2)
Definition: tz_compile.c:5227
static void tzc_build_filepath(char *path, size_t size, const char *dir, const char *filename)
Definition: tz_compile.c:521
TZ_DS_CHANGE_ON change_on
TZ_RAW_ZONE_INFO * zones
Definition: tz_compile.c:220
struct tz_raw_link TZ_RAW_LINK
Definition: tz_compile.c:134
char type[TZ_RULE_TYPE_MAX_SIZE]
Definition: tz_compile.c:182
#define TZ_COORDINATES_MAX_SIZE
Definition: tz_compile.c:57
const char * letter_abbrev
#define TZC_ERR_MSG_MAX_SIZE
Definition: tz_compile.c:329
int db_query_end(DB_QUERY_RESULT *result)
Definition: db_query.c:3362
#define assert_release(e)
Definition: error_manager.h:96
static void print_seconds_as_time_hms_var(int seconds)
Definition: tz_compile.c:4165
int db_shutdown(void)
Definition: db_admin.c:964
static int tzc_get_timezone_aliases(const TZ_DATA *tzd, const int zone_id, int **aliases, int *alias_count)
Definition: tz_compile.c:4425
int tz_load_with_library_path(TZ_DATA *tzd, const char *timezone_library_path)
Definition: tz_support.c:4937
char * envvar_libdir_file(char *path, size_t size, const char *filename)
#define PATH_PARTIAL_TIMEZONES_FILE
Definition: tz_compile.c:65
static int tz_File_count
Definition: tz_compile.c:123
static int tzc_find_timezone_names(const TZ_DATA *tzd, const char *timezone_name)
Definition: tz_compile.c:5151
char code[TZ_COUNTRY_CODE_SIZE]
Definition: tz_compile.c:129
#define TZ_COUNTRY_CODE_SIZE
static void tzc_dump_one_offset_rule(const TZ_DATA *tzd, const TZ_OFFSET_RULE *offset_rule)
Definition: tz_compile.c:4466
static int compare_ints(const void *a, const void *b)
Definition: tz_compile.c:2800
const char * std_format
unsigned char day
int(* ELEM_START_FUNC)(void *, const char **)
Definition: xml_parser.h:60
#define TZ_MAX_LINE_LEN
Definition: tz_compile.c:54
int er_errid(void)
struct tz_raw_country TZ_RAW_COUNTRY
Definition: tz_compile.c:125
TZ_TIME_TYPE at_time_type
XML_Parser xml_init_parser(void *data, const char *xml_file, const char *encoding, XML_ELEMENT_DEF **element_array, const int count)
Definition: xml_parser.c:939
static int tzc_find_country_names(const TZ_COUNTRY *countries, const int country_count, const char *country_name)
Definition: tz_compile.c:5189
char current_file[PATH_MAX]
Definition: tz_compile.c:205
int leap_sec_count
Definition: tz_compile.c:225
static void tzc_index_raw_data(TZ_RAW_DATA *tzd_raw)
Definition: tz_compile.c:2581
#define LOG_TZC_SET_CURRENT_CONTEXT(tzd_raw, f, l)
Definition: tz_compile.c:323
char comments[TZ_COMMENTS_MAX_SIZE]
Definition: tz_compile.c:172
void tzc_dump_summary(const TZ_DATA *tzd)
Definition: tz_compile.c:4617
TZ_TIME_TYPE until_time_type
char letter_abbrev[TZ_RULE_LETTER_ABBREV_MAX_SIZE]
Definition: tz_compile.c:189
#define TZC_ERR_GENERIC
Definition: tz_compile.c:260
#define XML_USER_DATA(xml)
Definition: xml_parser.h:109
TZ_COUNTRY * countries
static int comp_func_tz_names(const void *arg1, const void *arg2)
Definition: tz_compile.c:4144
unsigned short until_year
Definition: tz_compile.c:146
struct tz_raw_ds_rule TZ_RAW_DS_RULE
Definition: tz_compile.c:177
#define TZ_GENERIC_NAME_SIZE
static int tzc_read_time_type(const char *str, const char **next, TZ_TIME_TYPE *time_type)
Definition: tz_compile.c:1983
static int tzc_load_rule_file(TZ_RAW_DATA *tzd_raw, const int file_index, const char *input_folder)
Definition: tz_compile.c:1262
TZ_FILE_TYPE
Definition: tz_compile.c:71
#define TZ_COMMENTS_MAX_SIZE
Definition: tz_compile.c:58
int tz_str_read_number(const char *str, const char *str_end, const bool strict, const bool read_sign, int *val, const char **str_next)
Definition: tz_support.c:2130
static const char * tzc_Err_messages[]
Definition: tz_compile.c:279
#define TZ_CAL_ABBREV_SIZE
Definition: tz_compile.c:238
int STATEMENT_ID
Definition: dbtype_def.h:302
unsigned char until_mon
XML_Parser xml_parser
Definition: xml_parser.h:114
#define TZC_ERR_OUT_OF_MEMORY
Definition: tz_compile.c:263
struct tz_raw_ds_ruleset TZ_RAW_DS_RULESET
Definition: tz_compile.c:192
TZ_TIME_TYPE until_time_type
Definition: tz_compile.c:154
#define INIT_COUNTRY(dst, src)
Definition: tz_compile.c:349
int db_restart(const char *program, int print_version, const char *volume)
Definition: db_admin.c:868
static int str_day_to_int(const char *str_in, int *day_num, const char **str_next)
Definition: tz_compile.c:3714
struct tz_raw_zone_info TZ_RAW_ZONE_INFO
Definition: tz_compile.c:158
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
char ds_ruleset_name[TZ_DS_RULESET_NAME_SIZE]
Definition: tz_compile.c:152
#define assert(x)
TZ_TIME_TYPE
char checksum[TZ_CHECKSUM_SIZE+1]
char name[TZ_DS_RULESET_NAME_SIZE]
Definition: tz_compile.c:197
unsigned char until_min
Definition: tz_compile.c:150
int tz_str_read_time(const char *str, const char *str_end, bool need_minutes, bool allow_sec60, int *hour, int *min, int *sec, const char **str_next)
Definition: tz_support.c:2186
#define TZC_ERR_INVALID_TIME
Definition: tz_compile.c:265
char format[TZ_MAX_FORMAT_SIZE]
Definition: tz_compile.c:153
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
#define TZC_ERR_INVALID_DS_RULE
Definition: tz_compile.c:268
#define TZC_ERR_INVALID_ZONE
Definition: tz_compile.c:274
#define TZC_ERR_INVALID_COUNTRY
Definition: tz_compile.c:273
int zone_count
Definition: tz_compile.c:219
#define TZC_ERR_DS_INVALID_DATE
Definition: tz_compile.c:271
void xml_parser_exec(XML_PARSER_DATA *pd)
Definition: xml_parser.c:1240
#define BUF_PUT_INT32(buf, v)
Definition: tz_compile.c:373
const char * save_format
int tz_str_to_seconds(const char *str, const char *str_end, int *seconds, const char **str_next, const bool is_offset)
Definition: tz_support.c:2278
int tz_get_ds_change_julian_date_diff(const int src_julian_date, const TZ_DS_RULE *ds_rule, const int year, int *ds_rule_julian_date, full_date_t *date_diff)
Definition: tz_support.c:2333
struct tz_leap_sec TZ_LEAP_SEC
#define ER_TZ_COMPILE_ERROR
Definition: error_code.h:1486
TZ_RAW_COUNTRY * countries
Definition: tz_compile.c:218
#define MAX_DS_CHANGES_YEAR
static int comp_func_raw_ds_rules(const void *arg1, const void *arg2)
Definition: tz_compile.c:4107
static int tzc_add_offset_rule(TZ_RAW_ZONE_INFO *zone, char *rule_text)
Definition: tz_compile.c:1869
static enum scanner_mode mode
static int tzc_del_unused_raw_data(TZ_RAW_DATA *tzd_raw)
Definition: tz_compile.c:951
#define TZC_ERR_LINKING_TRUE_ZONES
Definition: tz_compile.c:276
#define TZC_ERR_ZONE_RULE_UNORDERED
Definition: tz_compile.c:266
#define min(a, b)
static int tzc_get_zone(const TZ_RAW_DATA *tzd_raw, const char *zone_name, TZ_RAW_ZONE_INFO **zone)
Definition: tz_compile.c:1841
static int str_month_to_int(const char *month, int *month_num, const char **str_next)
Definition: tz_compile.c:3665
static int tzc_add_ds_rule(TZ_RAW_DATA *tzd_raw, char *rule_text)
Definition: tz_compile.c:2024
TZ_RAW_OFFSET_RULE * offset_rules
Definition: tz_compile.c:162
#define TZ_FILENAME_MAX_LEN
Definition: tz_compile.c:53
TZ_NAME * names
int db_abort_transaction(void)
Definition: db_admin.c:1114
#define LIB_TZ_NAME
Definition: tz_support.h:59
TZ_DS_CHANGE_ON change_on
Definition: tz_compile.c:184
unsigned char until_min
#define NULL
Definition: freelistheap.h:34
char name[TZ_FILENAME_MAX_LEN]
Definition: tz_compile.c:90
static int tzc_load_zone_names(TZ_RAW_DATA *tzd_raw, const char *input_folder)
Definition: tz_compile.c:1161
#define strncpy_bufsize(buf, str)
Definition: porting.h:340
#define DAYS_IN_MONTH(m)
Definition: tz_support.h:65
#define IS_EMPTY_STR(s)
Definition: tz_support.h:67
#define PRINT_STRING_VAR_TO_C_FILE(fp, valname, val)
Definition: tz_compile.c:366
if(extra_options)
Definition: dynamic_load.c:958
DB_SESSION * db_open_buffer(const char *buffer)
Definition: db_vdb.c:232
int db_compile_statement(DB_SESSION *session)
Definition: db_vdb.c:766
static void tzc_get_timezones_dot_c_filepath(size_t size, char *timezones_dot_c_file_path)
Definition: tz_compile.c:4189
unsigned short until_year
void db_close_session(DB_SESSION *session)
Definition: db_vdb.c:3319
TZ_UNTIL_FLAG until_flag
static int init_tz_name(TZ_NAME *dst, TZ_NAME *src)
Definition: tz_compile.c:5398
static const TZ_FILE_DESCRIPTOR tz_Files[]
Definition: tz_compile.c:101
int crypt_md5_buffer_hex(const char *buffer, size_t len, char *resblock)
Definition: crypt_opfunc.c:646
char full_name[TZ_GENERIC_NAME_SIZE]
Definition: tz_compile.c:171
static void tzc_dump_ds_ruleset(const TZ_DATA *tzd, const int ruleset_id)
Definition: tz_compile.c:4540
#define TZC_ERR_BAD_TZ_LINK
Definition: tz_compile.c:262
TZ_TIMEZONE * timezones
unsigned char is_alias
unsigned char day_of_month
void tz_set_new_timezone_data(const TZ_DATA *data)
Definition: tz_support.c:729
unsigned char until_mon
Definition: tz_compile.c:147
TZ_TIME_TYPE at_time_type
Definition: tz_compile.c:186
#define TZC_ERR_FILE_NOT_ACCESSIBLE
Definition: tz_compile.c:272
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
#define TZ_RULE_TYPE_MAX_SIZE
Definition: tz_compile.c:60
static int tzc_load_countries(TZ_RAW_DATA *tzd_raw, const char *input_folder)
Definition: tz_compile.c:1062
char code[TZ_COUNTRY_CODE_SIZE]
Definition: tz_compile.c:169
static int tzc_check_links_raw_data(TZ_RAW_DATA *tzd_raw)
Definition: tz_compile.c:2431
unsigned char until_day
#define STR_SKIP_LEADING_SPACES(str)
Definition: tz_compile.c:245
FILE * fopen_ex(const char *filename, const char *type)
Definition: util_common.c:322
TZ_FILE_TYPE type
Definition: tz_compile.c:89
#define IS_LEAP_YEAR(y)
Definition: tz_support.h:62
unsigned char until_day
Definition: tz_compile.c:148
unsigned char is_rolling
static void trim_comments_whitespaces(char *str)
Definition: tz_compile.c:552
#define TZ_DS_RULESET_NAME_SIZE
static int tzc_add_link(TZ_RAW_DATA *tzd_raw, const char *zone, const char *alias)
Definition: tz_compile.c:1661
const char * ruleset_name
static void error(const char *msg)
Definition: gencat.c:331
unsigned char day_of_week
static int str_to_offset_rule_until(TZ_RAW_OFFSET_RULE *offset_rule, char *str)
Definition: tz_compile.c:3465
static bool tzc_is_valid_date(const int day, const int month, const int year_start, const int year_end)
Definition: tz_compile.c:2325
const char * tz_timezone_names[]
int db_query_next_tuple(DB_QUERY_RESULT *result)
Definition: db_query.c:2088
int country_count
Definition: tz_compile.c:217
#define ARG_FILE_LINE
Definition: error_manager.h:44
static void tzc_sort_raw_data(TZ_RAW_DATA *tzd_raw)
Definition: tz_compile.c:2542
static char database_name[MAX_HA_DBINFO_LENGTH]
Definition: cas_execute.c:387
#define snprintf_dots_truncate(dest, max_len,...)
Definition: porting.h:323
int tz_get_first_weekday_around_date(const int year, const int month, const int weekday, const int ref_day, const bool before)
Definition: tz_support.c:2085
int ruleset_count
Definition: tz_compile.c:221
static int tzc_load_leap_secs(TZ_RAW_DATA *tzd_raw, const char *input_folder)
Definition: tz_compile.c:1511
static int tz_data_partial_clone(char **timezone_names, TZ_TIMEZONE *timezones, TZ_NAME *names, const TZ_DATA *tzd)
Definition: tz_compile.c:5369
int cfg_read_directory(DB_INFO **info_p, bool write_flag)
static void tzc_free_tz_data(TZ_DATA *tzd, bool full)
Definition: tz_compile.c:751
void julian_decode(int jul, int *monthp, int *dayp, int *yearp, int *weekp)
Definition: db_date.c:196
unsigned char until_sec
Definition: tz_compile.c:151
#define ABS(i)
#define TZ_MAX_YEAR
Definition: tz_support.h:69
#define free_and_init(ptr)
Definition: memory_alloc.h:147
static int tzc_export_timezone_dot_c(const TZ_DATA *tzd, const char *tz_C_filepath)
Definition: tz_compile.c:4205
static int tzc_load_raw_data(TZ_RAW_DATA *tzd_raw, const char *input_folder)
Definition: tz_compile.c:856
const char * default_abrev
static void tzc_free_raw_data(TZ_RAW_DATA *tzd_raw)
Definition: tz_compile.c:2363
static void tzc_log_error(const TZ_RAW_CONTEXT *context, const int code, const char *msg1, const char *msg2)
Definition: tz_compile.c:4814
static int init_ds_ruleset(TZ_DS_RULESET *dst_ruleset, const TZ_DATA *tzd, const int index, const int start)
Definition: tz_compile.c:5316
static int get_day_of_week_for_raw_rule(const TZ_RAW_DS_RULE *rule, const int year)
Definition: tz_compile.c:4074
char coordinates[TZ_COORDINATES_MAX_SIZE]
Definition: tz_compile.c:170
#define DB_CURSOR_SUCCESS
Definition: dbtype_def.h:166
void xml_destroy_parser(void *data)
Definition: xml_parser.c:977
char full_name[TZ_COUNTRY_NAME_SIZE]
char territory[TZ_COUNTRY_CODE_SIZE+1]
#define TZC_ERR_ADD_ZONE
Definition: tz_compile.c:275
#define TZ_WINDOWS_ZONE_NAME_SIZE
#define TZC_ERR_CANT_READ_VALUE
Definition: tz_compile.c:269
static int copy_offset_rule(TZ_OFFSET_RULE *dst, const TZ_DATA *tzd, const int index)
Definition: tz_compile.c:5268
TZ_RAW_LINK * links
Definition: tz_compile.c:224
TZ_DS_RULE * ds_rules
int link_count
Definition: tz_compile.c:223
char ** timezone_names
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
#define BUF_PUT_INT16(buf, v)
Definition: tz_compile.c:386
static int comp_func_raw_countries(const void *arg1, const void *arg2)
Definition: tz_compile.c:3889
int i
Definition: dynamic_load.c:954
#define TZ_MAX_FORMAT_SIZE
#define DB_IS_NULL(value)
Definition: dbtype.h:63
static const char DAY_NAMES_ABBREV[TZ_WEEK_DAY_COUNT][TZ_CAL_ABBREV_SIZE]
Definition: tz_compile.c:242
char * strdup(const char *str)
Definition: porting.c:901
unsigned short year
unsigned char in_month
char windows_zone[TZ_WINDOWS_ZONE_NAME_SIZE+1]
unsigned char until_sec
int db_query_get_tuple_value(DB_QUERY_RESULT *result, int index, DB_VALUE *value)
Definition: db_query.c:2873
#define TZ_COUNTRY_CODE_LEN
const TZ_COUNTRY tz_countries[]
DB_INFO * next
TZ_UNTIL_FLAG until_flag
Definition: tz_compile.c:155
static int tzc_index_raw_subdata(TZ_RAW_DATA *tzd_raw, const TZ_GEN_TYPE mode)
Definition: tz_compile.c:2680
static int str_read_day_var(const char *str, const int month, int *type, int *day, int *bound, const char **str_next)
Definition: tz_compile.c:3778
#define TZC_ERR_INVALID_VALUE
Definition: tz_compile.c:264
static int tzc_index_raw_data_w_static(TZ_RAW_DATA *tzd_raw, const TZ_GEN_TYPE mode)
Definition: tz_compile.c:2609
TZ_RAW_DS_RULESET * ds_rulesets
Definition: tz_compile.c:222
int xml_get_att_value(const char **attrs, const char *att_name, char **p_att_value)
Definition: xml_parser.c:1180
static const int tzc_Err_message_count
Definition: tz_compile.c:318
unsigned char until_hour
Definition: tz_compile.c:149
TZ_LEAP_SEC * leap_sec
Definition: tz_compile.c:226
TZ_LEAP_SEC * ds_leap_sec
const char * program_name
Definition: cas.c:147
#define TZC_LOG_ERROR_2ARG(context, err_code, s1, s2)
Definition: tz_compile.c:336
#define strlen(s1)
Definition: tz_compile.c:50
struct tz_raw_offset_rule TZ_RAW_OFFSET_RULE
Definition: tz_compile.c:142
#define SHLIB_EXPORT_PREFIX
Definition: tz_support.h:58
char * envvar_cubrid_dir(char *path, size_t size)
void tzc_dump_timezones(const TZ_DATA *tzd)
Definition: tz_compile.c:4655
#define TZ_COUNTRY_NAME_SIZE
static int comp_func_raw_offset_rules(const void *arg1, const void *arg2)
Definition: tz_compile.c:3996
static int tzc_check_new_package_validity(const char *input_folder)
Definition: tz_compile.c:584
char clone_of[TZ_GENERIC_NAME_SIZE]
Definition: tz_compile.c:167
static void tzc_summary(TZ_RAW_DATA *tzd_raw, TZ_DATA *tzd)
Definition: tz_compile.c:4839
TZ_OFFSET_RULE * offset_rules
void cfg_free_directory(DB_INFO *databases)
static int tzc_compile_ds_rules(TZ_RAW_DATA *tzd_raw, TZ_DATA *tzd)
Definition: tz_compile.c:3318
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
enum tz_until_flag TZ_UNTIL_FLAG
int db_commit_transaction(void)
Definition: db_admin.c:1091
static int tzc_parse_ds_change_on(TZ_RAW_DS_RULE *dest, const char *str)
Definition: tz_compile.c:2243
TZ_RAW_CONTEXT context
Definition: tz_compile.c:227
unsigned char corr_negative
static const char MONTH_NAMES_ABBREV[TZ_MON_COUNT][TZ_CAL_ABBREV_SIZE]
Definition: tz_compile.c:239
static int tzc_compile_data(TZ_RAW_DATA *tzd_raw, TZ_DATA *tzd)
Definition: tz_compile.c:2954