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

Last change on this file since 749 was 749, checked in by sjboddie, 25 years ago

moved table functions from browsetools

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