~charlesk/gnome-control-center/make-new-panel

« back to all changes in this revision

Viewing changes to panels/datetime/tz.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

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: 8 -*- */
 
2
/* Generic timezone utilities.
 
3
 *
 
4
 * Copyright (C) 2000-2001 Ximian, Inc.
 
5
 *
 
6
 * Authors: Hans Petter Jansson <hpj@ximian.com>
 
7
 * 
 
8
 * Largely based on Michael Fulbright's work on Anaconda.
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation; either version 2 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
23
 */
 
24
 
 
25
 
 
26
#include <glib.h>
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
#include <time.h>
 
31
#include <math.h>
 
32
#include <string.h>
 
33
#include "tz.h"
 
34
 
 
35
 
 
36
/* Forward declarations for private functions */
 
37
 
 
38
static float convert_pos (gchar *pos, int digits);
 
39
static int compare_country_names (const void *a, const void *b);
 
40
static void sort_locations_by_country (GPtrArray *locations);
 
41
static gchar * tz_data_file_get (void);
 
42
static void load_backward_tz (TzDB *tz_db);
 
43
 
 
44
/* ---------------- *
 
45
 * Public interface *
 
46
 * ---------------- */
 
47
TzDB *
 
48
tz_load_db (void)
 
49
{
 
50
        gchar *tz_data_file;
 
51
        TzDB *tz_db;
 
52
        FILE *tzfile;
 
53
        char buf[4096];
 
54
 
 
55
        tz_data_file = tz_data_file_get ();
 
56
        if (!tz_data_file) {
 
57
                g_warning ("Could not get the TimeZone data file name");
 
58
                return NULL;
 
59
        }
 
60
        tzfile = fopen (tz_data_file, "r");
 
61
        if (!tzfile) {
 
62
                g_warning ("Could not open *%s*\n", tz_data_file);
 
63
                g_free (tz_data_file);
 
64
                return NULL;
 
65
        }
 
66
 
 
67
        tz_db = g_new0 (TzDB, 1);
 
68
        tz_db->locations = g_ptr_array_new ();
 
69
 
 
70
        while (fgets (buf, sizeof(buf), tzfile))
 
71
        {
 
72
                gchar **tmpstrarr;
 
73
                gchar *latstr, *lngstr, *p;
 
74
                TzLocation *loc;
 
75
 
 
76
                if (*buf == '#') continue;
 
77
 
 
78
                g_strchomp(buf);
 
79
                tmpstrarr = g_strsplit(buf,"\t", 6);
 
80
                
 
81
                latstr = g_strdup (tmpstrarr[1]);
 
82
                p = latstr + 1;
 
83
                while (*p != '-' && *p != '+') p++;
 
84
                lngstr = g_strdup (p);
 
85
                *p = '\0';
 
86
                
 
87
                loc = g_new0 (TzLocation, 1);
 
88
                loc->country = g_strdup (tmpstrarr[0]);
 
89
                loc->zone = g_strdup (tmpstrarr[2]);
 
90
                loc->latitude  = convert_pos (latstr, 2);
 
91
                loc->longitude = convert_pos (lngstr, 3);
 
92
                
 
93
#ifdef __sun
 
94
                if (tmpstrarr[3] && *tmpstrarr[3] == '-' && tmpstrarr[4])
 
95
                        loc->comment = g_strdup (tmpstrarr[4]);
 
96
 
 
97
                if (tmpstrarr[3] && *tmpstrarr[3] != '-' && !islower(loc->zone)) {
 
98
                        TzLocation *locgrp;
 
99
 
 
100
                        /* duplicate entry */
 
101
                        locgrp = g_new0 (TzLocation, 1);
 
102
                        locgrp->country = g_strdup (tmpstrarr[0]);
 
103
                        locgrp->zone = g_strdup (tmpstrarr[3]);
 
104
                        locgrp->latitude  = convert_pos (latstr, 2);
 
105
                        locgrp->longitude = convert_pos (lngstr, 3);
 
106
                        locgrp->comment = (tmpstrarr[4]) ? g_strdup (tmpstrarr[4]) : NULL;
 
107
 
 
108
                        g_ptr_array_add (tz_db->locations, (gpointer) locgrp);
 
109
                }
 
110
#else
 
111
                loc->comment = (tmpstrarr[3]) ? g_strdup(tmpstrarr[3]) : NULL;
 
112
#endif
 
113
 
 
114
                g_ptr_array_add (tz_db->locations, (gpointer) loc);
 
115
 
 
116
                g_free (latstr);
 
117
                g_free (lngstr);
 
118
                g_strfreev (tmpstrarr);
 
119
        }
 
120
        
 
121
        fclose (tzfile);
 
122
        
 
123
        /* now sort by country */
 
124
        sort_locations_by_country (tz_db->locations);
 
125
        
 
126
        g_free (tz_data_file);
 
127
 
 
128
        /* Load up the hashtable of backward links */
 
129
        load_backward_tz (tz_db);
 
130
 
 
131
        return tz_db;
 
132
}
 
133
 
 
134
static void
 
135
tz_location_free (TzLocation *loc)
 
136
{
 
137
        g_free (loc->country);
 
138
        g_free (loc->zone);
 
139
        g_free (loc->comment);
 
140
 
 
141
        g_free (loc);
 
142
}
 
143
 
 
144
void
 
145
tz_db_free (TzDB *db)
 
146
{
 
147
        g_ptr_array_foreach (db->locations, (GFunc) tz_location_free, NULL);
 
148
        g_ptr_array_free (db->locations, TRUE);
 
149
        g_hash_table_destroy (db->backward);
 
150
        g_free (db);
 
151
}
 
152
 
 
153
GPtrArray *
 
154
tz_get_locations (TzDB *db)
 
155
{
 
156
        return db->locations;
 
157
}
 
158
 
 
159
 
 
160
gchar *
 
161
tz_location_get_country (TzLocation *loc)
 
162
{
 
163
        return loc->country;
 
164
}
 
165
 
 
166
 
 
167
gchar *
 
168
tz_location_get_zone (TzLocation *loc)
 
169
{
 
170
        return loc->zone;
 
171
}
 
172
 
 
173
 
 
174
gchar *
 
175
tz_location_get_comment (TzLocation *loc)
 
176
{
 
177
        return loc->comment;
 
178
}
 
179
 
 
180
 
 
181
void
 
182
tz_location_get_position (TzLocation *loc, double *longitude, double *latitude)
 
183
{
 
184
        *longitude = loc->longitude;
 
185
        *latitude = loc->latitude;
 
186
}
 
187
 
 
188
glong
 
189
tz_location_get_utc_offset (TzLocation *loc)
 
190
{
 
191
        TzInfo *tz_info;
 
192
        glong offset;
 
193
 
 
194
        tz_info = tz_info_from_location (loc);
 
195
        offset = tz_info->utc_offset;
 
196
        tz_info_free (tz_info);
 
197
        return offset;
 
198
}
 
199
 
 
200
TzInfo *
 
201
tz_info_from_location (TzLocation *loc)
 
202
{
 
203
        TzInfo *tzinfo;
 
204
        time_t curtime;
 
205
        struct tm *curzone;
 
206
        
 
207
        g_return_val_if_fail (loc != NULL, NULL);
 
208
        g_return_val_if_fail (loc->zone != NULL, NULL);
 
209
        
 
210
        setenv ("TZ", loc->zone, 1);
 
211
        
 
212
#if 0
 
213
        tzset ();
 
214
#endif
 
215
        tzinfo = g_new0 (TzInfo, 1);
 
216
 
 
217
        curtime = time (NULL);
 
218
        curzone = localtime (&curtime);
 
219
 
 
220
#ifndef __sun
 
221
        /* Currently this solution doesnt seem to work - I get that */
 
222
        /* America/Phoenix uses daylight savings, which is wrong    */
 
223
        tzinfo->tzname_normal = g_strdup (curzone->tm_zone);
 
224
        if (curzone->tm_isdst) 
 
225
                tzinfo->tzname_daylight =
 
226
                        g_strdup (&curzone->tm_zone[curzone->tm_isdst]);
 
227
        else
 
228
                tzinfo->tzname_daylight = NULL;
 
229
 
 
230
        tzinfo->utc_offset = curzone->tm_gmtoff;
 
231
#else
 
232
        tzinfo->tzname_normal = NULL;
 
233
        tzinfo->tzname_daylight = NULL;
 
234
        tzinfo->utc_offset = 0;
 
235
#endif
 
236
 
 
237
        tzinfo->daylight = curzone->tm_isdst;
 
238
 
 
239
        setenv ("TZ", "", 1);
 
240
        
 
241
        return tzinfo;
 
242
}
 
243
 
 
244
 
 
245
void
 
246
tz_info_free (TzInfo *tzinfo)
 
247
{
 
248
        g_return_if_fail (tzinfo != NULL);
 
249
        
 
250
        if (tzinfo->tzname_normal) g_free (tzinfo->tzname_normal);
 
251
        if (tzinfo->tzname_daylight) g_free (tzinfo->tzname_daylight);
 
252
        g_free (tzinfo);
 
253
}
 
254
 
 
255
struct {
 
256
        const char *orig;
 
257
        const char *dest;
 
258
} aliases[] = {
 
259
        { "Asia/Istanbul",  "Europe/Istanbul" },        /* Istanbul is in both Europe and Asia */
 
260
        { "Europe/Nicosia", "Asia/Nicosia" },           /* Ditto */
 
261
        { "EET",            "Europe/Istanbul" },        /* Same tz as the 2 above */
 
262
        { "HST",            "Pacific/Honolulu" },
 
263
        { "WET",            "Europe/Brussels" },        /* Other name for the mainland Europe tz */
 
264
        { "CET",            "Europe/Brussels" },        /* ditto */
 
265
        { "MET",            "Europe/Brussels" },
 
266
        { "Etc/Zulu",       "Etc/GMT" },
 
267
        { "Etc/UTC",        "Etc/GMT" },
 
268
        { "GMT",            "Etc/GMT" },
 
269
        { "Greenwich",      "Etc/GMT" },
 
270
        { "Etc/UCT",        "Etc/GMT" },
 
271
        { "Etc/GMT0",       "Etc/GMT" },
 
272
        { "Etc/GMT+0",      "Etc/GMT" },
 
273
        { "Etc/GMT-0",      "Etc/GMT" },
 
274
        { "Etc/Universal",  "Etc/GMT" },
 
275
        { "PST8PDT",        "America/Los_Angeles" },    /* Other name for the Atlantic tz */
 
276
        { "EST",            "America/New_York" },       /* Other name for the Eastern tz */
 
277
        { "EST5EDT",        "America/New_York" },       /* ditto */
 
278
        { "CST6CDT",        "America/Chicago" },        /* Other name for the Central tz */
 
279
        { "MST",            "America/Denver" },         /* Other name for the mountain tz */
 
280
        { "MST7MDT",        "America/Denver" },         /* ditto */
 
281
};
 
282
 
 
283
static gboolean
 
284
compare_timezones (const char *a,
 
285
                   const char *b)
 
286
{
 
287
        if (g_str_equal (a, b))
 
288
                return TRUE;
 
289
        if (strchr (b, '/') == NULL) {
 
290
                char *prefixed;
 
291
 
 
292
                prefixed = g_strdup_printf ("/%s", b);
 
293
                if (g_str_has_suffix (a, prefixed)) {
 
294
                        g_free (prefixed);
 
295
                        return TRUE;
 
296
                }
 
297
                g_free (prefixed);
 
298
        }
 
299
 
 
300
        return FALSE;
 
301
}
 
302
 
 
303
char *
 
304
tz_info_get_clean_name (TzDB *tz_db,
 
305
                        const char *tz)
 
306
{
 
307
        char *ret;
 
308
        const char *timezone;
 
309
        guint i;
 
310
        gboolean replaced;
 
311
 
 
312
        /* Remove useless prefixes */
 
313
        if (g_str_has_prefix (tz, "right/"))
 
314
                tz = tz + strlen ("right/");
 
315
        else if (g_str_has_prefix (tz, "posix/"))
 
316
                tz = tz + strlen ("posix/");
 
317
 
 
318
        /* Here start the crazies */
 
319
        replaced = FALSE;
 
320
 
 
321
        for (i = 0; i < G_N_ELEMENTS (aliases); i++) {
 
322
                if (compare_timezones (tz, aliases[i].orig)) {
 
323
                        replaced = TRUE;
 
324
                        timezone = aliases[i].dest;
 
325
                        break;
 
326
                }
 
327
        }
 
328
 
 
329
        /* Try again! */
 
330
        if (!replaced) {
 
331
                /* Ignore crazy solar times from the '80s */
 
332
                if (g_str_has_prefix (tz, "Asia/Riyadh") ||
 
333
                    g_str_has_prefix (tz, "Mideast/Riyadh")) {
 
334
                        timezone = "Asia/Riyadh";
 
335
                        replaced = TRUE;
 
336
                }
 
337
        }
 
338
 
 
339
        if (!replaced)
 
340
                timezone = tz;
 
341
 
 
342
        ret = g_hash_table_lookup (tz_db->backward, timezone);
 
343
        if (ret == NULL)
 
344
                return g_strdup (timezone);
 
345
        return g_strdup (ret);
 
346
}
 
347
 
 
348
/* ----------------- *
 
349
 * Private functions *
 
350
 * ----------------- */
 
351
 
 
352
static gchar *
 
353
tz_data_file_get (void)
 
354
{
 
355
        gchar *file;
 
356
 
 
357
        file = g_strdup (TZ_DATA_FILE);
 
358
 
 
359
        return file;
 
360
}
 
361
 
 
362
static float
 
363
convert_pos (gchar *pos, int digits)
 
364
{
 
365
        gchar whole[10];
 
366
        gchar *fraction;
 
367
        gint i;
 
368
        float t1, t2;
 
369
        
 
370
        if (!pos || strlen(pos) < 4 || digits > 9) return 0.0;
 
371
        
 
372
        for (i = 0; i < digits + 1; i++) whole[i] = pos[i];
 
373
        whole[i] = '\0';
 
374
        fraction = pos + digits + 1;
 
375
 
 
376
        t1 = g_strtod (whole, NULL);
 
377
        t2 = g_strtod (fraction, NULL);
 
378
 
 
379
        if (t1 >= 0.0) return t1 + t2/pow (10.0, strlen(fraction));
 
380
        else return t1 - t2/pow (10.0, strlen(fraction));
 
381
}
 
382
 
 
383
 
 
384
#if 0
 
385
 
 
386
/* Currently not working */
 
387
static void
 
388
free_tzdata (TzLocation *tz)
 
389
{
 
390
        
 
391
        if (tz->country)
 
392
          g_free(tz->country);
 
393
        if (tz->zone)
 
394
          g_free(tz->zone);
 
395
        if (tz->comment)
 
396
          g_free(tz->comment);
 
397
        
 
398
        g_free(tz);
 
399
}
 
400
#endif
 
401
 
 
402
 
 
403
static int
 
404
compare_country_names (const void *a, const void *b)
 
405
{
 
406
        const TzLocation *tza = * (TzLocation **) a;
 
407
        const TzLocation *tzb = * (TzLocation **) b;
 
408
        
 
409
        return strcmp (tza->zone, tzb->zone);
 
410
}
 
411
 
 
412
 
 
413
static void
 
414
sort_locations_by_country (GPtrArray *locations)
 
415
{
 
416
        qsort (locations->pdata, locations->len, sizeof (gpointer),
 
417
               compare_country_names);
 
418
}
 
419
 
 
420
static void
 
421
load_backward_tz (TzDB *tz_db)
 
422
{
 
423
  GError *error = NULL;
 
424
  char **lines, *contents;
 
425
  guint i;
 
426
 
 
427
  tz_db->backward = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
428
 
 
429
  if (g_file_get_contents (GNOMECC_DATA_DIR "/datetime/backward", &contents, NULL, &error) == FALSE)
 
430
    {
 
431
      g_warning ("Failed to load 'backward' file: %s", error->message);
 
432
      return;
 
433
    }
 
434
  lines = g_strsplit (contents, "\n", -1);
 
435
  g_free (contents);
 
436
  for (i = 0; lines[i] != NULL; i++)
 
437
    {
 
438
      char **items;
 
439
      guint j;
 
440
      char *real, *alias;
 
441
 
 
442
      if (g_ascii_strncasecmp (lines[i], "Link\t", 5) != 0)
 
443
        continue;
 
444
 
 
445
      items = g_strsplit (lines[i], "\t", -1);
 
446
      real = NULL;
 
447
      alias = NULL;
 
448
      /* Skip the "Link<tab>" part */
 
449
      for (j = 1; items[j] != NULL; j++)
 
450
        {
 
451
          if (items[j][0] == '\0')
 
452
            continue;
 
453
          if (real == NULL)
 
454
            {
 
455
              real = items[j];
 
456
              continue;
 
457
            }
 
458
          alias = items[j];
 
459
          break;
 
460
        }
 
461
 
 
462
      if (real == NULL || alias == NULL)
 
463
        g_warning ("Could not parse line: %s", lines[i]);
 
464
 
 
465
      /* We don't need more than one name for it */
 
466
      if (g_str_equal (real, "Etc/UTC") ||
 
467
          g_str_equal (real, "Etc/UCT"))
 
468
        real = "Etc/GMT";
 
469
 
 
470
      g_hash_table_insert (tz_db->backward, g_strdup (alias), g_strdup (real));
 
471
      g_strfreev (items);
 
472
    }
 
473
  g_strfreev (lines);
 
474
}
 
475