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

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

changes for new browsing support

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