Index: Evidence/Config.cc
===================================================================
--- Evidence/Config.cc	(revision 208)
+++ Evidence/Config.cc	(revision 209)
@@ -105,5 +105,5 @@
   if (pthread_mutex_lock(&Mutex) != 0) State(ERROR, "pthread_mutex_lock() failed in rpcHandler()");
 
-  // Search for config data in list
+  // Search for config data in list (default response is empty string)
   for (int i=0; i<List.size(); i++) {
     if (List[i].Name == getString()) Response = List[i].Data;
Index: Evidence/DColl.cc
===================================================================
--- Evidence/DColl.cc	(revision 208)
+++ Evidence/DColl.cc	(revision 209)
@@ -5,10 +5,10 @@
   - DColl subscribes to all services given by the configuration
     server and writes these to the data file at every update.
-  - One data file per day is generated, with roll-over at 13:00 local time.
-  - For each service, it creates a new service with '.hist' appended
-	that contains a history of events kept within a ring buffer. Each
+  - One data file per day is generated.
+  - A history of events is kept within a ring buffer for each service. Each
 	entry will be the result of a conversion to double of the text 
 	written to the data file. Only if the new value has changed by a
-	minimum amout it will be added to the ring buffer.
+	minimum amout it will be added to the ring buffer. The history is
+	available via an rpc call.
   - The history buffers are written to disk at program termination and
     are tired to be read when adding a service.
@@ -16,5 +16,5 @@
     file specified in the configuration.
   
-  Oliver Grimm, December 2009
+  Oliver Grimm, May 2010
 
 \********************************************************************/
@@ -22,5 +22,4 @@
 #define SERVER_NAME "DColl"
 
-#define DATE_ROLLOVER 12 	// localtime hour after which next date is used
 #define MIN_HIST_SIZE 1024	// Minimum history buffer in bytes (> 3*sizeof(int) !)
 
@@ -44,10 +43,9 @@
 // Class declaration
 //
-class DataHandler:	public DimClient, public DimBrowser,
+class DataHandler:	public DimRpc, public DimClient, public DimBrowser,
 					public EvidenceServer {
 
 	struct Item {
 	  DimStampedInfo *DataItem;
-      DimService *HistService;
 	  char *Buffer;
 	  unsigned int HistSize;
@@ -70,5 +68,6 @@
 	int SizeUpdateDelay;
 	int TimeForNextFile;
-	
+	int RollOver;
+
 	int RegExCount;
 	regex_t *RegEx;
@@ -77,9 +76,11 @@
 	
     void infoHandler();
+    void rpcHandler();
     void commandHandler();
 	void AddService(string);
 	void RemoveService(string);
 	float FileSize(FILE *);
-	    
+	FILE *OpenHistFile(string, const char *);
+   
   public:
     DataHandler();
@@ -90,5 +91,5 @@
 // Constructor
 //
-DataHandler::DataHandler(): EvidenceServer(SERVER_NAME) {
+DataHandler::DataHandler(): DimRpc("ServiceHistory", "C", "C"), EvidenceServer(SERVER_NAME) {
 
   // Initialization to prevent freeing unallocated memory 
@@ -108,5 +109,6 @@
   SizeUpdateDelay = atoi(GetConfig("sizeupdate"));
   HistDir = GetConfig("histdir");
-   
+  RollOver = atoi(GetConfig("rollover"));
+
   // Open log file
   char *Logname = GetConfig("logfile");
@@ -127,5 +129,5 @@
   DataFilename = new DimService(SERVER_NAME "/CurrentFile", (char *) "");
 
-  // Count how many minimum change value regular expressions are present
+  // Count how many minimum change regular expressions are present
   char *Change = GetConfig("items");
   RegExCount = 0;
@@ -137,5 +139,5 @@
   
   // Allocate memory for regular expressions, minimum change and history size
-  RegEx = new regex_t[RegExCount];
+  RegEx = new regex_t [RegExCount];
   MinChange = new double [RegExCount];
   HistSize = new unsigned int [RegExCount];
@@ -151,5 +153,7 @@
 	  char ErrMsg[200];
 	  regerror(Ret, &RegEx[i], ErrMsg, sizeof(ErrMsg));
-	  State(FATAL, "Error compiling regular expression '%s' (%s)", Token, ErrMsg);
+	  RegExCount--;
+	  i--;
+	  State(ERROR, "Error compiling regular expression '%s' (%s)", Token, ErrMsg);
 	}
 	else {
@@ -179,6 +183,6 @@
   delete[] Filename;
   
-  //delete LogSizeService; // These create segmentation faults?!
-  //delete DataSizeService;
+  delete LogSizeService;
+  delete DataSizeService;
 
   // Close files
@@ -258,12 +262,12 @@
 	DataFile = NULL;
   }
-  
+
   // Open new data file if necessary
   if (DataFile == NULL) {
 	time_t Time = time(NULL);
 	struct tm *T = localtime(&Time);
-	
+
 	// Get time structure with date rollover
-	if(T->tm_hour >= DATE_ROLLOVER) T->tm_mday++;
+	if (T->tm_hour >= RollOver) T->tm_mday++;
 	if (mktime(T) == -1) State(ERROR, "mktime() failed, check filename");
 
@@ -294,5 +298,5 @@
 	T->tm_sec = 0;
 	T->tm_min = 0;
-	T->tm_hour = DATE_ROLLOVER;
+	T->tm_hour = RollOver;
 	TimeForNextFile = mktime(T);
   }
@@ -460,10 +464,25 @@
 
 //
+// Implementation of history buffer distribution
+//
+void DataHandler::rpcHandler() {
+
+  // Search for history buffer
+  for (int i=0; i<List.size(); i++) {
+    if (strcmp(List[i].DataItem->getName(), getString()) == 0) {
+	  setData((void *) List[i].Buffer, List[i].HistSize);
+	  return;
+	}
+  }
+  
+  // Default response
+  setData(NULL, 0);
+}
+
+
+//
 // Add service to watch list
 //
 void DataHandler::AddService(string Name) {
-
-  // Do not subscribe to history services (otherwise infinite loop)
-  if (Name.find(".hist") != string::npos) return;
 
   // Check if already subscribed to this service
@@ -492,13 +511,9 @@
   New.Next = 4;
   New.LastValue = DBL_MAX;
-  New.HistService = new DimService ((Name+".hist").c_str(), (char *) "C",
-  					  New.Buffer, New.HistSize);
 
   // Load history buffer from file if existing
-  string Filename = New.HistService->getName();
-  for (int j=0; j<Filename.size(); j++) if (Filename[j] == '/') Filename[j] = '_';
-  FILE *File = fopen((HistDir + "/" + Filename).c_str(), "rb");
+  FILE *File = OpenHistFile(Name, "rb");
   if (File != NULL) {
-    // Only load if current buffer size if equal or larger
+    // Only load if current buffer size is equal or larger
     if (FileSize(File) <= New.HistSize*sizeof(char)+sizeof(New.Next) && FileSize(File) != -1) {
       fread(&New.Next, sizeof(New.Next), 1, File);
@@ -527,8 +542,6 @@
 	delete (*E).DataItem;
 
-	// Save history buffer (replace '/' by '_')
-    string Name = (*E).HistService->getName();
-	for (int j=0; j<Name.size(); j++) if (Name[j] == '/') Name[j] = '_';
-    FILE *File = fopen((HistDir + "/" + Name).c_str(), "wb");
+	// Save history buffer
+	FILE *File = OpenHistFile(Name, "wb");
 	if (File != NULL) {
       fwrite(&(*E).Next, sizeof((*E).Next), 1, File);
@@ -538,5 +551,4 @@
 	
 	// Delete history service and free memory
-	delete (*E).HistService;
     delete[] (*E).Buffer;
 	List.erase(E);
@@ -558,4 +570,13 @@
 
   return (float) FileStatus.st_size/1024;
+}
+
+//
+// Replace all '/' by '_' in string
+//
+FILE *DataHandler::OpenHistFile(string Service, const char *Mode) {
+
+  for (int i=0; i<Service.size(); i++) if (Service[i] == '/') Service[i] = '_';
+  return fopen((HistDir + "/" + Service).c_str(), Mode);
 }
 
Index: Evidence/Evidence.cc
===================================================================
--- Evidence/Evidence.cc	(revision 208)
+++ Evidence/Evidence.cc	(revision 209)
@@ -38,4 +38,5 @@
   // Initialize
   Status = NULL;
+  StdOutText = NULL;
   ExitRequest = false;
   ThisServer = this;
@@ -60,4 +61,5 @@
   
   Status = new DimService((ServerName+"/Status").c_str(), (char *) "C", InitMsg, strlen(InitMsg)+1);
+  StdOut = new DimService((ServerName+"/Textout").c_str(), (char *) "");
 
   start(Name);
@@ -74,4 +76,7 @@
   }
   delete ModifyInfo;
+  
+  delete Status;
+  delete StdOut;
 }
 
@@ -126,4 +131,17 @@
   // Terminate if message type is fatal
   if (Severity == FATAL) exit(EXIT_FAILURE);
+}
+
+// Set text of StdOut service
+void EvidenceServer::SetStdOut(char *Text) {
+
+  // Copy text to permanent buffer
+  char *Tmp = new char[strlen(Text)+1];
+  strcpy(Tmp, Text);
+  StdOut->updateService(Tmp);
+
+  // Delete old buffer and save new buffer pointer
+  delete[] StdOutText;
+  StdOutText = Tmp;    
 }
 
@@ -148,11 +166,15 @@
 	break;
   } 
-  
+
   // Make configuration request
-  DimRpcInfo Config((char *) "ConfigRequest", (char *) "");
+  DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
   Config.setData((char *) (ServerName + " " + Item).c_str());
   char *Result = Config.getString();
-  
+
   // Terminate if not successful
+  if (!EvidenceServer::ServiceOK(&Config)) {
+    State(FATAL, "Configuration server unreachable, can't get '%s'", Item.c_str());
+  }
+
   if (strlen(Result) == 0) {
     if (Default == NULL) State(FATAL, "Missing configuration data '%s'", Item.c_str());
@@ -172,5 +194,5 @@
   strcpy(ConfigList[ItemNo].Value, Result);
   ConfigList[ItemNo].Time = ModifyInfo->LastModifyTime;
-    
+
   // Return address to configuration value  
   return ConfigList[ItemNo].Value;
@@ -314,7 +336,11 @@
   return !((Item->getSize() == strlen(NO_LINK)+1) &&  
 	  (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
-
-}
-
+}
+
+bool EvidenceServer::ServiceOK(DimRpcInfo *Item) {
+
+  return !((Item->getSize() == strlen(NO_LINK)+1) &&  
+	  (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
+}
 
 ///////////////////////////
@@ -333,10 +359,7 @@
 
 // Constructor
-EvidenceHistory::EvidenceHistory(std::string Name, int Delay):
-	Name(Name+".hist"),
-	Delay(Delay) {
+EvidenceHistory::EvidenceHistory(std::string Name):	Name(Name) {
 
   Buffer = NULL;
-  LastUpdate = 0;
 }
 
@@ -350,21 +373,13 @@
 bool EvidenceHistory::GetHistory() {
 
-  // Check if last buffer update less than minimum delay in the past 
-  if ((Buffer != NULL) && (time(NULL)-LastUpdate < Delay)) {
-	Offset = *(int *) Buffer;
-	return true;
-  }
-  LastUpdate = time(NULL);
-  
-  // Check if service available
-  DimCurrentInfo Info(Name.c_str(), NO_LINK);
-  if (((Info.getSize() == strlen(NO_LINK)+1) &&  
-	  (memcmp(Info.getData(), NO_LINK, Info.getSize()) == 0))) return false;
+  DimRpcInfo R((char *) "ServiceHistory", NO_LINK);
+  R.setData((char *) Name.c_str());
+  if (!EvidenceServer::ServiceOK(&R)) return false;
 
   delete[] Buffer;
-  BufferSize = Info.getSize();
+  BufferSize = R.getSize();
   Buffer = new char [BufferSize];
 
-  memcpy(Buffer, Info.getData(), BufferSize);
+  memcpy(Buffer, R.getData(), BufferSize);
   Offset = *(int *) Buffer;
   
Index: Evidence/Evidence.h
===================================================================
--- Evidence/Evidence.h	(revision 208)
+++ Evidence/Evidence.h	(revision 209)
@@ -47,10 +47,11 @@
 
 	std::string ServerName;
-    DimService *Status;
+    DimService *Status, *StdOut;
 	class ConfigUpdate *ModifyInfo;
 	
 	char InitMsg[STATUS_SIZE];
 	int LastModifyTime;
-
+	char *StdOutText;
+	
     static void SignalHandler(int); // static for signal()
     static void Terminate();  		// static for set_terminate()
@@ -65,7 +66,9 @@
 
 	void State(StateType, const char *, ...);
+	void SetStdOut(char *);
 	char* GetConfig(std::string, const char * = NULL);
 	static char* ToString(DimInfo *);
 	static bool ServiceOK(DimInfo *);
+	static bool ServiceOK(DimRpcInfo *);
 
     bool ExitRequest;
@@ -81,9 +84,7 @@
   int BufferSize;
   int Offset;
-  int Delay;
-  int LastUpdate;
   
   public:
-	EvidenceHistory(std::string, int = 10);
+	EvidenceHistory(std::string);
 	~EvidenceHistory();
 	
Index: Evidence/readme.txt
===================================================================
--- Evidence/readme.txt	(revision 208)
+++ Evidence/readme.txt	(revision 209)
@@ -21,4 +21,12 @@
 
 - Oliver Grimm, 18/1/2010
+
+Version history
+---------------
+
+19/5/2010	Service histories now available via DimRpc from DColl, not via .hist service
+			When regular expression compiling results in error, State is set to ERROR, not
+			FATAL. The erroneous expression is ignored in the following.
+			
 
 
