Changeset 7389


Ignore:
Timestamp:
2004-05-24T16:45:38+12:00 (20 years ago)
Author:
davidb
Message:

Format statment 'if' syntax extended to support operators such as
'eq' and 'ne'. Can now say things like: {If}{[format] eq 'ab cd',X,Y}
Two main changes in code. The first is where the text of the text-condition
of the if statement is handled. This now needs to be parsed, to ensure
any metadata present it recorded, so when 'docinfo' is setup the necessary
metadata is there. The second change is that, when the test condition
of the if statement is evaluated, it is parsed 'on the fly' to look
for the precence of an operator such as 'eq' or 'ne' (in fact these are
currently the only ones implemented; others, such as 'gt' for greater
than etc would be straightforward to add). If there is an operator
detected, the the left and right hand sides of the expression are
determined (any metadata looked up) and the operator applied.

Location:
trunk/gsdl/src/recpt
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/gsdl/src/recpt/formattools.cpp

    r7266 r7389  
    777777      // Decision is a piece of text (probably a macro like _cgiargmode_).
    778778      else {
     779
     780        // hunt for any metadata in string, which might be uses in
     781        // to test a condition, e.g. [Format] eq 'PDF'
     782        format_t* dummyformat = new format_t();
     783        // update which metadata fields needed
     784        // (not interested in updatng formatlistptr)
     785        parse_string (text, dummyformat, metadata, getParents);
     786        delete dummyformat;
     787
    779788        formatlistptr->decision.command = dText;
    780789        formatlistptr->decision.text = text;
     
    976985}
    977986
     987static bool char_is_whitespace(const char c)
     988{
     989  return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
     990
     991}
     992
     993static int scan_over_whitespace(const text_t& outstring, const int start_pos)
     994{
     995  int pos = start_pos;
     996  while (pos<outstring.size()) {
     997    if (!char_is_whitespace(outstring[pos])) {
     998      break;
     999    }
     1000    pos++;
     1001  }
     1002
     1003  return pos;
     1004}
     1005
     1006static int rscan_over_whitespace(const text_t& outstring, const int start_pos)
     1007{
     1008  int pos = start_pos;
     1009  while (pos>=0) {
     1010    if (!char_is_whitespace(outstring[pos])) {
     1011      break;
     1012    }
     1013    pos--;
     1014  }
     1015
     1016  return pos;
     1017}
     1018
     1019static int rscan_for_whitespace(const text_t& outstring, const int start_pos)
     1020{
     1021  int pos = start_pos;
     1022  while (pos>=0) {
     1023    if (char_is_whitespace(outstring[pos])) {
     1024      break;
     1025    }
     1026    pos--;
     1027  }
     1028
     1029  return pos;
     1030}
     1031
     1032
     1033static int rscan_for(const text_t& outstring, const int start_pos,
     1034             const char find_c)
     1035{
     1036  int pos = start_pos;
     1037  while (pos>=0) {
     1038    char c = outstring[pos];
     1039    if (outstring[pos] == find_c) {
     1040      break;
     1041    }
     1042    pos--;
     1043  }
     1044
     1045  return pos;
     1046}
     1047
     1048text_t extract_substr(const text_t& outstring, const int start_pos,
     1049              const int end_pos)
     1050{
     1051  text_t extracted_str;
     1052  extracted_str.clear();
     1053
     1054  for (int pos=start_pos; pos<=end_pos; pos++) {
     1055    extracted_str.push_back(outstring[pos]);
     1056  }
     1057
     1058  return extracted_str;
     1059}
     1060
     1061
     1062static text_t expand_potential_metadata(ResultDocInfo_t &docinfo,
     1063                    const text_t& intext)
     1064{
     1065  text_t outtext;
     1066
     1067  // decide if dealing with metadata or text
     1068
     1069  text_t::const_iterator beginbracket = intext.begin();
     1070  text_t::const_iterator endbracket = (intext.end() - 1);
     1071
     1072  // Decision is based on a metadata element
     1073  if ((*beginbracket == '[') && (*endbracket == ']')) {
     1074    // Ignore the surrounding square brackets
     1075    text_t meta_text = substr (beginbracket+1, endbracket);
     1076
     1077    metadata_t meta;
     1078    meta.metaname = meta_text;
     1079    meta.parentcommand = pNone;
     1080    meta.metacommand = mSibling;
     1081
     1082    bool getParents =false;
     1083    outtext = get_meta (docinfo,meta);
     1084  }
     1085  else {
     1086    outtext = intext;
     1087  }
     1088
     1089  return outtext;
     1090}
     1091
     1092
     1093
     1094
     1095static bool uses_expression(ResultDocInfo_t &docinfo,
     1096                const text_t& outstring, text_t& lhs_expr,
     1097                text_t& op_expr, text_t& rhs_expr)
     1098{
     1099  // Note: the string may not be of the form: str1 op str2, however
     1100  // to deterine this we have to process it on the assumption it is,
     1101  // and if at any point an 'erroneous' value is encountered, return
     1102  // false and let something else have a go at evaluating it
     1103
     1104  // Starting at the end of the string and working backwards ..
     1105
     1106  const int outstring_len = outstring.size();
     1107
     1108  // skip over white space
     1109  int rhs_end = rscan_over_whitespace(outstring,outstring_len-1);
     1110
     1111  if (rhs_end<=0) {
     1112    // no meaningful text or (rhs_end==0) no room for operator
     1113    return false;
     1114  }
     1115
     1116  // check for ' or " and then scan over token
     1117  const char potential_quote = outstring[rhs_end];
     1118  int rhs_start=rhs_end;
     1119  bool quoted = false;
     1120
     1121  if ((potential_quote == '\'') || (potential_quote == '\"')) {
     1122    rhs_end--;
     1123    rhs_start = rscan_for(outstring,rhs_end-1,potential_quote) +1;
     1124    quoted = true;
     1125  }
     1126  else {
     1127    rhs_start = rscan_for_whitespace(outstring,rhs_end-1) +1;
     1128  }
     1129
     1130  if ((rhs_end-rhs_start)<=0) {
     1131    // no meaningful rhs expression
     1132    return false;
     1133  }
     1134
     1135  // form rhs_expr
     1136  rhs_expr = extract_substr(outstring,rhs_start,rhs_end);
     1137
     1138  // skip over white space
     1139
     1140  const int to_whitespace = (quoted) ? 2 : 1;
     1141
     1142  int op_end = rscan_over_whitespace(outstring,rhs_start-to_whitespace);
     1143  int op_start = rscan_for_whitespace(outstring,op_end-1)+1;
     1144
     1145
     1146  if (op_end-op_start<=0) {
     1147    // no meaningful expression operator
     1148    return false;
     1149  }
     1150
     1151  op_expr = extract_substr(outstring,op_start,op_end);
     1152
     1153
     1154  // check for operator
     1155  if ((op_expr != "eq") && (op_expr != "ne")) {
     1156    // not a valid operator
     1157    return false;
     1158  }
     1159
     1160  int lhs_end = rscan_over_whitespace(outstring,op_start-1);
     1161  if (lhs_end<=0) {
     1162    // no meaningful lhs expression
     1163    return false;
     1164  }
     1165
     1166  int lhs_start = scan_over_whitespace(outstring,0);
     1167
     1168  // form lhs_expr from remainder of string
     1169  lhs_expr = extract_substr(outstring,lhs_start,lhs_end);
     1170
     1171  // Now we know we have a valid expression, look up any
     1172  // metadata terms
     1173
     1174  rhs_expr = expand_potential_metadata(docinfo,rhs_expr);
     1175  lhs_expr = expand_potential_metadata(docinfo,lhs_expr);
     1176
     1177  return true;
     1178}
     1179
     1180static bool eval_expression_true(const text_t& lhs_expr,const text_t& op_expr,
     1181                 const text_t& rhs_expr, ostream& logout)
     1182{
     1183  if (op_expr == "eq") {
     1184    return (lhs_expr == rhs_expr);
     1185  }
     1186  else if (op_expr == "ne" ) {
     1187    return (lhs_expr != rhs_expr);
     1188  }
     1189  else {
     1190    logout << "Error: '" << op_expr << "' is not a recognised operator." << endl;
     1191  }
     1192
     1193  return false;
     1194}
     1195
     1196
    9781197static text_t get_if (const text_t& collection, recptproto* collectproto,
    9791198              ResultDocInfo_t &docinfo, displayclass &disp,
     
    9821201              text_tmap &options, ostream& logout)
    9831202{
    984 
    9851203  // If the decision component is a metadata element, then evaluate it
    9861204  // to see whether we output the "then" or the "else" clause
     
    10051223    disp.expandstring (decision.text, outstring);
    10061224
     1225    // Check for if expression in form: str1 op str2
     1226    // (such as [x] eq "y")
     1227    text_t lhs_expr, op_expr, rhs_expr;
     1228    if (uses_expression(docinfo, outstring,lhs_expr,op_expr,rhs_expr)) {
     1229      if (eval_expression_true(lhs_expr,op_expr,rhs_expr,logout)) {
     1230    if (ifptr != NULL) {
     1231      return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
     1232                       options, logout);
     1233    }
     1234    else {
     1235      return "";
     1236    }
     1237      } else {
     1238    if (elseptr != NULL) {
     1239      return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
     1240                       options, logout);
     1241    }
     1242    else {
     1243      return "";
     1244    }
     1245      }
     1246    }
     1247
     1248
    10071249    // This is a tad tricky.  When we expand a string like _cgiargmode_, that is
    10081250    // a cgi argument macro that has not been set, it evaluates to itself.
    10091251    // Therefore, were have to say that a piece of text evalautes true if
    10101252    // it is non-empty and if it is a cgi argument evaulating to itself.
     1253
    10111254    if ((outstring != "") && !((outstring == decision.text) && (outstring[0] == '_'))) {
    10121255      if (ifptr != NULL)
  • trunk/gsdl/src/recpt/formattools.h

    r6710 r7389  
    5353
    5454// The decision component of an {If}{decision,true-text,false-text}
    55 // formatstring.  Te decision can be based on metadata or on text;
     55// formatstring.  The decision can be based on metadata or on text;
    5656// normally that text would be a macro like _cgiargmode_.  --gordon
    5757struct decision_t {
Note: See TracChangeset for help on using the changeset viewer.