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

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

changed the default order of detach/expand/highlight buttons

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