Merge branch 'master' into cde-next
[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 libraries 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             int 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                 int 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         wchar_t *wcp = (wchar_t *) string;
360
361         while (0 < byte_len)
362           {
363             wcStr[x++] = *wcp++;
364             byte_len--;
365 }
366       }
367 }
368
369 /*****************************************************************************
370  * Function:    void TermRenderElem ();
371  *
372  * Parameters:
373  *
374  * Returns:
375  *
376  * Purpose:
377  *
378  *****************************************************************************/
379 static  void
380 TermRenderElem (
381     _DtCvPointer        client_data,
382     _DtCvElemType       elem_type,
383     _DtCvUnit           x,
384     _DtCvUnit           y,
385     int                 link_type,
386     _DtCvFlags          old_flags,
387     _DtCvFlags          new_flags,
388     _DtCvElemType       trav_type,
389     _DtCvPointer        trav_data,
390     _DtCvPointer        data)
391 {
392     _DtCvStringInfo *strInfo;
393     _DtCvRenderInfo *posInfo = (_DtCvRenderInfo *) data;
394
395     if (_DtCvSTRING_TYPE == elem_type)
396       {
397         strInfo = (_DtCvStringInfo *) posInfo->info;
398         TermStrDraw (client_data, x, y, strInfo->string, strInfo->byte_len,
399                         strInfo->wc        , strInfo->font_ptr,
400                         posInfo->box_x     , posInfo->box_y   ,
401                         posInfo->box_height, link_type,
402                         old_flags          , new_flags);
403       }
404     else if (_DtCvREGION_TYPE == elem_type)
405       {
406         const char *spcStr = (const char*) posInfo->info;
407         int len = spcStr ? strlen(spcStr) : 0;
408
409         TermStrDraw (client_data, x, y, spcStr, len, 0, 0,
410                         posInfo->box_x     , posInfo->box_y,
411                         posInfo->box_height, link_type,
412                         old_flags          , new_flags);
413       }
414 }
415
416 /*****************************************************************************
417  * Function:    void TermMetrics ();
418  *
419  * Parameters:
420  *
421  * Returns:
422  *
423  * Purpose:
424  *
425  *****************************************************************************/
426 static  _DtCvSpaceMetrics       defLinkMetrics = { 0, 0, 0, 0 };
427
428 static  void
429 TermMetrics (
430     _DtCvPointer                 client_data,
431     _DtCvElemType       elem_type,
432     _DtCvPointer        ret_metrics)
433 {
434     TerminalInfo *pTerm = (TerminalInfo *) client_data;
435     _DtCvSpaceMetrics *retSpace = (_DtCvSpaceMetrics *) ret_metrics;
436
437     if (_DtCvCANVAS_TYPE == elem_type)
438       {
439         _DtCvMetrics *retCanvas = (_DtCvMetrics *) ret_metrics;
440
441         retCanvas->width          = pTerm->max_columns;
442         retCanvas->height         = 50;
443         retCanvas->top_margin     = 0;
444         retCanvas->side_margin    = 0;
445         retCanvas->line_height    = 1;
446         retCanvas->horiz_pad_hint = 1;
447       }
448
449     else if (_DtCvLOCALE_TYPE == elem_type)
450       {
451         _DtCvLocale *retLocale = (_DtCvLocale *) ret_metrics;
452
453         retLocale->line_wrap_mode   = _DtCvModeWrapNone;
454         retLocale->cant_begin_chars = pTerm->cant_begin_chars;
455         retLocale->cant_end_chars   = pTerm->cant_end_chars;
456       }
457     else if (_DtCvLINK_TYPE == elem_type || _DtCvTRAVERSAL_TYPE == elem_type)
458         *retSpace = defLinkMetrics;
459 }
460
461 /*****************************************************************************
462  * Function:    void TermGetFont ();
463  *
464  * Parameters:
465  *
466  * Returns:
467  *
468  * Purpose:
469  *
470  *****************************************************************************/
471 static  void
472 TermGetFont (
473     _DtCvPointer                 client_data,
474     char                *lang,
475     char                *charset,
476     _DtHelpFontHints     font_attr,
477     _DtCvPointer        *ret_font )
478 {
479     *ret_font = (_DtCvPointer) 0;
480 }
481
482 /*****************************************************************************
483  * Function:    _DtCvStatus TermResolveSpc ();
484  *
485  * Parameters:
486  *
487  * Returns:
488  *
489  * Purpose:
490  *
491  *****************************************************************************/
492 static  _DtCvStatus
493 TermResolveSpc (
494     _DtCvPointer         client_data,
495     char                *lang,
496     char                *charset,
497     _DtHelpFontHints     font_attr,
498     char                *spc_symbol,
499     _DtCvPointer        *ret_handle,
500     _DtCvUnit           *ret_width,
501     _DtCvUnit           *ret_height,
502     _DtCvUnit           *ret_ascent)
503 {
504     const char* spcStr;
505
506     /*
507      * initialize the returned information to nothing.
508      */
509     *ret_handle = NULL;
510     *ret_height = 0;
511     *ret_width  = 0;
512     *ret_ascent = 0;
513
514     spcStr = _DtHelpCeResolveSpcToAscii (spc_symbol);
515
516     if (spcStr != NULL)
517       {
518         *ret_handle = ((_DtCvPointer)(spcStr));
519         *ret_height = 1;
520         *ret_width  = strlen(spcStr);
521
522       }
523
524     return 0;
525 }
526
527 /*****************************************************************************
528  * Function:    void TermFontMetrics ();
529  *
530  * Parameters:
531  *
532  * Returns:
533  *
534  * Purpose:
535  *
536  *****************************************************************************/
537 static  void
538 TermFontMetrics (
539     _DtCvPointer         client_data,
540     _DtCvPointer font_ptr,
541     _DtCvUnit   *ret_ascent,
542     _DtCvUnit   *ret_descent,
543     _DtCvUnit   *char_width,
544     _DtCvUnit   *ret_super,
545     _DtCvUnit   *ret_sub)
546 {
547     if (ret_ascent)
548         *ret_ascent = 0;
549     if (ret_descent)
550         *ret_descent = 0;
551     if (char_width)
552         *char_width = 0;
553     if (ret_super)
554         *ret_super = 0;
555     if (ret_sub)
556         *ret_sub = 0;
557
558     return;
559 }
560
561 /*****************************************************************************
562  * Function:    _DtCvUnit TermStrWidth ();
563  *
564  * Parameters:
565  *
566  * Returns:
567  *
568  * Purpose:
569  *
570  *****************************************************************************/
571 static  _DtCvUnit
572 TermStrWidth (
573     _DtCvPointer         client_data,
574     _DtCvElemType       elem_type,
575     _DtCvPointer        data)
576 {
577    _DtCvStringInfo *strInfo = (_DtCvStringInfo *) data;
578
579    if (elem_type != _DtCvSTRING_TYPE)
580         return 0;
581
582    return ((_DtCvUnit)(strInfo->byte_len));
583 }
584
585 /******************************************************************************
586  * End Canvas functions
587  * Begin other private functions
588  ******************************************************************************/
589
590 /******************************************************************************
591  * Function: DtHelpHyperLines *AddHyperToArray (DtHelpHyperLines *array_ptr,
592  *                              int value, char *link_spec, char *title)
593  *
594  * Parameters:
595  *              array_ptr       Specifies a NULL terminated list of
596  *                              DtHelpHyperLines or NULL.
597  *              value           Specifies the link type.
598  *              link_spec       Specifies the link specification.
599  *              title           Specifies the title of the link.
600  *
601  * Returns:     A ptr to the new DtHelpHyperLines if successful,
602  *              NULL if errors.
603  *
604  * errno Values:
605  *              DtErrorMalloc
606  *
607  * Purpose:     Add a hypertext link to an array of DtHelpHyperLines.
608  * 
609  *****************************************************************************/
610 static  DtHelpHyperLines *
611 AddHyperToArray(
612         DtHelpHyperLines *array_ptr,
613         int              value,
614         int              win_hint,
615         char            *link_spec,
616         char            *title )
617 {
618     DtHelpHyperLines *next;
619     int            num = 0;
620
621
622     if (array_ptr)
623       {
624         for (next = array_ptr; next->specification != NULL; next++)
625                 num++;
626
627         if (((num + 1) % GROW_SIZE) == 0)
628             array_ptr = (DtHelpHyperLines *) realloc ((void *) array_ptr,
629                         (sizeof (DtHelpHyperLines) * (num + 1 + GROW_SIZE)));
630       }
631     else
632         array_ptr = (DtHelpHyperLines *) malloc (
633                                         sizeof (DtHelpHyperLines) * GROW_SIZE);
634
635     if (array_ptr == NULL)
636         errno = DtErrorMalloc;
637     else
638       {
639         next = array_ptr + num;
640
641         next->hyper_type    = value;
642         next->win_hint      = win_hint;
643         next->specification = strdup(link_spec);
644         next->title         = title;
645         next++;
646
647         next->specification = NULL;
648         next->title         = NULL;
649       }
650
651     return array_ptr;
652 }
653
654 /******************************************************************************
655  * Function:  void DeallocateHyperArray (DtHelpHyperLines *array_ptr)
656  *
657  * Parameters:
658  *              array_ptr       Specifies a NULL terminated array of
659  *                              DtHelpHyperLines.
660  *
661  * Returns:     Nothing
662  *
663  * errno Values:
664  *
665  * Purpose:     De-allocate an array of DtHelpHyperLines structures.
666  *
667  *****************************************************************************/
668 static  void
669 DeallocateHyperArray(
670         DtHelpHyperLines        *array_ptr )
671 {
672     DtHelpHyperLines *next = array_ptr;
673
674     if (array_ptr)
675       {
676         while (next->title && next->specification)
677           {
678             free (next->title);
679             free (next->specification);
680             next++;
681           }
682         free (array_ptr);
683       }
684 }
685
686 /******************************************************************************
687  * Function: int AddHyperToList(
688  * 
689  * Parameters:
690  *
691  * Returns:      0 if successful.
692  *              -1 if unrecoverable errors.
693  *              -2 if could not resolve the hypertext link.
694  *
695  * errno Values:
696  *              DtErrorMalloc
697  *              DtErrorFormattingLabel
698  *                              A label has illegal syntax.
699  *              DtErrorHyperType
700  *                              Invalid (negative) hypertype.
701  *              DtErrorFormattingLink
702  *                              Invalid <LINK>.
703  *              DtErrorHyperSpec
704  *                              Invalid 'hyper_specification' in the
705  *                              the <LINK>.
706  *              DtErrorFormattingId
707  *                              Invalid <ID> syntax.
708  *
709  * Purpose:     Process the result of a hypertext link, filling out
710  *              a hypertext structure element with the information.
711  *                      
712  *****************************************************************************/
713 static  int
714 AddHyperToList(
715     _DtHelpVolumeHdl volume,
716     _DtCvHandle canvas,
717     int          i,
718     DtHelpHyperLines    **ret_list)
719 {
720     _DtCanvasStruct     *myCanvas = (_DtCanvasStruct *)canvas;
721     _DtCvLinkInfo        hyperInfo;
722     _DtHelpVolumeHdl     newVol    = NULL;
723     _DtHelpVolumeHdl     useVol    = volume;
724     char                *volName   = NULL;
725     char                *title     = NULL;
726     char                *allocName = NULL;
727     char                *spec      = NULL;
728     char                *id;
729     int                 result    = -3;
730
731     if (_DtLinkDbGetLinkInfo(myCanvas->link_data, i,
732                                 myCanvas->virt_functions.exec_cmd_filter,
733                                 myCanvas->client_data, &hyperInfo) == 0)
734       {
735         result = 0;
736         if (hyperInfo.description == NULL)
737           {
738             id = hyperInfo.specification;
739             switch (hyperInfo.hyper_type)
740               {
741                 case _DtCvLinkType_CrossLink:
742                         spec = strdup (id);
743                         if (spec != NULL)
744                           {
745                             volName = spec;
746                             id = NULL;
747                             _DtHelpCeStrchr (spec," ",MB_CUR_MAX,&id);
748                             if (id != NULL)
749                               {
750                                 *id = '\0';
751                                 id++;
752
753                                 /* find the volume (volName is malloc'd) */
754                                 allocName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, volName,
755                                                  _DtHelpFileSuffixList,False,R_OK);
756                                 if (allocName == NULL) 
757                                      result = -2;
758
759                                 if (_DtHelpOpenVolume(allocName, &newVol)==0)
760                                     useVol = newVol;
761                                 else
762                                     result = -2;
763                               }
764                             else
765                                 id = spec;
766                           }
767                         else
768                             result = -1;
769                         /* fall thru */
770                 case _DtCvLinkType_SameVolume:
771                         if (result == 0)
772                           {
773                             result = _DtHelpGetTopicTitle(useVol, id, &title);
774                             if (result == -2)
775                                 HyperErr = DtErrorLocIdNotFound;
776                           }
777
778                         if (newVol != NULL)
779                             _DtHelpCloseVolume(newVol);
780                         if (spec != NULL)
781                             free(spec);
782                         if (allocName != NULL)
783                             free(allocName);
784
785                         break;
786
787                 case _DtCvLinkType_Execute:
788                         title = (char *) malloc(strlen(id) + 11);
789                         sprintf(title, "Execute \"%s\"", id);
790                         break;
791
792                 case _DtCvLinkType_ManPage:
793                         title = (char *) malloc(strlen(id) + 13);
794                         sprintf(title, "Man Page \"%s\"", id);
795                         break;
796
797                 case _DtCvLinkType_AppDefine:
798                         title = (char *) malloc(strlen(id) + 26);
799                         sprintf(title, "Application Link Type \"%s\"", id);
800                         break;
801
802                 case _DtCvLinkType_TextFile:
803                         title = (char *) malloc(strlen(id) + 12);
804                         sprintf(title, "Text File \"%s\"", id);
805                         break;
806                 default:
807                         title = strdup ("Unkown link type");
808                         break;
809
810               }
811           }
812         else
813           {
814             title = strdup (hyperInfo.description);
815           }
816       }
817
818     if (result == -2)
819         *ret_list = AddHyperToArray (*ret_list, -(hyperInfo.hyper_type + 1),
820                                 hyperInfo.win_hint,
821                                 hyperInfo.specification,
822                                 strdup("Invalid Link"));
823     else if (result >= 0)
824         *ret_list = AddHyperToArray (*ret_list, hyperInfo.hyper_type,
825                                 hyperInfo.win_hint,
826                                 hyperInfo.specification,
827                                 title);
828
829     /*
830      * report unable to resolve the hypertext link
831      */
832     if (result == -2)
833         return -2;
834
835     if (result == -1 || *ret_list == NULL)
836         return -1;
837
838     return (0);
839
840 } /* End AddHyperToList */
841
842 /******************************************************************************
843  * Function: TerminalInfo * GetTermInfo(canvasHandle)
844  *
845  * Parameters:
846  *              canvasHandle    Canvas whose client_data is a TerminalInfo *
847  *
848  * Returns:     0 for success, -1 for failure.
849  *
850  ******************************************************************************/
851 static TerminalInfo * 
852 GetTermInfo(
853            _DtCvHandle canvasHandle)
854 {
855    _DtCanvasStruct * canvas = (_DtCanvasStruct *) canvasHandle;
856
857    return (TerminalInfo *) canvas->client_data;
858 }
859
860 /******************************************************************************
861  *
862  * Public functions
863  *
864  ******************************************************************************/
865 /******************************************************************************
866  * Function: int _DtHelpTermCreateCanvas (int maxColumns,_DtCvHandle * ret_canvas)
867  *
868  * Parameters:
869  *              maxColumns      Specifies the column width of the window
870  *                              for which to format the information.
871  *              ret_canvas      handle to the canvas that was created
872  *
873  * Returns:     0 for success, -1 for failure.
874  *
875  * errno Values:
876  *              EINVAL          'ret_canvas' was NULL or 'maxColumns'
877  *                              was less than one.
878  *              ENOMEM          unable to allocate necessary memory
879  *              DtErrorMalloc
880  *
881  * Purpose:     _DtHelpTermCreateCanvas creates a canvas that use 
882  *              text-only content processing routines
883  *
884  *****************************************************************************/
885 int
886 _DtHelpTermCreateCanvas (
887         int               maxColumns,
888         _DtCvHandle *    ret_canvas)
889 {
890     TerminalInfo * termInfo;
891
892     /*
893      * check the parameters
894      */
895     if (maxColumns < 1 || ret_canvas == NULL)
896       {
897         errno = EINVAL;
898         return -1;
899       }
900
901     termInfo = (TerminalInfo *) malloc(sizeof(TerminalInfo));
902     if (termInfo == NULL)
903     {
904         errno = ENOMEM;
905         return -1;
906     }
907
908      /* init info and create a canvas */
909     *termInfo = DfltTermInfo;
910     termInfo->max_columns = maxColumns;
911     if (1 < MB_CUR_MAX)
912         _DtHelpLoadMultiInfo(&(termInfo->cant_begin_chars),
913                                 &(termInfo->cant_begin_chars),
914                                 &(termInfo->nl_to_space));
915
916     *ret_canvas  = _DtCanvasCreate (TermVirtInfo, (_DtCvPointer) termInfo);
917
918     if (*ret_canvas == NULL)
919             return -1;
920
921     return 0;
922 }
923
924
925 /******************************************************************************
926  * Function: int _DtHelpTermGetTopicData(canvasHandle,volHandle,
927  *                                           locationId,helpList,hyperList)
928  *
929  * Parameters:
930  *              canvasHandle    Canvas used to retrieve the info; MUST
931  *                              be a Terminal canvas Since it isn't easy
932  *                              to verify this, we don't try.  So if the
933  *                              Canvas ISN'T a Terminal Canvas, we'll
934  *                              crash.
935  *              volHandle       Help volume to use
936  *              locationId      Specifies the locationId of the desired topic.
937  *              helpList        Returns a NULL terminated array of
938  *                              strings.
939  *              hyperList       Returns a NULL terminated array of
940  *                              DtHelpHyperLines containing the hyperlinks
941  *                              found in the topic.
942  *
943  * Returns:     0 for success, -1 for failure.
944  *
945  * errno Values:
946  *              EINVAL          'helpVolume', 'locationId', 'helpList',
947  *                              or 'hyperList' were NULL. 'maxColumns'
948  *                              was less than one.
949  *              open(2)         errno set via an open call on
950  *                              the file for 'locationId'.
951  *              DtErrorMalloc
952  *              DtErrorExceedMaxSize
953  *                              When following symbolic links, the
954  *                              new path will exceed the system
955  *                              maximum file path length.
956  *              DtErrorIllegalPath
957  *                              When following symbolic links, the
958  *                              new path would change to a parent
959  *                              directory beyond the beginning
960  *                              of the base path.
961  *              DtErrorIllegalDatabaseFile
962  *                              Specifies that 'helpVolume' is
963  *                              an illegal database file.
964  *              DtErrorMissingFilenameRes
965  *                              Specifies that the 'Filename/filename'
966  *                              resource for the topic does not exist.
967  *              DtErrorMissingFileposRes
968  *                              Specifies that the 'Filepos/filepos'
969  *                              resource for the topic does not exist.
970  *              DtErrorLocIdNotFound
971  *                              Specifies that 'locationId' was not found.
972  *              DtErrorFormattingLabel
973  *                              A label has illegal syntax.
974  *              DtErrorHyperType
975  *                              Invalid (negative) hypertype.
976  *              DtErrorFormattingLink
977  *                              Invalid <LINK>.
978  *              DtErrorHyperSpec
979  *                              Invalid 'hyper_specification' in the
980  *                              the <LINK>.
981  *              DtErrorFormattingId
982  *                              Invalid <ID> syntax.
983  *              DtErrorFormattingTitle
984  *                              Invalid <TITLE> syntax.
985  *
986  * Purpose:     _DtHelpTermGetTopicData retrieves Help Files content with
987  *              in a form understood by a terminal
988  *
989  *****************************************************************************/
990 int
991 _DtHelpTermGetTopicData(
992     _DtCvHandle      canvasHandle,
993     _DtHelpVolumeHdl      volHandle,
994     char *            locationId,
995     char * * *        helpList,
996     DtHelpHyperLines ** hyperList)
997 {
998     int          result = -1;
999     int          offset;
1000     _DtCvUnit    maxRows;
1001     _DtCvUnit    maxWidth;
1002     char * *     strList;
1003     char*        fileName = NULL;
1004     _DtHelpCeLockInfo lockInfo;
1005     _DtCvTopicPtr        topic = NULL;
1006     TerminalInfo * termInfo;
1007     _FrmtUiInfo     myUiInfo;
1008
1009     termInfo = GetTermInfo(canvasHandle);
1010
1011     _DtHelpProcessLock();
1012     if (WcSpace == 0)
1013         mbtowc (&WcSpace, " ", 1);
1014     _DtHelpProcessUnlock();
1015
1016     /*
1017      * find the filename and the Id string.
1018      */
1019     if (_DtHelpCeLockVolume(volHandle, &lockInfo) != 0)
1020       {
1021         return -1;
1022       }
1023
1024     if (_DtHelpCeFindId(volHandle,locationId,lockInfo.fd,&fileName,&offset)==0)
1025       {
1026         _DtHelpCeUnlockVolume(lockInfo);
1027         return -1;
1028       }
1029
1030     /*
1031      * create the ui structure for the parsing.
1032      */
1033 #ifdef  XTAG
1034     myUiInfo.load_graphic = TermFindGraphic;
1035 #else
1036     myUiInfo.load_graphic = NULL;
1037 #endif /* XTAG */
1038     myUiInfo.resolve_spc  = TermResolveSpc;
1039     myUiInfo.load_font    = TermGetFont;
1040     myUiInfo.destroy_region = NULL;
1041     myUiInfo.exec_filter  = NULL;
1042     myUiInfo.client_data  = (_DtCvPointer) termInfo;
1043     myUiInfo.line_width   = 0;
1044     myUiInfo.line_height  = 1;
1045     myUiInfo.leading      = 0;
1046     myUiInfo.avg_char     = 1;
1047     myUiInfo.nl_to_space  = termInfo->nl_to_space;
1048
1049     /*
1050      * Format the topic.
1051      */
1052     result = _DtHelpCeGetVolumeFlag(volHandle);
1053
1054     _DtHelpProcessLock();
1055     if (result == 1)
1056         result = _DtHelpCeParseSdlTopic(volHandle,
1057                                                 &myUiInfo,
1058                                                 lockInfo.fd,
1059                                                 offset, NULL, True, &topic);
1060     else if (result == 0)
1061         result = _DtHelpCeFrmtCcdfTopic(volHandle, fileName,
1062                                                 offset, NULL, &myUiInfo,
1063                                                 &topic);
1064     _DtHelpProcessUnlock();
1065
1066     /* if successfully formatted topic */
1067     if (result != -1)
1068     {
1069         int     i;
1070         int     len;
1071         wchar_t **wcList;
1072         _DtCanvasStruct *myCStruct = (_DtCanvasStruct *)canvasHandle;
1073
1074         /* build the help text list, if requested */
1075         if (NULL != helpList)
1076         {
1077            _DtCanvasSetTopic(canvasHandle, topic, _DtCvIGNORE_BOUNDARY,
1078                                                 &maxWidth, &maxRows, NULL);
1079    
1080            /*
1081             * The 'maxRows' variable is really misnamed; it's really the
1082             * 'maxY', and is 0-based.  Thus, the 'lines' and 'wc_num'
1083             * arrays need to be 'maxRows+1', in order to hold all the 
1084             * entries.  Likewise, 'strList' must be 'maxRows+2', because
1085             * it also needs to be NULL terminated.
1086             */
1087            termInfo->lines = (wchar_t **)malloc(sizeof(wchar_t *) *(maxRows+1));
1088            termInfo->wc_num = (size_t   *)malloc(sizeof(size_t) * (maxRows+1));
1089            strList          = (char **)   malloc(sizeof(char *) * (maxRows+2));
1090            if (termInfo->lines == NULL || termInfo->wc_num == NULL ||
1091                                                         strList == NULL)
1092            {
1093               free(fileName);
1094               if (termInfo->lines != NULL)
1095                 free(termInfo->lines);
1096               if (termInfo->wc_num != NULL)
1097                 free(termInfo->wc_num);
1098               if (strList != NULL)
1099                 free(strList);
1100               _DtHelpCeUnlockVolume(lockInfo);
1101               return -1;
1102            }
1103    
1104            for (i = 0; i <= maxRows; i++)
1105              {
1106                termInfo->lines[i]  = NULL;
1107                termInfo->wc_num[i] = 0;
1108              }
1109    
1110            _DtCanvasRender(canvasHandle, 0, 0, maxWidth, maxRows,
1111                                 _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
1112    
1113            *helpList = strList;
1114            wcList    = termInfo->lines;
1115            for (i = 0; i <= maxRows; i++, wcList++, strList++)
1116            {
1117               if (*wcList == NULL)
1118               {
1119                  *strList  = (char *) malloc (1);
1120                  **strList = '\0';
1121               }
1122               else
1123               {
1124                 len      = (termInfo->wc_num[i] + 1) * MB_CUR_MAX;
1125                 *strList = (char *) malloc (sizeof (char) * len);
1126                 if (*strList != NULL)
1127                     wcstombs(*strList, *wcList, len);
1128               }
1129            }
1130    
1131           *strList = NULL;
1132
1133            /*
1134             * free the allocated memory
1135             */
1136            for (i = 0, wcList = termInfo->lines; i <= maxRows; i++, wcList++)
1137                if (*wcList != NULL)
1138                    free(*wcList);
1139            free(termInfo->lines);
1140            free(termInfo->wc_num);
1141
1142         }  /* if requested help text */
1143
1144         /*
1145          * build the hyperlinks list, if requested
1146          */
1147         if ( NULL != hyperList )
1148         {
1149            *hyperList = NULL;
1150            for (i = 0; result != -1 && i < myCStruct->link_data->max; i++)
1151                result = AddHyperToList(volHandle, canvasHandle, i, hyperList);
1152         }
1153     }  /* if successfully formatted topic */
1154
1155     _DtCanvasClean(canvasHandle);
1156     _DtHelpDestroyTopicData(topic, NULL, NULL);
1157
1158     free(fileName);
1159     _DtHelpCeUnlockVolume(lockInfo);
1160     return result;
1161
1162 }  /* End _DtHelpTermGetTopicData */
1163
1164 /******************************************************************************
1165  * Function: int _DtHelpGetTopicDataHandles(ret_canvasHandle,ret_volHandle)
1166  *
1167  * Parameters:
1168  *              ret_canvasHandle        Canvas used to retrieve the info
1169  *              ret_volHandle   Help volume in use
1170  *
1171  * Returns:
1172  *  0:  canvas handle & volHandle are not NULL
1173  * -1:  canvas handle & volHandle are NULL
1174  ******************************************************************************/
1175 int
1176 _DtHelpGetTopicDataHandles(
1177     _DtCvHandle *    ret_canvasHandle,
1178     _DtHelpVolumeHdl *    ret_volHandle)
1179 {
1180    _DtHelpProcessLock();
1181    *ret_canvasHandle = MyCanvas;
1182    *ret_volHandle = MyVolume;
1183    if (MyCanvas != NULL && MyVolume != NULL)
1184      {
1185        _DtHelpProcessUnlock();
1186        return 0;
1187      }
1188    else
1189      {
1190        _DtHelpProcessUnlock();
1191        return -1;
1192      }
1193 }
1194
1195
1196 /******************************************************************************
1197  * Function: int _DtHelpGetTopicData (char *helpVolume, char *locationId,
1198  *              int maxColumns, char ***helpList, DtHelpHyperLines **hyperList)
1199  *
1200  * Parameters:
1201  *              helpVolume      Specifies a file path to the volume.
1202  *              locationId      Specifies the locationId of the desired topic.
1203  *              maxColumns      Specifies the column width of the window
1204  *                              for which to format the information.
1205  *              helpList        Returns a NULL terminated array of
1206  *                              strings.
1207  *              hyperList       Returns a NULL terminated array of
1208  *                              DtHelpHyperLines containing the hyperlinks
1209  *                              found in the topic.
1210  *
1211  * Returns:     0 for success, -1 for failure.
1212  *
1213  * errno Values:
1214  *              EINVAL          'helpVolume', 'locationId', 'helpList',
1215  *                              or 'hyperList' were NULL. 'maxColumns'
1216  *                              was less than one.
1217  *              getcwd(2)       errno set via a getcwd call.
1218  *              readlink(2)     errno set via a readlink call.
1219  *              open(2)         errno set via an open call on
1220  *                              the file for 'locationId'.
1221  *              DtErrorMalloc
1222  *              DtErrorExceedMaxSize
1223  *                              When following symbolic links, the
1224  *                              new path will exceed the system
1225  *                              maximum file path length.
1226  *              DtErrorIllegalPath
1227  *                              When following symbolic links, the
1228  *                              new path would change to a parent
1229  *                              directory beyond the beginning
1230  *                              of the base path.
1231  *              DtErrorIllegalDatabaseFile
1232  *                              Specifies that 'helpVolume' is
1233  *                              an illegal database file.
1234  *                      DtErrorMissingFilenameRes
1235  *                              Specifies that the 'Filename/filename'
1236  *                              resource for the topic does not exist.
1237  *              DtErrorMissingFileposRes
1238  *                              Specifies that the 'Filepos/filepos'
1239  *                              resource for the topic does not exist.
1240  *              DtErrorLocIdNotFound
1241  *                              Specifies that 'locationId' was not found.
1242  *              DtErrorFormattingLabel
1243  *                              A label has illegal syntax.
1244  *              DtErrorHyperType
1245  *                              Invalid (negative) hypertype.
1246  *              DtErrorFormattingLink
1247  *                              Invalid <LINK>.
1248  *              DtErrorHyperSpec
1249  *                              Invalid 'hyper_specification' in the
1250  *                              the <LINK>.
1251  *              DtErrorFormattingId
1252  *                              Invalid <ID> syntax.
1253  *              DtErrorFormattingTitle
1254  *                              Invalid <TITLE> syntax.
1255  *
1256  * Purpose:     _DtHelpGetTopicData formats Help Files with
1257  *              formatting information
1258  *              into a form understood by a terminal
1259  *
1260  *****************************************************************************/
1261 int
1262 _DtHelpGetTopicData (
1263         char *               helpVolume,
1264         char *               locationId,
1265         int                  maxColumns,
1266         char * * *           helpList,
1267         DtHelpHyperLines * * hyperList )
1268 {
1269     int           result = -1;
1270     _DtHelpVolumeHdl  volume = NULL;
1271     char *        path = NULL;
1272
1273     /* find the volume (path is malloc'd) */
1274     path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, helpVolume,
1275                                   _DtHelpFileSuffixList,False,R_OK);
1276     if (path == NULL) { errno = EINVAL; return -1; }          /* RETURN */
1277
1278     /* open new canvas or reuse old one with new size */
1279     _DtHelpProcessLock();
1280     if (MyCanvas == NULL)
1281     {
1282        _DtHelpTermCreateCanvas(maxColumns,&MyCanvas);
1283        if (MyCanvas == NULL)
1284        {
1285           free(path);
1286           _DtHelpProcessUnlock();
1287           return -1;            /* RETURN: errno=from CreateCanvas */
1288        }
1289     }
1290     else
1291     {
1292        MyInfo.max_columns = maxColumns;
1293        _DtCanvasResize (MyCanvas, _DtCvFALSE, NULL, NULL);
1294     }
1295
1296     if (_DtHelpOpenVolume (helpVolume, &volume) == -1)
1297     {
1298         free(path);
1299         _DtHelpProcessUnlock();
1300         return -1;              /* RETURN: errno=from OpenVolume */
1301     }
1302
1303     /* release any previously opened volume */
1304     if (MyVolume)
1305         _DtHelpCloseVolume (MyVolume);
1306
1307     /* assign the new volume */
1308     MyVolume = volume;
1309
1310     /* get the terminal info */
1311    result = _DtHelpTermGetTopicData(MyCanvas,MyVolume,locationId,helpList,hyperList);
1312
1313    _DtHelpProcessUnlock();
1314    free(path);
1315    return result;
1316 }
1317
1318 /*****************************************************************************
1319  * Function: int _DtHelpProcessLinkData (char * ref_volume,DtHelpHyperLines *hyperLine,
1320  *                                      char **ret_helpVolume, char **ret_locationId)
1321  *
1322  * Parameters:
1323  *              hyperLine       Specifies the hypertext line that
1324  *                              the caller wishes to be resolved.
1325  *              helpVolume      Returns the help volume specified by
1326  *                              'hyperLine'.
1327  *              locationId      Returns the location Id specified by
1328  *                              'hyperLine'.
1329  *
1330  * Returns:     0 if successful, -1 if errors.
1331  *
1332  * errno Values:
1333  *              EINVAL          'hyperLines', 'helpVolume', or 'locationId'
1334  *                              is NULL.
1335  *              DtErrorMalloc
1336  *              DtErrorHyperType
1337  *                              The hyper type is not _DtJUMP_REUSE,
1338  *                              _DtJUMP_NEW, or _DtDEFINITION.
1339  *              DtErrorHyperSpec
1340  *                              Invalid hyper specification.
1341  *              DtErrorIllegalPath
1342  *                              The volume used by the link spec (either
1343  *                              embedded or the ref_volume) could not be
1344  *                              located.
1345  *
1346  * Purpose:     _DtHelpProcessLinkData resolves a hypertext specification
1347  *              into a pathname to a help volume and a location Id within
1348  *              the help volume.
1349  *
1350  *****************************************************************************/
1351 int
1352 _DtHelpProcessLinkData (
1353     char *              ref_volume,
1354     DtHelpHyperLines  * hyperLine,
1355     char * *            ret_helpVolume,
1356     char * *            ret_locationId )
1357 {
1358     char * linkSpec   = NULL;
1359     char * volumeName = NULL;
1360     char * idToken    = NULL;
1361
1362     /* check params */
1363     if (ref_volume == NULL || hyperLine == NULL ||
1364                         ret_helpVolume == NULL || ret_locationId == NULL)
1365     {
1366         errno = EINVAL;
1367         return -1;
1368     }
1369
1370     /* only process SameVolume or CrossVolume links */
1371     switch (hyperLine->hyper_type)
1372     {
1373         case _DtCvLinkType_SameVolume:
1374         case _DtCvLinkType_CrossLink:
1375                 break;
1376
1377         default:
1378                 errno = DtErrorHyperType;
1379                 return -1;                      /* RETURN */
1380     }
1381
1382     /* Initialize the pointers. */
1383     *ret_helpVolume  = NULL;
1384     *ret_locationId = NULL;
1385
1386     /* get working copy of spec */
1387     linkSpec = strdup (hyperLine->specification);
1388     if (linkSpec == NULL)
1389     {
1390         errno = DtErrorMalloc;
1391         return -1;
1392     }
1393
1394     /* parse the link spec.  Syntax is: "[volume] locationId" */
1395     if (linkSpec == NULL || *linkSpec == EOS)
1396     {
1397         errno = DtErrorHyperSpec;      /* no spec */
1398     }
1399     else  /* at least one token exists */
1400     {
1401         volumeName = linkSpec;  /* posit that first token is the volume */
1402
1403         /* look for another possible token */
1404         idToken = NULL;
1405         _DtHelpCeStrchr (linkSpec," ",MB_CUR_MAX,&idToken);
1406
1407         /* second token? */
1408         if (idToken) /* second token */
1409         {
1410             /* separate the tokens and advance idToken to first valid char */
1411             *idToken = EOS; idToken++;
1412
1413             /* find the fully qualified volume (volName is malloc'd) */
1414             volumeName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, volumeName,
1415                               _DtHelpFileSuffixList,False,R_OK);
1416             if (volumeName == NULL)
1417                 errno = DtErrorIllegalPath;
1418         }
1419         else /* no second token */
1420         {
1421             idToken = volumeName;
1422             /* find the fully qualified volume (volName is malloc'd) */
1423             volumeName = _DtHelpFileLocate(DtHelpVOLUME_TYPE, ref_volume,
1424                               _DtHelpFileSuffixList,False,R_OK);
1425             if (volumeName == NULL)
1426                 errno = DtErrorIllegalPath;
1427         }
1428
1429         if (idToken && volumeName)
1430         {
1431             *ret_helpVolume = volumeName;  /* already allocd by _DtHelpFileLocate */
1432             *ret_locationId = strdup (idToken);
1433             if (*ret_locationId == NULL)
1434                 errno = DtErrorMalloc;
1435         }
1436     } /* if at least one token exists */
1437
1438     free (linkSpec);
1439          
1440     return ( (*ret_helpVolume && *ret_locationId) ? 0 : -1 );
1441
1442 }  /* End _DtHelpProcessLinkData */
1443
1444 /*****************************************************************************
1445  * Function: void _DtHelpFreeTopicData (char **helpList,
1446  *                                      DtHelpHyperLines *hyperList)
1447  *
1448  * Parameters:
1449  *              helpList        Specifies a pointer to a NULL terminated
1450  *                              array of strings.
1451  *              hyperList       Specifies a pointer to a NULL terminated
1452  *                              list of DtHelpHyperLines.
1453  *
1454  * Returns:     Nothing
1455  *
1456  * Purpose:     _DtHelpFreeTopicData frees the data associated with a topic.
1457  *
1458  *****************************************************************************/
1459 void
1460 _DtHelpFreeTopicData (
1461         char             **helpList,
1462         DtHelpHyperLines     *hyperList)
1463 {
1464     if (helpList != NULL)
1465         _DtHelpCeFreeStringArray (helpList);
1466
1467     if (hyperList != NULL)
1468         DeallocateHyperArray (hyperList);
1469
1470 }  /* End _DtHelpFreeTopicData */
1471
1472 /******************************************************************************
1473  * Function: int _DtHelpGetTopicChildren (char *helpVolume, char *topic_id,
1474  *              char ***ret_children)
1475  *
1476  * Parameters:
1477  *              helpVolume      Specifies a file path to the volume.
1478  *              topic_id        Specifies the id of the desired topic.
1479  *              ret_children    Returns a NULL terminated array of
1480  *                              strings. The memory for these strings
1481  *                              *IS OWNED* by the caller and must be freed
1482  *                              after use.
1483  *
1484  * Returns:     > 0 for success, -1 for failure.
1485  *
1486  * errno Values:
1487  *
1488  * Purpose:     _DtHelpGetTopicChildren returns the topic ids of the children
1489  *              for a given topic id.
1490  *
1491  *****************************************************************************/
1492 int
1493 _DtHelpGetTopicChildren (
1494         char             *helpVolume,
1495         char             *topic_id,
1496         char            ***ret_children)
1497 {
1498     int           result = -1;
1499     _DtHelpVolumeHdl  volume = NULL;
1500     char *        path;
1501
1502     /* Initialize the pointer */
1503     *ret_children  = NULL;
1504
1505     /* find the volume (path is malloc'd) */
1506     path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, helpVolume,
1507                                   _DtHelpFileSuffixList,False,R_OK);
1508     if (path == NULL) { errno = EINVAL; return -1; }          /* RETURN */
1509
1510     /* open new canvas or reuse old one with new size */
1511     _DtHelpProcessLock();
1512     if (MyCanvas == NULL)
1513     {
1514        _DtHelpTermCreateCanvas(72,&MyCanvas);  /* 72: arbitary value for max columns */
1515        if (MyCanvas == NULL)
1516        {
1517           free(path);
1518           _DtHelpProcessUnlock();
1519           return -1;            /* RETURN: errno=??? */
1520        }
1521     }
1522
1523     if (_DtHelpOpenVolume (helpVolume, &volume) == -1)
1524     {
1525         free(path);
1526         _DtHelpProcessUnlock();
1527         return -1;              /* RETURN: errno=??? */
1528     }
1529
1530     /* release any previously opened volume */
1531     if (MyVolume)
1532         _DtHelpCloseVolume (MyVolume);
1533
1534     /* assign the new volume */
1535     MyVolume = volume;
1536
1537     /* Get the children */
1538    result = _DtHelpCeGetTopicChildren(MyVolume, topic_id, ret_children);
1539
1540    _DtHelpProcessUnlock();
1541    free(path);
1542    return result;
1543 }
1544
1545