source: trunk/gsdl/src/recpt/browsetools.cpp@ 772

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

added collection argument to browserclass output_section_group
functions -- moved table functions to formattools

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 KB
Line 
1
2/**********************************************************************
3 *
4 * browsetools.cpp --
5 * Copyright (C) 1999 The New Zealand Digital Library Project
6 *
7 * A component of the Greenstone digital library software
8 * from the New Zealand Digital Library Project at the
9 * University of Waikato, New Zealand.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: browsetools.cpp 748 1999-10-30 22:22:26Z sjboddie $
26 *
27 *********************************************************************/
28
29/*
30 $Log$
31 Revision 1.33 1999/10/30 22:22:26 sjboddie
32 added collection argument to browserclass output_section_group
33 functions -- moved table functions to formattools
34
35 Revision 1.32 1999/10/24 07:22:37 sjboddie
36 added a FullTOC option
37
38 Revision 1.31 1999/10/20 03:54:20 sjboddie
39 problem with expanded contents
40
41 Revision 1.30 1999/10/19 21:36:59 sjboddie
42 fixed bug in DocumentContents
43
44 Revision 1.29 1999/10/19 08:40:12 sjboddie
45 fixed some stupid compiler warnings on windows
46
47 Revision 1.28 1999/10/18 20:08:36 sjboddie
48 tidied up a few things
49
50 Revision 1.27 1999/10/15 03:31:42 sjboddie
51 oops, left out an '&'
52
53 Revision 1.26 1999/10/14 22:58:05 sjboddie
54 finished up on changes to browseing support - may still need some
55 tidying up
56
57 Revision 1.25 1999/10/10 08:14:04 sjboddie
58 - metadata now returns mp rather than array
59 - redesigned browsing support (although it's not finished so
60 won't currently work ;-)
61
62 Revision 1.24 1999/09/28 01:46:55 rjmcnab
63 removed some unused stuff
64
65 Revision 1.23 1999/09/23 10:09:17 sjboddie
66 made some changes so AZLists within other classifications are
67 handled properly
68
69 Revision 1.22 1999/09/07 23:06:58 rjmcnab
70 removed some compiler warnings.
71
72 Revision 1.21 1999/09/07 04:56:52 sjboddie
73 added GPL notice
74
75 Revision 1.20 1999/08/25 04:46:58 sjboddie
76 fixed bug
77
78 Revision 1.19 1999/08/13 04:18:04 sjboddie
79 fixed some typos
80
81 Revision 1.18 1999/08/10 22:42:21 sjboddie
82 added more format options to document tocs - there are now just two
83 types of toc - standard (Hierarchical) and document (as in books)
84
85 Revision 1.17 1999/08/09 02:12:07 sjboddie
86 made it so dates may be only 4 digits (i.e. year only)
87
88 Revision 1.16 1999/07/30 02:16:10 sjboddie
89 -added ability to display nested classifications (expanded versions
90 of nested classifications has yet to be done).
91 -changed set_arrow_macros slightly to fit in with new showtoppage
92 format option
93
94 Revision 1.15 1999/07/21 05:01:56 sjboddie
95 wrote handler for DateList classification
96
97 Revision 1.14 1999/07/20 02:58:15 sjboddie
98 got List and AZList classifications using format strings - tidied
99 up a bit
100
101 Revision 1.13 1999/07/07 05:44:25 sjboddie
102 Made some changes to allow for new way classifiers work (i.e. you can
103 now have classifiers containing other classifiers). At present there's
104 only a special case for dealing with the hdl 'magazine' section. A bit
105 of a redesign is needed to get it completely flexible
106
107 Revision 1.12 1999/07/01 03:47:49 rjmcnab
108 Fixed a small warning.
109
110 Revision 1.11 1999/06/27 21:49:01 sjboddie
111 fixed a couple of version conflicts - tidied up some small things
112
113 Revision 1.10 1999/06/26 01:07:21 rjmcnab
114 Fixed a small "bug" -- well I probably just covered another one...
115
116 Revision 1.9 1999/06/24 05:12:15 sjboddie
117 lots of small changes
118
119 Revision 1.8 1999/06/17 03:06:53 sjboddie
120 got detach button working properly - the close book icon is now disabled
121 when page is detached as the javascript close() function I was using is
122 too unreliable over different browsers
123 note that in my last comment I meant the "cl" arg (not the "c" arg).
124
125 Revision 1.7 1999/06/16 23:53:14 sjboddie
126 tidied a few things up. documentaction::define_external_macros now
127 resets the "c" arg if it's set to something stupid by the .xx suffixes
128
129 Revision 1.6 1999/06/16 04:03:47 sjboddie
130 Now sets "cl" arg to "search" when going to a document from a search
131 results page. This allows the close book icon (in hierarchy toc) to
132 take you back to the results page if that's where you came from.
133 If you got to the document page somehow other than from a
134 classification or a search (i.e. if "cl" isn't set) then the close
135 book icon is disabled
136
137 Revision 1.5 1999/06/16 03:11:25 sjboddie
138 get_info() now takes a getParents argument
139
140 Revision 1.4 1999/05/10 03:40:26 sjboddie
141 lots of changes - slowly getting document action sorted out
142
143 Revision 1.3 1999/04/30 01:59:39 sjboddie
144 lots of stuff - getting documentaction working (documentaction replaces
145 old browseaction)
146
147 Revision 1.2 1999/03/29 02:14:29 sjboddie
148
149 More changes to browseaction
150
151 Revision 1.1 1999/03/25 03:10:15 sjboddie
152
153 new library for browse stuff
154
155 */
156
157#include "browsetools.h"
158#include "OIDtools.h"
159
160
161// output_controls displays the detach, expand/contract contents,
162// expand/contract text and highlighting/no highlighting buttons
163static void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
164 recptproto * /*collectproto*/, displayclass &disp,
165 outconvertclass &outconvert, ostream &textout,
166 ostream &/*logout*/) {
167
168 if (args["u"] != "1") {
169
170 FilterResponse_t response;
171 text_tarray metadata;
172 text_tarray buttons;
173
174 text_tarray::const_iterator here = ibuttons.begin();
175 text_tarray::const_iterator end = ibuttons.end();
176
177 while (here != end) {
178
179 if (*here == "Detach")
180 buttons.push_back ("_document:imagedetach_");
181 else if (*here == "Highlight") {
182 if (args["hl"] == "1")
183 buttons.push_back ("_document:imagenohighlight_");
184 else
185 buttons.push_back ("_document:imagehighlight_");
186 } else if (*here == "Expand Contents") {
187 if (args["gc"] == "1")
188 buttons.push_back ("_document:imagecontracttoc_");
189 else
190 buttons.push_back ("_document:imageexpandtoc_");
191 } else if (*here == "Expand Text") {
192 if (args.getintarg("gt"))
193 buttons.push_back ("_document:imagecontracttext_");
194 else
195 buttons.push_back ("_document:imageexpandtext_");
196 }
197 here ++;
198 }
199
200 here = buttons.begin();
201 end = buttons.end();
202 int count = 0;
203 while (here != end) {
204 if ((count != 0) && ((count % 3) == 0)) textout << "<br>\n";
205 textout << outconvert << disp << *here;
206 count ++;
207 here ++;
208 }
209 }
210}
211
212
213// at the moment this just writes out the html to display
214// the cover image (assuming it's called cover.jpg)
215// this whole thing should be done with a call to the collection
216// server which would send a link to the cover image if there
217// was one otherwise send title, author and stuff
218static void output_cover_image (cgiargsclass &args, recptproto * /*collectproto*/,
219 displayclass &disp, outconvertclass &outconvert,
220 ostream &textout, ostream &/*logout*/) {
221
222 if (args["d"].empty()) return;
223
224 textout << outconvert << disp <<
225 "<img src=\"_httpcollection_/archives/_thisOID_/cover.jpg\"><br>\n";
226}
227
228static void output_titles (cgiargsclass &args, recptproto *collectproto,
229 formatinfo_t &formatinfo, displayclass &disp,
230 outconvertclass &outconvert, ostream &textout,
231 ostream &logout) {
232
233 if (args["d"].empty()) return;
234
235 text_tset metadata;
236 bool getParents;
237 FilterResponse_t response;
238
239 format_t *formatlistptr = new format_t();
240 parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
241
242 if (!get_info (args["d"], args["c"], metadata, getParents, collectproto, response, logout))
243 return;
244
245 textout << outconvert << disp << get_formatted_string (response.docInfo[0], formatlistptr);
246}
247
248
249static void recurse_contents (ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
250 browserclass *bptr, text_tset &metadata, bool &getParents,
251 format_t *formatlistptr, format_tmap &formatlistmap,
252 formatinfo_t &formatinfo, browsermapclass *browsermap,
253 int tabcount, recptproto *collectproto, displayclass &disp,
254 outconvertclass &outconvert, ostream &textout, ostream &logout) {
255 text_t formatstring;
256
257 bool is_classify = false;
258 if (args["d"].empty() || fulltoc) is_classify = true;
259
260 // output this section
261 bool use_table = is_table_content (formatlistptr);
262 tabcount += bptr->output_section_group (section, args, "", tabcount, formatlistptr, use_table,
263 metadata, getParents, collectproto, disp, outconvert,
264 textout, logout);
265
266 text_t classification;
267 if (!is_classify) classification = "Document";
268 else get_top (args["cl"], classification);
269
270 int haschildren = section.metadata["haschildren"].values[0].getint();
271 const text_t &doctype = section.metadata["doctype"].values[0];
272 text_t classifytype = section.metadata["childtype"].values[0];
273 // HLists and DateLists are displayed as VLists when contents
274 // are expanded, Paged documents are displayed as HLists
275 if (classifytype == "HList" || classifytype == "DateList") classifytype = "VList";
276 if (classifytype == "Paged") classifytype = "HList";
277
278 // recurse through children
279 if ((haschildren == 1) && (!is_classify || fulltoc || doctype == "classify")) {
280
281 // get browser for displaying children
282 bptr = browsermap->getbrowser (classifytype);
283 bptr->load_metadata_defaults (metadata);
284
285 // get the formatstring if there is one
286 if (!get_formatstring (classification, classifytype,
287 formatinfo.formatstrings, formatstring))
288 formatstring = bptr->get_default_formatstring();
289
290 format_tmap::const_iterator it = formatlistmap.find (formatstring);
291 // check if formatlistptr is cached
292 if (it != formatlistmap.end()) formatlistptr = (*it).second;
293 else {
294 formatlistptr = new format_t();
295 parse_formatstring (formatstring, formatlistptr, metadata, getParents);
296 formatlistmap[formatstring] = formatlistptr;
297 }
298
299 FilterResponse_t tmp;
300 get_children (section.OID, args["c"], metadata, getParents, collectproto, tmp, logout);
301 ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
302 ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
303
304 while (thisdoc != lastdoc) {
305 recurse_contents (*thisdoc, args, fulltoc, bptr, metadata, getParents,
306 formatlistptr, formatlistmap, formatinfo, browsermap,
307 tabcount, collectproto, disp, outconvert, textout, logout);
308 thisdoc ++;
309 }
310 }
311}
312
313
314// expanded_contents recurses through all contents. there's a special case
315// for an HList when contents are expanded (i.e. it's displayed as a VList)
316//
317// if we're inside a document we expand all contents from the top,
318// if we're at classification level we'll just expand out those contents below
319// the current one
320
321static void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
322 browsermapclass *browsermap, formatinfo_t &formatinfo,
323 recptproto *collectproto, displayclass &disp,
324 outconvertclass &outconvert, ostream &textout,
325 ostream &logout) {
326
327 if (args["d"].empty() && args["cl"].empty()) return;
328 text_t OID;
329
330 FilterResponse_t response;
331 bool getParents = false;
332 text_tset metadata;
333 text_t classifytype, classification, formatstring;
334
335 if (!args["d"].empty()) {
336 // document level
337 if (fulltoc) {
338 get_top (args["cl"], OID);
339 classification = OID;
340 }
341 else {
342 // always expand document level from top
343 get_top (args["d"], OID);
344 classification = "Document";
345 }
346 } else {
347 // classification level
348 OID = args["cl"];
349 get_top (args["cl"], classification);
350 }
351
352 // get classifytype of this level
353 text_t tOID;
354 if (is_top(OID)) {
355 classifytype = "thistype";
356 tOID = OID;
357 } else {
358 classifytype = "childtype";
359 tOID = get_parent (OID);
360 }
361 metadata.insert (classifytype);
362
363 if (!get_info (tOID, args["c"], metadata, getParents, collectproto, response, logout))
364 return;
365 classifytype = response.docInfo[0].metadata[classifytype].values[0];
366 // if we still don't have a classifytype we'll use the default
367 if (classifytype.empty()) {
368 browserclass *bptr = browsermap->get_default_browser ();
369 classifytype = bptr->get_browser_name ();
370 }
371
372 // HLists are displayed as VLists when contents are expanded,
373 // Paged documents are displayed as HLists
374 if (classifytype == "HList") classifytype = "VList";
375 if (classifytype == "Paged") classifytype = "HList";
376
377 metadata.erase (metadata.begin(), metadata.end());
378
379 // metadata elements needed by recurse_contents
380 metadata.insert ("childtype");
381 metadata.insert ("doctype");
382 metadata.insert ("haschildren");
383
384 // load up metadata array with browser defaults
385 browserclass *bptr = browsermap->getbrowser (classifytype);
386 bptr->load_metadata_defaults (metadata);
387
388 // get the formatstring if there is one or use the browsers default
389 if (!get_formatstring (classification, classifytype,
390 formatinfo.formatstrings, formatstring))
391 formatstring = bptr->get_default_formatstring();
392
393 format_t *formatlistptr = new format_t();
394 parse_formatstring (formatstring, formatlistptr, metadata, getParents);
395
396 // protocol call
397 if (!get_info (OID, args["c"], metadata, getParents, collectproto, response, logout))
398 return;
399
400 format_tmap formatlistmap;
401 formatlistmap[formatstring] = formatlistptr;
402
403 recurse_contents (response.docInfo[0], args, fulltoc, bptr, metadata,
404 getParents, formatlistptr, formatlistmap, formatinfo, browsermap,
405 tabcount, collectproto, disp, outconvert, textout, logout);
406
407 // clean up format list pointers
408 format_tmap::const_iterator here = formatlistmap.begin();
409 format_tmap::const_iterator end = formatlistmap.end();
410 while (here != end) {
411 delete (*here).second;
412 here ++;
413 }
414}
415
416
417static void load_formatstring (const text_t &classifytype, text_tset &metadata,
418 bool &getParents, const text_t &classification,
419 browsermapclass *browsermap, formatinfo_t &formatinfo,
420 format_tmap &formatlistmap) {
421 text_t formatstring;
422
423 // load up metadata array with browser defaults
424 browserclass *bptr = browsermap->getbrowser (classifytype);
425 bptr->load_metadata_defaults (metadata);
426
427 // get the formatstring if there is one or use the browsers default
428 if (!get_formatstring (classification, classifytype,
429 formatinfo.formatstrings, formatstring))
430 formatstring = bptr->get_default_formatstring();
431
432 // see if it's cached
433 format_tmap::const_iterator it = formatlistmap.find (formatstring);
434 if (it == formatlistmap.end()) {
435 format_t *formatlistptr = new format_t();
436 parse_formatstring (formatstring, formatlistptr, metadata, getParents);
437 formatlistmap[formatstring] = formatlistptr;
438 }
439}
440
441static void load_formatstrings (FilterResponse_t &response, text_tset &metadata,
442 bool &getParents, const text_t &classification,
443 browsermapclass *browsermap, formatinfo_t &formatinfo,
444 format_tmap &formatlistmap) {
445
446 text_tset cache;
447
448 ResultDocInfo_tarray::iterator thisdoc = response.docInfo.begin();
449 ResultDocInfo_tarray::iterator lastdoc = response.docInfo.end();
450
451 while (thisdoc != lastdoc) {
452
453 if (is_top ((*thisdoc).OID))
454 load_formatstring ((*thisdoc).metadata["thistype"].values[0], metadata,
455 getParents, classification, browsermap, formatinfo,
456 formatlistmap);
457
458 text_t &childtype = (*thisdoc).metadata["childtype"].values[0];
459 text_tset::const_iterator it = cache.find (childtype);
460 if (it == cache.end()) {
461 load_formatstring (childtype, metadata, getParents, classification,
462 browsermap, formatinfo, formatlistmap);
463 cache.insert (childtype);
464 }
465 thisdoc ++;
466 }
467}
468
469static void output_parents (FilterResponse_t &response, cgiargsclass &args,
470 browsermapclass *browsermap, formatinfo_t &formatinfo,
471 format_tmap &formatlistmap, const text_t &classification,
472 int &tabcount, text_tset &metadata, bool &getParents,
473 recptproto *collectproto, displayclass &disp,
474 outconvertclass &outconvert, ostream &textout,
475 ostream &logout) {
476
477 format_t *formatlistptr = NULL;
478 text_t classifytype, formatstring;
479 bool use_table, first = true;
480 ResultDocInfo_tarray::iterator thisparent = response.docInfo.begin();
481 ResultDocInfo_tarray::iterator lastparent = response.docInfo.end();
482 while (thisparent != lastparent) {
483
484 // get classifytype of this level
485 if (is_top ((*thisparent).OID)) classifytype = (*thisparent).metadata["thistype"].values[0];
486 else if (!first) classifytype = (*(thisparent-1)).metadata["childtype"].values[0];
487
488 // if we still don't have a classifytype we'll use the default
489 if (classifytype.empty()) {
490 browserclass *bptr = browsermap->get_default_browser ();
491 classifytype = bptr->get_browser_name ();
492 }
493
494 browserclass *bptr = browsermap->getbrowser (classifytype);
495
496 // get the formatstring if there is one or use the browsers default
497 if (!get_formatstring (classification, classifytype,
498 formatinfo.formatstrings, formatstring))
499 formatstring = bptr->get_default_formatstring();
500
501 // see if it's cached
502 format_tmap::const_iterator it = formatlistmap.find (formatstring);
503 if (it != formatlistmap.end()) formatlistptr = (*it).second;
504 else {
505 logout << "browsetools error\n";
506 return;
507 }
508
509 use_table = is_table_content (formatlistptr);
510 tabcount += bptr->output_section_group (*thisparent, args, "", tabcount, formatlistptr,
511 use_table, metadata, getParents, collectproto,
512 disp, outconvert, textout, logout);
513 first = false;
514 thisparent ++;
515 }
516}
517
518
519static void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc,
520 browsermapclass *browsermap, formatinfo_t &formatinfo,
521 recptproto *collectproto, displayclass &disp,
522 outconvertclass &outconvert, ostream &textout,
523 ostream &logout) {
524 FilterResponse_t response;
525 text_tset metadata;
526 bool getParents = false;
527 text_t formatstring;
528 text_tarray parents;
529 text_t OID = args["d"];
530 text_t classification = "Document";
531 if (OID.empty()) {
532 OID = args["cl"];
533 get_top (OID, classification);
534 } else if (fulltoc)
535 get_top (args["cl"], classification);
536
537 bool haschildren = has_children (OID, args["c"], collectproto, logout);
538
539 if ((!args["d"].empty()) && fulltoc)
540 get_parents_array (args["cl"] + ".fc", parents);
541 if (haschildren) get_parents_array (OID + ".fc", parents);
542 else get_parents_array (OID, parents);
543
544 if (!parents.empty()) {
545 // get classifytypes of each parent
546 metadata.insert ("thistype");
547 metadata.insert ("childtype");
548
549 if (!get_info (parents, args["c"], metadata, getParents, collectproto, response, logout))
550 return;
551
552 // get formatstrings for all parents
553 format_tmap formatlistmap;
554 load_formatstrings (response, metadata, getParents, classification,
555 browsermap, formatinfo, formatlistmap);
556
557 if (!get_info (parents, args["c"], metadata, getParents, collectproto, response, logout))
558 return;
559
560 // display each parent
561 output_parents (response, args, browsermap, formatinfo, formatlistmap,
562 classification, tabcount, metadata, getParents,
563 collectproto, disp, outconvert, textout, logout);
564
565 metadata.erase (metadata.begin(), metadata.end());
566
567 // clean up cached format list pointers
568 format_tmap::const_iterator here = formatlistmap.begin();
569 format_tmap::const_iterator end = formatlistmap.end();
570 while (here != end) {
571 delete (*here).second;
572 here ++;
573 }
574 }
575
576 // get childrens classifytype
577 text_t classifytype;
578 int numparents = response.docInfo.size();
579 if (!parents.empty())
580 classifytype = response.docInfo[numparents-1].metadata["childtype"].values[0];
581 else {
582 // use the default
583 browserclass *bptr = browsermap->get_default_browser ();
584 classifytype = bptr->get_browser_name ();
585 }
586
587 // load up metadata array with browser defaults
588 browserclass *bptr = browsermap->getbrowser (classifytype);
589 bptr->load_metadata_defaults (metadata);
590
591 // get the formatstring if there is one or use the browsers default
592 if (!get_formatstring (classification, classifytype,
593 formatinfo.formatstrings, formatstring))
594 formatstring = bptr->get_default_formatstring();
595
596 format_t *formatlistptr = new format_t();
597 parse_formatstring (formatstring, formatlistptr, metadata, getParents);
598
599 if (haschildren)
600 get_children (OID, args["c"], metadata, getParents,
601 collectproto, response, logout);
602 else
603 get_children (OID + ".pr", args["c"], metadata, getParents,
604 collectproto, response, logout);
605
606 // display children
607 bool use_table = is_table_content (formatlistptr);
608 bptr->output_section_group (response, args, "", tabcount, formatlistptr, use_table,
609 metadata, getParents, collectproto, disp, outconvert,
610 textout, logout);
611
612 delete formatlistptr;
613}
614
615void output_toc (cgiargsclass &args, browsermapclass *browsermap,
616 formatinfo_t &formatinfo, recptproto *collectproto,
617 displayclass &disp, outconvertclass &outconvert,
618 ostream &textout, ostream &logout) {
619
620 int tabcount = 0;
621 bool havecontrols = false;
622 bool fulltoc = false;
623
624 if (args["cl"] != "search") {
625 // see if there's a FullTOC string
626 text_t cl_top, full_toc;
627 get_top (args["cl"], cl_top);
628 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
629 if (full_toc == "true") fulltoc = true;
630 }
631
632 // get the cover image (if there is one) and the control buttons
633 // if we're inside a book
634 if ((!fulltoc) && (!args["d"].empty())) {
635 textout << "<p><table cellpadding=0 cellspacing=0><tr>\n";
636 textout << "<td valign=top";
637 if (formatinfo.DocumentContents) textout << " width=200>\n";
638 else textout << " width=100%>\n";
639 if (formatinfo.DocumentImages)
640 output_cover_image (args, collectproto, disp, outconvert, textout, logout);
641 else if (formatinfo.DocumentTitles)
642 output_titles (args, collectproto, formatinfo, disp, outconvert, textout, logout);
643 output_controls (args, formatinfo.DocumentButtons, collectproto, disp,
644 outconvert, textout, logout);
645 textout << "</td><td valign=top>\n";
646 havecontrols = true;
647 }
648
649 if (formatinfo.DocumentContents || args["d"].empty()) {
650 if (args.getintarg("gc") == 1) {
651
652 // expanded table of contents
653 expanded_contents (args, tabcount, fulltoc, browsermap, formatinfo,
654 collectproto, disp, outconvert, textout, logout);
655 } else {
656
657 // contracted table of contents
658 contracted_contents (args, tabcount, fulltoc, browsermap, formatinfo,
659 collectproto, disp, outconvert, textout, logout);
660 }
661 }
662
663 if (havecontrols) textout << "</td></tr></table>\n";
664}
Note: See TracBrowser for help on using the repository browser.