/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: Access.c /main/11 1996/11/01 10:09:29 drk $ */ /************************************<+>************************************* **************************************************************************** ** ** File: Access.c ** ** Project: Run Time Project File Access ** ** Description: This body of code handles the access routines for the ** Display Area. ** ** ** (c) Copyright 1987-1994, 1996 Hewlett-Packard Company ** (c) Copyright 1993, 1994, 1996 International Business Machines Corp. ** (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. ** (c) Copyright 1993, 1994, 1996 Novell, Inc. ** (c) Copyright 1996 Digital Equipment Corporation. ** (c) Copyright 1996 FUJITSU LIMITED. ** (c) Copyright 1996 Hitachi. ** ** **************************************************************************** ************************************<+>*************************************/ /* * system includes */ #include #include #include #include #include #include #include #include #include #include #include #ifdef X_NOT_STDC_ENV extern int errno; #endif /* * Canvas Engine includes */ #include "CanvasP.h" #include "CanvasSegP.h" /* * private includes */ #include "CanvasError.h" #include "Access.h" #include "bufioI.h" #include "FontAttrI.h" #include "AccessP.h" #include "AccessI.h" #include "AccessSDLP.h" #include "AccessSDLI.h" #include "AccessCCDFI.h" #include "FormatUtilI.h" #include "SDLI.h" #include "FormatSDLI.h" #include "CCDFUtilI.h" #include "StringFuncsI.h" #include "Lock.h" /* Process and App Lock macros */ #ifdef NLS16 #endif /******** Private Defines ********/ #define LIST_INCREMENT 10 #define BUFF_SIZE 256 /******** End Private Defines ********/ /******** Private Function Declarations ********/ static int GetVolumeKeywords ( _DtHelpVolume vol, char ***retKeywords); static int VolumeLoad ( char *volFile, _DtHelpVolume *retVol); static int VolumeUnload ( _DtHelpVolume vol); /******** End Private Function Declarations ********/ /******** Private Macro Declarations ********/ /******** End Private Macro Declarations ********/ /****************************************************************************** * * Private variables used within this file. * *******************************************************************************/ static _DtHelpVolume volChain = NULL; /* Pointer to the head of the chain */ /* of all the open volumes. */ static const char *Slash = "/"; static const char *Period = "."; /****************************************************************************** * Private Functions ******************************************************************************/ /****************************************************************************** * Function: CheckVolList (_DtHelpVolume vol, _DtHelpVolume *ret_prev) * * Parameters: vol Specifies the volume to search for. * ret_prev Returns the volume whose nextVol element * points to 'vol' if non NULL. * * Returns: 0 if successful, -1 if failure. * * errno Values: * * Purpose: To check for the existence of a volume. * ******************************************************************************/ static int CheckVolList ( _DtHelpVolume vol, _DtHelpVolume *ret_prev ) { _DtHelpVolume myVol; _DtHelpVolume prevVol = NULL; _DtHelpProcessLock(); myVol = volChain; while (myVol != NULL && myVol != vol) { prevVol = myVol; myVol = myVol->nextVol; } if (ret_prev) *ret_prev = prevVol; if (myVol != vol) { _DtHelpProcessUnlock(); return -1; } _DtHelpProcessUnlock(); return 0; } /****************************************************************************** * Function: int VolumeLoad (char *volFile, _DtHelpVolume *retVol); * * Parameters: volFile Specifies the name of the Help Volume file * to load. * * retVol Returns the handle to the loaded volume. * * Return Value: Returns 0 if successful, * -1 if an error occurred. * * errno Values: CEErrorMalloc * CEErrorIllegalDatabaseFile * * Purpose: This function must be called to load a Help Volume file * before any of the information in the volume can be * accessed. * ******************************************************************************/ static int VolumeLoad ( char *volFile, _DtHelpVolume *retVol) { /* Allocate the volume structure and initialize it. */ *retVol = (_DtHelpVolume) malloc (sizeof (struct _DtHelpVolumeRec)); if (*retVol) { (*retVol)->sdl_flag = False; (*retVol)->volFile = volFile; (*retVol)->keywords = NULL; (*retVol)->keywordTopics = NULL; (*retVol)->openCount = 1; (*retVol)->nextVol = NULL; (*retVol)->vols.ccdf_vol = NULL; if (_DtHelpCeOpenSdlVolume ((*retVol)) == 0) return 0; else if (_DtHelpCeOpenCcdfVolume(*retVol) == 0) return 0; /* * Set the global error */ errno = CEErrorIllegalDatabaseFile; /* * error on loading the database. */ free ((char *) ((*retVol)->volFile)); free ((char *) (*retVol)); *retVol = NULL; } else errno = CEErrorMalloc; return -1; } /* End VolumeLoad */ /******************************************************************************* * Function: int VolumeUnload (_DtHelpVolume vol); * * Parameters: vol Specifies the loaded volume. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: None * * Purpose: When the volume is no longer needed, it should be unloaded * with this call. Unloading it frees the memory (which means * any handles on the volume become invalid.) * ******************************************************************************/ static int VolumeUnload ( _DtHelpVolume vol) { char ***topicList; if (vol != NULL) { if (vol->sdl_flag == True) _DtHelpCeCloseSdlVolume((_DtHelpVolumeHdl) vol); else _DtHelpCeCloseCcdfVolume(vol); if (vol->volFile != NULL) free (vol->volFile); if (vol->keywords != NULL) _DtHelpCeFreeStringArray (vol->keywords); if (vol->keywordTopics != NULL) { for (topicList = vol->keywordTopics; *topicList != NULL; topicList++) _DtHelpCeFreeStringArray (*topicList); free (vol->keywordTopics); } free (vol); } return (0); } /******************************************************************************* * Function: int RereadVolume (_DtHelpVolume vol); * * Parameters: vol Specifies the loaded volume. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: None * * Purpose: When the volume is no longer needed, it should be unloaded * with this call. Unloading it frees the memory (which means * any handles on the volume become invalid.) * ******************************************************************************/ static int RereadVolume ( _DtHelpVolume vol) { int result; char ***topicList; if (vol->keywords != NULL) { _DtHelpCeFreeStringArray (vol->keywords); vol->keywords = NULL; } if (vol->keywordTopics != NULL) { for (topicList = vol->keywordTopics; *topicList != NULL; topicList++) _DtHelpCeFreeStringArray (*topicList); free (vol->keywordTopics); vol->keywordTopics = NULL; } if (vol->sdl_flag == False) result = _DtHelpCeRereadCcdfVolume(vol); else result = _DtHelpCeRereadSdlVolume(vol); return (result); } /****************************************************************************** * Function: static int GetKeywordTopics (_DtHelpVolume vol, char *keyword, * char ***topics); * * Parameters: vol Specifies the loaded volume * keyword Specifies the keyword whose location is desired. * topics Returns a NULL-terminated string array of the * list of topics which contain the keyword. * This array is NOT owned by the caller and * should only be read or copied. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: CEErrorNoKeywordList * Specifies that the volume does not * have a keyword list. * CEErrorIllegalKeyword * Specifies that 'keyword' was not * found. * CEErrorMalloc * CEErrorIllegalDatabaseFile * Specifies that the keyword file is * invalid or corrupt. * CEErrorMissingKeywordsRes * Specifies that the keyword file does * not contain the 'Keywords/keywords' * resource or the resource is NULL * * * Purpose: Find which topic contains a specified locationId. * ******************************************************************************/ static int GetKeywordTopics ( _DtHelpVolume vol, char *keyword, char ***retTopics) { char **keywords; char **nextKey; int index; _DtHelpProcessLock(); *retTopics = NULL; /* Get the list of keywords. */ if (GetVolumeKeywords (vol, &keywords) != 0) { _DtHelpProcessUnlock(); return -1; } if (keywords == NULL || vol->keywordTopics == NULL) { errno = CEErrorNoKeywordList; _DtHelpProcessUnlock(); return -1; } /* Search the list of keywords for the current one. */ nextKey = keywords; while (*nextKey != NULL && strcmp (*nextKey, keyword)) nextKey++; if (*nextKey == NULL) { errno = CEErrorIllegalKeyword; _DtHelpProcessUnlock(); return -1; } index = nextKey - keywords; *retTopics = *(vol->keywordTopics + index); _DtHelpProcessUnlock(); return (0); } /****************************************************************************** * Function: static int GetVolumeKeywords(_DtHelpVolume vol,char ***keywords); * * Parameters: vol Specifies the volume. * keywords Returns a NULL-terminated string array * containing the sorted list of keywords in the * volume. This array is NOT owned by the caller * and should only be read or copied. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: CEErrorMalloc * CEErrorIllegalDatabaseFile * Specifies that the keyword file is * invalid or corrupt. * CEErrorMissingKeywordsRes * Specifies that the keyword file does * not contain the 'Keywords/keywords' * resource or the resource is NULL * * Purpose: Get the list of keywords defined in a volume. * ******************************************************************************/ static int GetVolumeKeywords ( _DtHelpVolume vol, char ***retKeywords) { int result; _DtHelpCeLockInfo lockInfo; _DtHelpProcessLock(); /* Keywords aren't loaded until they are needed, so see if they have been loaded yet. */ if (vol->keywords == NULL) { /* * What type of volume is it? */ if (_DtHelpCeLockVolume(vol, &lockInfo) != 0) { _DtHelpProcessUnlock(); return -1; } if (vol->sdl_flag == False) result = _DtHelpCeGetCcdfKeywordList(vol); else result = _DtHelpCeGetSdlKeywordList(vol); _DtHelpCeUnlockVolume(lockInfo); if (result != 0) { _DtHelpProcessUnlock(); return -1; } } /* All of the keyword processing is done when they are loaded. */ *retKeywords = vol->keywords; if (*retKeywords == NULL) { _DtHelpProcessUnlock(); return (-1); } _DtHelpProcessUnlock(); return (0); } /***************************************************************************** * Function: GetTopicTitleAndAbbrev ( * * Parameters: * * Memory own by caller: * ret_name * ret_abrrev * * Returns: 0 if successful, -2 if didn't find the id, * -3 if couldn't format the topic, * otherwise -1. * * Purpose: Find the title and abbreviated title of a topic. * *****************************************************************************/ static int GetTopicTitleAndAbbrev ( _DtHelpVolume volume, char *id, char **ret_name, char **ret_abbrev ) { int result = 0; int offset; char buffer[BUFF_SIZE]; char *bufPtr; char *filename = NULL; BufFilePtr file; _DtHelpCeLockInfo lockInfo; if (_DtHelpCeLockVolume(volume, &lockInfo) != 0) return -1; if (_DtHelpCeFindId(volume, id, lockInfo.fd, &filename, &offset) != True) result = -2; /* * What type of volume is it? */ if (result == 0) { if (0 == _DtHelpCeGetVolumeFlag(volume)) { result = _DtHelpCeFileOpenAndSeek(filename,offset,-1,&file,NULL); if (result == 0) { result = -1; if (_DtHelpCeReadBuf (file, buffer, BUFF_SIZE) != -1) { result = 0; bufPtr = buffer; if (_DtHelpCeGetCcdfTopicAbbrev (NULL, file, buffer, &bufPtr, BUFF_SIZE, MB_CUR_MAX, ret_name, NULL, ret_abbrev) != 0) result = -3; } _DtHelpCeBufFileClose(file, True); } } else { _DtHelpProcessLock(); if (_DtHelpCeFrmtSDLTitleToAscii(volume, offset, ret_name, ret_abbrev) != 0) result = -3; _DtHelpProcessUnlock(); } } if (filename != NULL) free(filename); _DtHelpCeUnlockVolume(lockInfo); return result; } /***************************************************************************** * Function: static int FileOpenRtnFd (char *name, int *ret_fd) * * Parameters: name Specifies the file to open. * ret_fd Returns the fd of the opened file. * * Returns: 0 if required uncompress. * file descriptor to remove the file from the system. * 1 if no uncompression required. * -1 if a failure occurs * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorFileSeek * Specifies the seek offset was invalid. * * Purpose: Find out if a file is compressed and uncompress it if it is. * *****************************************************************************/ static int FileOpenRtnFd ( char *name, int *ret_fd ) { char *inFile = NULL; char tmpName[MAXPATHLEN + 1]; int result = 1; /* * check to see if the file exists in uncompressed form */ *ret_fd = open(name, O_RDONLY); if (*ret_fd == -1) { /* * get a temporary name */ (void) tmpnam (tmpName); /* * malloc memory for the dot Z file name. */ inFile = (char *) malloc (strlen (name) + 3); if (inFile != NULL) { /* * make the dot Z file */ strcpy (inFile, name); strcat (inFile, ".Z"); /* * do the uncompress */ result = _DtHelpCeUncompressFile (inFile, tmpName); free (inFile); if (result != 0) { errno = ENOENT; return -1; } /* * now open the uncompressed file */ *ret_fd = open(tmpName, O_RDONLY); if (*ret_fd == -1) result = -1; else unlink(tmpName); } else { errno = CEErrorMalloc; return -1; } } return result; } /* End FileOpenRtnFd */ /****************************************************************************** * Semi-Public Functions ******************************************************************************/ /***************************************************************************** * Function: char *_DtHelpCeExpandPathname (char *spec, char *filename, char *type, * char *suffix, char *lang, _DtSubstitutionRec *subs, int num) * * Parameters: * spec Specifies a string with substitution * characters. * containing the character set if found. * filename Specifies the string to substitute for %N. * type Specifies the string to substitute for %T. * suffix Specifies the string to substitute for %S. * lang Specifies the string to substitute for %L. * subs Specifies the application own specific * substitutions. * num Specifies the number of substitution pairs * in 'subs'. * * Memory own by caller: * returned pointer * * Returns: The expanded filename if successful. NULL if errors. * * Purpose: Expand a string with % substitution values. * Default substitutions are: * %N replaced with 'filename'. * %T replaced with 'type' * %S replaced with 'suffix' * %L replaced with 'lang' * * %l replaced with the language sub part of 'lang'. * %t replaced with the territory sub part of 'lang'. * %c replaced with the code set sub part of 'lang'. * Other substitutions can be done via the 'subs' parameter. * *****************************************************************************/ char * _DtHelpCeExpandPathname ( char *spec, char *filename, char *type, char *suffix, char *lang, _DtSubstitutionRec *subs, int num ) { int i; int len = 1; char *ptr; char *subString; char *partLang; char *partTer; char *partCodeSet; char pathName [MAXPATHLEN + 5]; Boolean previousSlash = False; #define MY_NUM 7 _DtSubstitutionRec mySubs [MY_NUM]; if (spec == NULL || *spec == '\0') { errno = EINVAL; return NULL; } /* * fill in the language sub parts */ if (_DtHelpCeGetLangSubParts (lang, &partLang, &partTer, &partCodeSet)) return NULL; mySubs[0].match = 'N'; mySubs[0].substitution = filename; mySubs[1].match = 'T'; mySubs[1].substitution = type; mySubs[2].match = 'S'; mySubs[2].substitution = suffix; mySubs[3].match = 'L'; mySubs[3].substitution = lang; mySubs[4].match = 'l'; mySubs[4].substitution = partLang; mySubs[5].match = 't'; mySubs[5].substitution = partTer; mySubs[6].match = 's'; mySubs[6].substitution = partCodeSet; ptr = pathName; while (*spec) { len = 1; if (MB_CUR_MAX != 1) len = mblen (spec, MB_CUR_MAX); if (len == 1 && *spec == '/') { if (previousSlash) spec++; else { previousSlash = True; *ptr++ = *spec++; } } else if (len == 1 && *spec == '%') { spec++; switch (*spec) { case '\0': *ptr++ = '%'; break; case '/': if (!previousSlash) { previousSlash = True; *ptr++ = *spec; } spec++; break; default: i = 0; while (i < MY_NUM && mySubs && mySubs[i].match != *spec) i++; if (i < MY_NUM) { if (mySubs[i].substitution != NULL) { subString = mySubs[i].substitution; if (((int)(ptr - pathName + strlen(subString))) > MAXPATHLEN) { errno = CEErrorExceedMaxSize; return NULL; } while (subString && *subString) *ptr++ = *subString++; } } else { i = 0; while (i < num && subs && subs[i].match != *spec) i++; /* * If the substitution character is not found * include the character onto the final string. */ if (i >= num) *ptr++ = *spec; else if (subs[i].substitution != NULL) { subString = subs[i].substitution; if (((int)(ptr - pathName + strlen(subString))) > MAXPATHLEN) { errno = CEErrorExceedMaxSize; return NULL; } while (subString && *subString) *ptr++ = *subString++; } } spec++; previousSlash = False; break; } } else { previousSlash = False; do { *ptr++ = *spec++; len--; } while (len > 0); } if (ptr - pathName > MAXPATHLEN) { errno = CEErrorExceedMaxSize; return NULL; } } if (partLang) free (partLang); if (partTer) free (partTer); if (partCodeSet) free (partCodeSet); *ptr = '\0'; ptr = strdup (pathName); if (ptr == NULL) errno = CEErrorMalloc; return ptr; } /***************************************************************************** * Function: char *_DtHelpCeGetLangSubParts (char *lang, char **subLang, * char **subTer, char **subCodeSet) * * Parameters: * lang Specifies the language string. * subLang Returns the language sub part of 'lang' * or NULL. * subTer Returns the territory sub part of 'lang' * or NULL. * subCodeSet Returns the code set sub part of 'lang' * or NULL. * * Memory own by caller: * subLang * subTer * subCodeSet * * errno Values: * EINVAL * CEErrorMalloc * * Returns: 0 if successful, -1 if errors. * * Purpose: Break a %l_%t.%c language specification into its sub parts. * *****************************************************************************/ int _DtHelpCeGetLangSubParts ( char *lang, char **subLang, char **subTer, char **subCodeSet ) { int len; char *ptr; char *sLang = NULL; char *sTer = NULL; char *sCode = NULL; if (subLang == NULL || subTer == NULL || subCodeSet == NULL) { errno = EINVAL; return -1; } if (lang != NULL && *lang != '\0') { /* * look for lang_ter */ _DtHelpCeStrchr (lang, "_", MB_CUR_MAX, &ptr); if (ptr) { /* * do we want this string? */ if (subLang != NULL) { len = ptr - lang; sLang = (char *) malloc (len + 1); if (sLang != NULL) { strncpy (sLang, lang, len); sLang[len] = '\0'; } else { errno = CEErrorMalloc; return -1; } } /* * just mark that the lang part was found */ else sLang = lang; lang = ptr + 1; } /* * look for lang.codeset */ _DtHelpCeStrchr (lang, Period, MB_CUR_MAX, &ptr); if (ptr) { len = ptr - lang; /* * if it was in the form lang_ter.codeset, sLang will non-null */ if (sLang != NULL) { /* * do we want to save the territory? */ if (subTer != NULL) { sTer = (char *) malloc (len + 1); if (sTer != NULL) { strncpy (sTer, lang, len); sTer[len] = '\0'; } else { errno = CEErrorMalloc; return -1; } } /* * don't wan to save, but make sure we mark the territory * as being found (non-null). */ else sTer = lang; } /* * the lang was in the form lang.codeset. * now check to see if want to save the lang portion. */ else if (subLang != NULL) { sLang = (char *) malloc (len + 1); if (sLang != NULL) { strncpy (sLang, lang, len); sLang[len] = '\0'; } else { errno = CEErrorMalloc; return -1; } } /* * didn't want to save the lang portion, but mark as found. */ else sLang = lang; } /* * currently pointing at the dot? */ if (ptr && *ptr == '.') { /* * yes save the code set */ ptr++; if (subCodeSet != NULL) { sCode = strdup (ptr); if (sCode == NULL) { errno = CEErrorMalloc; return -1; } } /* * don't save the code set, but make sure we mark as found */ else sCode = ptr; } /* * didn't find a code set, so save the current info. * If we haven't already processed a lang portion, save as the * lang. */ else if (sLang == NULL) { if (subLang != NULL) { sLang = strdup (lang); if (sLang == NULL) { errno = CEErrorMalloc; return -1; } } else sLang = lang; } /* * otherwise this is the territory of the language. Save if desired */ else if (subTer != NULL) { sTer = strdup (lang); if (sTer == NULL) { errno = CEErrorMalloc; return -1; } } } if (subLang) *subLang = sLang; if (subTer) *subTer = sTer; if (subCodeSet) *subCodeSet = sCode; return 0; } /***************************************************************************** * Function: int _DtHelpCeGetUncompressedFileName (char *name, char **ret_name) * * Parameters: name Specifies the file to open. * ret_name Returns the name of the uncompressed file. * This memory must be freed by the caller. * * Returns: 0 if required uncompress. ret_name will contain the * name of the uncompressed file. The caller is required * to free the memory. * 1 if no uncompression required. ret_name points to name. * -1 if a failure occurs * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorFileSeek * Specifies the seek offset was invalid. * * Purpose: Find out if a file is compressed and uncompress it if it is. * *****************************************************************************/ int _DtHelpCeGetUncompressedFileName ( char *name, char **ret_name ) { char *inFile = NULL; char tmpName[MAXPATHLEN + 1]; int result = 1; /* * check to see if the file exists in uncompressed form */ *ret_name = name; if (access (name, F_OK) == -1) { /* * get a temporary name */ (void) tmpnam (tmpName); /* * malloc memory for the dot Z file name. */ inFile = (char *) malloc (strlen (name) + 3); if (inFile != NULL) { /* * make the dot Z file */ strcpy (inFile, name); strcat (inFile, ".Z"); /* * do the uncompress */ result = _DtHelpCeUncompressFile (inFile, tmpName); free (inFile); if (result != 0) { errno = ENOENT; return -1; } *ret_name = strdup (tmpName); if (*ret_name == NULL) { errno = CEErrorMalloc; return -1; } } else { errno = CEErrorMalloc; return -1; } } return result; } /****************************************************************************** * Function: int _DtHelpCeCompressPathname (char *basePath) * * Parameters: basePath Specifies the path for the file possibily * containing /./, //, and /../. * * Return Value: 0 for success, -1 for failure. * The number of bytes in basePath will be less than or * equal to the number of bytes in basePath when passed * in. * * errno Values: EINVAL * * Purpose: This function compresses directory changes found * in a file name path. * ******************************************************************************/ int _DtHelpCeCompressPathname ( char *basePath ) { int len; int result; short char1; short char2; short char3; char *ptr = basePath; char *prevPtr = NULL; if (basePath == NULL || *basePath != '/') { errno = EINVAL; return -1; } do { /* * for multi-byte environments, check how far single bytes extend. */ char1 = False; char2 = False; char3 = False; if (MB_CUR_MAX == 1 || mblen (&ptr[1], MB_CUR_MAX) == 1) { char1 = True; if (MB_CUR_MAX == 1 || mblen (&ptr[2], MB_CUR_MAX) == 1) { char2 = True; if (MB_CUR_MAX == 1 || mblen (&ptr[3], MB_CUR_MAX) == 1) char3 = True; } } /* * check for // */ if (char1 == True && ptr[1] == '/') strcpy (ptr, (ptr + 1)); /* * check for /./ */ else if (char2 == True && ptr[1] == '.' && ptr[2] == '/') strcpy (ptr, (ptr + 2)); /* * check for /../ */ else if (char3 == True && strncmp (&ptr[1], "../", 3) == 0) { /* * if at the top of the path, just ignore the extra * directory change. */ if (prevPtr == NULL) strcpy (ptr, (ptr + 3)); else { /* * compress the /../ */ strcpy (prevPtr, (ptr + 3)); /* * reset the current pointer */ ptr = prevPtr; /* * find the previous slash */ *ptr = '\0'; result = _DtHelpCeStrrchr(basePath,Slash,MB_CUR_MAX,&prevPtr); if (result == -1) return -1; /* * if there is no previous slash, set the pointer to * indicate that we're at the top of the path (NULL). */ if (result != 0) prevPtr = NULL; /* * restore the slash (or null byte) */ *ptr = '/'; } } else { /* * remember this slash for /../ directory changes */ prevPtr = ptr; /* * skip this slash, and find the next one. */ ptr++; result = _DtHelpCeStrcspn (ptr, "/", MB_CUR_MAX, &len); /* * if we run into invalid data, error */ if (result == -1) return -1; ptr += len; } } while (*ptr != '\0'); return (0); } /****************************************************************************** * Function: char *_DtHelpCeTracePathName (char *path) * * Parameters: * path Specifies the a path to trace and compress * * Return Value: The new string if successful, NULL otherwise. * The new string is owned by the caller and contains * an absolute pathname. * * errno Values: EINVAL Illegal parameter specified. * getcwd(2) errno set via a getcwd call. * readlink(2) errno set via a readlink call. * DtErrorMalloc * DtErrorExceedMaxSize The new path will exceed * max_size. * DtErrorIllegalPath The compression will required * the path to change to a parent * directory beyond the beginning * of basePath. * * Purpose: This function is called to trace the path of a file. * It can contain symbolic links, //, /./, and /../. * ******************************************************************************/ char * _DtHelpCeTracePathName (char *path) { int result; int len; char c; char *ptr; char *prev; char newPath [2 * MAXPATHLEN + 2]; char linkPath [MAXPATHLEN + 2]; char tempPath [MAXPATHLEN + 2]; if (path == NULL || *path == '\0') { errno = EINVAL; return NULL; } /* * initialize the new path */ newPath[0] = '\0'; /* * if the path passed in does not start with a slash, * get the current working directory and append the path to it. */ if ((MB_CUR_MAX == 1 || mblen(path, MB_CUR_MAX) == 1) && *path != '/') { if (getcwd (newPath, MAXPATHLEN) == NULL) return NULL; strcat (newPath, "/"); } /* * put the path in the working path buffer (or append it to * the current working directory). */ strcat (newPath, path); /* * Compress out the slashes and directory changes. */ if (_DtHelpCeCompressPathname (newPath) != 0) return NULL; ptr = newPath; do { /* * point to the first character of the next directory */ prev = ptr + 1; /* * get the next slash after that */ result = _DtHelpCeStrcspn (prev, "/", MB_CUR_MAX, &len); if (result == -1) return NULL; /* * Found either a slash or a null byte. * place the string terminator at this point */ ptr = prev + len; c = *ptr; *ptr = '\0'; /* * find out if this path is a symbolic link */ result = readlink (newPath, linkPath, MAXPATHLEN); /* * replace the slash (or null byte). */ *ptr = c; /* * check for the result of the readlink call */ if (result == -1) { /* * if this was NOT a symbolic link, errno should be EINVAL */ if (errno != EINVAL) return NULL; } else { /* * put the null byte on the end of the symbolic link string. */ linkPath [result] = '\0'; /* * Save the rest of the string that we haven't processed * for tacking on after the new link path has been * dropped into the path. */ snprintf(tempPath, sizeof(tempPath), "%s", ptr); /* * is it an absolute path? Simply replace the path * being search with the new link path. */ if (*linkPath == '/') strcpy (newPath, linkPath); else { /* * this is a relative link. * prev is looking at the first character of this directory. * replace with the link. */ strcpy (prev, linkPath); } /* * now tack on the rest of the name */ strcat (newPath, tempPath); /* * compress out the directory changes. */ if (_DtHelpCeCompressPathname (newPath) != 0) return NULL; /* * start again from the top, until we have a clean path */ ptr = newPath; } } while (*ptr != '\0'); return (strdup (newPath)); } /****************************************************************************** * Function: char *_DtHelpCeTraceFilenamePath (char *file_path) * * Parameters: * file_path Specifies the a path to trace and compress * * Return Value: The new string if successful, NULL otherwise. * The new string is owned by the caller and * contains an absolute filename path. * * errno Values: EINVAL Illegal parameter specified. * getcwd(2) errno set via a getcwd call. * readlink(2) errno set via a readlink call. * DtErrorMalloc * DtErrorExceedMaxSize The new path will exceed * max_size. * DtErrorIllegalPath The compression will required * the path to change to a parent * directory beyond the beginning * of basePath. * * Purpose: This function is called to trace a filename path. * It can contain symbolic links, //, /./, and /../. * ******************************************************************************/ char * _DtHelpCeTraceFilenamePath (char *file_path) { int result; int done = False; char *newPath; char *oldName; char *namePlace; char workName [MAXPATHLEN + 2]; char newName [MAXPATHLEN + 2]; char linkName [MAXPATHLEN + 2]; if (file_path == NULL || *file_path == '\0') { errno = EINVAL; return NULL; } workName[0] = '\0'; if ((MB_CUR_MAX == 1 || mblen(file_path, MB_CUR_MAX) == 1) && *file_path != '/') { if (getcwd(workName, MAXPATHLEN) == NULL) return NULL; strcat(workName, "/"); } strcat (workName, file_path); do { /* * find and save the old filename */ result = _DtHelpCeStrrchr(workName, Slash, MB_CUR_MAX, &oldName); if (result == -1) return NULL; /* * terminate the path */ *oldName = '\0'; /* * trace the path, resolving the symbolic links * and directory changes. If /filename given, * skip the path tracing. */ newName[0] = '\0'; if (workName[0] != '\0') { newPath = _DtHelpCeTracePathName(workName); if (newPath == NULL) return NULL; /* * copy the new path and free the allocated copy */ snprintf(newName, sizeof(newName), "%s", newPath); free (newPath); } /* * replace the slash */ *oldName = '/'; /* * now append the slash and filename (pointed to by oldName) * onto the end of the new path. */ namePlace = newName + strlen (newName); strcpy (namePlace, oldName); /* * See if the absolute path/filename is a symbolic link. */ result = readlink (newName, linkName, MAXPATHLEN); if (result == -1) { if (errno != EINVAL) return NULL; done = True; } else { /* * put the null byte on the end of the symbolic * link string. */ linkName [result] = '\0'; if (*linkName == '/') strcpy (newName, linkName); else { /* * overwrite the filename with the link * but don't overwrite the slash. */ strcpy ((namePlace + 1), linkName); } /* * make a copy of the new name to work on */ strcpy (workName, newName); } } while (!done); return (strdup (newName)); } /****************************************************************************** * Core Engine Semi-Public Functions ******************************************************************************/ /***************************************************************************** * Function: char *_DtHelpCeGetVolumeName (_DtHelpVolumeHdl volume) * * Parameters: * * Returns: ptr to the name of the volume, NULL otherwise. * * Purpose: Get the fully qualified volume name. * *****************************************************************************/ char * _DtHelpCeGetVolumeName ( _DtHelpVolumeHdl volume_handle) { char *volFile; _DtHelpProcessLock(); volFile = ((_DtHelpVolume)volume_handle)->volFile; _DtHelpProcessUnlock(); return volFile; } /* End __DtHelpCeGetVolumeName */ /***************************************************************************** * Function: int _DtHelpCeFileOpenAndSeek (char *name, int offset, int fildes, * BufFilePtr *ret_file) * * Parameters: name Specifies the file to open. * offset Specifies location within the file to seek to. * * Returns: 0 if successful, -1 if a failure occurs * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorFileSeek * Specifies the seek offset was invalid. * * Purpose: Open a file and seek to a specific place. * *****************************************************************************/ int _DtHelpCeFileOpenAndSeek ( char *name, int offset, int fd, BufFilePtr *ret_file, time_t *ret_time) { unsigned char fileMagic[4]; int bytesRead; int result = 0; int tmpFd; struct stat buf; /* * Get the file descriptor of the uncompressed file */ tmpFd = fd; if (fd == -1) { result = FileOpenRtnFd (name, &tmpFd); if (result == -1) return -1; } if (ret_time != NULL) { (void) fstat(tmpFd, &buf); *ret_time = buf.st_mtime; } /* * make sure we don't go past the end of the file */ result = lseek (tmpFd, 0, SEEK_END); if (result != -1) { if (result > offset) result = lseek (tmpFd, offset, SEEK_SET); else { result = -1; errno = CEErrorFileSeek; } } if (result == -1) { if (fd == -1) close (tmpFd); return -1; } bytesRead = read(tmpFd, fileMagic, 4); if (bytesRead != 4) { /* something's wrong in reading the file */ if (fd == -1) close (tmpFd); return -1; } if (!*fileMagic) { /* started with compressed file magic number */ CECompressInfoPtr myInfo; BufFilePtr inputRaw; /* * allocate the private information */ myInfo = (CECompressInfoPtr) malloc(sizeof(CECompressInfo)); if (myInfo == NULL) { if (fd == -1) close (tmpFd); errno = CEErrorMalloc; return -1; } /* * set the information * set the size to the maximum number of bytes we * want to read. */ myInfo->fd = tmpFd; myInfo->size = (((fileMagic[1] * 256) + fileMagic[2]) * 256) + fileMagic[3]; /* * start with raw functionality */ inputRaw = _DtHelpCeBufFileRdRawZ(myInfo); if (inputRaw == NULL) { if (fd == -1) close (tmpFd); return -1; } *ret_file = _DtHelpCeBufFilePushZ(inputRaw); if (*ret_file == NULL) { _DtHelpCeBufFileClose(inputRaw, (fd == -1 ? True : False)); return -1; } } else { /* * not a compressed file, back up the four bytes we read */ result = lseek (tmpFd, offset, SEEK_SET); if (result == -1) { if (fd == -1) close (tmpFd); return -1; } /* * read with raw functionality */ *ret_file = _DtHelpCeBufFileRdWithFd(tmpFd); if (*ret_file == NULL) { if (fd == -1) close (tmpFd); return -1; } } return 0; } /* End of _DtHelpCeFileOpenAndSeek */ /****************************************************************************** * Core Engine Public Functions ******************************************************************************/ /****************************************************************************** * Function: int _DtHelpOpenVolume (char *volFile, _DtHelpVolume *retVol); * * Parameters: volFile Specifies the name of the Help Volume file * to load. * * retVol Returns the handle to the loaded volume. * If a volume is opened several times, the * same handle will be returned each time. * * Return Value: 0 if successful, -1 if a failure occurred. * * errno Values: EINVAL Illegal parameter specified. * getcwd(2) errno set via a getcwd call. * readlink(2) errno set via a readlink call. * CEErrorMalloc * CEErrorExceedMaxSize The new path will exceed * max_size. * CEErrorIllegalPath The compression will required * the path to change to a parent * directory beyond the beginning * of basePath. * CEErrorIllegalDatabaseFile * Specifies that 'volFile' is * an illegal database file. * * * Purpose: This function must be called to open a Help Volume file * before any of the information in the volume can be * accessed. * ******************************************************************************/ int _DtHelpOpenVolume ( char *volFile, _DtHelpVolumeHdl *retVol) { int result = 0; _DtHelpVolume vol, prevVol; _DtHelpProcessLock(); if (volFile == NULL || retVol == NULL) { errno = EINVAL; _DtHelpProcessUnlock(); return -1; } /* * follow all the symbolic links and get the absolute path and filename. */ volFile = _DtHelpCeTraceFilenamePath(volFile); if (volFile == NULL) { _DtHelpProcessUnlock(); return -1; } /* Search the volume chain to see if it is already open. */ prevVol = NULL; vol = volChain; while (vol != NULL && strcmp (vol->volFile, volFile)) { prevVol = vol; vol = vol->nextVol; } if (vol) { vol->openCount++; free(volFile); } else /* if (vol == NULL) */ { /* If it isn't open, open it and insert it in the chain. */ result = VolumeLoad (volFile, &vol); if (result == 0) { if (prevVol == NULL) volChain = vol; else prevVol->nextVol = vol; } } /* Return the volume handle and a status indicating success/failure. */ *retVol = (_DtHelpVolumeHdl) vol; _DtHelpProcessUnlock(); return result; } /****************************************************************************** * Function: int _DtHelpCeUpVolumeOpenCnt (_DtHelpVolumeHdl vol); * * Parameters: vol Specifies the loaded volume. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: EINVAL 'vol' was NULL, no volumes open or * 'vol' does not exist. * * Purpose: When the volume is no longer needed, it should be * closed with this call. If the volume has been opened * several times, closing it will just decrement the * reference count. When it has been closed as many times * as it was opened, the memory it is using will be freed * and any handles to the volume will be invalid. * ******************************************************************************/ int _DtHelpCeUpVolumeOpenCnt ( _DtHelpVolumeHdl volume) { _DtHelpVolume prevVol; _DtHelpVolume vol = (_DtHelpVolume)volume; _DtHelpProcessLock(); if (vol == NULL || volChain == NULL) { errno = EINVAL; _DtHelpProcessUnlock(); return (-1); } /* * check to see if this volume is in our chain */ if (vol != volChain) { if (CheckVolList (vol, &prevVol) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return (-1); } } /* * increment it's usage count. */ vol->openCount++; _DtHelpProcessUnlock(); return (0); } /****************************************************************************** * Function: int _DtHelpCloseVolume (_DtHelpVolumeHdl vol); * * Parameters: vol Specifies the loaded volume. * * Return Value: 0 if successful, -1 if a failure occurs * * errno Values: EINVAL 'vol' was NULL, no volumes open or * 'vol' does not exist. * * Purpose: When the volume is no longer needed, it should be * closed with this call. If the volume has been opened * several times, closing it will just decrement the * reference count. When it has been closed as many times * as it was opened, the memory it is using will be freed * and any handles to the volume will be invalid. * ******************************************************************************/ int _DtHelpCloseVolume ( _DtHelpVolumeHdl volume) { _DtHelpVolume prevVol; _DtHelpVolume vol = (_DtHelpVolume)volume; _DtHelpProcessLock(); if (vol == NULL || volChain == NULL) { errno = EINVAL; _DtHelpProcessUnlock(); return (-1); } /* * check to see if this volume is in our chain */ if (vol != volChain) { if (CheckVolList (vol, &prevVol) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return (-1); } } /* * decrement it's usage count. */ vol->openCount--; if (vol->openCount == 0) { /* The volume is no longer needed. Unlink it from the chain and free it. */ if (vol == volChain) volChain = volChain->nextVol; else prevVol->nextVol = vol->nextVol; VolumeUnload (vol); } _DtHelpProcessUnlock(); return (0); } /***************************************************************************** * Function: int _DtHelpCeGetTopTopicId (_DtHelpVolume vol, * char **ret_idString) * * Parameters: vol Specifies the loaded volume * ret_idString Returns the location ID of the * the top level topic. * * Memory own by caller: * ret_idString * * Returns: True for success, False if a failure occurs. * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorMissingTopTopicRes * Specifies that the 'TopTopic/topTopic' * resource is missing from the database. * CEErrorMalloc * * Purpose: Get the information to access the top level topic. * *****************************************************************************/ int _DtHelpCeGetTopTopicId ( _DtHelpVolumeHdl volume, char **ret_idString ) { int found = False; _DtHelpVolume vol = (_DtHelpVolume)volume; _DtHelpProcessLock(); if (vol == NULL || ret_idString == NULL || CheckVolList(vol, NULL) == -1) errno = EINVAL; else { /* * What type of volume is it? */ if (vol->sdl_flag == False) (void) _DtHelpCeGetCcdfTopTopic(vol, ret_idString); else *ret_idString = _DtHelpCeGetSdlHomeTopicId((_DtHelpVolumeHdl) vol); if (*ret_idString != NULL) *ret_idString = strdup(*ret_idString); if (*ret_idString != NULL) found = True; } _DtHelpProcessUnlock(); return found; } /* End _DtHelpCeGetTopTopicId */ /***************************************************************************** * Function: int _DtHelpCeFindId (_DtHelpVolume vol, char *target_id, * int fd, * char *ret_name, int *ret_offset) * * Parameters: vol Specifies the loaded volume * target_id Specifies target location ID * fd Specifies the locked file descriptor. * ret_name Returns a null terminated string * containing a fully qualified path to * the file that contains 'target_id'. * ret_offset Returns the offset into 'ret_name' * to the topic that contains 'target_id'. * * Memory own by caller: * ret_name * * Returns: True if successful, False if a failure occurs * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorMalloc * CEErrorMissingFilenameRes * Specifies that the 'Filename/filename' * resource for 'topic' does not exist. * CEErrorMissingFileposRes * If the resource is not in the * database or if the resource NULL. * CEErrorLocIdNotFound * Specifies that 'locId' was not * found. * * Purpose: Find which topic contains a specified locationID. * *****************************************************************************/ int _DtHelpCeFindId ( _DtHelpVolumeHdl volume, char *target_id, int fd, char **ret_name, int *ret_offset ) { _DtHelpVolume vol = (_DtHelpVolume)volume; int result; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || target_id == NULL || ret_name == NULL || ret_offset == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return False; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { result = _DtHelpCeFindCcdfId(vol, target_id, ret_name, ret_offset); } else { result = _DtHelpCeFindSdlId(vol, target_id, fd, ret_name, ret_offset); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpCeFindId */ /***************************************************************************** * Function: int _DtHelpCeGetKeywordList (_DtHelpVolume vol, char ***ret_keywords) * * Parameters: vol Specifies the loaded volume * ret_keywords Returns a NULL-terminated string array * containing the sorted list of keywords in the * volume. This array is NOT owned by the caller * and should only be read or copied. * * Returns: The count of keywords associated with the volume if successful. * -1 if a failure occurs; * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorMalloc * CEErrorIllegalDatabaseFile * Specifies that the keyword file is * invalid or corrupt. * CEErrorMissingKeywordsRes * Specifies that the keyword file does * not contain the 'Keywords/keywords' * resource or the resource is NULL * * Purpose: Get the list of keywords contained in a volume. * *****************************************************************************/ int _DtHelpCeGetKeywordList ( _DtHelpVolumeHdl volume, char ***ret_keywords ) { int nameCount = -1; _DtHelpVolume vol = (_DtHelpVolume)volume; if (vol == NULL || ret_keywords == NULL || CheckVolList (vol, NULL) == -1) errno = EINVAL; else if (GetVolumeKeywords (vol, ret_keywords) == 0) { nameCount = 0; while (*ret_keywords && (*ret_keywords)[nameCount]) nameCount++; } return nameCount; } /* End _DtHelpCeGetKeywordList */ /***************************************************************************** * Function: int _DtHelpCeFindKeyword (_DtHelpVolume vol, char *target, char ***ret_ids) * * Parameters: vol Specifies the loaded volume * target The target keyword. * ret_ids Returns a null terminated list of location * ids associated with the target keyword. * * Returns: The count of ids associated with the keyword if successful. * -1 if a failure occurs; * * errno Values: EINVAL Specifies an invalid parameter was * used. * CEErrorNoKeywordList * Specifies that the volume does not * have a keyword list. * CEErrorIllegalKeyword * Specifies that 'target' was not * found. * CEErrorMalloc * CEErrorIllegalDatabaseFile * Specifies that the keyword file is * invalid or corrupt. * CEErrorMissingKeywordsRes * Specifies that the keyword file does * not contain the 'Keywords/keywords' * resource or the resource is NULL * * Purpose: Get the list of location ids associated with a keyword * *****************************************************************************/ int _DtHelpCeFindKeyword ( _DtHelpVolumeHdl volume, char *target, char ***ret_ids ) { int nameCount = -1; _DtHelpVolume vol = (_DtHelpVolume)volume; if (vol == NULL || target == NULL || ret_ids == NULL || CheckVolList (vol, NULL) == -1) errno = EINVAL; else if (GetKeywordTopics (vol, target, ret_ids) == 0) { nameCount = 0; while (*ret_ids && (*ret_ids)[nameCount]) nameCount++; } return nameCount; } /* End _DtHelpCeFindKeyword */ /***************************************************************************** * Function: int _DtHelpGetTopicTitle ( * _DtHelpVolumeHdl volume, * char *id, char **ret_title) * * Parameters: volume Specifies the volume containing the id. * id Specifies the id for the topic desired. * ret_title Returns a null terminated string containing * the title. * * Memory own by caller: * ret_title * * Returns: 0 if successful, -2 if didn't find the id, * otherwise -1. * * errno Values: EINVAL Specifies an invalid parameter was * used. * * Purpose: Get the title of a topic. * *****************************************************************************/ int _DtHelpGetTopicTitle ( _DtHelpVolumeHdl volume, char *id, char **ret_title) { int result; char *abbrevTitle; _DtHelpVolume vol = (_DtHelpVolume)volume; if (volume == NULL || id == NULL || CheckVolList (vol, NULL) == -1 || ret_title == NULL) { errno = EINVAL; return -1; } /* * Try to get the title via the and tags. */ result = GetTopicTitleAndAbbrev(vol, id, ret_title, &abbrevTitle); if (result == 0) { /* * If we have a abbreviated title, return it instead. */ if (abbrevTitle) { if (*ret_title) free ((char *) *ret_title); *ret_title = abbrevTitle; } } return result; } /* End _DtHelpGetTopicTitle */ /***************************************************************************** * Function: int _DtHelpCeMapTargetToId (_DtHelpVolume vol, * char *target_id, * char *ret_id) * * Parameters: vol Specifies the loaded volume * target_id Specifies target location ID * ret_id Returns the id containing the target_id. * This memory *IS NOT* owned by the caller. * * Returns: 0 if successful, -1 if a failure occurs * * Purpose: Find which topic contains a specified locationID. * *****************************************************************************/ int _DtHelpCeMapTargetToId ( _DtHelpVolumeHdl volume, char *target_id, char **ret_id) { _DtHelpVolume vol = (_DtHelpVolume)volume; int result; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || target_id == NULL || ret_id == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return -1; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { result = _DtHelpCeMapCcdfTargetToId(vol, target_id, ret_id); } else { result = _DtHelpCeMapIdToSdlTopicId(vol, target_id, ret_id); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpCeMapTargetToId */ /***************************************************************************** * Function: char * _DtHelpGetVolumeLocale (_DtHelpVolume vol) * * Parameters: vol Specifies the loaded volume * * Returns: The pointer to the locale string if successful. Otherwise * NULL. * * Purpose: Get the locale of the specified volume. * Returns the locale in a unix specific format * - locale[_ter][.charset] - This memory is owned by * the caller. * *****************************************************************************/ char * _DtHelpGetVolumeLocale ( _DtHelpVolumeHdl volume) { _DtHelpVolume vol = (_DtHelpVolume)volume; char *result; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return NULL; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { result = _DtHelpCeGetCcdfVolLocale(vol); } else { result = _DtHelpCeGetSdlVolumeLocale(vol); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpGetVolumeLocale */ /***************************************************************************** * Function: int _DtHelpCeGetDocStamp (_DtHelpVolumeHdl volume, char **ret_doc, * char **ret_time) * * Parameters: volume Specifies the loaded volume * ret_doc Returns the doc id. * ret_time Returns the time stamp. * * Memory: Caller owns the string in ret_doc and ret_time. * * Returns: 0 if successful, -2 if the volume does not contain * one or the other, -1 if any other failure. * * Purpose: Get doc id and time stamp of a volume. * *****************************************************************************/ int _DtHelpCeGetDocStamp ( _DtHelpVolumeHdl volume, char **ret_doc, char **ret_time) { _DtHelpVolume vol = (_DtHelpVolume)volume; int result; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return 0; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { result = _DtHelpCeGetCcdfDocStamp (vol, ret_doc, ret_time); } else { result = _DtHelpCeGetSdlDocStamp(vol, ret_doc, ret_time); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpCeGetDocStamp */ /***************************************************************************** * Function: char * _DtHelpCeGetTopicChilren (_DtHelpVolumeHdl vol) * * Parameters: vol Specifies the loaded volume * topic_id Speicifes the topic id of which the * children are to be found. * retTopics Returns the null terminated array of * ids. This memory is owned by the caller * and must be freed. * * Returns: > 0 if successful, -1 if failures. * * Purpose: Get the children of a topic. * *****************************************************************************/ int _DtHelpCeGetTopicChildren ( _DtHelpVolumeHdl volume, char *topic_id, char ***retTopics) { _DtHelpVolume vol = (_DtHelpVolume)volume; int result; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; _DtHelpProcessUnlock(); return -1; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { result = _DtHelpCeGetCcdfTopicChildren(volume, topic_id, retTopics); } else { result = _DtHelpCeGetSdlTopicChildren(volume, topic_id, retTopics); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpCeGetTopicChildren */ /***************************************************************************** * Function: int _DtHelpCeGetVolumeFlag (_DtHelpVolumeHdl vol) * * Parameters: vol Specifies the loaded volume * * Returns: 0 if CCDF volume, 1 if SDL, -1 if failures. * * Purpose: Determine the type of volume. * *****************************************************************************/ int _DtHelpCeGetVolumeFlag ( _DtHelpVolumeHdl volume) { _DtHelpVolume vol = (_DtHelpVolume)volume; /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { errno = EINVAL; return -1; } /* * What type of volume is it? */ return((int) vol->sdl_flag); } /* End _DtHelpCeGetVolumeFlag */ /***************************************************************************** * Function: int _DtHelpCeLockVolume (_DtHelpVolumeHdl vol) * * Parameters: vol Specifies the loaded volume * * Returns: > 0 if successful, -1 if failures. * * Purpose: Lock the volume so that it can't get change out from * under the caller. * *****************************************************************************/ int _DtHelpCeLockVolume ( _DtHelpVolumeHdl volume, _DtHelpCeLockInfo *lock_info) { struct stat buf; _DtHelpVolume vol = (_DtHelpVolume)volume; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { _DtHelpProcessUnlock(); return -1; } /* * lock it by opening it. */ lock_info->fd = open(vol->volFile, O_RDONLY); if (lock_info->fd == -1) { _DtHelpProcessUnlock(); return -1; } (void) fstat(lock_info->fd, &buf); if (buf.st_mtime != vol->check_time) { if (RereadVolume(vol) != 0) { close(lock_info->fd); _DtHelpProcessUnlock(); return -1; } vol->check_time = buf.st_mtime; } /* * Synthetic open */ vol->openCount++; lock_info->volume = volume; _DtHelpProcessUnlock(); return 0; } /* End _DtHelpCeLockVolume */ /***************************************************************************** * Function: int _DtHelpCeUnlockVolume (_DtHelpVolumeHdl vol) * * Parameters: vol Specifies the loaded volume * * Returns: > 0 if successful, -1 if failures. * * Purpose: Unlock the volume. * *****************************************************************************/ int _DtHelpCeUnlockVolume ( _DtHelpCeLockInfo lock_info) { _DtHelpVolume vol = (_DtHelpVolume)(lock_info.volume); _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { _DtHelpProcessUnlock(); return -1; } /* * check to see if it needs to be unlocked. */ if (lock_info.fd != -1) close(lock_info.fd); /* * Synthetic close */ vol->openCount--; _DtHelpProcessUnlock(); return 0; } /* End _DtHelpCeUnlockVolume */ /***************************************************************************** * Function: int _DtHelpCeIsTopTopic (_DtHelpVolumeHdl volume, const char *id) * * Parameters: vol Specifies the loaded volume * id Specifies a location id. * * Returns: = 0 if successful, != 0 if failures. * * Purpose: Tests to see if the location id is in the top topic of * the volume. * *****************************************************************************/ int _DtHelpCeIsTopTopic ( _DtHelpVolumeHdl volume, const char *id) { int result = -1; char *topicId = NULL; char *topId = NULL; _DtHelpVolume vol = (_DtHelpVolume) volume; _DtHelpProcessLock(); /* * check the parameters */ if (vol == NULL || CheckVolList (vol, NULL) == -1) { _DtHelpProcessUnlock(); return -1; } /* * What type of volume is it? */ if (vol->sdl_flag == False) { if (_DtHelpCeMapCcdfTargetToId(vol, id, &topicId) == 0 && _DtHelpCeGetCcdfTopTopic(vol, &topId) == 0) result = _DtHelpCeStrCaseCmpLatin1(topId, topicId); } else if (_DtHelpCeMapIdToSdlTopicId(vol, id, &topicId) == 0) { topId = _DtHelpCeGetSdlHomeTopicId(volume); if (topId != NULL) result = _DtHelpCeStrCaseCmpLatin1(topId, topicId); } _DtHelpProcessUnlock(); return result; } /* End _DtHelpCeIsTopTopic */