2669 lines
64 KiB
C
2669 lines
64 KiB
C
/*
|
|
* 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 librararies 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 <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xresource.h>
|
|
|
|
#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 existance 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 %<char> 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.
|
|
*/
|
|
strcpy (tempPath, 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
|
|
*/
|
|
strcpy (newName, 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 <TOPIC> and <ABBREV> 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 */
|