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

Last change on this file since 636 was 636, checked in by rjmcnab, 25 years ago

fixed a couple of bugs

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