const KstTimezones::ZoneMap KstTimezones::allZones() { // Have we already done all the hard work? If not, create the cache. if (m_zones) return *m_zones; m_zones = new ZoneMap(); // Go read the database. // // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones // is the place to look. The TZI binary value is the TIME_ZONE_INFORMATION structure. // // For Unix its all easy except knowing where to look. Try the LSB location first. QFile f; m_zoneinfoDir = "/usr/share/zoneinfo"; f.setName(m_zoneinfoDir + "/zone.tab"); if (!f.open(IO_ReadOnly)) { m_zoneinfoDir = "/usr/lib/zoneinfo"; f.setName(m_zoneinfoDir + "/zone.tab"); if (!f.open(IO_ReadOnly)) { m_zoneinfoDir = ::getenv("TZDIR"); f.setName(m_zoneinfoDir + "/zone.tab"); if (m_zoneinfoDir.isEmpty() || !f.open(IO_ReadOnly)) { // Solaris support. Synthesise something that looks like a zone.tab. // // /bin/grep -h ^Zone /usr/share/lib/zoneinfo/src/* | /bin/awk '{print "??\t+9999+99999\t" $2}' // // where the country code is set to "??" and the lattitude/longitude // values are dummies. m_zoneinfoDir = "/usr/share/lib/zoneinfo"; KTempFile temp; KShellProcess reader; reader << "/bin/grep" << "-h" << "^Zone" << m_zoneinfoDir << "/src/*" << temp.name() << "|" << "/bin/awk" << "'{print \"??\\t+9999+99999\\t\" $2}'"; // Note the use of blocking here...it is a trivial amount of data! temp.close(); reader.start(KProcess::Block); f.setName(temp.name()); if (!temp.status() || !f.open(IO_ReadOnly)) { return *m_zones; } } } } // Parse the zone.tab. QTextStream str(&f); QRegExp lineSeparator("[ \t]"); QRegExp ordinateSeparator("[+-]"); KSharedPtr<KstTimezoneSource> db(new KstTimezoneSource(m_zoneinfoDir)); while (!str.atEnd()) { QString line = str.readLine(); if (line.isEmpty() || '#' == line[0]) continue; QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4); if (tokens.count() < 3) { continue; } // Got three tokens. Now check for two ordinates plus first one is "". QStringList ordinates = KStringHandler::perlSplit(ordinateSeparator, tokens[1], 2); if (ordinates.count() < 2) { continue; } float latitude = convertCoordinate(ordinates[1]); float longitude = convertCoordinate(ordinates[2]); // Add entry to list. if (tokens[0] == "??") tokens[0] = ""; KstTimezone *timezone = new KstTimezone(db, tokens[2], tokens[0], latitude, longitude, tokens[3]); add(timezone); } f.close(); return *m_zones; }
/* * Find the location of the zoneinfo files and store in mZoneinfoDir. * Parse zone.tab and for each time zone, create a KSystemTimeZone instance. */ void KSystemTimeZonesPrivate::readZoneTab(bool update) { kDebug(161) << "readZoneTab(" << m_zonetab<< ")"; QStringList newZones; QFile f; f.setFileName(m_zonetab); if (!f.open(QIODevice::ReadOnly)) return; QTextStream str(&f); QRegExp lineSeparator("[ \t]"); QRegExp ordinateSeparator("[+-]"); if (!m_source) m_source = new KSystemTimeZoneSource; while (!str.atEnd()) { QString line = str.readLine(); if (line.isEmpty() || line[0] == '#') continue; QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4); int n = tokens.count(); if (n < 3) { kError(161) << "readZoneTab(): invalid record: " << line << endl; continue; } // Got three tokens. Now check for two ordinates plus first one is "". int i = tokens[1].indexOf(ordinateSeparator, 1); if (i < 0) { kError(161) << "readZoneTab() " << tokens[2] << ": invalid coordinates: " << tokens[1] << endl; continue; } float latitude = convertCoordinate(tokens[1].left(i)); float longitude = convertCoordinate(tokens[1].mid(i)); // Add entry to list. if (tokens[0] == "??") tokens[0] = ""; // Solaris sets the empty Comments field to '-', making it not empty. // Clean it up. if (n > 3 && tokens[3] == "-") tokens[3] = ""; KSystemTimeZone tz(m_source, tokens[2], tokens[0], latitude, longitude, (n > 3 ? tokens[3] : QString())); if (update) { // Update the existing collection with the new zone definition newZones += tz.name(); KTimeZone oldTz = zone(tz.name()); if (oldTz.isValid()) oldTz.updateBase(tz); // the zone previously existed, so update its definition else add(tz); // the zone didn't previously exist, so add it } else add(tz); } f.close(); if (update) { // Remove any zones from the collection which no longer exist const ZoneMap oldZones = zones(); for (ZoneMap::ConstIterator it = oldZones.constBegin(); it != oldZones.constEnd(); ++it) { if (newZones.indexOf(it.key()) < 0) remove(it.value()); } } }