source: gsdl/trunk/src/recpt/formattools.cpp@ 16347

Last change on this file since 16347 was 15418, checked in by mdewsnip, 16 years ago

(Untangling colservr/recpt) Split recpt/OIDtools into two: lib/OIDtools.cpp/h contains the purely string-based functions (may be used by the colservr), and recpt/recptprototools.cpp/h contains the functions requiring a call to the colservr (get_info() etc.).

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