aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README5
-rw-r--r--interface.ccl3
-rw-r--r--schedule.ccl12
-rw-r--r--src/announce.cc257
-rw-r--r--src/file.cc99
-rw-r--r--src/file.hh22
-rw-r--r--src/multistorage.cc14
-rw-r--r--src/multistorage.hh4
-rw-r--r--src/portal.cc250
-rw-r--r--src/portal.hh28
-rw-r--r--src/storage.cc61
-rw-r--r--src/storage.hh32
12 files changed, 685 insertions, 102 deletions
diff --git a/README b/README
index 1e4fc58..956768c 100644
--- a/README
+++ b/README
@@ -28,3 +28,8 @@ use a configuration script to amend all thorns' make.code.deps files
to create the tarballs when the thorns are compiled
use perl instead of C for makeblob and makemetablob
+
+announce: maybe use <array> for parameter arrays
+ maybe use <bool> for booleans
+ maybe use <dateTime.iso8601>20100302T00:00:00</dateTime.iso8601>
+ for dates and times
diff --git a/interface.ccl b/interface.ccl
index 37a672d..32918c2 100644
--- a/interface.ccl
+++ b/interface.ccl
@@ -2,3 +2,6 @@
# $Header$
IMPLEMENTS: Formaline
+
+# for HTTP_Port()
+USES INCLUDE HEADER: http_Content.h
diff --git a/schedule.ccl b/schedule.ccl
index 6e6dd28..3e7f971 100644
--- a/schedule.ccl
+++ b/schedule.ccl
@@ -11,7 +11,17 @@ if (output_source)
-SCHEDULE Formaline_Announce AT wragh
+SCHEDULE Formaline_AnnounceInitial AT wragh
+{
+ LANG: C
+} "Put some meta information about the current run into permanent storage"
+
+SCHEDULE Formaline_AnnounceUpdate AT analysis
+{
+ LANG: C
+} "Put some meta information about the current run into permanent storage"
+
+SCHEDULE Formaline_AnnounceFinal AT terminate
{
LANG: C
} "Put some meta information about the current run into permanent storage"
diff --git a/src/announce.cc b/src/announce.cc
index 2525671..6b11184 100644
--- a/src/announce.cc
+++ b/src/announce.cc
@@ -4,15 +4,22 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <ctime>
+#include <iomanip>
#include <sstream>
#include <string>
+#include <sys/types.h>
+#include <unistd.h>
+
#include "cctk.h"
#include "cctk_Arguments.h"
#include "cctk_Parameters.h"
#include "cctk_Version.h"
#include "util_Network.h"
+#include "http_Content.h"
+
#include "file.hh"
#include "multistorage.hh"
#include "portal.hh"
@@ -21,21 +28,69 @@ using namespace std;
-extern "C"
-void
-Formaline_Announce (CCTK_ARGUMENTS)
+static char * jobid = 0;
+
+
+
+ // Create a unique job id
+static void
+create_jobid (CCTK_ARGUMENTS)
{
+ DECLARE_CCTK_ARGUMENTS;
DECLARE_CCTK_PARAMETERS;
+ ostringstream jobidbuf;
+
+ char run_host [1000];
+ Util_GetHostName (run_host, sizeof run_host);
+ jobidbuf << run_host;
+ jobidbuf << "-";
+
+#if 0
+ char const * const run_user = CCTK_RunUser();
+#else
+ char const * const run_user = getenv ("USER");
+#endif
+ jobidbuf << run_user;
+
+ jobidbuf << "-";
+
+ time_t const tim = time (0);
+ struct tm * const ptm = gmtime (& tim);
+ jobidbuf << setfill ('0')
+ << setw(4) << ptm->tm_year
+ << setw(2) << ptm->tm_mon
+ << setw(2) << ptm->tm_mday
+ << "-"
+ << setw(2) << ptm->tm_hour
+ << setw(2) << ptm->tm_min
+ << setw(2) << ptm->tm_sec;
+
+ jobidbuf << "-";
+
+ pid_t const pid = getpid();
+ jobidbuf << pid;
+
+ string const jobidstr = jobidbuf.str();
+ jobid = strdup (jobidstr.c_str());
+}
+
+
+
+extern "C"
+void
+Formaline_AnnounceInitial (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
// Only store from the root processor
if (CCTK_MyProc (cctkGH) != 0) return;
- // Create a unique job id
- char const * const jobid = "unique ID";
+ create_jobid (cctkGH);
@@ -43,18 +98,117 @@ Formaline_Announce (CCTK_ARGUMENTS)
if (announce_to_portal)
{
- stores.add_storage (new portal (jobid));
+ stores.add_storage (new portal (jobid, storage::initial));
}
if (store_into_file)
{
- stores.add_storage (new file (jobid));
+ stores.add_storage (new file (jobid, storage::initial));
}
if (stores.num_storages() == 0) return;
+ // Information in the Portal/Announce format
+ {
+ // Don't know what this is for
+ stores.store ("jobtype", "default");
+ }
+ {
+ int type;
+ void const * const ptr
+ = CCTK_ParameterGet ("cctk_run_title", "Cactus", & type);
+ assert (type == PARAMETER_STRING);
+ char const * const run_title = * static_cast<char const * const *> (ptr);
+ stores.store ("app_title", run_title);
+ }
+ {
+ char run_date [1000];
+ Util_CurrentDate (sizeof run_date, run_date);
+ char run_time [1000];
+ Util_CurrentTime (sizeof run_time, run_time);
+ ostringstream timebuf;
+ timebuf << run_date << " " << run_time;
+ string const timestr = timebuf.str();
+ stores.store ("start_time", timestr.c_str());
+ }
+ {
+ // Don't know what this is for
+ stores.store ("project_name", "");
+ }
+ {
+ stores.store ("output_files", out_dir);
+ }
+ {
+ char run_host [1000];
+ Util_GetHostName (run_host, sizeof run_host);
+ stores.store ("host", run_host);
+ }
+ {
+ unsigned long http_port;
+#ifdef __HTTP_CONTENT_H__
+ if (CCTK_IsThornActive ("HTTPD"))
+ {
+ // Thorn is compiled in and active, ask it
+ http_port = HTTP_Port();
+ }
+ else
+ {
+ // Thorn is compiled in but not active, ignore it
+ http_port = 0;
+ }
+#else
+ {
+ // Thorn is not compiled in, ignore it
+ http_port = 0;
+ }
+#endif
+ stores.store ("port", (int) http_port);
+ }
+ {
+ stores.store ("portal_username", portal_username);
+ }
+ {
+#if 0
+ char const * const run_user = CCTK_RunUser();
+#else
+ char const * const run_user = getenv ("USER");
+#endif
+ stores.store ("local_username", run_user);
+ }
+ {
+ char parameter_filename [10000];
+ CCTK_ParameterFilename (sizeof parameter_filename, parameter_filename);
+ stores.store ("parameter_file", parameter_filename);
+ }
+ {
+ char ** argv;
+ int argc;
+ int n;
+ CCTK_CommandLine (& argv);
+ for (argc = 0; argv [argc]; ++ argc);
+ stores.store ("executable", argc == 0 ? "" : argv[0]);
+ }
+ {
+ // Don't know what this is for
+ stores.store ("data_directory", "");
+ }
+ {
+ // Could also be "private"
+ stores.store ("app_visibility", "public");
+ }
+ {
+ // Could apparently be none, register, update, deregister
+ stores.store ("notification_reports", "");
+ }
+ {
+ // Could apparently be none, email, im, sms
+ stores.store ("notification_methods", "");
+ }
+
+
+
// Cactus
{
@@ -122,7 +276,7 @@ Formaline_Announce (CCTK_ARGUMENTS)
void const * const ptr
= CCTK_ParameterGet ("cctk_run_title", "Cactus", & type);
assert (type == PARAMETER_STRING);
- char const * const run_title = static_cast<char const *> (ptr);
+ char const * const run_title = * static_cast<char const * const *> (ptr);
stores.store ("run title", run_title);
}
@@ -151,6 +305,8 @@ Formaline_Announce (CCTK_ARGUMENTS)
stores.store ("parameter filename", parameter_filename);
}
+#if 0
+ // This is superfluous, and it does not look nice
{
char parameter_filename [10000];
char parameter_file [1000000];
@@ -164,6 +320,7 @@ Formaline_Announce (CCTK_ARGUMENTS)
parameter_file [count] = '\0';
stores.store ("parameter file", parameter_file);
}
+#endif
{
int type;
@@ -182,6 +339,7 @@ Formaline_Announce (CCTK_ARGUMENTS)
+#if 0
// All Cactus thorns
{
@@ -269,4 +427,87 @@ Formaline_Announce (CCTK_ARGUMENTS)
first = 0;
}
}
+#endif
+
+
+
+ // Simulation state
+
+ {
+ stores.store ("cctk_iteration", cctk_iteration);
+ }
+}
+
+
+
+extern "C"
+void
+Formaline_AnnounceUpdate (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ // Only store from the root processor
+ if (CCTK_MyProc (cctkGH) != 0) return;
+
+
+
+ multistorage stores;
+
+ if (announce_to_portal)
+ {
+ stores.add_storage (new portal (jobid, storage::update));
+ }
+
+ if (store_into_file)
+ {
+ stores.add_storage (new file (jobid, storage::update));
+ }
+
+ if (stores.num_storages() == 0) return;
+
+
+
+ // Simulation state
+
+ {
+ stores.store ("cctk_iteration", cctk_iteration);
+ }
+}
+
+
+
+extern "C"
+void
+Formaline_AnnounceFinal (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ // Only store from the root processor
+ if (CCTK_MyProc (cctkGH) != 0) return;
+
+
+
+ multistorage stores;
+
+ if (announce_to_portal)
+ {
+ stores.add_storage (new portal (jobid, storage::final));
+ }
+
+ if (store_into_file)
+ {
+ stores.add_storage (new file (jobid, storage::final));
+ }
+
+ if (stores.num_storages() == 0) return;
+
+
+
+ // Simulation state
+
+ {
+ stores.store ("cctk_iteration", cctk_iteration);
+ }
}
diff --git a/src/file.cc b/src/file.cc
index 8982434..2bff9b8 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -1,5 +1,7 @@
// $Header$
+#include <iomanip>
+#include <ios>
#include <sstream>
#include "cctk_Parameters.h"
@@ -13,14 +15,23 @@ using namespace std;
file::
-file (char const * const id)
+file (char const * const id,
+ enum state const st)
+ : storage (st)
{
DECLARE_CCTK_PARAMETERS;
ostringstream filenamebuf;
filenamebuf << out_dir << "/" << storage_filename;
string const filenamestring = filenamebuf.str();
- fil.open (filenamestring.c_str());
+
+ ios::openmode const mode = get_state() == initial ? ios::trunc : ios::app;
+ fil.open (filenamestring.c_str(), mode);
+
+ if (get_state() == initial)
+ {
+ store ("jobid", id);
+ }
}
@@ -28,13 +39,97 @@ file (char const * const id)
file::
~ file ()
{
+ if (get_state() == final)
+ {
+ store ("simulation", "done");
+ }
fil.close();
}
void file::
+store (char const * const key,
+ int const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << value;
+
+ ostringstream buf;
+ buf << clean (keybuf.str()) << "=" << clean (valuebuf.str()) << endl;
+
+ write (buf.str());
+}
+
+
+
+void file::
+store (char const * const key,
+ double const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << setprecision(15) << value;
+
+ ostringstream buf;
+ buf << clean (keybuf.str()) << "=" << clean (valuebuf.str()) << endl;
+
+ write (buf.str());
+}
+
+
+
+void file::
+store (char const * const key,
+ char const * const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << value;
+
+ ostringstream buf;
+ buf << clean (keybuf.str()) << "="
+ << "\"" << clean (valuebuf.str()) << "\"" << endl;
+
+ write (buf.str());
+}
+
+
+
+void file::
write (std::string const & msg)
{
fil << msg;
}
+
+
+
+string file::
+clean (string const & txt)
+ const
+{
+ ostringstream buf;
+
+ for (string::const_iterator p = txt.begin(); p != txt.end(); ++ p)
+ {
+ switch (* p)
+ {
+ case '=': buf << "\\="; break;
+ case '"': buf << "\\\""; break;
+ case '\\': buf << "\\\\"; break;
+ default: buf << * p;
+ }
+ }
+
+ return buf.str();
+}
diff --git a/src/file.hh b/src/file.hh
index 17cc1ac..3c3c0ac 100644
--- a/src/file.hh
+++ b/src/file.hh
@@ -17,15 +17,33 @@ class file : public storage
ofstream fil;
public:
- file (char const * id);
+
+ file (char const * id,
+ enum state st);
virtual
~ file ();
-protected:
+ virtual void
+ store (char const * key,
+ int value);
+
+ virtual void
+ store (char const * key,
+ double value);
virtual void
+ store (char const * key,
+ char const * value);
+
+private:
+
+ void
write (std::string const & msg);
+
+ std::string
+ clean (std::string const & txt)
+ const;
};
diff --git a/src/multistorage.cc b/src/multistorage.cc
index bf25e33..6521d3c 100644
--- a/src/multistorage.cc
+++ b/src/multistorage.cc
@@ -58,6 +58,20 @@ store (char const * const key, int const value)
void multistorage::
+store (char const * const key, double const value)
+ const
+{
+ for (list<storage *>::const_iterator it = stores.begin();
+ it != stores.end();
+ ++ it)
+ {
+ (* it)->store (key, value);
+ }
+}
+
+
+
+void multistorage::
store (char const * const key, char const * const value)
const
{
diff --git a/src/multistorage.hh b/src/multistorage.hh
index d61e0ef..6affcbb 100644
--- a/src/multistorage.hh
+++ b/src/multistorage.hh
@@ -38,6 +38,10 @@ public:
const;
void
+ store (char const * key, double value)
+ const;
+
+ void
store (char const * key, char const * value)
const;
};
diff --git a/src/portal.cc b/src/portal.cc
index 5d36f5a..01d4a0c 100644
--- a/src/portal.cc
+++ b/src/portal.cc
@@ -1,46 +1,103 @@
// $Header$
#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
#include <string>
#include <sstream>
+#include "cctk.h"
#include "cctk_Parameters.h"
#include "portal.hh"
-using std::string;
-using std::ostringstream;
+using namespace std;
+
+
+
+extern int h_errno;
portal::
-portal (char const * const id)
+portal (char const * const id,
+ enum state const st)
+ : storage (st),
+ errorcount (0)
{
DECLARE_CCTK_PARAMETERS;
sock = socket (PF_INET, SOCK_STREAM, 0);
-#warning "TODO: handle errors"
+ if (sock < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s", strerror (errno));
+ }
struct hostent * hostinfo;
hostinfo = gethostbyname (portal_hostname);
-#warning "TODO: handle errors"
- assert (hostinfo);
+ if (hostinfo == 0)
+ {
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ CCTK_WARN (1, "The specified host is unknown.");
+ break;
+ case NO_ADDRESS:
+ // case NO_DATA:
+ CCTK_WARN (1, "The requested name is valid but does not have an IP address.");
+ break;
+ case NO_RECOVERY:
+ CCTK_WARN (1, "A non-recoverable name server error occurred.");
+ break;
+ case TRY_AGAIN:
+ CCTK_WARN (1, "A temporary error occurred on an authoritative name server. Try again later.");
+ break;
+ default:
+ CCTK_WARN (1, "unknown error");
+ }
+ }
struct sockaddr_in addr;
addr.sin_family = AF_INET;
- addr.sin_port = portal_port;
+ addr.sin_port = htons (portal_port);
addr.sin_addr = * (struct in_addr *) hostinfo->h_addr;
int const ierr
= connect (sock, (struct sockaddr const *) (& addr), sizeof addr);
-#warning "TODO: handle errors"
- assert (! ERROR_CHECK (ierr));
+ if (ierr < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s", strerror (errno));
+ }
- ostringstream buf;
- buf << "<simulation id=\"" << clean (id) << "\">\n";
- write (buf.str());
+ msgbuf << "<?xml version='1.0' ?>"
+ << "<methodCall><methodName>";
+ switch (get_state())
+ {
+ case initial:
+ msgbuf << "cactus.registerApplication";
+ break;
+ case update:
+ msgbuf << "cactus.updateApplication";
+ break;
+ case final:
+ msgbuf << "cactus.deregisterApplication";
+ break;
+ default:
+ assert (0);
+ }
+ msgbuf << "</methodName>"
+ << "<params><param><value><struct>"
+ << "<member>"
+ << "<name>jobid</name>"
+ << "<value><string>" << clean (id) << "</string></value>"
+ << "</member>";
}
@@ -48,25 +105,174 @@ portal (char const * const id)
portal::
~ portal ()
{
+ msgbuf << "</struct></value></param></params>";
+ msgbuf << "</methodCall>";
+ string const msgstr = msgbuf.str();
+
ostringstream buf;
- buf << "</simulation>\n";
+ buf << "POST HTTP/1.0 200\r\n"
+ << "Content-Type: text/xml\r\n"
+ << "Content-Length: " << msgstr.length() << "\r\n"
+ << "\r\n"
+ << msgstr << "\r\n"
+ << "\r\n";
write (buf.str());
CLOSESOCKET (sock);
-#warning "TODO: handle errors"
+}
+
+
+
+void portal::
+store (char const * const key,
+ int const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << value;
+
+ msgbuf << "<member>"
+ << "<name>" << clean (keybuf.str()) << "</name>"
+ << "<value><int>" << clean (valuebuf.str()) << "</int></value>"
+ << "</member>";
+}
+
+
+
+void portal::
+store (char const * const key,
+ double const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << setprecision(15) << value;
+
+ msgbuf << "<member>"
+ << "<name>" << clean (keybuf.str()) << "</name>"
+ << "<value><double>" << clean (valuebuf.str()) << "</double></value>"
+ << "</member>";
+}
+
+
+
+void portal::
+store (char const * const key,
+ char const * const value)
+{
+ assert (key);
+
+ ostringstream keybuf;
+ keybuf << key;
+ ostringstream valuebuf;
+ valuebuf << value;
+
+ msgbuf << "<member>"
+ << "<name>" << clean (keybuf.str()) << "</name>"
+ << "<value><string>" << clean (valuebuf.str()) << "</string></value>"
+ << "</member>";
}
void portal::
-write (string const & msg)
+write (string const & msg0)
+{
+ // cout << "[" << msg0 << "]" << endl;
+ string msg = msg0;
+ for (;;)
+ {
+
+ char const * const cmsg = msg.c_str();
+ size_t const len = msg.length();
+
+ // TODO: Make sure that we don't wait forever here. Maybe use
+ // MSG_DONTWAIT.
+ ssize_t const nelems = send (sock, cmsg, len, MSG_NOSIGNAL);
+ if (nelems < 0)
+ {
+#ifdef EMSGSIZE
+ if (nelems == EMSGSIZE)
+ {
+ // The socket type requires that message be sent atomically,
+ // and the size of the message to be sent made this
+ // impossible.
+ // Try to send the message as two smaller messages.
+ if (len > 0)
+ {
+ string const msg1 = msg.substr (0, len/2);
+ string const msg2 = msg.substr (len/2);
+ write (msg1);
+ write (msg2);
+ }
+ else
+ {
+ // There is a limit. In order to not be too inefficient,
+ // just do nothing if even small messages cannot be sent.
+ }
+ }
+ else
+#endif
+ {
+ int const maxerrors = 10;
+ ++ errorcount;
+ if (errorcount <= maxerrors)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s", strerror (errno));
+ if (errorcount == maxerrors)
+ {
+ CCTK_WARN (1, "Too many errors. Suppressing further error messages.");
+ }
+ }
+ }
+ return;
+ }
+
+ if (nelems == len) return;
+
+ assert (nelems < len);
+ msg = msg.substr (nelems);
+
+ // Wait until can write
+ fd_set fds;
+ FD_ZERO (& fds);
+ assert (sock >= 0 and sock < FD_SETSIZE);
+ FD_SET (sock, & fds);
+ // TODO: Make sure that we don't wait forever here.
+ int const ierr = select (FD_SETSIZE, 0, & fds, 0, 0);
+ if (ierr < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s", strerror (errno));
+ return;
+ }
+
+ }
+}
+
+
+
+string portal::
+clean (string const & txt)
+ const
{
- char const * const cmsg = msg.c_str();
+ ostringstream buf;
+
+ for (string::const_iterator p = txt.begin(); p != txt.end(); ++ p)
+ {
+ switch (* p)
+ {
+ case '<': buf << "&lt;"; break;
+ case '&': buf << "&amp;"; break;
+ default: buf << * p;
+ }
+ }
- size_t const len = strlen (cmsg);
- ssize_t const nelems = send (sock, cmsg, len, MSG_NOSIGNAL);
- assert (! ERROR_CHECK (nelems));
-#warning "TODO: handle errors"
-#warning "TODO: handle overflow"
- assert (nelems == len);
+ return buf.str();
}
diff --git a/src/portal.hh b/src/portal.hh
index c92faa0..0be9074 100644
--- a/src/portal.hh
+++ b/src/portal.hh
@@ -5,6 +5,7 @@
+#include <sstream>
#include <string>
#ifdef HAVE_UNISTD_H
@@ -55,18 +56,41 @@
class portal : public storage
{
+
SOCKET sock;
+ std::ostringstream msgbuf;
+
+ int errorcount;
+
public:
- portal (char const * id);
+
+ portal (char const * id,
+ enum state st);
virtual
~ portal ();
-protected:
+ virtual void
+ store (char const * key,
+ int value);
+
+ virtual void
+ store (char const * key,
+ double value);
virtual void
+ store (char const * key,
+ char const * value);
+
+private:
+
+ void
write (std::string const & msg);
+
+ std::string
+ clean (std::string const & txt)
+ const;
};
diff --git a/src/storage.cc b/src/storage.cc
index b4f6cd4..dee2659 100644
--- a/src/storage.cc
+++ b/src/storage.cc
@@ -9,69 +9,24 @@ using namespace std;
storage::
-~ storage ()
+storage (enum state const st)
+ : m_state (st)
{
}
-void storage::
-store (char const * const key,
- int const value)
-{
- assert (key);
-
- ostringstream keybuf;
- keybuf << key;
- ostringstream valuebuf;
- valuebuf << value;
-
- ostringstream buf;
- buf << "<key>" << clean (keybuf.str()) << "</key> "
- << "<value>" << clean (valuebuf.str()) << "</value>\n";
-
- write (buf.str());
-}
-
-
-
-void storage::
-store (char const * const key,
- char const * const value)
+storage::
+~ storage ()
{
- assert (key);
-
- ostringstream keybuf;
- keybuf << key;
- ostringstream valuebuf;
- valuebuf << value;
-
- ostringstream buf;
- buf << "<key>" << clean (keybuf.str()) << "</key> "
- << "<value>" << clean (valuebuf.str()) << "</value>\n";
-
- write (buf.str());
}
-string storage::
-clean (string const & txt)
+enum storage::state storage::
+get_state ()
const
{
- ostringstream buf;
-
- for (string::const_iterator p = txt.begin(); p != txt.end(); ++ p)
- {
- switch (* p)
- {
- case '<': buf << "<langle>"; break;
- case '>': buf << "<rangle>"; break;
-// case '"': buf << "<quote>"; break;
-// case '\\': buf << "<backslash>"; break;
- default: buf << * p;
- }
- }
-
- return buf.str();
+ return m_state;
}
+
diff --git a/src/storage.hh b/src/storage.hh
index ce8a6e7..5728404 100644
--- a/src/storage.hh
+++ b/src/storage.hh
@@ -1,7 +1,5 @@
// $Header$
-
-
#ifndef STORAGE_HH
#define STORAGE_HH
@@ -11,27 +9,37 @@ class storage
{
public:
+ enum state { initial, update, final };
+
+private:
+
+ enum state m_state;
+
+public:
+
+ storage (enum state);
+
virtual
~ storage ();
+ enum state
+ get_state ()
+ const;
+
virtual void
store (char const * key,
- int value);
+ int value)
+ = 0;
virtual void
store (char const * key,
- char const * value);
-
-protected:
+ double value)
+ = 0;
virtual void
- write (std::string const & msg)
+ store (char const * key,
+ char const * value)
= 0;
-
- virtual std::string
- clean (std::string const & txt)
- const;
-
};