Index: main/trunk/greenstone2/runtime-src/src/recpt/Makefile.in
===================================================================
--- main/trunk/greenstone2/runtime-src/src/recpt/Makefile.in	(revision 28759)
+++ main/trunk/greenstone2/runtime-src/src/recpt/Makefile.in	(revision 28760)
@@ -206,4 +206,5 @@
 	extlinkaction.cpp \
 	formattools.cpp \
+	formatconverter.cpp \
 	gtiaction.cpp \
 	highlighttext.cpp \
@@ -284,4 +285,11 @@
 	wizardaction.o 
 
+CONVERTER_OBJECTS = \
+	cgiargs.o \
+	cgiutils.o \
+	formattools.o \
+	formatconverter.o \
+	summarise.o
+
 LIBRARY = gsdlrecpt.a
 
@@ -301,5 +309,8 @@
 
 # Default target: make both gsdlrecpt.a and the library executable
-all: $(LIBRARY) $(EXECUTABLE) $(APACHE_MODULE)
+all: $(LIBRARY) $(EXECUTABLE) $(APACHE_MODULE) formatconverter
+
+formatconverter: $(CONVERTER_OBJECTS)
+	$(CXXLINK) $(CONVERTER_OBJECTS) $(COMMON_DIR)/src/lib/gsdllib.a $(PROTOCOL_DIR)/gsdlprotocol.a $(COLSERVR_DIR)/gsdlcolservr.a
 
 gsdlrecpt.a: $(OBJECTS)
Index: main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp
===================================================================
--- main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp	(revision 28759)
+++ main/trunk/greenstone2/runtime-src/src/recpt/formattools.cpp	(revision 28760)
@@ -49,4 +49,5 @@
 			      ResultDocInfo_t &docinfo, displayclass &disp, 
 			      text_tmap &options, ostream& logout);
+
 static text_t format_text (const text_t& collection, recptproto* collectproto,
 			      ResultDocInfo_t &docinfo, displayclass &disp, 
@@ -58,4 +59,5 @@
 			      ostream &logout);
 
+static text_t transform_to_GS3_format (format_t *formatlistptr);
 
 void metadata_t::clear() {
@@ -127,4 +129,5 @@
 	    (*(here+2) == 'd' || *(here+2) == 'D') &&
 	    (*(here+3) == '>' || *(here+3) == ' '))
+	  //|| *(here+3) == '\t' || *(here+3) == '\n'))
 	  return true;
       } else return false;
@@ -1552,6 +1555,4 @@
 
 
-
-
 static bool uses_expression(const text_t& collection, recptproto* collectproto,
 			    ResultDocInfo_t &docinfo,
@@ -1740,5 +1741,5 @@
     // This is a tad tricky.  When we expand a string like _cgiargmode_, that is
     // a cgi argument macro that has not been set, it evaluates to itself.
-    // Therefore, were have to say that a piece of text evalautes true if
+    // Therefore, we have to say that a piece of text evaluates true if
     // it is non-empty and if it is a cgi argument evaulating to itself.
 
@@ -2057,2 +2058,289 @@
   return summary;
 }
+
+//-------------- GS3 related functions --------------
+// copy of the other uses_expression function, but without using the extra GS2-runtime-specific parameters
+static bool uses_expression(const text_t& outstring, text_t& lhs_expr,
+			    text_t& op_expr, text_t& rhs_expr)
+{
+  // Note: the string may not be of the form: str1 op str2, however
+  // to deterine this we have to process it on the assumption it is,
+  // and if at any point an 'erroneous' value is encountered, return
+  // false and let something else have a go at evaluating it
+
+  // Starting at the end of the string and working backwards ..
+
+  const int outstring_len = outstring.size();
+
+  // skip over white space
+  int rhs_end = rscan_over_whitespace(outstring,outstring_len-1);
+
+  if (rhs_end<=0) { 
+    // no meaningful text or (rhs_end==0) no room for operator
+    return false;
+  }
+
+  // check for ' or " and then scan over token
+  const char potential_quote = outstring[rhs_end];
+  int rhs_start=rhs_end;
+  bool quoted = false;
+
+  if ((potential_quote == '\'') || (potential_quote == '\"')) {
+    --rhs_end;
+    rhs_start = rscan_for(outstring,rhs_end-1,potential_quote) +1;
+    quoted = true;
+  }
+  else {
+    rhs_start = rscan_for_whitespace(outstring,rhs_end-1) +1;
+  }
+
+  if ((rhs_end-rhs_start)<0) {
+    // no meaningful rhs expression
+    return false;
+  }
+
+  // form rhs_expr
+  rhs_expr = extract_substr(outstring,rhs_start,rhs_end);
+
+  // skip over white space
+  const int to_whitespace = (quoted) ? 2 : 1;
+
+  int op_end = rscan_over_whitespace(outstring,rhs_start-to_whitespace);
+  int op_start = rscan_for_whitespace(outstring,op_end-1)+1;
+
+  if ((op_end<0) && (op_start<0)) {
+	// no meaningful expression operator
+    return false;
+  }
+
+  if (op_end-op_start<0) {
+    // no meaningful expression operator
+    return false;
+  }
+
+  op_expr = extract_substr(outstring,op_start,op_end);
+
+
+  // check for operator
+  if ((op_expr != "eq") && (op_expr != "ne") && (op_expr != "gt") &&
+     (op_expr != "ge") && (op_expr != "lt") && (op_expr != "le") && (op_expr != "==") && (op_expr != "!=") &&  (op_expr != ">") && (op_expr != ">=") && (op_expr != "<") && (op_expr != "<=") && (op_expr != "sw") && (op_expr != "ew")) {
+
+    // not a valid operator
+    return false;
+  }
+
+  int lhs_end = rscan_over_whitespace(outstring,op_start-1);
+  if (lhs_end<0) {
+    // no meaningful lhs expression
+    return false;
+  }
+
+  int lhs_start = scan_over_whitespace(outstring,0);
+
+  // form lhs_expr from remainder of string
+  lhs_expr = extract_substr(outstring,lhs_start,lhs_end);
+
+  return true;
+}
+
+// [ex.Title] -> ex.Title
+static text_t remove_bracket_bookends(const text_t &str) {
+  
+  if(str[0] == '[' && str[str.size()-1] == ']') {
+    return substr (str.begin()+1, str.end()-1);
+  } else {
+    return str;
+  }
+}
+
+static text_t get_gs3_if (const decision_t &decision, format_t *ifptr, format_t *elseptr)
+{
+  text_t ifstmt ="<gsf:switch>";
+
+
+  if (decision.command == dMeta) {
+    ifstmt += "<gsf:metadata name=\"";
+    ifstmt += remove_bracket_bookends(decision.meta.metaname);
+    ifstmt += "\"/>"; 
+  }
+
+  else { //if(decision.command == dText) 
+
+    text_t outstring = decision.text;
+
+    // Check for if expression in form: str1 op str2 
+    // (such as [x] eq "y")
+    text_t lhs_expr, op_expr, rhs_expr;
+    if (uses_expression(outstring,lhs_expr,op_expr,rhs_expr)) {
+
+      text_t if_operator = op_expr;
+      if (op_expr == "eq" || op_expr == "==") {
+	if_operator = "equals";
+      } else if (op_expr == "ne" || op_expr == "!=") {
+	if_operator = "notEquals";
+      } else if (op_expr == "gt" || op_expr == ">") {
+	if_operator = "greaterThan";
+      } else if (op_expr == "lt" || op_expr == "<") {
+	if_operator = "lessThan";
+      } else if (op_expr == "ge" || op_expr == ">=") {
+	if_operator = "greaterThanOrEquals";
+      } else if (op_expr == "le" || op_expr == "<=") {
+	if_operator = "lessThanOrEquals";
+      } else if (op_expr == "sw") {
+	if_operator = "startsWith";
+      } else if (op_expr == "ew") {
+	if_operator = "endsWith";
+      }
+
+      ifstmt += "<gsf:metadata name=\"";
+      ifstmt += remove_bracket_bookends(lhs_expr);
+      ifstmt += "\"/>"; 
+
+      ifstmt += "<gsf:when test=\"";
+      ifstmt += if_operator; // the test operator
+      ifstmt += "\" test-value=\"";
+      ifstmt += remove_bracket_bookends(rhs_expr); // the test-value
+      ifstmt += "\">";
+    } 
+    else {
+      ifstmt += "<gsf:metadata name=\"";
+      ifstmt += remove_bracket_bookends(decision.text);
+      ifstmt += "\"/>";
+      ifstmt += "<gsf:when test=\"exists\">";
+    }
+  }
+   
+  // if portion
+  text_t if_body = "";
+  while(ifptr != NULL) { // body of if can contain a list of items to be transformed into GS3 format stmts
+    if_body += transform_to_GS3_format (ifptr);
+    ifptr = ifptr->nextptr;
+  }
+  ifstmt += if_body;
+  ifstmt += "</gsf:when>";
+
+  // else portion
+  if(elseptr != NULL) {
+
+    ifstmt += "<gsf:otherwise>";
+    text_t else_body = ""; // body of else can contain a list of items to be transformed into GS3 format stmts
+    while(elseptr != NULL) {
+      else_body += transform_to_GS3_format (elseptr);
+      elseptr = elseptr->nextptr;
+    }
+    ifstmt += else_body;
+    ifstmt += "</gsf:otherwise>";
+  }  
+
+  ifstmt += "</gsf:switch>";
+  return ifstmt;
+}
+
+
+static text_t get_gs3_or (format_t *orptr) {
+  text_t result = "<gsf:choose-metadata>";
+
+  while(orptr != NULL) {
+    text_t or_body = transform_to_GS3_format (orptr);
+    if (!or_body.empty()) {
+      result += or_body;
+    }
+
+    orptr = orptr->nextptr;    
+  }
+  result += "</gsf:choose-metadata>";
+  return result;
+}
+
+// what about all the <td>? Does that get stored in formatlistptr, such as under the ->text field?
+text_t get_GS3_formatstring (format_t *formatlistptr) {
+  text_t result;
+
+  while (formatlistptr != NULL) {
+    result += transform_to_GS3_format(formatlistptr);    
+    formatlistptr = formatlistptr->nextptr;
+  }
+  
+  return result;
+}
+
+text_t transform_to_GS3_format (format_t *formatlistptr) {
+
+  if (formatlistptr == NULL) return "";
+  
+  switch (formatlistptr->command) {
+  case comOID:
+    return "<gsf:OID/>";
+  case comTopOID:
+    return "<gsf:metadata name='OID' select='root' />"; // for now try this
+  case comRank:
+    return "<gsf:rank/>";
+  case comText:
+    return formatlistptr->text; // [text]? or any string that is not a command or reserved
+  case comLink:
+    return "<gsf:link type='document'>"; // type?
+  case comEndLink:
+    return "</gsf:link>";
+  case comHref:
+    return "<gsf:lib name=\"href\"/>"; // ??? in gslib xsl, output comment marking not sure what this maps to
+  case comIcon:
+    return "<gsf:icon type='document'/>";
+  case comNum:
+    return "<gsf:lib name=\"num\"/>"; // ??? in gslib xsl, output comment marking not sure what this maps to
+  case comRel: //if [RelatedDocuments] appears in format string, collect relation data
+    return "<gsf:lib name=\"RelatedDocuments\"/>"; // output comment marking this as deprecated or to be implemented for GS3 in gslib xslt
+  case comSummary:
+    return "<gsf:lib name=\"Summary\"/>"; // in gslib xslt output comment marking this as to be implemented for GS3 
+    // need to invent this for GS3 based on what GS2 does
+  case comAssocLink:
+    return "<gsf:link type='source'>";
+  case comEndAssocLink:
+    return "</gsf:link>";
+  case comMeta:
+    return "<gsf:metadata name=\"" + formatlistptr->meta.metaname + "\" />";//?
+  case comDoc:
+    return "<gsf:text/>";
+  case comImage: // the cover img seems to be handled by some magic code in GS3
+    return "<gsf:lib name=\"image\"/>"; // in gslib xslt output a comment marking this as not working in the same way in GS3 as in GS2. TOC currently not relocatable
+  case comTOC:
+    return "<gsf:lib name=\"TOC\"/>"; // in gslib xslt output a comment marking this as not working in the same way in GS3 as in GS2. TOC currently not relocatable
+    // need to think about whether an equivalent actually exists
+    // return "<gsf:option name=\"TOC\" value=\"true\"/>"; // this is wrong
+  case comDocumentButtonDetach:
+    return "<gsf:lib name=\"DocumentButtonDetach\"/>"; // output comment marking this as deprecated in gslib xslt
+  case comDocumentButtonHighlight:
+    return "<gsf:lib name=\"DocumentButtonHighlight\"/>"; // output comment marking this as deprecated in gslib xslt
+  case comDocumentButtonExpandContents:
+    return "<gsf:lib name=\"DocumentButtonExpandContents\"/>"; // output comment marking this as deprecated in gslib xslt
+  case comDocumentButtonExpandText:
+    return "<gsf:lib name=\"DocumentButtonExpandText\"/>"; // output comment marking this as deprecated in gslib xslt
+  case comHighlight:
+    return "<span class=\"highlight\">";
+    break;
+  case comEndHighlight:
+    return "</span>";
+    break;
+  case comMetadataSpanWrap:
+    metadata_wrap=true;  metadata_wrap_type="span"; return "";
+    break;
+  case comEndMetadataSpanWrap:
+    metadata_wrap=false; metadata_wrap_type="";     return "";
+    break;
+  case comMetadataDivWrap:
+    metadata_wrap=true;  metadata_wrap_type="div";  return "";
+    break;
+  case comEndMetadataDivWrap:
+    metadata_wrap=false; metadata_wrap_type="";     return "";
+    break;
+  case comIf:
+    return get_gs3_if (formatlistptr->decision, formatlistptr->ifptr, formatlistptr->elseptr);
+  case comOr:
+    return get_gs3_or (formatlistptr->orptr);
+    //return "<gsf:choose-metadata>"+get_gs3_or (formatlistptr->orptr)+"</gsf:choose-metadata>";
+  case comDocTermsFreqTotal:
+    return "<gsf:lib name=\"DocTermsFreqTotal\"/>";
+  case comCollection: // trying to get all the metadata for a collection. How is this done in GS3???
+    return "<gsf:lib name=\"collection\"/>";
+  }
+  return "";
+}
Index: main/trunk/greenstone2/runtime-src/src/recpt/formattools.h
===================================================================
--- main/trunk/greenstone2/runtime-src/src/recpt/formattools.h	(revision 28759)
+++ main/trunk/greenstone2/runtime-src/src/recpt/formattools.h	(revision 28760)
@@ -148,4 +148,6 @@
 			     ostream& logout);
 
+text_t get_GS3_formatstring (format_t *formatlistptr);
+
 #endif
 
