1 /* $XConsortium: Access.c /main/11 1996/11/01 10:09:29 drk $ */
2 /************************************<+>*************************************
3 ****************************************************************************
7 ** Project: Run Time Project File Access
9 ** Description: This body of code handles the access routines for the
13 ** (c) Copyright 1987-1994, 1996 Hewlett-Packard Company
14 ** (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
15 ** (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
16 ** (c) Copyright 1993, 1994, 1996 Novell, Inc.
17 ** (c) Copyright 1996 Digital Equipment Corporation.
18 ** (c) Copyright 1996 FUJITSU LIMITED.
19 ** (c) Copyright 1996 Hitachi.
22 ****************************************************************************
23 ************************************<+>*************************************/
35 #include <sys/param.h>
39 #include <X11/Xresource.h>
46 * Canvas Engine includes
49 #include "CanvasSegP.h"
54 #include "CanvasError.h"
57 #include "FontAttrI.h"
60 #include "AccessSDLP.h"
61 #include "AccessSDLI.h"
62 #include "AccessCCDFI.h"
63 #include "FormatUtilI.h"
66 #include "FormatSDLI.h"
68 #include "CCDFUtilI.h"
69 #include "StringFuncsI.h"
71 #include "Lock.h" /* Process and App Lock macros */
76 /******** Private Defines ********/
77 #define LIST_INCREMENT 10
79 /******** End Private Defines ********/
81 /******** Private Function Declarations ********/
82 static int GetVolumeKeywords (
85 static int VolumeLoad (
87 _DtHelpVolume *retVol);
88 static int VolumeUnload (
90 /******** End Private Function Declarations ********/
92 /******** Private Macro Declarations ********/
93 /******** End Private Macro Declarations ********/
95 /******************************************************************************
97 * Private variables used within this file.
99 *******************************************************************************/
100 static _DtHelpVolume volChain = NULL; /* Pointer to the head of the chain */
101 /* of all the open volumes. */
102 static const char *Slash = "/";
103 static const char *Period = ".";
105 /******************************************************************************
107 ******************************************************************************/
108 /******************************************************************************
109 * Function: CheckVolList (_DtHelpVolume vol, _DtHelpVolume *ret_prev)
111 * Parameters: vol Specifies the volume to search for.
112 * ret_prev Returns the volume whose nextVol element
113 * points to 'vol' if non NULL.
115 * Returns: 0 if successful, -1 if failure.
119 * Purpose: To check for the existance of a volume.
121 ******************************************************************************/
125 _DtHelpVolume *ret_prev )
128 _DtHelpVolume prevVol = NULL;
130 _DtHelpProcessLock();
133 while (myVol != NULL && myVol != vol)
136 myVol = myVol->nextVol;
144 _DtHelpProcessUnlock();
148 _DtHelpProcessUnlock();
152 /******************************************************************************
153 * Function: int VolumeLoad (char *volFile, _DtHelpVolume *retVol);
155 * Parameters: volFile Specifies the name of the Help Volume file
158 * retVol Returns the handle to the loaded volume.
160 * Return Value: Returns 0 if successful,
161 * -1 if an error occurred.
163 * errno Values: CEErrorMalloc
164 * CEErrorIllegalDatabaseFile
166 * Purpose: This function must be called to load a Help Volume file
167 * before any of the information in the volume can be
170 ******************************************************************************/
174 _DtHelpVolume *retVol)
176 /* Allocate the volume structure and initialize it. */
177 *retVol = (_DtHelpVolume) malloc (sizeof (struct _DtHelpVolumeRec));
180 (*retVol)->sdl_flag = False;
181 (*retVol)->volFile = volFile;
182 (*retVol)->keywords = NULL;
183 (*retVol)->keywordTopics = NULL;
184 (*retVol)->openCount = 1;
185 (*retVol)->nextVol = NULL;
186 (*retVol)->vols.ccdf_vol = NULL;
188 if (_DtHelpCeOpenSdlVolume ((*retVol)) == 0)
190 else if (_DtHelpCeOpenCcdfVolume(*retVol) == 0)
194 * Set the global error
196 errno = CEErrorIllegalDatabaseFile;
199 * error on loading the database.
201 free ((char *) ((*retVol)->volFile));
202 free ((char *) (*retVol));
206 errno = CEErrorMalloc;
210 } /* End VolumeLoad */
212 /*******************************************************************************
213 * Function: int VolumeUnload (_DtHelpVolume vol);
215 * Parameters: vol Specifies the loaded volume.
217 * Return Value: 0 if successful, -1 if a failure occurs
221 * Purpose: When the volume is no longer needed, it should be unloaded
222 * with this call. Unloading it frees the memory (which means
223 * any handles on the volume become invalid.)
225 ******************************************************************************/
235 if (vol->sdl_flag == True)
236 _DtHelpCeCloseSdlVolume((_DtHelpVolumeHdl) vol);
238 _DtHelpCeCloseCcdfVolume(vol);
240 if (vol->volFile != NULL)
243 if (vol->keywords != NULL)
244 _DtHelpCeFreeStringArray (vol->keywords);
246 if (vol->keywordTopics != NULL)
248 for (topicList = vol->keywordTopics;
249 *topicList != NULL; topicList++)
250 _DtHelpCeFreeStringArray (*topicList);
252 free (vol->keywordTopics);
261 /*******************************************************************************
262 * Function: int RereadVolume (_DtHelpVolume vol);
264 * Parameters: vol Specifies the loaded volume.
266 * Return Value: 0 if successful, -1 if a failure occurs
270 * Purpose: When the volume is no longer needed, it should be unloaded
271 * with this call. Unloading it frees the memory (which means
272 * any handles on the volume become invalid.)
274 ******************************************************************************/
282 if (vol->keywords != NULL)
284 _DtHelpCeFreeStringArray (vol->keywords);
285 vol->keywords = NULL;
288 if (vol->keywordTopics != NULL)
290 for (topicList = vol->keywordTopics; *topicList != NULL; topicList++)
291 _DtHelpCeFreeStringArray (*topicList);
293 free (vol->keywordTopics);
294 vol->keywordTopics = NULL;
297 if (vol->sdl_flag == False)
298 result = _DtHelpCeRereadCcdfVolume(vol);
300 result = _DtHelpCeRereadSdlVolume(vol);
305 /******************************************************************************
306 * Function: static int GetKeywordTopics (_DtHelpVolume vol, char *keyword,
309 * Parameters: vol Specifies the loaded volume
310 * keyword Specifies the keyword whose location is desired.
311 * topics Returns a NULL-terminated string array of the
312 * list of topics which contain the keyword.
313 * This array is NOT owned by the caller and
314 * should only be read or copied.
316 * Return Value: 0 if successful, -1 if a failure occurs
318 * errno Values: CEErrorNoKeywordList
319 * Specifies that the volume does not
320 * have a keyword list.
321 * CEErrorIllegalKeyword
322 * Specifies that 'keyword' was not
325 * CEErrorIllegalDatabaseFile
326 * Specifies that the keyword file is
327 * invalid or corrupt.
328 * CEErrorMissingKeywordsRes
329 * Specifies that the keyword file does
330 * not contain the 'Keywords/keywords'
331 * resource or the resource is NULL
334 * Purpose: Find which topic contains a specified locationId.
336 ******************************************************************************/
347 _DtHelpProcessLock();
350 /* Get the list of keywords. */
351 if (GetVolumeKeywords (vol, &keywords) != 0)
353 _DtHelpProcessUnlock();
357 if (keywords == NULL || vol->keywordTopics == NULL)
359 errno = CEErrorNoKeywordList;
360 _DtHelpProcessUnlock();
364 /* Search the list of keywords for the current one. */
366 while (*nextKey != NULL && strcmp (*nextKey, keyword))
369 if (*nextKey == NULL)
371 errno = CEErrorIllegalKeyword;
372 _DtHelpProcessUnlock();
376 index = nextKey - keywords;
377 *retTopics = *(vol->keywordTopics + index);
379 _DtHelpProcessUnlock();
383 /******************************************************************************
384 * Function: static int GetVolumeKeywords(_DtHelpVolume vol,char ***keywords);
386 * Parameters: vol Specifies the volume.
387 * keywords Returns a NULL-terminated string array
388 * containing the sorted list of keywords in the
389 * volume. This array is NOT owned by the caller
390 * and should only be read or copied.
392 * Return Value: 0 if successful, -1 if a failure occurs
394 * errno Values: CEErrorMalloc
395 * CEErrorIllegalDatabaseFile
396 * Specifies that the keyword file is
397 * invalid or corrupt.
398 * CEErrorMissingKeywordsRes
399 * Specifies that the keyword file does
400 * not contain the 'Keywords/keywords'
401 * resource or the resource is NULL
403 * Purpose: Get the list of keywords defined in a volume.
405 ******************************************************************************/
412 _DtHelpCeLockInfo lockInfo;
414 _DtHelpProcessLock();
416 /* Keywords aren't loaded until they are needed, so see if they have
418 if (vol->keywords == NULL)
421 * What type of volume is it?
423 if (_DtHelpCeLockVolume(vol, &lockInfo) != 0)
425 _DtHelpProcessUnlock();
429 if (vol->sdl_flag == False)
430 result = _DtHelpCeGetCcdfKeywordList(vol);
432 result = _DtHelpCeGetSdlKeywordList(vol);
434 _DtHelpCeUnlockVolume(lockInfo);
438 _DtHelpProcessUnlock();
443 /* All of the keyword processing is done when they are loaded. */
444 *retKeywords = vol->keywords;
446 if (*retKeywords == NULL)
448 _DtHelpProcessUnlock();
452 _DtHelpProcessUnlock();
456 /*****************************************************************************
457 * Function: GetTopicTitleAndAbbrev (
461 * Memory own by caller:
465 * Returns: 0 if successful, -2 if didn't find the id,
466 * -3 if couldn't format the topic,
469 * Purpose: Find the title and abbreviated title of a topic.
471 *****************************************************************************/
473 GetTopicTitleAndAbbrev (
474 _DtHelpVolume volume,
481 char buffer[BUFF_SIZE];
483 char *filename = NULL;
485 _DtHelpCeLockInfo lockInfo;
487 if (_DtHelpCeLockVolume(volume, &lockInfo) != 0)
490 if (_DtHelpCeFindId(volume, id, lockInfo.fd, &filename, &offset) != True)
494 * What type of volume is it?
498 if (0 == _DtHelpCeGetVolumeFlag(volume))
500 result = _DtHelpCeFileOpenAndSeek(filename,offset,-1,&file,NULL);
504 if (_DtHelpCeReadBuf (file, buffer, BUFF_SIZE) != -1)
508 if (_DtHelpCeGetCcdfTopicAbbrev (NULL, file,
509 buffer, &bufPtr, BUFF_SIZE, MB_CUR_MAX,
510 ret_name, NULL, ret_abbrev) != 0)
513 _DtHelpCeBufFileClose(file, True);
518 _DtHelpProcessLock();
519 if (_DtHelpCeFrmtSDLTitleToAscii(volume, offset,
520 ret_name, ret_abbrev) != 0)
522 _DtHelpProcessUnlock();
526 if (filename != NULL)
529 _DtHelpCeUnlockVolume(lockInfo);
534 /*****************************************************************************
535 * Function: static int FileOpenRtnFd (char *name, int *ret_fd)
537 * Parameters: name Specifies the file to open.
538 * ret_fd Returns the fd of the opened file.
540 * Returns: 0 if required uncompress.
541 * file descriptor to remove the file from the system.
542 * 1 if no uncompression required.
543 * -1 if a failure occurs
545 * errno Values: EINVAL Specifies an invalid parameter was
548 * Specifies the seek offset was invalid.
550 * Purpose: Find out if a file is compressed and uncompress it if it is.
552 *****************************************************************************/
559 char tmpName[MAXPATHLEN + 1];
563 * check to see if the file exists in uncompressed form
565 *ret_fd = open(name, O_RDONLY);
569 * get a temporary name
571 (void) tmpnam (tmpName);
574 * malloc memory for the dot Z file name.
576 inFile = (char *) malloc (strlen (name) + 3);
580 * make the dot Z file
582 strcpy (inFile, name);
583 strcat (inFile, ".Z");
588 result = _DtHelpCeUncompressFile (inFile, tmpName);
598 * now open the uncompressed file
600 *ret_fd = open(tmpName, O_RDONLY);
608 errno = CEErrorMalloc;
615 } /* End FileOpenRtnFd */
617 /******************************************************************************
618 * Semi-Public Functions
619 ******************************************************************************/
620 /*****************************************************************************
621 * Function: char *_DtHelpCeExpandPathname (char *spec, char *filename, char *type,
622 * char *suffix, char *lang, _DtSubstitutionRec *subs, int num)
625 * spec Specifies a string with substitution
627 * containing the character set if found.
628 * filename Specifies the string to substitute for %N.
629 * type Specifies the string to substitute for %T.
630 * suffix Specifies the string to substitute for %S.
631 * lang Specifies the string to substitute for %L.
632 * subs Specifies the application own specific
634 * num Specifies the number of substitution pairs
637 * Memory own by caller:
640 * Returns: The expanded filename if successful. NULL if errors.
642 * Purpose: Expand a string with %<char> substitution values.
643 * Default substitutions are:
644 * %N replaced with 'filename'.
645 * %T replaced with 'type'
646 * %S replaced with 'suffix'
647 * %L replaced with 'lang'
649 * %l replaced with the language sub part of 'lang'.
650 * %t replaced with the territory sub part of 'lang'.
651 * %c replaced with the code set sub part of 'lang'.
652 * Other substitutions can be done via the 'subs' parameter.
654 *****************************************************************************/
656 _DtHelpCeExpandPathname (
662 _DtSubstitutionRec *subs,
672 char pathName [MAXPATHLEN + 5];
673 Boolean previousSlash = False;
675 _DtSubstitutionRec mySubs [MY_NUM];
677 if (spec == NULL || *spec == NULL)
684 * fill in the language sub parts
686 if (_DtHelpCeGetLangSubParts (lang, &partLang, &partTer, &partCodeSet))
689 mySubs[0].match = 'N';
690 mySubs[0].substitution = filename;
691 mySubs[1].match = 'T';
692 mySubs[1].substitution = type;
693 mySubs[2].match = 'S';
694 mySubs[2].substitution = suffix;
695 mySubs[3].match = 'L';
696 mySubs[3].substitution = lang;
698 mySubs[4].match = 'l';
699 mySubs[4].substitution = partLang;
700 mySubs[5].match = 't';
701 mySubs[5].substitution = partTer;
702 mySubs[6].match = 's';
703 mySubs[6].substitution = partCodeSet;
710 len = mblen (spec, MB_CUR_MAX);
712 if (len == 1 && *spec == '/')
718 previousSlash = True;
722 else if (len == 1 && *spec == '%')
734 previousSlash = True;
742 while (i < MY_NUM && mySubs && mySubs[i].match != *spec)
747 if (mySubs[i].substitution != NULL)
749 subString = mySubs[i].substitution;
750 if (((int)(ptr - pathName + strlen(subString)))
753 errno = CEErrorExceedMaxSize;
756 while (subString && *subString)
757 *ptr++ = *subString++;
763 while (i < num && subs && subs[i].match != *spec)
766 * If the substitution character is not found
767 * include the character onto the final string.
771 else if (subs[i].substitution != NULL)
773 subString = subs[i].substitution;
774 if (((int)(ptr - pathName + strlen(subString)))
777 errno = CEErrorExceedMaxSize;
780 while (subString && *subString)
781 *ptr++ = *subString++;
785 previousSlash = False;
791 previousSlash = False;
799 if (ptr - pathName > MAXPATHLEN)
801 errno = CEErrorExceedMaxSize;
814 ptr = strdup (pathName);
816 errno = CEErrorMalloc;
821 /*****************************************************************************
822 * Function: char *_DtHelpCeGetLangSubParts (char *lang, char **subLang,
823 * char **subTer, char **subCodeSet)
826 * lang Specifies the language string.
827 * subLang Returns the language sub part of 'lang'
829 * subTer Returns the territory sub part of 'lang'
831 * subCodeSet Returns the code set sub part of 'lang'
834 * Memory own by caller:
843 * Returns: 0 if successful, -1 if errors.
845 * Purpose: Break a %l_%t.%c language specification into its sub parts.
847 *****************************************************************************/
849 _DtHelpCeGetLangSubParts (
861 if (subLang == NULL || subTer == NULL || subCodeSet == NULL)
867 if (lang != NULL && *lang != '\0')
872 _DtHelpCeStrchr (lang, "_", MB_CUR_MAX, &ptr);
876 * do we want this string?
881 sLang = (char *) malloc (len + 1);
884 strncpy (sLang, lang, len);
889 errno = CEErrorMalloc;
894 * just mark that the lang part was found
903 * look for lang.codeset
905 _DtHelpCeStrchr (lang, Period, MB_CUR_MAX, &ptr);
911 * if it was in the form lang_ter.codeset, sLang will non-null
916 * do we want to save the territory?
920 sTer = (char *) malloc (len + 1);
923 strncpy (sTer, lang, len);
928 errno = CEErrorMalloc;
933 * don't wan to save, but make sure we mark the territory
934 * as being found (non-null).
940 * the lang was in the form lang.codeset.
941 * now check to see if want to save the lang portion.
943 else if (subLang != NULL)
945 sLang = (char *) malloc (len + 1);
948 strncpy (sLang, lang, len);
953 errno = CEErrorMalloc;
958 * didn't want to save the lang portion, but mark as found.
965 * currently pointing at the dot?
967 if (ptr && *ptr == '.')
970 * yes save the code set
973 if (subCodeSet != NULL)
975 sCode = strdup (ptr);
978 errno = CEErrorMalloc;
983 * don't save the code set, but make sure we mark as found
989 * didn't find a code set, so save the current info.
990 * If we haven't already processed a lang portion, save as the
993 else if (sLang == NULL)
997 sLang = strdup (lang);
1000 errno = CEErrorMalloc;
1008 * otherwise this is the territory of the language. Save if desired
1010 else if (subTer != NULL)
1012 sTer = strdup (lang);
1015 errno = CEErrorMalloc;
1026 *subCodeSet = sCode;
1031 /*****************************************************************************
1032 * Function: int _DtHelpCeGetUncompressedFileName (char *name, char **ret_name)
1034 * Parameters: name Specifies the file to open.
1035 * ret_name Returns the name of the uncompressed file.
1036 * This memory must be freed by the caller.
1038 * Returns: 0 if required uncompress. ret_name will contain the
1039 * name of the uncompressed file. The caller is required
1040 * to free the memory.
1041 * 1 if no uncompression required. ret_name points to name.
1042 * -1 if a failure occurs
1044 * errno Values: EINVAL Specifies an invalid parameter was
1047 * Specifies the seek offset was invalid.
1049 * Purpose: Find out if a file is compressed and uncompress it if it is.
1051 *****************************************************************************/
1053 _DtHelpCeGetUncompressedFileName (
1057 char *inFile = NULL;
1058 char tmpName[MAXPATHLEN + 1];
1062 * check to see if the file exists in uncompressed form
1065 if (access (name, F_OK) == -1)
1068 * get a temporary name
1070 (void) tmpnam (tmpName);
1073 * malloc memory for the dot Z file name.
1075 inFile = (char *) malloc (strlen (name) + 3);
1079 * make the dot Z file
1081 strcpy (inFile, name);
1082 strcat (inFile, ".Z");
1087 result = _DtHelpCeUncompressFile (inFile, tmpName);
1096 *ret_name = strdup (tmpName);
1097 if (*ret_name == NULL)
1099 errno = CEErrorMalloc;
1105 errno = CEErrorMalloc;
1113 /******************************************************************************
1114 * Function: int _DtHelpCeCompressPathname (char *basePath)
1116 * Parameters: basePath Specifies the path for the file possibily
1117 * containing /./, //, and /../.
1119 * Return Value: 0 for success, -1 for failure.
1120 * The number of bytes in basePath will be less than or
1121 * equal to the number of bytes in basePath when passed
1124 * errno Values: EINVAL
1126 * Purpose: This function compresses directory changes found
1127 * in a file name path.
1129 ******************************************************************************/
1131 _DtHelpCeCompressPathname ( char *basePath )
1138 char *ptr = basePath;
1139 char *prevPtr = NULL;
1141 if (basePath == NULL || *basePath != '/')
1150 * for multi-byte environments, check how far single bytes extend.
1155 if (MB_CUR_MAX == 1 || mblen (&ptr[1], MB_CUR_MAX) == 1)
1158 if (MB_CUR_MAX == 1 || mblen (&ptr[2], MB_CUR_MAX) == 1)
1161 if (MB_CUR_MAX == 1 || mblen (&ptr[3], MB_CUR_MAX) == 1)
1169 if (char1 == True && ptr[1] == '/')
1170 strcpy (ptr, (ptr + 1));
1175 else if (char2 == True && ptr[1] == '.' && ptr[2] == '/')
1176 strcpy (ptr, (ptr + 2));
1181 else if (char3 == True && strncmp (&ptr[1], "../", 3) == 0)
1184 * if at the top of the path, just ignore the extra
1187 if (prevPtr == NULL)
1188 strcpy (ptr, (ptr + 3));
1194 strcpy (prevPtr, (ptr + 3));
1197 * reset the current pointer
1202 * find the previous slash
1205 result = _DtHelpCeStrrchr(basePath,Slash,MB_CUR_MAX,&prevPtr);
1210 * if there is no previous slash, set the pointer to
1211 * indicate that we're at the top of the path (NULL).
1217 * restore the slash (or null byte)
1225 * remember this slash for /../ directory changes
1230 * skip this slash, and find the next one.
1233 result = _DtHelpCeStrcspn (ptr, "/", MB_CUR_MAX, &len);
1236 * if we run into invalid data, error
1244 } while (*ptr != '\0');
1249 /******************************************************************************
1250 * Function: char *_DtHelpCeTracePathName (char *path)
1253 * path Specifies the a path to trace and compress
1255 * Return Value: The new string if successful, NULL otherwise.
1256 * The new string is owned by the caller and contains
1257 * an absolute pathname.
1259 * errno Values: EINVAL Illegal parameter specified.
1260 * getcwd(2) errno set via a getcwd call.
1261 * readlink(2) errno set via a readlink call.
1263 * DtErrorExceedMaxSize The new path will exceed
1265 * DtErrorIllegalPath The compression will required
1266 * the path to change to a parent
1267 * directory beyond the beginning
1270 * Purpose: This function is called to trace the path of a file.
1271 * It can contain symbolic links, //, /./, and /../.
1273 ******************************************************************************/
1275 _DtHelpCeTracePathName (char *path)
1282 char newPath [2 * MAXPATHLEN + 2];
1283 char linkPath [MAXPATHLEN + 2];
1284 char tempPath [MAXPATHLEN + 2];
1286 if (path == NULL || *path == '\0')
1293 * initialize the new path
1298 * if the path passed in does not start with a slash,
1299 * get the current working directory and append the path to it.
1301 if ((MB_CUR_MAX == 1 || mblen(path, MB_CUR_MAX) == 1) && *path != '/')
1303 if (getcwd (newPath, MAXPATHLEN) == NULL)
1306 strcat (newPath, "/");
1310 * put the path in the working path buffer (or append it to
1311 * the current working directory).
1313 strcat (newPath, path);
1316 * Compress out the slashes and directory changes.
1318 if (_DtHelpCeCompressPathname (newPath) != 0)
1325 * point to the first character of the next directory
1330 * get the next slash after that
1332 result = _DtHelpCeStrcspn (prev, "/", MB_CUR_MAX, &len);
1337 * Found either a slash or a null byte.
1338 * place the string terminator at this point
1345 * find out if this path is a symbolic link
1347 result = readlink (newPath, linkPath, MAXPATHLEN);
1350 * replace the slash (or null byte).
1355 * check for the result of the readlink call
1360 * if this was NOT a symbolic link, errno should be EINVAL
1362 if (errno != EINVAL)
1368 * put the null byte on the end of the symbolic link string.
1370 linkPath [result] = '\0';
1373 * Save the rest of the string that we haven't processed
1374 * for tacking on after the new link path has been
1375 * dropped into the path.
1377 strcpy (tempPath, ptr);
1380 * is it an absolute path? Simply replace the path
1381 * being search with the new link path.
1383 if (*linkPath == '/')
1384 strcpy (newPath, linkPath);
1388 * this is a relative link.
1389 * prev is looking at the first character of this directory.
1390 * replace with the link.
1392 strcpy (prev, linkPath);
1396 * now tack on the rest of the name
1398 strcat (newPath, tempPath);
1401 * compress out the directory changes.
1403 if (_DtHelpCeCompressPathname (newPath) != 0)
1407 * start again from the top, until we have a clean path
1412 } while (*ptr != '\0');
1414 return (strdup (newPath));
1417 /******************************************************************************
1418 * Function: char *_DtHelpCeTraceFilenamePath (char *file_path)
1421 * file_path Specifies the a path to trace and compress
1423 * Return Value: The new string if successful, NULL otherwise.
1424 * The new string is owned by the caller and
1425 * contains an absolute filename path.
1427 * errno Values: EINVAL Illegal parameter specified.
1428 * getcwd(2) errno set via a getcwd call.
1429 * readlink(2) errno set via a readlink call.
1431 * DtErrorExceedMaxSize The new path will exceed
1433 * DtErrorIllegalPath The compression will required
1434 * the path to change to a parent
1435 * directory beyond the beginning
1438 * Purpose: This function is called to trace a filename path.
1439 * It can contain symbolic links, //, /./, and /../.
1441 ******************************************************************************/
1443 _DtHelpCeTraceFilenamePath (char *file_path)
1450 char workName [MAXPATHLEN + 2];
1451 char newName [MAXPATHLEN + 2];
1452 char linkName [MAXPATHLEN + 2];
1454 if (file_path == NULL || *file_path == '\0')
1461 if ((MB_CUR_MAX == 1 || mblen(file_path, MB_CUR_MAX) == 1)
1462 && *file_path != '/')
1464 if (getcwd(workName, MAXPATHLEN) == NULL)
1467 strcat(workName, "/");
1470 strcat (workName, file_path);
1475 * find and save the old filename
1477 result = _DtHelpCeStrrchr(workName, Slash, MB_CUR_MAX, &oldName);
1482 * terminate the path
1487 * trace the path, resolving the symbolic links
1488 * and directory changes. If /filename given,
1489 * skip the path tracing.
1492 if (workName[0] != '\0')
1494 newPath = _DtHelpCeTracePathName(workName);
1495 if (newPath == NULL)
1499 * copy the new path and free the allocated copy
1501 strcpy (newName, newPath);
1511 * now append the slash and filename (pointed to by oldName)
1512 * onto the end of the new path.
1514 namePlace = newName + strlen (newName);
1515 strcpy (namePlace, oldName);
1518 * See if the absolute path/filename is a symbolic link.
1520 result = readlink (newName, linkName, MAXPATHLEN);
1523 if (errno != EINVAL)
1531 * put the null byte on the end of the symbolic
1534 linkName [result] = '\0';
1535 if (*linkName == '/')
1536 strcpy (newName, linkName);
1540 * overwrite the filename with the link
1541 * but don't overwrite the slash.
1543 strcpy ((namePlace + 1), linkName);
1547 * make a copy of the new name to work on
1549 strcpy (workName, newName);
1553 return (strdup (newName));
1557 /******************************************************************************
1558 * Core Engine Semi-Public Functions
1559 ******************************************************************************/
1560 /*****************************************************************************
1561 * Function: char *_DtHelpCeGetVolumeName (_DtHelpVolumeHdl volume)
1565 * Returns: ptr to the name of the volume, NULL otherwise.
1567 * Purpose: Get the fully qualified volume name.
1569 *****************************************************************************/
1571 _DtHelpCeGetVolumeName (
1572 _DtHelpVolumeHdl volume_handle)
1576 _DtHelpProcessLock();
1577 volFile = ((_DtHelpVolume)volume_handle)->volFile;
1578 _DtHelpProcessUnlock();
1581 } /* End __DtHelpCeGetVolumeName */
1583 /*****************************************************************************
1584 * Function: int _DtHelpCeFileOpenAndSeek (char *name, int offset, int fildes,
1585 * BufFilePtr *ret_file)
1587 * Parameters: name Specifies the file to open.
1588 * offset Specifies location within the file to seek to.
1590 * Returns: 0 if successful, -1 if a failure occurs
1592 * errno Values: EINVAL Specifies an invalid parameter was
1595 * Specifies the seek offset was invalid.
1597 * Purpose: Open a file and seek to a specific place.
1599 *****************************************************************************/
1601 _DtHelpCeFileOpenAndSeek (
1605 BufFilePtr *ret_file,
1608 unsigned char fileMagic[4];
1615 * Get the file descriptor of the uncompressed file
1620 result = FileOpenRtnFd (name, &tmpFd);
1625 if (ret_time != NULL)
1627 (void) fstat(tmpFd, &buf);
1628 *ret_time = buf.st_mtime;
1632 * make sure we don't go past the end of the file
1634 result = lseek (tmpFd, 0, SEEK_END);
1637 if (result > offset)
1638 result = lseek (tmpFd, offset, SEEK_SET);
1642 errno = CEErrorFileSeek;
1653 bytesRead = read(tmpFd, fileMagic, 4);
1655 { /* something's wrong in reading the file */
1662 { /* started with compressed file magic number */
1664 CECompressInfoPtr myInfo;
1665 BufFilePtr inputRaw;
1668 * allocate the private information
1670 myInfo = (CECompressInfoPtr) malloc(sizeof(CECompressInfo));
1675 errno = CEErrorMalloc;
1680 * set the information
1681 * set the size to the maximum number of bytes we
1686 (((fileMagic[1] * 256) + fileMagic[2]) * 256) + fileMagic[3];
1689 * start with raw functionality
1691 inputRaw = _DtHelpCeBufFileRdRawZ(myInfo);
1692 if (inputRaw == NULL)
1699 *ret_file = _DtHelpCeBufFilePushZ(inputRaw);
1700 if (*ret_file == NULL)
1702 _DtHelpCeBufFileClose(inputRaw, (fd == -1 ? True : False));
1709 * not a compressed file, back up the four bytes we read
1711 result = lseek (tmpFd, offset, SEEK_SET);
1720 * read with raw functionality
1722 *ret_file = _DtHelpCeBufFileRdWithFd(tmpFd);
1723 if (*ret_file == NULL)
1733 } /* End of _DtHelpCeFileOpenAndSeek */
1734 /******************************************************************************
1735 * Core Engine Public Functions
1736 ******************************************************************************/
1737 /******************************************************************************
1738 * Function: int _DtHelpOpenVolume (char *volFile, _DtHelpVolume *retVol);
1740 * Parameters: volFile Specifies the name of the Help Volume file
1743 * retVol Returns the handle to the loaded volume.
1744 * If a volume is opened several times, the
1745 * same handle will be returned each time.
1747 * Return Value: 0 if successful, -1 if a failure occurred.
1749 * errno Values: EINVAL Illegal parameter specified.
1750 * getcwd(2) errno set via a getcwd call.
1751 * readlink(2) errno set via a readlink call.
1753 * CEErrorExceedMaxSize The new path will exceed
1755 * CEErrorIllegalPath The compression will required
1756 * the path to change to a parent
1757 * directory beyond the beginning
1759 * CEErrorIllegalDatabaseFile
1760 * Specifies that 'volFile' is
1761 * an illegal database file.
1764 * Purpose: This function must be called to open a Help Volume file
1765 * before any of the information in the volume can be
1768 ******************************************************************************/
1772 _DtHelpVolumeHdl *retVol)
1775 _DtHelpVolume vol, prevVol;
1777 _DtHelpProcessLock();
1779 if (volFile == NULL || retVol == NULL)
1782 _DtHelpProcessUnlock();
1787 * follow all the symbolic links and get the absolute path and filename.
1789 volFile = _DtHelpCeTraceFilenamePath(volFile);
1790 if (volFile == NULL)
1792 _DtHelpProcessUnlock();
1796 /* Search the volume chain to see if it is already open. */
1799 while (vol != NULL && strcmp (vol->volFile, volFile))
1810 else /* if (vol == NULL) */
1812 /* If it isn't open, open it and insert it in the chain. */
1813 result = VolumeLoad (volFile, &vol);
1816 if (prevVol == NULL)
1819 prevVol->nextVol = vol;
1823 /* Return the volume handle and a status indicating success/failure. */
1824 *retVol = (_DtHelpVolumeHdl) vol;
1825 _DtHelpProcessUnlock();
1829 /******************************************************************************
1830 * Function: int _DtHelpCeUpVolumeOpenCnt (_DtHelpVolumeHdl vol);
1832 * Parameters: vol Specifies the loaded volume.
1834 * Return Value: 0 if successful, -1 if a failure occurs
1836 * errno Values: EINVAL 'vol' was NULL, no volumes open or
1837 * 'vol' does not exist.
1839 * Purpose: When the volume is no longer needed, it should be
1840 * closed with this call. If the volume has been opened
1841 * several times, closing it will just decrement the
1842 * reference count. When it has been closed as many times
1843 * as it was opened, the memory it is using will be freed
1844 * and any handles to the volume will be invalid.
1846 ******************************************************************************/
1848 _DtHelpCeUpVolumeOpenCnt (
1849 _DtHelpVolumeHdl volume)
1851 _DtHelpVolume prevVol;
1852 _DtHelpVolume vol = (_DtHelpVolume)volume;
1854 _DtHelpProcessLock();
1856 if (vol == NULL || volChain == NULL)
1859 _DtHelpProcessUnlock();
1864 * check to see if this volume is in our chain
1866 if (vol != volChain)
1868 if (CheckVolList (vol, &prevVol) == -1)
1871 _DtHelpProcessUnlock();
1877 * increment it's usage count.
1880 _DtHelpProcessUnlock();
1884 /******************************************************************************
1885 * Function: int _DtHelpCloseVolume (_DtHelpVolumeHdl vol);
1887 * Parameters: vol Specifies the loaded volume.
1889 * Return Value: 0 if successful, -1 if a failure occurs
1891 * errno Values: EINVAL 'vol' was NULL, no volumes open or
1892 * 'vol' does not exist.
1894 * Purpose: When the volume is no longer needed, it should be
1895 * closed with this call. If the volume has been opened
1896 * several times, closing it will just decrement the
1897 * reference count. When it has been closed as many times
1898 * as it was opened, the memory it is using will be freed
1899 * and any handles to the volume will be invalid.
1901 ******************************************************************************/
1903 _DtHelpCloseVolume (
1904 _DtHelpVolumeHdl volume)
1906 _DtHelpVolume prevVol;
1907 _DtHelpVolume vol = (_DtHelpVolume)volume;
1909 _DtHelpProcessLock();
1911 if (vol == NULL || volChain == NULL)
1914 _DtHelpProcessUnlock();
1919 * check to see if this volume is in our chain
1921 if (vol != volChain)
1923 if (CheckVolList (vol, &prevVol) == -1)
1926 _DtHelpProcessUnlock();
1932 * decrement it's usage count.
1935 if (vol->openCount == 0)
1937 /* The volume is no longer needed. Unlink it from the chain
1940 if (vol == volChain)
1941 volChain = volChain->nextVol;
1944 prevVol->nextVol = vol->nextVol;
1949 _DtHelpProcessUnlock();
1953 /*****************************************************************************
1954 * Function: int _DtHelpCeGetTopTopicId (_DtHelpVolume vol,
1955 * char **ret_idString)
1957 * Parameters: vol Specifies the loaded volume
1958 * ret_idString Returns the location ID of the
1959 * the top level topic.
1961 * Memory own by caller:
1964 * Returns: True for success, False if a failure occurs.
1966 * errno Values: EINVAL Specifies an invalid parameter was
1968 * CEErrorMissingTopTopicRes
1969 * Specifies that the 'TopTopic/topTopic'
1970 * resource is missing from the database.
1973 * Purpose: Get the information to access the top level topic.
1975 *****************************************************************************/
1977 _DtHelpCeGetTopTopicId (
1978 _DtHelpVolumeHdl volume,
1979 char **ret_idString )
1982 _DtHelpVolume vol = (_DtHelpVolume)volume;
1984 _DtHelpProcessLock();
1986 if (vol == NULL || ret_idString == NULL || CheckVolList(vol, NULL) == -1)
1991 * What type of volume is it?
1993 if (vol->sdl_flag == False)
1994 (void) _DtHelpCeGetCcdfTopTopic(vol, ret_idString);
1996 *ret_idString = _DtHelpCeGetSdlHomeTopicId((_DtHelpVolumeHdl) vol);
1998 if (*ret_idString != NULL)
1999 *ret_idString = strdup(*ret_idString);
2001 if (*ret_idString != NULL)
2005 _DtHelpProcessUnlock();
2008 } /* End _DtHelpCeGetTopTopicId */
2010 /*****************************************************************************
2011 * Function: int _DtHelpCeFindId (_DtHelpVolume vol, char *target_id,
2013 * char *ret_name, int *ret_offset)
2015 * Parameters: vol Specifies the loaded volume
2016 * target_id Specifies target location ID
2017 * fd Specifies the locked file descriptor.
2018 * ret_name Returns a null terminated string
2019 * containing a fully qualified path to
2020 * the file that contains 'target_id'.
2021 * ret_offset Returns the offset into 'ret_name'
2022 * to the topic that contains 'target_id'.
2024 * Memory own by caller:
2027 * Returns: True if successful, False if a failure occurs
2029 * errno Values: EINVAL Specifies an invalid parameter was
2032 * CEErrorMissingFilenameRes
2033 * Specifies that the 'Filename/filename'
2034 * resource for 'topic' does not exist.
2035 * CEErrorMissingFileposRes
2036 * If the resource is not in the
2037 * database or if the resource NULL.
2038 * CEErrorLocIdNotFound
2039 * Specifies that 'locId' was not
2042 * Purpose: Find which topic contains a specified locationID.
2044 *****************************************************************************/
2047 _DtHelpVolumeHdl volume,
2053 _DtHelpVolume vol = (_DtHelpVolume)volume;
2056 _DtHelpProcessLock();
2059 * check the parameters
2061 if (vol == NULL || target_id == NULL || ret_name == NULL ||
2062 ret_offset == NULL || CheckVolList (vol, NULL) == -1)
2065 _DtHelpProcessUnlock();
2070 * What type of volume is it?
2072 if (vol->sdl_flag == False)
2074 result = _DtHelpCeFindCcdfId(vol, target_id, ret_name, ret_offset);
2078 result = _DtHelpCeFindSdlId(vol, target_id, fd, ret_name, ret_offset);
2081 _DtHelpProcessUnlock();
2084 } /* End _DtHelpCeFindId */
2086 /*****************************************************************************
2087 * Function: int _DtHelpCeGetKeywordList (_DtHelpVolume vol, char ***ret_keywords)
2089 * Parameters: vol Specifies the loaded volume
2090 * ret_keywords Returns a NULL-terminated string array
2091 * containing the sorted list of keywords in the
2092 * volume. This array is NOT owned by the caller
2093 * and should only be read or copied.
2095 * Returns: The count of keywords associated with the volume if successful.
2096 * -1 if a failure occurs;
2098 * errno Values: EINVAL Specifies an invalid parameter was
2101 * CEErrorIllegalDatabaseFile
2102 * Specifies that the keyword file is
2103 * invalid or corrupt.
2104 * CEErrorMissingKeywordsRes
2105 * Specifies that the keyword file does
2106 * not contain the 'Keywords/keywords'
2107 * resource or the resource is NULL
2109 * Purpose: Get the list of keywords contained in a volume.
2111 *****************************************************************************/
2113 _DtHelpCeGetKeywordList (
2114 _DtHelpVolumeHdl volume,
2115 char ***ret_keywords )
2118 _DtHelpVolume vol = (_DtHelpVolume)volume;
2120 if (vol == NULL || ret_keywords == NULL || CheckVolList (vol, NULL) == -1)
2122 else if (GetVolumeKeywords (vol, ret_keywords) == 0)
2125 while (*ret_keywords && (*ret_keywords)[nameCount])
2131 } /* End _DtHelpCeGetKeywordList */
2133 /*****************************************************************************
2134 * Function: int _DtHelpCeFindKeyword (_DtHelpVolume vol, char *target, char ***ret_ids)
2136 * Parameters: vol Specifies the loaded volume
2137 * target The target keyword.
2138 * ret_ids Returns a null terminated list of location
2139 * ids associated with the target keyword.
2141 * Returns: The count of ids associated with the keyword if successful.
2142 * -1 if a failure occurs;
2144 * errno Values: EINVAL Specifies an invalid parameter was
2146 * CEErrorNoKeywordList
2147 * Specifies that the volume does not
2148 * have a keyword list.
2149 * CEErrorIllegalKeyword
2150 * Specifies that 'target' was not
2153 * CEErrorIllegalDatabaseFile
2154 * Specifies that the keyword file is
2155 * invalid or corrupt.
2156 * CEErrorMissingKeywordsRes
2157 * Specifies that the keyword file does
2158 * not contain the 'Keywords/keywords'
2159 * resource or the resource is NULL
2161 * Purpose: Get the list of location ids associated with a keyword
2163 *****************************************************************************/
2165 _DtHelpCeFindKeyword (
2166 _DtHelpVolumeHdl volume,
2171 _DtHelpVolume vol = (_DtHelpVolume)volume;
2173 if (vol == NULL || target == NULL || ret_ids == NULL ||
2174 CheckVolList (vol, NULL) == -1)
2176 else if (GetKeywordTopics (vol, target, ret_ids) == 0)
2179 while (*ret_ids && (*ret_ids)[nameCount])
2185 } /* End _DtHelpCeFindKeyword */
2187 /*****************************************************************************
2188 * Function: int _DtHelpGetTopicTitle (
2189 * _DtHelpVolumeHdl volume,
2190 * char *id, char **ret_title)
2192 * Parameters: volume Specifies the volume containing the id.
2193 * id Specifies the id for the topic desired.
2194 * ret_title Returns a null terminated string containing
2197 * Memory own by caller:
2200 * Returns: 0 if successful, -2 if didn't find the id,
2203 * errno Values: EINVAL Specifies an invalid parameter was
2206 * Purpose: Get the title of a topic.
2208 *****************************************************************************/
2210 _DtHelpGetTopicTitle (
2211 _DtHelpVolumeHdl volume,
2217 _DtHelpVolume vol = (_DtHelpVolume)volume;
2219 if (volume == NULL || id == NULL ||
2220 CheckVolList (vol, NULL) == -1 || ret_title == NULL)
2227 * Try to get the title via the <TOPIC> and <ABBREV> tags.
2229 result = GetTopicTitleAndAbbrev(vol, id, ret_title, &abbrevTitle);
2233 * If we have a abbreviated title, return it instead.
2238 free ((char *) *ret_title);
2239 *ret_title = abbrevTitle;
2245 } /* End _DtHelpGetTopicTitle */
2247 /*****************************************************************************
2248 * Function: int _DtHelpCeMapTargetToId (_DtHelpVolume vol,
2252 * Parameters: vol Specifies the loaded volume
2253 * target_id Specifies target location ID
2254 * ret_id Returns the id containing the target_id.
2255 * This memory *IS NOT* owned by the caller.
2257 * Returns: 0 if successful, -1 if a failure occurs
2259 * Purpose: Find which topic contains a specified locationID.
2261 *****************************************************************************/
2263 _DtHelpCeMapTargetToId (
2264 _DtHelpVolumeHdl volume,
2268 _DtHelpVolume vol = (_DtHelpVolume)volume;
2271 _DtHelpProcessLock();
2274 * check the parameters
2276 if (vol == NULL || target_id == NULL || ret_id == NULL ||
2277 CheckVolList (vol, NULL) == -1)
2280 _DtHelpProcessUnlock();
2285 * What type of volume is it?
2287 if (vol->sdl_flag == False)
2289 result = _DtHelpCeMapCcdfTargetToId(vol, target_id, ret_id);
2293 result = _DtHelpCeMapIdToSdlTopicId(vol, target_id, ret_id);
2296 _DtHelpProcessUnlock();
2299 } /* End _DtHelpCeMapTargetToId */
2301 /*****************************************************************************
2302 * Function: char * _DtHelpGetVolumeLocale (_DtHelpVolume vol)
2304 * Parameters: vol Specifies the loaded volume
2306 * Returns: The pointer to the locale string if successful. Otherwise
2309 * Purpose: Get the locale of the specified volume.
2310 * Returns the locale in a unix specific format
2311 * - locale[_ter][.charset] - This memory is owned by
2314 *****************************************************************************/
2316 _DtHelpGetVolumeLocale (
2317 _DtHelpVolumeHdl volume)
2319 _DtHelpVolume vol = (_DtHelpVolume)volume;
2322 _DtHelpProcessLock();
2325 * check the parameters
2327 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2330 _DtHelpProcessUnlock();
2335 * What type of volume is it?
2337 if (vol->sdl_flag == False)
2339 result = _DtHelpCeGetCcdfVolLocale(vol);
2343 result = _DtHelpCeGetSdlVolumeLocale(vol);
2346 _DtHelpProcessUnlock();
2349 } /* End _DtHelpGetVolumeLocale */
2351 /*****************************************************************************
2352 * Function: int _DtHelpCeGetDocStamp (_DtHelpVolumeHdl volume, char **ret_doc,
2355 * Parameters: volume Specifies the loaded volume
2356 * ret_doc Returns the doc id.
2357 * ret_time Returns the time stamp.
2359 * Memory: Caller owns the string in ret_doc and ret_time.
2361 * Returns: 0 if successful, -2 if the volume does not contain
2362 * one or the other, -1 if any other failure.
2364 * Purpose: Get doc id and time stamp of a volume.
2366 *****************************************************************************/
2368 _DtHelpCeGetDocStamp (
2369 _DtHelpVolumeHdl volume,
2373 _DtHelpVolume vol = (_DtHelpVolume)volume;
2376 _DtHelpProcessLock();
2379 * check the parameters
2381 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2384 _DtHelpProcessUnlock();
2389 * What type of volume is it?
2391 if (vol->sdl_flag == False)
2393 result = _DtHelpCeGetCcdfDocStamp (vol, ret_doc, ret_time);
2397 result = _DtHelpCeGetSdlDocStamp(vol, ret_doc, ret_time);
2400 _DtHelpProcessUnlock();
2403 } /* End _DtHelpCeGetDocStamp */
2405 /*****************************************************************************
2406 * Function: char * _DtHelpCeGetTopicChilren (_DtHelpVolumeHdl vol)
2408 * Parameters: vol Specifies the loaded volume
2409 * topic_id Speicifes the topic id of which the
2410 * children are to be found.
2411 * retTopics Returns the null terminated array of
2412 * ids. This memory is owned by the caller
2413 * and must be freed.
2415 * Returns: > 0 if successful, -1 if failures.
2417 * Purpose: Get the children of a topic.
2419 *****************************************************************************/
2421 _DtHelpCeGetTopicChildren (
2422 _DtHelpVolumeHdl volume,
2426 _DtHelpVolume vol = (_DtHelpVolume)volume;
2429 _DtHelpProcessLock();
2432 * check the parameters
2434 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2437 _DtHelpProcessUnlock();
2442 * What type of volume is it?
2444 if (vol->sdl_flag == False)
2446 result = _DtHelpCeGetCcdfTopicChildren(volume, topic_id, retTopics);
2450 result = _DtHelpCeGetSdlTopicChildren(volume, topic_id, retTopics);
2453 _DtHelpProcessUnlock();
2456 } /* End _DtHelpCeGetTopicChildren */
2458 /*****************************************************************************
2459 * Function: int _DtHelpCeGetVolumeFlag (_DtHelpVolumeHdl vol)
2461 * Parameters: vol Specifies the loaded volume
2463 * Returns: 0 if CCDF volume, 1 if SDL, -1 if failures.
2465 * Purpose: Determine the type of volume.
2467 *****************************************************************************/
2469 _DtHelpCeGetVolumeFlag (
2470 _DtHelpVolumeHdl volume)
2472 _DtHelpVolume vol = (_DtHelpVolume)volume;
2475 * check the parameters
2477 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2484 * What type of volume is it?
2486 return((int) vol->sdl_flag);
2488 } /* End _DtHelpCeGetVolumeFlag */
2490 /*****************************************************************************
2491 * Function: int _DtHelpCeLockVolume (_DtHelpVolumeHdl vol)
2493 * Parameters: vol Specifies the loaded volume
2495 * Returns: > 0 if successful, -1 if failures.
2497 * Purpose: Lock the volume so that it can't get change out from
2500 *****************************************************************************/
2502 _DtHelpCeLockVolume (
2503 _DtHelpVolumeHdl volume,
2504 _DtHelpCeLockInfo *lock_info)
2507 _DtHelpVolume vol = (_DtHelpVolume)volume;
2509 _DtHelpProcessLock();
2512 * check the parameters
2514 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2516 _DtHelpProcessUnlock();
2521 * lock it by opening it.
2523 lock_info->fd = open(vol->volFile, O_RDONLY);
2524 if (lock_info->fd == -1)
2526 _DtHelpProcessUnlock();
2530 (void) fstat(lock_info->fd, &buf);
2531 if (buf.st_mtime != vol->check_time)
2533 if (RereadVolume(vol) != 0)
2535 close(lock_info->fd);
2536 _DtHelpProcessUnlock();
2540 vol->check_time = buf.st_mtime;
2547 lock_info->volume = volume;
2548 _DtHelpProcessUnlock();
2551 } /* End _DtHelpCeLockVolume */
2553 /*****************************************************************************
2554 * Function: int _DtHelpCeUnlockVolume (_DtHelpVolumeHdl vol)
2556 * Parameters: vol Specifies the loaded volume
2558 * Returns: > 0 if successful, -1 if failures.
2560 * Purpose: Unlock the volume.
2562 *****************************************************************************/
2564 _DtHelpCeUnlockVolume (
2565 _DtHelpCeLockInfo lock_info)
2567 _DtHelpVolume vol = (_DtHelpVolume)(lock_info.volume);
2569 _DtHelpProcessLock();
2572 * check the parameters
2574 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2576 _DtHelpProcessUnlock();
2581 * check to see if it needs to be unlocked.
2583 if (lock_info.fd != -1)
2584 close(lock_info.fd);
2590 _DtHelpProcessUnlock();
2593 } /* End _DtHelpCeUnlockVolume */
2595 /*****************************************************************************
2596 * Function: int _DtHelpCeIsTopTopic (_DtHelpVolumeHdl volume, const char *id)
2598 * Parameters: vol Specifies the loaded volume
2599 * id Specifies a location id.
2601 * Returns: = 0 if successful, != 0 if failures.
2603 * Purpose: Tests to see if the location id is in the top topic of
2606 *****************************************************************************/
2608 _DtHelpCeIsTopTopic (
2609 _DtHelpVolumeHdl volume,
2613 char *topicId = NULL;
2615 _DtHelpVolume vol = (_DtHelpVolume) volume;
2617 _DtHelpProcessLock();
2619 * check the parameters
2621 if (vol == NULL || CheckVolList (vol, NULL) == -1)
2623 _DtHelpProcessUnlock();
2628 * What type of volume is it?
2630 if (vol->sdl_flag == False)
2632 if (_DtHelpCeMapCcdfTargetToId(vol, id, &topicId) == 0 &&
2633 _DtHelpCeGetCcdfTopTopic(vol, &topId) == 0)
2634 result = _DtHelpCeStrCaseCmpLatin1(topId, topicId);
2636 else if (_DtHelpCeMapIdToSdlTopicId(vol, id, &topicId) == 0)
2638 topId = _DtHelpCeGetSdlHomeTopicId(volume);
2640 result = _DtHelpCeStrCaseCmpLatin1(topId, topicId);
2643 _DtHelpProcessUnlock();
2646 } /* End _DtHelpCeIsTopTopic */