From f7fee0bfbd5fc3a6a9c27912a064c98b4bb467e1 Mon Sep 17 00:00:00 2001 From: Stelios Bounanos Date: Wed, 10 Dec 2008 22:48:53 +0000 Subject: [PATCH] Add preliminary contest country file support --- src/Makefile.am | 2 + src/include/dxcc.h | 20 +++++ src/misc/dxcc.cxx | 182 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 src/include/dxcc.h create mode 100644 src/misc/dxcc.cxx diff --git a/src/Makefile.am b/src/Makefile.am index 72cd91d2..d51f5853 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -162,6 +162,7 @@ fldigi_SOURCES += \ include/cw.h \ include/debug.h \ include/digiscope.h \ + include/dxcc.h \ include/thor.h \ include/thorvaricode.h \ include/dominoex.h \ @@ -287,6 +288,7 @@ fldigi_SOURCES += \ misc/ascii.cxx \ misc/configuration.cxx \ misc/debug.cxx \ + misc/dxcc.cxx \ misc/flstring.c \ misc/icons.cxx \ misc/log.cxx \ diff --git a/src/include/dxcc.h b/src/include/dxcc.h new file mode 100644 index 00000000..e0a9a66d --- /dev/null +++ b/src/include/dxcc.h @@ -0,0 +1,20 @@ +#ifndef DXCC_H_ +#define DXCC_H_ + +struct dxcc { + const char* country; + int cq_zone; + int itu_zone; + char continent[3]; + float latitude; + float longitude; + float gmt_offset; + dxcc(const char* cn = "", int cq = 0, int itu = 0, const char* ct = "", + float lat = 0.0f, float lon = 0.0f, float tz = 0.0f); +}; + +bool dxcc_open(const char* filename); +void dxcc_close(void); +const dxcc* dxcc_lookup(const char* callsign); + +#endif // DXCC_H_ diff --git a/src/misc/dxcc.cxx b/src/misc/dxcc.cxx new file mode 100644 index 00000000..a68f84a9 --- /dev/null +++ b/src/misc/dxcc.cxx @@ -0,0 +1,182 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dxcc.h" +#include "debug.h" + +using namespace std; + + +dxcc::dxcc(const char* cn, int cq, int itu, const char* ct, float lat, float lon, float tz) + : country(cn), cq_zone(cq), itu_zone(itu), latitude(lat), longitude(lon), gmt_offset(tz) +{ + if (*ct) { + continent[0] = ct[0]; + continent[1] = ct[1]; + } + continent[2] = '\0'; +} + +typedef map dxcc_map; +static dxcc_map* cmap = 0; +static list* cnames = 0; + +static void add_prefix(string& prefix, dxcc* entry); + +bool dxcc_open(const char* filename) +{ + dxcc_close(); + + ifstream in(filename); + if (!in) { + LOG_WARN("Could not read contest country file \"%s\"", filename); + return false; + } + + cmap = new dxcc_map; + cnames = new list; + + dxcc* entry; + string record; + + unsigned nrec = 0; + while (getline(in, record, ';')) { + istringstream is(record); + entry = new dxcc; + nrec++; + + // read country name + cnames->resize(cnames->size() + 1); + getline(is, cnames->back(), ':'); + entry->country = cnames->back().c_str(); + // cq zone + (is >> entry->cq_zone).ignore(); + // itu zone + (is >> entry->itu_zone).ignore(); + // continent + (is >> ws).get(entry->continent, 3).ignore(); + + // latitude + (is >> entry->latitude).ignore(); + // longitude + (is >> entry->longitude).ignore(); + // gmt offset + (is >> entry->gmt_offset).ignore(256, '\n'); + + // prefixes and exceptions + int c; + string prefix; + while ((c = is.peek()) == ' ' || c == '\r' || c == '\n') { + is >> ws; + if (is.peek() == '=') + is.ignore(); + while (getline(is, prefix, ',')) { + add_prefix(prefix, entry); + if ((c = is.peek()) == '\r' || c == '\n') + break; + else if (c == '=') + is.ignore(); + } + } + + in >> ws; // cr/lf after ';' + } + + LOG_INFO("Loaded %zu prefixes for %u countries", cmap->size(), nrec); + return true; +} + +void dxcc_close(void) +{ + delete cnames; + cnames = 0; + delete cmap; + cmap = 0; +} + +const dxcc* dxcc_lookup(const char* callsign) +{ + if (!cmap) + return NULL; + + string sstr; + sstr.resize(strlen(callsign)); + transform(callsign, callsign + sstr.length(), sstr.begin(), static_cast(toupper)); + + dxcc_map::const_iterator entry; + size_t len = sstr.length(); + do { + sstr.resize(len--); + if ((entry = cmap->find(sstr)) != cmap->end()) + return entry->second; + } while (len); + + return NULL; +} + +static void add_prefix(string& prefix, dxcc* entry) +{ + static dxcc_map::iterator prev_entry = cmap->begin(); + + string::size_type i = prefix.find_first_of("([<{"); + if (likely(i == string::npos)) { + prev_entry = cmap->insert(prev_entry, make_pair(prefix, entry)); + return; + } + + string::size_type j = i, first = i; + do { + entry = new struct dxcc(*entry); + switch (prefix[i++]) { // increment i past opening bracket + case '(': + if ((j = prefix.find(')', i)) == string::npos) { + delete entry; + return; + } + prefix[j] = '\0'; + entry->cq_zone = atoi(prefix.data() + i); + break; + case '[': + if ((j = prefix.find(']', i)) == string::npos) { + delete entry; + return; + } + prefix[j] = '\0'; + entry->itu_zone = atoi(prefix.data() + i); + break; + case '<': + if ((j = prefix.find('/', i)) == string::npos) { + delete entry; + return; + } + prefix[j] = '\0'; + entry->latitude = atof(prefix.data() + i); + if ((j = prefix.find('>', j)) == string::npos) { + delete entry; + return; + } + prefix[j] = '\0'; + entry->longitude = atof(prefix.data() + i); + break; + case '{': + if ((j = prefix.find('}', i)) == string::npos) { + delete entry; + return; + } + memcpy(entry->continent, prefix.data() + i, 2); + break; + } + } while ((i = prefix.find_first_of("([<{", j)) != string::npos); + + prefix.erase(first); + prev_entry = cmap->insert(prev_entry, make_pair(prefix, entry)); +}