/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2017 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "oFreeImport.h" #include "oEvent.h" #include #include "gdioutput.h" #include "gdifonts.h" #include "localizer.h" #include "meos_util.h" #include "io.h" #include "fcntl.h" #include "sys/stat.h" #include #include void oWordDB::insert(const char *s) { str.insert(s); } bool oWordDB::lookup(const char *s) const { return str.count(s)==1; } const char *oWordDB::deserialize(const char *bf, const char *end) { BYTE s=bf[0]; bf++; str.clear(); for (int k=0;kend) throw std::exception("Internal error deserializing wordlist."); str.insert(n); } return bf; } char *oWordDB::serialize(char *bf) const { //Randomize order for better search performace on reload. BYTE s=BYTE(str.size()); vector rnd(s); int k=0; for (set::const_iterator it=str.begin(); it!=str.end(); ++it) rnd[k++]=*it; bf[0]=s; bf++; for (k=0;k::const_iterator it=str.begin(); it!=str.end(); ++it) s+=it->size()+1; return s; } pWordDatabase oWordDB::split() { if (str.size()>=hashSplitSize) { oWordIndexHash *db=new oWordIndexHash(false); set::iterator it; for(it=str.begin();it!=str.end();++it) db->insert(it->c_str()); delete this; return db; } else return this; } size_t oWordDB::size() { return str.size(); } void oWordIndexHash::clear() { MapTable::iterator it; for(it=unMapped.begin(); it!=unMapped.end(); ++it) if (it->second) delete it->second; unMapped.clear(); for(int k=0;kdeserialize(bf, end); } DWORD i=a-indexMapStart; if (i<=(indexMapEnd-indexMapStart)) { if (hashTable[i]) throw std::exception("Internal error deserilizing wordlist."); else hashTable[i]=db; } else unMapped[a]=db; } return bf; } char *oWordIndexHash::serialize(char *bf) const { int s=unMapped.size(); for (int k=0;kfirst; if (bf[0]) { bf[1]=it->second->getType(); bf=it->second->serialize(bf+2); } else { //Empty string. bf[1]=0; bf+=2; } } for (int k=0;kgetType(); bf=hashTable[k]->serialize(bf+2); } } return bf; } int oWordIndexHash::serialSize() const { int s=1; for (int k=0;kserialSize()+2; } for(MapTable::const_iterator it=unMapped.begin(); it!=unMapped.end(); ++it) s+=it->second ? it->second->serialSize()+2: 2; return s; } void oWordIndexHash::insert(const char *s) { DWORD i=BYTE(s[0])-indexMapStart; if (i<=(indexMapEnd-indexMapStart)) { if (!hashTable[i]) { hashTable[i]=new oWordDB(); hashTable[i]->insert(s+1); } else { hashTable[i]=hashTable[i]->split(); hashTable[i]->insert(s+1); } } else { if (s[0]==0) unMapped[0]=0; //Empty string else { MapTable::iterator it=unMapped.find(s[0]); if (it==unMapped.end()) { pWordDatabase db(hashAll ? pWordDatabase(new oWordIndexHash(false)): pWordDatabase(new oWordDB())); db->insert(s+1); unMapped[s[0]]=db; } else { if (it->second) { it->second=it->second->split(); it->second->insert(s+1); } else assert(s[0]==0); } } } } bool oWordIndexHash::lookup(const char *s) const { DWORD i=BYTE(s[0])-indexMapStart; if (i<=(indexMapEnd-indexMapStart)) { if (!hashTable[i]) return false; else return hashTable[i]->lookup(s+1); } else { MapTable::const_iterator it=unMapped.find(s[0]); if (it==unMapped.end()) return false; else if (s[0]==0) return true; else return it->second->lookup(s+1); } } oWordIndexHash::oWordIndexHash(bool hashAll_) : hashAll(hashAll_) { for(int k=0;k &serial) const { int s=wh.serialSize(); serial.resize(s); wh.serialize(&serial[0]); } void oWordList::deserialize(const vector &serial) { wh.clear(); wh.deserialize(&serial[0], &serial[0]+serial.size()); } void oWordList::save(const char *file) const { int f=-1; _sopen_s(&f, file, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, _SH_DENYWR, _S_IREAD|_S_IWRITE); if (f!=-1) { vector serial; serialize(serial); char *hdr="MWDB"; _write(f, hdr, 4); DWORD s=serial.size(); _write(f, &s, 4); _write(f, &serial[0], s); _close(f); } else throw std::exception("Could not save word database."); } void oWordList::load(const char *file) { string ex=string("Bad word database. ")+file; int f=-1; _sopen_s(&f, file, _O_BINARY|_O_RDONLY, _SH_DENYWR, _S_IREAD|_S_IWRITE); if (f!=-1) { char hdr[5]={0,0,0,0,0}; _read(f, hdr, 4); if ( strcmp(hdr, "MWDB")!=0 ) throw std::exception(ex.c_str()); DWORD s=0; _read(f, &s, 4); vector serial(s); if (_read(f, &serial[0], s)!=s) throw std::exception(ex.c_str()); _close(f); deserialize(serial); } else throw std::exception(ex.c_str()); } oFreeImport::oFreeImport(void) { separator[0]=0; for(int k=1;k<256;k++) separator[k]=k<30 ? 1:0; separator[' ']=1; separator[',']=1; separator[';']=1; separator['(']=1; separator[')']=1; separator['/']=1; loaded=false; } oFreeImport::~oFreeImport(void) { } char *trim(char *str) { int k=strlen(str)-1; while(k>=0 && (isspace(BYTE(str[k])) || BYTE(str[k])==BYTE(160))) str[k--] = 0; while(isspace(BYTE(*str)) || BYTE(str[k])==BYTE(160)) str++; return str; } char *oFreeImport::extractPart(char *&str, int &wordCount) const { wordCount=0; while (separator[*LPBYTE(str)]) str++; if (!*str) return str; char *out=str; wordCount=1; while (*str && (!separator[*LPBYTE(str)] || *str==' ')) { if (*str==' ') { while (*++str==' '); if (separator[*LPBYTE(str)] || !*str) { if (*str) *str++=0; return trim(out); } wordCount++; } str++; } if (*str) *str++=0; return trim(out); } char *oFreeImport::extractWord(char *&str, int &count) const { count=0; while (separator[*str]) str++; if (!*str) return str; char *out=str; count=1; while (*str && !separator[*LPBYTE(str)]) { count++; str++; } if (*str) *str++=0; return out; } char *oFreeImport::extractLine(char *&str, int &count) const { count=0; while (*str=='\n') str++; char *out=str; while (*str && *str!='\n') { str++; count++; } if (*str) *str++=0; return out; } oEntryPerson::oEntryPerson(const string &clb) { club = clb; cardNo=0; } void oEntryPerson::swap() { if (!name1.empty()) std::swap(name1, name2); } int oEntryPerson::nameCount() const { if (!name2.empty()) return countWords(name1.c_str()) + countWords(name2.c_str()); else return countWords(name1.c_str()); } void oEntryBlock::clear(const string &rulingClub, const string &rulingClass) { ePersons.clear(); eClub = rulingClub; eClass = rulingClass; eStartTime.clear(); canInsertName = true; isClassSet = false; // Count only explicit set class nClubsSet = rulingClub.empty() ? 0 : 1; } oEntryBlock::oEntryBlock(const oFreeImport &importer) : freeImporter(importer) { canInsertName=true; nClubsSet = 0; isClassSet = false; } oEntryBlock::oEntryBlock(const oEntryBlock &eb) : freeImporter(eb.freeImporter) { ePersons = eb.ePersons; eClub = eb.eClub; eClass = eb.eClass; eStartTime = eb.eStartTime; canInsertName = eb.canInsertName; isClassSet = eb.isClassSet; nClubsSet = eb.nClubsSet; } void oEntryBlock::operator=(const oEntryBlock &eb) { ePersons = eb.ePersons; eClub = eb.eClub; eClass = eb.eClass; eStartTime = eb.eStartTime; canInsertName = eb.canInsertName; isClassSet = eb.isClassSet; nClubsSet = eb.nClubsSet; } void oEntryBlock::setClass(const char *s) { eClass=s; if (!ePersons.empty()) canInsertName=false; isClassSet = true; completeName(); } void oEntryBlock::setClub(const char *s) { eClub = s; nClubsSet++; for (size_t k = 0; k=freeImporter.getExpectedNumRunners(eClass)) canInsertName=false; completeName(); } void oEntryBlock::completeName() { if (!ePersons.empty() && !ePersons.back().name1.empty() && ePersons.back().name2.empty()) ePersons.back().name2="*"; } void oEntryBlock::setStartTime(const char *s) { eStartTime=s; if (!ePersons.empty()) canInsertName=false; completeName(); } void oEntryBlock::setCardNo(int c) { if (ePersons.empty() || ePersons.back().cardNo!=0) ePersons.push_back(oEntryPerson(eClub)); for (size_t i = 0; i < ePersons.size(); i++) { if (ePersons[i].cardNo == 0) { ePersons[i].cardNo=c; break; } } completeName(); } bool oEntryBlock::needCard() const { if (ePersons.empty()) return true; for (size_t i = 0; i < ePersons.size(); i++) { if (ePersons[i].cardNo == 0) { return true; } } return false; } string oEntryBlock::getTeamName() const { set clubs; if (!eClub.empty()) clubs.insert(eClub); for (size_t k = 0; k 1) { string tname; for (set::iterator it = clubs.begin(); it != clubs.end(); ++it) { if (!tname.empty()) tname += "/"; tname += *it; } return tname; } else return "Lag"; } string oEntryBlock::getName(int k) const { if (size_t(k)>=ePersons.size()) return "N.N."; string n=ePersons[k].name1; if (!ePersons[k].name2.empty()) n+=" "+ePersons[k].name2; return n; } string oEntryBlock::getClub(int k) const { if (size_t(k)>=ePersons.size()) return eClub; const string &c=ePersons[k].club; if (!c.empty()) return c; return eClub; } int oEntryBlock::getCard(int k) const { if (k oEntryBlock::getPersons() const { vector names; string n; char bf[256]; for (size_t k=0;k0) { sprintf_s(bf, " (%d)", ePersons[k].cardNo); n+=bf; } names.push_back(n); n.clear(); } return names; } int oEntryBlock::nameCount() { if (ePersons.empty()) return 0; int space=0; const string &name1=ePersons.back().name1; const string &name2=ePersons.back().name2; if (!name1.empty()) { space++; for (size_t k=0;k=2 && countWords(s)>=2) completeName(); if (complete) { if (!ePersons.back().name1.empty()) ePersons.push_back(oEntryPerson(eClub)); ePersons.back().name1=s; } else { if (ePersons.back().name1.empty()) ePersons.back().name1=s; else if (ePersons.back().name2.empty()) ePersons.back().name2=s; else { ePersons.push_back(oEntryPerson(eClub)); ePersons.back().name1=s; } } } bool oEntryBlock::acceptMoreClubs(int expectedNumRunners) const { return nClubsSet < int(ePersons.size()) || nClubsSet < expectedNumRunners; } bool oEntryBlock::expectMoreNames(int expectedNumRunners) const { return int(ePersons.size()) < expectedNumRunners || (expectedNumRunners == ePersons.size() && ePersons.back().nameCount()<=1); } void oEntryBlock::cleanEntry() { for (size_t k=0;k &b, int &offset, int &delta) const { vector d; d.reserve(b.size()/3); for (size_t k=0;k1) { int x=offset; while(unsigned(x)=1000 && k<10000000); } bool oFreeImport::isTime(const string &m) const { if (m.empty() || m.length()>9) return false; for(size_t k=0;k23) return false; int minute=0; int second=0; int kp=m.find_first_of(':'); if (kp>0) { string mtext=m.substr(kp+1); minute=atoi(mtext.c_str()); if (minute<0 || minute>60) return false; kp=mtext.find_last_of(':'); if (kp>0) { second=atoi(mtext.substr(kp+1).c_str()); if (second<0 || second>60) return false; } } int t=hour*3600+minute*60+second; if (t<=0) return false; return true; } bool oFreeImport::isCrap(const char *p) const { int s=strlen(p); for (int k=0;k='0' && p[k]<='9')) return true; } return false; } bool oFreeImport::isName(const char *p) const { char bf[1024]; strcpy_s(bf, p); char *str=bf; int c=1; vector w; while(c>0) { const char *out= extractWord(str,c); if (c>0) w.push_back(out); } if (w.size()==1) return familyDB.lookup(w[0]) || givenDB.lookup(w[0]); else if (w.size()<4) { int n=0; int t=(w.size()+1)/2; for (size_t k=0;k=t; } return false; } void oFreeImport::analyzePart(char *part, const MatchPattern &ptrn, int nNamesPerPart, oEntryBlock &entry, vector &entries, bool allowName) { vector words; int count=1; while (count>0) { const char *out=extractWord(part, count); if (count>0) words.push_back(out); } allowName &= !entry.hasName() || nNamesPerPart!=1; vector isNameV(words.size(), false); vector isClub(words.size(), false); vector isClass(words.size(), false); vector isCardV(words.size(), false); vector isTimeV(words.size(), false); vector used(words.size(), false); int names=0; int classes=0; int clubs=0; int cards=0; int times=0; for (size_t j=0;j0 && (clubs+classes+cards+times)<1) { if (!entry.canInsertName) { entry.cleanEntry(); entries.push_back(entry); entry.clear(rulingClub, rulingClass); } string n; for (size_t j=0;j0 && !entry.expectMoreNames(getExpectedNumRunners(entry.eClass)) && !allowName) lastType = Club; //Guess club for (size_t k=0;k2); lastInsertedType = Name; } } void oFreeImport::test(const oRunnerList &li) { oRunnerList::const_iterator it; //classDB.insert("H21"); //classDB.insert("Herrar"); for(it=li.begin();it!=li.end();++it) { givenDB.insert(it->getGivenName().c_str()); familyDB.insert(it->getFamilyName().c_str()); clubDB.insert(it->getClub().c_str()); classDB.insert(it->getClass().c_str()); } string b("0"), c("a2"), d("a"); const int end='z'+5; for(int k='a';k<=end+1;k++) if (k>end) givenDB.insert(b.c_str()); else { string z=b+char(k); for( int j='a';j<=end+1;j++) { if (j>end) givenDB.insert(z.c_str()); else { givenDB.insert( (z+char(j)+d).c_str() ); } } } givenDB.save("test.mwd"); oWordList wl; wl.load("test.mwd"); wl.save("test2.mwd"); for(it=li.begin();it!=li.end();++it) givenDB.insert(it->getGivenName().c_str()); wl.save("test3.mwd"); //char bf[256]=" Erik Melin , 37837, OK Linné , H21\nJan Troeng, 54323, OK Linné, H21\nLinna Willdén, 810230,IF Thor,D21"; //vector entries; //extractEntries(bf, entries); } /** Must not return 0 */ int oFreeImport::getExpectedNumRunners(const string &cls) const { string key(canonizeName(cls.c_str())); map::const_iterator it = runnersPerClass.find(key); if (it != runnersPerClass.end()) return it->second; else return 1; } void oFreeImport::init(const oRunnerList &r, const oClubList &clb, const oClassList &cls) { runnersPerClass.clear(); vector split_vector; string sep(" "); for(oRunnerList::const_iterator it=r.begin();it!=r.end();++it) { givenDB.insert(it->getGivenName().c_str()); string f=it->getFamilyName(); familyDB.insert(f.c_str()); split(f, sep, split_vector); if (split_vector.size()>1) for(size_t k=0;kgetName().c_str()); split(it->getName().c_str(), sep, split_vector); if (split_vector.size()>1) for(size_t k=0;kgetName().c_str()); split(it->getName().c_str(), sep, split_vector); if (split_vector.size()>1) for(size_t k=0;kgetNumDistinctRunners(); string key(canonizeName(it->getName().c_str())); runnersPerClass[key] = numrunner; } const char *clsPrefix[8] = {"h", "d", "m", "w", "herrar", "damer", "men", "women"}; char bf[64]; vector ages; for (int k=10;k<=16;k++) ages.push_back(k); ages.push_back(18); ages.push_back(20); ages.push_back(21); for (int k=35;k<=100;k+=5) ages.push_back(k); for (int k=0;k<8;k++) { classDB.insert(clsPrefix[k]); for (size_t j=0; j=18 && ages[j]<=21) { sprintf_s(bf, "%s %dE", clsPrefix[k], ages[j]); classDB.insert(bf); sprintf_s(bf, "%s %d Elit", clsPrefix[k], ages[j]); classDB.insert(bf); sprintf_s(bf, "%s%dE", clsPrefix[k], ages[j]); classDB.insert(bf); sprintf_s(bf, "%s%d Elit", clsPrefix[k], ages[j]); classDB.insert(bf); } } } classDB.insert("L"); classDB.insert("Lång"); classDB.insert("E"); classDB.insert("Elit"); classDB.insert("Elite"); classDB.insert("Adult"); classDB.insert("Vuxen"); classDB.insert("Insk"); classDB.insert("Insk."); classDB.insert("Inskolning"); classDB.insert("M"); classDB.insert("ÖM"); classDB.insert("Motion"); classDB.insert("K"); classDB.insert("Kort"); classDB.insert("Mellan"); classDB.insert("Svår"); classDB.insert("Lätt"); classDB.insert("Kortlätt"); classDB.insert("Långsvår"); classDB.insert("km"); classDB.insert("Short"); classDB.insert("Long"); classDB.insert("Öppen"); classDB.insert("Ö"); classDB.insert("Ungdom"); classDB.insert("Ung."); classDB.insert("U"); classDB.insert("U1"); classDB.insert("U2"); classDB.insert("U3"); classDB.insert("U4"); for (int j=1;j<10;j++) { sprintf_s(bf, "Ö%d", j); classDB.insert(bf); sprintf_s(bf, "Ö %d", j); classDB.insert(bf); sprintf_s(bf, "Öppen %d", j); classDB.insert(bf); sprintf_s(bf, "D%d", j); classDB.insert(bf); sprintf_s(bf, "Direkt %d", j); classDB.insert(bf); } } bool oFreeImport::isHeaderWord(const string &word) const { if (headerWords.empty()) { headerWords.insert(canonizeName("namn")); headerWords.insert(canonizeName("klass")); headerWords.insert(canonizeName("ålder")); headerWords.insert(canonizeName("anmälda")); headerWords.insert(canonizeName("anmälningar")); headerWords.insert(canonizeName("deltagare")); headerWords.insert(canonizeName("löpare")); headerWords.insert(canonizeName("bricka")); headerWords.insert(canonizeName("starttid")); headerWords.insert(canonizeName("nummer")); headerWords.insert(canonizeName("startnummer")); headerWords.insert(canonizeName("bricknummer")); headerWords.insert(canonizeName("nummer")); headerWords.insert(canonizeName("klubb")); headerWords.insert(canonizeName("klassnamn")); headerWords.insert(canonizeName("pinne")); headerWords.insert(canonizeName("nummerlapp")); headerWords.insert(canonizeName("SI")); headerWords.insert(canonizeName("förening")); headerWords.insert(canonizeName("rank")); headerWords.insert(canonizeName("ranking")); headerWords.insert(canonizeName("nr-lapp")); headerWords.insert(canonizeName("tid")); headerWords.insert(canonizeName("name")); headerWords.insert(canonizeName("age")); headerWords.insert(canonizeName("class")); headerWords.insert(canonizeName("start")); headerWords.insert(canonizeName("time")); headerWords.insert(canonizeName("club")); headerWords.insert(canonizeName("card")); } return headerWords.count(canonizeName(word.c_str()))>0; } bool match_char(char c, const string &sep) { for (size_t j = 0; j &line) const { if (line.empty()) return true; int header = 0; int nonheader = 0; bool forceNoHeader = false; vector firstWord; const string separators = " :,.="; for (size_t k = 0; k < line.size(); k++) { vector words; split(line[k], separators, words); if (words.empty()) firstWord.push_back(""); else firstWord.push_back(words.front()); for (size_t j = 0; j < words.size(); j++) { if (words[j].empty()) continue; if (isHeaderWord(words[j]) ) header++; else { nonheader++; // If the header contains a real name, class or club, do not reject if (isName(words[j].c_str())) forceNoHeader = true; if (classDB.lookup(words[j].c_str())) forceNoHeader = true; if (clubDB.lookup(words[j].c_str()) || clubDB.lookup(line[k])) forceNoHeader = true; } } } if (!forceNoHeader && header > nonheader) return true; // Remove header words for (size_t k = line.size()-1; k < line.size(); k--) { if (isHeaderWord(line[k])) { line.erase(line.begin()+k); } else if (isHeaderWord(firstWord[k])) { line[k] += firstWord[k].size(); int j = 0; while (line[k][j] && match_char(line[k][j], separators)) j++; line[k] += j; } } return false; } const int CLEARROW = 1; const int IGNOREROW = 2; const int COMPLETEROW = 4; int oFreeImport::preAnalyzeRow(vector &p, const vector &ptrn, vector &classified) { int stat = 0; int names = 0; int clubs = 0; int cards = 0; int classes = 0; int unknown = 0; for (size_t j=0;j1) { if (ptrn[j].isClub()) type=0; else if (ptrn[j].isClass()) type=1; else if (ptrn[j].isCard() && atoi(p[j])>0) type=3; } classified.push_back(type); if (type == 1) classes++; else if (type==3) cards++; else if (type==4) names++; else if (type==0) clubs++; else unknown++; const char *canP = canonizeName(p[j]); if (strcmp(canP, "vakant")==0 || strcmp(canP, "vacant")==0) stat|=IGNOREROW; } if (clubs>0 && names>0 && cards>0) stat|=COMPLETEROW; if (p.size()==1 && (classes>0 || clubs>0)) stat|=CLEARROW; while (cards > names && names>0) { int idx = -1; for (size_t k = 0; k=0 ? atoi(p[idx]) : -1; if (a==-1) idx = k; else { int b = atoi(p[k]); if (b>0 && b=0) { classified[idx] = -2; cards--; unknown++; } } for (int k = p.size()-1; k>=0;k--) { if (classified[k] == -2) { classified.erase(classified.begin()+k); p.erase(p.begin()+k); } } return stat; } void oFreeImport::extractEntries(char *str, vector &entries) { entries.clear(); vector< vector > parts; parts.reserve(strlen(str)/24); set lineTypes; int count=1; while(count>0) { char *line=extractLine(str, count); if (count>0) { parts.push_back( vector() ); while(count>0) { char *out=extractPart(line, count); if (count>0) parts.back().push_back(out); } if ( analyzeHeaders(parts.back()) ) { parts.pop_back(); count = 1; } else { lineTypes.insert(parts.back().size()); count=1; } } } map > patterns; map nNames; //Number of name entries per pattern //Analyze line types for(set::iterator it=lineTypes.begin(); it!=lineTypes.end();++it) { vector mp(*it); int limit=0; for (size_t k=0;k &p=parts[k]; for (int j=0;j<*it; j++) { if (classDB.lookup(p[j])) mp[j].nClass++; if (clubDB.lookup(p[j])) mp[j].nClub++; if (isName(p[j])) { mp[j].nName++; if (countWords(p[j])==1) mp[j].singleName++; } if (isCard(p[j])) mp[j].nCard++; if (isTime(p[j])) mp[j].nTime++; } } } if (limit==1) limit=0; else if (limit<=3) limit=1; else if (limit<=10) limit=2; else limit=limit/5; int nn=0; for (size_t k=0;k=mp.size() || !mp[k+1].isName(limit)) && (k==0 || !mp[k-1].isName(limit)) ) { mp[k].singleName=false; } nNames[*it]=nn; swap(patterns[*it], mp); } entries.reserve(parts.size()); oEntryBlock entry(*this); vector words; rulingClub = ""; rulingClass = ""; lastInsertedType = None; for (size_t k=0;k &p=parts[k]; vector classified; int res = preAnalyzeRow(p, patterns[p.size()], classified); int s = p.size(); vector &ptrn=patterns[s]; if (ptrn.empty()) ptrn.resize(s); assert(ptrn.size() == s); lastInsertedType = None; if (res & CLEARROW) { entry.cleanEntry(); if (entry.hasName()) { entries.push_back(entry); } entry.clear(rulingClub, rulingClass); } else if (res & COMPLETEROW) { entry.cleanEntry(); if (entry.hasName()) { entries.push_back(entry); } entry.clear(rulingClub, rulingClass); } if (res & IGNOREROW) continue; for (int j=0;j1) { if (ptrn[j].isClub()) type = Club; else if (ptrn[j].isClass()) type = Class; else if (ptrn[j].isCard() && atoi(p[j])>0) type = Card; } //We have a suggested name, but there should only //be one name and we already got one. if ((type == Name && entry.hasName() && (2*nNames[s])<=readNames)) type = Unknown; if (type==Name && isCrap(p[j])) type = Unknown; if (type == Unknown) analyzePart(p[j], ptrn[j], nNames[s], entry, entries, (2*nNames[s])>readNames); else if (type == Club) { bool moreClubs = entry.acceptMoreClubs(getExpectedNumRunners(entry.eClass)); if (!moreClubs && lastInsertedType == Club) continue; if (!moreClubs && entry.hasName()) { readNames=0; entry.cleanEntry(); entries.push_back(entry); entry.clear(rulingClub, rulingClass); } else if (j<=1 && s<=2) // Set a ruling club if it first on a line containing at most 2 parts. (We allow club+class) rulingClub = p[j]; lastInsertedType = Club; entry.setClub(p[j]); // If we have an odd number of names read // we were expecting a completing name, // but none came, so we complete what we have instead. if (readNames&1) { readNames++; entry.completeName(); } } else if (type == Class) { if (lastInsertedType == Class) continue; if (entry.hasClass() && entry.hasName()) { readNames=0; entry.cleanEntry(); entries.push_back(entry); entry.clear(rulingClub, rulingClass); } else if (j<=1 && s<=2) // Set a ruling class if it first on a line containing at most 2 parts. (We allow club+class) rulingClass = p[j]; lastInsertedType = Class; entry.setClass(p[j]); if (readNames&1) { readNames++; entry.completeName(); } } else if (type == Time) { if (lastInsertedType == Time) continue; if (!entry.eStartTime.empty()) { if (entry.ePersons.size()>1 && !entry.hasName()) entry.ePersons.pop_back(); //Warning if (entry.hasName()) { readNames=0; entry.cleanEntry(); entries.push_back(entry); entry.clear(rulingClub, rulingClass); } } lastInsertedType = Time; entry.setStartTime(p[j]); if (readNames&1) { readNames++; entry.completeName(); } } else if (type == Card) { if (lastInsertedType == Card && !entry.needCard()) continue; lastInsertedType = Card; entry.setCardNo(atoi(p[j])); if (readNames&1) { readNames++; entry.completeName(); } } else if (type == Name) { lastInsertedType = Name; bool complete = ptrn[j].isCompleteName(); entry.addPerson(p[j], complete); readNames += complete ? 2:1; } }// End loop over parts if (entry.hasName()) { entry.cleanEntry(); entries.push_back(entry); entry.clear(rulingClub, rulingClass); } else if (res & COMPLETEROW) { entry.cleanEntry(); if (entry.hasName()) entries.push_back(entry); // Else lost data entry.clear(rulingClub, rulingClass); } } for (size_t k=1;k=0; k--) { if (entries[k].eClub.empty()) entries[k].eClub=entries[k+1].eClub; if (entries[k].eClass.empty()) entries[k].eClass=entries[k+1].eClass; } } void oFreeImport::showEntries(gdioutput &gdi, const vector &entries) { gdi.setCX(20); for (size_t k=0;k names = entries[k].getPersons(); for (size_t j=0;j &entries) { map teamno; //For automatic name generation Club/Class for (size_t k=0;kgetClass(entries[k].eClass); if (!pc) { pc=oe->addClass(entries[k].eClass); if (entries[k].getNumPersons()>1) pc->setNumStages(entries[k].getNumPersons()); pc->synchronize(); } if (pc) { int nr=pc->getNumDistinctRunners(); if (nr==1) { pRunner r=oe->addRunner(entries[k].getName(0), entries[k].getClub(0), pc->getId(), entries[k].getCard(0), 0, true); r->setStartTimeS(entries[k].eStartTime); r->setCardNo(entries[k].getCard(0), false); r->addClassDefaultFee(false); r->synchronize(); } else { pClub club=oe->getClubCreate(0, entries[k].eClub); string team = entries[k].getTeamName(); //int id=pc->getId() + 10000 * (club ? club->getId() : 0); //char tname[256]; //sprintf_s(tname, "%s %d", entries[k].eClub.c_str(), ++teamno[id]); pTeam t=oe->addTeam(team, club ? club->getId() : 0, pc->getId()); if (t) { t->setStartNo(t->getId(), false); for (int j=0;jaddRunner(entries[k].getName(j), entries[k].getClub(j), pc->getId(), entries[k].getCard(j), 0, false); r->setCardNo(entries[k].getCard(j), false); r->addClassDefaultFee(false); t->setRunner(j, r, true); } t->apply(true, 0, false); } } } } oe->makeUniqueTeamNames(); } void oFreeImport::load() { char bf[260]; bool warn=false; getUserFile(bf, "family.mwd"); try { familyDB.load(bf); } catch(std::exception &) {warn=true;} getUserFile(bf, "given.mwd"); try { givenDB.load(bf); } catch(std::exception &) {warn=true;} getUserFile(bf, "club.mwd"); try { clubDB.load(bf); } catch(std::exception &) {warn=true;} getUserFile(bf, "class.mwd"); try { classDB.load(bf); } catch(std::exception &) {warn=true;} loaded=true; } void oFreeImport::save() const { char bf[260]; string bu; getUserFile(bf, "family.mwd"); bu=string(bf)+".old"; remove(bu.c_str()); rename(bf, bu.c_str()); familyDB.save(bf); getUserFile(bf, "given.mwd"); bu=string(bf)+".old"; remove(bu.c_str()); rename(bf, bu.c_str()); givenDB.save(bf); getUserFile(bf, "club.mwd"); bu=string(bf)+".old"; remove(bu.c_str()); rename(bf, bu.c_str()); clubDB.save(bf); getUserFile(bf, "class.mwd"); bu=string(bf)+".old"; remove(bu.c_str()); rename(bf, bu.c_str()); classDB.save(bf); }