Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtHelp / FormatTerm.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: FormatTerm.c /main/14 1997/08/07 10:52:34 samborn $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        FormatTerm.c
28  **
29  **   Project:     CDE Help System
30  **  
31  **   Description: This code uses the core engine functionality of the
32  **                the help system to get topics into a form understood
33  **                by ASCII based applications.
34  **
35  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
36  **
37  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
38  **  (c) Copyright 1993, 1994 International Business Machines Corp.
39  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
40  **  (c) Copyright 1993, 1994 Novell, Inc.
41  **
42  ****************************************************************************
43  ************************************<+>*************************************/
44
45 /*
46  * system includes
47  */
48 #include <stdio.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <sys/param.h>
55 #include <sys/stat.h>
56
57 #include <X11/Xos.h>
58 #ifdef X_NOT_STDC_ENV
59 extern int errno;
60 #endif
61
62 /*
63  * Canvas Engine includes
64  */
65 #include "CanvasP.h"
66 #include "CanvasSegP.h"
67 #include "LinkMgrP.h"
68
69 /*
70  * private includes
71  */
72 #include "LinkMgrI.h"
73 #include "HelpTermP.h"
74 #include "HelpP.h"
75 #include "HelpI.h"
76 #include "bufioI.h"
77 #include "AsciiSpcI.h"
78 #include "Access.h"
79 #include "AccessI.h"
80 #include "CanvasI.h"
81 #include "CleanUpI.h"
82 #include "HelpErrorP.h"
83 #include "FileUtilsI.h"
84 #include "FontAttrI.h"
85 #include "StringFuncsI.h"
86 #include "SDLI.h"
87 #include "FormatUtilI.h"
88 #include "FormatSDLI.h"
89 #include "FormatCCDFI.h"
90 #include "Lock.h"
91
92 #ifdef NLS16
93 #endif
94
95
96 /********    Private Function Declarations    ********/
97 static  void            TermMetrics(
98                                 _DtCvPointer             client_data,
99                                 _DtCvElemType   elem_type,
100                                 _DtCvPointer    ret_metrics);
101 static  _DtCvUnit       TermStrWidth(
102                                 _DtCvPointer    client_data,
103                                 _DtCvElemType   elem_type,
104                                 _DtCvPointer    data);
105 static  void            TermStrDraw(
106                                 _DtCvPointer     client_data,
107                                 _DtCvUnit        x,
108                                 _DtCvUnit        y,
109                                 const void      *string,
110                                 int              byte_len,
111                                 int              wc,
112                                 _DtCvPointer     font_ptr,
113                                 _DtCvUnit        box_x,
114                                 _DtCvUnit        box_y,
115                                 _DtCvUnit        box_height,
116                                 int              link_type,
117                                 _DtCvFlags       old_flags,
118                                 _DtCvFlags       new_flags );
119 #ifdef  XTAG
120 static  _DtCvStatus             TermFindGraphic(
121                                 _DtCvPointer     client_data,
122                                 char            *vol_xid,
123                                 char            *topic_xid,
124                                 char            *file_xid,
125                                 char            *format,
126                                 char            *method,
127                                 _DtCvUnit       *ret_width,
128                                 _DtCvUnit       *ret_height,
129                                 _DtCvPointer    *ret_graphic);
130 #endif
131 static  void            TermGetFont(
132                                 _DtCvPointer     client_data,
133                                 char            *lang,
134                                 char            *charset,
135                                 _DtHelpFontHints font_attr,
136                                 _DtCvPointer    *ret_font );
137 static  void            TermFontMetrics(
138                                 _DtCvPointer     client_data,
139                                 _DtCvPointer     font_ptr,
140                                 _DtCvUnit       *ret_ascent,
141                                 _DtCvUnit       *ret_descent,
142                                 _DtCvUnit       *char_width,
143                                 _DtCvUnit       *ret_super,
144                                 _DtCvUnit       *ret_sub);
145 static  _DtCvStatus     TermResolveSpc(
146                                 _DtCvPointer     client_data,
147                                 char            *lang,
148                                 char            *charset,
149                                 _DtHelpFontHints         font_attr,
150                                 char            *spc_symbol,
151                                 _DtCvPointer    *ret_handle,
152                                 _DtCvUnit       *ret_width,
153                                 _DtCvUnit       *ret_height,
154                                 _DtCvUnit       *ret_ascent);
155 static  void            TermRenderElem(
156                                 _DtCvPointer    client_data,
157                                 _DtCvElemType   elem_type,
158                                 _DtCvUnit       x,
159                                 _DtCvUnit       y,
160                                 int             link_type,
161                                 _DtCvFlags      old_flags,
162                                 _DtCvFlags      new_flags,
163                                 _DtCvElemType   trav_type,
164                                 _DtCvPointer    trav_data,
165                                 _DtCvPointer    data );
166
167 /********    End Public Function Declarations    ********/
168
169 /******************************************************************************
170  *
171  * Private variables and defines.
172  *
173  *****************************************************************************/
174 #define GROW_SIZE       10
175 #define EOS             '\0'
176
177 /*
178  * My private values
179  */
180 static  _DtHelpVolumeHdl         MyVolume     = NULL;
181 static  int              HyperErr     = 0;
182 static  wchar_t          WcSpace      = 0;
183
184 /*
185  * These values change as the information is processed.
186  */
187 typedef struct {
188         wchar_t **lines;
189         size_t   *wc_num;
190         int       max_lines;
191         _DtCvUnit         max_columns;
192         _DtCvUnit         max_rows;
193         short             nl_to_space;
194         wchar_t         *cant_begin_chars;
195         wchar_t         *cant_end_chars;
196 } TerminalInfo;
197
198 /* default values */
199 static TerminalInfo     DfltTermInfo   = {NULL, NULL, 0, 1, 100000, 1, NULL, NULL};
200 static _DtCvVirtualInfo TermVirtInfo =
201   {
202         TermMetrics,            /* void      (*_DtCvGetMetrics)(); */
203         TermRenderElem,         /* void      (*_DtCvRenderElem)(); */
204         TermStrWidth,           /* _DtCvUnit (*_DtCvGetElemWidth)(); */
205         TermFontMetrics,        /* void      (*_DtCvGetFontMetrics)(); */
206         NULL,                   /* _DtCvStatus   (*_DtCvBuildSelection)(); */
207         NULL,                   /* _DtCvStatus   (*_DtCvFilterExecCmd)(); */
208   };
209
210 static TerminalInfo     MyInfo   = {NULL, NULL, 0, 1, 100000, 1, NULL, NULL};
211 static _DtCvHandle      MyCanvas = NULL;
212
213 #ifdef  XTAG
214 int     missingGraphics = 0;  /* Counter used by cdewalk */
215 #endif  /* XTAG */
216
217 /******************************************************************************
218  *
219  * Private functions
220  *
221  ******************************************************************************/
222 /******************************************************************************
223  * Canvas functions
224  ******************************************************************************/
225 #ifdef  XTAG
226 /*****************************************************************************
227  * Function:    _DtCvStatus TermFindGraphic ();
228  *
229  * Parameters:
230  *
231  * Returns:
232  *
233  * Purpose:
234  *
235  *****************************************************************************/
236 static _DtCvStatus
237 TermFindGraphic (
238     _DtCvPointer         client_data,
239     char                *vol_xid,
240     char                *topic_xid,
241     char                *file_xid,
242     char                *format,
243     char                *method,
244     _DtCvUnit           *ret_width,
245     _DtCvUnit           *ret_height,
246     _DtCvPointer        *ret_graphic )
247 {
248     char                 *ptr;
249     char                 *fileName = file_xid;
250
251     if (fileName != NULL && *fileName != '/')
252       {
253         fileName = (char *) malloc (strlen(vol_xid) + strlen (file_xid) + 2);
254         if (fileName == NULL)
255             return -1;
256
257         strcpy(fileName, vol_xid);
258
259         if (_DtHelpCeStrrchr(fileName, "/", MB_CUR_MAX, &ptr) != -1)
260             *ptr = '\0';
261
262         strcat(fileName, "/");
263         strcat(fileName, file_xid);
264       }
265
266     if (access(fileName, R_OK) != 0)
267       {
268         missingGraphics++;
269         fprintf (stdout, "\tGRAPHICS LINK            ***UNRESOLVED***\n");
270         fprintf (stdout, "\tUnable to find graphic file: %s\n\n", fileName);
271       }
272
273     if (fileName != file_xid)
274         free (fileName);
275
276     *ret_width   = 0;
277     *ret_height  = 0;
278     *ret_graphic = 0;
279
280     return 0;
281 }
282 #endif /* XTAG */
283
284 /*****************************************************************************
285  * Function:    void TermStrDraw ();
286  *
287  * Parameters:
288  *
289  * Returns:
290  *
291  * Purpose:
292  *
293  *****************************************************************************/
294 static  void
295 TermStrDraw (
296     _DtCvPointer client_data,
297     _DtCvUnit    x,
298     _DtCvUnit    y,
299     const void  *string,
300     int          byte_len,
301     int          wc,
302     _DtCvPointer font_ptr,
303     _DtCvUnit    box_x,
304     _DtCvUnit    box_y,
305     _DtCvUnit    box_height,
306     int          link_type,
307     _DtCvFlags   old_flags,
308     _DtCvFlags   new_flags )
309 {
310     TerminalInfo   *pTerm  = (TerminalInfo *) client_data;
311     wchar_t        *wcStr  = pTerm->lines[y];
312     size_t          length = 1;
313
314     length = x + byte_len;
315     if (wcStr == NULL)
316       {
317         pTerm->lines[y] = (wchar_t *) malloc (sizeof(wchar_t) * (length + 1));
318         if (pTerm->lines[y] != NULL)
319           {
320             register i;
321
322             wcStr = pTerm->lines[y];
323             _DtHelpProcessLock();
324             for (i = 0; i < x; i++)
325                 wcStr[i] = WcSpace;
326             _DtHelpProcessUnlock();
327             /*
328              * this will leave a hole that will be plugged by the next 
329              * mbstowc call.
330              */
331             wcStr[length] = 0;
332             pTerm->wc_num[y] = length;
333           }
334       }
335     else
336       {
337         if (length > pTerm->wc_num[y])
338           {
339             pTerm->lines[y] = (wchar_t *) realloc (wcStr,
340                                         (sizeof(wchar_t) * (length + 1)));
341             if (pTerm->lines[y] != NULL)
342               {
343                 register i;
344                 wcStr = pTerm->lines[y];
345                 _DtHelpProcessLock();
346                 for (i = pTerm->wc_num[y]; i < x; i++)
347                     wcStr[i] = WcSpace;
348                 _DtHelpProcessUnlock();
349                 wcStr[length] = 0;
350                 pTerm->wc_num[y] = length;
351               }
352           }
353       }
354
355     if (0 == wc)
356         mbstowcs(&wcStr[x], string, byte_len);
357     else
358       {
359         int i;
360         wchar_t *wcp = (wchar_t *) string;
361
362         while (0 < byte_len)
363           {
364             wcStr[x++] = *wcp++;
365             byte_len--;
366 }
367       }
368 }
369
370 /*****************************************************************************
371  * Function:    void TermRenderElem ();
372  *
373  * Parameters:
374  *
375  * Returns:
376  *
377  * Purpose:
378  *
379  *****************************************************************************/
380 static  void
381 TermRenderElem (
382     _DtCvPointer        client_data,
383     _DtCvElemType       elem_type,
384     _DtCvUnit           x,
385     _DtCvUnit           y,
386     int                 link_type,
387     _DtCvFlags          old_flags,
388     _DtCvFlags          new_flags,
389     _DtCvElemType       trav_type,
390     _DtCvPointer        trav_data,
391     _DtCvPointer        data)
392 {
393     _DtCvStringInfo *strInfo;
394     _DtCvRenderInfo *posInfo = (_DtCvRenderInfo *) data;
395
396     if (_DtCvSTRING_TYPE == elem_type)
397       {
398         strInfo = (_DtCvStringInfo *) posInfo->info;
399         TermStrDraw (client_data, x, y, strInfo->string, strInfo->byte_len,
400                         strInfo->wc        , strInfo->font_ptr,
401                         posInfo->box_x     , posInfo->box_y   ,
402                         posInfo->box_height, link_type,
403                         old_flags          , new_flags);
404       }
405     else if (_DtCvREGION_TYPE == elem_type)
406       {
407         const char *spcStr = (const char*) posInfo->info;
408         int len = spcStr ? strlen(spcStr) : 0;
409
410         TermStrDraw (client_data, x, y, spcStr, len, 0, 0,
411                         posInfo->box_x     , posInfo->box_y,
412                         posInfo->box_height, link_type,
413                         old_flags          , new_flags);
414       }
415 }
416
417 /*****************************************************************************
418  * Function:    void TermMetrics ();
419  *
420  * Parameters:
421  *
422  * Returns:
423  *
424  * Purpose:
425  *
426  *****************************************************************************/
427 static  _DtCvSpaceMetrics       defLinkMetrics = { 0, 0, 0, 0 };
428
429 static  void
430 TermMetrics (
431     _DtCvPointer                 client_data,
432     _DtCvElemType       elem_type,
433     _DtCvPointer        ret_metrics)
434 {
435     TerminalInfo *pTerm = (TerminalInfo *) client_data;
436     _DtCvSpaceMetrics *retSpace = (_DtCvSpaceMetrics *) ret_metrics;
437
438     if (_DtCvCANVAS_TYPE == elem_type)
439       {
440         _DtCvMetrics *retCanvas = (_DtCvMetrics *) ret_metrics;
441
442         retCanvas->width          = pTerm->max_columns;
443         retCanvas->height         = 50;
444         retCanvas->top_margin     = 0;
445         retCanvas->side_margin    = 0;
446         retCanvas->line_height    = 1;
447         retCanvas->horiz_pad_hint = 1;
448       }
449
450     else if (_DtCvLOCALE_TYPE == elem_type)
451       {
452         _DtCvLocale *retLocale = (_DtCvLocale *) ret_metrics;
453
454         retLocale->line_wrap_mode   = _DtCvModeWrapNone;
455         retLocale->cant_begin_chars = pTerm->cant_begin_chars;
456         retLocale->cant_end_chars   = pTerm->cant_end_chars;
457       }
458     else if (_DtCvLINK_TYPE == elem_type || _DtCvTRAVERSAL_TYPE == elem_type)
459         *retSpace = defLinkMetrics;
460 }
461
462 /*****************************************************************************
463  * Function:    void TermGetFont ();
464  *
465  * Parameters:
466  *
467  * Returns:
468  *
469  * Purpose:
470  *
471  *****************************************************************************/
472 static  void
473 TermGetFont (
474     _DtCvPointer                 client_data,
475     char                *lang,
476     char                *charset,
477     _DtHelpFontHints     font_attr,
478     _DtCvPointer        *ret_font )
479 {
480     *ret_font = (_DtCvPointer) 0;
481 }
482
483 /*****************************************************************************
484  * Function:    _DtCvStatus TermResolveSpc ();
485  *
486  * Parameters:
487  *
488  * Returns:
489  *
490  * Purpose:
491  *
492  *****************************************************************************/
493 static  _DtCvStatus
494 TermResolveSpc (
495     _DtCvPointer         client_data,
496     char                *lang,
497     char                *charset,
498     _DtHelpFontHints     font_attr,
499     char                *spc_symbol,
500     _DtCvPointer        *ret_handle,
501     _DtCvUnit           *ret_width,
502     _DtCvUnit           *ret_height,
503     _DtCvUnit           *ret_ascent)
504 {
505     const char* spcStr;
506
507     /*
508      * initialize the returned information to nothing.
509      */
510     *ret_handle = NULL;
511     *ret_height = 0;
512     *ret_width  = 0;
513     *ret_ascent = 0;
514
515     spcStr = _DtHelpCeResolveSpcToAscii (spc_symbol);
516
517     if (spcStr != NULL)
518       {
519         *ret_handle = ((_DtCvPointer)(spcStr));
520         *ret_height = 1;
521         *ret_width  = strlen(spcStr);
522
523       }
524
525     return 0;
526 }
527
528 /*****************************************************************************
529  * Function:    void TermFontMetrics ();
530  *
531  * Parameters:
532  *
533  * Returns:
534  *
535  * Purpose:
536  *
537  *****************************************************************************/
538 static  void
539 TermFontMetrics (
540     _DtCvPointer         client_data,
541     _DtCvPointer font_ptr,
542     _DtCvUnit   *ret_ascent,
543     _DtCvUnit   *ret_descent,
544     _DtCvUnit   *char_width,
545     _DtCvUnit   *ret_super,
546     _DtCvUnit   *ret_sub)
547 {
548     if (ret_ascent)
549         *ret_ascent = 0;
550     if (ret_descent)
551         *ret_descent = 0;
552     if (char_width)
553         *char_width = 0;
554     if (ret_super)
555         *ret_super = 0;
556     if (ret_sub)
557         *ret_sub = 0;
558
559     return;
560 }
561
562 /*****************************************************************************
563  * Function:    _DtCvUnit TermStrWidth ();
564  *
565  * Parameters:
566  *
567  * Returns:
568  *
569  * Purpose:
570  *
571  *****************************************************************************/
572 static  _DtCvUnit
573 TermStrWidth (
574     _DtCvPointer         client_data,
575     _DtCvElemType       elem_type,
576     _DtCvPointer        data)
577 {
578    _DtCvStringInfo *strInfo = (_DtCvStringInfo *) data;
579
580    if (elem_type != _DtCvSTRING_TYPE)
581         return 0;
582
583    return ((_DtCvUnit)(strInfo->byte_len));
584 }
585
586 /******************************************************************************
587  * End Canvas functions
588  * Begin other private functions
589  ******************************************************************************/
590
591 /******************************************************************************
592  * Function: DtHelpHyperLines *AddHyperToArray (DtHelpHyperLines *array_ptr,
593  *                              int value, char *link_spec, char *title)
594  *
595  * Parameters:
596  *              array_ptr       Specifies a NULL terminated list of
597  *                              DtHelpHyperLines or NULL.
598  *              value           Specifies the link type.
599  *              link_spec       Specifies the link specification.
600  *              title           Specifies the title of the link.
601  *
602  * Returns:     A ptr to the new DtHelpHyperLines if successful,
603  *              NULL if errors.
604  *
605  * errno Values:
606  *              DtErrorMalloc
607  *
608  * Purpose:     Add a hypertext link to an array of DtHelpHyperLines.
609  * 
610  *****************************************************************************/
611 static  DtHelpHyperLines *
612 AddHyperToArray(
613         DtHelpHyperLines *array_ptr,
614         int              value,
615         int              win_hint,
616         char            *link_spec,
617         char            *title )
618 {
619     DtHelpHyperLines *next;
620     int            num = 0;
621
622
623     if (array_ptr)
624       {
625         for (next = array_ptr; next->specification != NULL; next++)
626                 num++;
627
628         if (((num + 1) % GROW_SIZE) == 0)
629             array_ptr = (DtHelpHyperLines *) realloc ((void *) array_ptr,
630                         (sizeof (DtHelpHyperLines) * (num + 1 + GROW_SIZE)));
631       }
632     else
633         array_ptr = (DtHelpHyperLines *) malloc (
634                                         sizeof (DtHelpHyperLines) * GROW_SIZE);
635
636     if (array_ptr == NULL)
637         errno = DtErrorMalloc;
638     else
639       {
640         next = array_ptr + num;
641
642         next->hyper_type    = value;
643         next->win_hint      = win_hint;
644         next->specification = strdup(link_spec);
645         next->title         = title;
646         next++;
647
648         next->specification = NULL;
649         next->title         = NULL;
650       }
651
652     return array_ptr;
653 }
654
655 /******************************************************************************
656  * Function:  void DeallocateHyperArray (DtHelpHyperLines *array_ptr)
657  *
658  * Parameters:
659  *              array_ptr       Specifies a NULL terminated array of
660  *                              DtHelpHyperLines.
661  *
662  * Returns:     Nothing
663  *
664  * errno Values:
665  *
666  * Purpose:     De-allocate an array of DtHelpHyperLines structures.
667  *
668  *****************************************************************************/
669 static  void
670 DeallocateHyperArray(
671         DtHelpHyperLines        *array_ptr )
672 {
673     register DtHelpHyperLines *next = array_ptr;
674
675     if (array_ptr)
676       {
677         while (next->title && next->specification)
678           {
679             free (next->title);
680             free (next->specification);
681             next++;
682           }
683         free (array_ptr);
684       }
685 }
686
687 /******************************************************************************
688  * Function: int AddHyperToList(
689  * 
690  * Parameters:
691  *
692  * Returns:      0 if successful.
693  *              -1 if unrecoverable errors.
694  *              -2 if could not resolve the hypertext link.
695  *
696  * errno Values:
697  *              DtErrorMalloc
698  *              DtErrorFormattingLabel
699  *                              A label has illegal syntax.
700  *              DtErrorHyperType
701  *                              Invalid (negative) hypertype.
702  *              DtErrorFormattingLink
703  *                              Invalid <LINK>.
704  *              DtErrorHyperSpec
705  *                              Invalid 'hyper_specification' in the
706  *                              the <LINK>.
707  *              DtErrorFormattingId
708  *                              Invalid <ID> syntax.
709  *
710  * Purpose:     Process the result of a hypertext link, filling out
711  *              a hypertext structure element with the information.
712  *                      
713  *****************************************************************************/
714 static  int
715 AddHyperToList(
716     _DtHelpVolumeHdl volume,
717     _DtCvHandle canvas,
718     int          i,
719     DtHelpHyperLines    **ret_list)
720 {
721     _DtCanvasStruct     *myCanvas = (_DtCanvasStruct *)canvas;
722     _DtCvLinkInfo        hyperInfo;
723     _DtHelpVolumeHdl     newVol    = NULL;
724     _DtHelpVolumeHdl     useVol    = volume;
725     char                *volName   = NULL;
726     char                *title     = NULL;
727     char                *allocName = NULL;
728     char                *spec      = NULL;
729     char                *id;
730     int                 result    = -3;
731
732     if (_DtLinkDbGetLinkInfo(myCanvas->link_data, i,
733                                 myCanvas->virt_functions.exec_cmd_filter,
734                                 myCanvas->client_data, &hyperInfo) == 0)
735       {
736         result = 0;
737         if (hyperInfo.description == NULL)
738           {
739             id = hyperInfo.specification;
740             switch (hyperInfo.hyper_type)
741               {
742                 case _DtCvLinkType_CrossLink:
743                         spec = strdup (id);
744                         if (spec != NULL)
745                           {
746                             volName = spec;
747                             id = NULL;
748                             _DtHelpCeStrchr (spec," ",MB_CUR_MAX,&id);
749                             if (id != NULL)
750                               {
751                                 *id = '\0';
752                                 id++;
753
754                                 /* find the volume (volName is malloc'd) */
755                                 allocName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, volName,
756                                                  _DtHelpFileSuffixList,False,R_OK);
757                                 if (allocName == NULL) 
758                                      result = -2;
759
760                                 if (_DtHelpOpenVolume(allocName, &newVol)==0)
761                                     useVol = newVol;
762                                 else
763                                     result = -2;
764                               }
765                             else
766                                 id = spec;
767                           }
768                         else
769                             result = -1;
770                         /* fall thru */
771                 case _DtCvLinkType_SameVolume:
772                         if (result == 0)
773                           {
774                             result = _DtHelpGetTopicTitle(useVol, id, &title);
775                             if (result == -2)
776                                 HyperErr = DtErrorLocIdNotFound;
777                           }
778
779                         if (newVol != NULL)
780                             _DtHelpCloseVolume(newVol);
781                         if (spec != NULL)
782                             free(spec);
783                         if (allocName != NULL)
784                             free(allocName);
785
786                         break;
787
788                 case _DtCvLinkType_Execute:
789                         title = (char *) malloc(strlen(id) + 11);
790                         sprintf(title, "Execute \"%s\"", id);
791                         break;
792
793                 case _DtCvLinkType_ManPage:
794                         title = (char *) malloc(strlen(id) + 13);
795                         sprintf(title, "Man Page \"%s\"", id);
796                         break;
797
798                 case _DtCvLinkType_AppDefine:
799                         title = (char *) malloc(strlen(id) + 26);
800                         sprintf(title, "Application Link Type \"%s\"", id);
801                         break;
802
803                 case _DtCvLinkType_TextFile:
804                         title = (char *) malloc(strlen(id) + 12);
805                         sprintf(title, "Text File \"%s\"", id);
806                         break;
807                 default:
808                         title = strdup ("Unkown link type");
809                         break;
810
811               }
812           }
813         else
814           {
815             title = strdup (hyperInfo.description);
816           }
817       }
818
819     if (result == -2)
820         *ret_list = AddHyperToArray (*ret_list, -(hyperInfo.hyper_type + 1),
821                                 hyperInfo.win_hint,
822                                 hyperInfo.specification,
823                                 strdup("Invalid Link"));
824     else if (result >= 0)
825         *ret_list = AddHyperToArray (*ret_list, hyperInfo.hyper_type,
826                                 hyperInfo.win_hint,
827                                 hyperInfo.specification,
828                                 title);
829
830     /*
831      * report unable to resolve the hypertext link
832      */
833     if (result == -2)
834         return -2;
835
836     if (result == -1 || *ret_list == NULL)
837         return -1;
838
839     return (0);
840
841 } /* End AddHyperToList */
842
843 /******************************************************************************
844  * Function: TerminalInfo * GetTermInfo(canvasHandle)
845  *
846  * Parameters:
847  *              canvasHandle    Canvas whose client_data is a TerminalInfo *
848  *
849  * Returns:     0 for success, -1 for failure.
850  *
851  ******************************************************************************/
852 static TerminalInfo * 
853 GetTermInfo(
854            _DtCvHandle canvasHandle)
855 {
856    _DtCanvasStruct * canvas = (_DtCanvasStruct *) canvasHandle;
857
858    return (TerminalInfo *) canvas->client_data;
859 }
860
861 /******************************************************************************
862  *
863  * Public functions
864  *
865  ******************************************************************************/
866 /******************************************************************************
867  * Function: int _DtHelpTermCreateCanvas (int maxColumns,_DtCvHandle * ret_canvas)
868  *
869  * Parameters:
870  *              maxColumns      Specifies the column width of the window
871  *                              for which to format the information.
872  *              ret_canvas      handle to the canvas that was created
873  *
874  * Returns:     0 for success, -1 for failure.
875  *
876  * errno Values:
877  *              EINVAL          'ret_canvas' was NULL or 'maxColumns'
878  *                              was less than one.
879  *              ENOMEM          unable to allocate necessary memory
880  *              DtErrorMalloc
881  *
882  * Purpose:     _DtHelpTermCreateCanvas creates a canvas that use 
883  *              text-only content processing routines
884  *
885  *****************************************************************************/
886 int
887 _DtHelpTermCreateCanvas (
888         int               maxColumns,
889         _DtCvHandle *    ret_canvas)
890 {
891     TerminalInfo * termInfo;
892
893     /*
894      * check the parameters
895      */
896     if (maxColumns < 1 || ret_canvas == NULL)
897       {
898         errno = EINVAL;
899         return -1;
900       }
901
902     termInfo = (TerminalInfo *) malloc(sizeof(TerminalInfo));
903     if (termInfo == NULL)
904     {
905         errno = ENOMEM;
906         return -1;
907     }
908
909      /* init info and create a canvas */
910     *termInfo = DfltTermInfo;
911     termInfo->max_columns = maxColumns;
912     if (1 < MB_CUR_MAX)
913         _DtHelpLoadMultiInfo(&(termInfo->cant_begin_chars),
914                                 &(termInfo->cant_begin_chars),
915                                 &(termInfo->nl_to_space));
916
917     *ret_canvas  = _DtCanvasCreate (TermVirtInfo, (_DtCvPointer) termInfo);
918
919     if (*ret_canvas == NULL)
920             return -1;
921
922     return 0;
923 }
924
925
926 /******************************************************************************
927  * Function: int _DtHelpTermGetTopicData(canvasHandle,volHandle,
928  *                                           locationId,helpList,hyperList)
929  *
930  * Parameters:
931  *              canvasHandle    Canvas used to retrieve the info; MUST
932  *                              be a Terminal canvas Since it isn't easy
933  *                              to verify this, we don't try.  So if the
934  *                              Canvas ISN'T a Terminal Canvas, we'll
935  *                              crash.
936  *              volHandle       Help volume to use
937  *              locationId      Specifies the locationId of the desired topic.
938  *              helpList        Returns a NULL terminated array of
939  *                              strings.
940  *              hyperList       Returns a NULL terminated array of
941  *                              DtHelpHyperLines containing the hyperlinks
942  *                              found in the topic.
943  *
944  * Returns:     0 for success, -1 for failure.
945  *
946  * errno Values:
947  *              EINVAL          'helpVolume', 'locationId', 'helpList',
948  *                              or 'hyperList' were NULL. 'maxColumns'
949  *                              was less than one.
950  *              open(2)         errno set via an open call on
951  *                              the file for 'locationId'.
952  *              DtErrorMalloc
953  *              DtErrorExceedMaxSize
954  *                              When following symbolic links, the
955  *                              new path will exceed the system
956  *                              maximum file path length.
957  *              DtErrorIllegalPath
958  *                              When following symbolic links, the
959  *                              new path would change to a parent
960  *                              directory beyond the beginning
961  *                              of the base path.
962  *              DtErrorIllegalDatabaseFile
963  *                              Specifies that 'helpVolume' is
964  *                              an illegal database file.
965  *              DtErrorMissingFilenameRes
966  *                              Specifies that the 'Filename/filename'
967  *                              resource for the topic does not exist.
968  *              DtErrorMissingFileposRes
969  *                              Specifies that the 'Filepos/filepos'
970  *                              resource for the topic does not exist.
971  *              DtErrorLocIdNotFound
972  *                              Specifies that 'locationId' was not found.
973  *              DtErrorFormattingLabel
974  *                              A label has illegal syntax.
975  *              DtErrorHyperType
976  *                              Invalid (negative) hypertype.
977  *              DtErrorFormattingLink
978  *                              Invalid <LINK>.
979  *              DtErrorHyperSpec
980  *                              Invalid 'hyper_specification' in the
981  *                              the <LINK>.
982  *              DtErrorFormattingId
983  *                              Invalid <ID> syntax.
984  *              DtErrorFormattingTitle
985  *                              Invalid <TITLE> syntax.
986  *
987  * Purpose:     _DtHelpTermGetTopicData retrieves Help Files content with
988  *              in a form understood by a terminal
989  *
990  *****************************************************************************/
991 int
992 _DtHelpTermGetTopicData(
993     _DtCvHandle      canvasHandle,
994     _DtHelpVolumeHdl      volHandle,
995     char *            locationId,
996     char * * *        helpList,
997     DtHelpHyperLines ** hyperList)
998 {
999     int          result = -1;
1000     int          offset;
1001     _DtCvUnit    maxRows;
1002     _DtCvUnit    maxWidth;
1003     char * *     strList;
1004     char*        fileName = NULL;
1005     _DtHelpCeLockInfo lockInfo;
1006     _DtCvTopicPtr        topic;
1007     TerminalInfo * termInfo;
1008     _FrmtUiInfo     myUiInfo;
1009
1010     termInfo = GetTermInfo(canvasHandle);
1011
1012     _DtHelpProcessLock();
1013     if (WcSpace == 0)
1014         mbtowc (&WcSpace, " ", 1);
1015     _DtHelpProcessUnlock();
1016
1017     /*
1018      * find the filename and the Id string.
1019      */
1020     if (_DtHelpCeLockVolume(volHandle, &lockInfo) != 0)
1021       {
1022         return -1;
1023       }
1024
1025     if (_DtHelpCeFindId(volHandle,locationId,lockInfo.fd,&fileName,&offset)==0)
1026       {
1027         _DtHelpCeUnlockVolume(lockInfo);
1028         return -1;
1029       }
1030
1031     /*
1032      * create the ui structure for the parsing.
1033      */
1034 #ifdef  XTAG
1035     myUiInfo.load_graphic = TermFindGraphic;
1036 #else
1037     myUiInfo.load_graphic = NULL;
1038 #endif /* XTAG */
1039     myUiInfo.resolve_spc  = TermResolveSpc;
1040     myUiInfo.load_font    = TermGetFont;
1041     myUiInfo.destroy_region = NULL;
1042     myUiInfo.exec_filter  = NULL;
1043     myUiInfo.client_data  = (_DtCvPointer) termInfo;
1044     myUiInfo.line_width   = 0;
1045     myUiInfo.line_height  = 1;
1046     myUiInfo.leading      = 0;
1047     myUiInfo.avg_char     = 1;
1048     myUiInfo.nl_to_space  = termInfo->nl_to_space;
1049
1050     /*
1051      * Format the topic.
1052      */
1053     result = _DtHelpCeGetVolumeFlag(volHandle);
1054
1055     _DtHelpProcessLock();
1056     if (result == 1)
1057         result = _DtHelpCeParseSdlTopic(volHandle,
1058                                                 &myUiInfo,
1059                                                 lockInfo.fd,
1060                                                 offset, NULL, True, &topic);
1061     else if (result == 0)
1062         result = _DtHelpCeFrmtCcdfTopic(volHandle, fileName,
1063                                                 offset, NULL, &myUiInfo,
1064                                                 &topic);
1065     _DtHelpProcessUnlock();
1066
1067     /* if successfully formatted topic */
1068     if (result != -1)
1069     {
1070         int     i;
1071         int     len;
1072         wchar_t **wcList;
1073         _DtCanvasStruct *myCStruct = (_DtCanvasStruct *)canvasHandle;
1074
1075         /* build the help text list, if requested */
1076         if (NULL != helpList)
1077         {
1078            _DtCanvasSetTopic(canvasHandle, topic, _DtCvIGNORE_BOUNDARY,
1079                                                 &maxWidth, &maxRows, NULL);
1080    
1081            /*
1082             * The 'maxRows' variable is really misnamed; it's really the
1083             * 'maxY', and is 0-based.  Thus, the 'lines' and 'wc_num'
1084             * arrays need to be 'maxRows+1', in order to hold all the 
1085             * entries.  Likewise, 'strList' must be 'maxRows+2', because
1086             * it also needs to be NULL terminated.
1087             */
1088            termInfo->lines = (wchar_t **)malloc(sizeof(wchar_t *) *(maxRows+1));
1089            termInfo->wc_num = (size_t   *)malloc(sizeof(size_t) * (maxRows+1));
1090            strList          = (char **)   malloc(sizeof(char *) * (maxRows+2));
1091            if (termInfo->lines == NULL || termInfo->wc_num == NULL ||
1092                                                         strList == NULL)
1093            {
1094               free(fileName);
1095               if (termInfo->lines != NULL)
1096                 free(termInfo->lines);
1097               if (termInfo->wc_num != NULL)
1098                 free(termInfo->wc_num);
1099               if (strList != NULL)
1100                 free(strList);
1101               _DtHelpCeUnlockVolume(lockInfo);
1102               return -1;
1103            }
1104    
1105            for (i = 0; i <= maxRows; i++)
1106              {
1107                termInfo->lines[i]  = NULL;
1108                termInfo->wc_num[i] = 0;
1109              }
1110    
1111            _DtCanvasRender(canvasHandle, 0, 0, maxWidth, maxRows,
1112                                 _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
1113    
1114            *helpList = strList;
1115            wcList    = termInfo->lines;
1116            for (i = 0; i <= maxRows; i++, wcList++, strList++)
1117            {
1118               if (*wcList == NULL)
1119               {
1120                  *strList  = (char *) malloc (1);
1121                  **strList = '\0';
1122               }
1123               else
1124               {
1125                 len      = (termInfo->wc_num[i] + 1) * MB_CUR_MAX;
1126                 *strList = (char *) malloc (sizeof (char) * len);
1127                 if (*strList != NULL)
1128                     wcstombs(*strList, *wcList, len);
1129               }
1130            }
1131    
1132           *strList = NULL;
1133
1134            /*
1135             * free the allocated memory
1136             */
1137            for (i = 0, wcList = termInfo->lines; i <= maxRows; i++, wcList++)
1138                if (*wcList != NULL)
1139                    free(*wcList);
1140            free(termInfo->lines);
1141            free(termInfo->wc_num);
1142
1143         }  /* if requested help text */
1144
1145         /*
1146          * build the hyperlinks list, if requested
1147          */
1148         if ( NULL != hyperList )
1149         {
1150            *hyperList = NULL;
1151            for (i = 0; result != -1 && i < myCStruct->link_data->max; i++)
1152                result = AddHyperToList(volHandle, canvasHandle, i, hyperList);
1153         }
1154     }  /* if successfully formatted topic */
1155
1156     _DtCanvasClean(canvasHandle);
1157     _DtHelpDestroyTopicData(topic, NULL, NULL);
1158
1159     free(fileName);
1160     _DtHelpCeUnlockVolume(lockInfo);
1161     return result;
1162
1163 }  /* End _DtHelpTermGetTopicData */
1164
1165 /******************************************************************************
1166  * Function: int _DtHelpGetTopicDataHandles(ret_canvasHandle,ret_volHandle)
1167  *
1168  * Parameters:
1169  *              ret_canvasHandle        Canvas used to retrieve the info
1170  *              ret_volHandle   Help volume in use
1171  *
1172  * Returns:
1173  *  0:  canvas handle & volHandle are not NULL
1174  * -1:  canvas handle & volHandle are NULL
1175  ******************************************************************************/
1176 int
1177 _DtHelpGetTopicDataHandles(
1178     _DtCvHandle *    ret_canvasHandle,
1179     _DtHelpVolumeHdl *    ret_volHandle)
1180 {
1181    _DtHelpProcessLock();
1182    *ret_canvasHandle = MyCanvas;
1183    *ret_volHandle = MyVolume;
1184    if (MyCanvas != NULL && MyVolume != NULL)
1185      {
1186        _DtHelpProcessUnlock();
1187        return 0;
1188      }
1189    else
1190      {
1191        _DtHelpProcessUnlock();
1192        return -1;
1193      }
1194 }
1195
1196
1197 /******************************************************************************
1198  * Function: int _DtHelpGetTopicData (char *helpVolume, char *locationId,
1199  *              int maxColumns, char ***helpList, DtHelpHyperLines **hyperList)
1200  *
1201  * Parameters:
1202  *              helpVolume      Specifies a file path to the volume.
1203  *              locationId      Specifies the locationId of the desired topic.
1204  *              maxColumns      Specifies the column width of the window
1205  *                              for which to format the information.
1206  *              helpList        Returns a NULL terminated array of
1207  *                              strings.
1208  *              hyperList       Returns a NULL terminated array of
1209  *                              DtHelpHyperLines containing the hyperlinks
1210  *                              found in the topic.
1211  *
1212  * Returns:     0 for success, -1 for failure.
1213  *
1214  * errno Values:
1215  *              EINVAL          'helpVolume', 'locationId', 'helpList',
1216  *                              or 'hyperList' were NULL. 'maxColumns'
1217  *                              was less than one.
1218  *              getcwd(2)       errno set via a getcwd call.
1219  *              readlink(2)     errno set via a readlink call.
1220  *              open(2)         errno set via an open call on
1221  *                              the file for 'locationId'.
1222  *              DtErrorMalloc
1223  *              DtErrorExceedMaxSize
1224  *                              When following symbolic links, the
1225  *                              new path will exceed the system
1226  *                              maximum file path length.
1227  *              DtErrorIllegalPath
1228  *                              When following symbolic links, the
1229  *                              new path would change to a parent
1230  *                              directory beyond the beginning
1231  *                              of the base path.
1232  *              DtErrorIllegalDatabaseFile
1233  *                              Specifies that 'helpVolume' is
1234  *                              an illegal database file.
1235  *                      DtErrorMissingFilenameRes
1236  *                              Specifies that the 'Filename/filename'
1237  *                              resource for the topic does not exist.
1238  *              DtErrorMissingFileposRes
1239  *                              Specifies that the 'Filepos/filepos'
1240  *                              resource for the topic does not exist.
1241  *              DtErrorLocIdNotFound
1242  *                              Specifies that 'locationId' was not found.
1243  *              DtErrorFormattingLabel
1244  *                              A label has illegal syntax.
1245  *              DtErrorHyperType
1246  *                              Invalid (negative) hypertype.
1247  *              DtErrorFormattingLink
1248  *                              Invalid <LINK>.
1249  *              DtErrorHyperSpec
1250  *                              Invalid 'hyper_specification' in the
1251  *                              the <LINK>.
1252  *              DtErrorFormattingId
1253  *                              Invalid <ID> syntax.
1254  *              DtErrorFormattingTitle
1255  *                              Invalid <TITLE> syntax.
1256  *
1257  * Purpose:     _DtHelpGetTopicData formats Help Files with
1258  *              formatting information
1259  *              into a form understood by a terminal
1260  *
1261  *****************************************************************************/
1262 int
1263 _DtHelpGetTopicData (
1264         char *               helpVolume,
1265         char *               locationId,
1266         int                  maxColumns,
1267         char * * *           helpList,
1268         DtHelpHyperLines * * hyperList )
1269 {
1270     int           result = -1;
1271     _DtHelpVolumeHdl  volume = NULL;
1272     char *        path = NULL;
1273
1274     /* find the volume (path is malloc'd) */
1275     path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, helpVolume,
1276                                   _DtHelpFileSuffixList,False,R_OK);
1277     if (path == NULL) { errno = EINVAL; return -1; }          /* RETURN */
1278
1279     /* open new canvas or reuse old one with new size */
1280     _DtHelpProcessLock();
1281     if (MyCanvas == NULL)
1282     {
1283        _DtHelpTermCreateCanvas(maxColumns,&MyCanvas);
1284        if (MyCanvas == NULL)
1285        {
1286           free(path);
1287           _DtHelpProcessUnlock();
1288           return -1;            /* RETURN: errno=from CreateCanvas */
1289        }
1290     }
1291     else
1292     {
1293        MyInfo.max_columns = maxColumns;
1294        _DtCanvasResize (MyCanvas, _DtCvFALSE, NULL, NULL);
1295     }
1296
1297     if (_DtHelpOpenVolume (helpVolume, &volume) == -1)
1298     {
1299         free(path);
1300         _DtHelpProcessUnlock();
1301         return -1;              /* RETURN: errno=from OpenVolume */
1302     }
1303
1304     /* release any previously opened volume */
1305     if (MyVolume)
1306         _DtHelpCloseVolume (MyVolume);
1307
1308     /* assign the new volume */
1309     MyVolume = volume;
1310
1311     /* get the terminal info */
1312    result = _DtHelpTermGetTopicData(MyCanvas,MyVolume,locationId,helpList,hyperList);
1313
1314    _DtHelpProcessUnlock();
1315    free(path);
1316    return result;
1317 }
1318
1319 /*****************************************************************************
1320  * Function: int _DtHelpProcessLinkData (char * ref_volume,DtHelpHyperLines *hyperLine,
1321  *                                      char **ret_helpVolume, char **ret_locationId)
1322  *
1323  * Parameters:
1324  *              hyperLine       Specifies the hypertext line that
1325  *                              the caller wishes to be resolved.
1326  *              helpVolume      Returns the help volume specified by
1327  *                              'hyperLine'.
1328  *              locationId      Returns the location Id specified by
1329  *                              'hyperLine'.
1330  *
1331  * Returns:     0 if successful, -1 if errors.
1332  *
1333  * errno Values:
1334  *              EINVAL          'hyperLines', 'helpVolume', or 'locationId'
1335  *                              is NULL.
1336  *              DtErrorMalloc
1337  *              DtErrorHyperType
1338  *                              The hyper type is not _DtJUMP_REUSE,
1339  *                              _DtJUMP_NEW, or _DtDEFINITION.
1340  *              DtErrorHyperSpec
1341  *                              Invalid hyper specification.
1342  *              DtErrorIllegalPath
1343  *                              The volume used by the link spec (either
1344  *                              embedded or the ref_volume) could not be
1345  *                              located.
1346  *
1347  * Purpose:     _DtHelpProcessLinkData resolves a hypertext specification
1348  *              into a pathname to a help volume and a location Id within
1349  *              the help volume.
1350  *
1351  *****************************************************************************/
1352 int
1353 _DtHelpProcessLinkData (
1354     char *              ref_volume,
1355     DtHelpHyperLines  * hyperLine,
1356     char * *            ret_helpVolume,
1357     char * *            ret_locationId )
1358 {
1359     char * linkSpec   = NULL;
1360     char * volumeName = NULL;
1361     char * idToken    = NULL;
1362
1363     /* check params */
1364     if (ref_volume == NULL || hyperLine == NULL ||
1365                         ret_helpVolume == NULL || ret_locationId == NULL)
1366     {
1367         errno = EINVAL;
1368         return -1;
1369     }
1370
1371     /* only process SameVolume or CrossVolume links */
1372     switch (hyperLine->hyper_type)
1373     {
1374         case _DtCvLinkType_SameVolume:
1375         case _DtCvLinkType_CrossLink:
1376                 break;
1377
1378         default:
1379                 errno = DtErrorHyperType;
1380                 return -1;                      /* RETURN */
1381     }
1382
1383     /* Initialize the pointers. */
1384     *ret_helpVolume  = NULL;
1385     *ret_locationId = NULL;
1386
1387     /* get working copy of spec */
1388     linkSpec = strdup (hyperLine->specification);
1389     if (linkSpec == NULL)
1390     {
1391         errno = DtErrorMalloc;
1392         return -1;
1393     }
1394
1395     /* parse the link spec.  Syntax is: "[volume] locationId" */
1396     if (linkSpec == NULL || *linkSpec == EOS)
1397     {
1398         errno = DtErrorHyperSpec;      /* no spec */
1399     }
1400     else  /* at least one token exists */
1401     {
1402         volumeName = linkSpec;  /* posit that first token is the volume */
1403
1404         /* look for another possible token */
1405         idToken = NULL;
1406         _DtHelpCeStrchr (linkSpec," ",MB_CUR_MAX,&idToken);
1407
1408         /* second token? */
1409         if (idToken) /* second token */
1410         {
1411             /* separate the tokens and advance idToken to first valid char */
1412             *idToken = EOS; idToken++;
1413
1414             /* find the fully qualified volume (volName is malloc'd) */
1415             volumeName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, volumeName,
1416                               _DtHelpFileSuffixList,False,R_OK);
1417             if (volumeName == NULL)
1418                 errno = DtErrorIllegalPath;
1419         }
1420         else /* no second token */
1421         {
1422             idToken = volumeName;
1423             /* find the fully qualified volume (volName is malloc'd) */
1424             volumeName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, ref_volume,
1425                               _DtHelpFileSuffixList,False,R_OK);
1426             if (volumeName == NULL)
1427                 errno = DtErrorIllegalPath;
1428         }
1429
1430         if (idToken && volumeName)
1431         {
1432             *ret_helpVolume = volumeName;  /* already allocd by _DtHelpFileLocate */
1433             *ret_locationId = strdup (idToken);
1434             if (*ret_locationId == NULL)
1435                 errno = DtErrorMalloc;
1436         }
1437     } /* if at least one token exists */
1438
1439     free (linkSpec);
1440          
1441     return ( (*ret_helpVolume && *ret_locationId) ? 0 : -1 );
1442
1443 }  /* End _DtHelpProcessLinkData */
1444
1445 /*****************************************************************************
1446  * Function: void _DtHelpFreeTopicData (char **helpList,
1447  *                                      DtHelpHyperLines *hyperList)
1448  *
1449  * Parameters:
1450  *              helpList        Specifies a pointer to a NULL terminated
1451  *                              array of strings.
1452  *              hyperList       Specifies a pointer to a NULL terminated
1453  *                              list of DtHelpHyperLines.
1454  *
1455  * Returns:     Nothing
1456  *
1457  * Purpose:     _DtHelpFreeTopicData frees the data associated with a topic.
1458  *
1459  *****************************************************************************/
1460 void
1461 _DtHelpFreeTopicData (
1462         char             **helpList,
1463         DtHelpHyperLines     *hyperList)
1464 {
1465     if (helpList != NULL)
1466         _DtHelpCeFreeStringArray (helpList);
1467
1468     if (hyperList != NULL)
1469         DeallocateHyperArray (hyperList);
1470
1471 }  /* End _DtHelpFreeTopicData */
1472
1473 /******************************************************************************
1474  * Function: int _DtHelpGetTopicChildren (char *helpVolume, char *topic_id,
1475  *              char ***ret_children)
1476  *
1477  * Parameters:
1478  *              helpVolume      Specifies a file path to the volume.
1479  *              topic_id        Specifies the id of the desired topic.
1480  *              ret_children    Returns a NULL terminated array of
1481  *                              strings. The memory for these strings
1482  *                              *IS OWNED* by the caller and must be freed
1483  *                              after use.
1484  *
1485  * Returns:     > 0 for success, -1 for failure.
1486  *
1487  * errno Values:
1488  *
1489  * Purpose:     _DtHelpGetTopicChildren returns the topic ids of the children
1490  *              for a given topic id.
1491  *
1492  *****************************************************************************/
1493 int
1494 _DtHelpGetTopicChildren (
1495         char             *helpVolume,
1496         char             *topic_id,
1497         char            ***ret_children)
1498 {
1499     int           result = -1;
1500     _DtHelpVolumeHdl  volume = NULL;
1501     char *        path;
1502
1503     /* Initialize the pointer */
1504     *ret_children  = NULL;
1505
1506     /* find the volume (path is malloc'd) */
1507     path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, helpVolume,
1508                                   _DtHelpFileSuffixList,False,R_OK);
1509     if (path == NULL) { errno = EINVAL; return -1; }          /* RETURN */
1510
1511     /* open new canvas or reuse old one with new size */
1512     _DtHelpProcessLock();
1513     if (MyCanvas == NULL)
1514     {
1515        _DtHelpTermCreateCanvas(72,&MyCanvas);  /* 72: arbitary value for max columns */
1516        if (MyCanvas == NULL)
1517        {
1518           free(path);
1519           _DtHelpProcessUnlock();
1520           return -1;            /* RETURN: errno=??? */
1521        }
1522     }
1523
1524     if (_DtHelpOpenVolume (helpVolume, &volume) == -1)
1525     {
1526         free(path);
1527         _DtHelpProcessUnlock();
1528         return -1;              /* RETURN: errno=??? */
1529     }
1530
1531     /* release any previously opened volume */
1532     if (MyVolume)
1533         _DtHelpCloseVolume (MyVolume);
1534
1535     /* assign the new volume */
1536     MyVolume = volume;
1537
1538     /* Get the children */
1539    result = _DtHelpCeGetTopicChildren(MyVolume, topic_id, ret_children);
1540
1541    _DtHelpProcessUnlock();
1542    free(path);
1543    return result;
1544 }
1545
1546