dtcm: make it build
[oweals/cde.git] / cde / lib / DtHelp / AccessCCDF.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 /* $XConsortium: AccessCCDF.c /main/10 1996/11/01 10:09:50 drk $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        AccessCCDF.c
28  **
29  **   Project:     Cde 1.0 Help Library
30  **
31  **   Description: This body of code handles the access routines to the
32  **                legacy CCDF Help files.
33  **
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 /*
47  * system includes
48  */
49 #include <errno.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <X11/Xlib.h>
55 #include <X11/Xresource.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
68 /*
69  * private includes
70  */
71 #include "CanvasError.h"
72 #include "AccessP.h"
73 #include "bufioI.h"
74 #include "AccessCCDFP.h"
75 #include "AccessCCDFI.h"
76 #include "FormatUtilI.h"
77 #include "StringFuncsI.h"
78 #include "HelpXlate.h"
79
80 #ifdef NLS16
81 #endif
82
83 /********    Private Defines      ********/
84 #define LIST_INCREMENT  10
85 #define BUFF_SIZE       256
86 /********    End Private Defines  ********/
87
88 /********    Private Function Declarations    ********/
89 static  char     *CreateFileName(
90                         char    *path,
91                         char    *string );
92 static  int       GetResourceInt (
93                         XrmDatabase  db, 
94                         char    *topic, 
95                         char    *resClass, 
96                         char    *resName,
97                         int     *ret_value);
98 static  char     *GetResourceString (
99                         XrmDatabase      db, 
100                         char            *topic, 
101                         char            *resClass, 
102                         char            *resName);
103 static  char    **GetResourceStringArray (
104                         XrmDatabase      db, 
105                         char            *topic, 
106                         char            *resClass, 
107                         char            *resName);
108 static  int       GetTopicMap (
109                         _DtHelpVolume    vol,
110                         char            *target_id,
111                         int              level,
112                         char            ***ret_ids );
113 /********    End Private Function Declarations    ********/
114
115 /********    Private Macro Declarations        ********/
116 #define GetCcdfVolumePtr(vol) \
117                 ((CcdfVolumePtr)((vol)->vols.ccdf_vol))
118
119 #define GetFilenameResource(vol, topic) \
120         GetResourceString((vol)->volDb, topic, "Filename", "filename")
121
122 /********    End Private Macro Declarations    ********/
123
124 /******************************************************************************
125 *
126 * Private variables used within this file.
127 *
128 *******************************************************************************/
129 static const char *Period    = ".";
130 static const char *Slash     = "/";
131 static const char *VolumeStr = "Volume.";
132 static const char *volumeStr = "Volume.";
133
134 static const struct _CcdfVolumeInfo DefaultCcdfVol =
135   {
136     NULL,               /* XrmDatabase volDb; */
137     NULL,               /* char **topicList;  */
138     NULL,               /* char *keywordFile; */
139   };
140
141 /******************************************************************************
142  *                             Private Functions
143  ******************************************************************************/
144 /******************************************************************************
145  * Function:    CreateFileName (char *path, char *string)
146  *
147  * Parameters:  path    Specifies the path to the volume.
148  *              string  Specifies the file's name including the extension.
149  *
150  * Memory owned by caller:
151  *              ptr returned
152  *
153  * Returns:             Non null ptr if successful, null if a failure occurs.
154  *
155  * errno Values:        CEErrorMalloc
156  *
157  * Purpose:     Creates a fully qualified path to a file based on the
158  *              path given.
159  *
160  ******************************************************************************/
161 static  char *
162 CreateFileName (
163         char     *path,
164         char     *string )
165 {
166     int    len = 0;
167     char  *ptr;
168
169     if ((MB_CUR_MAX == 1 || mblen (string, MB_CUR_MAX) == 1) && *string != '/'
170                                 && path)
171       {
172         /*
173          * determine the length of the path.
174          */
175         _DtHelpCeStrrchr (path, Slash, MB_CUR_MAX, &ptr);
176         if (ptr)
177             len = ptr - path + 1;
178       }
179
180     /*
181      * malloc the room for the path and file name.
182      */
183     ptr = (char *) malloc (len + strlen(string) + 1);
184
185     if (ptr)
186       {
187         /*
188          * copy the name into the destination string.
189          */
190         ptr[0] = '\0';
191         if (len && path)
192             strncat (ptr, path, len);
193         strcat (ptr, string);
194       }
195
196     return ptr;
197 }
198
199 /*****************************************************************************
200  * Function: GetTopicMap (_DtHelpVolume vol, char *target_id,
201  *                                              int level, char ***ret_ids)
202  *
203  * Parameters:  vol             Specifies the loaded volume
204  *              target_id       The target location ID of a topic.
205  *              level           The levels progressed so far. It is
206  *                              used to calculate how much memory
207  *                              is required to hold all the ids.
208  *              ret_ids         Returns a null terminated list of the
209  *                              location IDs of the topics between the
210  *                              target and the parent.
211  * Memory own by caller:
212  *              ret_ids
213  *
214  * Returns:             The number of ids put in the list so far,
215  *                      -1 for failure.
216  *
217  * errno Values:        CEErrorMalloc
218  *
219  *
220  * Purpose:     Recursively build a list of id strings containing all of
221  *              the target_id's ancestors.
222  *
223  *****************************************************************************/
224 static int
225 GetTopicMap (
226         _DtHelpVolume    vol,
227         char            *target_id,
228         int              level,
229         char            ***ret_ids )
230 {
231     int    result = -1;
232
233     char   *idParent;
234
235     if (_DtHelpCeGetCcdfTopicParent (vol, target_id, &idParent) == 0)
236       {
237         /*
238          * still not at the top
239          */
240         if (idParent)
241           {
242             result = GetTopicMap (vol, idParent, level + 1, ret_ids);
243             if (result != -1)
244               {
245                 (*ret_ids)[result] = strdup (idParent);
246                 result++;
247               }
248           }
249         else
250           {
251             *ret_ids = (char **) malloc (sizeof(char *) * (level + 2));
252             if ((*ret_ids) == NULL)
253                 return -1;
254
255             (*ret_ids)[level + 1] = NULL;
256             result = 0;
257           }
258       }
259
260    return result;
261
262 }  /* End GetTopicMap */
263
264 /******************************************************************************
265  * Function:    char *GetResourceString (XrmDatabase db, char *topic,
266  *                                         char *resClass, char *resName)
267  *
268  * Parameters:  db              Specifies the handle to a resource database.
269  *              topic           Specifies the topic whose resource value is
270  *                              desired.  If 'topic' is NULL, the
271  *                              desired resource is for the volume and
272  *                              not a specific topic.
273  *              resClass        Specifies the resource class name.
274  *              resName         Specifies the resource name.
275  *
276  * Return Value:        Returns the desired resource as string.
277  *                      This string is NOT owned by the caller and
278  *                      should only be read or copied.
279  *
280  *                      Returns NULL if an error occurs.
281  *
282  * errno Values:        CEErrorMalloc
283  *                      CEErrorIllegalResource  If the resource is not in
284  *                                              the database or if the
285  *                                              resource NULL
286  *
287  * Purpose:     Get a resource value for a volume or topic.
288  *
289  ******************************************************************************/
290 static char * 
291 GetResourceString (
292     XrmDatabase  db, 
293     char        *topic, 
294     char        *resClass, 
295     char        *resName)
296 {
297     int          len;
298     int          topicLen = 0;
299     char        *retVal   = NULL;
300     char        *fullResName;
301     char        *fullResClass;
302     char        *resType;
303     XrmValue     resValue;
304
305
306     if (topic != NULL)
307         topicLen = strlen(topic) + strlen(Period);
308
309     len          = strlen(volumeStr) + topicLen + 1;
310     fullResName  = (char *) malloc (len + strlen (resName));
311     fullResClass = (char *) malloc (len + strlen (resClass));
312     if (fullResName != NULL && fullResClass != NULL)
313       {
314         strcpy (fullResName, volumeStr);
315         strcpy (fullResClass, VolumeStr);
316
317         if (topic != NULL)
318           {
319             strcat (fullResName, topic);
320             strcat (fullResName, Period);
321
322             strcat (fullResClass, topic);
323             strcat (fullResClass, Period);
324           }
325
326         strcat (fullResName , resName);
327         strcat (fullResClass, resClass);
328       }
329     else
330         errno = CEErrorMalloc;
331
332
333     if (fullResClass != NULL && fullResName != NULL)
334       {
335         if (XrmGetResource (db, fullResClass, fullResName, &resType, &resValue)
336                                 && strlen ((char *) resValue.addr))
337             retVal = (char *) resValue.addr;
338         else
339             errno = CEErrorIllegalResource;
340       }
341
342     if (fullResName)
343         free (fullResName);
344     if (fullResClass)
345         free (fullResClass);
346
347     return (retVal);
348 }
349
350 /******************************************************************************
351  * Function:    char **GetResourceStringArray (XrmDatabase db, char *topic,
352  *                                          char *resClass, char *resName)
353  *
354  * Parameters:  db              Specifies the handle to a resource database.
355  *              topic           Specifies the topic whose resource value is
356  *                              desired.  If 'topic' is NULL, the
357  *                              desired resource is for the volume and
358  *                              not a specific topic.
359  *              resClass        Specifies the resource class name.
360  *              resName         Specifies the resource name.
361  *
362  * Return Value:        Returns a NULL-terminated string array containing the
363  *                      value of the desired resource.  The elements of the
364  *                      array are the strings of non-whitespace characters in
365  *                      the resource value.  This array is owned by the caller
366  *                      and should be freed (using _DtHelpCeFreeStringArray) when
367  *                      not needed.
368  *
369  * Purpose:     Get am array-valued resource for a volume or topic.
370  *
371  ******************************************************************************/
372 static char **
373 GetResourceStringArray (
374     XrmDatabase  db, 
375     char        *topic, 
376     char        *resClass, 
377     char        *resName)
378 {
379     char         *val;
380     char        **valArray = NULL;
381     char         *token;
382     char         *nextC;
383
384     /* Get the resource value which is a single string where the elements are 
385        separated by white space. */
386     val = GetResourceString (db, topic, resClass, resName);
387     if (val != NULL)
388       {
389         nextC = val;
390         while (nextC && *nextC != '\0')
391           {
392             nextC = _DtHelpGetNxtToken (nextC, &token);
393
394             if (token == NULL)
395               {
396                 _DtHelpCeFreeStringArray (valArray);
397                 return NULL;
398               }
399
400             /* If the token is a '\0' then we are at the end and we can quit. 
401                If the token is a '\n', then ignore it.  Otherwise the token
402                is an element of the array we are building. */
403             if (*token == '\0')
404                 break;
405
406             if (*token != '\n')
407               {
408                 valArray = (char **) _DtHelpCeAddPtrToArray (
409                                         (void **) valArray, (void *) token);
410                 /*
411                  * If we malloc'ed ourselves out of existence...stop processing.
412                  */
413                 if (!valArray)
414                     break;
415               }
416           }
417       }
418
419     return (valArray);
420 }
421
422 /******************************************************************************
423  * Function:    char *GetNextKeyword (char *str, char *delimiter,
424                                                         char **ret_token)
425  *
426  * Parameters:  str             Specifies the string which is being parsed.
427  *              delimiter       Specifies the delimiter string.
428  *              ret_token       Returns the string found between the current
429  *                              position of the input string and the delimiter
430  *                              string.
431  *
432  *                              Newline or Null strings are
433  *                              not owned by the caller.
434  *
435  *                              Otherwise, the memory for the returned
436  *                              token is owned by the caller.
437  *
438  * Return Value:        Returns a pointer to the next unparsed character
439  *                      in the input string. A NULL value indicates an error.
440  *
441  * Purpose:     Load the keywords associated with a volume.
442  *
443  ******************************************************************************/
444 static char * 
445 GetNextKeyword (
446         char     *str,
447         char     *delimiter,
448         char    **ret_token )
449 {
450     int          len;
451     char        *start;
452     char        *token;
453     short        done;
454
455     /* Find the next token in the string.  The parsing rules are:
456
457          - The deliminater (except for \n) separate a keyword from
458            its list of location IDs.
459          - \n is a token itself.
460          - The \0 at the end of the string is a token.
461      */
462
463     /* Skip all of the whitespace and \n. */
464     (void) _DtHelpCeStrspn (str, " \n", MB_CUR_MAX, &len);
465     str += len;
466
467     /* Str is pointing at the start of the next keyword.  Depending on the
468        type of token, malloc the memory and copy the token value. */
469     if (*str == '\0')
470         token = str;
471
472     else
473       {
474         /* We have some non-whitespace characters.  Find the end of */
475         /* them and copy them into new memory. */
476         start = str;
477         done  = False;
478         do
479           {
480             _DtHelpCeStrchr (str, delimiter, MB_CUR_MAX, &str);
481             if (str)
482               {
483                 if (strncmp (str, delimiter, strlen(delimiter)) == 0)
484                     done = True;
485                 else
486                     str++;
487               }
488             else /* if (str == NULL) */
489               {
490                 str = start + strlen (start);
491                 done = -1;
492               }
493           } while (!done);
494
495         token = (char *) malloc ((str - start + 1) * sizeof (char));
496         if (token)
497           {
498             strncpy (token, start, str - start);
499             *(token + (str - start)) = '\0';
500             if (done == True)
501                 str += strlen (delimiter);
502           }
503       }
504
505     *ret_token = token;
506     return (str);
507 }
508
509 /******************************************************************************
510  * Function:    int TopicFilename (_DtHelpVolume vol, char *topic,
511  *                                                      char **retFname);
512  *
513  * Parameters:  vol             Specifies the loaded volume
514  *              topic           Specifies locationID for the topic
515  *              retFname        Returns the name of the file where the topic
516  *                              is located.
517  * Memory own by caller:
518  *              retFname
519  *
520  * Returns:     0 if successful, -1 if a failure occurs
521  *
522  * Purpose:     Get the name of the file where a topic is stored.
523  *
524  ******************************************************************************/
525 static int 
526 TopicFilename (
527     _DtHelpVolume    vol, 
528     char         *topic, 
529     char        **retFname)
530 {
531     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
532
533     *retFname = GetFilenameResource (ccdfVol, topic);
534     if (*retFname == NULL && errno == CEErrorIllegalResource)
535         errno = CEErrorMissingFilenameRes;
536     else
537         *retFname = CreateFileName (vol->volFile, *retFname);
538
539     if (*retFname == NULL)
540         return (-1);
541
542     return (0);
543 }
544
545 /******************************************************************************
546  * Function:    int TopicFilepos (_DtHelpVolume vol, char *topic, int *retFpos);
547  *
548  * Parameters:  vol             Specifies the loaded volume
549  *              topic           The locationID for the topic
550  *              retFpos         Returns the byte offset of the start of the
551  *                              topic within the topic file.
552  *
553  * Return Value:        0 if successful, -1 if a failure occurs.
554  *
555  * Purpose:     Determine the position of the topic within the topic file.
556  ******************************************************************************/
557 static int 
558 TopicFilepos (
559     _DtHelpVolume   vol, 
560     char        *topic, 
561     int         *retFpos)
562 {
563     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
564
565     if (GetResourceInt(ccdfVol->volDb, topic, "Filepos", "filepos", retFpos) == -1)
566         return -1;
567
568     return (0);
569 }
570
571 /******************************************************************************
572  * Function:    int GetResourceInt (XrmDatabase db, char *topic,
573  *                              char *resClass, char *resName, ret_value)
574  *
575  * Parameters:  db              Specifies the handle to a resource database.
576  *              topic           Specifies the topic whose resource value is
577  *                              desired.  If 'topic' is NULL, the
578  *                              desired resource is for the volume and
579  *                              not a specific topic.
580  *              resClass        Specifies the resource class name.
581  *              resName         Specifies the resource name.
582  *              ret_value       Returns an int containing the resource value.
583  *
584  * Return Value: 0 if successful, -1 if a failure occurs.
585  *
586  * Purpose:     Get an integer-valued resource for a volume or topic.
587  ******************************************************************************/
588 static int 
589 GetResourceInt (
590     XrmDatabase  db, 
591     char        *topic, 
592     char        *resClass, 
593     char        *resName,
594     int         *ret_value)
595 {
596     char  *retValue;
597
598     retValue = GetResourceString (db, topic, resClass, resName);
599     if (retValue)
600       {
601         *ret_value = atoi(retValue);
602         return 0;
603       }
604
605     return -1;
606 }
607
608 /******************************************************************************
609  * Function:    static int LocationIDTopic (_DtHelpVolume vol, char *locId,
610  *                                       char **retTopic);
611  *
612  * Parameters:  vol             Specifies the loaded volume
613  *              locId           Specifies locationID desired.
614  *              retTopic        Returns the locationID of the topic with
615  *                              contains 'locId'.  This string IS owned by
616  *                              the caller and must be freed when no longer
617  *                              needed.
618  *
619  * Return Value:        0 if successful, -1 if a failure occurs
620  *
621  * Purpose:             Find which topic contains a specified locationID.
622  ******************************************************************************/
623 static int 
624 LocationIDTopic (
625      _DtHelpVolume   vol, 
626      char        *locId, 
627      char       **retTopic)
628 {
629     char        **allTopics;
630     char        **nextTopic;
631     char        **locIdList = NULL;
632     char        **nextLocId;
633
634     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
635
636     *retTopic = NULL;
637
638     if (_DtHelpCeGetCcdfVolIdList (vol, &allTopics) != 0)
639         return (-1);
640
641     /* Check whether the locationID is a topic. */
642     for (nextTopic = allTopics;
643         nextTopic && *nextTopic != NULL && *retTopic == NULL; nextTopic++)
644       {
645         if (_DtHelpCeStrCaseCmpLatin1 (locId, *nextTopic) == 0)
646             *retTopic = strdup(*nextTopic);
647       }
648
649     /* For each topic in the volume, get its list of locationIDs and
650        check them. NOTE: This code should be separated out into a public 
651        _DtTopicLocationIDs function.  Then we would have a function 
652        that returns all of the locationIDs in a topic, which might
653        prove useful someday. */
654
655     if (*retTopic == NULL)
656       {
657         for (nextTopic = allTopics;
658                 nextTopic && *nextTopic != NULL && *retTopic == NULL;
659                                                                 nextTopic++)
660           {
661             /*
662              * valid to get a NULL on this resource, but not good
663              */
664             errno = 0;
665             locIdList = GetResourceStringArray  (ccdfVol->volDb, *nextTopic,
666                                                 "LocationIDs", "locationIDs");
667             if (locIdList == NULL && errno != CEErrorIllegalResource)
668                 break;
669
670             errno = CEErrorLocIdNotFound;
671             for (nextLocId = locIdList;
672                 nextLocId != NULL && *nextLocId != NULL && *retTopic == NULL;
673                                                                 nextLocId++)
674               {
675                 if (_DtHelpCeStrCaseCmpLatin1 (locId, *nextLocId) == 0)
676                     *retTopic = strdup(*nextTopic);
677               }
678
679             if (NULL != locIdList)
680                 _DtHelpCeFreeStringArray (locIdList);
681           }
682       }
683
684     if (*retTopic == NULL)
685         return (-1);
686
687     return (0);
688 }
689
690 /******************************************************************************
691  *                       Semi-Public CCDF Access Functions
692  ******************************************************************************/
693 /*****************************************************************************
694  * Function: int _DtHelpCeGetCcdfIdPath (_DtHelpVolume vol, char *target_id,
695  *                                              char ***ret_ids)
696  *
697  * Parameters:  vol             Specifies the loaded volume
698  *              target_id       The target location ID of a topic.
699  *              ret_ids         Returns a null terminated list of the
700  *                              location IDs of the topics between the
701  *                              target and the parent.
702  * Memory own by caller:
703  *              ret_ids
704  *
705  * Returns:     The number of ids in the list, -1 for failure. If successful,
706  *              the list will always contain at least the target_id.
707  *
708  * Purpose:     Get the list of ids between the top and the target id.
709  *
710  *****************************************************************************/
711 int
712 _DtHelpCeGetCcdfIdPath (
713     _DtHelpVolume    vol,
714     char              *target_id,
715     char            ***ret_ids )
716 {
717     int       idCount = 0;
718     char     *topicId = NULL;
719
720     if (LocationIDTopic (vol, target_id, &topicId) != 0)
721         return -1;
722
723     idCount = GetTopicMap (vol, topicId, 0, ret_ids);
724     if (idCount != -1)
725       {
726         /*
727          * include this entry in the count
728          */
729         (*ret_ids)[idCount] = topicId;
730         idCount++;
731       }
732     else
733       {
734         free(topicId);
735       }
736
737     return idCount;
738
739 }  /* End _DtHelpCeGetCcdfIdPath */
740
741 /******************************************************************************
742  * Function:    int  _DtHelpCeGetCcdfTopicChildren (_DtHelpVolume vol,
743  *                                                      char *topic_id,
744  *                                                      char ***topics);
745  *
746  * Parameters:  vol             Specifies the loaded volume.
747  *              topic_id        Specifies the topic for which children
748  *                              are desired.
749  *              retTopics       Returns a NULL-terminated string array
750  *                              containing the list of children for a topic
751  *                              in the volume. This array is owned by the
752  *                              caller and should be freed (using
753  *                              _DtHelpCeFreeStringArray) when not needed.
754  *
755  * Memory own by caller:
756  *      retTopics
757  *
758  * Return Value:                > 0 if successful, -1 if a failure occurs
759  *
760  * Purpose:     Get the list of children for a topic contained in a volume.
761  *
762  ******************************************************************************/
763 int 
764 _DtHelpCeGetCcdfTopicChildren (
765     _DtHelpVolume   vol,
766     char          *topic_id,
767     char        ***retTopics)
768 {
769     int     result;
770     int     count = 0;
771     char   *parent_id;
772     char   *child_id;
773     char   *topicId = NULL;
774     char  **topicList;
775
776     if (LocationIDTopic (vol, topic_id, &topicId) != 0)
777         return -1;
778
779     /*
780      * initialize the return value
781      */
782     *retTopics = NULL;
783
784     /*
785      * get the list
786      */
787     result = _DtHelpCeGetCcdfVolIdList (vol, &topicList);
788     if (result == 0)
789       {
790         while (*topicList && result == 0)
791           {
792             result = _DtHelpCeGetCcdfTopicParent (vol, *topicList, &parent_id);
793             if (result == 0)
794               {
795                 /*
796                  * It's legal to get a NULL back - means the topic
797                  * doesn't have a parent.
798                  */
799                 if (parent_id &&
800                         _DtHelpCeStrCaseCmpLatin1 (parent_id, topicId) == 0)
801                   {
802                     child_id = strdup (*topicList);
803                     if (child_id)
804                       {
805                         *retTopics = (char **) _DtHelpCeAddPtrToArray (
806                                         (void **) (*retTopics), child_id);
807                         if (*retTopics == NULL)
808                             result = -1;
809                         count++;
810                       }
811                     else
812                       {
813                         /*
814                          * lost the previous data...stop processing.
815                          */
816                         if (*retTopics)
817                             _DtHelpCeFreeStringArray (*retTopics);
818                         *retTopics = NULL;
819                         result = -1;
820                         break;
821                       }
822                   }
823               }
824             else
825               {
826                 /*
827                  * problems processing TopicParent...stop processing
828                  */
829                 if (*retTopics)
830                     _DtHelpCeFreeStringArray (*retTopics);
831                 *retTopics = NULL;
832                 break;
833               }
834             topicList++;
835           }
836       }
837
838     /*
839      * free the duplicate string
840      */
841     if (topicId)
842         free (topicId);
843
844     if (result != 0)
845         return -1;
846
847     return count;
848 }
849
850 /******************************************************************************
851  * Function:    int _DtHelpCeGetCcdfVolIdList (_DtHelpVolume vol, char ***topics);
852  *
853  * Parameters:  vol     Specifies the loaded volume.
854  *              topics  Returns a NULL-terminated string array
855  *                      containing the ordered list of topics in the
856  *                      volume.  This array is NOT owned by the caller
857  *                      and should only be read or copied.
858  *
859  * Return Value:        0 if successful, -1 if a failure occurs
860  *
861  * Purpose:     Get the list of topics contained in a volume.
862  *
863  ******************************************************************************/
864 int 
865 _DtHelpCeGetCcdfVolIdList (
866     _DtHelpVolume       vol,
867      char       ***retTopics)
868 {
869     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
870
871     if (ccdfVol->topicList == NULL)
872         ccdfVol->topicList = GetResourceStringArray (ccdfVol->volDb, NULL, 
873                                                 "TopicList", "topicList");
874     *retTopics = ccdfVol->topicList;
875     if (*retTopics == NULL)
876       {
877         if (errno == CEErrorIllegalResource)
878             errno = CEErrorMissingTopicList;
879         return -1;
880       }
881
882     return 0;
883 }
884
885 /*****************************************************************************
886  * Function: int _DtHelpCeFindCcdfId (_DtHelpVolume vol, char *target_id,
887  *                                      char *ret_name, int *ret_offset)
888  *
889  * Parameters:  vol             Specifies the loaded volume
890  *              target_id       Specifies target location ID
891  *              ret_name        Returns a null terminated string
892  *                              containing a fully qualified path to
893  *                              the file that contains 'target_id'.
894  *              ret_offset      Returns the offset into 'ret_name'
895  *                              to the topic that contains 'target_id'.
896  *
897  * Memory own by caller:
898  *              ret_name
899  *
900  * Returns:     True if successful, False if a failure occurs
901  *
902  * Purpose:     Find which topic contains a specified locationID.
903  *****************************************************************************/
904 int
905 _DtHelpCeFindCcdfId (
906     _DtHelpVolume       vol,
907     char                *target_id,
908     char                **ret_name,
909     int         *ret_offset )
910 {
911     char        newTarget[65];
912     char       *topicId = NULL;
913     int   found = False;
914
915     snprintf(newTarget, sizeof(newTarget), "%s", target_id);
916     _DtHelpCeUpperCase(newTarget);
917
918     /*
919      * find the location id for the topic that contains the
920      * target_id (they may be the same). Then find the filename
921      * and offset.
922      */
923     if (TopicFilename (vol, newTarget, ret_name) == -1)
924       {
925         /*
926          * if the reason TopicFilename failed was because we couldn't
927          * find a resource, try looking for it in the LocationIDs.
928          */
929         if (errno == CEErrorMissingFilenameRes &&
930                 LocationIDTopic (vol, newTarget, &topicId) == 0 &&
931                         TopicFilename (vol, topicId, ret_name) == 0 &&
932                                 TopicFilepos (vol, topicId, ret_offset) == 0)
933             found = True;
934       }
935     else if (TopicFilepos (vol, newTarget, ret_offset) != -1)
936         found = True;
937
938     /*
939      * free the excess strings
940      */
941     if (topicId)
942         free (topicId);
943
944     return found;
945
946 }  /* End _DtHelpCeFindCcdfId */
947
948 /******************************************************************************
949  * Function:   int _DtHelpCeGetCcdfTopicParent (_DtHelpVolume vol, char *topic,
950  *                                      char **retParent)
951  *
952  * Parameters:  vol             Specifies the loaded volume
953  *              topic           Specifies locationID for the topic
954  *              retParent       Returns a string with the locationID for the
955  *                              topic which is the parent of the current
956  *                              topic.  If the current topic is at the top of
957  *                              the hierarchy, a NULL string is returned.
958  *                              This string is NOT owned by the caller and
959  *                              should only be read or copied.
960  *
961  * Return Value:        0 if successful, -1 if a failure occurs
962  *
963  * Purpose:     Find the parent for a topic.
964  ******************************************************************************/
965 int 
966 _DtHelpCeGetCcdfTopicParent (
967      _DtHelpVolume   vol, 
968      char        *topic, 
969      char       **retParent)
970 {
971     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
972
973     /* Don't return an error if we are asked for the parent of NULL, or if 
974        the topic has no parent.  Both cases are valid (and used by
975        _DtTopicPath). */
976
977     *retParent = NULL;
978     if (topic != NULL)
979       {
980         errno = 0;
981         *retParent = GetResourceString(ccdfVol->volDb, topic,
982                                                         "Parent", "parent");
983         if (*retParent == NULL && errno != CEErrorIllegalResource)
984             return -1;
985       }
986
987     return (0);
988 }
989
990 /*****************************************************************************
991  * Function: int _DtHelpCeGetCcdfKeywordList (_DtHelpVolume vol,
992  *
993  * Parameters:  vol     Specifies the volume whose keywords need to be
994  *                      loaded from disk.  Once loaded, they can be 
995  *                      accessed through the fields of the volume structure.
996  *
997  * Return Value:        0 if successful, -1 if a failure occurs
998  *
999  * Purpose:     Load the keywords associated with a volume.
1000  *****************************************************************************/
1001 int
1002 _DtHelpCeGetCcdfKeywordList (
1003     _DtHelpVolume       vol)
1004 {
1005     XrmDatabase   kDb;
1006     char         *keywordString;
1007     char         *nextC;
1008     char        **topics;
1009     char        ***topicList;
1010     char         *token;
1011     char         *currKeyword;
1012     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1013
1014     /* Generate the name of the keyword file.  Because volume files
1015        use the ".hv" suffix and keyword files use ".hvk", all we have 
1016        to do is append a "k". */
1017     /*
1018      * If the keywordFile is non-null, we've already tried once.
1019      * We want to try again, because the problem may have been
1020      * fixed without restarting this process.
1021      *
1022      * But don't malloc memory again, because we'll leak memory.
1023      * Just use what is given.
1024      */
1025     if (ccdfVol->keywordFile == NULL)
1026       {
1027         ccdfVol->keywordFile = (char *) malloc (strlen (vol->volFile) + 2);
1028         if (ccdfVol->keywordFile == NULL)
1029             return -1;
1030
1031         strcpy (ccdfVol->keywordFile, vol->volFile);
1032         strcat (ccdfVol->keywordFile, "k");
1033       }
1034
1035     /*
1036      * check to see if it exists
1037      */
1038     if (access (ccdfVol->keywordFile, R_OK) == -1)
1039         return -1;
1040
1041     /* Load the keyword file and get the "keywords" resource. */
1042     kDb = XrmGetFileDatabase (ccdfVol->keywordFile);
1043     if (kDb == NULL)
1044         return -1;
1045
1046     keywordString = GetResourceString (kDb, NULL, "Keywords", "keywords");
1047     if (keywordString == NULL)
1048       {
1049         if (errno == CEErrorIllegalResource)
1050             errno = CEErrorMissingKeywordsRes;
1051         XrmDestroyDatabase (kDb);
1052         return (-1);
1053       }
1054
1055     /* Now parse the string into the appropriate arrays.  The string has the 
1056        following syntax:
1057
1058                 keyword1<\>topic topic topic ... \n
1059                 keyword2<\>topic topic topic ... \n
1060        
1061      */
1062     nextC = (char *) keywordString;
1063
1064     while (nextC && *nextC)
1065       {
1066
1067         /* Get the next keyword.  If we find newlines while looking for
1068            the keyword, throw them away.  If the next token is the end-
1069            of-file (\0), quit.
1070          */
1071         nextC = GetNextKeyword (nextC, "<\\>", &token);
1072
1073         if (token == NULL)
1074           {
1075             XrmDestroyDatabase (kDb);
1076             if (vol->keywords)
1077               {
1078                 _DtHelpCeFreeStringArray (vol->keywords);
1079                 vol->keywords = NULL;
1080               }
1081             if (vol->keywordTopics)
1082               {
1083                 for (topicList = vol->keywordTopics;
1084                                                 topicList; topicList++)
1085                     _DtHelpCeFreeStringArray (*topicList);
1086                 free (vol->keywordTopics);
1087                 vol->keywordTopics = NULL;
1088               }
1089             return -1;
1090           }
1091
1092         if (*token == '\0')
1093             break;
1094
1095         /* We have the next keyword.  Hang onto it and add it to the list
1096            once we get the array of topics.  We don't add it yet because if
1097            there are no topics we want to throw it away.  (Silently ignoring
1098            keywords which specify no topics is an undocumented feature.) */
1099
1100         currKeyword = token;
1101
1102         /* Now get the list of topics. */
1103         topics = NULL;
1104         do
1105           {
1106             nextC = _DtHelpGetNxtToken (nextC, &token);
1107
1108             if (token == NULL)
1109               {
1110                 XrmDestroyDatabase (kDb);
1111                 if (vol->keywords)
1112                   {
1113                     _DtHelpCeFreeStringArray (vol->keywords);
1114                     vol->keywords = NULL;
1115                   }
1116                 if (vol->keywordTopics)
1117                   {
1118                     for (topicList = vol->keywordTopics;
1119                                                 topicList; topicList++)
1120                         _DtHelpCeFreeStringArray (*topicList);
1121                     free (vol->keywordTopics);
1122                     vol->keywordTopics = NULL;
1123                   }
1124                 if (topics)
1125                         _DtHelpCeFreeStringArray (topics);
1126                 free (currKeyword);
1127
1128                 return -1;
1129               }
1130
1131             /* If the next token is end-of-file (\0), then quit.  Otherwise
1132                if the next token is a newline, then we have gotten all of
1133                the topics and we need to add them to the array of topic 
1134                arrays.  The final choice is that the token is a string so
1135                we add it to the current array of topics. */
1136             if (*token == '\0')
1137                 break;
1138
1139             if (*token == '\n')
1140               {
1141                 /* We have all of the topics.  If the array of topics isn't
1142                    empty, add everything to the data structures.
1143                  */
1144                 if (topics != NULL)
1145                   {
1146                     vol->keywords = (char **) _DtHelpCeAddPtrToArray (
1147                                       (void **) vol->keywords,
1148                                       (void *) currKeyword);
1149                     vol->keywordTopics = (char ***) _DtHelpCeAddPtrToArray (
1150                                         (void **) vol->keywordTopics,
1151                                         (void *) topics);
1152                     /*
1153                      * If we just malloc'ed ourselves out of existence...
1154                      * stop here.
1155                      */
1156                     if (vol->keywords == 0 || vol->keywordTopics == 0)
1157                       {
1158                         XrmDestroyDatabase (kDb);
1159                         if (vol->keywords)
1160                           {
1161                             free (currKeyword);
1162                             _DtHelpCeFreeStringArray (vol->keywords);
1163                             _DtHelpCeFreeStringArray (topics);
1164                             vol->keywords = NULL;
1165                           }
1166                         if (vol->keywordTopics)
1167                           {
1168                             for (topicList = vol->keywordTopics;
1169                                                         topicList; topicList++)
1170                                 _DtHelpCeFreeStringArray (*topicList);
1171                             free (vol->keywordTopics);
1172                             vol->keywordTopics = NULL;
1173                           }
1174                         return -1;
1175                       }
1176                   }
1177                 break;
1178               }
1179             else
1180               {
1181                 topics = (char **) _DtHelpCeAddPtrToArray ((void **) topics, 
1182                                                 (void *) token);
1183                 /*
1184                  * If we just malloc'ed ourselves out of existence
1185                  * stop here.
1186                  */
1187                 if (topics == NULL)
1188                   {
1189                     free (currKeyword);
1190                     XrmDestroyDatabase (kDb);
1191                     if (vol->keywords)
1192                       {
1193                         _DtHelpCeFreeStringArray (vol->keywords);
1194                         vol->keywords = NULL;
1195                       }
1196                     if (vol->keywordTopics != NULL)
1197                       {
1198                         for (topicList = vol->keywordTopics;
1199                                                         topicList; topicList++)
1200                             _DtHelpCeFreeStringArray (*topicList);
1201                         free (vol->keywordTopics);
1202                         vol->keywordTopics = NULL;
1203                       }
1204
1205                     return -1;
1206                   }
1207               }
1208
1209           } while (nextC && *nextC);
1210
1211         if (topics == NULL)
1212             free (currKeyword);
1213       }
1214
1215     XrmDestroyDatabase (kDb);
1216
1217     return (0);
1218
1219 }  /* End _DtHelpCeGetCcdfKeywordList */
1220
1221 /******************************************************************************
1222  * Function:    int _DtHelpCeGetCcdfVolumeAbstract (_DtHelpVolume vol,
1223  *                              char **abstract);
1224  *
1225  * Parameters:  vol     Specifies the loaded volume.
1226  *              abstract Returns the abstract of the volume.  This string
1227  *                       is owned by the caller and should be freed.
1228  *
1229  * Return Value: 0 if successful, -1 if a failure occurs
1230  *
1231  * Purpose:     Get the abstract of a volume.
1232  ******************************************************************************/
1233 int 
1234 _DtHelpCeGetCcdfVolumeAbstract (
1235     _DtHelpVolume         vol,
1236     char                **retAbs)
1237 {
1238     char          *abstract;
1239     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1240
1241     *retAbs = NULL;
1242     abstract = GetResourceString(ccdfVol->volDb, NULL, "Abstract", "abstract");
1243     if (abstract == NULL)
1244       {
1245         if (errno == CEErrorIllegalResource)
1246             errno = CEErrorMissingAbstractRes;
1247       }
1248     else
1249         *retAbs = strdup(abstract);
1250
1251     if (*retAbs == NULL)
1252         return (-1);
1253
1254     return (0);
1255 }
1256
1257 /*****************************************************************************
1258  * Function: int _DtHelpCeMapCcdfTargetToId (_DtHelpVolume vol,
1259  *                                      char *target_id,
1260  *                                      char *ret_id)
1261  *
1262  * Parameters:  vol             Specifies the loaded volume
1263  *              target_id       Specifies target location ID
1264  *              ret_id          Returns the id containing the target_id.
1265  *                              This memory *IS NOT* owned by the caller.
1266  *                              And *MAY* point to target_id.
1267  *
1268  * Returns:     0 if successful, -1 if a failure occurs
1269  *
1270  * Purpose:     Find which topic contains a specified locationID.
1271  *
1272  *****************************************************************************/
1273 int
1274 _DtHelpCeMapCcdfTargetToId (
1275     _DtHelpVolume       vol,
1276     const char          *target_id,
1277     char                **ret_id)
1278 {
1279     char        newTarget[128];
1280     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1281
1282     snprintf(newTarget, sizeof(newTarget), "%s", target_id);
1283     _DtHelpCeUpperCase(newTarget);
1284
1285     /*
1286      * find the location id for the topic that contains the
1287      * target_id (they may be the same). Then find the filename
1288      * and offset.
1289      */
1290     *ret_id = (char *) target_id;
1291     if (GetFilenameResource (ccdfVol, newTarget) == NULL)
1292       {
1293         /*
1294          * if the reason TopicFilename failed was because we couldn't
1295          * find a resource, try looking for it in the LocationIDs.
1296          */
1297         if (errno == CEErrorIllegalResource &&
1298                 LocationIDTopic (vol, newTarget, ret_id) == 0 &&
1299                                 GetFilenameResource(ccdfVol, *ret_id) != NULL)
1300             return 0;
1301
1302         return -1;
1303       }
1304
1305     return 0;
1306
1307 }  /* End _DtHelpCeMapCcdfTargetToId */
1308
1309 /*****************************************************************************
1310  * Function: char * _DtHelpCeGetCcdfVolLocale (_DtHelpVolume vol)
1311  *
1312  * Parameters:  vol             Specifies the loaded volume
1313  *
1314  * Returns:     The pointer to the locale string if successful. Otherwise
1315  *              NULL.
1316  *
1317  * Purpose:     Get the locale of the specified volume.
1318  *              Returns the locale in a unix specific format
1319  *              - locale[_ter][.charset] - This memory is owned by
1320  *              the caller.
1321  *
1322  *****************************************************************************/
1323 char *
1324 _DtHelpCeGetCcdfVolLocale (
1325         _DtHelpVolume   vol)
1326 {
1327     char          *locale = NULL;
1328     char          *charSet;
1329     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1330
1331     errno  = 0;
1332     locale = GetResourceString(ccdfVol->volDb, NULL, "CharSet", "charSet");
1333     if (_DtHelpCeStrchr(locale, ".", 1, &charSet) != 0)
1334       {
1335         charSet = locale;
1336         _DtHelpCeXlateOpToStdLocale(DtLCX_OPER_CCDF,charSet,&locale,NULL,NULL); 
1337         /* charset is owned by the volume Xrm database; don't free */
1338       }
1339     else if (NULL != locale)
1340         locale = strdup(locale);
1341
1342     return locale;
1343
1344 }  /* End _DtHelpCeGetCcdfVolLocale */
1345
1346 /*****************************************************************************
1347  * Function: int _DtHelpCeGetCcdfDocStamp (_DtHelpVolume vol, char **ret_doc,
1348  *                                              char **ret_time)
1349  *
1350  * Parameters:  volume          Specifies the loaded volume
1351  *              ret_doc         Returns the doc id.
1352  *              ret_time        Returns the time stamp.
1353  *
1354  * Memory:      Caller owns the string in ret_doc and ret_time.
1355  *
1356  * Returns:     0 if successful, -2 if the volume does not contain
1357  *              one or the other, -1 if any other failure.
1358  *
1359  * Purpose:     Get doc id and time stamp of a volume.
1360  *
1361  *****************************************************************************/
1362 int
1363 _DtHelpCeGetCcdfDocStamp (
1364     _DtHelpVolume       vol,
1365     char                **ret_doc,
1366     char                **ret_time)
1367 {
1368     int  result;
1369     struct stat buf;
1370
1371     result = -2;
1372     if (ret_doc != NULL)
1373         *ret_doc = NULL;
1374
1375     if (ret_time != NULL)
1376       {
1377         result = -1;
1378         *ret_time = NULL;
1379         if (stat(vol->volFile, &buf) == 0)
1380           {
1381             *ret_time = (char *) malloc (sizeof(time_t) * 3 + 1);
1382             if (*ret_time != NULL)
1383               {
1384                 sprintf(*ret_time, "%u", (unsigned) buf.st_mtime);
1385                 return -2;
1386               }
1387           }
1388       }
1389     return result;
1390
1391 }  /* End _DtHelpCeGetCcdfDocStamp */
1392
1393 /******************************************************************************
1394  * Function:    static int _DtHelpCeGetCcdfTopTopic (_DtHelpVolume vol,
1395  *                                      char **topic);
1396  *
1397  * Parameters:  vol     Specifies the loaded volume.
1398  *              topic   Returns the locationID for the top topic in
1399  *                      the volume hierarchy.  This string is NOT
1400  *                      owned by the caller and should only be read or
1401  *                      copied.
1402  *
1403  * Return Value:        0 if successful, -1 if a failure occurs
1404  *
1405  * Purpose:     Get the top topic of a volume.
1406  ******************************************************************************/
1407 int 
1408 _DtHelpCeGetCcdfTopTopic (
1409     _DtHelpVolume   vol,
1410     char        **retTopic)
1411 {
1412     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1413
1414     *retTopic = GetResourceString(ccdfVol->volDb, NULL, "TopTopic", "topTopic");
1415     if (*retTopic == NULL)
1416       {
1417         if (errno == CEErrorIllegalResource)
1418             errno = CEErrorMissingTopTopicRes;
1419         return (-1);
1420       }
1421
1422     return (0);
1423 }
1424
1425 /******************************************************************************
1426  * Function:    char  *_DtHelpCeGetCcdfVolTitle (_DtHelpVolume vol);
1427  *
1428  * Parameters:  vol             Specifies the loaded volume.
1429  *
1430  * Return Value:        The title if successful, NULL otherwise.
1431  *                      The caller *DOES NOT* own the memory returned
1432  *                      and *MUST NOT* modify the memory.
1433  *
1434  * Purpose:     Get the title of a volume.
1435  *
1436  ******************************************************************************/
1437 char * 
1438 _DtHelpCeGetCcdfVolTitle (
1439     _DtHelpVolume         vol)
1440 {
1441     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1442
1443     return (GetResourceString (ccdfVol->volDb, NULL, "Title", "title"));
1444 }
1445
1446 /******************************************************************************
1447  * Function:    int  _DtHelpCeGetCcdfVolumeTitle (_DtHelpVolume vol);
1448  *
1449  * Parameters:  vol             Specifies the loaded volume.
1450  *
1451  * Return Value:        The title if successful, NULL otherwise.
1452  *                      The caller *DOES NOT* own the memory returned
1453  *                      and *MUST NOT* modify the memory.
1454  *
1455  * Purpose:     Get the title of a volume.
1456  *
1457  ******************************************************************************/
1458 int 
1459 _DtHelpCeGetCcdfVolumeTitle (
1460     _DtHelpVolume         vol,
1461     char                **ret_title)
1462 {
1463     *ret_title = _DtHelpCeGetCcdfVolTitle(vol);
1464
1465     if (*ret_title == NULL)
1466       {
1467         if (errno == CEErrorIllegalResource)
1468             errno = CEErrorMissingTitleRes;
1469         return (-1);
1470       }
1471
1472     *ret_title = strdup(*ret_title);
1473     if (*ret_title == NULL)
1474       {
1475         errno = CEErrorMalloc;
1476         return (-1);
1477       }
1478     return (0);
1479 }
1480
1481 /******************************************************************************
1482  * Function:    int  _DtHelpCeOpenCcdfVolume (_DtHelpVolume vol);
1483  *
1484  * Parameters:  vol             Specifies the loaded volume.
1485  *
1486  * Return Value:
1487  *
1488  * Purpose:     Open a CCDF help volume
1489  *
1490  ******************************************************************************/
1491 int 
1492 _DtHelpCeOpenCcdfVolume (
1493     _DtHelpVolume         vol)
1494 {
1495     struct stat buf;
1496     CcdfVolumePtr ccdfVol;
1497
1498     ccdfVol = (struct _CcdfVolumeInfo *) malloc(sizeof(struct _CcdfVolumeInfo));
1499     if (ccdfVol != NULL)
1500       {
1501         *ccdfVol = DefaultCcdfVol;
1502         ccdfVol->volDb = XrmGetFileDatabase(vol->volFile);
1503         if (ccdfVol->volDb != NULL)
1504           {
1505             (void) stat(vol->volFile, &buf);
1506             vol->check_time = buf.st_mtime;
1507             vol->vols.ccdf_vol = (CcdfVolumeHandle) ccdfVol;
1508             return 0;
1509           }
1510         free(ccdfVol);
1511       }
1512
1513     return -1;
1514 }
1515
1516 /******************************************************************************
1517  * Function:    void  _DtHelpCeCloseCcdfVolume (_DtHelpVolume vol);
1518  *
1519  * Parameters:  vol             Specifies the loaded volume.
1520  *
1521  * Return Value:
1522  *
1523  * Purpose:     Open a CCDF help volume
1524  *
1525  ******************************************************************************/
1526 void 
1527 _DtHelpCeCloseCcdfVolume (
1528     _DtHelpVolume         vol)
1529 {
1530     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1531
1532     if (ccdfVol->volDb != NULL)
1533         XrmDestroyDatabase (ccdfVol->volDb);
1534
1535     if (ccdfVol->topicList != NULL)
1536         _DtHelpCeFreeStringArray (ccdfVol->topicList);
1537
1538     if (ccdfVol->keywordFile != NULL)
1539         free (ccdfVol->keywordFile);
1540
1541     free(ccdfVol);
1542 }
1543
1544 /******************************************************************************
1545  * Function:    int  _DtHelpCeRereadCcdfVolume (_DtHelpVolume vol);
1546  *
1547  * Parameters:  vol             Specifies the loaded volume.
1548  *
1549  * Return Value:
1550  *
1551  * Purpose:     Reread a CCDF volume.
1552  *
1553  ******************************************************************************/
1554 int 
1555 _DtHelpCeRereadCcdfVolume (
1556     _DtHelpVolume         vol)
1557 {
1558     CcdfVolumePtr  ccdfVol = GetCcdfVolumePtr(vol);
1559
1560     if (ccdfVol->volDb != NULL)
1561         XrmDestroyDatabase (ccdfVol->volDb);
1562
1563     if (ccdfVol->topicList != NULL)
1564         _DtHelpCeFreeStringArray (ccdfVol->topicList);
1565
1566     if (ccdfVol->keywordFile != NULL)
1567         free (ccdfVol->keywordFile);
1568
1569     ccdfVol->topicList   = NULL;
1570     ccdfVol->keywordFile = NULL;
1571     ccdfVol->volDb       = XrmGetFileDatabase(vol->volFile);
1572
1573     if (ccdfVol->volDb != NULL)
1574         return 0;
1575
1576     return -1;
1577 }
1578
1579 /******************************************************************************
1580  * Function:    char *_DtHelpCeGetResourceString (XrmDatabase db, char *topic,
1581  *                                         char *resClass, char *resName)
1582  *
1583  * Parameters:  db              Specifies the handle to a resource database.
1584  *              topic           Specifies the topic whose resource value is
1585  *                              desired.  If 'topic' is NULL, the
1586  *                              desired resource is for the volume and
1587  *                              not a specific topic.
1588  *              resClass        Specifies the resource class name.
1589  *              resName         Specifies the resource name.
1590  *
1591  * Return Value:        Returns the desired resource as string.
1592  *                      This string is NOT owned by the caller and
1593  *                      should only be read or copied.
1594  *
1595  *                      Returns NULL if an error occurs.
1596  *
1597  * errno Values:        CEErrorMalloc
1598  *                      CEErrorIllegalResource  If the resource is not in
1599  *                                              the database or if the
1600  *                                              resource NULL
1601  *
1602  * Purpose:     Get a resource value for a volume or topic.
1603  *
1604  ******************************************************************************/
1605 char * 
1606 _DtHelpCeGetResourceString (
1607     XrmDatabase  db, 
1608     char        *topic, 
1609     char        *resClass, 
1610     char        *resName)
1611 {
1612     return (GetResourceString(db, topic, resClass, resName));
1613 }
1614
1615 /******************************************************************************
1616  * Function:    char **_DtHelpCeGetResourceStringArray (XrmDatabase db,
1617  *                              char *topic, char *resClass, char *resName)
1618  *
1619  * Parameters:  db              Specifies the handle to a resource database.
1620  *              topic           Specifies the topic whose resource value
1621  *                              is desired.  If 'topic' is NULL, the
1622  *                              desired resource is for the volume and
1623  *                              not a specific topic.
1624  *              resClass        Specifies the resource class name.
1625  *              resName         Specifies the resource name.
1626  *
1627  * Return Value:        Returns a NULL-terminated string array
1628  *                      containing the value of the desired resource.
1629  *                      The elements of the array are the strings of
1630  *                      non-whitespace characters in the resource value.
1631  *                      This array is owned by the caller and should be
1632  *                      freed (using _DtHelpCeFreeStringArray) when not
1633  *                      needed.
1634  *
1635  * Purpose:     Get am array-valued resource for a volume or topic.
1636  *
1637  ******************************************************************************/
1638 char **
1639 _DtHelpCeGetResourceStringArray (
1640     XrmDatabase  db, 
1641     char        *topic, 
1642     char        *resClass, 
1643     char        *resName)
1644 {
1645     return (GetResourceStringArray(db, topic, resClass, resName));
1646 }