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

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

added some date formatting

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