dtcalc: change from obsoleted MAXFLOAT to FLT_MAX from std C
[oweals/cde.git] / cde / lib / DtHelp / Access.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: Access.c /main/11 1996/11/01 10:09:29 drk $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        Access.c
28  **
29  **   Project:     Run Time Project File Access
30  **
31  **   Description: This body of code handles the access routines for the
32  **                Display Area.
33  **
34  **
35  **  (c) Copyright 1987-1994, 1996 Hewlett-Packard Company
36  **  (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
37  **  (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
38  **  (c) Copyright 1993, 1994, 1996 Novell, Inc.
39  **  (c) Copyright 1996 Digital Equipment Corporation.  
40  **  (c) Copyright 1996 FUJITSU LIMITED.        
41  **  (c) Copyright 1996 Hitachi.        
42  **
43  **
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 /*
48  * system includes
49  */
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <limits.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <sys/param.h>
58 #include <sys/stat.h>
59
60 #include <X11/Xlib.h>
61 #include <X11/Xresource.h>
62
63 #ifdef X_NOT_STDC_ENV
64 extern int errno;
65 #endif
66
67 /*
68  * Canvas Engine includes
69  */
70 #include "CanvasP.h"
71 #include "CanvasSegP.h"
72
73 /*
74  * private includes
75  */
76 #include "CanvasError.h"
77 #include "Access.h"
78 #include "bufioI.h"
79 #include "FontAttrI.h"
80 #include "AccessP.h"
81 #include "AccessI.h"
82 #include "AccessSDLP.h"
83 #include "AccessSDLI.h"
84 #include "AccessCCDFI.h"
85 #include "FormatUtilI.h"
86
87 #include "SDLI.h"
88 #include "FormatSDLI.h"
89
90 #include "CCDFUtilI.h"
91 #include "StringFuncsI.h"
92
93 #include "Lock.h"              /* Process and App Lock macros */
94
95 #ifdef NLS16
96 #endif
97
98 /********    Private Defines      ********/
99 #define LIST_INCREMENT  10
100 #define BUFF_SIZE       256
101 /********    End Private Defines  ********/
102
103 /********    Private Function Declarations    ********/
104 static  int       GetVolumeKeywords (
105                         _DtHelpVolume     vol, 
106                         char    ***retKeywords);
107 static  int       VolumeLoad (
108                         char        *volFile, 
109                         _DtHelpVolume  *retVol);
110 static  int       VolumeUnload (
111                         _DtHelpVolume vol);
112 /********    End Private Function Declarations    ********/
113
114 /********    Private Macro Declarations        ********/
115 /********    End Private Macro Declarations    ********/
116
117 /******************************************************************************
118 *
119 * Private variables used within this file.
120 *
121 *******************************************************************************/
122 static _DtHelpVolume volChain = NULL;   /* Pointer to the head of the chain */
123                                         /* of all the open volumes. */
124 static const char *Slash  = "/";
125 static const char *Period = ".";
126
127 /******************************************************************************
128  *                             Private Functions
129  ******************************************************************************/
130 /******************************************************************************
131  * Function:    CheckVolList (_DtHelpVolume vol, _DtHelpVolume *ret_prev)
132  *
133  * Parameters:  vol             Specifies the volume to search for.
134  *              ret_prev        Returns the volume whose nextVol element
135  *                              points to 'vol' if non NULL.
136  *
137  * Returns:     0 if successful, -1 if failure.
138  *
139  * errno Values:
140  *
141  * Purpose:     To check for the existance of a volume.
142  *
143  ******************************************************************************/
144 static  int
145 CheckVolList (
146     _DtHelpVolume        vol,
147     _DtHelpVolume       *ret_prev )
148 {
149     _DtHelpVolume       myVol;
150     _DtHelpVolume       prevVol = NULL;
151
152     _DtHelpProcessLock();
153     myVol = volChain;
154
155     while (myVol != NULL && myVol != vol)
156       {
157         prevVol = myVol;
158         myVol = myVol->nextVol;
159       }
160
161     if (ret_prev)
162         *ret_prev = prevVol;
163
164     if (myVol != vol)
165       {
166         _DtHelpProcessUnlock();
167         return -1;
168       }
169
170     _DtHelpProcessUnlock();
171     return 0;
172 }
173
174 /******************************************************************************
175  * Function:    int VolumeLoad (char *volFile, _DtHelpVolume *retVol);
176  *
177  * Parameters:  volFile         Specifies the name of the Help Volume file
178  *                              to load.
179  *
180  *              retVol          Returns the handle to the loaded volume.
181  *
182  * Return Value:        Returns 0 if successful,
183  *                      -1 if an error occurred.
184  *
185  * errno Values:        CEErrorMalloc
186  *                      CEErrorIllegalDatabaseFile
187  *
188  * Purpose:     This function must be called to load a Help Volume file
189  *              before any of the information in the volume can be
190  *              accessed. 
191  *
192  ******************************************************************************/
193 static int 
194 VolumeLoad (
195     char        *volFile, 
196     _DtHelpVolume  *retVol)
197 {
198     /* Allocate the volume structure and initialize it. */
199     *retVol = (_DtHelpVolume) malloc (sizeof (struct _DtHelpVolumeRec));
200     if (*retVol)
201       {
202         (*retVol)->sdl_flag      = False;
203         (*retVol)->volFile       = volFile;
204         (*retVol)->keywords      = NULL;
205         (*retVol)->keywordTopics = NULL;
206         (*retVol)->openCount     = 1;
207         (*retVol)->nextVol       = NULL;
208         (*retVol)->vols.ccdf_vol = NULL;
209
210         if (_DtHelpCeOpenSdlVolume ((*retVol)) == 0)
211             return 0;
212         else if (_DtHelpCeOpenCcdfVolume(*retVol) == 0)
213             return 0;
214
215         /*
216          * Set the global error
217          */
218         errno = CEErrorIllegalDatabaseFile;
219
220         /*
221          * error on loading the database.
222          */
223         free ((char *) ((*retVol)->volFile));
224         free ((char *) (*retVol));
225         *retVol = NULL;
226       }
227     else
228         errno = CEErrorMalloc;
229
230     return -1;
231
232 } /* End VolumeLoad */
233
234 /*******************************************************************************
235  * Function:    int VolumeUnload (_DtHelpVolume vol);
236  *
237  * Parameters:  vol     Specifies the loaded volume.
238  *
239  * Return Value:        0 if successful, -1 if a failure occurs
240  *
241  * errno Values:        None
242  *
243  * Purpose:     When the volume is no longer needed, it should be unloaded
244  *              with this call.  Unloading it frees the memory (which means
245  *              any handles on the volume become invalid.)
246  *
247  ******************************************************************************/
248 static int 
249 VolumeUnload (
250      _DtHelpVolume vol)
251 {
252     char        ***topicList;
253     
254     if (vol != NULL)
255       {
256
257         if (vol->sdl_flag == True)
258             _DtHelpCeCloseSdlVolume((_DtHelpVolumeHdl) vol);
259         else
260             _DtHelpCeCloseCcdfVolume(vol);
261
262         if (vol->volFile != NULL)
263             free (vol->volFile);
264
265         if (vol->keywords != NULL)
266             _DtHelpCeFreeStringArray (vol->keywords);
267
268         if (vol->keywordTopics != NULL)
269           {
270             for (topicList = vol->keywordTopics;
271                                         *topicList != NULL; topicList++)
272                 _DtHelpCeFreeStringArray (*topicList);
273
274             free (vol->keywordTopics);
275           }
276
277         free (vol);
278       }
279
280     return (0);
281 }
282
283 /*******************************************************************************
284  * Function:    int RereadVolume (_DtHelpVolume vol);
285  *
286  * Parameters:  vol     Specifies the loaded volume.
287  *
288  * Return Value:        0 if successful, -1 if a failure occurs
289  *
290  * errno Values:        None
291  *
292  * Purpose:     When the volume is no longer needed, it should be unloaded
293  *              with this call.  Unloading it frees the memory (which means
294  *              any handles on the volume become invalid.)
295  *
296  ******************************************************************************/
297 static int 
298 RereadVolume (
299      _DtHelpVolume vol)
300 {
301     int            result;
302     char        ***topicList;
303     
304     if (vol->keywords != NULL)
305       {
306         _DtHelpCeFreeStringArray (vol->keywords);
307         vol->keywords = NULL;
308       }
309
310     if (vol->keywordTopics != NULL)
311       {
312         for (topicList = vol->keywordTopics; *topicList != NULL; topicList++)
313             _DtHelpCeFreeStringArray (*topicList);
314
315         free (vol->keywordTopics);
316         vol->keywordTopics = NULL;
317       }
318
319     if (vol->sdl_flag == False)
320         result = _DtHelpCeRereadCcdfVolume(vol);
321     else
322         result = _DtHelpCeRereadSdlVolume(vol);
323
324     return (result);
325 }
326
327 /******************************************************************************
328  * Function:    static int GetKeywordTopics (_DtHelpVolume vol, char *keyword,
329  *                                     char ***topics);
330  *
331  * Parameters:  vol             Specifies the loaded volume
332  *              keyword         Specifies the keyword whose location is desired.
333  *              topics          Returns a NULL-terminated string array of the
334  *                              list of topics which contain the keyword.
335  *                              This array is NOT owned by the caller and
336  *                              should only be read or copied.
337  *
338  * Return Value:        0 if successful, -1 if a failure occurs
339  *
340  * errno Values:        CEErrorNoKeywordList
341  *                                      Specifies that the volume does not
342  *                                      have a keyword list.
343  *                      CEErrorIllegalKeyword
344  *                                      Specifies that 'keyword' was not
345  *                                      found.
346  *                      CEErrorMalloc
347  *                      CEErrorIllegalDatabaseFile
348  *                                      Specifies that the keyword file is
349  *                                      invalid or corrupt.
350  *                      CEErrorMissingKeywordsRes
351  *                                      Specifies that the keyword file does
352  *                                      not contain the 'Keywords/keywords'
353  *                                      resource or the resource is NULL
354  *
355  *
356  * Purpose:     Find which topic contains a specified locationId.
357  *
358  ******************************************************************************/
359 static int 
360 GetKeywordTopics (
361    _DtHelpVolume     vol, 
362    char           *keyword, 
363    char         ***retTopics)
364 {
365     char        **keywords;
366     char        **nextKey;
367     int index;
368
369     _DtHelpProcessLock();
370     *retTopics = NULL;
371
372     /* Get the list of keywords. */
373     if (GetVolumeKeywords (vol, &keywords) != 0)
374       {
375         _DtHelpProcessUnlock();
376         return -1;
377       }
378
379     if (keywords == NULL || vol->keywordTopics == NULL)
380       {
381         errno = CEErrorNoKeywordList;
382         _DtHelpProcessUnlock();
383         return -1;
384       }
385
386     /* Search the list of keywords for the current one. */
387     nextKey = keywords;
388     while (*nextKey != NULL && strcmp (*nextKey, keyword))
389         nextKey++;
390
391     if (*nextKey == NULL)
392       {
393         errno = CEErrorIllegalKeyword;
394         _DtHelpProcessUnlock();
395         return -1;
396       }
397
398     index = nextKey - keywords;
399     *retTopics = *(vol->keywordTopics + index);
400
401     _DtHelpProcessUnlock();
402     return (0);
403 }
404
405 /******************************************************************************
406  * Function:    static int GetVolumeKeywords(_DtHelpVolume vol,char ***keywords);
407  *
408  * Parameters:  vol             Specifies the volume.
409  *              keywords        Returns a NULL-terminated string array
410  *                              containing the sorted list of keywords in the
411  *                              volume.  This array is NOT owned by the caller
412  *                              and should only be read or copied.
413  *
414  * Return Value:        0 if successful, -1 if a failure occurs
415  *
416  * errno Values:        CEErrorMalloc
417  *                      CEErrorIllegalDatabaseFile
418  *                                      Specifies that the keyword file is
419  *                                      invalid or corrupt.
420  *                      CEErrorMissingKeywordsRes
421  *                                      Specifies that the keyword file does
422  *                                      not contain the 'Keywords/keywords'
423  *                                      resource or the resource is NULL
424  *
425  * Purpose:     Get the list of keywords defined in a volume.
426  *
427  ******************************************************************************/
428 static int 
429 GetVolumeKeywords (
430     _DtHelpVolume     vol, 
431     char        ***retKeywords)
432 {
433     int   result;
434     _DtHelpCeLockInfo lockInfo;
435
436     _DtHelpProcessLock();
437
438     /* Keywords aren't loaded until they are needed, so see if they have
439        been loaded yet. */
440     if (vol->keywords == NULL)
441       {
442         /*
443          * What type of volume is it?
444          */
445         if (_DtHelpCeLockVolume(vol, &lockInfo) != 0)
446           {
447             _DtHelpProcessUnlock();
448             return -1;
449           }
450
451         if (vol->sdl_flag == False)
452             result = _DtHelpCeGetCcdfKeywordList(vol);
453         else
454             result = _DtHelpCeGetSdlKeywordList(vol);
455
456         _DtHelpCeUnlockVolume(lockInfo);
457
458         if (result != 0)
459           {
460             _DtHelpProcessUnlock();
461             return -1;
462           }
463       }
464
465     /* All of the keyword processing is done when they are loaded. */
466      *retKeywords = vol->keywords;
467
468     if (*retKeywords == NULL)
469       {
470         _DtHelpProcessUnlock();
471         return (-1);
472       }
473
474     _DtHelpProcessUnlock();
475     return (0);
476 }
477
478 /*****************************************************************************
479  * Function: GetTopicTitleAndAbbrev (
480  *
481  * Parameters:
482  *
483  * Memory own by caller:
484  *              ret_name
485  *              ret_abrrev
486  *
487  * Returns:     0 if successful, -2 if didn't find the id,
488  *              -3 if couldn't format the topic,
489  *              otherwise -1.
490  *
491  * Purpose:     Find the title and abbreviated title of a topic.
492  *
493  *****************************************************************************/
494 static int
495 GetTopicTitleAndAbbrev (
496         _DtHelpVolume    volume,
497         char             *id,
498         char            **ret_name,
499         char            **ret_abbrev )
500 {
501     int         result = 0;
502     int         offset;
503     char        buffer[BUFF_SIZE];
504     char       *bufPtr;
505     char       *filename = NULL;
506     BufFilePtr  file;
507     _DtHelpCeLockInfo lockInfo;
508
509     if (_DtHelpCeLockVolume(volume, &lockInfo) != 0)
510         return -1;
511
512     if (_DtHelpCeFindId(volume, id, lockInfo.fd, &filename, &offset) != True)
513         result = -2;
514
515     /*
516      * What type of volume is it?
517      */
518     if (result == 0)
519       {
520         if (0 == _DtHelpCeGetVolumeFlag(volume))
521           {
522             result = _DtHelpCeFileOpenAndSeek(filename,offset,-1,&file,NULL);
523             if (result == 0)
524               {
525                 result = -1;
526                 if (_DtHelpCeReadBuf (file, buffer, BUFF_SIZE) != -1)
527                   {
528                     result = 0;
529                     bufPtr = buffer;
530                     if (_DtHelpCeGetCcdfTopicAbbrev (NULL, file,
531                                 buffer, &bufPtr, BUFF_SIZE, MB_CUR_MAX,
532                                         ret_name, NULL, ret_abbrev) != 0)
533                         result = -3;
534                   }
535                 _DtHelpCeBufFileClose(file, True);
536               }
537           }
538         else
539           {
540             _DtHelpProcessLock();
541             if (_DtHelpCeFrmtSDLTitleToAscii(volume, offset,
542                                                 ret_name, ret_abbrev) != 0)
543               result = -3;
544             _DtHelpProcessUnlock();
545           }
546       }
547
548     if (filename != NULL)
549         free(filename);
550
551     _DtHelpCeUnlockVolume(lockInfo);
552
553     return result;
554 }
555
556 /*****************************************************************************
557  * Function: static int FileOpenRtnFd (char *name, int *ret_fd)
558  *
559  * Parameters:  name            Specifies the file to open.
560  *              ret_fd          Returns the fd of the opened file.
561  *
562  * Returns:      0 if required uncompress.
563  *                 file descriptor to remove the file from the system.
564  *               1 if no uncompression required.
565  *              -1 if a failure occurs
566  *
567  * errno Values:        EINVAL          Specifies an invalid parameter was
568  *                                      used.
569  *                      CEErrorFileSeek
570  *                                      Specifies the seek offset was invalid.
571  *
572  * Purpose:     Find out if a file is compressed and uncompress it if it is.
573  *
574  *****************************************************************************/
575 static int
576 FileOpenRtnFd (
577     char        *name,
578     int         *ret_fd )
579 {
580     char *inFile = NULL;
581     char  tmpName[MAXPATHLEN + 1];
582     int   result = 1;
583
584     /*
585      * check to see if the file exists in uncompressed form
586      */
587     *ret_fd = open(name, O_RDONLY);
588     if (*ret_fd == -1)
589       {
590         /*
591          * get a temporary name
592          */
593         (void) tmpnam (tmpName);
594
595         /*
596          * malloc memory for the dot Z file name.
597          */
598         inFile = (char *) malloc (strlen (name) + 3);
599         if (inFile != NULL)
600           {
601             /*
602              * make the dot Z file
603              */
604             strcpy (inFile, name);
605             strcat (inFile, ".Z");
606
607             /*
608              * do the uncompress
609              */
610             result = _DtHelpCeUncompressFile (inFile, tmpName);
611             free (inFile);
612
613             if (result != 0)
614               {
615                 errno = ENOENT;
616                 return -1;
617               }
618
619             /*
620              * now open the uncompressed file
621              */
622             *ret_fd = open(tmpName, O_RDONLY);
623             if (*ret_fd == -1)
624                 result = -1;
625             else
626                 unlink(tmpName);
627           }
628         else
629           {
630             errno = CEErrorMalloc;
631             return -1;
632           }
633       }
634
635     return result;
636
637 } /* End FileOpenRtnFd */
638
639 /******************************************************************************
640  *                          Semi-Public Functions
641  ******************************************************************************/
642 /*****************************************************************************
643  * Function: char *_DtHelpCeExpandPathname (char *spec, char *filename, char *type,
644  *              char *suffix, char *lang, _DtSubstitutionRec *subs, int num)
645  *
646  * Parameters:
647  *              spec            Specifies a string with substitution
648  *                                      characters.
649  *                              containing the character set if found.
650  *              filename        Specifies the string to substitute for %N.
651  *              type            Specifies the string to substitute for %T.
652  *              suffix          Specifies the string to substitute for %S.
653  *              lang            Specifies the string to substitute for %L.
654  *              subs            Specifies the application own specific
655  *                                      substitutions.
656  *              num             Specifies the number of substitution pairs
657  *                                      in 'subs'.
658  *
659  * Memory own by caller:
660  *              returned pointer
661  *
662  * Returns:     The expanded filename if successful. NULL if errors.
663  *
664  * Purpose:     Expand a string with %<char> substitution values.
665  *              Default substitutions are:
666  *                      %N      replaced with 'filename'.
667  *                      %T      replaced with 'type'
668  *                      %S      replaced with 'suffix'
669  *                      %L      replaced with 'lang'
670  *
671  *                      %l      replaced with the language sub part of 'lang'.
672  *                      %t      replaced with the territory sub part of 'lang'.
673  *                      %c      replaced with the code set sub part of 'lang'.
674  *              Other substitutions can be done via the 'subs' parameter.
675  *
676  *****************************************************************************/
677 char *
678 _DtHelpCeExpandPathname (
679     char  *spec,
680     char  *filename,
681     char  *type,
682     char  *suffix,
683     char  *lang,
684     _DtSubstitutionRec *subs,
685     int    num )
686 {
687     int    i;
688     int    len = 1;
689     char  *ptr;
690     char  *subString;
691     char  *partLang;
692     char  *partTer;
693     char  *partCodeSet;
694     char   pathName [MAXPATHLEN + 5];
695     Boolean   previousSlash = False;
696 #define MY_NUM 7
697     _DtSubstitutionRec mySubs [MY_NUM];
698
699     if (spec == NULL || *spec == '\0')
700       {
701         errno = EINVAL;
702         return NULL;
703       }
704
705     /*
706      * fill in the language sub parts
707      */
708     if (_DtHelpCeGetLangSubParts (lang, &partLang, &partTer, &partCodeSet))
709         return NULL;
710
711     mySubs[0].match = 'N';
712     mySubs[0].substitution = filename;
713     mySubs[1].match = 'T';
714     mySubs[1].substitution = type;
715     mySubs[2].match = 'S';
716     mySubs[2].substitution = suffix;
717     mySubs[3].match = 'L';
718     mySubs[3].substitution = lang;
719
720     mySubs[4].match = 'l';
721     mySubs[4].substitution = partLang;
722     mySubs[5].match = 't';
723     mySubs[5].substitution = partTer;
724     mySubs[6].match = 's';
725     mySubs[6].substitution = partCodeSet;
726
727     ptr = pathName;
728     while (*spec)
729       {
730         len = 1;
731         if (MB_CUR_MAX != 1)
732             len = mblen (spec, MB_CUR_MAX);
733
734         if (len == 1 && *spec == '/')
735           {
736             if (previousSlash)
737                 spec++;
738             else
739               {
740                 previousSlash = True;
741                 *ptr++ = *spec++;
742               }
743           }
744         else if (len == 1 && *spec == '%')
745           {
746             spec++;
747             switch (*spec)
748               {
749                 case '\0':
750                         *ptr++ = '%';
751                         break;
752
753                 case '/':
754                         if (!previousSlash)
755                           {
756                              previousSlash = True;
757                              *ptr++ = *spec;
758                           }
759                         spec++;
760                         break;
761
762                 default:
763                         i = 0;
764                         while (i < MY_NUM && mySubs && mySubs[i].match != *spec)
765                             i++;
766
767                         if (i < MY_NUM)
768                           {
769                             if (mySubs[i].substitution != NULL)
770                               {
771                                 subString = mySubs[i].substitution;
772                                 if (((int)(ptr - pathName + strlen(subString)))
773                                                 > MAXPATHLEN)
774                                   {
775                                     errno = CEErrorExceedMaxSize;
776                                     return NULL;
777                                   }
778                                 while (subString && *subString)
779                                     *ptr++ = *subString++;
780                               }
781                           }
782                         else
783                           {
784                             i = 0;
785                             while (i < num && subs && subs[i].match != *spec)
786                                 i++;
787                             /*
788                              * If the substitution character is not found
789                              * include the character onto the final string.
790                              */
791                             if (i >= num)
792                                 *ptr++ = *spec;
793                             else if (subs[i].substitution != NULL)
794                               {
795                                 subString = subs[i].substitution;
796                                 if (((int)(ptr - pathName + strlen(subString)))
797                                                 > MAXPATHLEN)
798                                   {
799                                     errno = CEErrorExceedMaxSize;
800                                     return NULL;
801                                   }
802                                 while (subString && *subString)
803                                     *ptr++ = *subString++;
804                               }
805                           }
806                         spec++;
807                         previousSlash = False;
808                         break;
809               }
810           }
811         else
812           {
813             previousSlash = False;
814             do 
815               {
816                 *ptr++ = *spec++;
817                 len--;
818               } while (len > 0);
819           }
820
821         if (ptr - pathName > MAXPATHLEN)
822           {
823             errno = CEErrorExceedMaxSize;
824             return NULL;
825           }
826       }
827
828     if (partLang)
829         free (partLang);
830     if (partTer)
831         free (partTer);
832     if (partCodeSet)
833         free (partCodeSet);
834
835     *ptr = '\0';
836     ptr = strdup (pathName);
837     if (ptr == NULL)
838         errno = CEErrorMalloc;
839
840     return ptr;
841 }
842
843 /*****************************************************************************
844  * Function: char *_DtHelpCeGetLangSubParts (char *lang, char **subLang,
845  *                                      char **subTer, char **subCodeSet)
846  *
847  * Parameters:
848  *              lang            Specifies the language string.
849  *              subLang         Returns the language sub part of 'lang'
850  *                                      or NULL.
851  *              subTer          Returns the territory sub part of 'lang'
852  *                                      or NULL.
853  *              subCodeSet      Returns the code set sub part of 'lang'
854  *                                      or NULL.
855  *
856  * Memory own by caller:
857  *              subLang
858  *              subTer
859  *              subCodeSet
860  *
861  * errno Values:
862  *              EINVAL
863  *              CEErrorMalloc
864  *
865  * Returns:     0 if successful, -1 if errors.
866  *
867  * Purpose:     Break a %l_%t.%c language specification into its sub parts.
868  *
869  *****************************************************************************/
870 int
871 _DtHelpCeGetLangSubParts (
872     char   *lang,
873     char  **subLang,
874     char  **subTer,
875     char  **subCodeSet )
876 {
877     int   len;
878     char *ptr;
879     char *sLang = NULL;
880     char *sTer  = NULL;
881     char *sCode = NULL;
882
883     if (subLang == NULL || subTer == NULL || subCodeSet == NULL)
884       {
885         errno = EINVAL;
886         return -1;
887       }
888
889     if (lang != NULL && *lang != '\0')
890       {
891         /*
892          * look for lang_ter
893          */
894         _DtHelpCeStrchr (lang, "_", MB_CUR_MAX, &ptr);
895         if (ptr)
896           {
897             /*
898              * do we want this string?
899              */
900             if (subLang != NULL)
901               {
902                 len = ptr - lang;
903                 sLang = (char *) malloc (len + 1);
904                 if (sLang != NULL)
905                   {
906                     strncpy (sLang, lang, len);
907                     sLang[len] = '\0';
908                   }
909                 else
910                   {
911                     errno = CEErrorMalloc;
912                     return -1;
913                   }
914               }
915             /*
916              * just mark that the lang part was found
917              */
918             else
919                 sLang = lang;
920     
921             lang = ptr + 1;
922           }
923     
924         /*
925          * look for lang.codeset
926          */
927         _DtHelpCeStrchr (lang, Period, MB_CUR_MAX, &ptr);
928         if (ptr)
929           {
930             len = ptr - lang;
931     
932             /*
933              * if it was in the form lang_ter.codeset, sLang will non-null
934              */
935             if (sLang != NULL)
936               {
937                 /*
938                  * do we want to save the territory?
939                  */
940                 if (subTer != NULL)
941                   {
942                     sTer = (char *) malloc (len + 1);
943                     if (sTer != NULL)
944                       {
945                         strncpy (sTer, lang, len);
946                         sTer[len] = '\0';
947                       }
948                     else
949                       {
950                         errno = CEErrorMalloc;
951                         return -1;
952                       }
953                   }
954                 /*
955                  * don't wan to save, but make sure we mark the territory
956                  * as being found (non-null).
957                  */
958                 else
959                     sTer = lang;
960               }
961             /*
962              * the lang was in the form lang.codeset.
963              * now check to see if want to save the lang portion.
964              */
965             else if (subLang != NULL)
966               {
967                 sLang = (char *) malloc (len + 1);
968                 if (sLang != NULL)
969                   {
970                     strncpy (sLang, lang, len);
971                     sLang[len] = '\0';
972                   }
973                 else
974                   {
975                     errno = CEErrorMalloc;
976                     return -1;
977                   }
978               }
979             /*
980              * didn't want to save the lang portion, but mark as found.
981              */
982             else
983                 sLang = lang;
984           }
985     
986        /*
987         * currently pointing at the dot?
988         */
989        if (ptr && *ptr == '.')
990          {
991             /*
992              * yes save the code set
993              */
994             ptr++;
995             if (subCodeSet != NULL)
996               {
997                 sCode = strdup (ptr);
998                 if (sCode == NULL)
999                   {
1000                     errno = CEErrorMalloc;
1001                     return -1;
1002                   }
1003               }
1004             /*
1005              * don't save the code set, but make sure we mark as found
1006              */
1007             else
1008                 sCode = ptr;
1009          }
1010        /*
1011         * didn't find a code set, so save the current info.
1012         * If we haven't already processed a lang portion, save as the
1013         * lang.
1014         */
1015        else if (sLang == NULL)
1016          {
1017             if (subLang != NULL)
1018               {
1019                 sLang = strdup (lang);
1020                 if (sLang == NULL)
1021                   {
1022                     errno = CEErrorMalloc;
1023                     return -1;
1024                   }
1025               }
1026             else
1027                 sLang = lang;
1028          }
1029        /*
1030         * otherwise this is the territory of the language. Save if desired
1031         */
1032        else if (subTer != NULL)
1033          {
1034             sTer = strdup (lang);
1035             if (sTer == NULL)
1036               {
1037                 errno = CEErrorMalloc;
1038                 return -1;
1039               }
1040           }
1041       }
1042
1043     if (subLang)
1044         *subLang = sLang;
1045     if (subTer)
1046         *subTer = sTer;
1047     if (subCodeSet)
1048         *subCodeSet = sCode;
1049
1050     return 0;
1051 }
1052
1053 /*****************************************************************************
1054  * Function: int _DtHelpCeGetUncompressedFileName (char *name, char **ret_name)
1055  *
1056  * Parameters:  name            Specifies the file to open.
1057  *              ret_name        Returns the name of the uncompressed file.
1058  *                              This memory must be freed by the caller.
1059  *
1060  * Returns:      0 if required uncompress. ret_name will contain the
1061  *                 name of the uncompressed file. The caller is required
1062  *                 to free the memory.
1063  *               1 if no uncompression required. ret_name points to name.
1064  *              -1 if a failure occurs
1065  *
1066  * errno Values:        EINVAL          Specifies an invalid parameter was
1067  *                                      used.
1068  *                      CEErrorFileSeek
1069  *                                      Specifies the seek offset was invalid.
1070  *
1071  * Purpose:     Find out if a file is compressed and uncompress it if it is.
1072  *
1073  *****************************************************************************/
1074 int
1075 _DtHelpCeGetUncompressedFileName (
1076         char             *name,
1077         char            **ret_name )
1078 {
1079     char *inFile = NULL;
1080     char  tmpName[MAXPATHLEN + 1];
1081     int   result = 1;
1082
1083     /*
1084      * check to see if the file exists in uncompressed form
1085      */
1086     *ret_name = name;
1087     if (access (name, F_OK) == -1)
1088       {
1089         /*
1090          * get a temporary name
1091          */
1092         (void) tmpnam (tmpName);
1093
1094         /*
1095          * malloc memory for the dot Z file name.
1096          */
1097         inFile = (char *) malloc (strlen (name) + 3);
1098         if (inFile != NULL)
1099           {
1100             /*
1101              * make the dot Z file
1102              */
1103             strcpy (inFile, name);
1104             strcat (inFile, ".Z");
1105
1106             /*
1107              * do the uncompress
1108              */
1109             result = _DtHelpCeUncompressFile (inFile, tmpName);
1110             free (inFile);
1111
1112             if (result != 0)
1113               {
1114                 errno = ENOENT;
1115                 return -1;
1116               }
1117
1118             *ret_name = strdup (tmpName);
1119             if (*ret_name == NULL)
1120               {
1121                 errno = CEErrorMalloc;
1122                 return -1;
1123               }
1124           }
1125         else
1126           {
1127             errno = CEErrorMalloc;
1128             return -1;
1129           }
1130       }
1131
1132     return result;
1133 }
1134
1135 /******************************************************************************
1136  * Function:    int _DtHelpCeCompressPathname (char *basePath)
1137  *
1138  * Parameters:  basePath        Specifies the path for the file possibily
1139  *                              containing /./, //, and /../.
1140  *
1141  * Return Value:        0 for success, -1 for failure.
1142  *                      The number of bytes in basePath will be less than or
1143  *                      equal to the number of bytes in basePath when passed
1144  *                      in.
1145  *
1146  * errno Values:        EINVAL
1147  *
1148  * Purpose:     This function compresses directory changes found
1149  *              in a file name path.
1150  *
1151  ******************************************************************************/
1152 int
1153 _DtHelpCeCompressPathname ( char        *basePath )
1154 {
1155     int    len;
1156     int    result;
1157     short  char1;
1158     short  char2;
1159     short  char3;
1160     char  *ptr     = basePath;
1161     char  *prevPtr = NULL;
1162
1163     if (basePath == NULL || *basePath != '/')
1164       {
1165         errno = EINVAL;
1166         return -1;
1167       }
1168
1169     do
1170       {
1171         /*
1172          * for multi-byte environments, check how far single bytes extend.
1173          */
1174         char1 = False;
1175         char2 = False;
1176         char3 = False;
1177         if (MB_CUR_MAX == 1 || mblen (&ptr[1], MB_CUR_MAX) == 1)
1178           {
1179             char1 = True;
1180             if (MB_CUR_MAX == 1 || mblen (&ptr[2], MB_CUR_MAX) == 1)
1181               {
1182                 char2 = True;
1183                 if (MB_CUR_MAX == 1 || mblen (&ptr[3], MB_CUR_MAX) == 1)
1184                     char3 = True;
1185               }
1186           }
1187
1188         /*
1189          * check for //
1190          */
1191         if (char1 == True && ptr[1] == '/')
1192             strcpy (ptr, (ptr + 1));
1193
1194         /*
1195          * check for /./
1196          */
1197         else if (char2 == True && ptr[1] == '.' && ptr[2] == '/')
1198             strcpy (ptr, (ptr + 2));
1199
1200         /*
1201          * check for /../
1202          */
1203         else if (char3 == True && strncmp (&ptr[1], "../", 3) == 0)
1204           {
1205             /*
1206              * if at the top of the path, just ignore the extra
1207              * directory change.
1208              */
1209             if (prevPtr == NULL)
1210                 strcpy (ptr, (ptr + 3));
1211             else
1212               {
1213                 /*
1214                  * compress the /../
1215                  */
1216                 strcpy (prevPtr, (ptr + 3));
1217
1218                 /*
1219                  * reset the current pointer
1220                  */
1221                 ptr    = prevPtr;
1222
1223                 /*
1224                  * find the previous slash
1225                  */
1226                 *ptr   = '\0';
1227                 result = _DtHelpCeStrrchr(basePath,Slash,MB_CUR_MAX,&prevPtr);
1228                 if (result == -1)
1229                     return -1;
1230
1231                 /*
1232                  * if there is no previous slash, set the pointer to
1233                  * indicate that we're at the top of the path (NULL).
1234                  */
1235                 if (result != 0)
1236                     prevPtr = NULL;
1237
1238                 /*
1239                  * restore the slash (or null byte)
1240                  */
1241                 *ptr = '/';
1242               }
1243           }
1244         else
1245           {
1246             /*
1247              * remember this slash for /../ directory changes
1248              */
1249             prevPtr = ptr;
1250
1251             /*
1252              * skip this slash, and find the next one.
1253              */
1254             ptr++;
1255             result = _DtHelpCeStrcspn (ptr, "/", MB_CUR_MAX, &len);
1256
1257             /*
1258              * if we run into invalid data, error
1259              */
1260             if (result == -1)
1261                 return -1;
1262
1263             ptr += len;
1264           }
1265
1266       } while (*ptr != '\0');
1267
1268     return (0);
1269 }
1270
1271 /******************************************************************************
1272  * Function:    char *_DtHelpCeTracePathName (char *path)
1273  *
1274  * Parameters:
1275  *               path   Specifies the a path to trace and compress
1276  *
1277  * Return Value:        The new string if successful, NULL otherwise.
1278  *                      The new string is owned by the caller and contains
1279  *                      an absolute pathname.
1280  *
1281  * errno Values:        EINVAL                  Illegal parameter specified.
1282  *                      getcwd(2)               errno set via a getcwd call.
1283  *                      readlink(2)             errno set via a readlink call.
1284  *                      DtErrorMalloc
1285  *                      DtErrorExceedMaxSize   The new path will exceed
1286  *                                              max_size.
1287  *                      DtErrorIllegalPath     The compression will required
1288  *                                              the path to change to a parent
1289  *                                              directory beyond the beginning
1290  *                                              of basePath.
1291  *
1292  * Purpose:     This function is called to trace the path of a file.
1293  *              It can contain symbolic links, //, /./, and /../.
1294  *
1295  ******************************************************************************/
1296 char *
1297 _DtHelpCeTracePathName (char *path)
1298 {
1299     int     result;
1300     int     len;
1301     char    c;
1302     char   *ptr;
1303     char   *prev;
1304     char    newPath  [2 * MAXPATHLEN + 2];
1305     char    linkPath [MAXPATHLEN + 2];
1306     char    tempPath [MAXPATHLEN + 2];
1307
1308     if (path == NULL || *path == '\0')
1309       {
1310         errno = EINVAL;
1311         return NULL;
1312       }
1313
1314     /*
1315      * initialize the new path
1316      */
1317     newPath[0] = '\0';
1318
1319     /*
1320      * if the path passed in does not start with a slash,
1321      * get the current working directory and append the path to it.
1322      */
1323     if ((MB_CUR_MAX == 1 || mblen(path, MB_CUR_MAX) == 1) && *path != '/')
1324       {
1325         if (getcwd (newPath, MAXPATHLEN) == NULL)
1326             return NULL;
1327
1328         strcat (newPath, "/");
1329       }
1330
1331     /*
1332      * put the path in the working path buffer (or append it to
1333      * the current working directory).
1334      */
1335     strcat (newPath, path);
1336
1337     /*
1338      * Compress out the slashes and directory changes.
1339      */
1340     if (_DtHelpCeCompressPathname (newPath) != 0)
1341         return NULL;
1342
1343     ptr = newPath;
1344     do
1345       {
1346         /*
1347          * point to the first character of the next directory
1348          */
1349         prev = ptr + 1;
1350
1351         /*
1352          * get the next slash after that
1353          */
1354         result = _DtHelpCeStrcspn (prev, "/", MB_CUR_MAX, &len);
1355         if (result == -1)
1356             return NULL;
1357
1358         /*
1359          * Found either a slash or a null byte.
1360          * place the string terminator at this point
1361          */
1362         ptr  = prev + len;
1363         c    = *ptr;
1364         *ptr = '\0';
1365
1366         /*
1367          * find out if this path is a symbolic link
1368          */
1369         result = readlink (newPath, linkPath, MAXPATHLEN);
1370
1371         /*
1372          * replace the slash (or null byte).
1373          */
1374         *ptr = c;
1375
1376         /*
1377          * check for the result of the readlink call
1378          */
1379         if (result == -1)
1380           {
1381             /*
1382              * if this was NOT a symbolic link, errno should be EINVAL
1383              */
1384             if (errno != EINVAL)
1385                 return NULL;
1386           }
1387         else
1388           {
1389             /*
1390              * put the null byte on the end of the symbolic link string.
1391              */
1392             linkPath [result] = '\0';
1393
1394             /*
1395              * Save the rest of the string that we haven't processed
1396              * for tacking on after the new link path has been
1397              * dropped into the path.
1398              */
1399             strcpy (tempPath, ptr);
1400
1401             /*
1402              * is it an absolute path? Simply replace the path
1403              * being search with the new link path.
1404              */
1405             if (*linkPath == '/')
1406                 strcpy (newPath, linkPath);
1407             else
1408               {
1409                 /*
1410                  * this is a relative link.
1411                  * prev is looking at the first character of this directory.
1412                  * replace with the link.
1413                  */
1414                 strcpy (prev, linkPath);
1415               }
1416
1417             /*
1418              * now tack on the rest of the name
1419              */
1420             strcat (newPath, tempPath);
1421
1422             /*
1423              * compress out the directory changes.
1424              */
1425             if (_DtHelpCeCompressPathname (newPath) != 0)
1426                 return NULL;
1427
1428             /*
1429              * start again from the top, until we have a clean path
1430              */
1431             ptr = newPath;
1432           }
1433
1434       } while (*ptr != '\0');
1435
1436     return (strdup (newPath));
1437 }
1438
1439 /******************************************************************************
1440  * Function:    char *_DtHelpCeTraceFilenamePath (char *file_path)
1441  *
1442  * Parameters:
1443  *               file_path      Specifies the a path to trace and compress
1444  *
1445  * Return Value:        The new string if successful, NULL otherwise.
1446  *                      The new string is owned by the caller and
1447  *                      contains an absolute filename path.
1448  *
1449  * errno Values:        EINVAL                  Illegal parameter specified.
1450  *                      getcwd(2)               errno set via a getcwd call.
1451  *                      readlink(2)             errno set via a readlink call.
1452  *                      DtErrorMalloc
1453  *                      DtErrorExceedMaxSize   The new path will exceed
1454  *                                              max_size.
1455  *                      DtErrorIllegalPath     The compression will required
1456  *                                              the path to change to a parent
1457  *                                              directory beyond the beginning
1458  *                                              of basePath.
1459  *
1460  * Purpose:     This function is called to trace a filename path.
1461  *              It can contain symbolic links, //, /./, and /../.
1462  *
1463  ******************************************************************************/
1464 char *
1465 _DtHelpCeTraceFilenamePath (char *file_path)
1466 {
1467     int     result;
1468     int     done = False;
1469     char   *newPath;
1470     char   *oldName;
1471     char   *namePlace;
1472     char    workName [MAXPATHLEN + 2];
1473     char    newName  [MAXPATHLEN + 2];
1474     char    linkName [MAXPATHLEN + 2];
1475
1476     if (file_path == NULL || *file_path == '\0')
1477       {
1478         errno = EINVAL;
1479         return NULL;
1480       }
1481
1482     workName[0] = '\0';
1483     if ((MB_CUR_MAX == 1 || mblen(file_path, MB_CUR_MAX) == 1)
1484                                                         && *file_path != '/')
1485       {
1486         if (getcwd(workName, MAXPATHLEN) == NULL)
1487            return NULL;
1488
1489         strcat(workName, "/");
1490       }
1491
1492     strcat (workName, file_path);
1493
1494     do
1495       {
1496         /*
1497          * find and save the old filename
1498          */
1499         result = _DtHelpCeStrrchr(workName, Slash, MB_CUR_MAX, &oldName);
1500         if (result == -1)
1501             return NULL;
1502
1503         /*
1504          * terminate the path
1505          */
1506         *oldName = '\0';
1507
1508         /*
1509          * trace the path, resolving the symbolic links
1510          * and directory changes. If /filename given,
1511          * skip the path tracing.
1512          */
1513         newName[0] = '\0';
1514         if (workName[0] != '\0')
1515           {
1516             newPath = _DtHelpCeTracePathName(workName);
1517             if (newPath == NULL)
1518                 return NULL;
1519
1520             /*
1521              * copy the new path and free the allocated copy
1522              */
1523             strcpy (newName, newPath);
1524             free (newPath);
1525           }
1526
1527         /*
1528          * replace the slash
1529          */
1530         *oldName = '/';
1531
1532         /*
1533          * now append the slash and filename (pointed to by oldName)
1534          * onto the end of the new path.
1535          */
1536         namePlace = newName + strlen (newName);
1537         strcpy (namePlace, oldName);
1538
1539         /*
1540          * See if the absolute path/filename is a symbolic link.
1541          */
1542         result = readlink (newName, linkName, MAXPATHLEN);
1543         if (result == -1)
1544           {
1545             if (errno != EINVAL)
1546                 return NULL;
1547
1548             done = True;
1549           }
1550         else
1551           {
1552             /*
1553              * put the null byte on the end of the symbolic
1554              * link string.
1555              */
1556             linkName [result] = '\0';
1557             if (*linkName == '/')
1558                 strcpy (newName, linkName);
1559             else
1560               {
1561                 /*
1562                  * overwrite the filename with the link
1563                  * but don't overwrite the slash.
1564                  */
1565                 strcpy ((namePlace + 1), linkName);
1566               }
1567
1568             /*
1569              * make a copy of the new name to work on
1570              */
1571             strcpy (workName, newName);
1572           }
1573       } while (!done);
1574
1575     return (strdup (newName));
1576 }
1577
1578
1579 /******************************************************************************
1580  *                    Core Engine Semi-Public Functions
1581  ******************************************************************************/
1582 /*****************************************************************************
1583  * Function: char *_DtHelpCeGetVolumeName (_DtHelpVolumeHdl volume)
1584  *
1585  * Parameters:
1586  *
1587  * Returns:     ptr to the name of the volume, NULL otherwise.
1588  *
1589  * Purpose:     Get the fully qualified volume name.
1590  *
1591  *****************************************************************************/
1592 char *
1593 _DtHelpCeGetVolumeName (
1594     _DtHelpVolumeHdl  volume_handle)
1595 {
1596     char *volFile;
1597
1598     _DtHelpProcessLock();
1599     volFile = ((_DtHelpVolume)volume_handle)->volFile;
1600     _DtHelpProcessUnlock();
1601     return volFile;
1602
1603 } /* End __DtHelpCeGetVolumeName */
1604
1605 /*****************************************************************************
1606  * Function: int _DtHelpCeFileOpenAndSeek (char *name, int offset, int fildes,
1607  *                                                      BufFilePtr *ret_file)
1608  *
1609  * Parameters:  name            Specifies the file to open.
1610  *              offset          Specifies location within the file to seek to.
1611  *
1612  * Returns:     0 if successful, -1 if a failure occurs
1613  *
1614  * errno Values:        EINVAL          Specifies an invalid parameter was
1615  *                                      used.
1616  *                      CEErrorFileSeek
1617  *                                      Specifies the seek offset was invalid.
1618  *
1619  * Purpose:     Open a file and seek to a specific place.
1620  *
1621  *****************************************************************************/
1622 int
1623 _DtHelpCeFileOpenAndSeek (
1624         char            *name,
1625         int              offset,
1626         int              fd,
1627         BufFilePtr      *ret_file,
1628         time_t          *ret_time)
1629 {
1630     unsigned char fileMagic[4];
1631     int           bytesRead;
1632     int           result = 0;
1633     int           tmpFd;
1634     struct stat   buf;
1635
1636     /*
1637      * Get the file descriptor of the uncompressed file
1638      */
1639     tmpFd = fd;
1640     if (fd == -1)
1641       {
1642         result = FileOpenRtnFd (name, &tmpFd);
1643         if (result == -1)
1644             return -1;
1645       }
1646
1647     if (ret_time != NULL)
1648       {
1649         (void) fstat(tmpFd, &buf);
1650         *ret_time = buf.st_mtime;
1651       }
1652
1653     /*
1654      * make sure we don't go past the end of the file
1655      */
1656     result = lseek (tmpFd, 0, SEEK_END);
1657     if (result != -1)
1658       {
1659         if (result > offset)
1660             result = lseek (tmpFd, offset, SEEK_SET);
1661         else
1662           {
1663             result = -1;
1664             errno = CEErrorFileSeek;
1665           }
1666       }
1667
1668     if (result == -1)
1669       {
1670         if (fd == -1)
1671             close (tmpFd);
1672         return -1;
1673       }
1674
1675     bytesRead = read(tmpFd, fileMagic, 4);
1676     if (bytesRead != 4)
1677       { /* something's wrong in reading the file */
1678         if (fd == -1)
1679             close (tmpFd);
1680         return -1;
1681       }
1682
1683     if (!*fileMagic)
1684       { /* started with compressed file magic number */
1685
1686         CECompressInfoPtr myInfo;
1687         BufFilePtr        inputRaw;
1688
1689         /*
1690          * allocate the private information
1691          */
1692         myInfo = (CECompressInfoPtr) malloc(sizeof(CECompressInfo));
1693         if (myInfo == NULL)
1694           {
1695             if (fd == -1)
1696                 close (tmpFd);
1697             errno = CEErrorMalloc;
1698             return -1;
1699           }
1700
1701         /*
1702          * set the information
1703          * set the size to the maximum number of bytes we
1704          * want to read.
1705          */
1706         myInfo->fd   = tmpFd;
1707         myInfo->size =
1708           (((fileMagic[1] * 256) + fileMagic[2]) * 256) + fileMagic[3];
1709
1710         /*
1711          * start with raw functionality
1712          */
1713         inputRaw = _DtHelpCeBufFileRdRawZ(myInfo);
1714         if (inputRaw == NULL)
1715           {
1716             if (fd == -1)
1717                 close (tmpFd);
1718             return -1;
1719           }
1720
1721         *ret_file = _DtHelpCeBufFilePushZ(inputRaw);
1722         if (*ret_file == NULL)
1723           {
1724             _DtHelpCeBufFileClose(inputRaw, (fd == -1 ? True : False));
1725             return -1;
1726           }
1727       }
1728     else
1729       {
1730         /*
1731          * not a compressed file, back up the four bytes we read
1732          */
1733         result = lseek (tmpFd, offset, SEEK_SET);
1734         if (result == -1)
1735           {
1736             if (fd == -1)
1737                 close (tmpFd);
1738             return -1;
1739           }
1740
1741         /*
1742          * read with raw functionality
1743          */
1744         *ret_file = _DtHelpCeBufFileRdWithFd(tmpFd);
1745         if (*ret_file == NULL)
1746           {
1747             if (fd == -1)
1748                 close (tmpFd);
1749             return -1;
1750           }
1751       }
1752
1753     return 0;
1754
1755 } /* End of _DtHelpCeFileOpenAndSeek */
1756 /******************************************************************************
1757  *                     Core Engine Public Functions
1758  ******************************************************************************/
1759 /******************************************************************************
1760  * Function:    int _DtHelpOpenVolume (char *volFile, _DtHelpVolume *retVol);
1761  *
1762  * Parameters:  volFile         Specifies the name of the Help Volume file
1763  *                              to load.
1764  *
1765  *              retVol          Returns the handle to the loaded volume.
1766  *                              If a volume is opened several times, the
1767  *                              same handle will be returned each time.
1768  *
1769  * Return Value:                0 if successful, -1 if a failure occurred.
1770  *
1771  * errno Values:        EINVAL                  Illegal parameter specified.
1772  *                      getcwd(2)               errno set via a getcwd call.
1773  *                      readlink(2)             errno set via a readlink call.
1774  *                      CEErrorMalloc
1775  *                      CEErrorExceedMaxSize    The new path will exceed
1776  *                                              max_size.
1777  *                      CEErrorIllegalPath      The compression will required
1778  *                                              the path to change to a parent
1779  *                                              directory beyond the beginning
1780  *                                              of basePath.
1781  *                      CEErrorIllegalDatabaseFile
1782  *                                              Specifies that 'volFile' is
1783  *                                              an illegal database file.
1784  *
1785  *
1786  * Purpose:     This function must be called to open a Help Volume file
1787  *              before any of the information in the volume can be
1788  *              accessed. 
1789  *
1790  ******************************************************************************/
1791 int 
1792 _DtHelpOpenVolume (
1793     char        *volFile, 
1794     _DtHelpVolumeHdl  *retVol)
1795 {
1796     int     result  = 0;
1797     _DtHelpVolume vol, prevVol;
1798
1799     _DtHelpProcessLock();
1800
1801     if (volFile == NULL || retVol == NULL)
1802       {
1803         errno = EINVAL;
1804         _DtHelpProcessUnlock();
1805         return -1;
1806       }
1807
1808     /*
1809      * follow all the symbolic links and get the absolute path and filename.
1810      */
1811     volFile = _DtHelpCeTraceFilenamePath(volFile);
1812     if (volFile == NULL)
1813       {
1814         _DtHelpProcessUnlock();
1815         return -1;
1816       }
1817
1818     /* Search the volume chain to see if it is already open. */
1819     prevVol = NULL;
1820     vol = volChain; 
1821     while (vol != NULL && strcmp (vol->volFile, volFile))
1822       {
1823         prevVol = vol;
1824         vol     = vol->nextVol;
1825       }
1826
1827     if (vol)
1828       {
1829         vol->openCount++;
1830         free(volFile);
1831       }
1832     else /* if (vol == NULL) */
1833       {
1834         /* If it isn't open, open it and insert it in the chain. */
1835         result = VolumeLoad (volFile, &vol);
1836         if (result == 0)
1837           {
1838             if (prevVol == NULL)
1839                 volChain = vol;
1840             else
1841                 prevVol->nextVol = vol;
1842           }
1843       }
1844
1845     /* Return the volume handle and a status indicating success/failure. */
1846     *retVol = (_DtHelpVolumeHdl) vol;
1847     _DtHelpProcessUnlock();
1848     return result;
1849 }
1850
1851 /******************************************************************************
1852  * Function:    int _DtHelpCeUpVolumeOpenCnt (_DtHelpVolumeHdl vol);
1853  *
1854  * Parameters:  vol     Specifies the loaded volume.
1855  *
1856  * Return Value: 0 if successful, -1 if a failure occurs
1857  *
1858  * errno Values:        EINVAL          'vol' was NULL, no volumes open or
1859  *                                      'vol' does not exist.
1860  *
1861  * Purpose:     When the volume is no longer needed, it should be
1862  *              closed with this call.  If the volume has been opened
1863  *              several times, closing it will just decrement the 
1864  *              reference count.  When it has been closed as many times
1865  *              as it was opened, the memory it is using will be freed
1866  *              and any handles to the volume will be invalid.
1867  *
1868  ******************************************************************************/
1869 int 
1870 _DtHelpCeUpVolumeOpenCnt (
1871      _DtHelpVolumeHdl   volume)
1872 {
1873     _DtHelpVolume prevVol;
1874     _DtHelpVolume vol = (_DtHelpVolume)volume;
1875
1876     _DtHelpProcessLock();
1877
1878     if (vol == NULL || volChain == NULL)
1879       {
1880         errno = EINVAL;
1881         _DtHelpProcessUnlock();
1882         return (-1);
1883      }
1884
1885     /*
1886      * check to see if this volume is in our chain
1887      */
1888     if (vol != volChain)
1889       {
1890         if (CheckVolList (vol, &prevVol) == -1)
1891           {
1892             errno = EINVAL;
1893             _DtHelpProcessUnlock();
1894             return (-1);
1895           }
1896       }
1897
1898     /*
1899      * increment it's usage count.
1900      */
1901     vol->openCount++;
1902     _DtHelpProcessUnlock();
1903     return (0);
1904 }
1905
1906 /******************************************************************************
1907  * Function:    int _DtHelpCloseVolume (_DtHelpVolumeHdl vol);
1908  *
1909  * Parameters:  vol     Specifies the loaded volume.
1910  *
1911  * Return Value: 0 if successful, -1 if a failure occurs
1912  *
1913  * errno Values:        EINVAL          'vol' was NULL, no volumes open or
1914  *                                      'vol' does not exist.
1915  *
1916  * Purpose:     When the volume is no longer needed, it should be
1917  *              closed with this call.  If the volume has been opened
1918  *              several times, closing it will just decrement the 
1919  *              reference count.  When it has been closed as many times
1920  *              as it was opened, the memory it is using will be freed
1921  *              and any handles to the volume will be invalid.
1922  *
1923  ******************************************************************************/
1924 int 
1925 _DtHelpCloseVolume (
1926      _DtHelpVolumeHdl   volume)
1927 {
1928     _DtHelpVolume prevVol;
1929     _DtHelpVolume vol = (_DtHelpVolume)volume;
1930
1931     _DtHelpProcessLock();
1932
1933     if (vol == NULL || volChain == NULL)
1934       {
1935         errno = EINVAL;
1936         _DtHelpProcessUnlock();
1937         return (-1);
1938       }
1939
1940     /*
1941      * check to see if this volume is in our chain
1942      */
1943     if (vol != volChain)
1944       {
1945         if (CheckVolList (vol, &prevVol) == -1)
1946           {
1947             errno = EINVAL;
1948             _DtHelpProcessUnlock();
1949             return (-1);
1950           }
1951       }
1952
1953     /*
1954      * decrement it's usage count.
1955      */
1956     vol->openCount--;
1957     if (vol->openCount == 0)
1958       {
1959         /* The volume is no longer needed.  Unlink it from the chain
1960            and free it. */
1961
1962         if (vol == volChain) 
1963             volChain = volChain->nextVol;
1964
1965         else
1966             prevVol->nextVol = vol->nextVol;
1967
1968         VolumeUnload (vol);
1969       }
1970
1971     _DtHelpProcessUnlock();
1972     return (0);
1973 }
1974
1975 /*****************************************************************************
1976  * Function: int _DtHelpCeGetTopTopicId (_DtHelpVolume vol,
1977  *                                      char **ret_idString)
1978  *
1979  * Parameters:  vol             Specifies the loaded volume
1980  *              ret_idString    Returns the location ID of the
1981  *                              the top level topic.
1982  *
1983  * Memory own by caller:
1984  *              ret_idString
1985  *
1986  * Returns:     True for success, False if a failure occurs.
1987  *
1988  * errno Values:        EINVAL          Specifies an invalid parameter was
1989  *                                      used.
1990  *                      CEErrorMissingTopTopicRes
1991  *                                      Specifies that the 'TopTopic/topTopic'
1992  *                                      resource is missing from the database.
1993  *                      CEErrorMalloc
1994  *
1995  * Purpose:     Get the information to access the top level topic.
1996  *
1997  *****************************************************************************/
1998 int
1999 _DtHelpCeGetTopTopicId (
2000         _DtHelpVolumeHdl        volume,
2001         char            **ret_idString )
2002 {
2003     int   found = False;
2004     _DtHelpVolume vol = (_DtHelpVolume)volume;
2005
2006     _DtHelpProcessLock();
2007
2008     if (vol == NULL || ret_idString == NULL || CheckVolList(vol, NULL) == -1)
2009         errno = EINVAL;
2010     else
2011       {
2012         /*
2013          * What type of volume is it?
2014          */
2015         if (vol->sdl_flag == False)
2016             (void) _DtHelpCeGetCcdfTopTopic(vol, ret_idString);
2017         else
2018             *ret_idString = _DtHelpCeGetSdlHomeTopicId((_DtHelpVolumeHdl) vol);
2019
2020         if (*ret_idString != NULL)
2021             *ret_idString = strdup(*ret_idString);
2022
2023         if (*ret_idString != NULL)
2024             found = True;
2025       }
2026
2027     _DtHelpProcessUnlock();
2028     return found;
2029
2030 }  /* End _DtHelpCeGetTopTopicId */
2031
2032 /*****************************************************************************
2033  * Function: int _DtHelpCeFindId (_DtHelpVolume vol, char *target_id,
2034  *                                      int fd,
2035  *                                      char *ret_name, int *ret_offset)
2036  *
2037  * Parameters:  vol             Specifies the loaded volume
2038  *              target_id       Specifies target location ID
2039  *              fd              Specifies the locked file descriptor.
2040  *              ret_name        Returns a null terminated string
2041  *                              containing a fully qualified path to
2042  *                              the file that contains 'target_id'.
2043  *              ret_offset      Returns the offset into 'ret_name'
2044  *                              to the topic that contains 'target_id'.
2045  *
2046  * Memory own by caller:
2047  *              ret_name
2048  *
2049  * Returns:     True if successful, False if a failure occurs
2050  *
2051  * errno Values:        EINVAL          Specifies an invalid parameter was
2052  *                                      used.
2053  *                      CEErrorMalloc
2054  *                      CEErrorMissingFilenameRes
2055  *                                      Specifies that the 'Filename/filename'
2056  *                                      resource for 'topic' does not exist.
2057  *                      CEErrorMissingFileposRes
2058  *                                      If the resource is not in the
2059  *                                      database or if the resource NULL.
2060  *                      CEErrorLocIdNotFound
2061  *                                      Specifies that 'locId' was not
2062  *                                      found.
2063  *
2064  * Purpose:     Find which topic contains a specified locationID.
2065  *
2066  *****************************************************************************/
2067 int
2068 _DtHelpCeFindId (
2069         _DtHelpVolumeHdl        volume,
2070         char            *target_id,
2071         int              fd,
2072         char            **ret_name,
2073         int             *ret_offset )
2074 {
2075     _DtHelpVolume vol = (_DtHelpVolume)volume;
2076     int result;
2077
2078     _DtHelpProcessLock();
2079
2080     /*
2081      * check the parameters
2082      */
2083     if (vol == NULL || target_id == NULL || ret_name == NULL ||
2084                         ret_offset == NULL || CheckVolList (vol, NULL) == -1)
2085       {
2086         errno = EINVAL;
2087         _DtHelpProcessUnlock();
2088         return False;
2089       }
2090
2091     /*
2092      * What type of volume is it?
2093      */
2094     if (vol->sdl_flag == False)
2095       {
2096         result = _DtHelpCeFindCcdfId(vol, target_id, ret_name, ret_offset);
2097       }
2098     else
2099       {
2100         result = _DtHelpCeFindSdlId(vol, target_id, fd, ret_name, ret_offset);
2101       }
2102
2103     _DtHelpProcessUnlock();
2104     return result;
2105
2106 }  /* End _DtHelpCeFindId */
2107
2108 /*****************************************************************************
2109  * Function: int _DtHelpCeGetKeywordList (_DtHelpVolume vol, char ***ret_keywords)
2110  *
2111  * Parameters:  vol             Specifies the loaded volume
2112  *              ret_keywords    Returns a NULL-terminated string array
2113  *                              containing the sorted list of keywords in the
2114  *                              volume.  This array is NOT owned by the caller
2115  *                              and should only be read or copied.
2116  *
2117  * Returns:     The count of keywords associated with the volume if successful.
2118  *              -1 if a failure occurs;
2119  *
2120  * errno Values:        EINVAL          Specifies an invalid parameter was
2121  *                                      used.
2122  *                      CEErrorMalloc
2123  *                      CEErrorIllegalDatabaseFile
2124  *                                      Specifies that the keyword file is
2125  *                                      invalid or corrupt.
2126  *                      CEErrorMissingKeywordsRes
2127  *                                      Specifies that the keyword file does
2128  *                                      not contain the 'Keywords/keywords'
2129  *                                      resource or the resource is NULL
2130  *
2131  * Purpose:     Get the list of keywords contained in a volume.
2132  *
2133  *****************************************************************************/
2134 int
2135 _DtHelpCeGetKeywordList (
2136         _DtHelpVolumeHdl        volume,
2137         char            ***ret_keywords )
2138 {
2139     int       nameCount = -1;
2140     _DtHelpVolume vol = (_DtHelpVolume)volume;
2141
2142     if (vol == NULL || ret_keywords == NULL || CheckVolList (vol, NULL) == -1)
2143         errno = EINVAL;
2144     else if (GetVolumeKeywords (vol, ret_keywords) == 0)
2145       {
2146         nameCount = 0;
2147         while (*ret_keywords && (*ret_keywords)[nameCount])
2148             nameCount++;
2149       }
2150
2151     return nameCount;
2152
2153 }  /* End _DtHelpCeGetKeywordList */
2154
2155 /*****************************************************************************
2156  * Function: int _DtHelpCeFindKeyword (_DtHelpVolume vol, char *target, char ***ret_ids)
2157  *
2158  * Parameters:  vol             Specifies the loaded volume
2159  *              target          The target keyword.
2160  *              ret_ids         Returns a null terminated list of location
2161  *                              ids associated with the target keyword.
2162  *
2163  * Returns:     The count of ids associated with the keyword if successful.
2164  *              -1 if a failure occurs;
2165  *
2166  * errno Values:        EINVAL          Specifies an invalid parameter was
2167  *                                      used.
2168  *                      CEErrorNoKeywordList
2169  *                                      Specifies that the volume does not
2170  *                                      have a keyword list.
2171  *                      CEErrorIllegalKeyword
2172  *                                      Specifies that 'target' was not
2173  *                                      found.
2174  *                      CEErrorMalloc
2175  *                      CEErrorIllegalDatabaseFile
2176  *                                      Specifies that the keyword file is
2177  *                                      invalid or corrupt.
2178  *                      CEErrorMissingKeywordsRes
2179  *                                      Specifies that the keyword file does
2180  *                                      not contain the 'Keywords/keywords'
2181  *                                      resource or the resource is NULL
2182  *
2183  * Purpose:     Get the list of location ids associated with a keyword
2184  *
2185  *****************************************************************************/
2186 int
2187 _DtHelpCeFindKeyword (
2188         _DtHelpVolumeHdl        volume,
2189         char            *target,
2190         char            ***ret_ids )
2191 {
2192     int       nameCount = -1;
2193     _DtHelpVolume vol = (_DtHelpVolume)volume;
2194
2195     if (vol == NULL || target == NULL || ret_ids == NULL ||
2196                                         CheckVolList (vol, NULL) == -1)
2197         errno = EINVAL;
2198     else if (GetKeywordTopics (vol, target, ret_ids) == 0)
2199       {
2200         nameCount = 0;
2201         while (*ret_ids && (*ret_ids)[nameCount])
2202             nameCount++;
2203       }
2204
2205     return nameCount;
2206
2207 }  /* End _DtHelpCeFindKeyword */
2208
2209 /*****************************************************************************
2210  * Function: int _DtHelpGetTopicTitle (
2211  *                                      _DtHelpVolumeHdl volume,
2212  *                                      char *id, char **ret_title)
2213  *
2214  * Parameters:  volume          Specifies the volume containing the id.
2215  *              id              Specifies the id for the topic desired.
2216  *              ret_title       Returns a null terminated string containing
2217  *                              the title.
2218  *
2219  * Memory own by caller:
2220  *              ret_title
2221  *
2222  * Returns:     0 if successful, -2 if didn't find the id,
2223  *              otherwise -1.
2224  *
2225  * errno Values:        EINVAL          Specifies an invalid parameter was
2226  *                                      used.
2227  *
2228  * Purpose:     Get the title of a topic.
2229  *
2230  *****************************************************************************/
2231 int
2232 _DtHelpGetTopicTitle (
2233     _DtHelpVolumeHdl          volume,
2234     char                 *id,
2235     char                **ret_title)
2236 {
2237     int            result;
2238     char          *abbrevTitle;
2239     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2240
2241     if (volume == NULL || id == NULL ||
2242                         CheckVolList (vol, NULL) == -1 || ret_title == NULL)
2243       {
2244         errno = EINVAL;
2245         return -1;
2246       }
2247
2248     /*
2249      * Try to get the title via the <TOPIC> and <ABBREV> tags.
2250      */
2251     result = GetTopicTitleAndAbbrev(vol, id, ret_title, &abbrevTitle);
2252     if (result == 0)
2253       {
2254         /*
2255          * If we have a abbreviated title, return it instead.
2256          */
2257         if (abbrevTitle)
2258           {
2259             if (*ret_title)
2260                 free ((char *) *ret_title);
2261             *ret_title = abbrevTitle;
2262           }
2263       }
2264
2265     return result;
2266
2267 }  /* End _DtHelpGetTopicTitle */
2268
2269 /*****************************************************************************
2270  * Function: int _DtHelpCeMapTargetToId (_DtHelpVolume vol,
2271  *                                      char *target_id,
2272  *                                      char *ret_id)
2273  *
2274  * Parameters:  vol             Specifies the loaded volume
2275  *              target_id       Specifies target location ID
2276  *              ret_id          Returns the id containing the target_id.
2277  *                              This memory *IS NOT* owned by the caller.
2278  *
2279  * Returns:     0 if successful, -1 if a failure occurs
2280  *
2281  * Purpose:     Find which topic contains a specified locationID.
2282  *
2283  *****************************************************************************/
2284 int
2285 _DtHelpCeMapTargetToId (
2286         _DtHelpVolumeHdl        volume,
2287         char            *target_id,
2288         char            **ret_id)
2289 {
2290     _DtHelpVolume vol = (_DtHelpVolume)volume;
2291     int result;
2292
2293     _DtHelpProcessLock();
2294
2295     /*
2296      * check the parameters
2297      */
2298     if (vol == NULL || target_id == NULL || ret_id == NULL ||
2299                                         CheckVolList (vol, NULL) == -1)
2300       {
2301         errno = EINVAL;
2302         _DtHelpProcessUnlock();
2303         return -1;
2304       }
2305
2306     /*
2307      * What type of volume is it?
2308      */
2309     if (vol->sdl_flag == False)
2310       {
2311         result = _DtHelpCeMapCcdfTargetToId(vol, target_id, ret_id);
2312       }
2313     else
2314       {
2315         result = _DtHelpCeMapIdToSdlTopicId(vol, target_id, ret_id);
2316       }
2317
2318     _DtHelpProcessUnlock();
2319     return result;
2320
2321 }  /* End _DtHelpCeMapTargetToId */
2322
2323 /*****************************************************************************
2324  * Function: char * _DtHelpGetVolumeLocale (_DtHelpVolume vol)
2325  *
2326  * Parameters:  vol             Specifies the loaded volume
2327  *
2328  * Returns:     The pointer to the locale string if successful. Otherwise
2329  *              NULL.
2330  *
2331  * Purpose:     Get the locale of the specified volume.
2332  *              Returns the locale in a unix specific format
2333  *              - locale[_ter][.charset] - This memory is owned by
2334  *              the caller.
2335  *
2336  *****************************************************************************/
2337 char *
2338 _DtHelpGetVolumeLocale (
2339         _DtHelpVolumeHdl        volume)
2340 {
2341     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2342     char *result;
2343
2344     _DtHelpProcessLock();
2345
2346     /*
2347      * check the parameters
2348      */
2349     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2350       {
2351         errno = EINVAL;
2352         _DtHelpProcessUnlock();
2353         return NULL;
2354       }
2355
2356     /*
2357      * What type of volume is it?
2358      */
2359     if (vol->sdl_flag == False)
2360       {
2361         result = _DtHelpCeGetCcdfVolLocale(vol);
2362       }
2363     else
2364       {
2365         result = _DtHelpCeGetSdlVolumeLocale(vol);
2366       }
2367
2368     _DtHelpProcessUnlock();
2369     return result;
2370
2371 }  /* End _DtHelpGetVolumeLocale */
2372
2373 /*****************************************************************************
2374  * Function: int _DtHelpCeGetDocStamp (_DtHelpVolumeHdl volume, char **ret_doc,
2375  *                                              char **ret_time)
2376  *
2377  * Parameters:  volume          Specifies the loaded volume
2378  *              ret_doc         Returns the doc id.
2379  *              ret_time        Returns the time stamp.
2380  *
2381  * Memory:      Caller owns the string in ret_doc and ret_time.
2382  *
2383  * Returns:     0 if successful, -2 if the volume does not contain
2384  *              one or the other, -1 if any other failure.
2385  *
2386  * Purpose:     Get doc id and time stamp of a volume.
2387  *
2388  *****************************************************************************/
2389 int
2390 _DtHelpCeGetDocStamp (
2391     _DtHelpVolumeHdl    volume,
2392     char                **ret_doc,
2393     char                **ret_time)
2394 {
2395     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2396     int result;
2397
2398     _DtHelpProcessLock();
2399
2400     /*
2401      * check the parameters
2402      */
2403     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2404       {
2405         errno = EINVAL;
2406         _DtHelpProcessUnlock();
2407         return 0;
2408       }
2409
2410     /*
2411      * What type of volume is it?
2412      */
2413     if (vol->sdl_flag == False)
2414       {
2415         result = _DtHelpCeGetCcdfDocStamp (vol, ret_doc, ret_time);
2416       }
2417     else
2418       {
2419         result = _DtHelpCeGetSdlDocStamp(vol, ret_doc, ret_time);
2420       }
2421
2422     _DtHelpProcessUnlock();
2423     return result;
2424
2425 }  /* End _DtHelpCeGetDocStamp */
2426
2427 /*****************************************************************************
2428  * Function: char * _DtHelpCeGetTopicChilren (_DtHelpVolumeHdl vol)
2429  *
2430  * Parameters:  vol             Specifies the loaded volume
2431  *              topic_id        Speicifes the topic id of which the
2432  *                              children are to be found.
2433  *              retTopics       Returns the null terminated array of
2434  *                              ids. This memory is owned by the caller
2435  *                              and must be freed.
2436  *
2437  * Returns:     > 0 if successful, -1 if failures.
2438  *
2439  * Purpose:     Get the children of a topic.
2440  *
2441  *****************************************************************************/
2442 int 
2443 _DtHelpCeGetTopicChildren (
2444     _DtHelpVolumeHdl   volume,
2445     char          *topic_id,
2446     char        ***retTopics)
2447 {
2448     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2449     int result;
2450
2451     _DtHelpProcessLock();
2452
2453     /*
2454      * check the parameters
2455      */
2456     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2457       {
2458         errno = EINVAL;
2459         _DtHelpProcessUnlock();
2460         return -1;
2461       }
2462
2463     /*
2464      * What type of volume is it?
2465      */
2466     if (vol->sdl_flag == False)
2467       {
2468         result = _DtHelpCeGetCcdfTopicChildren(volume, topic_id, retTopics);
2469       }
2470     else
2471       {
2472         result = _DtHelpCeGetSdlTopicChildren(volume, topic_id, retTopics);
2473       }
2474
2475     _DtHelpProcessUnlock();
2476     return result;
2477
2478 }  /* End _DtHelpCeGetTopicChildren */
2479
2480 /*****************************************************************************
2481  * Function: int _DtHelpCeGetVolumeFlag (_DtHelpVolumeHdl vol)
2482  *
2483  * Parameters:  vol             Specifies the loaded volume
2484  *
2485  * Returns:     0 if CCDF volume, 1 if SDL, -1 if failures.
2486  *
2487  * Purpose:     Determine the type of volume.
2488  *
2489  *****************************************************************************/
2490 int 
2491 _DtHelpCeGetVolumeFlag (
2492     _DtHelpVolumeHdl   volume)
2493 {
2494     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2495
2496     /*
2497      * check the parameters
2498      */
2499     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2500       {
2501         errno = EINVAL;
2502         return -1;
2503       }
2504
2505     /*
2506      * What type of volume is it?
2507      */
2508     return((int) vol->sdl_flag);
2509
2510 }  /* End _DtHelpCeGetVolumeFlag */
2511
2512 /*****************************************************************************
2513  * Function: int _DtHelpCeLockVolume (_DtHelpVolumeHdl vol)
2514  *
2515  * Parameters:  vol             Specifies the loaded volume
2516  *
2517  * Returns:     > 0 if successful, -1 if failures.
2518  *
2519  * Purpose:     Lock the volume so that it can't get change out from
2520  *              under the caller.
2521  *
2522  *****************************************************************************/
2523 int 
2524 _DtHelpCeLockVolume (
2525     _DtHelpVolumeHdl     volume,
2526     _DtHelpCeLockInfo   *lock_info)
2527 {
2528     struct stat    buf;
2529     _DtHelpVolume  vol = (_DtHelpVolume)volume;
2530
2531     _DtHelpProcessLock();
2532
2533     /*
2534      * check the parameters
2535      */
2536     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2537       {
2538         _DtHelpProcessUnlock();
2539         return -1;
2540       }
2541
2542     /*
2543      * lock it by opening it.
2544      */
2545     lock_info->fd = open(vol->volFile, O_RDONLY);
2546     if (lock_info->fd == -1)
2547       {
2548         _DtHelpProcessUnlock();
2549         return -1;
2550       }
2551
2552     (void) fstat(lock_info->fd, &buf);
2553     if (buf.st_mtime != vol->check_time)
2554       {
2555         if (RereadVolume(vol) != 0)
2556           {
2557             close(lock_info->fd);
2558             _DtHelpProcessUnlock();
2559             return -1;
2560           }
2561
2562         vol->check_time = buf.st_mtime;
2563       }
2564
2565     /*
2566      * Synthetic open
2567      */
2568     vol->openCount++;
2569     lock_info->volume = volume;
2570     _DtHelpProcessUnlock();
2571     return 0;
2572
2573 }  /* End _DtHelpCeLockVolume */
2574
2575 /*****************************************************************************
2576  * Function: int _DtHelpCeUnlockVolume (_DtHelpVolumeHdl vol)
2577  *
2578  * Parameters:  vol             Specifies the loaded volume
2579  *
2580  * Returns:     > 0 if successful, -1 if failures.
2581  *
2582  * Purpose:     Unlock the volume.
2583  *
2584  *****************************************************************************/
2585 int 
2586 _DtHelpCeUnlockVolume (
2587     _DtHelpCeLockInfo   lock_info)
2588 {
2589     _DtHelpVolume  vol = (_DtHelpVolume)(lock_info.volume);
2590
2591     _DtHelpProcessLock();
2592
2593     /*
2594      * check the parameters
2595      */
2596     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2597       {
2598         _DtHelpProcessUnlock();
2599         return -1;
2600       }
2601
2602     /*
2603      * check to see if it needs to be unlocked.
2604      */
2605     if (lock_info.fd != -1)
2606         close(lock_info.fd);
2607
2608     /*
2609      * Synthetic close
2610      */
2611     vol->openCount--;
2612     _DtHelpProcessUnlock();
2613     return 0;
2614
2615 }  /* End _DtHelpCeUnlockVolume */
2616
2617 /*****************************************************************************
2618  * Function: int _DtHelpCeIsTopTopic (_DtHelpVolumeHdl volume, const char *id)
2619  *
2620  * Parameters:  vol             Specifies the loaded volume
2621  *              id              Specifies a location id.
2622  *
2623  * Returns:     = 0 if successful, != 0 if failures.
2624  *
2625  * Purpose:     Tests to see if the location id is in the top topic of
2626  *              the volume.
2627  *
2628  *****************************************************************************/
2629 int 
2630 _DtHelpCeIsTopTopic (
2631     _DtHelpVolumeHdl     volume,
2632     const char          *id)
2633 {
2634     int            result  = -1;
2635     char          *topicId = NULL;
2636     char          *topId   = NULL;
2637     _DtHelpVolume  vol = (_DtHelpVolume) volume;
2638
2639     _DtHelpProcessLock();
2640     /*
2641      * check the parameters
2642      */
2643     if (vol == NULL || CheckVolList (vol, NULL) == -1)
2644       {
2645         _DtHelpProcessUnlock();
2646         return -1;
2647       }
2648
2649     /*
2650      * What type of volume is it?
2651      */
2652     if (vol->sdl_flag == False)
2653       {
2654         if (_DtHelpCeMapCcdfTargetToId(vol, id, &topicId) == 0 &&
2655                                 _DtHelpCeGetCcdfTopTopic(vol, &topId) == 0)
2656             result = _DtHelpCeStrCaseCmpLatin1(topId, topicId);
2657       }
2658     else if (_DtHelpCeMapIdToSdlTopicId(vol, id, &topicId) == 0)
2659       {
2660         topId = _DtHelpCeGetSdlHomeTopicId(volume);
2661         if (topId != NULL)
2662             result = _DtHelpCeStrCaseCmpLatin1(topId, topicId);
2663       }
2664
2665     _DtHelpProcessUnlock();
2666     return result;
2667
2668 }  /* End _DtHelpCeIsTopTopic */