source: branches/corba/gsdl/src/recpt/formattools.cpp@ 1074

Last change on this file since 1074 was 1059, checked in by sjboddie, 24 years ago

replaced old DocumentIcon and DocumentContents format options
with DocumentColumn stuff

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 19.9 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 * $Id: formattools.cpp 1059 2000-04-03 07:28:25Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.19 2000/04/03 07:28:24 sjboddie
31 replaced old DocumentIcon and DocumentContents format options
32 with DocumentColumn stuff
33
34 Revision 1.18 2000/03/31 03:04:31 nzdl
35 tidied up some of the browsing code - replaced DocumentImages,
36 DocumentTitles and DocumentHeading with DocumentIcon
37
38 Revision 1.17 2000/01/26 20:10:31 sjboddie
39 changed the default order of detach/expand/highlight buttons
40
41 Revision 1.16 2000/01/25 22:33:31 sjboddie
42 added DocumentUseHTML
43
44 Revision 1.15 1999/12/13 02:45:16 davidb
45 Support for more than one metavalue for the same metadata name
46
47 Revision 1.14 1999/10/30 22:23:11 sjboddie
48 moved table functions from browsetools
49
50 Revision 1.13 1999/10/14 23:01:24 sjboddie
51 changes for new browsing support
52
53 Revision 1.12 1999/10/10 08:14:07 sjboddie
54 - metadata now returns mp rather than array
55 - redesigned browsing support (although it's not finished so
56 won't currently work ;-)
57
58 Revision 1.11 1999/09/28 20:38:19 rjmcnab
59 fixed a couple of bugs
60
61 Revision 1.10 1999/09/07 04:56:55 sjboddie
62 added GPL notice
63
64 Revision 1.9 1999/09/02 00:31:25 rjmcnab
65 fixed small error.
66
67 Revision 1.8 1999/08/20 00:56:38 sjboddie
68 added cgisafe option - you can now do something like [cgisafe:Title] if
69 you want Title to be entered safely into a url
70
71 Revision 1.7 1999/08/10 22:38:08 sjboddie
72 added some more format options
73
74 Revision 1.6 1999/07/30 02:25:42 sjboddie
75 made format_date function global
76
77 Revision 1.5 1999/07/21 05:00:00 sjboddie
78 added some date formatting
79
80 Revision 1.4 1999/07/20 03:02:15 sjboddie
81 added an [icon] option, added ability to call get_formatted_string
82 with icon and link arguments set
83
84 Revision 1.3 1999/07/09 02:44:35 sjboddie
85 fixed parent(All) function so it only outputs parents and not current
86 level meta
87
88 Revision 1.2 1999/07/08 20:48:33 rjmcnab
89 Added ability to print the result number
90
91 Revision 1.1 1999/07/07 05:49:34 sjboddie
92 had another crack at the format string code - created a new formattools
93 module. It can now handle {If} and {Or} statements although there's a
94 bug preventing nested if's and or's.
95
96 */
97
98
99#include "formattools.h"
100#include "cgiutils.h"
101
102// a few function prototypes
103static text_t format_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
104 const text_t &link, const text_t &icon,
105 const text_t &text, bool highlight);
106
107static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
108 format_t *formatlistptr, text_tset &metadata, bool &getParents);
109
110void metadata_t::clear() {
111 metaname.clear();
112 metacommand = mNone;
113 parentcommand = pNone;
114 parentoptions.clear();
115}
116
117void decision_t::clear() {
118 command = dMeta;
119 meta.clear();
120}
121
122void format_t::clear() {
123 command = comText;
124 decision.clear();
125 text.clear();
126 meta.clear();
127 nextptr = NULL;
128 ifptr = NULL;
129 elseptr = NULL;
130 orptr = NULL;
131}
132
133void formatinfo_t::clear() {
134 DocumentColumns = "2";
135 DocumentColumnsTotalWidth = "_pagewidth_";
136 DocumentColumnLeft = "[Title]<br>[Buttons]";
137 DocumentColumnLeftWidth = "200";
138 DocumentColumnRight = "[TOC]";
139 DocumentArrowsBottom = true;
140 DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
141 DocumentButtons.push_back ("Expand Text");
142 DocumentButtons.push_back ("Expand Contents");
143 DocumentButtons.push_back ("Detach");
144 DocumentButtons.push_back ("Highlight");
145 DocumentText = "[Text]";
146 formatstrings.erase (formatstrings.begin(), formatstrings.end());
147 DocumentUseHTML = false;
148}
149
150// simply checks to see if formatstring begins with a <td> tag
151bool is_table_content (const text_t &formatstring) {
152 text_t::const_iterator here = formatstring.begin();
153 text_t::const_iterator end = formatstring.end();
154
155 while (here != end) {
156 if (*here != ' ') {
157 if (*here == '<') {
158 if ((*(here+1) == 't' || *(here+1) == 'T') &&
159 (*(here+2) == 'd' || *(here+2) == 'D') &&
160 (*(here+3) == '>' || *(here+3) == ' '))
161 return true;
162 } else return false;
163 }
164 here ++;
165 }
166 return false;
167}
168
169bool is_table_content (const format_t *formatlistptr) {
170
171 if (formatlistptr == NULL) return false;
172
173 if (formatlistptr->command == comText)
174 return is_table_content (formatlistptr->text);
175
176 return false;
177}
178
179// returns false if key isn't in formatstringmap
180bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
181 text_t &formatstring) {
182
183 formatstring.clear();
184 text_tmap::const_iterator it = formatstringmap.find(key);
185 if (it == formatstringmap.end()) return false;
186 formatstring = (*it).second;
187 return true;
188}
189
190// tries to find "key1key2" then "key1" then "key2"
191bool get_formatstring (const text_t &key1, const text_t &key2,
192 const text_tmap &formatstringmap,
193 text_t &formatstring) {
194
195 formatstring.clear();
196 text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
197 if (it != formatstringmap.end()) {
198 formatstring = (*it).second;
199 return true;
200 }
201 it = formatstringmap.find(key1);
202 if (it != formatstringmap.end()) {
203 formatstring = (*it).second;
204 return true;
205 }
206 it = formatstringmap.find(key2);
207 if (it != formatstringmap.end()) {
208 formatstring = (*it).second;
209 return true;
210 }
211 return false;
212}
213
214
215// returns a date of form _textmonthnn_ 31, 1999
216// input is date of type 19991231
217// at least the year must be present in date
218text_t format_date (const text_t &date) {
219
220 if (date.size() < 4) return "";
221
222 text_t::const_iterator datebegin = date.begin();
223
224 text_t year = substr (datebegin, datebegin+4);
225
226 if (date.size() < 6) return year;
227
228 text_t month = "_textmonth" + substr (datebegin+4, datebegin+6) + "_";
229 int imonth = month.getint();
230 if (imonth < 0 || imonth > 12) return year;
231
232 if (date.size() < 8) return month + ", " + year;
233
234 text_t day = substr (datebegin+6, datebegin+8);
235 if (day[0] == '0') day = substr (day.begin()+1, day.end());
236 int iday = day.getint();
237 if (iday < 0 || iday > 31) return month + ", " + year;
238
239 return month + " " + day + ", " + year;
240}
241
242static void get_parent_options (text_t &instring, metadata_t &metaoption) {
243
244 text_t meta, com, op;
245 bool inbraces = false;
246 bool inquotes = false;
247 bool foundcolon = false;
248 text_t::const_iterator here = instring.begin()+6;
249 text_t::const_iterator end = instring.end();
250 while (here != end) {
251 if (*here == '(') inbraces = true;
252 else if (*here == ')') inbraces = false;
253 else if (*here == '\'' && !inquotes) inquotes = true;
254 else if (*here == '\'' && inquotes) inquotes = false;
255 else if (*here == ':' && !inbraces) foundcolon = true;
256 else if (foundcolon) meta.push_back (*here);
257 else if (inquotes) op.push_back (*here);
258 else com.push_back (*here);
259 here ++;
260 }
261 instring = meta;
262 if (com.empty())
263 metaoption.parentcommand = pImmediate;
264 else if (com == "Top")
265 metaoption.parentcommand = pTop;
266 else if (com == "All") {
267 metaoption.parentcommand = pAll;
268 metaoption.parentoptions = op;
269 }
270}
271
272static void parse_meta (text_t &meta, metadata_t &metaoption,
273 text_tset &metadata, bool &getParents) {
274
275 if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
276 metaoption.metacommand = mCgiSafe;
277 meta = substr (meta.begin()+8, meta.end());
278 }
279
280 if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
281 getParents = true;
282 get_parent_options (meta, metaoption);
283 }
284
285 metadata.insert (meta);
286 metaoption.metaname = meta;
287}
288
289static void parse_meta (text_t &meta, format_t *formatlistptr,
290 text_tset &metadata, bool &getParents) {
291
292 if (meta == "link")
293 formatlistptr->command = comLink;
294 else if (meta == "/link")
295 formatlistptr->command = comEndLink;
296
297 else if (meta == "num")
298 formatlistptr->command = comNum;
299
300 else if (meta == "icon")
301 formatlistptr->command = comIcon;
302
303 else if (meta == "Text")
304 formatlistptr->command = comDoc;
305
306 else if (meta == "highlight")
307 formatlistptr->command = comHighlight;
308
309 else if (meta == "/highlight")
310 formatlistptr->command = comEndHighlight;
311
312 else {
313 formatlistptr->command = comMeta;
314 parse_meta (meta, formatlistptr->meta, metadata, getParents);
315 }
316}
317
318static bool parse_string (const text_t &formatstring, format_t *formatlistptr,
319 text_tset &metadata, bool &getParents) {
320
321 text_t text;
322 text_t::const_iterator here = formatstring.begin();
323 text_t::const_iterator end = formatstring.end();
324
325 while (here != end) {
326
327 if (*here == '\\')
328 text.push_back (*(++here));
329
330 else if (*here == '{') {
331 if (!text.empty()) {
332 formatlistptr->command = comText;
333 formatlistptr->text = text;
334 formatlistptr->nextptr = new format_t();
335 formatlistptr = formatlistptr->nextptr;
336
337 text.clear();
338 }
339 if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
340 formatlistptr->nextptr = new format_t();
341 formatlistptr = formatlistptr->nextptr;
342 if (here == end) break;
343 }
344 } else if (*here == '[') {
345 if (!text.empty()) {
346 formatlistptr->command = comText;
347 formatlistptr->text = text;
348 formatlistptr->nextptr = new format_t();
349 formatlistptr = formatlistptr->nextptr;
350
351 text.clear();
352 }
353 text_t meta;
354 here ++;
355 while (*here != ']') {
356 if (here == end) return false;
357 meta.push_back (*here);
358 here ++;
359 }
360 parse_meta (meta, formatlistptr, metadata, getParents);
361 formatlistptr->nextptr = new format_t();
362 formatlistptr = formatlistptr->nextptr;
363
364 } else
365 text.push_back (*here);
366
367 if (here != end) here ++;
368 }
369 if (!text.empty()) {
370 formatlistptr->command = comText;
371 formatlistptr->text = text;
372 formatlistptr->nextptr = new format_t();
373 formatlistptr = formatlistptr->nextptr;
374
375 }
376 return true;
377}
378
379
380static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
381 format_t *formatlistptr, text_tset &metadata, bool &getParents) {
382
383 text_t::const_iterator it = findchar (here, end, '}');
384 if (it == end) return false;
385
386 text_t com = substr (here, it);
387 here = findchar (it, end, '{');
388 if (here == end) return false;
389 else here ++;
390
391 if (com == "If") formatlistptr->command = comIf;
392 else if (com == "Or") formatlistptr->command = comOr;
393 else return false;
394
395 int curlycount = 0;
396 int commacount = 0;
397 text_t text;
398 while (here != end) {
399
400 if (*here == '\\') {
401 here++;
402 if (here != end) text.push_back(*here);
403
404 } else if (*here == '{') {curlycount ++; text.push_back(*here);}
405 else if (*here == '}' && curlycount > 0) {
406 curlycount --;
407 text.push_back(*here);
408 }
409
410 else if ((*here == ',' || *here == '}') && curlycount <= 0) {
411
412 if (formatlistptr->command == comOr) {
413 // the {Or}{this, or this, or this, or this} statement
414 // or'ed statements may be either [metadata] or plain text
415 format_t *or_ptr;
416
417 // find the next unused orptr
418 if (formatlistptr->orptr == NULL) {
419 formatlistptr->orptr = new format_t();
420 or_ptr = formatlistptr->orptr;
421 } else {
422 or_ptr = formatlistptr->orptr;
423 while (or_ptr->nextptr != NULL)
424 or_ptr = or_ptr->nextptr;
425 or_ptr->nextptr = new format_t();
426 or_ptr = or_ptr->nextptr;
427 }
428
429 text_t::const_iterator beginbracket = text.begin();
430 text_t::const_iterator endbracket = (text.end() - 1);
431 if ((*beginbracket == '[') && (*endbracket == ']')) {
432 // it's metadata
433 text_t meta = substr (beginbracket+1, endbracket);
434 parse_meta (meta, or_ptr, metadata, getParents);
435
436 } else {
437 // assume it's plain text
438 or_ptr->command = comText;
439 or_ptr->text = text;
440 }
441 text.clear();
442
443 } else {
444 // the {If}{decide,do,else} statement
445 if (commacount == 0) {
446 // If decision only supports metadata at present
447
448 // remove the surrounding square brackets
449 text_t::const_iterator beginbracket = text.begin();
450 text_t::const_iterator endbracket = (text.end() - 1);
451 if ((*beginbracket == '[') && (*endbracket == ']')) {
452 text_t meta = substr (beginbracket+1, endbracket);
453 parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
454 commacount ++;
455 text.clear();
456 }
457
458 } else if (commacount == 1) {
459 formatlistptr->ifptr = new format_t();
460 parse_string (text, formatlistptr->ifptr, metadata, getParents);
461 commacount ++;
462 text.clear();
463
464 } else if (commacount == 2) {
465 formatlistptr->elseptr = new format_t();
466 parse_string (text, formatlistptr->elseptr, metadata, getParents);
467 commacount ++;
468 text.clear();
469 }
470 }
471 if (*here == '}') break;
472
473 } else text.push_back(*here);
474
475 if (here != end) here ++;
476 }
477
478 return true;
479}
480
481
482bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr,
483 text_tset &metadata, bool &getParents) {
484
485 formatlistptr->clear();
486 getParents = false;
487
488 return (parse_string (formatstring, formatlistptr, metadata, getParents));
489}
490
491
492// note: all the format_date stuff is assuming that all Date metadata is going to
493// be of the form yyyymmdd, this is of course, crap ;)
494
495static text_t get_meta (ResultDocInfo_t &docinfo, const metadata_t &meta) {
496
497 // make sure we have the requested metadata
498 MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
499 if (it == docinfo.metadata.end()) return "";
500
501 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
502
503 switch (meta.parentcommand) {
504 case pNone:
505 {
506 text_t classifier_metaname = docinfo.classifier_metadata_type;
507 int metaname_index
508 = (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
509 text_t metadata_item = docinfo.metadata[meta.metaname].values[metaname_index];
510
511 if (meta.metaname == "Date")
512 return format_date (metadata_item);
513 if (meta.metacommand == mCgiSafe)
514 return cgi_safe (metadata_item);
515 else return metadata_item;
516 }
517
518 case pImmediate:
519 if (parent != NULL) {
520 if (meta.metaname == "Date")
521 return format_date (parent->values[0]);
522 if (meta.metacommand == mCgiSafe)
523 return cgi_safe (parent->values[0]);
524 else return parent->values[0];
525 }
526 break;
527
528 case pTop:
529 if (parent != NULL) {
530 while (parent->parent != NULL) parent = parent->parent;
531
532 if (meta.metaname == "Date")
533 return format_date (parent->values[0]);
534 if (meta.metacommand == mCgiSafe)
535 return cgi_safe (parent->values[0]);
536 else return parent->values[0];
537 }
538 break;
539
540 case pAll:
541 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
542 if (parent != NULL) {
543 text_tarray tmparray;
544 while (parent != NULL) {
545 tmparray.push_back (parent->values[0]);
546 parent = parent->parent;
547 }
548 bool first = true;
549 text_t tmp;
550 text_tarray::reverse_iterator here = tmparray.rbegin();
551 text_tarray::reverse_iterator end = tmparray.rend();
552 while (here != end) {
553 if (!first) tmp += meta.parentoptions;
554 if (meta.metaname == "Date") tmp += format_date (*here);
555 else tmp += *here;
556 first = false;
557 here ++;
558 }
559 if (meta.metacommand == mCgiSafe) return cgi_safe (tmp);
560 else return tmp;
561 }
562 }
563 return "";
564}
565
566static text_t get_or (ResultDocInfo_t &docinfo, format_t *orptr,
567 const text_t &link, const text_t &icon,
568 const text_t &text, bool highlight) {
569
570 text_t tmp;
571 while (orptr != NULL) {
572
573 tmp = format_string (docinfo, orptr, link, icon, text, highlight);
574 if (!tmp.empty()) return tmp;
575
576 orptr = orptr->nextptr;
577 }
578 return "";
579}
580
581static text_t get_if (ResultDocInfo_t &docinfo, const decision_t &decision,
582 format_t *ifptr, format_t *elseptr, const text_t &link,
583 const text_t &icon, const text_t &text, bool highlight) {
584
585 // not much of a choice yet ...
586 if (decision.command == dMeta) {
587 if (get_meta (docinfo, decision.meta) != "") {
588 if (ifptr != NULL)
589 return get_formatted_string (docinfo, ifptr, link, icon, text, highlight);
590 }
591 else {
592 if (elseptr != NULL)
593 return get_formatted_string (docinfo, elseptr, link, icon, text, highlight);
594 }
595 }
596 return "";
597}
598
599text_t format_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
600 const text_t &link, const text_t &icon,
601 const text_t &text, bool highlight) {
602
603 if (formatlistptr == NULL) return "";
604
605 switch (formatlistptr->command) {
606 case comText:
607 return formatlistptr->text;
608 case comLink:
609 return link;
610 case comEndLink:
611 if (link.empty()) return "";
612 else return "</a>";
613 case comIcon:
614 return icon;
615 case comNum:
616 return docinfo.result_num;
617 case comMeta:
618 return get_meta (docinfo, formatlistptr->meta);
619 case comDoc:
620 return text;
621 case comHighlight:
622 if (highlight) return "<b>";
623 break;
624 case comEndHighlight:
625 if (highlight) return "</b>";
626 break;
627 case comIf:
628 return get_if (docinfo, formatlistptr->decision, formatlistptr->ifptr,
629 formatlistptr->elseptr, link, icon, text, highlight);
630 case comOr:
631 return get_or (docinfo, formatlistptr->orptr, link, icon, text, highlight);
632 }
633 return "";
634}
635
636
637text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
638 const text_t &link, const text_t &icon) {
639
640 text_t text;
641
642 text_t ft;
643 while (formatlistptr != NULL) {
644 ft += format_string (docinfo, formatlistptr, link, icon, text, false);
645 formatlistptr = formatlistptr->nextptr;
646 }
647 return ft;
648}
649
650
651text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr) {
652
653 text_t link = "<a href=\"_httpdocument_&cl=search&d=" + docinfo.OID + "\">";
654 text_t icon = "_icontext_";
655 text_t text;
656
657 text_t ft;
658 while (formatlistptr != NULL) {
659 ft += format_string (docinfo, formatlistptr, link, icon, text, false);
660 formatlistptr = formatlistptr->nextptr;
661 }
662 return ft;
663}
664
665
666text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
667 const text_t &text) {
668
669 text_t link = "<a href=\"_httpdocument_&cl=search&d=" + docinfo.OID + "\">";
670 text_t icon = "_icontext_";
671
672 text_t ft;
673 while (formatlistptr != NULL) {
674 ft += format_string (docinfo, formatlistptr, link, icon, text, false);
675 formatlistptr = formatlistptr->nextptr;
676 }
677 return ft;
678}
679
680
681text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
682 const text_t &link, const text_t &icon, const text_t &text) {
683
684 text_t ft;
685 while (formatlistptr != NULL) {
686 ft += format_string (docinfo, formatlistptr, link, icon, text, false);
687 formatlistptr = formatlistptr->nextptr;
688 }
689 return ft;
690}
691
692text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
693 const text_t &link, const text_t &icon, bool highlight) {
694
695 text_t text, ft;
696 while (formatlistptr != NULL) {
697 ft += format_string (docinfo, formatlistptr, link, icon, text, highlight);
698 formatlistptr = formatlistptr->nextptr;
699 }
700 return ft;
701}
702
703text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
704 const text_t &link, const text_t &icon,
705 const text_t &text, bool highlight) {
706
707 text_t ft;
708 while (formatlistptr != NULL) {
709 ft += format_string (docinfo, formatlistptr, link, icon, text, highlight);
710 formatlistptr = formatlistptr->nextptr;
711 }
712 return ft;
713}
714
715
Note: See TracBrowser for help on using the repository browser.