[dasher: 12/28] File searching w/ glob wildcards; RM SP_{USER,SYSTEM}_LOC; drop XML trainfiles
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher: 12/28] File searching w/ glob wildcards; RM SP_{USER,SYSTEM}_LOC; drop XML trainfiles
- Date: Tue, 22 Nov 2011 17:03:40 +0000 (UTC)
commit 8edc8186d07db99a1eedcf7e2a32be02dab667c2
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Wed Sep 14 15:18:16 2011 +0100
File searching w/ glob wildcards; RM SP_{USER,SYSTEM}_LOC; drop XML trainfiles
AbstractParser superclass w/ Scan(istream&, bUser) for all input, not just XML
Single method CDasherInterfaceBase::ScanFiles(AbstractParser*, string&)
feeds all files in system/user location(s) matching pattern to parser.
Common/Globber.h uses glob in <glob.h> for Mac, iPhone, Gtk2; Win32 separate.
Messages.cpp adds FormatMessageWithString for common-case of exactly one %s.
Note, this allows an alphabet to specify a wildcard for its game sentences file
(=>will use last one) and/or training file (=>use all matches, but user text
will be written to a filename containing literal '*'s - TODO sthg better?)
Src/Common/Globber.cpp | 35 ++++++
Src/Common/Globber.h | 17 +++
Src/Common/Makefile.am | 2 +
Src/DasherCore/AbstractXMLParser.cpp | 55 +++++++---
Src/DasherCore/AbstractXMLParser.h | 40 ++++++-
Src/DasherCore/Alphabet/AlphIO.cpp | 19 +---
Src/DasherCore/Alphabet/AlphIO.h | 9 +-
Src/DasherCore/AlphabetManager.cpp | 21 ++--
Src/DasherCore/ColourIO.cpp | 20 +---
Src/DasherCore/ColourIO.h | 13 ++-
Src/DasherCore/ControlManager.cpp | 158 ++++++++++++--------------
Src/DasherCore/ControlManager.h | 24 +++-
Src/DasherCore/DasherInterfaceBase.cpp | 14 +--
Src/DasherCore/DasherInterfaceBase.h | 43 +++-----
Src/DasherCore/FileWordGenerator.cpp | 13 ++-
Src/DasherCore/FileWordGenerator.h | 29 ++---
Src/DasherCore/Makefile.am | 1 +
Src/DasherCore/Messages.cpp | 50 ++++++++
Src/DasherCore/Messages.h | 4 +
Src/DasherCore/NodeCreationManager.cpp | 48 ++++----
Src/DasherCore/Parameters.cpp | 2 -
Src/DasherCore/Parameters.h | 2 +-
Src/DasherCore/Trainer.cpp | 90 +++------------
Src/DasherCore/Trainer.h | 18 +--
Src/Gtk2/DasherControl.cpp | 98 ++++------------
Src/Gtk2/DasherControl.h | 7 +-
Src/MacOSX/COSXDasherControl.h | 8 +-
Src/MacOSX/COSXDasherControl.mm | 70 +++---------
Src/MacOSX/Dasher.xcodeproj/project.pbxproj | 12 ++
Src/Win32/Dasher.cpp | 84 +++++---------
Src/Win32/Dasher.h | 4 +-
Src/iPhone/Classes/CDasherInterfaceBridge.h | 6 +-
Src/iPhone/Classes/CDasherInterfaceBridge.mm | 71 +++++-------
Src/iPhone/Dasher.xcodeproj/project.pbxproj | 10 ++
34 files changed, 524 insertions(+), 573 deletions(-)
---
diff --git a/Src/Common/Globber.cpp b/Src/Common/Globber.cpp
new file mode 100644
index 0000000..9a4153b
--- /dev/null
+++ b/Src/Common/Globber.cpp
@@ -0,0 +1,35 @@
+//
+// Globber.cpp
+// Dasher
+//
+// Created by Alan Lawrence on 21/9/11.
+// Copyright 2011 Cambridge University. All rights reserved.
+//
+
+#include "Globber.h"
+#include <glob.h>
+#include <string.h>
+
+void globScan(AbstractParser *parser, const char **usrPaths, const char **sysPaths) {
+ int flags = GLOB_MARK | GLOB_NOSORT;
+ glob_t info;
+ int numUser = 0;
+ while (*usrPaths) {
+ glob(*usrPaths++, flags, NULL, &info); //NULL error function
+ flags |= GLOB_APPEND;
+ }
+ numUser = info.gl_pathc;
+ while (*sysPaths) {
+ glob(*sysPaths++, flags, NULL, &info);
+ flags |= GLOB_APPEND;
+ }
+
+ if (info.gl_pathc) {
+ //user paths first
+ for (char **fname = info.gl_pathv; *fname; fname++, numUser=(numUser>0 ? numUser-1 : 0)) {
+ if ((*fname)[strlen(*fname)-1]=='/') continue; //directories were marked by GLOB_MARK
+ parser->ParseFile(*fname, numUser>0);
+ }
+ }
+ globfree(&info);
+}
diff --git a/Src/Common/Globber.h b/Src/Common/Globber.h
new file mode 100644
index 0000000..69ee08f
--- /dev/null
+++ b/Src/Common/Globber.h
@@ -0,0 +1,17 @@
+//
+// Globber.h
+// Dasher
+//
+// Created by Alan Lawrence on 21/9/11.
+// Copyright 2011 Cambridge University. All rights reserved.
+//
+
+#ifndef __GLOBBER_H__
+#define __GLOBBER_H__
+
+#include "../DasherCore/AbstractXMLParser.h"
+
+void globScan(AbstractParser *parser,
+ const char **userPaths,
+ const char **systemPaths);
+#endif
diff --git a/Src/Common/Makefile.am b/Src/Common/Makefile.am
index fe1dcff..6ecafdf 100644
--- a/Src/Common/Makefile.am
+++ b/Src/Common/Makefile.am
@@ -3,6 +3,8 @@ libdashermisc_a_SOURCES = \
AppSettingsData.h \
AppSettingsHeader.h \
Common.h \
+ Globber.h \
+ Globber.cpp \
Hash.h \
I18n.h \
MSVC_Unannoy.h \
diff --git a/Src/DasherCore/AbstractXMLParser.cpp b/Src/DasherCore/AbstractXMLParser.cpp
index 14a567d..6d5d8d0 100644
--- a/Src/DasherCore/AbstractXMLParser.cpp
+++ b/Src/DasherCore/AbstractXMLParser.cpp
@@ -9,17 +9,35 @@
#include "AbstractXMLParser.h"
-#include <string.h>
+#include <fstream>
+#include <stdio.h>
+#include <cstring>
-using std::string;
+using namespace std;
-bool AbstractXMLParser::ParseFile(CMessageDisplay *pMsgs, const std::string &strFilename) {
- FILE *Input;
- if((Input = fopen(strFilename.c_str(), "r")) == (FILE *) 0) {
- // could not open file
- return false;
- }
+bool AbstractParser::ParseFile(const string &strPath, bool bUser) {
+ std::ifstream in(strPath.c_str(), ios::binary);
+ bool res=Parse("file://"+strPath, in, bUser);
+ in.close();
+ return res;
+}
+
+AbstractXMLParser::AbstractXMLParser(CMessageDisplay *pMsgs) : AbstractParser(pMsgs) {
+}
+bool AbstractXMLParser::isUser() {
+ return m_bUser;
+}
+
+bool AbstractXMLParser::Parse(const std::string &strDesc, istream &in, bool bUser) {
+ if (!in.good()) return false;
+
+ //we'll be re-entrant (i.e. allow nested calls), as it's not difficult here...
+ const bool bOldUser = m_bUser;
+ const string strOldDesc = m_strDesc;
+ m_bUser = bUser;
+ m_strDesc = strDesc;
+
XML_Parser Parser = XML_ParserCreate(NULL);
// Members passed as callbacks must be static, so don't have a "this" pointer.
@@ -32,17 +50,22 @@ bool AbstractXMLParser::ParseFile(CMessageDisplay *pMsgs, const std::string &str
char Buffer[1024];
int Done;
do {
- size_t len = fread(Buffer, 1, sizeof(Buffer), Input);
+ in.read(Buffer, sizeof(Buffer));
+ size_t len = in.gcount();
Done = len < sizeof(Buffer);
if(XML_Parse(Parser, Buffer, len, Done) == XML_STATUS_ERROR) {
bRes=false;
- if (pMsgs) {
- const char *msg=_("XML Error %s in file %s somewhere in block: %s");
+ if (m_pMsgs) {
const XML_LChar *xmle=XML_ErrorString(XML_GetErrorCode(Parser)); //think XML_LChar==char, depends on preprocessor variables...
- char *buf(new char[strlen(msg)+ strlen(xmle) + strFilename.length() + len + 3]);
- //constructing a string here to get a null terminator. Can we put a null into Buffer instead?
- sprintf(buf, msg, xmle, strFilename.c_str(), string(Buffer,len).c_str());
- pMsgs->Message(buf,true);
+
+ ///TRANSLATORS: the first string is the error message from the XML Parser;
+ /// the second is the URL of the file we're trying to read; the third
+ /// is a section excerpt from the file, containing the error.
+ const char *msg=_("XML Error %s in %s somewhere in block: %s");
+ //we can't use FormatMessage as we have too many substitutions...
+ char *buf(new char[strlen(msg) + strlen(xmle) + m_strDesc.length() + len]);
+ sprintf(buf, xmle, m_strDesc.c_str(), string(Buffer,len).c_str());
+ m_pMsgs->Message(buf, true);
delete buf;
}
break;
@@ -50,7 +73,7 @@ bool AbstractXMLParser::ParseFile(CMessageDisplay *pMsgs, const std::string &str
} while (!Done);
XML_ParserFree(Parser);
- fclose(Input);
+ m_bUser = bOldUser; m_strDesc = strOldDesc;
return bRes;
}
diff --git a/Src/DasherCore/AbstractXMLParser.h b/Src/DasherCore/AbstractXMLParser.h
index a02d0b4..70ced74 100644
--- a/Src/DasherCore/AbstractXMLParser.h
+++ b/Src/DasherCore/AbstractXMLParser.h
@@ -19,18 +19,46 @@
#include <string>
#include <expat.h>
+#include <iostream>
+
+class AbstractParser {
+public:
+ AbstractParser(CMessageDisplay *pMsgs) : m_pMsgs(pMsgs) { }
+ ///Utility method: constructs an ifstream to read from the specified file,
+ /// then calls Parse(string&,istream&,bool) with the description 'file://strPath'
+ virtual bool ParseFile(const std::string &strPath, bool bUser);
+
+ /// \param strDesc string to display to user to identify the source of this data,
+ /// if there is an error. (Suggest: use a url, e.g. file://...)
+ /// \param bUser if True, the file is from a user location (editable), false if from a
+ /// system one. (Some subclasses treat the data differently according to which of these
+ /// it is from.)
+ virtual bool Parse(const std::string &strDesc, std::istream &in, bool bUser) = 0;
+
+protected:
+ ///The MessageDisplay to use to inform the user. Subclasses should use this
+ /// too for any (e.g. semantic) errors they may detect.
+ CMessageDisplay * const m_pMsgs;
+};
///Basic wrapper over (Expat) XML Parser, handling file IO and wrapping C++
/// virtual methods over C callbacks. Subclasses must implement methods to
/// handle actual tags.
-class AbstractXMLParser {
+class AbstractXMLParser : public AbstractParser {
public:
///Parse (the whole) file - done in chunks to avoid loading the whole thing into memory.
- /// \param pInterface if non-null, any errors _besides_ file-not-found, will be passed
- /// to the Message(,true) method to report to the user.
- /// \return true if the file was opened+parsed OK; false if there was an error (e.g. FNF)
- bool ParseFile(CMessageDisplay *pMsgs, const std::string &strFilename);
+ /// Any errors _besides_ file-not-found, will be passed to m_pMsgs as modal messages.
+ virtual bool Parse(const std::string &strDesc, std::istream &in, bool bUser);
protected:
+ ///Create an AbstractXMLParser which will use the specified MessageDisplay to
+ /// inform the user of any errors.
+ AbstractXMLParser(CMessageDisplay *pMsgs);
+
+ ///Subclasses may call to get the description of the current file
+ const std::string &GetDesc();
+ ///Subclasses may call to determine if the current file is from a user location
+ bool isUser();
+
///Subclass should override to handle a start tag
virtual void XmlStartHandler(const XML_Char *name, const XML_Char **atts)=0;
///Subclass should override to handle an end tag
@@ -51,6 +79,8 @@ private:
static void XML_StartElement(void *userData, const XML_Char * name, const XML_Char ** atts);
static void XML_EndElement(void *userData, const XML_Char * name);
static void XML_CharacterData(void *userData, const XML_Char * s, int len);
+ bool m_bUser;
+ std::string m_strDesc;
};
#endif
diff --git a/Src/DasherCore/Alphabet/AlphIO.cpp b/Src/DasherCore/Alphabet/AlphIO.cpp
index e92abf0..8a506f6 100644
--- a/Src/DasherCore/Alphabet/AlphIO.cpp
+++ b/Src/DasherCore/Alphabet/AlphIO.cpp
@@ -36,8 +36,7 @@ static char THIS_FILE[] = __FILE__;
#endif
#endif
-CAlphIO::CAlphIO(CMessageDisplay *pMsgs, const std::string &SystemLocation, const std::string &UserLocation, const std::vector<std::string> &Filenames)
-: LoadMutable(false), CData("") {
+CAlphIO::CAlphIO(CMessageDisplay *pMsgs) : AbstractXMLParser(pMsgs) {
Alphabets["Default"]=CreateDefault();
typedef pair < Opts::AlphabetTypes, std::string > AT;
@@ -62,20 +61,6 @@ CAlphIO::CAlphIO(CMessageDisplay *pMsgs, const std::string &SystemLocation, cons
TtoS[Types[i].first] = Types[i].second;
}
- LoadMutable = false;
- ParseFile(pMsgs, SystemLocation + "alphabet.xml");
- if(Filenames.size() > 0) {
- for(unsigned int i = 0; i < Filenames.size(); i++) {
- ParseFile(pMsgs, SystemLocation + Filenames[i]);
- }
- }
- LoadMutable = true;
- ParseFile(pMsgs, UserLocation + "alphabet.xml");
- if(Filenames.size() > 0) {
- for(unsigned int i = 0; i < Filenames.size(); i++) {
- ParseFile(pMsgs, UserLocation + Filenames[i]);
- }
- }
}
void CAlphIO::GetAlphabets(std::vector <std::string >*AlphabetList) const {
@@ -182,7 +167,7 @@ void CAlphIO::XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
if(strcmp(name, "alphabet") == 0) {
InputInfo = new CAlphInfo();
- InputInfo->Mutable = LoadMutable;
+ InputInfo->Mutable = isUser();
ParagraphCharacter = NULL;
SpaceCharacter = NULL;
iGroupIdx = 0;
diff --git a/Src/DasherCore/Alphabet/AlphIO.h b/Src/DasherCore/Alphabet/AlphIO.h
index ce9f32d..529df9f 100644
--- a/Src/DasherCore/Alphabet/AlphIO.h
+++ b/Src/DasherCore/Alphabet/AlphIO.h
@@ -47,10 +47,14 @@ namespace Dasher {
/// object per alphabet at this time, and stores them in a map from AlphID
/// string until shutdown/destruction. (CAlphIO is a friend of CAlphInfo,
/// so can create/manipulate instances.)
-class Dasher::CAlphIO : private AbstractXMLParser {
+class Dasher::CAlphIO : public AbstractXMLParser {
public:
- CAlphIO(CMessageDisplay *pMsgs, const std::string &SystemLocation, const std::string &UserLocation, const std::vector < std::string > &Filenames);
+ ///Create a new AlphIO. Initially, it will have only a 'default' alphabet
+ /// definition (English); further alphabets may be loaded in by calling the
+ /// Parse... methods inherited from Abstract[XML]Parser
+ CAlphIO(CMessageDisplay *pMsgs);
+
~CAlphIO();
void GetAlphabets(std::vector < std::string > *AlphabetList) const;
std::string GetDefault();
@@ -67,7 +71,6 @@ private:
// XML handling:
/////////////////////////
- bool LoadMutable;
void ReadCharAtts(const XML_Char **atts, CAlphInfo::character &ch);
// Alphabet types:
std::map < std::string, Opts::AlphabetTypes > StoT;
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 9f8d5e4..c52c7f6 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -152,24 +152,25 @@ CAlphabetManager::SGroupInfo *CAlphabetManager::copyGroups(CDasherScreen *pScree
}
CWordGeneratorBase *CAlphabetManager::GetGameWords() {
- CFileWordGenerator *pGen = new CFileWordGenerator(m_pAlphabet, m_pAlphabetMap);
+ CFileWordGenerator *pGen = new CFileWordGenerator(m_pInterface, m_pAlphabet, m_pAlphabetMap);
+ pGen->setAcceptUser(true);
if (!GetStringParameter(SP_GAME_TEXT_FILE).empty()) {
const string >f(GetStringParameter(SP_GAME_TEXT_FILE));
- if (pGen->open(gtf)) return pGen;
+ if (pGen->ParseFile(gtf,true)) return pGen;
///TRANSLATORS: the string "GameTextFile" is the name of a setting in gsettings
/// (or equivalent), and should not be translated. The %s is the value of that
/// setting (this message displayed only if the user has provided a value)
- const char *msg=_("Note: GameTextFile setting specifies game sentences file '%s' but this does not exist");
- char *buf(new char[strlen(msg)+gtf.length()]);
- sprintf(buf,msg,gtf.c_str());
- m_pInterface->Message(buf,false);
- delete buf;
+ m_pInterface->FormatMessageWithString(_("Note: GameTextFile setting specifies game sentences file '%s' but this does not exist"),gtf.c_str());
}
if (!m_pAlphabet->GetGameModeFile().empty()) {
- if (pGen->open(GetStringParameter(SP_USER_LOC) + m_pAlphabet->GetGameModeFile())) return pGen;
- if (pGen->open(GetStringParameter(SP_SYSTEM_LOC) + m_pAlphabet->GetGameModeFile())) return pGen;
+ //TODO, try user dir first / give one or other priority?
+ // This will concatenate all - which doesn't seem too bad...?
+ m_pInterface->ScanFiles(pGen, m_pAlphabet->GetGameModeFile());
+ if (pGen->HasLines()) return pGen;
}
- if (pGen->open(GetStringParameter(SP_SYSTEM_LOC) + m_pAlphabet->GetTrainingFile())) return pGen;
+ pGen->setAcceptUser(false);
+ m_pInterface->ScanFiles(pGen, m_pAlphabet->GetTrainingFile());
+ if (pGen->HasLines()) return pGen;
delete pGen;
return NULL;
}
diff --git a/Src/DasherCore/ColourIO.cpp b/Src/DasherCore/ColourIO.cpp
index 5df2232..b7d7b04 100644
--- a/Src/DasherCore/ColourIO.cpp
+++ b/Src/DasherCore/ColourIO.cpp
@@ -23,24 +23,8 @@ static char THIS_FILE[] = __FILE__;
// TODO: Share information with AlphIO class?
-CColourIO::CColourIO(CMessageDisplay *pMsgs, const string &SystemLocation, const string &UserLocation, const vector<string> &Filenames)
-:BlankInfo(), LoadMutable(false), CData("") {
+CColourIO::CColourIO(CMessageDisplay *pMsgs) : AbstractXMLParser(pMsgs), BlankInfo() {
CreateDefault();
-
- LoadMutable = false;
- ParseFile(pMsgs, SystemLocation + "colour.xml");
- if(Filenames.size() > 0) {
- for(unsigned int i = 0; i < Filenames.size(); i++) {
- ParseFile(pMsgs, SystemLocation + Filenames[i]);
- }
- }
- LoadMutable = true;
- ParseFile(pMsgs, UserLocation + "colour.xml");
- if(Filenames.size() > 0) {
- for(unsigned int i = 0; i < Filenames.size(); i++) {
- ParseFile(pMsgs, UserLocation + Filenames[i]);
- }
- }
}
void CColourIO::GetColours(std::vector <std::string >*ColourList) const {
@@ -816,7 +800,7 @@ void CColourIO::XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
if(strcmp(name, "palette") == 0) {
ColourInfo NewInfo;
InputInfo = NewInfo;
- InputInfo.Mutable = LoadMutable;
+ InputInfo.Mutable = isUser();
while(*atts != 0) {
if(strcmp(*atts, "name") == 0) {
InputInfo.ColourID = *(atts+1);
diff --git a/Src/DasherCore/ColourIO.h b/Src/DasherCore/ColourIO.h
index e707a4d..1f115ad 100644
--- a/Src/DasherCore/ColourIO.h
+++ b/Src/DasherCore/ColourIO.h
@@ -24,7 +24,9 @@ namespace Dasher {
/// \defgroup Colours Colour scheme information
/// @{
-class Dasher::CColourIO : private AbstractXMLParser {
+/// Class for reading in colour-scheme definitions, and storing all read schemes
+/// in a list.
+class Dasher::CColourIO : public AbstractXMLParser {
public:
// This structure completely describes the characters used in alphabet
struct ColourInfo {
@@ -38,8 +40,11 @@ public:
std::vector < int >Greens;
std::vector < int >Blues;
};
-
- CColourIO(CMessageDisplay *pMsgs, const std::string &SystemLocation, const std::string &UserLocation, const std::vector < std::string > &Filenames);
+
+ ///Construct a new ColourIO. It will have only a 'default' colour scheme;
+ /// further schemes may be loaded in by calling the Parse... methods inherited
+ /// from Abstract[XML]Parser.
+ CColourIO(CMessageDisplay *pMsgs);
void GetColours(std::vector < std::string > *ColourList) const;
const ColourInfo & GetInfo(const std::string & ColourID);
private:
@@ -51,8 +56,6 @@ private:
// XML handling:
/////////////////////////
- bool LoadMutable;
-
// Data gathered
std::string CData; // Text gathered from when an elemnt starts to when it ends
ColourInfo InputInfo;
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 458a905..f75aabd 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -128,6 +128,8 @@ const vector<CControlBase::NodeTemplate *> &CControlParser::parsedNodes() {
return m_vParsed;
}
+///Template used for all node defns read in from XML - just
+/// execute a list of Actions.
class XMLNodeTemplate : public CControlBase::NodeTemplate {
public:
XMLNodeTemplate(const string &label, int color) : NodeTemplate(label, color) {
@@ -146,92 +148,87 @@ public:
vector<CControlBase::Action*> actions;
};
-bool CControlParser::LoadFile(CMessageDisplay *pMsgs, const string &strFileName) {
- ///Template used for all node defns read in from XML - just
- /// execute a list of Actions.
-
- class ParseHandler : public AbstractXMLParser {
- typedef CControlBase::NodeTemplate NodeTemplate;
- protected:
- void XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
- vector<NodeTemplate *> &parent(nodeStack.empty() ? m_pMgr->m_vParsed : nodeStack.back()->successors);
- if (strcmp(name,"node")==0) {
- string label,nodeName; int color=-1;
- while (*atts) {
- if (strcmp(*atts,"name")==0) {
- nodeName=*(atts+1);
- DASHER_ASSERT(namedNodes.find(nodeName)==namedNodes.end());
- } else if (strcmp(*atts,"label")==0) {
- label = *(atts+1);
- } else if (strcmp(*atts,"color")==0) {
- color = atoi(*(atts+1));
- }
- atts+=2;
- }
- XMLNodeTemplate *n = new XMLNodeTemplate(label,color);
- parent.push_back(n);
- nodeStack.push_back(n);
- if (nodeName!="")
- namedNodes[nodeName]=n; //all refs resolved at end.
- } else if (strcmp(name,"ref")==0) {
- string target;
- while (*atts) {
- if (strcmp(*atts,"name")==0)
- target=*(atts+1);
- atts+=2;
- }
- map<string,NodeTemplate*>::iterator it=namedNodes.find(target);
- if (it!=namedNodes.end())
- parent.push_back(it->second);
- else {
- parent.push_back(NULL);
- unresolvedRefs.push_back(pair<NodeTemplate**,string>(&(parent.back()),target));
- }
- } else if (strcmp(name,"alph")==0) {
- parent.push_back(NULL);
- } else if (NodeTemplate *n = m_pMgr->parseOther(name, atts)) {
- parent.push_back(n);
- } else if (CControlBase::Action *a=m_pMgr->parseAction(name, atts)) {
- DASHER_ASSERT(!nodeStack.empty());
- nodeStack.back()->actions.push_back(a);
- }
- }
+CControlParser::CControlParser(CMessageDisplay *pMsgs) : AbstractXMLParser(pMsgs) {
+}
+
+bool CControlParser::ParseFile(const string &strFileName, bool bUser) {
+ if (m_bUser) {
+ //have user files
+ if (!bUser) return true; //so ignore system!
+ } else {
+ //have system files (or none)
+ if (bUser) m_vParsed.clear(); //replace system with user
+ m_bUser = true;
+ }
+
+ namedNodes.clear();
+ unresolvedRefs.clear();
+ nodeStack.clear();
+
+ if (!AbstractXMLParser::ParseFile(strFileName, bUser)) return false;
+ //resolve any forward references to nodes declared later
+ for (vector<pair<CControlBase::NodeTemplate**,string> >::iterator it=unresolvedRefs.begin(); it!=unresolvedRefs.end(); it++) {
+ map<string,CControlBase::NodeTemplate*>::iterator target = namedNodes.find(it->second);
+ if (target != namedNodes.end())
+ *(it->first) = target->second;
+ }
+ //somehow, need to clear out any refs that weren't resolved...???
+ return true;
+}
- void XmlEndHandler(const XML_Char *szName) {
- if (strcmp(szName,"node")==0) {
- DASHER_ASSERT(!nodeStack.empty());
- nodeStack.pop_back();
+void CControlParser::XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
+ vector<CControlBase::NodeTemplate *> &parent(nodeStack.empty() ? m_vParsed : nodeStack.back()->successors);
+ if (strcmp(name,"node")==0) {
+ string label,nodeName; int color=-1;
+ while (*atts) {
+ if (strcmp(*atts,"name")==0) {
+ nodeName=*(atts+1);
+ DASHER_ASSERT(namedNodes.find(nodeName)==namedNodes.end());
+ } else if (strcmp(*atts,"label")==0) {
+ label = *(atts+1);
+ } else if (strcmp(*atts,"color")==0) {
+ color = atoi(*(atts+1));
}
+ atts+=2;
}
-
- private:
- ///Following only used in parsing...
- map<string,NodeTemplate*> namedNodes;
- vector<pair<NodeTemplate**,string> > unresolvedRefs;
- vector<XMLNodeTemplate*> nodeStack;
- CControlParser *m_pMgr;
- public:
- ParseHandler(CControlParser *pMgr) : m_pMgr(pMgr) {
+ XMLNodeTemplate *n = new XMLNodeTemplate(label,color);
+ parent.push_back(n);
+ nodeStack.push_back(n);
+ if (nodeName!="")
+ namedNodes[nodeName]=n; //all refs resolved at end.
+ } else if (strcmp(name,"ref")==0) {
+ string target;
+ while (*atts) {
+ if (strcmp(*atts,"name")==0)
+ target=*(atts+1);
+ atts+=2;
}
- void resolveRefs() {
- //resolve any forward references to nodes declared later
- for (vector<pair<NodeTemplate**,string> >::iterator it=unresolvedRefs.begin(); it!=unresolvedRefs.end(); it++) {
- map<string,NodeTemplate*>::iterator target = namedNodes.find(it->second);
- if (target != namedNodes.end())
- *(it->first) = target->second;
- }
- //somehow, need to clear out any refs that weren't resolved...???
+ map<string,CControlBase::NodeTemplate*>::iterator it=namedNodes.find(target);
+ if (it!=namedNodes.end())
+ parent.push_back(it->second);
+ else {
+ parent.push_back(NULL);
+ unresolvedRefs.push_back(pair<CControlBase::NodeTemplate**,string>(&(parent.back()),target));
}
- };
+ } else if (strcmp(name,"alph")==0) {
+ parent.push_back(NULL);
+ } else if (CControlBase::NodeTemplate *n = parseOther(name, atts)) {
+ parent.push_back(n);
+ } else if (CControlBase::Action *a=parseAction(name, atts)) {
+ DASHER_ASSERT(!nodeStack.empty());
+ static_cast<XMLNodeTemplate*>(nodeStack.back())->actions.push_back(a);
+ }
+}
- ParseHandler p(this);
- if (!p.ParseFile(pMsgs, strFileName)) return false;
- p.resolveRefs();
- return true;
+void CControlParser::XmlEndHandler(const XML_Char *szName) {
+ if (strcmp(szName,"node")==0) {
+ DASHER_ASSERT(!nodeStack.empty());
+ nodeStack.pop_back();
+ }
}
CControlManager::CControlManager(CSettingsUser *pCreateFrom, CNodeCreationManager *pNCManager, CDasherInterfaceBase *pInterface)
-: CControlBase(pCreateFrom, pInterface, pNCManager), CSettingsObserver(pCreateFrom), m_pSpeech(NULL), m_pCopy(NULL) {
+: CControlParser(pInterface), CControlBase(pCreateFrom, pInterface, pNCManager), CSettingsObserver(pCreateFrom), m_pSpeech(NULL), m_pCopy(NULL) {
//TODO, used to be able to change label+colour of root/pause/stop from controllabels.xml
// (or, get the root node title "control" from the alphabet!)
SetRootTemplate(new NodeTemplate("Control",8)); //default NodeTemplate does nothing
@@ -244,12 +241,7 @@ CControlManager::CControlManager(CSettingsUser *pCreateFrom, CNodeCreationManage
m_pStop->successors.push_back(NULL);
m_pStop->successors.push_back(GetRootTemplate());
- //TODO, have a parameter to try first, and if that fails:
- if(!LoadFile(m_pInterface, GetStringParameter(SP_USER_LOC) + "control.xml")) {
- LoadFile(m_pInterface, GetStringParameter(SP_SYSTEM_LOC)+"control.xml");
- //if that fails, we'll have no editing functions. Fine -
- // doesn't seem vital enough to hardcode a fallback as well!
- }
+ m_pInterface->ScanFiles(this, "control.xml"); //just look for the one
updateActions();
}
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index a07b58f..4968d9a 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -146,15 +146,20 @@ namespace Dasher {
/// <alph/> tag, meaning one child of the node is to escape back to the alphabet. Subclasses
/// may override parseAction to provide actions for the nodes to perform, also parseOther
/// to link with NodeTemplates from other sources.
- class CControlParser {
+ class CControlParser : public AbstractXMLParser {
+ public:
+ CControlParser(CMessageDisplay *pMsgs);
protected:
- ///Loads all node definitions from the specified filename, adding them to
- /// any loaded from previous calls. (However, files processed independently:
+ ///Loads all node definitions from the specified filename. Note that
+ /// system files will not be loaded if user files are (and user files will
+ /// clear out any nodes from system ones). However, multiple system or multiple
+ /// user files, will be concatenated. (However, files are processed separately:
/// e.g. names defined in one file will not be seen from another)
- /// \param pMsgs Used to report errors via Message(,true) (i.e. modal)
/// \param strFilename name+full-path of xml file to load
+ /// \param bUser true if from user-specific location (takes priority over system)
/// \return true if the file was opened successfully; false if not.
- bool LoadFile(CMessageDisplay *pMsgs, const std::string &strFilename);
+ bool ParseFile(const std::string &strFilename, bool bUser);
+
/// \return all node definitions that have been loaded by this CControlParser.
const vector<CControlBase::NodeTemplate*> &parsedNodes();
///Subclasses may override to parse other nodes (besides "node", "ref" and "alph").
@@ -170,9 +175,18 @@ namespace Dasher {
return NULL;
};
//TODO cleanup/deletion
+ void XmlStartHandler(const XML_Char *name, const XML_Char **atts);
+ void XmlEndHandler(const XML_Char *szName);
private:
///all top-level parsed nodes
vector<CControlBase::NodeTemplate *> m_vParsed;
+ ///whether parsed nodes were from user file or not
+ bool m_bUser;
+
+ ///Following only used as temporary variables during parsing...
+ map<string,CControlBase::NodeTemplate*> namedNodes;
+ vector<pair<CControlBase::NodeTemplate**,string> > unresolvedRefs;
+ vector<CControlBase::NodeTemplate*> nodeStack;
};
///subclass which we actually construct! Parses editing node definitions from a file,
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index e665b63..529fa85 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -123,16 +123,12 @@ void CDasherInterfaceBase::Realize(unsigned long ulTime) {
DASHER_ASSERT(m_DasherScreen ? m_pDasherView!=NULL : m_pDasherView==NULL);
srand(ulTime);
-
- SetupPaths();
-
- std::vector<std::string> vAlphabetFiles;
- ScanAlphabetFiles(vAlphabetFiles);
- m_AlphIO = new CAlphIO(this, GetStringParameter(SP_SYSTEM_LOC), GetStringParameter(SP_USER_LOC), vAlphabetFiles);
+
+ m_AlphIO = new CAlphIO(this);
+ ScanFiles(m_AlphIO, "alphabet*.xml");
- std::vector<std::string> vColourFiles;
- ScanColourFiles(vColourFiles);
- m_ColourIO = new CColourIO(this, GetStringParameter(SP_SYSTEM_LOC), GetStringParameter(SP_USER_LOC), vColourFiles);
+ m_ColourIO = new CColourIO(this);
+ ScanFiles(m_ColourIO, "colour*.xml");
ChangeColours();
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 815b63f..50d56ef 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -359,6 +359,21 @@ public:
///
virtual int GetFileSize(const std::string &strFileName) = 0;
+
+ /// @name Platform dependent utility functions
+ /// These functions provide various platform dependent functions
+ /// required by the core. A derived class is created for each
+ /// supported platform which implements these.
+ // @{
+
+ ///Look for files, matching a filename pattern, in whatever system and/or user
+ /// locations as may exist - e.g. on disk, in app package, on web, whatever.
+ /// TODO, can we add a default implementation that looks on the Dasher website?
+ /// \param pattern string matching just filename (not path), potentially
+ /// including '*'s (as per glob)
+ virtual void ScanFiles(AbstractParser *parser, const std::string &strPattern) = 0;
+
+ // @}
protected:
/// @name Startup
@@ -426,34 +441,6 @@ protected:
//The default expansion policy to use - an amortized policy depending on the LP_NODE_BUDGET parameter.
CExpansionPolicy *m_defaultPolicy;
- /// @name Platform dependent utility functions
- /// These functions provide various platform dependent functions
- /// required by the core. A derived class is created for each
- /// supported platform which implements these.
- // @{
-
- ///
- /// Initialise the SP_SYSTEM_LOC and SP_USER_LOC paths - the exact
- /// method of doing this will be OS dependent
- ///
-
- virtual void SetupPaths() = 0;
-
- ///
- /// Produce a list of filenames for alphabet files
- ///
-
- virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList) = 0;
-
- ///
- /// Produce a list of filenames for colour files
- ///
-
- virtual void ScanColourFiles(std::vector<std::string> &vFileList) = 0;
-
- /// @}
-
-
/// Provide a new CDasherInput input device object.
void CreateInput();
diff --git a/Src/DasherCore/FileWordGenerator.cpp b/Src/DasherCore/FileWordGenerator.cpp
index 5c6c290..2d66831 100644
--- a/Src/DasherCore/FileWordGenerator.cpp
+++ b/Src/DasherCore/FileWordGenerator.cpp
@@ -2,11 +2,18 @@
using namespace Dasher;
-CFileWordGenerator::CFileWordGenerator(const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
- : CWordGeneratorBase(pAlph,pAlphMap) {
+CFileWordGenerator::CFileWordGenerator(CMessageDisplay *pMsgs, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
+ : CWordGeneratorBase(pAlph,pAlphMap), AbstractParser(pMsgs) {
}
-bool CFileWordGenerator::open(const std::string &sPath) {
+bool CFileWordGenerator::Parse(const std::string &strDesc, istream &in, bool bUser) {
+ //non-file streams not supported (yet)
+ DASHER_ASSERT(false);
+ return false;
+}
+
+bool CFileWordGenerator::ParseFile(const std::string &sPath, bool bUser) {
+ if (bUser && !m_bAcceptUser) return false;
m_sFileHandle.close();
m_vLineIndices.clear();
m_sPath=sPath;
diff --git a/Src/DasherCore/FileWordGenerator.h b/Src/DasherCore/FileWordGenerator.h
index aaa49d5..b54d864 100644
--- a/Src/DasherCore/FileWordGenerator.h
+++ b/Src/DasherCore/FileWordGenerator.h
@@ -26,12 +26,16 @@ namespace Dasher {
* the behavior is undefined as you may cause the file to be read in all
* at once.
*/
-class CFileWordGenerator : public CWordGeneratorBase {
+class CFileWordGenerator : public CWordGeneratorBase, public AbstractParser {
public:
- CFileWordGenerator(const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
+ CFileWordGenerator(CMessageDisplay *pMsgs, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
+ ///Attempt to read from an arbitrary stream. Returns false, as we
+ /// only support reading game mode sentences from files.
+ bool Parse(const std::string &strDesc, std::istream &in, bool bUser);
+
///Attempt to open the specified file. Return true for success, false for failure
- bool open(const std::string &sPath);
+ bool ParseFile(const std::string &strFileName, bool bUser);
virtual ~CFileWordGenerator() {
m_sFileHandle.close();
@@ -42,22 +46,11 @@ public:
* @throw Throws an exception if the file cannot be read.
*/
virtual std::string GetLine();
-
-
- /**
- * File path getter
- * @return The path to the file this generator reads from.
- */
- std::string GetPath();
-
- /**
- * File name getter. Returns the file name and extension, without
- * any slashes.
- * @return The actual name of the file being read from
- */
- std::string GetFilename();
+ void setAcceptUser(bool bAcceptUser) {m_bAcceptUser = bAcceptUser;}
+ bool HasLines() {return !m_vLineIndices.empty();}
+
private:
/* ---------------------------------------------------------------------
@@ -76,6 +69,8 @@ private:
ifstream m_sFileHandle;
std::vector<streampos> m_vLineIndices;
+
+ bool m_bAcceptUser;
};
}
diff --git a/Src/DasherCore/Makefile.am b/Src/DasherCore/Makefile.am
index c4aff81..309393d 100644
--- a/Src/DasherCore/Makefile.am
+++ b/Src/DasherCore/Makefile.am
@@ -90,6 +90,7 @@ libdashercore_a_SOURCES = \
MemoryLeak.cpp \
MemoryLeak.h \
Messages.h \
+ Messages.cpp \
ModuleManager.cpp \
ModuleManager.h \
NodeCreationManager.cpp \
diff --git a/Src/DasherCore/Messages.cpp b/Src/DasherCore/Messages.cpp
new file mode 100644
index 0000000..c5e2e5c
--- /dev/null
+++ b/Src/DasherCore/Messages.cpp
@@ -0,0 +1,50 @@
+#include "Messages.h"
+#include <string.h>
+#include <vector>
+#include <stdarg.h>
+#include <stdio.h>
+
+using std::vector;
+
+void CMessageDisplay::FormatMessageWithString(const char *fmt, const char *str) {
+ char *buf(new char[strlen(fmt)+strlen(str)]);
+ sprintf(buf, fmt, str);
+ Message(buf, true);
+ delete buf;
+}
+
+ //The following implements a varargs version of the above,
+ // dynamically allocating enough storage for the formatted string
+ // using snprintf. However, this doesn't work on Solaris,
+ // hence commenting out.
+
+ //Note: vector is guaranteed to store elements contiguously.
+ // C++98 did not guarantee this, but this was corrected in a 2003
+ // technical corrigendum. As Bjarne Stroustrup says,
+ // "this was always the intent and all implementations always did it that way"
+ /*vector<char> buf;
+ for (int len = strlen(fmt)+1024; ;) {
+ buf.resize(len);
+ va_list args;
+ va_start(args,fmt);
+ int res = vsnprintf(&buf[0], len, fmt, args);
+ va_end(args);
+ if (res>=0 && res<len) {
+ //ok, buf big enough, now contains string
+ Message(&buf[0], true);
+ return;
+ }
+ if (res<0) {
+ //on windows, returns -1 for "buffer not big enough" => double size & retry.
+ // However, on linux, -1 indicates "some other error".
+ // So make sure we don't infinite loop but instead break out somehow...
+ if (len*=2 > 1<<16) {
+ printf("Could not allocate big enough buffer, or other error, when trying to print:\n");
+ va_list args2;
+ va_start(args2,fmt);
+ vprintf(fmt,args2);
+ va_end(args2);
+ return; //exit loop + function, no call to Message()
+ }
+ } else len = res+1; //that identifies necessary size of buffer
+ }*/
diff --git a/Src/DasherCore/Messages.h b/Src/DasherCore/Messages.h
index 035fd9a..892a2aa 100644
--- a/Src/DasherCore/Messages.h
+++ b/Src/DasherCore/Messages.h
@@ -43,6 +43,10 @@ public:
/// \param bInterrupt if true, text entry should be interrupted; if false, user should
/// be able to continue writing uninterrupted.
virtual void Message(const std::string &strText, bool bInterrupt)=0;
+
+ ///Utility method for common case of displaying a modal message with a format
+ /// string containing a single %s.
+ void FormatMessageWithString(const char* fmt, const char* str);
};
/// @}
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index ddf72aa..51258b2 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -10,24 +10,33 @@
using namespace Dasher;
-class ProgressNotifier : public CTrainer::ProgressIndicator {
+//Wraps the ParseFile of a provided Trainer, to setup progress notification
+// - and then passes self, as a ProgressIndicator, to the Trainer's ParseFile method.
+class ProgressNotifier : public AbstractParser, private CTrainer::ProgressIndicator {
public:
ProgressNotifier(CDasherInterfaceBase *pInterface, CTrainer *pTrainer)
- : m_pInterface(pInterface), m_pTrainer(pTrainer) { }
+ : AbstractParser(pInterface), m_bSystem(false), m_bUser(false), m_pInterface(pInterface), m_pTrainer(pTrainer) { }
void bytesRead(off_t n) {
int iNewPercent = ((m_iStart + n)*100)/m_iStop;
if (iNewPercent != m_iPercent) {
m_pInterface->SetLockStatus(m_strDisplay, m_iPercent = iNewPercent);
}
}
- bool run(const string &strDisplay, string strFile) {
- m_pInterface->SetLockStatus(m_strDisplay=strDisplay, m_iPercent=0);
+ bool ParseFile(const string &strFilename, bool bUser) {
m_iStart = 0;
- m_iStop = m_pInterface->GetFileSize(strFile);
+ m_iStop = m_pInterface->GetFileSize(strFilename);
if (m_iStop==0) return false;
- m_pTrainer->LoadFile(strFile,this); //Hmmm. Error-reporting is only via Message()...?
+ return AbstractParser::ParseFile(strFilename, bUser);
+ }
+ bool Parse(const string &strUrl, istream &in, bool bUser) {
+ m_strDisplay = bUser ? _("Training on User Text") : _("Training on System Text");
+ m_pInterface->SetLockStatus(m_strDisplay, m_iPercent=0);
+ m_pTrainer->SetProgressIndicator(this);
+ if (!m_pTrainer->Parse(strUrl, in, bUser)) return false;
+ if (bUser) m_bUser=true; else m_bSystem=true;
return true;
}
+ bool m_bSystem, m_bUser;
private:
CDasherInterfaceBase *m_pInterface;
CTrainer *m_pTrainer;
@@ -77,30 +86,18 @@ CNodeCreationManager::CNodeCreationManager(CSettingsUser *pCreateFrom,
if (!pAlphInfo->GetTrainingFile().empty()) {
ProgressNotifier pn(pInterface, m_pTrainer);
- //1. Look for system training text...
- bool bFound=pn.run(_("Training on System Text"), GetStringParameter(SP_SYSTEM_LOC) + pAlphInfo->GetTrainingFile());
- //2. Now add in any user-provided individual training text...
- if (!pn.run(_("Training on User Text"), GetStringParameter(SP_USER_LOC) + pAlphInfo->GetTrainingFile())) {
+ pInterface->ScanFiles(&pn,pAlphInfo->GetTrainingFile());
+ if (!pn.m_bUser) {
///TRANSLATORS: These 3 messages will be displayed when the user has just chosen a new alphabet. The %s parameter will be the name of the alphabet.
- const char *msg = bFound ? _("No user training text found - if you have written in \"%s\" before, this means Dasher may not be learning from previous sessions")
+ const char *msg = pn.m_bSystem ? _("No user training text found - if you have written in \"%s\" before, this means Dasher may not be learning from previous sessions")
: _("No training text (user or system) found for \"%s\". Dasher will still work but entry will be slower. We suggest downloading a training text file from the Dasher website, or constructing your own.");
- char *buf(new char[strlen(msg)+pAlphInfo->GetID().length()]);
- sprintf(buf,msg,pAlphInfo->GetID().c_str());
- pInterface->Message(buf, true);
- delete buf;
+ pInterface->FormatMessageWithString(msg, pAlphInfo->GetID().c_str());
}
//3. Finished, so unlock.
m_pInterface->SetLockStatus("", -1);
+ } else {
+ pInterface->FormatMessageWithString(_("\"%s\" does not specify training file. Dasher will work but entry will be slower. Check you have the latest version of the alphabet definition."), pAlphInfo->GetID().c_str());
}
-#ifdef DEBUG
- else {
- const char *msg = _("\"%s\" does not specify training file. Dasher will work but entry will be slower. Check you have the latest version of the alphabet definition.");
- char *buf(new char[strlen(msg) + pAlphInfo->GetID().length()]);
- sprintf(buf, msg, pAlphInfo->GetID().c_str());
- pInterface->Message(buf, true);
- delete buf;
- }
-#endif
#ifdef DEBUG_LM_READWRITE
{
//test...
@@ -171,5 +168,6 @@ void CNodeCreationManager::AddExtras(CDasherNode *pParent) {
void
CNodeCreationManager::ImportTrainingText(const std::string &strPath) {
ProgressNotifier pn(m_pInterface, m_pTrainer);
- pn.run("Training on New Text", strPath);
+ ifstream in(strPath.c_str(), ios::binary);
+ pn.ParseFile(strPath, true);
}
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
index bf81a98..67c3dd9 100644
--- a/Src/DasherCore/Parameters.cpp
+++ b/Src/DasherCore/Parameters.cpp
@@ -153,8 +153,6 @@ const sp_table stringparamtable[] = {
{SP_ALPHABET_4, "Alphabet4", PERS, "", "Alphabet History 4"},
{SP_COLOUR_ID, "ColourID", PERS, "", "ColourID"},
{SP_DASHER_FONT, "DasherFont", PERS, "", "DasherFont"},
- {SP_SYSTEM_LOC, "SystemLocation", !PERS, "sys_", "System Directory"},
- {SP_USER_LOC, "UserLocation", !PERS, "usr_", "User Directory"},
{SP_GAME_TEXT_FILE, "GameTextFile", PERS, "", "User-specified file with strings to practice writing"},
{SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", PERS, "x", "Label preceding X values for network input"},
{SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", PERS, "y", "Label preceding Y values for network input"},
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 2b77da3..e6d055b 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -68,7 +68,7 @@ enum {
enum {
SP_ALPHABET_ID = END_OF_LPS, SP_ALPHABET_1, SP_ALPHABET_2, SP_ALPHABET_3, SP_ALPHABET_4,
- SP_COLOUR_ID, SP_DASHER_FONT, SP_SYSTEM_LOC, SP_USER_LOC, SP_GAME_TEXT_FILE,
+ SP_COLOUR_ID, SP_DASHER_FONT, SP_GAME_TEXT_FILE,
SP_SOCKET_INPUT_X_LABEL, SP_SOCKET_INPUT_Y_LABEL, SP_INPUT_FILTER, SP_INPUT_DEVICE,
SP_BUTTON_0, SP_BUTTON_1, SP_BUTTON_2, SP_BUTTON_3, SP_BUTTON_4, SP_BUTTON_10, SP_JOYSTICK_DEVICE,
END_OF_SPS
diff --git a/Src/DasherCore/Trainer.cpp b/Src/DasherCore/Trainer.cpp
index 1815c21..d0cdca4 100644
--- a/Src/DasherCore/Trainer.cpp
+++ b/Src/DasherCore/Trainer.cpp
@@ -8,6 +8,8 @@
#include <sstream>
#include <string>
+#include <iostream>
+
using namespace Dasher;
using namespace std;
@@ -22,18 +24,15 @@ static char THIS_FILE[] = __FILE__;
#endif
CTrainer::CTrainer(CMessageDisplay *pMsgs, CLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pAlphabet)
- : m_pMsgs(pMsgs), m_pAlphabet(pAlphabet), m_pLanguageModel(pLanguageModel), m_pInfo(pInfo) {
+ : AbstractParser(pMsgs), m_pAlphabet(pAlphabet), m_pLanguageModel(pLanguageModel), m_pInfo(pInfo), m_pProg(NULL) {
vector<symbol> syms;
pAlphabet->GetSymbols(syms,pInfo->GetContextEscapeChar());
if (syms.size()==1)
m_iCtxEsc = syms[0];
else {
//no context switch commands will be executed!
- const char *msg(_("Warning: faulty alphabet definition, escape sequence %s must be a single unicode character. This may worsen Dasher's text prediction."));
- char *buf(new char[strlen(msg) + pInfo->GetContextEscapeChar().length() +1]);
- sprintf(buf,msg,pInfo->GetContextEscapeChar().c_str());
- pMsgs->Message(string(buf),true);
- delete buf;
+ pMsgs->FormatMessageWithString(_("Warning: faulty alphabet definition, escape sequence %s must be a single unicode character. This may worsen Dasher's text prediction."),
+ pInfo->GetContextEscapeChar().c_str());
m_iCtxEsc = -1;
}
}
@@ -95,64 +94,17 @@ private:
CTrainer::ProgressIndicator *m_pProg;
};
-void
-Dasher::CTrainer::LoadFile(const std::string &strFileName, ProgressIndicator *pProg) {
- if(strFileName == "")
- return;
-
- FILE *pInputFile;
- if((pInputFile = fopen(strFileName.c_str(), "r")) == (FILE *) 0)
- return;
-
- char szTestBuffer[6];
-
- int iNumberRead = fread(szTestBuffer, 1, 5, pInputFile);
- szTestBuffer[iNumberRead] = '\0';
-
- fclose(pInputFile);
+bool
+Dasher::CTrainer::Parse(const string &strDesc, istream &in, bool bUser) {
+ if (in.fail()) {
+ m_pMsgs->FormatMessageWithString(_("Unable to open file \"%s\" for reading"),strDesc.c_str());
+ return false;
+ }
- if(!strcmp(szTestBuffer, "<?xml")) {
- //Invoke AbstractXMLParser method
- m_bInSegment = false;
- m_iLastBytes=0;
- ParseFile(m_pMsgs, strFileName);
- } else {
- std::ifstream in(strFileName.c_str(), std::ios::binary);
- if (in.fail()) {
- const char *msg=_("Unable to open file \"%f\" for reading");
- char *buf(new char[strlen(msg) + strFileName.length()+1]);
- sprintf(buf, msg, strFileName.c_str());
- m_pMsgs->Message(buf, true);
- delete buf;
- return;
- }
- ProgressStream syms(in,pProg,m_pMsgs);
- Train(syms);
+ ProgressStream syms(in,m_pProg,m_pMsgs);
+ Train(syms);
- in.close();
- }
-}
-
-void CTrainer::XmlStartHandler(const XML_Char *szName, const XML_Char **pAtts) {
- if(!strcmp(szName, "segment")) {
- m_strCurrentText = "";
- m_bInSegment = true;
- }
-}
-
-void CTrainer::XmlEndHandler(const XML_Char *szName) {
- if(!strcmp(szName, "segment")) {
- std::istringstream in(m_strCurrentText);
- ProgressStream syms(in, m_pProg, m_pMsgs, m_iLastBytes);
- Train(syms);
- m_iLastBytes = syms.m_iLastPos; //count that segment, ready for next
- m_bInSegment = false;
- }
-}
-
-void CTrainer::XmlCData(const XML_Char *szS, int iLen) {
- if(m_bInSegment)
- m_strCurrentText += std::string(szS, iLen);
+ return true;
}
CMandarinTrainer::CMandarinTrainer(CMessageDisplay *pMsgs, CPPMPYLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pPYAlphabet, const CAlphabetMap *pCHAlphabet, const std::string &strDelim)
@@ -170,22 +122,12 @@ void CMandarinTrainer::Train(CAlphabetMap::SymbolStream &syms) {
symbol Sympy = syms.next(m_pPYAlphabet);
if (Sympy==-1) break; //EOF
if (Sympy==0) {
- const char *msg(_("Training file contains unknown source alphabet character %s"));
- string prev = syms.peekBack();
- char *buf(new char[strlen(msg) + prev.length()+1]);
- sprintf(buf, msg, prev.c_str());
- m_pMsgs->Message(buf,true);
- delete buf;
+ m_pMsgs->FormatMessageWithString(_("Training file contains unknown source alphabet character %s"), syms.peekBack().c_str());
}
symbol Symchar = syms.next(m_pAlphabet);
if (Symchar==-1) break; //EOF...ignore final Pinyin?
if (Symchar==0) {
- const char *msg=_("Training file contains unknown target alphabet character %s");
- string prev = syms.peekBack();
- char *buf(new char[strlen(msg) + prev.length()+1]);
- sprintf(buf,msg,prev.c_str());
- m_pMsgs->Message(buf,true);
- delete buf;
+ m_pMsgs->FormatMessageWithString(_("Training file contains unknown target alphabet character %s"), syms.peekBack().c_str());
}
static_cast<CPPMPYLanguageModel *>(m_pLanguageModel)->LearnPYSymbol(trainContext, Sympy);
m_pLanguageModel->LearnSymbol(trainContext, Symchar);
diff --git a/Src/DasherCore/Trainer.h b/Src/DasherCore/Trainer.h
index 340a207..cb3488e 100644
--- a/Src/DasherCore/Trainer.h
+++ b/Src/DasherCore/Trainer.h
@@ -6,7 +6,7 @@
#include "AbstractXMLParser.h"
namespace Dasher {
- class CTrainer : private AbstractXMLParser {
+ class CTrainer : public AbstractParser {
public:
CTrainer(CMessageDisplay *pMsgs, CLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pAlphabet);
@@ -16,13 +16,12 @@ namespace Dasher {
virtual void bytesRead(off_t)=0;
};
- void LoadFile(const std::string &strFileName, ProgressIndicator *pProg=NULL);
+ void SetProgressIndicator(ProgressIndicator *pProg) {m_pProg = pProg;}
+
+ ///Parses a text file; bUser ignored.
+ bool Parse(const std::string &strDesc, std::istream &in, bool bUser);
protected:
- ///Override AbstractXMLParser methods to extract text in <segment>...</segment> pairs
- void XmlStartHandler(const XML_Char *szName, const XML_Char **pAtts);
- void XmlEndHandler(const XML_Char *szName);
- void XmlCData(const XML_Char *szS, int iLen);
virtual void Train(CAlphabetMap::SymbolStream &syms);
@@ -33,19 +32,12 @@ namespace Dasher {
/// false, if instead a double-escape-character (=encoding of that actual symbol) was read
bool readEscape(CLanguageModel::Context &sContext, CAlphabetMap::SymbolStream &syms);
- CMessageDisplay * const m_pMsgs;
const CAlphabetMap * const m_pAlphabet;
CLanguageModel * const m_pLanguageModel;
const CAlphInfo * const m_pInfo;
// symbol number in alphabet of the context-switch character (maybe 0 if not in alphabet!)
int m_iCtxEsc;
private:
- //For dealing with XML CData:
- bool m_bInSegment;
- std::string m_strCurrentText;
- ///Number of bytes read up to and including end of _previous_ segment in XML.
- off_t m_iLastBytes;
- ///Store ProgressIndicator only when parsing XML
ProgressIndicator *m_pProg;
};
diff --git a/Src/Gtk2/DasherControl.cpp b/Src/Gtk2/DasherControl.cpp
index 55703a2..2f387c9 100644
--- a/Src/Gtk2/DasherControl.cpp
+++ b/Src/Gtk2/DasherControl.cpp
@@ -11,6 +11,7 @@
#include "../DasherCore/ModuleManager.h"
#include "dasher_main.h"
#include "../DasherCore/GameModule.h"
+#include "../Common/Globber.cpp"
#include <fcntl.h>
@@ -80,6 +81,11 @@ CDasherControl::CDasherControl(GtkVBox *pVBox, GtkDasherControl *pDasherControl)
g_signal_connect(m_pCanvas, "expose_event", G_CALLBACK(canvas_expose_event), this);
#endif
+ char *home_dir = getenv("HOME");
+ char *user_data_dir = new char[strlen(home_dir) + 10];
+ sprintf(user_data_dir, "%s/.dasher/", home_dir);
+ m_user_data_dir = user_data_dir;
+
m_pScreen = new CCanvas(m_pCanvas);
ChangeScreen(m_pScreen);
@@ -116,82 +122,23 @@ void CDasherControl::CreateModules() {
#endif
}
-void CDasherControl::SetupPaths() {
- char *home_dir;
- char *user_data_dir;
- const char *system_data_dir;
-
- home_dir = getenv("HOME");
- user_data_dir = new char[strlen(home_dir) + 10];
- sprintf(user_data_dir, "%s/.dasher/", home_dir);
-
- mkdir(user_data_dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+void CDasherControl::ScanFiles(AbstractParser *parser, const std::string &strPattern) {
+ //System files.
// PROGDATA is provided by the makefile
- system_data_dir = PROGDATA "/";
-
- SetStringParameter(SP_SYSTEM_LOC, system_data_dir);
- SetStringParameter(SP_USER_LOC, user_data_dir);
- delete[] user_data_dir;
-}
-
-void CDasherControl::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
- GDir *directory;
- G_CONST_RETURN gchar *filename;
- GPatternSpec *alphabetglob;
- alphabetglob = g_pattern_spec_new("alphabet*xml");
-
- directory = g_dir_open(GetStringParameter(SP_SYSTEM_LOC).c_str(), 0, NULL);
-
- if(directory) {
- while((filename = g_dir_read_name(directory))) {
- if(g_pattern_match_string(alphabetglob, filename))
- vFileList.push_back(filename);
- }
- g_dir_close(directory);
- }
-
- directory = g_dir_open(GetStringParameter(SP_USER_LOC).c_str(), 0, NULL);
-
- if(directory) {
- while((filename = g_dir_read_name(directory))) {
- if(g_pattern_match_string(alphabetglob, filename))
- vFileList.push_back(filename);
- }
- g_dir_close(directory);
- }
+ string path(PROGDATA "/");
+ path += strPattern;
- g_pattern_spec_free(alphabetglob);
-}
-
-void CDasherControl::ScanColourFiles(std::vector<std::string> &vFileList) {
- GDir *directory;
- G_CONST_RETURN gchar *filename;
-
- GPatternSpec *colourglob;
- colourglob = g_pattern_spec_new("colour*xml");
-
- directory = g_dir_open(GetStringParameter(SP_SYSTEM_LOC).c_str(), 0, NULL);
-
- if(directory) {
- while((filename = g_dir_read_name(directory))) {
- if(g_pattern_match_string(colourglob, filename))
- vFileList.push_back(filename);
- }
- g_dir_close(directory);
- }
-
- directory = g_dir_open(GetStringParameter(SP_USER_LOC).c_str(), 0, NULL);
-
- if(directory) {
- while((filename = g_dir_read_name(directory))) {
- if(g_pattern_match_string(colourglob, filename))
- vFileList.push_back(filename);
- }
- g_dir_close(directory);
- }
-
- g_pattern_spec_free(colourglob);
+ //User files.
+ mkdir(m_user_data_dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ string user_path(m_user_data_dir);
+ user_path += strPattern;
+
+ const char *user[2], *sys[2];
+ user[0] = user_path.c_str(); sys[0] = path.c_str();
+ user[1] = sys[1] = NULL; //terminators
+
+ globScan(parser, user, sys);
}
void CDasherControl::ClearAllContext() {
@@ -238,6 +185,8 @@ CDasherControl::~CDasherControl() {
m_p1DMouseInput = NULL;
}
+ delete[] m_user_data_dir;
+
// if(m_pKeyboardHelper) {
// delete m_pKeyboardHelper;
// m_pKeyboardHelper = 0;
@@ -471,7 +420,8 @@ void CDasherControl::WriteTrainFile(const std::string &filename, const std::stri
if(strNewText.length() == 0)
return;
- std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
+ std::string strFilename(m_user_data_dir);
+ strFilename+=filename;
int fd=open(strFilename.c_str(),O_CREAT|O_WRONLY|O_APPEND,S_IRUSR|S_IWUSR);
write(fd,strNewText.c_str(),strNewText.length());
diff --git a/Src/Gtk2/DasherControl.h b/Src/Gtk2/DasherControl.h
index 9a57653..354052b 100644
--- a/Src/Gtk2/DasherControl.h
+++ b/Src/Gtk2/DasherControl.h
@@ -167,9 +167,7 @@ public:
CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel);
private:
- virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
- virtual void ScanColourFiles(std::vector<std::string> &vFileList);
- virtual void SetupPaths();
+ virtual void ScanFiles(AbstractParser *parser, const std::string &strPattern);
virtual void CreateModules();
GtkWidget *m_pVBox;
@@ -194,6 +192,9 @@ private:
GtkDasherControl *m_pDasherControl;
+ //full path of user data directory, including trailing /
+ const char *m_user_data_dir;
+
///
/// Keyboard helper class
///
diff --git a/Src/MacOSX/COSXDasherControl.h b/Src/MacOSX/COSXDasherControl.h
index 27ccc53..07e35b4 100644
--- a/Src/MacOSX/COSXDasherControl.h
+++ b/Src/MacOSX/COSXDasherControl.h
@@ -58,9 +58,7 @@ public:
void SetEdit(id<DasherEdit> pEdit);
CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel);
private:
- virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
- virtual void ScanColourFiles(std::vector<std::string> &vFileList);
- virtual void SetupPaths();
+ virtual void ScanFiles(AbstractParser *parser, const std::string &strPattern);
virtual void CreateModules();
virtual bool SupportsSpeech();
virtual void Speak(const std::string &strText, bool bInterrupt);
@@ -82,12 +80,12 @@ private:
///Just log (and call superclass)
void editConvert(CDasherNode *pSource);
void editProtect(CDasherNode *pSource);
-
+
DasherApp *dasherApp; // objc counterpart
id<DasherEdit> dasherEdit; // current output - sends to other apps or textfield
COSXMouseInput *m_pMouseInput;
COSX1DMouseInput *m_p1DMouseInput;
-
+ NSString * const userDir;
};
diff --git a/Src/MacOSX/COSXDasherControl.mm b/Src/MacOSX/COSXDasherControl.mm
index 1011bb9..c3bf296 100644
--- a/Src/MacOSX/COSXDasherControl.mm
+++ b/Src/MacOSX/COSXDasherControl.mm
@@ -17,6 +17,7 @@
#import "DasherEdit.h"
#import "Event.h"
#import "../Common/Common.h"
+#import "../Common/Globber.h"
#import "GameModule.h"
#import <iostream>
@@ -76,7 +77,8 @@ private:
};
COSXDasherControl::COSXDasherControl(DasherApp *aDasherApp)
-: CDashIntfScreenMsgs(new COSXSettingsStore()), dasherApp(aDasherApp), dasherEdit(nil) {
+: CDashIntfScreenMsgs(new COSXSettingsStore()), dasherApp(aDasherApp), dasherEdit(nil),
+ userDir([[NSString stringWithFormat:@"%@/Library/Application Support/Dasher/", NSHomeDirectory()] retain]) {
}
void COSXDasherControl::CreateModules() {
@@ -96,6 +98,7 @@ COSXDasherControl::~COSXDasherControl() {
if(m_p1DMouseInput) {
m_p1DMouseInput = NULL;
}
+ [userDir release];
}
void COSXDasherControl::Realize2() {
@@ -103,61 +106,24 @@ void COSXDasherControl::Realize2() {
[dasherApp startTimer];
}
-void COSXDasherControl::SetupPaths() {
+void COSXDasherControl::ScanFiles(AbstractParser *parser, const string &strPattern) {
- NSString *systemDir = [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] resourcePath]];
- NSString *userDir = [NSString stringWithFormat:@"%@/Library/Application Support/Dasher/", NSHomeDirectory()];
+ string strPath(StdStringFromNSString([[NSBundle mainBundle] resourcePath])+"/"+strPattern);
+ const char *sys[2];
+ sys[0] = strPath.c_str();
+ sys[1] = NULL;
- // if the userDir doesn't exist, create it, ready to receive stuff
- if (![[NSFileManager defaultManager] fileExistsAtPath:userDir isDirectory:NULL]) {
- (void)[[NSFileManager defaultManager] createDirectoryAtPath:userDir attributes:nil];
+ const char *user[2]; user[1] = NULL;
+ if ([[NSFileManager defaultManager] fileExistsAtPath:userDir isDirectory:NULL]) {
+ user[0] = (StdStringFromNSString(userDir)+strPattern).c_str();
+ } else {
+ // userDir doesn't exist => create it, ready to receive stuff
+ (void)[[NSFileManager defaultManager] createDirectoryAtPath:userDir withIntermediateDirectories:YES attributes:nil error:nil];
+ user[0] = 0;
}
-
- // system resources are inside the .app, under the Resources directory
- SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
- SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
-}
-
-void COSXDasherControl::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
-
- NSDirectoryEnumerator *dirEnum;
- NSString *file;
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_SYSTEM_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"alphabet"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_USER_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"alphabet"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
+ globScan(parser, user, sys);
}
-void COSXDasherControl::ScanColourFiles(std::vector<std::string> &vFileList) {
- NSDirectoryEnumerator *dirEnum;
- NSString *file;
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_SYSTEM_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"colour"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_USER_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"colour"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
-}
-
-
void COSXDasherControl::goddamn(unsigned long iTime, bool bForceRedraw) {
NewFrame(iTime, bForceRedraw);
}
@@ -231,7 +197,7 @@ void COSXDasherControl::WriteTrainFile(const std::string &filename, const std::s
if(strNewText.length() == 0)
return;
- std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
+ std::string strFilename(StdStringFromNSString(userDir) + filename);
NSLog(@"Write train file: %s", strFilename.c_str());
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index f57a05e..4f95fde 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -392,6 +392,9 @@
33FC93390FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */; };
33FC933A0FEFA2C900A9F08D /* TwoPushDynamicFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */; };
33FC93430FEFA2FB00A9F08D /* FrameRate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */; };
+ E7641875142A48AD0031FC91 /* Globber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E7641874142A48AD0031FC91 /* Globber.cpp */; };
+ E7641878142A48C70031FC91 /* Globber.h in Headers */ = {isa = PBXBuildFile; fileRef = E7641877142A48C70031FC91 /* Globber.h */; };
+ E7C68E691430824D00440B5B /* Messages.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E7C68E681430824D00440B5B /* Messages.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -798,6 +801,9 @@
33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoPushDynamicFilter.cpp; sourceTree = "<group>"; };
33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoPushDynamicFilter.h; sourceTree = "<group>"; };
33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameRate.cpp; sourceTree = "<group>"; };
+ E7641874142A48AD0031FC91 /* Globber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Globber.cpp; path = ../Common/Globber.cpp; sourceTree = "<group>"; };
+ E7641877142A48C70031FC91 /* Globber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Globber.h; path = ../Common/Globber.h; sourceTree = "<group>"; };
+ E7C68E681430824D00440B5B /* Messages.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Messages.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -889,6 +895,7 @@
1948BDF40C226CFC001DFA32 /* DasherCore */ = {
isa = PBXGroup;
children = (
+ E7C68E681430824D00440B5B /* Messages.cpp */,
3344F0681341297F001FACAB /* UserLogBase.cpp */,
33CB6E7F125E2C7A002DB8AD /* WordGeneratorBase.cpp */,
33E756A31202D6180012A0E9 /* WordGeneratorBase.h */,
@@ -1256,6 +1263,8 @@
196874000C2BDC2E00D63879 /* OpenGLScreen.h */,
196874010C2BDC2E00D63879 /* OpenGLScreen.mm */,
19F8C7E50C858A2800276B4F /* I18n.h */,
+ E7641874142A48AD0031FC91 /* Globber.cpp */,
+ E7641877142A48C70031FC91 /* Globber.h */,
);
name = Common;
sourceTree = "<group>";
@@ -1467,6 +1476,7 @@
33FC1D2C13ACE7E7007642CD /* ScreenGameModule.h in Headers */,
33C3BDD213854CC000C768E0 /* DasherTextView.h in Headers */,
33DDB9E113B8AF360001C52D /* DynamicButtons.h in Headers */,
+ E7641878142A48C70031FC91 /* Globber.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1824,6 +1834,8 @@
33FC1D2B13ACE7E7007642CD /* ScreenGameModule.cpp in Sources */,
33C3BDD313854CC000C768E0 /* DasherTextView.mm in Sources */,
33DDB9E013B8AF360001C52D /* DynamicButtons.cpp in Sources */,
+ E7641875142A48AD0031FC91 /* Globber.cpp in Sources */,
+ E7C68E691430824D00440B5B /* Messages.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Src/Win32/Dasher.cpp b/Src/Win32/Dasher.cpp
index c9d01a5..8106b40 100644
--- a/Src/Win32/Dasher.cpp
+++ b/Src/Win32/Dasher.cpp
@@ -214,68 +214,38 @@ void CDasher::ScanDirectory(const Tstring &strMask, std::vector<std::string> &vF
}
}
-void CDasher::ScanColourFiles(std::vector<std::string> &vFileList) {
- Tstring Colours;
-
- // TODO: Is it okay to have duplicate names in the array?
- std::string strAppData2(GetStringParameter(SP_SYSTEM_LOC));
- Tstring strAppData;
-
- WinUTF8::UTF8string_to_wstring(strAppData2, strAppData);
-
- Colours = strAppData;
- Colours += TEXT("colour*.xml");
- ScanDirectory(Colours, vFileList);
-
- std::string strUserData2(GetStringParameter(SP_USER_LOC));
- Tstring strUserData;
-
- WinUTF8::UTF8string_to_wstring(strUserData2, strUserData);
-
- Colours = strUserData;
- Colours += TEXT("colour*.xml");
- ScanDirectory(Colours, vFileList);
-}
-
-void CDasher::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
- Tstring Alphabets;
-
- // TODO: Is it okay to have duplicate names in the array?
- std::string strAppData2(GetStringParameter(SP_SYSTEM_LOC));
- Tstring strAppData;
-
- WinUTF8::UTF8string_to_wstring(strAppData2, strAppData);
-
- Alphabets = strAppData;
- Alphabets += TEXT("alphabet*.xml");
- ScanDirectory(Alphabets, vFileList);
-
- std::string strUserData2(GetStringParameter(SP_USER_LOC));
- Tstring strUserData;
-
- WinUTF8::UTF8string_to_wstring(strUserData2, strUserData);
-
- Alphabets = strUserData;
- Alphabets += TEXT("alphabet*.xml");
- ScanDirectory(Alphabets, vFileList);
-}
-
-void CDasher::SetupPaths() {
+void CDasher::ScanFiles(AbstractParser *parser, const std::string &strPattern) {
using namespace WinHelper;
using namespace WinUTF8;
-
- Tstring UserData, AppData;
- std::string UserData2, AppData2;
- GetUserDirectory(&UserData);
+
+ Tstring pattern;
+ UTF8string_to_wstring(strPattern, pattern);
+
+ std::vector<std::string> vFileList;
+
+ Tstring AppData;
GetAppDirectory(&AppData);
- UserData += TEXT("dasher.rc\\");
AppData += TEXT("system.rc\\");
- CreateDirectory(UserData.c_str(), NULL); // Try and create folders. Doesn't seem
CreateDirectory(AppData.c_str(), NULL); // to do any harm if they already exist.
- wstring_to_UTF8string(UserData, UserData2); // TODO: I don't know if special characters will work.
- wstring_to_UTF8string(AppData, AppData2); // ASCII-only filenames are safest. Being English doesn't help debug this...
- SetStringParameter(SP_SYSTEM_LOC, AppData2);
- SetStringParameter(SP_USER_LOC, UserData2);
+ string sysDir;
+ wstring_to_UTF8string(AppData,sysDir);
+ AppData += pattern;
+ ScanDirectory(AppData, vFileList);
+ for (vector<std::string>::iterator it=vFileList.begin(); it!=vFileList.end(); it++)
+ parser->ParseFile(sysDir + (*it),false);
+
+ vFileList.clear();
+
+ Tstring UserData;
+ GetUserDirectory(&UserData);
+ UserData += TEXT("dasher.rc\\");
+ CreateDirectory(UserData.c_str(), NULL); // Try and create folders. Doesn't seem
+ string userDir;
+ wstring_to_UTF8string(UserData,userDir);
+ UserData +=pattern;
+ ScanDirectory(UserData, vFileList);
+ for (vector<std::string>::iterator it=vFileList.begin(); it!=vFileList.end(); it++)
+ parser->ParseFile(userDir + (*it),true);
}
int CDasher::GetFileSize(const std::string &strFileName) {
diff --git a/Src/Win32/Dasher.h b/Src/Win32/Dasher.h
index 7e51f33..05d51bf 100644
--- a/Src/Win32/Dasher.h
+++ b/Src/Win32/Dasher.h
@@ -65,9 +65,7 @@ public:
virtual int GetFileSize(const std::string &strFileName);
private:
- virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
- virtual void ScanColourFiles(std::vector<std::string> &vFileList);
- virtual void SetupPaths();
+ virtual void ScanFiles(AbstractParser *parser, const std::string &strPattern);
virtual void CreateModules();
void ScanDirectory(const Tstring &strMask, std::vector<std::string> &vFileList);
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.h b/Src/iPhone/Classes/CDasherInterfaceBridge.h
index 064c70d..ef5e625 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.h
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.h
@@ -69,10 +69,8 @@ public:
///Override for asynchronous messages only...TODO?
void Message(const string &strText, bool bInterrupt);
Dasher::CGameModule *CreateGameModule(Dasher::CDasherView *pView,Dasher::CDasherModel *pModel);
+ void ScanFiles(AbstractParser *parser, const std::string &strPattern);
private:
- virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
- virtual void ScanColourFiles(std::vector<std::string> &vFileList);
- virtual void SetupPaths();
virtual void CreateModules();
///
@@ -81,6 +79,8 @@ private:
void HandleEvent(int iParameter);
+ const NSString * const userPath;
+
DasherAppDelegate *dasherApp; // objc counterpart
Dasher::CIPhoneMouseInput *m_pMouseDevice;
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index 59ed81a..85405ff 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -20,6 +20,7 @@
#import "TwoPushDynamicFilter.h"
#import "EAGLView.h"
#import "GameModule.h"
+#import "../Common/Globber.h"
#import <iostream>
#import <fcntl.h>
@@ -74,7 +75,9 @@ private:
UIWebView *m_pWebView;
};
-CDasherInterfaceBridge::CDasherInterfaceBridge(DasherAppDelegate *aDasherApp) : CDashIntfScreenMsgs(new COSXSettingsStore()), dasherApp(aDasherApp) {
+CDasherInterfaceBridge::CDasherInterfaceBridge(DasherAppDelegate *aDasherApp) : CDashIntfScreenMsgs(new COSXSettingsStore()),
+dasherApp(aDasherApp),
+userPath([[NSString stringWithFormat:@"%@/", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]] retain]) {
}
void CDasherInterfaceBridge::CreateModules() {
@@ -108,6 +111,7 @@ CDasherInterfaceBridge::~CDasherInterfaceBridge() {
delete m_pTwoFingerDevice;
delete m_pUndoubledTouch;
//(ACL)registered input filters should be automatically free'd by the module mgr?
+ [userPath release];
}
void CDasherInterfaceBridge::SetTiltAxes(Vec3 main, float off, Vec3 slow, float off2)
@@ -125,52 +129,35 @@ void CDasherInterfaceBridge::Realize() {
[dasherApp glView].animating=YES;
}
-void CDasherInterfaceBridge::SetupPaths() {
- NSString *systemDir = [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]];
- NSString *userDir = [NSString stringWithFormat:@"%@/", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
+void CDasherInterfaceBridge::ScanFiles(AbstractParser *parser, const std::string &strPattern) {
- SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
- SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
-}
-
-void CDasherInterfaceBridge::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
+ string strPath(StdStringFromNSString([[NSBundle mainBundle] bundlePath])+"/"+strPattern);
+ const char *sys[2];
+ sys[0] = strPath.c_str();
+ sys[1] = NULL;
- NSDirectoryEnumerator *dirEnum;
- NSString *file;
+ const char *user[2]; user[1] = NULL;
+ if ([[NSFileManager defaultManager] fileExistsAtPath:userPath isDirectory:NULL]) {
+ user[0] = (StdStringFromNSString(userPath)+strPattern).c_str();
+ } else {
+ // userDir doesn't exist => create it, ready to receive stuff
+ (void)[[NSFileManager defaultManager] createDirectoryAtPath:userPath withIntermediateDirectories:YES attributes:nil error:nil];
+ user[0] = 0;
+ }
+ globScan(parser, user, sys);
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_SYSTEM_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"alphabet"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_USER_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"alphabet"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
}
-void CDasherInterfaceBridge::ScanColourFiles(std::vector<std::string> &vFileList) {
- NSDirectoryEnumerator *dirEnum;
- NSString *file;
-
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_SYSTEM_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"colour"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
+/*void CDasherInterfaceBridge::ScanForFiles(AbstractFileParser *parser, const std::string &strName) {
+ NSFileManager *mgr = [NSFileManager defaultManager];
+ NSArray *names = [[mgr enumeratorAtPath:systemPath] allObjects];
+ if ([names containsObject:NSStringFromStdString(strName)])
+ parser->ParseFile(StdStringFromNSString(systemPath)+strName,false);
- dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:NSStringFromStdString(GetStringParameter(SP_USER_LOC))];
- while (file = [dirEnum nextObject]) {
- if ([file hasSuffix:@".xml"] && [file hasPrefix:@"colour"]) {
- vFileList.push_back(StdStringFromNSString(file));
- }
- }
-}
+ names = [[mgr enumeratorAtPath:userPath] allObjects];
+ if ([names containsObject:NSStringFromStdString(strName)])
+ parser->ParseFile(StdStringFromNSString(userPath)+strName,true);
+}*/
void CDasherInterfaceBridge::NewFrame(unsigned long iTime, bool bForceRedraw) {
CDashIntfScreenMsgs::NewFrame(iTime, bForceRedraw);
@@ -277,7 +264,7 @@ void CDasherInterfaceBridge::WriteTrainFile(const std::string &filename,const st
if(strNewText.length() == 0)
return;
- std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
+ std::string strFilename(StdStringFromNSString(userPath) + filename);
NSLog(@"Write train file: %s", strFilename.c_str());
diff --git a/Src/iPhone/Dasher.xcodeproj/project.pbxproj b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
index 6af3c32..f461384 100755
--- a/Src/iPhone/Dasher.xcodeproj/project.pbxproj
+++ b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
@@ -216,6 +216,8 @@
3344FE660F71717C00506EAA /* XMLUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FE130F71717C00506EAA /* XMLUtil.cpp */; };
334B1BF111232A8E007A6DFF /* ParametersController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 334B1BF011232A8E007A6DFF /* ParametersController.mm */; };
3354AF4811ADBAFD006CF570 /* Actions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3354AF4711ADBAFD006CF570 /* Actions.mm */; };
+ 33557FC4142B484E002C600E /* Globber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33557FC2142B484E002C600E /* Globber.cpp */; };
+ 33558058142B7206002C600E /* Messages.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33558057142B7206002C600E /* Messages.cpp */; };
3360335813ABDF3700417DFE /* ScreenGameModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3360335713ABDF3700417DFE /* ScreenGameModule.cpp */; };
33627FBA0F7A82CF000C8818 /* training_albanian_SQ.txt in Resources */ = {isa = PBXBuildFile; fileRef = 33627F9A0F7A82CE000C8818 /* training_albanian_SQ.txt */; };
33627FBD0F7A82CF000C8818 /* training_bengali_BD.txt in Resources */ = {isa = PBXBuildFile; fileRef = 33627F9D0F7A82CE000C8818 /* training_bengali_BD.txt */; };
@@ -654,6 +656,9 @@
334B1C2011233B8B007A6DFF /* ModuleSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleSettings.h; sourceTree = "<group>"; };
3354AF4611ADBAFD006CF570 /* Actions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Actions.h; sourceTree = "<group>"; };
3354AF4711ADBAFD006CF570 /* Actions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Actions.mm; sourceTree = "<group>"; };
+ 33557FC2142B484E002C600E /* Globber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Globber.cpp; sourceTree = "<group>"; };
+ 33557FC3142B484E002C600E /* Globber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Globber.h; sourceTree = "<group>"; };
+ 33558057142B7206002C600E /* Messages.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Messages.cpp; sourceTree = "<group>"; };
3360335613ABDF3700417DFE /* ScreenGameModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenGameModule.h; sourceTree = "<group>"; };
3360335713ABDF3700417DFE /* ScreenGameModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScreenGameModule.cpp; sourceTree = "<group>"; };
33627F9A0F7A82CE000C8818 /* training_albanian_SQ.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_albanian_SQ.txt; sourceTree = "<group>"; };
@@ -1238,6 +1243,7 @@
3344FDDE0F71717C00506EAA /* MemoryLeak.cpp */,
3344FDDF0F71717C00506EAA /* MemoryLeak.h */,
33B342F313A8A8B2009AE0D5 /* Messages.h */,
+ 33558057142B7206002C600E /* Messages.cpp */,
3344FDE00F71717C00506EAA /* ModuleManager.cpp */,
3344FDE10F71717C00506EAA /* ModuleManager.h */,
3344FDE20F71717C00506EAA /* NodeCreationManager.cpp */,
@@ -1343,6 +1349,8 @@
3344FE670F71718B00506EAA /* Common */ = {
isa = PBXGroup;
children = (
+ 33557FC2142B484E002C600E /* Globber.cpp */,
+ 33557FC3142B484E002C600E /* Globber.h */,
33EB49220F73E8B30048E7C2 /* OpenGLScreen.h */,
33EB49230F73E8B30048E7C2 /* OpenGLScreen.mm */,
334B1C2011233B8B007A6DFF /* ModuleSettings.h */,
@@ -1729,6 +1737,8 @@
33DFE416137AA32300F86CDE /* WordGeneratorBase.cpp in Sources */,
3360335813ABDF3700417DFE /* ScreenGameModule.cpp in Sources */,
33B6825013CA4CC300F0A952 /* DynamicButtons.cpp in Sources */,
+ 33557FC4142B484E002C600E /* Globber.cpp in Sources */,
+ 33558058142B7206002C600E /* Messages.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]