2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: AccessCCDF.c /main/10 1996/11/01 10:09:50 drk $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Cde 1.0 Help Library
31 ** Description: This body of code handles the access routines to the
32 ** legacy CCDF Help files.
35 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
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.
43 ****************************************************************************
44 ************************************<+>*************************************/
55 #include <X11/Xresource.h>
63 * Canvas Engine includes
66 #include "CanvasSegP.h"
71 #include "CanvasError.h"
74 #include "AccessCCDFP.h"
75 #include "AccessCCDFI.h"
76 #include "FormatUtilI.h"
77 #include "StringFuncsI.h"
78 #include "HelpXlate.h"
83 /******** Private Defines ********/
84 #define LIST_INCREMENT 10
86 /******** End Private Defines ********/
88 /******** Private Function Declarations ********/
89 static char *CreateFileName(
92 static int GetResourceInt (
98 static char *GetResourceString (
103 static char **GetResourceStringArray (
108 static int GetTopicMap (
113 /******** End Private Function Declarations ********/
115 /******** Private Macro Declarations ********/
116 #define GetCcdfVolumePtr(vol) \
117 ((CcdfVolumePtr)((vol)->vols.ccdf_vol))
119 #define GetFilenameResource(vol, topic) \
120 GetResourceString((vol)->volDb, topic, "Filename", "filename")
122 /******** End Private Macro Declarations ********/
124 /******************************************************************************
126 * Private variables used within this file.
128 *******************************************************************************/
129 static const char *Period = ".";
130 static const char *Slash = "/";
131 static const char *VolumeStr = "Volume.";
132 static const char *volumeStr = "Volume.";
134 static const struct _CcdfVolumeInfo DefaultCcdfVol =
136 NULL, /* XrmDatabase volDb; */
137 NULL, /* char **topicList; */
138 NULL, /* char *keywordFile; */
141 /******************************************************************************
143 ******************************************************************************/
144 /******************************************************************************
145 * Function: CreateFileName (char *path, char *string)
147 * Parameters: path Specifies the path to the volume.
148 * string Specifies the file's name including the extension.
150 * Memory owned by caller:
153 * Returns: Non null ptr if successful, null if a failure occurs.
155 * errno Values: CEErrorMalloc
157 * Purpose: Creates a fully qualified path to a file based on the
160 ******************************************************************************/
169 if ((MB_CUR_MAX == 1 || mblen (string, MB_CUR_MAX) == 1) && *string != '/'
173 * determine the length of the path.
175 _DtHelpCeStrrchr (path, Slash, MB_CUR_MAX, &ptr);
177 len = ptr - path + 1;
181 * malloc the room for the path and file name.
183 ptr = (char *) malloc (len + strlen(string) + 1);
188 * copy the name into the destination string.
192 strncat (ptr, path, len);
193 strcat (ptr, string);
199 /*****************************************************************************
200 * Function: GetTopicMap (_DtHelpVolume vol, char *target_id,
201 * int level, char ***ret_ids)
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:
214 * Returns: The number of ids put in the list so far,
217 * errno Values: CEErrorMalloc
220 * Purpose: Recursively build a list of id strings containing all of
221 * the target_id's ancestors.
223 *****************************************************************************/
235 if (_DtHelpCeGetCcdfTopicParent (vol, target_id, &idParent) == 0)
238 * still not at the top
242 result = GetTopicMap (vol, idParent, level + 1, ret_ids);
245 (*ret_ids)[result] = strdup (idParent);
251 *ret_ids = (char **) malloc (sizeof(char *) * (level + 2));
252 if ((*ret_ids) == NULL)
255 (*ret_ids)[level + 1] = NULL;
262 } /* End GetTopicMap */
264 /******************************************************************************
265 * Function: char *GetResourceString (XrmDatabase db, char *topic,
266 * char *resClass, char *resName)
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.
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.
280 * Returns NULL if an error occurs.
282 * errno Values: CEErrorMalloc
283 * CEErrorIllegalResource If the resource is not in
284 * the database or if the
287 * Purpose: Get a resource value for a volume or topic.
289 ******************************************************************************/
307 topicLen = strlen(topic) + strlen(Period);
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)
314 strcpy (fullResName, volumeStr);
315 strcpy (fullResClass, VolumeStr);
319 strcat (fullResName, topic);
320 strcat (fullResName, Period);
322 strcat (fullResClass, topic);
323 strcat (fullResClass, Period);
326 strcat (fullResName , resName);
327 strcat (fullResClass, resClass);
330 errno = CEErrorMalloc;
333 if (fullResClass != NULL && fullResName != NULL)
335 if (XrmGetResource (db, fullResClass, fullResName, &resType, &resValue)
336 && strlen ((char *) resValue.addr))
337 retVal = (char *) resValue.addr;
339 errno = CEErrorIllegalResource;
350 /******************************************************************************
351 * Function: char **GetResourceStringArray (XrmDatabase db, char *topic,
352 * char *resClass, char *resName)
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.
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
369 * Purpose: Get am array-valued resource for a volume or topic.
371 ******************************************************************************/
373 GetResourceStringArray (
380 char **valArray = NULL;
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);
390 while (nextC && *nextC != '\0')
392 nextC = _DtHelpGetNxtToken (nextC, &token);
396 _DtHelpCeFreeStringArray (valArray);
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. */
408 valArray = (char **) _DtHelpCeAddPtrToArray (
409 (void **) valArray, (void *) token);
411 * If we malloc'ed ourselves out of existence...stop processing.
422 /******************************************************************************
423 * Function: char *GetNextKeyword (char *str, char *delimiter,
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
432 * Newline or Null strings are
433 * not owned by the caller.
435 * Otherwise, the memory for the returned
436 * token is owned by the caller.
438 * Return Value: Returns a pointer to the next unparsed character
439 * in the input string. A NULL value indicates an error.
441 * Purpose: Load the keywords associated with a volume.
443 ******************************************************************************/
455 /* Find the next token in the string. The parsing rules are:
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.
463 /* Skip all of the whitespace and \n. */
464 (void) _DtHelpCeStrspn (str, " \n", MB_CUR_MAX, &len);
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. */
474 /* We have some non-whitespace characters. Find the end of */
475 /* them and copy them into new memory. */
480 _DtHelpCeStrchr (str, delimiter, MB_CUR_MAX, &str);
483 if (strncmp (str, delimiter, strlen(delimiter)) == 0)
488 else /* if (str == NULL) */
490 str = start + strlen (start);
495 token = (char *) malloc ((str - start + 1) * sizeof (char));
498 strncpy (token, start, str - start);
499 *(token + (str - start)) = '\0';
501 str += strlen (delimiter);
509 /******************************************************************************
510 * Function: int TopicFilename (_DtHelpVolume vol, char *topic,
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
517 * Memory own by caller:
520 * Returns: 0 if successful, -1 if a failure occurs
522 * Purpose: Get the name of the file where a topic is stored.
524 ******************************************************************************/
531 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
533 *retFname = GetFilenameResource (ccdfVol, topic);
534 if (*retFname == NULL && errno == CEErrorIllegalResource)
535 errno = CEErrorMissingFilenameRes;
537 *retFname = CreateFileName (vol->volFile, *retFname);
539 if (*retFname == NULL)
545 /******************************************************************************
546 * Function: int TopicFilepos (_DtHelpVolume vol, char *topic, int *retFpos);
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.
553 * Return Value: 0 if successful, -1 if a failure occurs.
555 * Purpose: Determine the position of the topic within the topic file.
556 ******************************************************************************/
563 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
565 if (GetResourceInt(ccdfVol->volDb, topic, "Filepos", "filepos", retFpos) == -1)
571 /******************************************************************************
572 * Function: int GetResourceInt (XrmDatabase db, char *topic,
573 * char *resClass, char *resName, ret_value)
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.
584 * Return Value: 0 if successful, -1 if a failure occurs.
586 * Purpose: Get an integer-valued resource for a volume or topic.
587 ******************************************************************************/
598 retValue = GetResourceString (db, topic, resClass, resName);
601 *ret_value = atoi(retValue);
608 /******************************************************************************
609 * Function: static int LocationIDTopic (_DtHelpVolume vol, char *locId,
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
619 * Return Value: 0 if successful, -1 if a failure occurs
621 * Purpose: Find which topic contains a specified locationID.
622 ******************************************************************************/
631 char **locIdList = NULL;
634 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
638 if (_DtHelpCeGetCcdfVolIdList (vol, &allTopics) != 0)
641 /* Check whether the locationID is a topic. */
642 for (nextTopic = allTopics;
643 nextTopic && *nextTopic != NULL && *retTopic == NULL; nextTopic++)
645 if (_DtHelpCeStrCaseCmpLatin1 (locId, *nextTopic) == 0)
646 *retTopic = strdup(*nextTopic);
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. */
655 if (*retTopic == NULL)
657 for (nextTopic = allTopics;
658 nextTopic && *nextTopic != NULL && *retTopic == NULL;
662 * valid to get a NULL on this resource, but not good
665 locIdList = GetResourceStringArray (ccdfVol->volDb, *nextTopic,
666 "LocationIDs", "locationIDs");
667 if (locIdList == NULL && errno != CEErrorIllegalResource)
670 errno = CEErrorLocIdNotFound;
671 for (nextLocId = locIdList;
672 nextLocId != NULL && *nextLocId != NULL && *retTopic == NULL;
675 if (_DtHelpCeStrCaseCmpLatin1 (locId, *nextLocId) == 0)
676 *retTopic = strdup(*nextTopic);
679 if (NULL != locIdList)
680 _DtHelpCeFreeStringArray (locIdList);
684 if (*retTopic == NULL)
690 /******************************************************************************
691 * Semi-Public CCDF Access Functions
692 ******************************************************************************/
693 /*****************************************************************************
694 * Function: int _DtHelpCeGetCcdfIdPath (_DtHelpVolume vol, char *target_id,
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:
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.
708 * Purpose: Get the list of ids between the top and the target id.
710 *****************************************************************************/
712 _DtHelpCeGetCcdfIdPath (
718 char *topicId = NULL;
720 if (LocationIDTopic (vol, target_id, &topicId) != 0)
723 idCount = GetTopicMap (vol, topicId, 0, ret_ids);
727 * include this entry in the count
729 (*ret_ids)[idCount] = topicId;
735 } /* End _DtHelpCeGetCcdfIdPath */
737 /******************************************************************************
738 * Function: int _DtHelpCeGetCcdfTopicChildren (_DtHelpVolume vol,
742 * Parameters: vol Specifies the loaded volume.
743 * topic_id Specifies the topic for which children
745 * retTopics Returns a NULL-terminated string array
746 * containing the list of children for a topic
747 * in the volume. This array is owned by the
748 * caller and should be freed (using
749 * _DtHelpCeFreeStringArray) when not needed.
751 * Memory own by caller:
754 * Return Value: > 0 if successful, -1 if a failure occurs
756 * Purpose: Get the list of children for a topic contained in a volume.
758 ******************************************************************************/
760 _DtHelpCeGetCcdfTopicChildren (
769 char *topicId = NULL;
772 if (LocationIDTopic (vol, topic_id, &topicId) != 0)
776 * initialize the return value
783 result = _DtHelpCeGetCcdfVolIdList (vol, &topicList);
786 while (*topicList && result == 0)
788 result = _DtHelpCeGetCcdfTopicParent (vol, *topicList, &parent_id);
792 * It's legal to get a NULL back - means the topic
793 * doesn't have a parent.
796 _DtHelpCeStrCaseCmpLatin1 (parent_id, topicId) == 0)
798 child_id = strdup (*topicList);
801 *retTopics = (char **) _DtHelpCeAddPtrToArray (
802 (void **) (*retTopics), child_id);
803 if (*retTopics == NULL)
810 * lost the previous data...stop processing.
813 _DtHelpCeFreeStringArray (*retTopics);
823 * problems processing TopicParent...stop processing
826 _DtHelpCeFreeStringArray (*retTopics);
835 * free the duplicate string
846 /******************************************************************************
847 * Function: int _DtHelpCeGetCcdfVolIdList (_DtHelpVolume vol, char ***topics);
849 * Parameters: vol Specifies the loaded volume.
850 * topics Returns a NULL-terminated string array
851 * containing the ordered list of topics in the
852 * volume. This array is NOT owned by the caller
853 * and should only be read or copied.
855 * Return Value: 0 if successful, -1 if a failure occurs
857 * Purpose: Get the list of topics contained in a volume.
859 ******************************************************************************/
861 _DtHelpCeGetCcdfVolIdList (
865 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
867 if (ccdfVol->topicList == NULL)
868 ccdfVol->topicList = GetResourceStringArray (ccdfVol->volDb, NULL,
869 "TopicList", "topicList");
870 *retTopics = ccdfVol->topicList;
871 if (*retTopics == NULL)
873 if (errno == CEErrorIllegalResource)
874 errno = CEErrorMissingTopicList;
881 /*****************************************************************************
882 * Function: int _DtHelpCeFindCcdfId (_DtHelpVolume vol, char *target_id,
883 * char *ret_name, int *ret_offset)
885 * Parameters: vol Specifies the loaded volume
886 * target_id Specifies target location ID
887 * ret_name Returns a null terminated string
888 * containing a fully qualified path to
889 * the file that contains 'target_id'.
890 * ret_offset Returns the offset into 'ret_name'
891 * to the topic that contains 'target_id'.
893 * Memory own by caller:
896 * Returns: True if successful, False if a failure occurs
898 * Purpose: Find which topic contains a specified locationID.
899 *****************************************************************************/
901 _DtHelpCeFindCcdfId (
908 char *topicId = NULL;
911 strcpy (newTarget, target_id);
912 _DtHelpCeUpperCase(newTarget);
915 * find the location id for the topic that contains the
916 * target_id (they may be the same). Then find the filename
919 if (TopicFilename (vol, newTarget, ret_name) == -1)
922 * if the reason TopicFilename failed was because we couldn't
923 * find a resource, try looking for it in the LocationIDs.
925 if (errno == CEErrorMissingFilenameRes &&
926 LocationIDTopic (vol, newTarget, &topicId) == 0 &&
927 TopicFilename (vol, topicId, ret_name) == 0 &&
928 TopicFilepos (vol, topicId, ret_offset) == 0)
931 else if (TopicFilepos (vol, newTarget, ret_offset) != -1)
935 * free the excess strings
942 } /* End _DtHelpCeFindCcdfId */
944 /******************************************************************************
945 * Function: int _DtHelpCeGetCcdfTopicParent (_DtHelpVolume vol, char *topic,
948 * Parameters: vol Specifies the loaded volume
949 * topic Specifies locationID for the topic
950 * retParent Returns a string with the locationID for the
951 * topic which is the parent of the current
952 * topic. If the current topic is at the top of
953 * the hierarchy, a NULL string is returned.
954 * This string is NOT owned by the caller and
955 * should only be read or copied.
957 * Return Value: 0 if successful, -1 if a failure occurs
959 * Purpose: Find the parent for a topic.
960 ******************************************************************************/
962 _DtHelpCeGetCcdfTopicParent (
967 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
969 /* Don't return an error if we are asked for the parent of NULL, or if
970 the topic has no parent. Both cases are valid (and used by
977 *retParent = GetResourceString(ccdfVol->volDb, topic,
979 if (*retParent == NULL && errno != CEErrorIllegalResource)
986 /*****************************************************************************
987 * Function: int _DtHelpCeGetCcdfKeywordList (_DtHelpVolume vol,
989 * Parameters: vol Specifies the volume whose keywords need to be
990 * loaded from disk. Once loaded, they can be
991 * accessed through the fields of the volume structure.
993 * Return Value: 0 if successful, -1 if a failure occurs
995 * Purpose: Load the keywords associated with a volume.
996 *****************************************************************************/
998 _DtHelpCeGetCcdfKeywordList (
1002 char *keywordString;
1008 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1010 /* Generate the name of the keyword file. Because volume files
1011 use the ".hv" suffix and keyword files use ".hvk", all we have
1012 to do is append a "k". */
1014 * If the keywordFile is non-null, we've already tried once.
1015 * We want to try again, because the problem may have been
1016 * fixed without restarting this process.
1018 * But don't malloc memory again, because we'll leak memory.
1019 * Just use what is given.
1021 if (ccdfVol->keywordFile == NULL)
1023 ccdfVol->keywordFile = (char *) malloc (strlen (vol->volFile) + 2);
1024 if (ccdfVol->keywordFile == NULL)
1027 strcpy (ccdfVol->keywordFile, vol->volFile);
1028 strcat (ccdfVol->keywordFile, "k");
1032 * check to see if it exists
1034 if (access (ccdfVol->keywordFile, R_OK) == -1)
1037 /* Load the keyword file and get the "keywords" resource. */
1038 kDb = XrmGetFileDatabase (ccdfVol->keywordFile);
1042 keywordString = GetResourceString (kDb, NULL, "Keywords", "keywords");
1043 if (keywordString == NULL)
1045 if (errno == CEErrorIllegalResource)
1046 errno = CEErrorMissingKeywordsRes;
1047 XrmDestroyDatabase (kDb);
1051 /* Now parse the string into the appropriate arrays. The string has the
1054 keyword1<\>topic topic topic ... \n
1055 keyword2<\>topic topic topic ... \n
1058 nextC = (char *) keywordString;
1060 while (nextC && *nextC)
1063 /* Get the next keyword. If we find newlines while looking for
1064 the keyword, throw them away. If the next token is the end-
1067 nextC = GetNextKeyword (nextC, "<\\>", &token);
1071 XrmDestroyDatabase (kDb);
1074 _DtHelpCeFreeStringArray (vol->keywords);
1075 vol->keywords = NULL;
1077 if (vol->keywordTopics)
1079 for (topicList = vol->keywordTopics;
1080 topicList; topicList++)
1081 _DtHelpCeFreeStringArray (*topicList);
1082 free (vol->keywordTopics);
1083 vol->keywordTopics = NULL;
1091 /* We have the next keyword. Hang onto it and add it to the list
1092 once we get the array of topics. We don't add it yet because if
1093 there are no topics we want to throw it away. (Silently ignoring
1094 keywords which specify no topics is an undocumented feature.) */
1096 currKeyword = token;
1098 /* Now get the list of topics. */
1102 nextC = _DtHelpGetNxtToken (nextC, &token);
1106 XrmDestroyDatabase (kDb);
1109 _DtHelpCeFreeStringArray (vol->keywords);
1110 vol->keywords = NULL;
1112 if (vol->keywordTopics)
1114 for (topicList = vol->keywordTopics;
1115 topicList; topicList++)
1116 _DtHelpCeFreeStringArray (*topicList);
1117 free (vol->keywordTopics);
1118 vol->keywordTopics = NULL;
1121 _DtHelpCeFreeStringArray (topics);
1127 /* If the next token is end-of-file (\0), then quit. Otherwise
1128 if the next token is a newline, then we have gotten all of
1129 the topics and we need to add them to the array of topic
1130 arrays. The final choice is that the token is a string so
1131 we add it to the current array of topics. */
1137 /* We have all of the topics. If the array of topics isn't
1138 empty, add everything to the data structures.
1142 vol->keywords = (char **) _DtHelpCeAddPtrToArray (
1143 (void **) vol->keywords,
1144 (void *) currKeyword);
1145 vol->keywordTopics = (char ***) _DtHelpCeAddPtrToArray (
1146 (void **) vol->keywordTopics,
1149 * If we just malloc'ed ourselves out of existence...
1152 if (vol->keywords == 0 || vol->keywordTopics == 0)
1154 XrmDestroyDatabase (kDb);
1158 _DtHelpCeFreeStringArray (vol->keywords);
1159 _DtHelpCeFreeStringArray (topics);
1160 vol->keywords = NULL;
1162 if (vol->keywordTopics)
1164 for (topicList = vol->keywordTopics;
1165 topicList; topicList++)
1166 _DtHelpCeFreeStringArray (*topicList);
1167 free (vol->keywordTopics);
1168 vol->keywordTopics = NULL;
1177 topics = (char **) _DtHelpCeAddPtrToArray ((void **) topics,
1180 * If we just malloc'ed ourselves out of existence
1186 XrmDestroyDatabase (kDb);
1189 _DtHelpCeFreeStringArray (vol->keywords);
1190 vol->keywords = NULL;
1192 if (vol->keywordTopics != NULL)
1194 for (topicList = vol->keywordTopics;
1195 topicList; topicList++)
1196 _DtHelpCeFreeStringArray (*topicList);
1197 free (vol->keywordTopics);
1198 vol->keywordTopics = NULL;
1205 } while (nextC && *nextC);
1211 XrmDestroyDatabase (kDb);
1215 } /* End _DtHelpCeGetCcdfKeywordList */
1217 /******************************************************************************
1218 * Function: int _DtHelpCeGetCcdfVolumeAbstract (_DtHelpVolume vol,
1221 * Parameters: vol Specifies the loaded volume.
1222 * abstract Returns the abstract of the volume. This string
1223 * is owned by the caller and should be freed.
1225 * Return Value: 0 if successful, -1 if a failure occurs
1227 * Purpose: Get the abstract of a volume.
1228 ******************************************************************************/
1230 _DtHelpCeGetCcdfVolumeAbstract (
1235 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1238 abstract = GetResourceString(ccdfVol->volDb, NULL, "Abstract", "abstract");
1239 if (abstract == NULL)
1241 if (errno == CEErrorIllegalResource)
1242 errno = CEErrorMissingAbstractRes;
1245 *retAbs = strdup(abstract);
1247 if (*retAbs == NULL)
1253 /*****************************************************************************
1254 * Function: int _DtHelpCeMapCcdfTargetToId (_DtHelpVolume vol,
1258 * Parameters: vol Specifies the loaded volume
1259 * target_id Specifies target location ID
1260 * ret_id Returns the id containing the target_id.
1261 * This memory *IS NOT* owned by the caller.
1262 * And *MAY* point to target_id.
1264 * Returns: 0 if successful, -1 if a failure occurs
1266 * Purpose: Find which topic contains a specified locationID.
1268 *****************************************************************************/
1270 _DtHelpCeMapCcdfTargetToId (
1272 const char *target_id,
1275 char newTarget[128];
1276 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1278 strcpy (newTarget, target_id);
1279 _DtHelpCeUpperCase(newTarget);
1282 * find the location id for the topic that contains the
1283 * target_id (they may be the same). Then find the filename
1286 *ret_id = (char *) target_id;
1287 if (GetFilenameResource (ccdfVol, newTarget) == NULL)
1290 * if the reason TopicFilename failed was because we couldn't
1291 * find a resource, try looking for it in the LocationIDs.
1293 if (errno == CEErrorIllegalResource &&
1294 LocationIDTopic (vol, newTarget, ret_id) == 0 &&
1295 GetFilenameResource(ccdfVol, *ret_id) != NULL)
1303 } /* End _DtHelpCeMapCcdfTargetToId */
1305 /*****************************************************************************
1306 * Function: char * _DtHelpCeGetCcdfVolLocale (_DtHelpVolume vol)
1308 * Parameters: vol Specifies the loaded volume
1310 * Returns: The pointer to the locale string if successful. Otherwise
1313 * Purpose: Get the locale of the specified volume.
1314 * Returns the locale in a unix specific format
1315 * - locale[_ter][.charset] - This memory is owned by
1318 *****************************************************************************/
1320 _DtHelpCeGetCcdfVolLocale (
1323 char *locale = NULL;
1325 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1328 locale = GetResourceString(ccdfVol->volDb, NULL, "CharSet", "charSet");
1329 if (_DtHelpCeStrchr(locale, ".", 1, &charSet) != 0)
1332 _DtHelpCeXlateOpToStdLocale(DtLCX_OPER_CCDF,charSet,&locale,NULL,NULL);
1333 /* charset is owned by the volume Xrm database; don't free */
1335 else if (NULL != locale)
1336 locale = strdup(locale);
1340 } /* End _DtHelpCeGetCcdfVolLocale */
1342 /*****************************************************************************
1343 * Function: int _DtHelpCeGetCcdfDocStamp (_DtHelpVolume vol, char **ret_doc,
1346 * Parameters: volume Specifies the loaded volume
1347 * ret_doc Returns the doc id.
1348 * ret_time Returns the time stamp.
1350 * Memory: Caller owns the string in ret_doc and ret_time.
1352 * Returns: 0 if successful, -2 if the volume does not contain
1353 * one or the other, -1 if any other failure.
1355 * Purpose: Get doc id and time stamp of a volume.
1357 *****************************************************************************/
1359 _DtHelpCeGetCcdfDocStamp (
1368 if (ret_doc != NULL)
1371 if (ret_time != NULL)
1375 if (stat(vol->volFile, &buf) == 0)
1377 *ret_time = (char *) malloc (sizeof(time_t) * 3 + 1);
1378 if (*ret_time != NULL)
1380 sprintf(*ret_time, "%u", (unsigned) buf.st_mtime);
1387 } /* End _DtHelpCeGetCcdfDocStamp */
1389 /******************************************************************************
1390 * Function: static int _DtHelpCeGetCcdfTopTopic (_DtHelpVolume vol,
1393 * Parameters: vol Specifies the loaded volume.
1394 * topic Returns the locationID for the top topic in
1395 * the volume hierarchy. This string is NOT
1396 * owned by the caller and should only be read or
1399 * Return Value: 0 if successful, -1 if a failure occurs
1401 * Purpose: Get the top topic of a volume.
1402 ******************************************************************************/
1404 _DtHelpCeGetCcdfTopTopic (
1408 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1410 *retTopic = GetResourceString(ccdfVol->volDb, NULL, "TopTopic", "topTopic");
1411 if (*retTopic == NULL)
1413 if (errno == CEErrorIllegalResource)
1414 errno = CEErrorMissingTopTopicRes;
1421 /******************************************************************************
1422 * Function: char *_DtHelpCeGetCcdfVolTitle (_DtHelpVolume vol);
1424 * Parameters: vol Specifies the loaded volume.
1426 * Return Value: The title if successful, NULL otherwise.
1427 * The caller *DOES NOT* own the memory returned
1428 * and *MUST NOT* modify the memory.
1430 * Purpose: Get the title of a volume.
1432 ******************************************************************************/
1434 _DtHelpCeGetCcdfVolTitle (
1437 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1439 return (GetResourceString (ccdfVol->volDb, NULL, "Title", "title"));
1442 /******************************************************************************
1443 * Function: int _DtHelpCeGetCcdfVolumeTitle (_DtHelpVolume vol);
1445 * Parameters: vol Specifies the loaded volume.
1447 * Return Value: The title if successful, NULL otherwise.
1448 * The caller *DOES NOT* own the memory returned
1449 * and *MUST NOT* modify the memory.
1451 * Purpose: Get the title of a volume.
1453 ******************************************************************************/
1455 _DtHelpCeGetCcdfVolumeTitle (
1459 *ret_title = _DtHelpCeGetCcdfVolTitle(vol);
1461 if (*ret_title == NULL)
1463 if (errno == CEErrorIllegalResource)
1464 errno = CEErrorMissingTitleRes;
1468 *ret_title = strdup(*ret_title);
1469 if (*ret_title == NULL)
1471 errno = CEErrorMalloc;
1477 /******************************************************************************
1478 * Function: int _DtHelpCeOpenCcdfVolume (_DtHelpVolume vol);
1480 * Parameters: vol Specifies the loaded volume.
1484 * Purpose: Open a CCDF help volume
1486 ******************************************************************************/
1488 _DtHelpCeOpenCcdfVolume (
1492 CcdfVolumePtr ccdfVol;
1494 ccdfVol = (struct _CcdfVolumeInfo *) malloc(sizeof(struct _CcdfVolumeInfo));
1495 if (ccdfVol != NULL)
1497 *ccdfVol = DefaultCcdfVol;
1498 ccdfVol->volDb = XrmGetFileDatabase(vol->volFile);
1499 if (ccdfVol->volDb != NULL)
1501 (void) stat(vol->volFile, &buf);
1502 vol->check_time = buf.st_mtime;
1503 vol->vols.ccdf_vol = (CcdfVolumeHandle) ccdfVol;
1512 /******************************************************************************
1513 * Function: void _DtHelpCeCloseCcdfVolume (_DtHelpVolume vol);
1515 * Parameters: vol Specifies the loaded volume.
1519 * Purpose: Open a CCDF help volume
1521 ******************************************************************************/
1523 _DtHelpCeCloseCcdfVolume (
1526 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1528 if (ccdfVol->volDb != NULL)
1529 XrmDestroyDatabase (ccdfVol->volDb);
1531 if (ccdfVol->topicList != NULL)
1532 _DtHelpCeFreeStringArray (ccdfVol->topicList);
1534 if (ccdfVol->keywordFile != NULL)
1535 free (ccdfVol->keywordFile);
1540 /******************************************************************************
1541 * Function: int _DtHelpCeRereadCcdfVolume (_DtHelpVolume vol);
1543 * Parameters: vol Specifies the loaded volume.
1547 * Purpose: Reread a CCDF volume.
1549 ******************************************************************************/
1551 _DtHelpCeRereadCcdfVolume (
1554 CcdfVolumePtr ccdfVol = GetCcdfVolumePtr(vol);
1556 if (ccdfVol->volDb != NULL)
1557 XrmDestroyDatabase (ccdfVol->volDb);
1559 if (ccdfVol->topicList != NULL)
1560 _DtHelpCeFreeStringArray (ccdfVol->topicList);
1562 if (ccdfVol->keywordFile != NULL)
1563 free (ccdfVol->keywordFile);
1565 ccdfVol->topicList = NULL;
1566 ccdfVol->keywordFile = NULL;
1567 ccdfVol->volDb = XrmGetFileDatabase(vol->volFile);
1569 if (ccdfVol->volDb != NULL)
1575 /******************************************************************************
1576 * Function: char *_DtHelpCeGetResourceString (XrmDatabase db, char *topic,
1577 * char *resClass, char *resName)
1579 * Parameters: db Specifies the handle to a resource database.
1580 * topic Specifies the topic whose resource value is
1581 * desired. If 'topic' is NULL, the
1582 * desired resource is for the volume and
1583 * not a specific topic.
1584 * resClass Specifies the resource class name.
1585 * resName Specifies the resource name.
1587 * Return Value: Returns the desired resource as string.
1588 * This string is NOT owned by the caller and
1589 * should only be read or copied.
1591 * Returns NULL if an error occurs.
1593 * errno Values: CEErrorMalloc
1594 * CEErrorIllegalResource If the resource is not in
1595 * the database or if the
1598 * Purpose: Get a resource value for a volume or topic.
1600 ******************************************************************************/
1602 _DtHelpCeGetResourceString (
1608 return (GetResourceString(db, topic, resClass, resName));
1611 /******************************************************************************
1612 * Function: char **_DtHelpCeGetResourceStringArray (XrmDatabase db,
1613 * char *topic, char *resClass, char *resName)
1615 * Parameters: db Specifies the handle to a resource database.
1616 * topic Specifies the topic whose resource value
1617 * is desired. If 'topic' is NULL, the
1618 * desired resource is for the volume and
1619 * not a specific topic.
1620 * resClass Specifies the resource class name.
1621 * resName Specifies the resource name.
1623 * Return Value: Returns a NULL-terminated string array
1624 * containing the value of the desired resource.
1625 * The elements of the array are the strings of
1626 * non-whitespace characters in the resource value.
1627 * This array is owned by the caller and should be
1628 * freed (using _DtHelpCeFreeStringArray) when not
1631 * Purpose: Get am array-valued resource for a volume or topic.
1633 ******************************************************************************/
1635 _DtHelpCeGetResourceStringArray (
1641 return (GetResourceStringArray(db, topic, resClass, resName));