source: trunk/gsdl/src/recpt/queryaction.cpp@ 622

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

EndResults query filter option may now take '-1' for 'all'

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.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: queryaction.cpp 622 1999-09-22 03:44:31Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.24 1999/09/22 03:44:31 sjboddie
31 EndResults query filter option may now take '-1' for 'all'
32
33 Revision 1.23 1999/09/21 11:34:42 sjboddie
34 added Maxdocs queryfilter option which may be -1 for 'all'
35
36 Revision 1.22 1999/09/07 23:08:51 rjmcnab
37 removed some compiler warnings
38
39 Revision 1.21 1999/09/07 04:56:57 sjboddie
40 added GPL notice
41
42 Revision 1.20 1999/08/25 04:47:55 sjboddie
43 added advanced search option - other minor changes
44
45 Revision 1.19 1999/08/13 04:17:24 sjboddie
46 small change to do with new collection-level metadata
47
48 Revision 1.18 1999/08/10 22:46:33 sjboddie
49 changed format option result to QueryResults and added QueryLinks option
50
51 Revision 1.17 1999/07/30 02:24:42 sjboddie
52 added collectinfo argument to some functions
53
54 Revision 1.16 1999/07/19 00:16:58 sjboddie
55 no longer display documents that don't match all phrases in query string
56
57 Revision 1.15 1999/07/16 08:33:36 rjmcnab
58 Changed the logic for getting the results string slightly
59
60 Revision 1.14 1999/07/16 03:41:29 sjboddie
61 changed isApprox
62
63 Revision 1.13 1999/07/16 00:19:01 sjboddie
64 some changes to the way quoted queries are handled
65
66 Revision 1.12 1999/07/09 02:17:55 rjmcnab
67 Setting macros needed for a second query.
68
69 Revision 1.11 1999/07/07 06:13:10 rjmcnab
70 Added ability to combine two independant queries.
71
72 Revision 1.10 1999/07/07 05:49:35 sjboddie
73 had another crack at the format string code - created a new formattools
74 module. It can now handle {If} and {Or} statements although there's a
75 bug preventing nested if's and or's.
76
77 Revision 1.9 1999/07/01 22:48:46 sjboddie
78 had a go at getting a query result format string working
79
80 Revision 1.8 1999/06/27 22:02:11 sjboddie
81 author is added to queryresults if there is one
82
83 Revision 1.7 1999/06/26 01:10:18 rjmcnab
84 Made h, i, and n arguments saved in the compressed arguments.
85
86 Revision 1.6 1999/06/24 05:12:25 sjboddie
87 lots of small changes
88
89 Revision 1.5 1999/06/16 04:03:48 sjboddie
90 Now sets "cl" arg to "search" when going to a document from a search
91 results page. This allows the close book icon (in hierarchy toc) to
92 take you back to the results page if that's where you came from.
93 If you got to the document page somehow other than from a
94 classification or a search (i.e. if "cl" isn't set) then the close
95 book icon is disabled
96
97 Revision 1.4 1999/06/16 02:08:38 sjboddie
98 got queryaction working
99
100 Revision 1.3 1999/03/25 03:06:45 sjboddie
101
102 altered receptionist slightly so it now passes *collectproto to
103 define_internal_macros and define_external_macros - need it
104 for browseaction
105
106 Revision 1.2 1999/03/03 20:26:50 rjmcnab
107
108 Modified stuff.
109
110 Revision 1.1 1999/02/28 22:45:21 rjmcnab
111
112 Initial revision.
113
114 */
115
116
117#include "queryaction.h"
118#include "querytools.h"
119#include "formattools.h"
120
121queryaction::queryaction () {
122
123 num_phrases = 0;
124
125 // this action uses cgi variable "a"
126 cgiarginfo arg_ainfo;
127 arg_ainfo.shortname = "a";
128 arg_ainfo.longname = "action";
129 arg_ainfo.multiplechar = true;
130 arg_ainfo.defaultstatus = cgiarginfo::weak;
131 arg_ainfo.argdefault = "q";
132 arg_ainfo.savedarginfo = cgiarginfo::must;
133 argsinfo.addarginfo (NULL, arg_ainfo);
134
135 // "b" - 0 = simple, 1 = advanced
136 arg_ainfo.shortname = "b";
137 arg_ainfo.longname = "query mode";
138 arg_ainfo.multiplechar = false;
139 arg_ainfo.defaultstatus = cgiarginfo::weak;
140 arg_ainfo.argdefault = "0";
141 arg_ainfo.savedarginfo = cgiarginfo::must;
142 argsinfo.addarginfo (NULL, arg_ainfo);
143
144 // "h"
145 arg_ainfo.shortname = "h";
146 arg_ainfo.longname = "main index";
147 arg_ainfo.multiplechar = true;
148 arg_ainfo.defaultstatus = cgiarginfo::weak;
149 arg_ainfo.argdefault = "";
150 arg_ainfo.savedarginfo = cgiarginfo::must;
151 argsinfo.addarginfo (NULL, arg_ainfo);
152
153 // "h2"
154 arg_ainfo.shortname = "h2";
155 arg_ainfo.longname = "main index for second query";
156 arg_ainfo.multiplechar = true;
157 arg_ainfo.defaultstatus = cgiarginfo::weak;
158 arg_ainfo.argdefault = "";
159 arg_ainfo.savedarginfo = cgiarginfo::must;
160 argsinfo.addarginfo (NULL, arg_ainfo);
161
162 // "j"
163 arg_ainfo.shortname = "j";
164 arg_ainfo.longname = "sub collection index";
165 arg_ainfo.multiplechar = true;
166 arg_ainfo.defaultstatus = cgiarginfo::weak;
167 arg_ainfo.argdefault = "";
168 arg_ainfo.savedarginfo = cgiarginfo::must;
169 argsinfo.addarginfo (NULL, arg_ainfo);
170
171 // "j2"
172 arg_ainfo.shortname = "j2";
173 arg_ainfo.longname = "sub collection index for second query";
174 arg_ainfo.multiplechar = true;
175 arg_ainfo.defaultstatus = cgiarginfo::weak;
176 arg_ainfo.argdefault = "";
177 arg_ainfo.savedarginfo = cgiarginfo::must;
178 argsinfo.addarginfo (NULL, arg_ainfo);
179
180 // "n"
181 arg_ainfo.shortname = "n";
182 arg_ainfo.longname = "language index";
183 arg_ainfo.multiplechar = true;
184 arg_ainfo.defaultstatus = cgiarginfo::weak;
185 arg_ainfo.argdefault = "";
186 arg_ainfo.savedarginfo = cgiarginfo::must;
187 argsinfo.addarginfo (NULL, arg_ainfo);
188
189 // "n2"
190 arg_ainfo.shortname = "n2";
191 arg_ainfo.longname = "language index for second query";
192 arg_ainfo.multiplechar = true;
193 arg_ainfo.defaultstatus = cgiarginfo::weak;
194 arg_ainfo.argdefault = "";
195 arg_ainfo.savedarginfo = cgiarginfo::must;
196 argsinfo.addarginfo (NULL, arg_ainfo);
197
198 // "q"
199 arg_ainfo.shortname = "q";
200 arg_ainfo.longname = "query string";
201 arg_ainfo.multiplechar = true;
202 arg_ainfo.defaultstatus = cgiarginfo::weak;
203 arg_ainfo.argdefault = "";
204 arg_ainfo.savedarginfo = cgiarginfo::must;
205 argsinfo.addarginfo (NULL, arg_ainfo);
206
207 // "q2"
208 arg_ainfo.shortname = "q2";
209 arg_ainfo.longname = "query string for second query";
210 arg_ainfo.multiplechar = true;
211 arg_ainfo.defaultstatus = cgiarginfo::weak;
212 arg_ainfo.argdefault = "";
213 arg_ainfo.savedarginfo = cgiarginfo::must;
214 argsinfo.addarginfo (NULL, arg_ainfo);
215
216 // "cq2" ""=don't combine, "and", "or", "not"
217 arg_ainfo.shortname = "cq2";
218 arg_ainfo.longname = "combine queries";
219 arg_ainfo.multiplechar = true;
220 arg_ainfo.defaultstatus = cgiarginfo::weak;
221 arg_ainfo.argdefault = "";
222 arg_ainfo.savedarginfo = cgiarginfo::must;
223 argsinfo.addarginfo (NULL, arg_ainfo);
224
225 // "t" - 1 = ranked 0 = boolean
226 arg_ainfo.shortname = "t";
227 arg_ainfo.longname = "search type";
228 arg_ainfo.multiplechar = false;
229 arg_ainfo.defaultstatus = cgiarginfo::weak;
230 arg_ainfo.argdefault = "1";
231 arg_ainfo.savedarginfo = cgiarginfo::must;
232 argsinfo.addarginfo (NULL, arg_ainfo);
233
234 // "k"
235 arg_ainfo.shortname = "k";
236 arg_ainfo.longname = "casefolding";
237 arg_ainfo.multiplechar = false;
238 arg_ainfo.defaultstatus = cgiarginfo::weak;
239 arg_ainfo.argdefault = "1";
240 arg_ainfo.savedarginfo = cgiarginfo::must;
241 argsinfo.addarginfo (NULL, arg_ainfo);
242
243 // "s"
244 arg_ainfo.shortname = "s";
245 arg_ainfo.longname = "stemming";
246 arg_ainfo.multiplechar = false;
247 arg_ainfo.defaultstatus = cgiarginfo::weak;
248 arg_ainfo.argdefault ="0";
249 arg_ainfo.savedarginfo = cgiarginfo::must;
250 argsinfo.addarginfo (NULL, arg_ainfo);
251
252 // "m"
253 arg_ainfo.shortname = "m";
254 arg_ainfo.longname = "maximum number of documents";
255 arg_ainfo.multiplechar = true;
256 arg_ainfo.defaultstatus = cgiarginfo::weak;
257 arg_ainfo.argdefault = "50";
258 arg_ainfo.savedarginfo = cgiarginfo::must;
259 argsinfo.addarginfo (NULL, arg_ainfo);
260
261 // "o"
262 arg_ainfo.shortname = "o";
263 arg_ainfo.longname = "hits per page";
264 arg_ainfo.multiplechar = true;
265 arg_ainfo.defaultstatus = cgiarginfo::weak;
266 arg_ainfo.argdefault = "20";
267 arg_ainfo.savedarginfo = cgiarginfo::must;
268 argsinfo.addarginfo (NULL, arg_ainfo);
269
270 // "r"
271 arg_ainfo.shortname = "r";
272 arg_ainfo.longname = "start results from";
273 arg_ainfo.multiplechar = true;
274 arg_ainfo.defaultstatus = cgiarginfo::weak;
275 arg_ainfo.argdefault = "1";
276 arg_ainfo.savedarginfo = cgiarginfo::must;
277 argsinfo.addarginfo (NULL, arg_ainfo);
278}
279
280void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
281 action::configure (key, cfgline);
282}
283
284bool queryaction::init (ostream &logout) {
285 return action::init (logout);
286}
287
288bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
289 ostream &logout) {
290
291 // check t argument
292 int arg_t = args.getintarg("t");
293 if (arg_t != 0 && arg_t != 1) {
294 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
295 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
296 if (tinfo != NULL) args["t"] = tinfo->argdefault;
297 }
298
299 // check k argument
300 int arg_k = args.getintarg("k");
301 if (arg_k != 0 && arg_k != 1) {
302 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
303 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
304 if (kinfo != NULL) args["k"] = kinfo->argdefault;
305 }
306
307 // check s argument
308 int arg_s = args.getintarg("s");
309 if (arg_s != 0 && arg_s != 1) {
310 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
311 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
312 if (sinfo != NULL) args["s"] = sinfo->argdefault;
313 }
314
315 // check m argument
316 int arg_m = args.getintarg("m");
317 if (arg_m < -1) {
318 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
319 cgiarginfo *minfo = argsinfo.getarginfo ("m");
320 if (minfo != NULL) args["m"] = minfo->argdefault;
321 }
322
323 // check o argument
324 int arg_o = args.getintarg("o");
325 if (arg_o < -1) {
326 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
327 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
328 if (oinfo != NULL) args["o"] = oinfo->argdefault;
329 }
330
331 // check r argument
332 int arg_r = args.getintarg("r");
333 if (arg_r < 1) {
334 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
335 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
336 if (rinfo != NULL) args["r"] = rinfo->argdefault;
337 }
338
339 return true;
340}
341
342void queryaction::get_cgihead_info (cgiargsclass &/*args*/, response_t &response,
343 text_t &response_data, ostream &/*logout*/) {
344 response = content;
345 response_data = "text/html";
346}
347
348void queryaction::define_internal_macros (const ColInfoResponse_t &/*collectinfo*/, displayclass &disp,
349 cgiargsclass &args, recptproto * /*collectproto*/,
350 ostream &/*logout*/) {
351
352 // define_internal_macros sets the following macros:
353
354 // _quotedquery_ the part of the query string that was quoted for post-processing
355
356
357
358 // The following macros are set later (in define_query_macros) as they can't be set until
359 // the query has been done.
360
361 // _freqmsg_ the term frequency string
362
363 // _resultline_ the "x documents matched the query" string
364
365 // _prevfirst_ these are used when setting up the links to previous/next
366 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
367 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
368 // _nextlast_
369 // _thisfirst_
370 // _thislast_
371
372
373 // get the quoted bits of the query string and set _quotedquery_
374 text_tarray phrases;
375 get_phrases (args["q"], phrases);
376 text_tarray::const_iterator phere = phrases.begin();
377 text_tarray::const_iterator pend = phrases.end();
378 bool first = true;
379 text_t quotedquery;
380 while (phere != pend) {
381 if (!first)
382 if ((phere +1) == pend) quotedquery += " and ";
383 else quotedquery += ", ";
384
385 quotedquery += "\"" + *phere + "\"";
386 first = false;
387 phere ++;
388 }
389 if (args.getintarg("s")) quotedquery += "_textstemon_";
390 disp.setmacro ("quotedquery", "query", quotedquery);
391
392 // we'll also set num_phrases here so we don't have to parse the
393 // querystring again later (we need to know this before outputting
394 // results so we don't include results for documents not containing
395 // all requested phrases).
396 num_phrases = phrases.size();
397
398}
399
400// sets the selection box macros _hselection_, _jselection_, and _nselection_.
401void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
402 const FilterOption_t &option, displayclass &disp) {
403
404 if (option.validValues.size() < 2) return;
405
406 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
407
408 if (current_value.empty()) current_value = option.defaultValue;
409
410 text_tarray::const_iterator thisvalue = option.validValues.begin();
411 text_tarray::const_iterator endvalue = option.validValues.end();
412
413 while (thisvalue != endvalue) {
414 macrovalue += "<option value=\"" + *thisvalue + "\"";
415 if (*thisvalue == current_value)
416 macrovalue += " selected";
417 macrovalue += ">_" + *thisvalue + "_\n";
418 thisvalue ++;
419 }
420 macrovalue += "</select>\n";
421 disp.setmacro (macroname + "selection", "Global", macrovalue);
422}
423
424void queryaction::define_external_macros (const ColInfoResponse_t &/*collectinfo*/, displayclass &disp,
425 cgiargsclass &args, recptproto *collectproto,
426 ostream &logout) {
427
428 // define_external_macros sets the following macros:
429
430 // some or all of these may not be required to be set
431 // _hselection_, _h2selection_ the selection box for the main part of the index
432 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
433 // _nselection_, _n2selection_ the selection box for the language part of the index
434 // _cq2selection the selection box for combining two queries
435
436
437 // can't do anything if collectproto is null (i.e. no collection was specified)
438 if (collectproto == NULL) return;
439
440 comerror_t err;
441 InfoFilterOptionsResponse_t response;
442 InfoFilterOptionsRequest_t request;
443 request.filterName = "QueryFilter";
444
445 collectproto->get_filteroptions (args["c"], request, response, err, logout);
446 if (err == noError) {
447
448 FilterOption_tmap::const_iterator it;
449 FilterOption_tmap::const_iterator end = response.filterOptions.end();
450
451 // _hselection_ and _h2selection_ (Index)
452 it = response.filterOptions.find ("Index");
453 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
454 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
455
456 // _jselection_ and _j2selection_ (Subcollection)
457 it = response.filterOptions.find ("Subcollection");
458 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
459 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
460
461 // _nselection_ and _n2selection_ (Language)
462 it = response.filterOptions.find ("Language");
463 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
464 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
465
466 // _cq2selection_ (CombineQuery)
467 it = response.filterOptions.find ("CombineQuery");
468 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
469 }
470}
471
472bool queryaction::do_action (cgiargsclass &args, const ColInfoResponse_t &collectinfo,
473 recptproto *collectproto, displayclass &disp,
474 outconvertclass &outconvert, ostream &textout,
475 ostream &logout) {
476
477 if (formatstring.empty()) {
478 text_tmap::const_iterator result = collectinfo.format.find("QueryResults");
479 if (result != collectinfo.format.end())
480 formatstring = (*result).second;
481 }
482
483 // see if there's a QueryLinks format option
484 text_t querylinkmeta;
485 bool havequerylink = false;
486 text_tmap::const_iterator it = collectinfo.format.find("QueryLinks");
487 if (it != collectinfo.format.end()) {
488 querylinkmeta = (*it).second;
489 havequerylink = true;
490 }
491
492 // if we still don't have a format string use the default
493 if (formatstring.empty())
494 formatstring = "<td valign=top nowrap>[link]_icontext_[/link]</td><td>[Title]</td>";
495
496 if (collectproto == NULL) {
497 logout << "queryaction::do_action called with NULL collectproto\n";
498 textout << outconvert << disp << "_query:header_\n"
499 << "Error: Attempt to do query without setting collection\n"
500 << "_query:footer_\n";
501 } else {
502
503 FilterRequest_t request;
504 FilterResponse_t response;
505 format_t *formatlistptr = new format_t();
506
507 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
508
509 if (havequerylink)
510 request.fields.push_back (querylinkmeta);
511
512 int metasize = request.fields.size();
513
514 // do the query
515 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
516 if (!do_query (request, args, collectproto, response, logout))
517 return false;
518
519 // set macros
520 define_query_macros (args, disp, response);
521
522 // output the header
523 textout << outconvert << disp << "_query:header_\n"
524 << "_query:content_";
525
526 // output the results
527 textout << "<table cellspacing=4>\n";
528 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
529 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
530
531 while (this_doc != end_doc) {
532 // don't include docs that didn't match phrases (if there were any)
533 // those that did match will have been sorted to the top
534 if ((*this_doc).num_phrase_match < num_phrases) break;
535 textout << "<tr>\n";
536 if (havequerylink) {
537 const text_t &qlmeta = (*this_doc).metadata[metasize-1].values.back();
538 if (qlmeta.empty())
539 textout << outconvert << disp
540 << get_formatted_string (*this_doc, formatlistptr, "", "_iconblanktext_") << "\n";
541 else
542 textout << outconvert << disp
543 << get_formatted_string (*this_doc, formatlistptr) << "\n";
544 } else {
545 textout << outconvert << disp
546 << get_formatted_string (*this_doc, formatlistptr) << "\n";
547 }
548 textout << "</tr>\n";
549
550 this_doc ++;
551 }
552 textout << "</table>\n";
553
554 delete (formatlistptr);
555
556 // output the footer
557 textout << outconvert << disp << "_query:footer_";
558 }
559
560 return true;
561}
562
563// define_query_macros sets the macros that couldn't be set until the
564// query had been done. Those macros are _freqmsg_, _quotedquery_,
565// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
566// _thisfirst_, and _thislast_
567void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
568 const FilterResponse_t &response) {
569 // set up _freqmsg_ and _quotedquery_ macros
570 text_t freqmsg = "_textfreqmsg1_";
571 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
572 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
573 while (this_term != end_term) {
574 freqmsg += (*this_term).term + ": " + (*this_term).freq;
575 if ((this_term + 1) != end_term)
576 freqmsg += ", ";
577 this_term ++;
578 }
579
580 disp.setmacro ("freqmsg", "query", freqmsg);
581
582
583 // set up _resultline_ macro
584 text_t resline;
585 int maxdocs = args.getintarg("m");
586 int numdocs = response.numDocs;
587 if (maxdocs == -1) maxdocs = response.numDocs;
588 isapprox isApprox = response.isApprox;
589
590 // if there were phrases (post-processing) we're not going to include
591 // those documents that didn't match
592 if (num_phrases > 0) {
593 numdocs = 0;
594 isApprox = Exact;
595 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
596 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
597 while (this_doc != end_doc) {
598 if ((*this_doc).num_phrase_match == num_phrases) numdocs ++;
599 else break; // we can bail here as matching docs are sorted to top
600 this_doc++;
601 }
602 }
603
604 if (isApprox == Approximate) resline = "_textapprox_";
605 else if (isApprox == MoreThan) resline = "_textmorethan_";
606
607 if (numdocs == 0) resline = "_textnodocs_";
608 else if (numdocs == 1) resline += "_text1doc_";
609 else resline += text_t(numdocs) + " _textlotsdocs_";
610
611 disp.setmacro("resultline", "query", resline);
612
613 int firstdoc = args.getintarg("r");
614 int hitsperpage = args.getintarg("o");
615 if (hitsperpage == -1) hitsperpage = numdocs;
616
617 // set up _thisfirst_ and _thislast_ macros
618 disp.setmacro ("thisfirst", "query", firstdoc);
619 int thislast = firstdoc + (hitsperpage - 1);
620 if (thislast > numdocs) thislast = numdocs;
621 disp.setmacro ("thislast", "query", thislast);
622
623 // set up _prevfirst_ and _prevlast_ macros
624 if (firstdoc > 1) {
625 disp.setmacro ("prevlast", "query", firstdoc - 1);
626 int prevfirst = firstdoc - hitsperpage;
627 if (prevfirst < 1) prevfirst = 1;
628 disp.setmacro ("prevfirst", "query", prevfirst);
629 }
630
631 // set up _nextfirst_ and _nextlast_ macros
632 if (thislast < numdocs) {
633 disp.setmacro ("nextfirst", "query", thislast + 1);
634 int nextlast = thislast + hitsperpage;
635 if (nextlast > numdocs) nextlast = numdocs;
636 disp.setmacro ("nextlast", "query", nextlast);
637 }
638}
639
640
641
Note: See TracBrowser for help on using the repository browser.