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

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

added GPL notice

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