~ubuntu-branches/ubuntu/trusty/libgweather/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/01_gettext_not_xml.patch/libgweather/gweather-timezone.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-05-27 11:58:15 UTC
  • mfrom: (13.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20130527115815-l51yffuy20gbv9q0
Tags: 3.8.0-1ubuntu1
* Sync with Debian (LP: #1184168). Remaining changes: 
  - debian/control.in, debian/rules:
    + Run autoreconf
  - debian/rules:
    + Generate POT files on build
  - debian/patches/01_gettext_not_xml.patch: 
    + using gettext rather than add translations to the xml databases
  - debian/patches/02_no_external_gettext.patch:
    + Can't have both IT_PROG_INTLTOOL and AM_GNU_GETTEXT

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
2
/* gweather-timezone.c - Timezone handling
 
3
 *
 
4
 * Copyright 2008, Red Hat, Inc.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public License
 
8
 * as published by the Free Software Foundation; either version 2.1 of
 
9
 * the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, see
 
18
 * <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <string.h>
 
26
 
 
27
#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
 
28
#include "gweather-timezone.h"
 
29
#include "parser.h"
 
30
#include "weather-priv.h"
 
31
 
 
32
/**
 
33
 * SECTION:gweathertimezone
 
34
 * @Title: GWeatherTimezone
 
35
 *
 
36
 * A timezone.
 
37
 *
 
38
 * There are no public methods for creating timezones; they can only
 
39
 * be created by calling gweather_location_new_world() to parse
 
40
 * Locations.xml, and then calling various #GWeatherLocation methods
 
41
 * to extract relevant timezones from the location hierarchy.
 
42
 */
 
43
 
 
44
struct _GWeatherTimezone {
 
45
    char *id, *name;
 
46
    int offset, dst_offset;
 
47
    gboolean has_dst;
 
48
 
 
49
    int ref_count;
 
50
};
 
51
 
 
52
#define TZ_MAGIC "TZif"
 
53
#define TZ_HEADER_SIZE 44
 
54
#define TZ_TIMECNT_OFFSET 32
 
55
#define TZ_TRANSITIONS_OFFSET 44
 
56
 
 
57
#define TZ_TTINFO_SIZE 6
 
58
#define TZ_TTINFO_GMTOFF_OFFSET 0
 
59
#define TZ_TTINFO_ISDST_OFFSET 4
 
60
 
 
61
static gboolean
 
62
parse_tzdata (const char *tzname, time_t start, time_t end,
 
63
              int *offset, gboolean *has_dst, int *dst_offset)
 
64
{
 
65
    char *filename, *contents;
 
66
    gsize length;
 
67
    int timecnt, transitions_size, ttinfo_map_size;
 
68
    int initial_transition = -1, second_transition = -1;
 
69
    gint32 *transitions;
 
70
    char *ttinfo_map, *ttinfos;
 
71
    gint32 initial_offset, second_offset;
 
72
    char initial_isdst, second_isdst;
 
73
    int i;
 
74
 
 
75
    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
 
76
    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
 
77
        g_free (filename);
 
78
        return FALSE;
 
79
    }
 
80
    g_free (filename);
 
81
 
 
82
    if (length < TZ_HEADER_SIZE ||
 
83
        strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
 
84
        g_free (contents);
 
85
        return FALSE;
 
86
    }
 
87
 
 
88
    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
 
89
    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
 
90
    transitions_size = timecnt * sizeof (*transitions);
 
91
    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
 
92
    ttinfo_map_size = timecnt;
 
93
    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
 
94
 
 
95
    /* @transitions is an array of @timecnt time_t values. We need to
 
96
     * find the transition into the current offset, which is the last
 
97
     * transition before @start. If the following transition is before
 
98
     * @end, then note that one too, since it presumably means we're
 
99
     * doing DST.
 
100
     */
 
101
    for (i = 1; i < timecnt && initial_transition == -1; i++) {
 
102
        if (GINT32_FROM_BE (transitions[i]) > start) {
 
103
            initial_transition = ttinfo_map[i - 1];
 
104
            if (GINT32_FROM_BE (transitions[i]) < end)
 
105
                second_transition = ttinfo_map[i];
 
106
        }
 
107
    }
 
108
    if (initial_transition == -1) {
 
109
        if (timecnt)
 
110
            initial_transition = ttinfo_map[timecnt - 1];
 
111
        else
 
112
            initial_transition = 0;
 
113
    }
 
114
 
 
115
    /* Copy the data out of the corresponding ttinfo structs */
 
116
    initial_offset = *(gint32 *)(ttinfos +
 
117
                                 initial_transition * TZ_TTINFO_SIZE +
 
118
                                 TZ_TTINFO_GMTOFF_OFFSET);
 
119
    initial_offset = GINT32_FROM_BE (initial_offset);
 
120
    initial_isdst = *(ttinfos +
 
121
                      initial_transition * TZ_TTINFO_SIZE +
 
122
                      TZ_TTINFO_ISDST_OFFSET);
 
123
 
 
124
    if (second_transition != -1) {
 
125
        second_offset = *(gint32 *)(ttinfos +
 
126
                                    second_transition * TZ_TTINFO_SIZE +
 
127
                                    TZ_TTINFO_GMTOFF_OFFSET);
 
128
        second_offset = GINT32_FROM_BE (second_offset);
 
129
        second_isdst = *(ttinfos +
 
130
                         second_transition * TZ_TTINFO_SIZE +
 
131
                         TZ_TTINFO_ISDST_OFFSET);
 
132
 
 
133
        *has_dst = (initial_isdst != second_isdst);
 
134
    } else
 
135
        *has_dst = FALSE;
 
136
 
 
137
    if (!*has_dst)
 
138
        *offset = initial_offset / 60;
 
139
    else {
 
140
        if (initial_isdst) {
 
141
            *offset = second_offset / 60;
 
142
            *dst_offset = initial_offset / 60;
 
143
        } else {
 
144
            *offset = initial_offset / 60;
 
145
            *dst_offset = second_offset / 60;
 
146
        }
 
147
    }
 
148
 
 
149
    g_free (contents);
 
150
    return TRUE;
 
151
}
 
152
 
 
153
static GWeatherTimezone *
 
154
parse_timezone (GWeatherParser *parser)
 
155
{
 
156
    GWeatherTimezone *zone = NULL;
 
157
    char *id = NULL, *name = NULL;
 
158
    int offset = 0, dst_offset = 0;
 
159
    gboolean has_dst = FALSE;
 
160
 
 
161
    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
 
162
    if (!id) {
 
163
        xmlTextReaderNext (parser->xml);
 
164
        return NULL;
 
165
    }
 
166
 
 
167
    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
 
168
        if (xmlTextReaderRead (parser->xml) != 1) {
 
169
            xmlFree (id);
 
170
            return NULL;
 
171
        }
 
172
 
 
173
        while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
 
174
            if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
 
175
                if (xmlTextReaderRead (parser->xml) != 1)
 
176
                    break;
 
177
                continue;
 
178
            }
 
179
 
 
180
            if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
 
181
                name = gweather_parser_get_localized_value (parser);
 
182
            else {
 
183
                if (xmlTextReaderNext (parser->xml) != 1)
 
184
                    break;
 
185
            }
 
186
        }
 
187
    }
 
188
 
 
189
    if (parse_tzdata (id, parser->year_start, parser->year_end,
 
190
                      &offset, &has_dst, &dst_offset)) {
 
191
        zone = g_slice_new0 (GWeatherTimezone);
 
192
        zone->ref_count = 1;
 
193
        zone->id = g_strdup (id);
 
194
        zone->name = g_strdup (name);
 
195
        zone->offset = offset;
 
196
        zone->has_dst = has_dst;
 
197
        zone->dst_offset = dst_offset;
 
198
    }
 
199
 
 
200
    xmlFree (id);
 
201
    if (name)
 
202
        xmlFree (name);
 
203
 
 
204
    return zone;
 
205
}
 
206
 
 
207
GWeatherTimezone **
 
208
gweather_timezones_parse_xml (GWeatherParser *parser)
 
209
{
 
210
    GPtrArray *zones;
 
211
    GWeatherTimezone *zone;
 
212
    const char *tagname;
 
213
    int tagtype, i;
 
214
 
 
215
    zones = g_ptr_array_new ();
 
216
 
 
217
    if (xmlTextReaderRead (parser->xml) != 1)
 
218
        goto error_out;
 
219
    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
 
220
           XML_READER_TYPE_END_ELEMENT) {
 
221
        if (tagtype != XML_READER_TYPE_ELEMENT) {
 
222
            if (xmlTextReaderRead (parser->xml) != 1)
 
223
                goto error_out;
 
224
            continue;
 
225
        }
 
226
 
 
227
        tagname = (const char *) xmlTextReaderConstName (parser->xml);
 
228
 
 
229
        if (!strcmp (tagname, "timezone")) {
 
230
            zone = parse_timezone (parser);
 
231
            if (zone)
 
232
                g_ptr_array_add (zones, zone);
 
233
        }
 
234
 
 
235
        if (xmlTextReaderNext (parser->xml) != 1)
 
236
            goto error_out;
 
237
    }
 
238
    if (xmlTextReaderRead (parser->xml) != 1)
 
239
        goto error_out;
 
240
 
 
241
    g_ptr_array_add (zones, NULL);
 
242
    return (GWeatherTimezone **)g_ptr_array_free (zones, FALSE);
 
243
 
 
244
error_out:
 
245
    for (i = 0; i < zones->len; i++)
 
246
        gweather_timezone_unref (zones->pdata[i]);
 
247
    g_ptr_array_free (zones, TRUE);
 
248
    return NULL;
 
249
}
 
250
 
 
251
/**
 
252
 * gweather_timezone_ref:
 
253
 * @zone: a #GWeatherTimezone
 
254
 *
 
255
 * Adds 1 to @zone's reference count.
 
256
 *
 
257
 * Return value: @zone
 
258
 **/
 
259
GWeatherTimezone *
 
260
gweather_timezone_ref (GWeatherTimezone *zone)
 
261
{
 
262
    g_return_val_if_fail (zone != NULL, NULL);
 
263
 
 
264
    zone->ref_count++;
 
265
    return zone;
 
266
}
 
267
 
 
268
/**
 
269
 * gweather_timezone_unref:
 
270
 * @zone: a #GWeatherTimezone
 
271
 *
 
272
 * Subtracts 1 from @zone's reference count and frees it if it reaches 0.
 
273
 **/
 
274
void
 
275
gweather_timezone_unref (GWeatherTimezone *zone)
 
276
{
 
277
    g_return_if_fail (zone != NULL);
 
278
 
 
279
    if (!--zone->ref_count) {
 
280
        g_free (zone->id);
 
281
        g_free (zone->name);
 
282
        g_slice_free (GWeatherTimezone, zone);
 
283
    }
 
284
}
 
285
 
 
286
GType
 
287
gweather_timezone_get_type (void)
 
288
{
 
289
    static volatile gsize type_volatile = 0;
 
290
 
 
291
    if (g_once_init_enter (&type_volatile)) {
 
292
        GType type = g_boxed_type_register_static (
 
293
            g_intern_static_string ("GWeatherTimezone"),
 
294
            (GBoxedCopyFunc) gweather_timezone_ref,
 
295
            (GBoxedFreeFunc) gweather_timezone_unref);
 
296
        g_once_init_leave (&type_volatile, type);
 
297
    }
 
298
    return type_volatile;
 
299
}
 
300
 
 
301
/**
 
302
 * gweather_timezone_get_utc:
 
303
 *
 
304
 * Gets the UTC timezone.
 
305
 *
 
306
 * Return value: a #GWeatherTimezone for UTC, or %NULL on error.
 
307
 **/
 
308
GWeatherTimezone *
 
309
gweather_timezone_get_utc (void)
 
310
{
 
311
    GWeatherTimezone *zone = NULL;
 
312
 
 
313
    zone = g_slice_new0 (GWeatherTimezone);
 
314
    zone->ref_count = 1;
 
315
    zone->id = g_strdup ("GMT");
 
316
    zone->name = g_strdup (_("Greenwich Mean Time"));
 
317
    zone->offset = 0;
 
318
    zone->has_dst = FALSE;
 
319
    zone->dst_offset = 0;
 
320
 
 
321
    return zone;
 
322
}
 
323
 
 
324
/**
 
325
 * gweather_timezone_get_name:
 
326
 * @zone: a #GWeatherTimezone
 
327
 *
 
328
 * Gets @zone's name; a translated, user-presentable string.
 
329
 *
 
330
 * Note that the returned name might not be unique among timezones,
 
331
 * and may not make sense to the user unless it is presented along
 
332
 * with the timezone's country's name (or in some context where the
 
333
 * country is obvious).
 
334
 *
 
335
 * Return value: @zone's name
 
336
 **/
 
337
const char *
 
338
gweather_timezone_get_name (GWeatherTimezone *zone)
 
339
{
 
340
    g_return_val_if_fail (zone != NULL, NULL);
 
341
    return zone->name;
 
342
}
 
343
 
 
344
/**
 
345
 * gweather_timezone_get_tzid:
 
346
 * @zone: a #GWeatherTimezone
 
347
 *
 
348
 * Gets @zone's tzdata identifier, eg "America/New_York".
 
349
 *
 
350
 * Return value: @zone's tzid
 
351
 **/
 
352
const char *
 
353
gweather_timezone_get_tzid (GWeatherTimezone *zone)
 
354
{
 
355
    g_return_val_if_fail (zone != NULL, NULL);
 
356
    return zone->id;
 
357
}
 
358
 
 
359
/**
 
360
 * gweather_timezone_get_offset:
 
361
 * @zone: a #GWeatherTimezone
 
362
 *
 
363
 * Gets @zone's standard offset from UTC, in minutes. Eg, a value of
 
364
 * 120 would indicate "GMT+2".
 
365
 *
 
366
 * Return value: @zone's standard offset, in minutes
 
367
 **/
 
368
int
 
369
gweather_timezone_get_offset (GWeatherTimezone *zone)
 
370
{
 
371
    g_return_val_if_fail (zone != NULL, 0);
 
372
    return zone->offset;
 
373
}
 
374
 
 
375
/**
 
376
 * gweather_timezone_has_dst:
 
377
 * @zone: a #GWeatherTimezone
 
378
 *
 
379
 * Checks if @zone observes daylight/summer time for part of the year.
 
380
 *
 
381
 * Return value: %TRUE if @zone observes daylight/summer time.
 
382
 **/
 
383
gboolean
 
384
gweather_timezone_has_dst (GWeatherTimezone *zone)
 
385
{
 
386
    g_return_val_if_fail (zone != NULL, FALSE);
 
387
    return zone->has_dst;
 
388
}
 
389
 
 
390
/**
 
391
 * gweather_timezone_get_dst_offset:
 
392
 * @zone: a #GWeatherTimezone
 
393
 *
 
394
 * Gets @zone's daylight/summer time offset from UTC, in minutes. Eg,
 
395
 * a value of 120 would indicate "GMT+2". This is only meaningful if
 
396
 * gweather_timezone_has_dst() returns %TRUE.
 
397
 *
 
398
 * Return value: @zone's daylight/summer time offset, in minutes
 
399
 **/
 
400
int
 
401
gweather_timezone_get_dst_offset (GWeatherTimezone *zone)
 
402
{
 
403
    g_return_val_if_fail (zone != NULL, 0);
 
404
    g_return_val_if_fail (zone->has_dst, 0);
 
405
    return zone->dst_offset;
 
406
}
 
407