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

Last change on this file since 1860 was 1610, checked in by paynter, 24 years ago

Changed the formatstring parser in formattools so that an {If} macro (which
has the form {If}{decision,then,else}) can branch on any text, not just on
metadata. This means you can use extra cgi arguments and macros like
_cgiargmode_ to display documents in different modes and switch between
them. To accomplish all this, the formattools class needed to be able to
evaluate macros (through displayclass), so the other files have been
changed to pass in a displayclass object.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 21.7 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
30#include <assert.h>
31
32// a few function prototypes
33static text_t format_string (const text_t& collection, recptproto* collectproto,
34 ResultDocInfo_t &docinfo, displayclass &disp,
35 format_t *formatlistptr,
36 const text_t &link, const text_t &icon,
37 const text_t &text, bool highlight, ostream& logout);
38
39static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
40 format_t *formatlistptr, text_tset &metadata, bool &getParents);
41
42void metadata_t::clear() {
43 metaname.clear();
44 metacommand = mNone;
45 parentcommand = pNone;
46 parentoptions.clear();
47}
48
49void decision_t::clear() {
50 command = dMeta;
51 meta.clear();
52 text.clear();
53}
54
55void format_t::clear() {
56 command = comText;
57 decision.clear();
58 text.clear();
59 meta.clear();
60 nextptr = NULL;
61 ifptr = NULL;
62 elseptr = NULL;
63 orptr = NULL;
64}
65
66void formatinfo_t::clear() {
67 DocumentImages = false;
68 DocumentTitles = true;
69 DocumentHeading = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
70 DocumentContents = true;
71 DocumentArrowsBottom = true;
72 DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
73 // DocumentButtons.push_back ("Expand Text");
74 // DocumentButtons.push_back ("Expand Contents");
75 DocumentButtons.push_back ("Detach");
76 DocumentButtons.push_back ("Highlight");
77 DocumentText = "<center><table width=_pagewidth_><tr><td>[Text]</td></tr></table></center>";
78 formatstrings.erase (formatstrings.begin(), formatstrings.end());
79 DocumentUseHTML = false;
80}
81
82// simply checks to see if formatstring begins with a <td> tag
83bool is_table_content (const text_t &formatstring) {
84 text_t::const_iterator here = formatstring.begin();
85 text_t::const_iterator end = formatstring.end();
86
87 while (here != end) {
88 if (*here != ' ') {
89 if ((*here == '<') && ((here+3) < end)) {
90 if ((*(here+1) == 't' || *(here+1) == 'T') &&
91 (*(here+2) == 'd' || *(here+2) == 'D') &&
92 (*(here+3) == '>' || *(here+3) == ' '))
93 return true;
94 } else return false;
95 }
96 here ++;
97 }
98 return false;
99}
100
101bool is_table_content (const format_t *formatlistptr) {
102
103 if (formatlistptr == NULL) return false;
104
105 if (formatlistptr->command == comText)
106 return is_table_content (formatlistptr->text);
107
108 return false;
109}
110
111// returns false if key isn't in formatstringmap
112bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
113 text_t &formatstring) {
114
115 formatstring.clear();
116 text_tmap::const_iterator it = formatstringmap.find(key);
117 if (it == formatstringmap.end()) return false;
118 formatstring = (*it).second;
119 return true;
120}
121
122// tries to find "key1key2" then "key1" then "key2"
123bool get_formatstring (const text_t &key1, const text_t &key2,
124 const text_tmap &formatstringmap,
125 text_t &formatstring) {
126
127 formatstring.clear();
128 text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
129 if (it != formatstringmap.end()) {
130 formatstring = (*it).second;
131 return true;
132 }
133 it = formatstringmap.find(key1);
134 if (it != formatstringmap.end()) {
135 formatstring = (*it).second;
136 return true;
137 }
138 it = formatstringmap.find(key2);
139 if (it != formatstringmap.end()) {
140 formatstring = (*it).second;
141 return true;
142 }
143 return false;
144}
145
146
147// returns a date of form 31 _textmonthnn_ 1999
148// input is date of type 19991231
149// at least the year must be present in date
150text_t format_date (const text_t &date) {
151
152 if (date.size() < 4) return "";
153
154 text_t::const_iterator datebegin = date.begin();
155
156 text_t year = substr (datebegin, datebegin+4);
157
158 if (date.size() < 6) return year;
159
160 text_t month = "_textmonth" + substr (datebegin+4, datebegin+6) + "_";
161 int imonth = month.getint();
162 if (imonth < 0 || imonth > 12) return year;
163
164 if (date.size() < 8) return month + " " + year;
165
166 text_t day = substr (datebegin+6, datebegin+8);
167 if (day[0] == '0') day = substr (day.begin()+1, day.end());
168 int iday = day.getint();
169 if (iday < 0 || iday > 31) return month + " " + year;
170
171 return day + " " + month + " " + year;
172}
173
174static void get_parent_options (text_t &instring, metadata_t &metaoption) {
175
176 assert (instring.size() > 7);
177 if (instring.size() <= 7) return;
178
179 text_t meta, com, op;
180 bool inbraces = false;
181 bool inquotes = false;
182 bool foundcolon = false;
183 text_t::const_iterator here = instring.begin()+6;
184 text_t::const_iterator end = instring.end();
185 while (here != end) {
186 if (*here == '(') inbraces = true;
187 else if (*here == ')') inbraces = false;
188 else if (*here == '\'' && !inquotes) inquotes = true;
189 else if (*here == '\'' && inquotes) inquotes = false;
190 else if (*here == ':' && !inbraces) foundcolon = true;
191 else if (foundcolon) meta.push_back (*here);
192 else if (inquotes) op.push_back (*here);
193 else com.push_back (*here);
194 here ++;
195 }
196 instring = meta;
197 if (com.empty())
198 metaoption.parentcommand = pImmediate;
199 else if (com == "Top")
200 metaoption.parentcommand = pTop;
201 else if (com == "All") {
202 metaoption.parentcommand = pAll;
203 metaoption.parentoptions = op;
204 }
205}
206
207static void parse_meta (text_t &meta, metadata_t &metaoption,
208 text_tset &metadata, bool &getParents) {
209
210 if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
211 metaoption.metacommand = mCgiSafe;
212 meta = substr (meta.begin()+8, meta.end());
213 }
214
215 if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
216 getParents = true;
217 get_parent_options (meta, metaoption);
218 }
219
220 metadata.insert (meta);
221 metaoption.metaname = meta;
222}
223
224static void parse_meta (text_t &meta, format_t *formatlistptr,
225 text_tset &metadata, bool &getParents) {
226
227 if (meta == "link")
228 formatlistptr->command = comLink;
229 else if (meta == "/link")
230 formatlistptr->command = comEndLink;
231
232 else if (meta == "num")
233 formatlistptr->command = comNum;
234
235 else if (meta == "icon")
236 formatlistptr->command = comIcon;
237
238 else if (meta == "Text")
239 formatlistptr->command = comDoc;
240
241 else if (meta == "highlight")
242 formatlistptr->command = comHighlight;
243
244 else if (meta == "/highlight")
245 formatlistptr->command = comEndHighlight;
246
247 else {
248 formatlistptr->command = comMeta;
249 parse_meta (meta, formatlistptr->meta, metadata, getParents);
250 }
251}
252
253static bool parse_string (const text_t &formatstring, format_t *formatlistptr,
254 text_tset &metadata, bool &getParents) {
255
256 text_t text;
257 text_t::const_iterator here = formatstring.begin();
258 text_t::const_iterator end = formatstring.end();
259
260 while (here != end) {
261
262 if (*here == '\\') {
263 here ++;
264 if (here != end) text.push_back (*here);
265
266 } else if (*here == '{') {
267 if (!text.empty()) {
268 formatlistptr->command = comText;
269 formatlistptr->text = text;
270 formatlistptr->nextptr = new format_t();
271 formatlistptr = formatlistptr->nextptr;
272
273 text.clear();
274 }
275 if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
276
277 formatlistptr->nextptr = new format_t();
278 formatlistptr = formatlistptr->nextptr;
279 if (here == end) break;
280 }
281 } else if (*here == '[') {
282 if (!text.empty()) {
283 formatlistptr->command = comText;
284 formatlistptr->text = text;
285 formatlistptr->nextptr = new format_t();
286 formatlistptr = formatlistptr->nextptr;
287
288 text.clear();
289 }
290 text_t meta;
291 here ++;
292 while (*here != ']') {
293 if (here == end) return false;
294 meta.push_back (*here);
295 here ++;
296 }
297 parse_meta (meta, formatlistptr, metadata, getParents);
298 formatlistptr->nextptr = new format_t();
299 formatlistptr = formatlistptr->nextptr;
300
301 } else
302 text.push_back (*here);
303
304 if (here != end) here ++;
305 }
306 if (!text.empty()) {
307 formatlistptr->command = comText;
308 formatlistptr->text = text;
309 formatlistptr->nextptr = new format_t();
310 formatlistptr = formatlistptr->nextptr;
311
312 }
313 return true;
314}
315
316
317static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
318 format_t *formatlistptr, text_tset &metadata, bool &getParents) {
319
320 text_t::const_iterator it = findchar (here, end, '}');
321 if (it == end) return false;
322
323 text_t com = substr (here, it);
324 here = findchar (it, end, '{');
325 if (here == end) return false;
326 else here ++;
327
328 if (com == "If") formatlistptr->command = comIf;
329 else if (com == "Or") formatlistptr->command = comOr;
330 else return false;
331
332 int commacount = 0;
333 text_t text;
334 while (here != end) {
335
336 if (*here == '\\') {
337 here++;
338 if (here != end) text.push_back(*here);
339
340 }
341
342 else if (*here == ',' || *here == '}' || *here == '{') {
343
344 if (formatlistptr->command == comOr) {
345 // the {Or}{this, or this, or this, or this} statement
346 format_t *or_ptr;
347
348 // find the next unused orptr
349 if (formatlistptr->orptr == NULL) {
350 formatlistptr->orptr = new format_t();
351 or_ptr = formatlistptr->orptr;
352 } else {
353 or_ptr = formatlistptr->orptr;
354 while (or_ptr->nextptr != NULL)
355 or_ptr = or_ptr->nextptr;
356 or_ptr->nextptr = new format_t();
357 or_ptr = or_ptr->nextptr;
358 }
359
360 if (!text.empty())
361 {
362 if (!parse_string(text, or_ptr, metadata, getParents)) { return false; }
363 }
364
365 if (*here == '{')
366 {
367 // Supports: {Or}{[Booktitle],[Title],{If}{[XXXX],aaa,bbb}}
368 // but not : {Or}{[Booktitle],[Title]{If}{[XXXX],aaa,bbb}}
369 // The latter can always be re-written:
370 // {Or}{[Booktitle],{If}{[Title],[Title]{If}{[XXXX],aaa,bbb}}}
371
372 if (!text.empty()) // already used up allocated format_t
373 {
374 // => allocate new one for detected action
375 or_ptr->nextptr = new format_t();
376 or_ptr = or_ptr->nextptr;
377 }
378 if (!parse_action(++here, end, or_ptr, metadata, getParents))
379 {
380 return false;
381 }
382 }
383 else
384 {
385 if (*here == '}') break;
386 }
387 text.clear();
388
389 }
390
391 // Parse an {If}{decide,do,else} statement
392 else {
393
394 // Read the decision component.
395 if (commacount == 0) {
396 // Decsion can be a metadata element, or a piece of text.
397 // Originally Stefan's code, updated 25/10/2000 by Gordon.
398
399 text_t::const_iterator beginbracket = text.begin();
400 text_t::const_iterator endbracket = (text.end() - 1);
401
402 // Decision is based on a metadata element
403 if ((*beginbracket == '[') && (*endbracket == ']')) {
404 // Ignore the surrounding square brackets
405 text_t meta = substr (beginbracket+1, endbracket);
406 parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
407 commacount ++;
408 text.clear();
409 }
410
411 // Decision is a piece of text (probably a macro like _cgiargmode_).
412 else {
413 formatlistptr->decision.command = dText;
414 formatlistptr->decision.text = text;
415 commacount ++;
416 text.clear();
417 }
418 }
419
420 // Read the "then" and "else" components of the {If} statement.
421 else {
422 format_t** nextlistptr = NULL;
423 if (commacount == 1) {
424 nextlistptr = &formatlistptr->ifptr;
425 } else if (commacount == 2 ) {
426 nextlistptr = &formatlistptr->elseptr;
427 } else {
428 return false;
429 }
430
431 if (!text.empty()) {
432 if (*nextlistptr == NULL) {
433 *nextlistptr = new format_t();
434 } else {
435
436 // skip to the end of any format_t statements already added
437 while ((*nextlistptr)->nextptr != NULL)
438 {
439 nextlistptr = &(*nextlistptr)->nextptr;
440 }
441
442 (*nextlistptr)->nextptr = new format_t();
443 nextlistptr = &(*nextlistptr)->nextptr;
444 }
445
446 if (!parse_string (text, *nextlistptr, metadata, getParents))
447 {
448 return false;
449 }
450 text.clear();
451 }
452
453 if (*here == '{')
454 {
455 if (*nextlistptr == NULL) {
456 *nextlistptr = new format_t();
457 } else {
458 (*nextlistptr)->nextptr = new format_t();
459 nextlistptr = &(*nextlistptr)->nextptr;
460 }
461
462 if (!parse_action(++here, end, *nextlistptr, metadata, getParents))
463 {
464 return false;
465 }
466 }
467 else
468 {
469 if (*here == '}') break;
470 commacount ++;
471 }
472 }
473 }
474
475 } else text.push_back(*here);
476
477 if (here != end) here ++;
478 }
479
480 return true;
481}
482
483
484bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr,
485 text_tset &metadata, bool &getParents) {
486
487 formatlistptr->clear();
488 getParents = false;
489
490 return (parse_string (formatstring, formatlistptr, metadata, getParents));
491}
492
493
494// note: all the format_date stuff is assuming that all Date metadata is going to
495// be of the form yyyymmdd, this is of course, crap ;)
496
497static text_t get_meta (ResultDocInfo_t &docinfo, const metadata_t &meta) {
498
499 // make sure we have the requested metadata
500 MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
501 if (it == docinfo.metadata.end()) return "";
502
503 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
504
505 switch (meta.parentcommand) {
506 case pNone:
507 {
508 text_t classifier_metaname = docinfo.classifier_metadata_type;
509 int metaname_index
510 = (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
511 text_t metadata_item = docinfo.metadata[meta.metaname].values[metaname_index];
512
513 if (meta.metaname == "Date")
514 return format_date (metadata_item);
515 if (meta.metacommand == mCgiSafe)
516 return cgi_safe (metadata_item);
517 else return metadata_item;
518 }
519
520 case pImmediate:
521 if (parent != NULL) {
522 if (meta.metaname == "Date")
523 return format_date (parent->values[0]);
524 if (meta.metacommand == mCgiSafe)
525 return cgi_safe (parent->values[0]);
526 else return parent->values[0];
527 }
528 break;
529
530 case pTop:
531 if (parent != NULL) {
532 while (parent->parent != NULL) parent = parent->parent;
533
534 if (meta.metaname == "Date")
535 return format_date (parent->values[0]);
536 if (meta.metacommand == mCgiSafe)
537 return cgi_safe (parent->values[0]);
538 else return parent->values[0];
539 }
540 break;
541
542 case pAll:
543 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
544 if (parent != NULL) {
545 text_tarray tmparray;
546 while (parent != NULL) {
547 tmparray.push_back (parent->values[0]);
548 parent = parent->parent;
549 }
550 bool first = true;
551 text_t tmp;
552 text_tarray::reverse_iterator here = tmparray.rbegin();
553 text_tarray::reverse_iterator end = tmparray.rend();
554 while (here != end) {
555 if (!first) tmp += meta.parentoptions;
556 if (meta.metaname == "Date") tmp += format_date (*here);
557 else tmp += *here;
558 first = false;
559 here ++;
560 }
561 if (meta.metacommand == mCgiSafe) return cgi_safe (tmp);
562 else return tmp;
563 }
564 }
565 return "";
566}
567
568static text_t get_or (const text_t& collection, recptproto* collectproto,
569 ResultDocInfo_t &docinfo, displayclass &disp,
570 format_t *orptr,
571 const text_t &link, const text_t &icon,
572 const text_t &text, bool highlight,
573 ostream& logout) {
574
575 text_t tmp;
576 while (orptr != NULL) {
577
578 tmp = format_string (collection,collectproto, docinfo, disp, orptr,
579 link, icon, text, highlight, logout);
580 if (!tmp.empty()) return tmp;
581
582 orptr = orptr->nextptr;
583 }
584 return "";
585}
586
587static text_t get_if (const text_t& collection, recptproto* collectproto,
588 ResultDocInfo_t &docinfo, displayclass &disp,
589 const decision_t &decision,
590 format_t *ifptr, format_t *elseptr, const text_t &link,
591 const text_t &icon, const text_t &text, bool highlight,
592 ostream& logout)
593{
594
595 // If the decision component is a metadata element, then evaluate it
596 // to see whether we output the "then" or the "else" clause
597 if (decision.command == dMeta) {
598 if (get_meta (docinfo, decision.meta) != "") {
599 if (ifptr != NULL)
600 return get_formatted_string (collection,collectproto, docinfo, disp, ifptr,
601 link, icon, text, highlight, logout);
602 }
603 else {
604 if (elseptr != NULL)
605 return get_formatted_string (collection,collectproto, docinfo, disp, elseptr,
606 link, icon, text, highlight, logout);
607 }
608 }
609
610 // If the decision component is text, then evaluate it (it is probably a
611 // macro like _cgiargmode_) to decide what to output.
612 else if (decision.command == dText) {
613
614 text_t outstring;
615 disp.expandstring (decision.text, outstring);
616
617 // This is a tad tricky. When we expand a string like _cgiargmode_, that is
618 // a cgi argument macro that has not been set, it evaluates to itself.
619 // Therefore, were have to say that a piece of text evalautes true if
620 // it is non-empty and if it is a cgi argument evaulating to itself.
621 if ((outstring != "") && !((outstring == decision.text) && (outstring[0] == '_'))) {
622 if (ifptr != NULL)
623 return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
624 link, icon, text, highlight, logout);
625 } else {
626 if (elseptr != NULL)
627 return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
628 link, icon, text, highlight, logout);
629 }
630 }
631
632 return "";
633}
634
635bool includes_metadata(const text_t& text)
636{
637 text_t::const_iterator here = text.begin();
638 text_t::const_iterator end = text.end();
639 while (here != end) {
640 if (*here == '[') return true;
641 here ++;
642 }
643
644 return false;
645}
646
647text_t format_string (const text_t& collection, recptproto* collectproto,
648 ResultDocInfo_t &docinfo, displayclass &disp,
649 format_t *formatlistptr,
650 const text_t &link, const text_t &icon,
651 const text_t &text, bool highlight,
652 ostream& logout) {
653
654 if (formatlistptr == NULL) return "";
655
656 switch (formatlistptr->command) {
657 case comText:
658 return formatlistptr->text;
659 case comLink:
660 return link;
661 case comEndLink:
662 if (link.empty()) return "";
663 else return "</a>";
664 case comIcon:
665 return icon;
666 case comNum:
667 return docinfo.result_num;
668 case comMeta:
669
670 {
671 const text_t& metavalue = get_meta (docinfo, formatlistptr->meta);
672
673 if (includes_metadata(metavalue))
674 {
675 // text has embedded metadata in it => expand it
676 FilterRequest_t request;
677 FilterResponse_t response;
678
679 request.getParents = false;
680
681 format_t *expanded_formatlistptr = new format_t();
682 parse_formatstring (metavalue, expanded_formatlistptr,
683 request.fields, request.getParents);
684
685 // retrieve metadata
686 get_info(docinfo.OID, collection, request.fields, request.getParents,
687 collectproto, response, logout);
688
689 if (!response.docInfo.empty())
690 {
691 text_t expanded_metavalue
692 = get_formatted_string(collection, collectproto,
693 response.docInfo[0], disp, expanded_formatlistptr,
694 link,icon,highlight,
695 logout);
696
697 return expanded_metavalue;
698 }
699 else
700 {
701 return metavalue;
702 }
703 }
704 else
705 {
706 return metavalue;
707 }
708 }
709 case comDoc:
710 return text;
711 case comHighlight:
712 if (highlight) return "<b>";
713 break;
714 case comEndHighlight:
715 if (highlight) return "</b>";
716 break;
717 case comIf:
718 return get_if (collection, collectproto, docinfo, disp,
719 formatlistptr->decision, formatlistptr->ifptr,
720 formatlistptr->elseptr, link, icon, text, highlight,
721 logout);
722 case comOr:
723 return get_or (collection,collectproto, docinfo, disp, formatlistptr->orptr,
724 link, icon, text, highlight, logout);
725 }
726 return "";
727}
728
729
730
731
732text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
733 ResultDocInfo_t& docinfo, displayclass &disp,
734 format_t* formatlistptr,
735 const text_t& link, const text_t& icon,
736 const text_t& text, const bool highlight,
737 ostream& logout) {
738
739 text_t ft;
740 while (formatlistptr != NULL)
741 {
742 ft += format_string (collection, collectproto, docinfo, disp, formatlistptr,
743 link, icon, text, highlight, logout);
744 formatlistptr = formatlistptr->nextptr;
745 }
746
747 return ft;
748}
749
750text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
751 ResultDocInfo_t &docinfo, displayclass &disp,
752 format_t *formatlistptr,
753 const text_t &link, const text_t &icon,
754 const bool highlight,
755 ostream& logout) {
756
757 text_t text = "";
758
759 return get_formatted_string(collection, collectproto, docinfo, disp, formatlistptr,
760 link, icon, text, highlight, logout);
761}
762
763text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
764 ResultDocInfo_t &docinfo, displayclass &disp,
765 format_t *formatlistptr,
766 const text_t& text,
767 ostream& logout) {
768
769 text_t link = "<a href=\"_httpdocument_&cl=search&d=" + docinfo.OID + "\">";
770 text_t icon = "_icontext_";
771 bool highlight = false;
772
773 return get_formatted_string(collection, collectproto, docinfo, disp, formatlistptr,
774 link, icon, text, highlight, logout);
775}
776
777text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
778 ResultDocInfo_t &docinfo, displayclass &disp,
779 format_t *formatlistptr,
780 ostream& logout) {
781
782 text_t text = "";
783
784 return get_formatted_string(collection, collectproto, docinfo, disp, formatlistptr,
785 text, logout);
786}
787
788
789
790
791
792
793
Note: See TracBrowser for help on using the repository browser.