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

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

added Maxdocs queryfilter option which may be -1 for 'all'

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