source: main/tags/2.80/gsdl/src/recpt/formattools.cpp@ 24528

Last change on this file since 24528 was 13457, checked in by kjdon, 17 years ago

cgi_safe method renamed to cgi_safe_unicode, see comment in cgiutils

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 46.8 KB
Line 
1/**********************************************************************
2 *
3 * formattools.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "formattools.h"
27#include "cgiutils.h"
28#include "OIDtools.h"
29#include "summarise.h"
30
31#include <assert.h>
32
33// a few function prototypes
34
35static text_t format_string (const text_t& collection, recptproto* collectproto,
36 ResultDocInfo_t &docinfo, displayclass &disp,
37 format_t *formatlistptr, text_tmap &options,
38 ostream& logout);
39
40static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
41 format_t *formatlistptr, text_tset &metadata, bool &getParents);
42
43static text_t format_summary (const text_t& collection, recptproto* collectproto,
44 ResultDocInfo_t &docinfo, displayclass &disp,
45 text_tmap &options, ostream& logout);
46static text_t format_text (const text_t& collection, recptproto* collectproto,
47 ResultDocInfo_t &docinfo, displayclass &disp,
48 text_tmap &options, ostream& logout);
49
50static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
51 recptproto* collectproto, ResultDocInfo_t &docinfo,
52 displayclass &disp, text_tmap &options,
53 ostream &logout);
54
55
56void metadata_t::clear() {
57 metaname.clear();
58 metacommand = mNone;
59 mqualifier.parent = pNone;
60 mqualifier.sibling = sNone;
61 mqualifier.child = cNone;
62 parentoptions.clear();
63 siblingoptions.clear();
64 childoptions.clear();
65}
66
67void decision_t::clear() {
68 command = dMeta;
69 meta.clear();
70 text.clear();
71}
72
73void format_t::clear() {
74 command = comText;
75 decision.clear();
76 text.clear();
77 meta.clear();
78 nextptr = NULL;
79 ifptr = NULL;
80 elseptr = NULL;
81 orptr = NULL;
82}
83
84void formatinfo_t::clear() {
85 DocumentImages = false;
86 DocumentTitles = true;
87 DocumentHeading = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
88 DocumentContents = true;
89 DocumentArrowsBottom = true;
90 DocumentArrowsTop = false;
91 DocumentSearchResultLinks = false;
92 DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
93 // DocumentButtons.push_back ("Expand Text");
94 // DocumentButtons.push_back ("Expand Contents");
95 DocumentButtons.push_back ("Detach");
96 DocumentButtons.push_back ("Highlight");
97 RelatedDocuments = "";
98 DocumentText = "[Text]";
99 formatstrings.erase (formatstrings.begin(), formatstrings.end());
100 DocumentUseHTML = false;
101 AllowExtendedOptions = false;
102}
103
104// simply checks to see if formatstring begins with a <td> tag
105bool is_table_content (const text_t &formatstring) {
106 text_t::const_iterator here = formatstring.begin();
107 text_t::const_iterator end = formatstring.end();
108
109 while (here != end) {
110 if (*here != ' ') {
111 if ((*here == '<') && ((here+3) < end)) {
112 if ((*(here+1) == 't' || *(here+1) == 'T') &&
113 (*(here+2) == 'd' || *(here+2) == 'D') &&
114 (*(here+3) == '>' || *(here+3) == ' '))
115 return true;
116 } else return false;
117 }
118 ++here;
119 }
120 return false;
121}
122
123bool is_table_content (const format_t *formatlistptr) {
124
125 if (formatlistptr == NULL) return false;
126
127 if (formatlistptr->command == comText)
128 return is_table_content (formatlistptr->text);
129
130 return false;
131}
132
133// returns false if key isn't in formatstringmap
134bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
135 text_t &formatstring) {
136
137 formatstring.clear();
138 text_tmap::const_iterator it = formatstringmap.find(key);
139 if (it == formatstringmap.end()) return false;
140 formatstring = (*it).second;
141 return true;
142}
143
144// tries to find "key1key2" then "key1" then "key2"
145bool get_formatstring (const text_t &key1, const text_t &key2,
146 const text_tmap &formatstringmap,
147 text_t &formatstring) {
148
149 formatstring.clear();
150 text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
151 if (it != formatstringmap.end()) {
152 formatstring = (*it).second;
153 return true;
154 }
155 it = formatstringmap.find(key1);
156 if (it != formatstringmap.end()) {
157 formatstring = (*it).second;
158 return true;
159 }
160 it = formatstringmap.find(key2);
161 if (it != formatstringmap.end()) {
162 formatstring = (*it).second;
163 return true;
164 }
165 return false;
166}
167
168
169text_t remove_namespace(const text_t &meta_name) {
170 text_t::const_iterator end = meta_name.end();
171 text_t::const_iterator it = findchar(meta_name.begin(), end, '.');
172 if (it != end) {
173 return substr(it+1, end);
174 }
175
176 return meta_name;
177
178}
179// returns a date of form _format:date_(year, month, day)
180// input is date of type yyyy-?mm-?dd
181// at least the year must be present in date
182text_t format_date (const text_t &date) {
183
184 if (date.size() < 4) return "";
185
186 text_t::const_iterator datebegin = date.begin();
187
188 text_t year = substr (datebegin, datebegin+4);
189 int chars_seen_so_far = 4;
190
191 if (date[chars_seen_so_far] == '-') ++chars_seen_so_far ;
192 if (date.size() < chars_seen_so_far+2) return "_format:date_("+year+")";
193
194 text_t month = substr (datebegin+chars_seen_so_far, datebegin+chars_seen_so_far+2);
195 int imonth = month.getint();
196 if (imonth <= 0 || imonth > 12) return "_format:date_("+year+")";
197
198 chars_seen_so_far += 2;
199 if (date[chars_seen_so_far] == '-') ++chars_seen_so_far ;
200
201 if (date.size() < chars_seen_so_far+2) return "_format:date_("+year+","+month+")";
202
203 text_t day = substr (datebegin+chars_seen_so_far, datebegin+chars_seen_so_far+2);
204 if (day[0] == '0') day = substr (day.begin()+1, day.end());
205 int iday = day.getint();
206 if (iday <= 0 || iday > 31) return "_format:date_("+year+","+month+")";
207
208 return "_format:date_("+year+","+month+","+day+")";
209}
210
211// converts an iso639 language code to its English equivalent
212// should we be checking that the macro exists??
213text_t iso639 (const text_t &langcode) {
214 if (langcode.empty()) return "";
215 return "_iso639:iso639"+langcode+"_";
216}
217
218
219text_t get_href (const text_t &link) {
220
221 text_t href;
222
223 text_t::const_iterator here = findchar(link.begin(), link.end(), '"');
224 text_t::const_iterator end = link.end();
225 if (here == end) return g_EmptyText;
226
227 ++here;
228 while (here != end) {
229 if (*here == '"') break;
230 href.push_back(*here);
231 ++here;
232 }
233
234 return href;
235}
236
237//this function gets the information associated with the relation
238//metadata for the document associated with 'docinfo'. This relation
239//metadata consists of a line of pairs containing 'collection, document OID'
240//(this is the OID of the document related to the current document, and
241//the collection the related document belongs to). For each of these pairs
242//the title metadata is obtained and then an html link between the title
243//of the related doc and the document's position (the document will be
244//found in "<a href=\"_httpdocument_&c=collection&cl=search&d=OID">
245//(where collection is the related documents collection, and OID is the
246//related documents OID). A list of these html links are made for as many
247//related documents as there are. This list is then returned. If there are
248//no related documents available for the current document then the string
249//'.. no related documents .. ' is returned.
250text_t get_related_docs(const text_t& collection, recptproto* collectproto,
251 ResultDocInfo_t &docinfo, ostream& logout){
252
253 text_tset metadata;
254
255 //insert the metadata we wish to collect
256 metadata.insert("dc.Relation");
257 metadata.insert("Title");
258 metadata.insert("Subject"); //for emails, where title data doesn't apply
259
260 FilterResponse_t response;
261 text_t relation = ""; //string for displaying relation metadata
262 text_t relationTitle = ""; //the related documents Title (or subject)
263 text_t relationOID = ""; //the related documents OID
264
265 //get the information associated with the metadata for current doc
266 if (get_info (docinfo.OID, collection, "", metadata,
267 false, collectproto, response, logout)) {
268
269 //if the relation metadata exists, store for displaying
270 if(!response.docInfo[0].metadata["dc.Relation"].values.empty()){
271 relationOID += response.docInfo[0].metadata["dc.Relation"].values[0];
272
273 //split relation data into pairs of collectionname,ID number
274 text_tarray relationpairs;
275 splitchar (relationOID.begin(), relationOID.end(), ' ', relationpairs);
276
277 text_tarray::const_iterator currDoc = relationpairs.begin();
278 text_tarray::const_iterator lastDoc = relationpairs.end();
279
280 //iterate through the pairs to split and display
281 while(currDoc != lastDoc){
282
283 //split pairs into collectionname and ID
284 text_tarray relationdata;
285 splitchar ((*currDoc).begin(), (*currDoc).end(), ',', relationdata);
286
287 //get first element in the array (collection)
288 text_tarray::const_iterator doc_data = relationdata.begin();
289 text_t document_collection = *doc_data;
290 ++doc_data; //increment to get next item in array (oid)
291 text_t document_OID = *doc_data;
292
293 //create html link to related document
294 relation += "<a href=\"_httpdocument_&c=" + document_collection;
295 relation += "&cl=search&d=" + document_OID;
296
297 //get the information associated with the metadata for related doc
298 if (get_info (document_OID, document_collection, "", metadata,
299 false, collectproto, response, logout)) {
300
301 //if title metadata doesn't exist, collect subject metadata
302 //if that doesn't exist, just call it 'related document'
303 if (!response.docInfo[0].metadata["Title"].values[0].empty())
304 relationTitle = response.docInfo[0].metadata["Title"].values[0];
305 else if (!response.docInfo[0].metadata["Subject"].values.empty())
306 relationTitle = response.docInfo[0].metadata["Subject"].values[0];
307 else relationTitle = "RELATED DOCUMENT";
308
309 }
310
311 //link the related document's title to its page
312 relation += "\">" + relationTitle + "</a>";
313 relation += " (" + document_collection + ")<br>";
314
315 ++currDoc;
316 }
317 }
318
319 }
320
321 if(relation.empty()) //no relation data for documnet
322 relation = ".. no related documents .. ";
323
324 return relation;
325}
326
327
328
329static void get_parent_options (text_t &instring, metadata_t &metaoption) {
330
331 assert (instring.size() > 7);
332 if (instring.size() <= 7) return;
333
334 text_t meta, com, op;
335 bool inbraces = false;
336 bool inquotes = false;
337 bool foundcolon = false;
338 text_t::const_iterator here = instring.begin()+6;
339 text_t::const_iterator end = instring.end();
340 while (here != end) {
341 if (foundcolon) meta.push_back (*here);
342 else if (*here == '(') inbraces = true;
343 else if (*here == ')') inbraces = false;
344 else if (*here == '\'' && !inquotes) inquotes = true;
345 else if (*here == '\'' && inquotes) inquotes = false;
346 else if (*here == ':' && !inbraces) foundcolon = true;
347 else if (inquotes) op.push_back (*here);
348 else com.push_back (*here);
349 ++here;
350 }
351
352 instring = meta;
353 if (com.empty())
354 metaoption.mqualifier.parent = pImmediate;
355 else if (com == "Top")
356 metaoption.mqualifier.parent = pTop;
357 else if (com == "All") {
358 metaoption.mqualifier.parent = pAll;
359 metaoption.parentoptions = op;
360 }
361}
362
363
364static void get_sibling_options (text_t &instring, metadata_t &metaoption) {
365
366 assert (instring.size() > 8);
367 if (instring.size() <= 8) return;
368 text_t meta, com, op;
369 bool inbraces = false;
370 bool inquotes = false;
371 bool foundcolon = false;
372 text_t::const_iterator here = instring.begin()+7;
373 text_t::const_iterator end = instring.end();
374 while (here != end) {
375 if (foundcolon) meta.push_back (*here);
376 else if (*here == '(') inbraces = true;
377 else if (*here == ')') inbraces = false;
378 else if (*here == '\'' && !inquotes) inquotes = true;
379 else if (*here == '\'' && inquotes) inquotes = false;
380 else if (*here == ':' && !inbraces) foundcolon = true;
381 else if (inquotes) op.push_back (*here);
382 else com.push_back (*here);
383 ++here;
384 }
385
386 instring = meta;
387 metaoption.siblingoptions.clear();
388
389 if (com.empty()) {
390 metaoption.mqualifier.sibling = sAll;
391 metaoption.siblingoptions = " ";
392 }
393 else if (com == "first") {
394 metaoption.mqualifier.sibling = sNum;
395 metaoption.siblingoptions = "0";
396 }
397 else if (com == "last") {
398 metaoption.mqualifier.sibling = sNum;
399 metaoption.siblingoptions = "-2"; // == last
400 }
401 else if (com.getint()>0) {
402 metaoption.mqualifier.sibling = sNum;
403 int pos = com.getint()-1;
404 metaoption.siblingoptions +=pos;
405 }
406 else {
407 metaoption.mqualifier.sibling = sAll;
408 metaoption.siblingoptions = op;
409 }
410}
411
412static void get_child_options (text_t &instring, metadata_t &metaoption) {
413
414 assert (instring.size() > 6);
415 if (instring.size() <= 6) return;
416 text_t meta, com, op;
417 bool inbraces = false;
418 bool inquotes = false;
419 bool foundcolon = false;
420 text_t::const_iterator here = instring.begin()+5;
421 text_t::const_iterator end = instring.end();
422 while (here != end) {
423 if (foundcolon) meta.push_back (*here);
424 else if (*here == '(') inbraces = true;
425 else if (*here == ')') inbraces = false;
426 else if (*here == '\'' && !inquotes) inquotes = true;
427 else if (*here == '\'' && inquotes) inquotes = false;
428 else if (*here == ':' && !inbraces) foundcolon = true;
429 else if (inquotes) op.push_back (*here);
430 else com.push_back (*here);
431 ++here;
432 }
433
434 instring = meta;
435 if (com.empty()) {
436 metaoption.mqualifier.child = cAll;
437 metaoption.childoptions = " ";
438 }
439 else if (com == "first") {
440 metaoption.mqualifier.child = cNum;
441 metaoption.childoptions = ".fc";
442 }
443 else if (com == "last") {
444 metaoption.mqualifier.child = cNum;
445 metaoption.childoptions = ".lc";
446 }
447 else if (com.getint()>0) {
448 metaoption.mqualifier.child = cNum;
449 metaoption.childoptions = "."+com;
450 }
451 else {
452 metaoption.mqualifier.child = cAll;
453 metaoption.childoptions = op;
454 }
455}
456
457
458
459static void parse_meta (text_t &meta, metadata_t &metaoption,
460 text_tset &metadata, bool &getParents) {
461
462 if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
463 metaoption.metacommand |= mCgiSafe;
464 meta = substr (meta.begin()+8, meta.end());
465 }
466 if (meta.size() > 7 && (substr(meta.begin(), meta.begin()+7) == "format:")) {
467 metaoption.metacommand |= mSpecial;
468 meta = substr (meta.begin()+7, meta.end());
469 }
470
471 if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
472 getParents = true;
473 metaoption.metacommand |= mParent;
474 get_parent_options (meta, metaoption);
475 }
476 else if (meta.size() > 6 && (substr (meta.begin(), meta.begin()+5) == "child")) {
477 metaoption.metacommand |= mChild;
478 get_child_options (meta, metaoption);
479 metadata.insert("contains");
480 }
481 // parent and child can have sibling also
482 if (meta.size() > 8 && (substr (meta.begin(), meta.begin()+7) == "sibling")) {
483 metaoption.metacommand |= mSibling;
484 get_sibling_options (meta, metaoption);
485 }
486
487 // check for ex. which may occur in format statements
488 if (meta.size()>3 && (substr(meta.begin(), meta.begin()+3) == "ex.")) {
489 meta = substr (meta.begin()+3, meta.end());
490 }
491 metadata.insert (meta);
492 metaoption.metaname = meta;
493}
494
495static void parse_coll_meta(text_t &meta, metadata_t &metaoption) {
496 if (meta == "collection") {
497 // no qualifiers
498 metaoption.metaname = g_EmptyText;
499 return;
500 }
501 meta = substr (meta.begin()+11, meta.end());
502 metaoption.metaname = meta;
503
504}
505
506static void parse_meta (text_t &meta, format_t *formatlistptr,
507 text_tset &metadata, bool &getParents) {
508
509 if (meta == "link")
510 formatlistptr->command = comLink;
511 else if (meta == "/link")
512 formatlistptr->command = comEndLink;
513
514 else if (meta == "href")
515 formatlistptr->command = comHref;
516
517 else if (meta == "num")
518 formatlistptr->command = comNum;
519
520 else if (meta == "icon")
521 formatlistptr->command = comIcon;
522
523 else if (meta == "Text")
524 formatlistptr->command = comDoc;
525
526 else if (meta == "RelatedDocuments")
527 formatlistptr->command = comRel;
528
529 else if (meta == "highlight")
530 formatlistptr->command = comHighlight;
531
532 else if (meta == "/highlight")
533 formatlistptr->command = comEndHighlight;
534
535 else if (meta == "Summary")
536 formatlistptr->command = comSummary;
537
538 else if (meta == "DocImage")
539 formatlistptr->command = comImage;
540
541 else if (meta == "DocTOC")
542 formatlistptr->command = comTOC;
543
544 else if (meta == "DocumentButtonDetach")
545 formatlistptr->command = comDocumentButtonDetach;
546
547 else if (meta == "DocumentButtonHighlight")
548 formatlistptr->command = comDocumentButtonHighlight;
549
550 else if (meta == "DocumentButtonExpandContents")
551 formatlistptr->command = comDocumentButtonExpandContents;
552
553 else if (meta == "DocumentButtonExpandText")
554 formatlistptr->command = comDocumentButtonExpandText;
555
556 else if (meta == "DocOID")
557 formatlistptr->command = comOID;
558 else if (meta == "DocTopOID")
559 formatlistptr->command = comTopOID;
560 else if (meta == "DocRank")
561 formatlistptr->command = comRank;
562 else if (meta.size() >= 10 && (substr(meta.begin(), meta.begin()+10) == "collection")) {
563 formatlistptr->command = comCollection;
564 parse_coll_meta(meta, formatlistptr->meta);
565 }
566 else {
567 formatlistptr->command = comMeta;
568 parse_meta (meta, formatlistptr->meta, metadata, getParents);
569 }
570}
571
572
573static bool parse_string (const text_t &formatstring, format_t *formatlistptr,
574 text_tset &metadata, bool &getParents) {
575
576 text_t text;
577 text_t::const_iterator here = formatstring.begin();
578 text_t::const_iterator end = formatstring.end();
579
580 while (here != end) {
581
582 if (*here == '\\') {
583 ++here;
584 if (here != end) text.push_back (*here);
585
586 } else if (*here == '{') {
587 if (!text.empty()) {
588 formatlistptr->command = comText;
589 formatlistptr->text = text;
590 formatlistptr->nextptr = new format_t();
591 formatlistptr = formatlistptr->nextptr;
592
593 text.clear();
594 }
595 if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
596
597 formatlistptr->nextptr = new format_t();
598 formatlistptr = formatlistptr->nextptr;
599 if (here == end) break;
600 }
601 } else if (*here == '[') {
602 if (!text.empty()) {
603 formatlistptr->command = comText;
604 formatlistptr->text = text;
605 formatlistptr->nextptr = new format_t();
606 formatlistptr = formatlistptr->nextptr;
607
608 text.clear();
609 }
610 text_t meta;
611 ++here;
612 while (*here != ']') {
613 if (here == end) return false;
614 meta.push_back (*here);
615 ++here;
616 }
617 parse_meta (meta, formatlistptr, metadata, getParents);
618 formatlistptr->nextptr = new format_t();
619 formatlistptr = formatlistptr->nextptr;
620
621 } else
622 text.push_back (*here);
623
624 if (here != end) ++here;
625 }
626 if (!text.empty()) {
627 formatlistptr->command = comText;
628 formatlistptr->text = text;
629 formatlistptr->nextptr = new format_t();
630 formatlistptr = formatlistptr->nextptr;
631
632 }
633 return true;
634}
635
636
637static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
638 format_t *formatlistptr, text_tset &metadata, bool &getParents) {
639
640 text_t::const_iterator it = findchar (here, end, '}');
641 if (it == end) return false;
642
643 text_t com = substr (here, it);
644 here = findchar (it, end, '{');
645 if (here == end) return false;
646 else ++here;
647
648 if (com == "If" || com == "if" || com == "IF") formatlistptr->command = comIf;
649 else if (com == "Or" || com == "or" || com == "OR") formatlistptr->command = comOr;
650 else return false;
651
652 int commacount = 0;
653 text_t text;
654 while (here != end) {
655
656 if (*here == '\\') {
657 ++here;
658 if (here != end) text.push_back(*here);
659
660 }
661
662 else if (*here == ',' || *here == '}' || *here == '{') {
663
664 if (formatlistptr->command == comOr) {
665 // the {Or}{this, or this, or this, or this} statement
666 format_t *or_ptr;
667
668 // find the next unused orptr
669 if (formatlistptr->orptr == NULL) {
670 formatlistptr->orptr = new format_t();
671 or_ptr = formatlistptr->orptr;
672 } else {
673 or_ptr = formatlistptr->orptr;
674 while (or_ptr->nextptr != NULL)
675 or_ptr = or_ptr->nextptr;
676 or_ptr->nextptr = new format_t();
677 or_ptr = or_ptr->nextptr;
678 }
679
680 if (!text.empty())
681 {
682 if (!parse_string(text, or_ptr, metadata, getParents)) { return false; }
683 }
684
685 if (*here == '{')
686 {
687 // Supports: {Or}{[Booktitle],[Title],{If}{[XXXX],aaa,bbb}}
688 // but not : {Or}{[Booktitle],[Title]{If}{[XXXX],aaa,bbb}}
689 // The latter can always be re-written:
690 // {Or}{[Booktitle],{If}{[Title],[Title]{If}{[XXXX],aaa,bbb}}}
691
692 if (!text.empty()) // already used up allocated format_t
693 {
694 // => allocate new one for detected action
695 or_ptr->nextptr = new format_t();
696 or_ptr = or_ptr->nextptr;
697 }
698 if (!parse_action(++here, end, or_ptr, metadata, getParents))
699 {
700 return false;
701 }
702 }
703 else
704 {
705 if (*here == '}') break;
706 }
707 text.clear();
708
709 }
710
711 // Parse an {If}{decide,do,else} statement
712 else {
713
714 // Read the decision component.
715 if (commacount == 0) {
716 // Decsion can be a metadata element, or a piece of text.
717 // Originally Stefan's code, updated 25/10/2000 by Gordon.
718
719 text_t::const_iterator beginbracket = text.begin();
720 text_t::const_iterator endbracket = (text.end() - 1);
721
722 // Decision is based on a metadata element
723 if ((*beginbracket == '[') && (*endbracket == ']')) {
724 // Ignore the surrounding square brackets
725 text_t meta = substr (beginbracket+1, endbracket);
726 parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
727 ++commacount;
728 text.clear();
729 }
730
731 // Decision is a piece of text (probably a macro like _cgiargmode_).
732 else {
733
734 // hunt for any metadata in string, which might be uses in
735 // to test a condition, e.g. [Format] eq 'PDF'
736 format_t* dummyformat = new format_t();
737 // update which metadata fields needed
738 // (not interested in updatng formatlistptr)
739 parse_string (text, dummyformat, metadata, getParents);
740 delete dummyformat;
741
742 formatlistptr->decision.command = dText;
743 formatlistptr->decision.text = text;
744 ++commacount;
745 text.clear();
746 }
747 }
748
749 // Read the "then" and "else" components of the {If} statement.
750 else {
751 format_t** nextlistptr = NULL;
752 if (commacount == 1) {
753 nextlistptr = &formatlistptr->ifptr;
754 } else if (commacount == 2 ) {
755 nextlistptr = &formatlistptr->elseptr;
756 } else {
757 return false;
758 }
759
760 if (!text.empty()) {
761 if (*nextlistptr == NULL) {
762 *nextlistptr = new format_t();
763 } else {
764
765 // skip to the end of any format_t statements already added
766 while ((*nextlistptr)->nextptr != NULL)
767 {
768 nextlistptr = &(*nextlistptr)->nextptr;
769 }
770
771 (*nextlistptr)->nextptr = new format_t();
772 nextlistptr = &(*nextlistptr)->nextptr;
773 }
774
775 if (!parse_string (text, *nextlistptr, metadata, getParents))
776 {
777 return false;
778 }
779 text.clear();
780 }
781
782 if (*here == '{')
783 {
784 if (*nextlistptr == NULL) {
785 *nextlistptr = new format_t();
786 } else {
787 // skip to the end of any format_t statements already added
788 while ((*nextlistptr)->nextptr != NULL)
789 {
790 nextlistptr = &(*nextlistptr)->nextptr;
791 }
792
793 (*nextlistptr)->nextptr = new format_t();
794 nextlistptr = &(*nextlistptr)->nextptr;
795 }
796
797 if (!parse_action(++here, end, *nextlistptr, metadata, getParents))
798 {
799 return false;
800 }
801 }
802 else
803 {
804 if (*here == '}') break;
805 ++commacount;
806 }
807 }
808 }
809
810 } else text.push_back(*here);
811
812 if (here != end) ++here;
813 }
814
815 return true;
816}
817
818
819bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr,
820 text_tset &metadata, bool &getParents) {
821
822 formatlistptr->clear();
823 getParents = false;
824
825 return (parse_string (formatstring, formatlistptr, metadata, getParents));
826}
827
828// position -1 for all, -2 for the last, 0 for the first, or x for a particular piece
829// metainfo has all the values for the metadata, meta has the request metadata name and options, position tells which values to get
830static text_t get_formatted_meta_text(MetadataInfo_t &metainfo, const metadata_t &meta, int position, bool no_cgisafe = false)
831{
832 text_t no_ns_metaname = remove_namespace(meta.metaname);
833 text_t tmp;
834 bool first = true;
835
836 const int start_i=0;
837 const int end_i = metainfo.values.size()-1;
838
839 if (position == -1) { // all
840 for (int i=start_i; i<=end_i; ++i) {
841 if (!first) tmp += meta.siblingoptions;
842 if (meta.metacommand & mSpecial) {
843 // special formatting
844 if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[i]);
845 else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[i]);
846 else tmp += "_format:"+meta.metaname+"_("+metainfo.values[i]+")";
847 }
848 else tmp += metainfo.values[i];
849 first = false;
850
851 }
852 } else {
853 if (position == -2) { // end
854 position = end_i;
855 } else if (position < start_i || position > end_i) {
856 return "";
857 }
858 if (meta.metacommand & mSpecial) {
859 // special formatting
860 if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[position]);
861 else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[position]);
862 else tmp += "_format:"+meta.metaname+"_("+metainfo.values[position]+")";
863 }
864 else tmp += metainfo.values[position];
865 }
866 if (meta.metacommand & mCgiSafe && !no_cgisafe) return cgi_safe_unicode (tmp);
867 else return tmp;
868}
869
870static text_t get_parent_meta (ResultDocInfo_t &docinfo, const metadata_t &meta, int siblings_values)
871{
872
873 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
874 switch (meta.mqualifier.parent) {
875 case pNone:
876 return "Nothing!!";
877 break;
878
879 case pImmediate:
880 if (parent != NULL) {
881 return get_formatted_meta_text(*parent, meta, siblings_values);
882 }
883 break;
884
885 case pTop:
886 if (parent != NULL) {
887 while (parent->parent != NULL) parent = parent->parent;
888 return get_formatted_meta_text(*parent, meta, siblings_values);
889 }
890 break;
891
892 case pAll:
893 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
894 if (parent != NULL) {
895 text_tarray tmparray;
896 while (parent != NULL) {
897 tmparray.push_back (get_formatted_meta_text(*parent, meta, siblings_values, true)); // set no_cgisafe to true, as we'll do it once we have all the metadata
898 parent = parent->parent;
899 }
900 // now join them up - use teh parent separator
901 bool first = true;
902 text_t tmp;
903 text_tarray::reverse_iterator here = tmparray.rbegin();
904 text_tarray::reverse_iterator end = tmparray.rend();
905 while (here != end) {
906 if (!first) tmp += meta.parentoptions;
907 tmp += *here;
908 first = false;
909 ++here;
910 }
911 if (meta.metacommand & mCgiSafe) return cgi_safe_unicode (tmp);
912 else return tmp;
913 }
914 }
915 return "";
916
917}
918
919static text_t get_child_meta (const text_t& collection,
920 recptproto* collectproto,
921 ResultDocInfo_t &docinfo, displayclass &disp,
922 const metadata_t &meta, text_tmap &options,
923 ostream& logout, int siblings_values)
924{
925 if (docinfo.metadata["contains"].values[0].size()==0) return ""; // no children
926
927 const text_t& child_metaname = meta.metaname;
928 const text_t& child_field = meta.childoptions;
929 text_tset child_metadata;
930 child_metadata.insert(child_metaname);
931
932 FilterResponse_t child_response;
933 if (meta.mqualifier.child == cNum) {
934 // just one child
935 //get the information associated with the metadata for child doc
936 if (!get_info (docinfo.OID+child_field, collection, "", child_metadata,
937 false, collectproto, child_response, logout)) return ""; // invalid child number
938
939 if (child_response.docInfo.empty()) return false; // no info for the child
940
941 ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
942 MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
943
944 text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
945 return expand_metadata(child_metavalue,collection,collectproto,
946 child_docinfo,disp,options,logout);
947 }
948
949
950 if (meta.mqualifier.child != cAll) return false; // invalid qualifier
951
952 // we need to get all children
953 text_t result = "";
954 text_tarray children;
955 text_t contains = docinfo.metadata["contains"].values[0];
956 splitchar (contains.begin(), contains.end(), ';', children);
957 text_tarray::const_iterator here = children.begin();
958 text_tarray::const_iterator end = children.end();
959 bool first = true;
960 while (here !=end) {
961 text_t oid = *here;
962 here++;
963 if (*(oid.begin()) == '"') translate_parent (oid, docinfo.OID);
964
965
966 //get the information associated with the metadata for child doc
967 if (!get_info (oid, collection, "", child_metadata,
968 false, collectproto, child_response, logout) ||
969 child_response.docInfo.empty()) {
970 first = false;
971 continue;
972 }
973
974
975 ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
976 MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
977
978 text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
979 if (!first) result += child_field;
980 first = false;
981 // need to do this here cos otherwise we are in the wrong document
982 result += expand_metadata(child_metavalue,collection,collectproto,
983 child_docinfo,disp,options,logout);
984 }
985 return result;
986
987}
988
989static text_t get_meta (const text_t& collection, recptproto* collectproto,
990 ResultDocInfo_t &docinfo, displayclass &disp,
991 const metadata_t &meta, text_tmap &options,
992 ostream& logout) {
993
994 // make sure we have the requested metadata
995 MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
996 if (it == docinfo.metadata.end()) return "";
997
998 int siblings_values = 0; // default is no siblings, just the first metadata available
999 if (meta.metacommand & mSibling) {
1000 if (meta.mqualifier.sibling == sAll) {
1001 siblings_values = -1; //all
1002 } else if (meta.mqualifier.sibling == sNum) {
1003 siblings_values = meta.siblingoptions.getint();
1004 }
1005 }
1006 if (meta.metacommand & mParent) {
1007 return get_parent_meta(docinfo,meta,siblings_values);
1008 }
1009
1010 else if (meta.metacommand & mChild) {
1011 return get_child_meta(collection,collectproto,docinfo,disp,meta,
1012 options,logout, siblings_values);
1013 }
1014 else if (meta.metacommand & mSibling) { // only siblings
1015 MetadataInfo_t& metaname_rec = docinfo.metadata[meta.metaname];
1016 return get_formatted_meta_text(docinfo.metadata[meta.metaname],meta, siblings_values);
1017 }
1018 else {
1019
1020 // straightforward metadata request (nothing fancy)
1021
1022 text_t classifier_metaname = docinfo.classifier_metadata_type;
1023 int metaname_index
1024 = (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
1025 return get_formatted_meta_text(docinfo.metadata[meta.metaname], meta, metaname_index);
1026 }
1027
1028 return "";
1029}
1030
1031static text_t get_or (const text_t& collection, recptproto* collectproto,
1032 ResultDocInfo_t &docinfo, displayclass &disp,
1033 format_t *orptr, text_tmap &options,
1034 ostream& logout) {
1035
1036 text_t tmp;
1037 while (orptr != NULL) {
1038
1039 tmp = format_string (collection,collectproto,docinfo, disp, orptr,
1040 options, logout);
1041 if (!tmp.empty()) return tmp;
1042
1043 orptr = orptr->nextptr;
1044 }
1045 return "";
1046}
1047
1048static bool char_is_whitespace(const char c)
1049{
1050 return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
1051
1052}
1053
1054static int scan_over_whitespace(const text_t& outstring, const int start_pos)
1055{
1056 int pos = start_pos;
1057 while (pos<outstring.size()) {
1058 if (!char_is_whitespace(outstring[pos])) {
1059 break;
1060 }
1061 ++pos;
1062 }
1063
1064 return pos;
1065}
1066
1067static int rscan_over_whitespace(const text_t& outstring, const int start_pos)
1068{
1069 int pos = start_pos;
1070 while (pos>=0) {
1071 if (!char_is_whitespace(outstring[pos])) {
1072 break;
1073 }
1074 --pos;
1075 }
1076
1077 return pos;
1078}
1079
1080static int rscan_for_whitespace(const text_t& outstring, const int start_pos)
1081{
1082 int pos = start_pos;
1083 while (pos>=0) {
1084 if (char_is_whitespace(outstring[pos])) {
1085 break;
1086 }
1087 --pos;
1088 }
1089
1090 return pos;
1091}
1092
1093
1094static int rscan_for(const text_t& outstring, const int start_pos,
1095 const char find_c)
1096{
1097 int pos = start_pos;
1098 while (pos>=0) {
1099 char c = outstring[pos];
1100 if (outstring[pos] == find_c) {
1101 break;
1102 }
1103 --pos;
1104 }
1105
1106 return pos;
1107}
1108
1109text_t extract_substr(const text_t& outstring, const int start_pos,
1110 const int end_pos)
1111{
1112 text_t extracted_str;
1113 extracted_str.clear();
1114
1115 for (int pos=start_pos; pos<=end_pos; ++pos) {
1116 extracted_str.push_back(outstring[pos]);
1117 }
1118
1119 return extracted_str;
1120}
1121
1122
1123static text_t expand_potential_metadata(const text_t& collection,
1124 recptproto* collectproto,
1125 ResultDocInfo_t &docinfo,
1126 displayclass &disp,
1127 const text_t& intext,
1128 text_tmap &options,
1129 ostream& logout)
1130{
1131 text_t outtext;
1132
1133 // decide if dealing with metadata or text
1134
1135 text_t::const_iterator beginbracket = intext.begin();
1136 text_t::const_iterator endbracket = (intext.end() - 1);
1137
1138 // Decision is based on a metadata element
1139 if ((*beginbracket == '[') && (*endbracket == ']')) {
1140 // Ignore the surrounding square brackets
1141 text_t meta_text = substr (beginbracket+1, endbracket);
1142
1143 if (meta_text == "Text") {
1144 outtext = format_text(collection, collectproto, docinfo, disp, options, logout);
1145 } else {
1146
1147 text_tset metadata;
1148 bool getParents =false;
1149 metadata_t meta;
1150
1151 parse_meta (meta_text, meta, metadata, getParents);
1152 outtext
1153 = get_meta (collection,collectproto,docinfo,disp,meta,options,logout);
1154 }
1155
1156 }
1157 else {
1158 outtext = intext;
1159 }
1160
1161 return outtext;
1162}
1163
1164
1165
1166
1167static bool uses_expression(const text_t& collection, recptproto* collectproto,
1168 ResultDocInfo_t &docinfo,
1169 displayclass &disp,
1170 const text_t& outstring, text_t& lhs_expr,
1171 text_t& op_expr, text_t& rhs_expr,
1172 text_tmap &options,
1173 ostream& logout)
1174{
1175 // Note: the string may not be of the form: str1 op str2, however
1176 // to deterine this we have to process it on the assumption it is,
1177 // and if at any point an 'erroneous' value is encountered, return
1178 // false and let something else have a go at evaluating it
1179
1180 // Starting at the end of the string and working backwards ..
1181
1182 const int outstring_len = outstring.size();
1183
1184 // skip over white space
1185 int rhs_end = rscan_over_whitespace(outstring,outstring_len-1);
1186
1187 if (rhs_end<=0) {
1188 // no meaningful text or (rhs_end==0) no room for operator
1189 return false;
1190 }
1191
1192 // check for ' or " and then scan over token
1193 const char potential_quote = outstring[rhs_end];
1194 int rhs_start=rhs_end;
1195 bool quoted = false;
1196
1197 if ((potential_quote == '\'') || (potential_quote == '\"')) {
1198 --rhs_end;
1199 rhs_start = rscan_for(outstring,rhs_end-1,potential_quote) +1;
1200 quoted = true;
1201 }
1202 else {
1203 rhs_start = rscan_for_whitespace(outstring,rhs_end-1) +1;
1204 }
1205
1206 if ((rhs_end-rhs_start)<0) {
1207 // no meaningful rhs expression
1208 return false;
1209 }
1210
1211 // form rhs_expr
1212 rhs_expr = extract_substr(outstring,rhs_start,rhs_end);
1213
1214 // skip over white space
1215 const int to_whitespace = (quoted) ? 2 : 1;
1216
1217 int op_end = rscan_over_whitespace(outstring,rhs_start-to_whitespace);
1218 int op_start = rscan_for_whitespace(outstring,op_end-1)+1;
1219
1220
1221 if (op_end-op_start<0) {
1222 // no meaningful expression operator
1223 return false;
1224 }
1225
1226 op_expr = extract_substr(outstring,op_start,op_end);
1227
1228
1229 // check for operator
1230 if ((op_expr != "eq") && (op_expr != "ne") && (op_expr != "gt") &&
1231 (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")) {
1232
1233 // not a valid operator
1234 return false;
1235 }
1236
1237 int lhs_end = rscan_over_whitespace(outstring,op_start-1);
1238 if (lhs_end<0) {
1239 // no meaningful lhs expression
1240 return false;
1241 }
1242
1243 int lhs_start = scan_over_whitespace(outstring,0);
1244
1245 // form lhs_expr from remainder of string
1246 lhs_expr = extract_substr(outstring,lhs_start,lhs_end);
1247
1248 // Now we know we have a valid expression, look up any
1249 // metadata terms
1250
1251 rhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
1252 disp,rhs_expr,options,logout);
1253 lhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
1254 disp,lhs_expr,options,logout);
1255
1256 return true;
1257}
1258
1259static bool eval_expression_true(const text_t& lhs_expr,const text_t& op_expr,
1260 const text_t& rhs_expr, ostream& logout)
1261{
1262 if (op_expr == "eq") return (lhs_expr == rhs_expr);
1263 else if (op_expr == "ne" ) return (lhs_expr != rhs_expr);
1264 else if (op_expr == "gt") return (lhs_expr > rhs_expr);
1265 else if (op_expr == "ge") return (lhs_expr >= rhs_expr);
1266 else if (op_expr == "lt") return (lhs_expr < rhs_expr);
1267 else if (op_expr == "le") return (lhs_expr <= rhs_expr);
1268 else if (op_expr == "==") return (lhs_expr.getint() == rhs_expr.getint());
1269 else if (op_expr == "!=") return (lhs_expr.getint() != rhs_expr.getint());
1270 else if (op_expr == ">") return (lhs_expr.getint() > rhs_expr.getint());
1271 else if (op_expr == ">=") return (lhs_expr.getint() >= rhs_expr.getint());
1272 else if (op_expr == "<") return (lhs_expr.getint() < rhs_expr.getint());
1273 else if (op_expr == "<=") return (lhs_expr.getint() <= rhs_expr.getint());
1274 else if (op_expr == "sw") return (starts_with(lhs_expr,rhs_expr));
1275 else if (op_expr == "ew") return (ends_with(lhs_expr,rhs_expr));
1276 else {
1277 logout << "Error: '" << op_expr << "' is not a recognised operator." << endl;
1278 }
1279
1280 return false;
1281}
1282
1283
1284static text_t get_if (const text_t& collection, recptproto* collectproto,
1285 ResultDocInfo_t &docinfo, displayclass &disp,
1286 const decision_t &decision,
1287 format_t *ifptr, format_t *elseptr,
1288 text_tmap &options, ostream& logout)
1289{
1290 // If the decision component is a metadata element, then evaluate it
1291 // to see whether we output the "then" or the "else" clause
1292 if (decision.command == dMeta) {
1293 if (get_meta (collection,collectproto,docinfo,disp,decision.meta,options,
1294 logout) != "") {
1295 if (ifptr != NULL)
1296 return get_formatted_string (collection,collectproto,docinfo, disp, ifptr,
1297 options, logout);
1298 }
1299 else {
1300 if (elseptr != NULL)
1301 return get_formatted_string (collection,collectproto,docinfo, disp, elseptr,
1302 options, logout);
1303 }
1304 }
1305
1306 // If the decision component is text, then evaluate it (it is probably a
1307 // macro like _cgiargmode_) to decide what to output.
1308 else if (decision.command == dText) {
1309
1310 text_t outstring;
1311 disp.expandstring (decision.text, outstring);
1312
1313 // Check for if expression in form: str1 op str2
1314 // (such as [x] eq "y")
1315 text_t lhs_expr, op_expr, rhs_expr;
1316 if (uses_expression(collection,collectproto,docinfo, disp, outstring,lhs_expr,op_expr,rhs_expr, options,logout)) {
1317 if (eval_expression_true(lhs_expr,op_expr,rhs_expr,logout)) {
1318 if (ifptr != NULL) {
1319 return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
1320 options, logout);
1321 }
1322 else {
1323 return "";
1324 }
1325 } else {
1326 if (elseptr != NULL) {
1327 return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
1328 options, logout);
1329 }
1330 else {
1331 return "";
1332 }
1333 }
1334 }
1335
1336
1337 // This is a tad tricky. When we expand a string like _cgiargmode_, that is
1338 // a cgi argument macro that has not been set, it evaluates to itself.
1339 // Therefore, were have to say that a piece of text evalautes true if
1340 // it is non-empty and if it is a cgi argument evaulating to itself.
1341
1342 if ((outstring != "") && !((outstring == decision.text) && (outstring[0] == '_'))) {
1343 if (ifptr != NULL)
1344 return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
1345 options, logout);
1346 } else {
1347 if (elseptr != NULL)
1348 return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
1349 options, logout);
1350 }
1351 }
1352
1353 return "";
1354}
1355
1356bool includes_metadata(const text_t& text)
1357{
1358 text_t::const_iterator here = text.begin();
1359 text_t::const_iterator end = text.end();
1360 while (here != end) {
1361 if (*here == '[') return true;
1362 ++here;
1363 }
1364
1365 return false;
1366}
1367
1368static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
1369 recptproto* collectproto,
1370 ResultDocInfo_t &docinfo,
1371 displayclass &disp, text_tmap &options,
1372 ostream &logout) {
1373
1374 if (includes_metadata(metavalue)) {
1375
1376 // text has embedded metadata in it => expand it
1377 FilterRequest_t request;
1378 FilterResponse_t response;
1379
1380 request.getParents = false;
1381
1382 format_t *expanded_formatlistptr = new format_t();
1383 parse_formatstring (metavalue, expanded_formatlistptr,
1384 request.fields, request.getParents);
1385
1386 // retrieve metadata
1387 get_info(docinfo.OID, collection, "", request.fields, request.getParents,
1388 collectproto, response, logout);
1389
1390 if (!response.docInfo.empty()) {
1391
1392 text_t expanded_metavalue
1393 = get_formatted_string(collection, collectproto,
1394 response.docInfo[0], disp, expanded_formatlistptr,
1395 options, logout);
1396
1397 return expanded_metavalue;
1398 }
1399 else {
1400 return metavalue;
1401 }
1402 }
1403 else {
1404
1405 return metavalue;
1406 }
1407}
1408
1409text_t get_collection_meta(const text_t& collection, recptproto* collectproto,
1410 displayclass &disp,
1411 text_t meta_name, ostream& logout) {
1412
1413 ColInfoResponse_t collectinfo;
1414 comerror_t err;
1415 collectproto->get_collectinfo (collection, collectinfo,err,logout);
1416 text_t meta_value = "";
1417 text_t lang;
1418 disp.expandstring("_cgiargl_",lang);
1419 if (lang.empty()) {
1420 lang = "en";
1421 }
1422
1423 if (err == noError) {
1424 meta_value = collectinfo.get_collectionmeta(meta_name, lang);
1425 }
1426 return meta_value;
1427
1428
1429}
1430text_t format_string (const text_t& collection, recptproto* collectproto,
1431 ResultDocInfo_t &docinfo, displayclass &disp,
1432 format_t *formatlistptr, text_tmap &options,
1433 ostream& logout) {
1434
1435 if (formatlistptr == NULL) return "";
1436
1437 switch (formatlistptr->command) {
1438 case comOID:
1439 return docinfo.OID;
1440 case comTopOID:
1441 {
1442 text_t top_id;
1443 get_top(docinfo.OID, top_id);
1444 return top_id;
1445 }
1446 case comRank:
1447 return text_t(docinfo.ranking);
1448 case comText:
1449 return formatlistptr->text;
1450 case comLink:
1451 return options["link"];
1452 case comEndLink:
1453 if (options["link"].empty()) return "";
1454 else return "</a>";
1455 case comHref:
1456 return get_href(options["link"]);
1457 case comIcon:
1458 return options["icon"];
1459 case comNum:
1460 return docinfo.result_num;
1461 case comRel: //if [RelatedDocuments] appears in format string, collect relation data
1462 return get_related_docs(collection, collectproto, docinfo, logout);
1463 case comSummary:
1464 return format_summary(collection, collectproto, docinfo, disp, options, logout);
1465 case comMeta:
1466 {
1467 const text_t& metavalue = get_meta (collection,collectproto, docinfo, disp,formatlistptr->meta,options,logout);
1468 return expand_metadata(metavalue, collection, collectproto, docinfo, disp, options, logout);
1469 }
1470 case comDoc:
1471 return format_text(collection, collectproto, docinfo, disp, options, logout);
1472 //return options["text"];
1473 case comImage:
1474 return expand_metadata(options["DocImage"], collection, collectproto, docinfo, disp, options, logout);
1475 case comTOC:
1476 return options["DocTOC"];
1477 case comDocumentButtonDetach:
1478 return options["DocumentButtonDetach"];
1479 case comDocumentButtonHighlight:
1480 return options["DocumentButtonHighlight"];
1481 case comDocumentButtonExpandContents:
1482 return options["DocumentButtonExpandContents"];
1483 case comDocumentButtonExpandText:
1484 return options["DocumentButtonExpandText"];
1485 case comHighlight:
1486 if (options["highlight"] == "1") return "<b>";
1487 break;
1488 case comEndHighlight:
1489 if (options["highlight"] == "1") return "</b>";
1490 break;
1491 case comIf:
1492 return get_if (collection, collectproto, docinfo, disp,
1493 formatlistptr->decision, formatlistptr->ifptr,
1494 formatlistptr->elseptr, options, logout);
1495 case comOr:
1496 return get_or (collection,collectproto, docinfo, disp, formatlistptr->orptr,
1497 options, logout);
1498 case comCollection:
1499 if (formatlistptr->meta.metaname == g_EmptyText) {
1500 return collection;
1501 }
1502 return get_collection_meta(collection, collectproto, disp, formatlistptr->meta.metaname, logout);
1503
1504 }
1505 return "";
1506}
1507
1508text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
1509 ResultDocInfo_t &docinfo, displayclass &disp,
1510 format_t *formatlistptr, text_tmap &options,
1511 ostream& logout) {
1512
1513 text_t ft;
1514 while (formatlistptr != NULL)
1515 {
1516 ft += format_string (collection, collectproto, docinfo, disp, formatlistptr,
1517 options, logout);
1518 formatlistptr = formatlistptr->nextptr;
1519 }
1520
1521 return ft;
1522}
1523
1524
1525// we have only preloaded the text in DocumentAction. But you may want to get the text in query. so copy what we have done with format_summary and get the text here. probably is quite expensive?
1526text_t format_text (const text_t& collection, recptproto* collectproto,
1527 ResultDocInfo_t &docinfo, displayclass &disp,
1528 text_tmap &options, ostream& logout) {
1529 if(!options["text"].empty()) {
1530 return options["text"];
1531 }
1532 // else get document text here
1533 DocumentRequest_t docrequest;
1534 DocumentResponse_t docresponse;
1535 comerror_t err;
1536 docrequest.OID = docinfo.OID;
1537 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1538 return docresponse.doc;
1539
1540}
1541
1542/* FUNCTION NAME: format_summary
1543 * DESC: this is invoked when a [Summary] special metadata is processed.
1544 * RETURNS: a query-biased summary for the document */
1545
1546text_t format_summary (const text_t& collection, recptproto* collectproto,
1547 ResultDocInfo_t &docinfo, displayclass &disp,
1548 text_tmap &options, ostream& logout) {
1549
1550 // GRB: added code here to ensure that the cstr (and other collections)
1551 // uses the document metadata item Summary, rather than compressing
1552 // the text of the document, processed via the methods in
1553 // summarise.cpp
1554 if (docinfo.metadata.count("Summary") > 0 &&
1555 docinfo.metadata["Summary"].values.size() > 0) {
1556 return docinfo.metadata["Summary"].values[0];
1557 }
1558
1559 text_t textToSummarise, query;
1560 if(options["text"].empty()) { // get document text
1561 DocumentRequest_t docrequest;
1562 DocumentResponse_t docresponse;
1563 comerror_t err;
1564 docrequest.OID = docinfo.OID;
1565 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1566 textToSummarise = docresponse.doc;
1567 } else // in practice, this would not happen, because text is only
1568 // loaded with the [Text] command
1569 textToSummarise = options["text"];
1570 disp.expandstring("_cgiargq_",query);
1571 return summarise(textToSummarise,query,80);
1572}
Note: See TracBrowser for help on using the repository browser.