Index: main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp
===================================================================
--- main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp	(revision 21747)
+++ main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp	(revision 21752)
@@ -462,15 +462,82 @@
 
 
+static void get_truncate_options (text_t &instring, metadata_t &metaoption)
+{
+  assert (instring.size() > ((text_t) "truncate").size());
+  if (instring.size() <= ((text_t) "truncate").size()) return;
+  text_t meta, com;
+  bool inbraces = false;
+  bool foundcolon = false;
+  text_t::const_iterator here = instring.begin() + ((text_t) "truncate").size();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (foundcolon) meta.push_back (*here);
+    else if (*here == '(') inbraces = true;
+    else if (*here == ')') inbraces = false;
+    else if (*here == ':' && !inbraces) foundcolon = true;    
+    else com.push_back (*here);
+    ++here;
+  }
+
+  instring = meta;
+
+  if (!com.empty())
+  {
+    metaoption.siblingoptions = com;
+  }
+  else
+  {
+    // Default is 100 characters if not specified
+    metaoption.siblingoptions = "100";
+  }
+}
+
+
 
 static void parse_meta (text_t &meta, metadata_t &metaoption,
 			text_tset &metadata, bool &getParents) {
 
-  if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
-    metaoption.metacommand |= mCgiSafe;
-    meta = substr (meta.begin()+8, meta.end());
-  }
-  if (meta.size() > 7 && (substr(meta.begin(), meta.begin()+7) == "format:")) {    
-    metaoption.metacommand |= mSpecial;
-    meta = substr (meta.begin()+7, meta.end());
+  // Look for the various format statement modifiers
+  // This needs to be done in a loop otherwise not all combinations will be accepted, but actually the order
+  //   is irrelevant because this is not stored in metaoption.metacommand anyway
+  bool keep_trying = true;
+  while (keep_trying)
+  {
+    keep_trying = false;
+
+    if (meta.size() > ((text_t) "cgisafe:").size() && starts_with(meta, "cgisafe:"))
+    {
+      metaoption.metacommand |= mCgiSafe;
+      meta = substr(meta.begin() + ((text_t) "cgisafe:").size(), meta.end());
+      keep_trying = true;
+    }
+    if (meta.size() > ((text_t) "format:").size() && starts_with(meta, "format:"))
+    {    
+      metaoption.metacommand |= mSpecial;
+      meta = substr(meta.begin() + ((text_t) "format:").size(), meta.end());
+      keep_trying = true;
+    }
+
+    // New "truncate" special formatting option
+    if (meta.size() > ((text_t) "truncate").size() && starts_with(meta, "truncate"))  // No colons due to truncate(X)
+    {
+      metaoption.metacommand |= mTruncate;
+      get_truncate_options (meta, metaoption);
+      keep_trying = true;
+    }
+    // New "htmlsafe" special formatting option
+    if (meta.size() > ((text_t) "htmlsafe:").size() && starts_with(meta, "htmlsafe:"))
+    {
+      metaoption.metacommand |= mHTMLSafe;
+      meta = substr(meta.begin() + ((text_t) "htmlsafe:").size(), meta.end());
+      keep_trying = true;
+    }
+    // New "xmlsafe" special formatting option
+    if (meta.size() > ((text_t) "xmlsafe:").size() && starts_with(meta, "xmlsafe:"))
+    {
+      metaoption.metacommand |= mXMLSafe;
+      meta = substr(meta.begin() + ((text_t) "xmlsafe:").size(), meta.end());
+      keep_trying = true;
+    }
   }
 
@@ -937,4 +1004,49 @@
       else fresh_metatext = metainfo.values[i];
 
+      // New "truncate" special formatting option
+      if (meta.metacommand & mTruncate)
+      {
+	int truncate_length = meta.siblingoptions.getint();
+	text_t truncated_value = fresh_metatext;
+	if (truncated_value.size() > truncate_length)
+	{
+	  truncated_value = substr(truncated_value.begin(), truncated_value.begin() + truncate_length) + "... _texttruncated_";
+	}
+	fresh_metatext = truncated_value;
+      }
+      // New "xmlsafe" special formatting option
+      if (meta.metacommand & mXMLSafe)
+      {
+	// Make it XML-safe
+	text_t text_xml_safe = "";
+	text_t::const_iterator text_iterator = fresh_metatext.begin();
+	while (text_iterator != fresh_metatext.end())
+	{
+	  if (*text_iterator == '&') text_xml_safe += "&amp;";
+	  else if (*text_iterator == '<') text_xml_safe += "&lt;";
+	  else if (*text_iterator == '>') text_xml_safe += "&gt;";
+	  else text_xml_safe.push_back(*text_iterator);
+	  text_iterator++;
+	}
+	fresh_metatext = text_xml_safe;
+      }
+      // New "htmlsafe" special formatting option
+      if (meta.metacommand & mHTMLSafe)
+      {
+	// Make it HTML-safe
+	text_t text_html_safe = "";
+	text_t::const_iterator text_iterator = fresh_metatext.begin();
+	while (text_iterator != fresh_metatext.end())
+	{
+	  if (*text_iterator == '&') text_html_safe += "&amp;";
+	  else if (*text_iterator == '<') text_html_safe += "&lt;";
+	  else if (*text_iterator == '>') text_html_safe += "&gt;";
+	  else if (*text_iterator == '"') text_html_safe += "&quot;";
+	  else text_html_safe.push_back(*text_iterator);
+	  text_iterator++;
+	}
+	fresh_metatext = text_html_safe;
+      }
+
       if (metadata_spanwrap) {
 	fresh_metatext = spanwrap_metatext(fresh_metatext,OID,meta.metaname,i);
@@ -961,4 +1073,49 @@
     } 
     else fresh_metatext = metainfo.values[position];
+
+    // New "truncate" special formatting option
+    if (meta.metacommand & mTruncate)
+    {
+      int truncate_length = meta.siblingoptions.getint();
+      text_t truncated_value = fresh_metatext;
+      if (truncated_value.size() > truncate_length)
+      {
+	truncated_value = substr(truncated_value.begin(), truncated_value.begin() + truncate_length) + "... _texttruncated_";
+      }
+      fresh_metatext = truncated_value;
+    }
+    // New "xmlsafe" special formatting option
+    if (meta.metacommand & mXMLSafe)
+    {
+      // Make it XML-safe
+      text_t text_xml_safe = "";
+      text_t::const_iterator text_iterator = fresh_metatext.begin();
+      while (text_iterator != fresh_metatext.end())
+      {
+	if (*text_iterator == '&') text_xml_safe += "&amp;";
+	else if (*text_iterator == '<') text_xml_safe += "&lt;";
+	else if (*text_iterator == '>') text_xml_safe += "&gt;";
+	else text_xml_safe.push_back(*text_iterator);
+	text_iterator++;
+      }
+      fresh_metatext = text_xml_safe;
+    }
+    // New "htmlsafe" special formatting option
+    if (meta.metacommand & mHTMLSafe)
+    {
+      // Make it HTML-safe
+      text_t text_html_safe = "";
+      text_t::const_iterator text_iterator = fresh_metatext.begin();
+      while (text_iterator != fresh_metatext.end())
+      {
+	if (*text_iterator == '&') text_html_safe += "&amp;";
+	else if (*text_iterator == '<') text_html_safe += "&lt;";
+	else if (*text_iterator == '>') text_html_safe += "&gt;";
+	else if (*text_iterator == '"') text_html_safe += "&quot;";
+	else text_html_safe.push_back(*text_iterator);
+	text_iterator++;
+      }
+      fresh_metatext = text_html_safe;
+    }
 
     if (metadata_spanwrap) {
Index: main/trunk/greenstone2/runtime-src/src/recpt/formattools.h
===================================================================
--- main/trunk/greenstone2/runtime-src/src/recpt/formattools.h	(revision 21747)
+++ main/trunk/greenstone2/runtime-src/src/recpt/formattools.h	(revision 21752)
@@ -40,5 +40,5 @@
 		comCollection, comDocTermsFreqTotal};
 
-enum mcommand_t {mNone=0, mCgiSafe=1, mParent=2, mSibling=4, mChild=8, mSpecial=16};
+enum mcommand_t {mNone=0, mCgiSafe=1, mParent=2, mSibling=4, mChild=8, mSpecial=16, mTruncate=32, mXMLSafe=64, mHTMLSafe=128};
 
 enum pcommand_t {pNone, pImmediate, pTop, pAll};
