FileUtils.c: fix CERT VU#575804
[oweals/cde.git] / cde / lib / DtHelp / AccessSDL.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: AccessSDL.c /main/13 1996/09/30 11:22:14 cde-hp $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        AccessSDL.c
28  **
29  **   Project:     Run Time Project File Access
30  **
31  **   Description: This body of code handles the access routines for the
32  **                SDL files.
33  **
34  **
35  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
36  **
37  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
38  **  (c) Copyright 1993, 1994 International Business Machines Corp.
39  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
40  **  (c) Copyright 1993, 1994 Novell, Inc.
41  **
42  **
43  ****************************************************************************
44  ************************************<+>*************************************/
45
46 /*
47  * system includes
48  */
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52
53 #include <X11/Xlib.h>
54 #include <X11/Xresource.h>
55
56 /*
57  * Canvas Engine includes
58  */
59 #include "CanvasP.h"
60 #include "CanvasSegP.h"
61
62 /*
63  * private includes
64  */
65 #include "bufioI.h"
66 #include "CleanUpI.h"
67 #include "CvStringI.h"
68 #include "FontAttrI.h"
69 #include "Access.h"
70 #include "AccessP.h"
71 #include "AccessSDLP.h"
72 #include "AccessSDLI.h"
73 #include "FormatUtilI.h"
74 #include "FormatSDLI.h"
75 #include "StringFuncsI.h"
76 #include "UtilSDLI.h"
77
78 #ifdef NLS16
79 #endif
80
81 /********    Private Defines      ********/
82 /********    End Private Defines  ********/
83
84 /********    Private Function Declarations    ********/
85 static  int     ProcessEntry (
86                         _DtHelpVolume    vol,
87                         _DtCvSegment    *p_seg,
88                         char            *parent_key);
89 /********    End Private Function Declarations    ********/
90
91 /********    Private Variable Declarations    ********/
92 static  const   char    *IsoString = "ISO-8859-1";
93 static  const   CESDLVolume     DefaultSdlVolume =
94   {
95      NULL,              /* _DtCvSegment *sdl_info; */
96      NULL,              /* _DtCvSegment *toss;     */
97      NULL,              /* _DtCvSegment *loids;    */
98      NULL,              /* _DtCvSegment *index;    */
99      NULL,              /* _DtCvSegment *title;    */
100      NULL,              /* _DtCvSegment *snb;      */
101      0,                 /* short      minor_no; */
102      False,             /* short      title_processed; */
103   };
104
105 /********    Private Macro Declarations    ********/
106
107 /******************************************************************************
108  *                          Private Functions
109  ******************************************************************************/
110 /******************************************************************************
111  * Function:    void FreeIds (
112  *
113  * Parameters:
114  *
115  * Return Value:
116  *
117  * errno Values:
118  *
119  * Purpose:
120  *
121  ******************************************************************************/
122 static void
123 FreeIds (
124     _DtCvSegment        *loids)
125 {
126     _DtCvSegment *p_seg;
127
128     if (NULL == loids)
129         return;
130
131     p_seg = _DtCvContainerListOfSeg(loids);
132
133     while (NULL != p_seg)
134       {
135         if (NULL != _SdlSegToSdlIdInfoPtr(p_seg))
136           {
137             if (NULL != _SdlSegToSdlIdInfoRssi(p_seg))
138                 free(_SdlSegToSdlIdInfoRssi(p_seg));
139
140             free(_SdlSegToSdlIdInfoPtr(p_seg));
141           }
142
143         p_seg = p_seg->next_seg;
144       }
145 }
146
147 /******************************************************************************
148  * Function:    void FreeTossInfo (
149  *
150  * Parameters:
151  *
152  * Return Value:
153  *
154  * errno Values:
155  *
156  * Purpose:
157  *
158  ******************************************************************************/
159 static void
160 FreeTossInfo (
161     _DtCvSegment        *toss)
162 {
163     _DtCvSegment *p_seg;
164     SDLTossInfo  *info;
165
166     if (NULL == toss)
167         return;
168
169     p_seg = _DtCvContainerListOfSeg(toss);
170
171     while (NULL != p_seg)
172       {
173         info = (SDLTossInfo *) _SdlSegTossInfo(p_seg);
174
175         /* free the ssi */
176         if (NULL != _SdlTossInfoPtrSsi(info))
177             free(_SdlTossInfoPtrSsi(info));
178
179         /* free the colj,colw or the enter, exit data */
180         if (NULL != _SdlTossInfoPtrStr1(info))
181             free(_SdlTossInfoPtrStr1(info));
182         if (NULL != _SdlTossInfoPtrStr2(info))
183             free(_SdlTossInfoPtrStr2(info));
184
185         /* free the font strings */
186         if (NULL != _DtHelpFontHintsColor(_SdlTossInfoPtrFontSpecs(info)))
187             free(_DtHelpFontHintsColor(_SdlTossInfoPtrFontSpecs(info)));
188         if (NULL != _DtHelpFontHintsXlfd(_SdlTossInfoPtrFontSpecs(info)))
189             free(_DtHelpFontHintsXlfd(_SdlTossInfoPtrFontSpecs(info)));
190         if (NULL != _DtHelpFontHintsXlfdb(_SdlTossInfoPtrFontSpecs(info)))
191             free(_DtHelpFontHintsXlfdb(_SdlTossInfoPtrFontSpecs(info)));
192         if (NULL != _DtHelpFontHintsXlfdi(_SdlTossInfoPtrFontSpecs(info)))
193             free(_DtHelpFontHintsXlfdi(_SdlTossInfoPtrFontSpecs(info)));
194         if (NULL != _DtHelpFontHintsXlfdib(_SdlTossInfoPtrFontSpecs(info)))
195             free(_DtHelpFontHintsXlfdib(_SdlTossInfoPtrFontSpecs(info)));
196         if (NULL != _DtHelpFontHintsTypeNam(_SdlTossInfoPtrFontSpecs(info)))
197             free(_DtHelpFontHintsTypeNam(_SdlTossInfoPtrFontSpecs(info)));
198         if (NULL != _DtHelpFontHintsTypeNamb(_SdlTossInfoPtrFontSpecs(info)))
199             free(_DtHelpFontHintsTypeNamb(_SdlTossInfoPtrFontSpecs(info)));
200         if (NULL != _DtHelpFontHintsTypeNami(_SdlTossInfoPtrFontSpecs(info)))
201             free(_DtHelpFontHintsTypeNami(_SdlTossInfoPtrFontSpecs(info)));
202         if (NULL != _DtHelpFontHintsTypeNamib(_SdlTossInfoPtrFontSpecs(info)))
203             free(_DtHelpFontHintsTypeNamib(_SdlTossInfoPtrFontSpecs(info)));
204
205         free(info);
206
207         p_seg = p_seg->next_seg;
208       }
209 }
210
211 /******************************************************************************
212  * Function:    void FreeEntryInfo (
213  *
214  * Parameters:
215  *
216  * Return Value:
217  *
218  * errno Values:
219  *
220  * Purpose:
221  *
222  ******************************************************************************/
223 static void
224 FreeEntryInfo (
225     _DtCvSegment        *index)
226 {
227     _DtCvSegment *p_seg;
228     SDLEntryInfo  *info;
229
230     if (NULL == index)
231         return;
232
233     p_seg = _DtCvContainerListOfSeg(index);
234
235     while (NULL != p_seg)
236       {
237         info = _SdlSegToSdlEntryInfo(p_seg);
238
239         if (NULL != info)
240           {
241             if (NULL != info->main)
242                 free(info->main);
243             if (NULL != info->locs)
244                 free(info->locs);
245             if (NULL != info->syns)
246                 free(info->syns);
247             if (NULL != info->sort)
248                 free(info->sort);
249           }
250
251         if (_DtCvIsSegContainer(p_seg))
252             FreeEntryInfo(p_seg);
253
254         free(info);
255
256         p_seg = p_seg->next_seg;
257       }
258 }
259
260 /******************************************************************************
261  * Function:    int ProcessSubEntries (
262  *
263  * Parameters:
264  *
265  * Return Value:
266  *
267  * errno Values:
268  *
269  * Purpose:
270  *
271  ******************************************************************************/
272 static int
273 ProcessSubEntries (
274     _DtHelpVolume vol,
275     _DtCvSegment        *p_seg,
276     char        *parent_key)
277 {
278     while (p_seg != NULL)
279       {
280         /*
281          * the only sub containers of an entry that should have an non-null
282          * internal pointer should be a sub <entry>.
283          */
284         if (_DtCvIsSegContainer(p_seg) && NULL != _SdlSegEntryInfo(p_seg)
285                 && ProcessEntry(vol, _DtCvContainerListOfSeg(p_seg),
286                                                 parent_key) == -1)
287             return -1;
288
289         p_seg = p_seg->next_seg;
290       }
291     return 0;
292 }
293
294 /******************************************************************************
295  * Function:    int AsciiKeyword (
296  *
297  * Parameters:
298  *              p_list          The segment list to process for strings.
299  *              parent_str      The string to append information onto.
300  *                              This may be NULL.
301  *              str_size        The malloc'ed size of the parent string.
302  *                              Includes room for the null byte. If zero
303  *                              and parent_str is non-null, then memory
304  *                              must be malloc'ed and parent_str copied
305  *                              into it. Otherwise, goodStr can just
306  *                              reuse parent_str.
307  *
308  * Return Value:
309  *
310  * errno Values:
311  *
312  * Purpose:
313  *
314  ******************************************************************************/
315 static char * 
316 AsciiKeyword (
317     _DtCvSegment        *p_list,
318     char                *parent_str,
319     int                 *str_size)
320 {
321     int          len     = 0;
322     int          newLen;
323     char        *goodStr;
324
325     /*
326      * if a starting string has been passed in, use it.
327      */
328     if (NULL != parent_str)
329       {
330         /*
331          * get the actual byte count.
332          */
333         len = strlen(parent_str) + 1;
334
335         /*
336          * is the starting value zero? If so, we have to copy it.
337          */
338         if (0 == *str_size)
339           {
340             parent_str = strdup(parent_str);
341             if (NULL == parent_str)
342                 return NULL;
343
344             *str_size = len;
345           }
346       }
347
348     /*
349      * start with the parent_string
350      */
351     goodStr = parent_str;
352
353     while (p_list != NULL)
354       {
355         if (_DtCvIsSegString(p_list))
356           {
357             /*
358              * get the number of characters in the next string.
359              */
360             newLen = _DtCvStrLen(_DtCvStringOfStringSeg(p_list),
361                                                 _DtCvIsSegWideChar(p_list));
362
363             /*
364              * if this is wide char string, multiply the count by
365              * MB_CUR_MAX to get the maximum number of bytes this
366              * string would take.
367              */
368             if (_DtCvIsSegWideChar(p_list))
369                 newLen = newLen * MB_CUR_MAX;
370
371             /*
372              * now add it to our previous size.
373              */
374             len += newLen;
375
376             /*
377              * are we starting from scratch?
378              */
379             if (goodStr == NULL)
380               {
381                 /*
382                  * include a byte for the end-of-string character.
383                  */
384                 len++;
385
386                 /*
387                  * malloc the memory
388                  */
389                 goodStr = (char *) malloc (len);
390
391               }
392             else if (*str_size < len) /* does this have to grow? */
393                 goodStr = (char *) realloc (goodStr, len);
394
395             if (goodStr == NULL)
396                 return NULL;
397
398             /*
399              * remember the absolute size of the memory for the string
400              */
401             if (*str_size < len)
402                 *str_size = len;
403
404             if (_DtCvIsSegWideChar(p_list))
405               {
406                 /*
407                  * back up to the insertion point.
408                  */
409                 len -= newLen;
410
411                 /*
412                  * transfer
413                  */
414                 newLen = wcstombs(&goodStr[len - 1],
415                                 (wchar_t *) _DtCvStringOfStringSeg(p_list),
416                                         newLen + 1);
417                 if ((size_t) -1 == newLen)
418                     return NULL;
419
420                 len += newLen;
421           }
422             else
423                 strcpy(&goodStr[len - newLen - 1],
424                                 (char *) _DtCvStringOfStringSeg(p_list));
425           }
426
427         /*
428          * the only containers in an <entry> that should have a non-null
429          * internal pointer should be a sub <entry>. Therefore, if null,
430          * process since it could be a <key>, <sphrase>, etc.
431          */
432         else if (_DtCvIsSegContainer(p_list) &&
433                                         NULL == _SdlSegEntryInfo(p_list))
434           {
435             goodStr = AsciiKeyword(_DtCvContainerListOfSeg(p_list), goodStr,
436                                                                 str_size);
437             if (goodStr == NULL)
438                 return NULL;
439
440             len = strlen(goodStr) + 1;
441           }
442
443         p_list = p_list->next_seg;
444       }
445
446     return goodStr;
447 }
448
449 /******************************************************************************
450  * Function:    int ProcessLocations (
451  *
452  * Parameters:
453  *
454  * Return Value:
455  *
456  * errno Values:
457  *
458  * Purpose:
459  *
460  ******************************************************************************/
461 static int 
462 ProcessLocations (
463     char        *locs,
464     char        ***list)
465 {
466     char  **myList = NULL;
467     char   *nextLoc;
468
469     while (locs != NULL && *locs != '\0')
470       {
471         locs = _DtHelpGetNxtToken(locs, &nextLoc);
472         if (nextLoc == NULL)
473             return -1;
474
475         if (*nextLoc != '\0')
476           {
477             myList = (char **) _DtHelpCeAddPtrToArray ((void **) myList,
478                                                         (void *) nextLoc);
479             if (myList == NULL)
480                 return -1;
481           }
482       }
483
484     *list = myList;
485     return 0;
486 }
487
488 /******************************************************************************
489  * Function:    int ProcessEntry (_DtHelpVolume vol)
490  *
491  * Parameters:  vol     Specifies the volume whose keywords need to be
492  *                      loaded from disk.  Once loaded, they can be 
493  *                      accessed through the fields of the volume structure.
494  *
495  * Return Value:        0 if successful, -1 if a failure occurs
496  *
497  * errno Values:        CEErrorMalloc
498  *                      CEErrorIllegalDatabaseFile
499  *                                      Specifies that the keyword file is
500  *                                      invalid or corrupt.
501  *                      CEErrorMissingKeywordsRes
502  *                                      Specifies that the keyword file does
503  *                                      not contain the 'Keywords/keywords'
504  *                                      resource or the resource is NULL
505  *
506  *
507  * Purpose:     Load the keywords associated with a volume.
508  *
509  ******************************************************************************/
510 static int 
511 ProcessEntry (
512     _DtHelpVolume        vol,
513     _DtCvSegment        *p_seg,
514     char                *parent_key)
515 {
516     int           strSize;
517     char        **topics;
518     char         *nextKey = NULL;
519
520     /* Now parse the string into the appropriate arrays.  The string has the 
521        following syntax:
522
523         <!ELEMENT entry     - - ((%simple; | #PCDATA)*, entry*)       >
524         <!ATTLIST entry         id      ID     #IMPLIED
525                                 main    IDREFS #IMPLIED
526                                 locs    IDREFS #IMPLIED
527                                 syns    IDREFS #IMPLIED
528                                 sort    CDATA  #IMPLIED               >
529      */
530
531 #define MAIN_STRINGS    (_SdlSegToSdlEntryInfo(p_seg))->main
532 #define LOCS_STRINGS    (_SdlSegToSdlEntryInfo(p_seg))->locs
533
534     while (p_seg != NULL)
535       {
536         strSize = 0;
537         nextKey = AsciiKeyword(_DtCvContainerListOfSeg(p_seg),
538                                                         parent_key, &strSize);
539
540         if (nextKey == NULL)
541             return -1;
542
543         /* We have the next keyword.  Hang onto it and add it to the list
544            once we get the array of topics.  We don't add it yet because if
545            there are no topics we want to throw it away.  (Silently ignoring
546            keywords which specify no topics is an undocumented feature.) */
547
548         /* Now get the list of topics. */
549         topics = NULL;
550         if (NULL != FrmtPrivInfoPtr(p_seg) && NULL != _SdlSegEntryInfo(p_seg)
551                 && (ProcessLocations(MAIN_STRINGS, &topics) == -1 ||
552                         ProcessLocations(LOCS_STRINGS, &topics) == -1))
553           {
554             free(nextKey);
555             return -1;
556           }
557
558         if (topics != NULL)
559           {
560             vol->keywords = (char **) _DtHelpCeAddPtrToArray (
561                                                 (void **) vol->keywords,
562                                                 (void *) nextKey);
563             vol->keywordTopics = (char ***) _DtHelpCeAddPtrToArray (
564                                                 (void **) vol->keywordTopics,
565                                                 (void *) topics);
566             /*
567              * If we just malloc'ed ourselves out of existance...
568              * stop here.
569              */
570             if (vol->keywords == 0 || vol->keywordTopics == 0)
571               {
572                 if (vol->keywords != NULL)
573                   {
574                     free(nextKey);
575                     _DtHelpCeFreeStringArray (vol->keywords);
576                     _DtHelpCeFreeStringArray (topics);
577                     vol->keywords = NULL;
578                   }
579                 if (vol->keywordTopics)
580                   {
581                     char ***topicList;
582
583                     for (topicList = vol->keywordTopics; topicList; topicList++)
584                         _DtHelpCeFreeStringArray (*topicList);
585                     free (vol->keywordTopics);
586                     vol->keywordTopics = NULL;
587                   }
588                 return -1;
589               }
590           }
591
592         if (_DtCvContainerListOfSeg(p_seg) != NULL &&
593             ProcessSubEntries(vol,_DtCvContainerListOfSeg(p_seg),nextKey) == -1)
594             return -1;
595
596         if (topics == NULL)
597             free (nextKey);
598
599         p_seg = p_seg->next_seg;
600       }
601
602     return (0);
603 }
604
605 /******************************************************************************
606  * Function:    int MapPath (_DtCvSegment *cur_id, int level, char ***ret_ids)
607  *
608  * Parameters:
609  *
610  * Return Value:        0 if successful, -1 if failure.
611  *
612  * Memory:      The memory returned in ret_ids is owned by the caller.
613  *
614  * Purpose:     To come up with a path from the top of the volume to the
615  *              target id.
616  *
617  ******************************************************************************/
618 static int 
619 MapPath (
620     _DtCvSegment  **cur_id,
621     _DtCvSegment   *target_el,
622     int             stop_lev,
623     int             lev_cnt,
624     int             hidden_no,
625     char        ***ret_ids)
626 {
627     _DtCvSegment        *mySeg  = *cur_id;
628     int          count  = -1;
629     int          myLev;
630     SDLIdInfo   *info;
631
632     while (mySeg != NULL)
633       {
634         /*
635          * Does this match the target id?
636          * And, is the element a child of the current path?
637          */
638         info  = _SdlSegToSdlIdInfoPtr(mySeg);
639         myLev = _SdlIdInfoPtrRlevel(info);
640         if (target_el == mySeg && (myLev == -1 || myLev > stop_lev))
641           {
642             /*
643              * matched the target id.
644              * allocate memory and return.
645              */
646             count = 0;
647             if (_SdlIdInfoPtrType(info) == SdlIdVirpage)
648               {
649                 count++;
650                 lev_cnt++;
651               }
652
653             *ret_ids = (char **) malloc (sizeof(char *) * (lev_cnt + 1));
654             if ((*ret_ids) == NULL)
655                 return -1;
656
657             (*ret_ids)[lev_cnt] = NULL;
658
659             if (_SdlIdInfoPtrType(info) == SdlIdVirpage)
660                 (*ret_ids)[lev_cnt - 1] = strdup(_DtCvContainerIdOfSeg(mySeg));
661
662             return count;
663           }
664         else if (myLev != -1 && myLev != hidden_no
665                                 && _SdlIdInfoPtrType(info) == SdlIdVirpage)
666           {
667             char *myId = _DtCvContainerIdOfSeg(mySeg);
668
669             /*
670              * If we've hit a virpage that is a sibling or an aunt
671              * set the search pointer to this segment (since this
672              * is where we want to start searching again) and return
673              * a negative on the successful search.
674              */
675             if (myLev <= stop_lev)
676               {
677                 *cur_id = mySeg;
678                 return -1;
679               }
680
681             /*
682              * this virpage is a child of mine, so look at it's children
683              * for the target id.
684              */
685             mySeg = mySeg->next_seg;
686             count = MapPath(&mySeg, target_el, myLev, lev_cnt + 1, hidden_no,
687                                 ret_ids);
688
689             /*
690              * successful response on finding the target id in the virpage's
691              * children. Duplicate the virpage's id string and return to
692              * my parent.
693              */
694             if (count != -1)
695               {
696                 (*ret_ids)[lev_cnt] = strdup(myId);
697
698                 count++;
699                 return count;
700               }
701           }
702         else /* did not match the target id and is not a virpage
703               * or is a hidden virpage */
704             mySeg = mySeg->next_seg;
705       }
706
707     *cur_id = mySeg;
708     return -1;
709 }
710
711 /******************************************************************************
712  *                          Semi-Private Functions
713  ******************************************************************************/
714 /*******************************************************************************
715  * Function:    CESDLVolume *_DtHelpCeGetSdlVolumePtr (_DtHelpVolumeHdl vol);
716  *
717  * Parameters:  vol     Specifies the loaded volume.
718  *
719  * Return Value:        0 if successful, -1 if a failure occurs
720  *
721  * errno Values:        None
722  *
723  * Purpose:     When the volume is no longer needed, it should be unloaded
724  *              with this call.  Unloading it frees the memory (which means
725  *              any handles on the volume become invalid.)
726  *
727  ******************************************************************************/
728 CESDLVolume *
729 _DtHelpCeGetSdlVolumePtr (
730      _DtHelpVolumeHdl    volume)
731 {
732     _DtHelpVolume vol = (_DtHelpVolume) volume;
733
734     if (vol != NULL)
735         return ((CESDLVolume *) vol->vols.sdl_vol);
736     return NULL;
737 }
738
739 /******************************************************************************
740  *                          Semi-Public Functions
741  ******************************************************************************/
742 /*******************************************************************************
743  * Function:    void _DtHelpCeInitSdlVolume (_DtHelpVolume vol);
744  *
745  * Parameters:  vol     Specifies the loaded volume.
746  *
747  * Return Value:        0 if successful, -1 if a failure occurs
748  *
749  * errno Values:        None
750  *
751  * Purpose:     When the volume is no longer needed, it should be unloaded
752  *              with this call.  Unloading it frees the memory (which means
753  *              any handles on the volume become invalid.)
754  *
755  ******************************************************************************/
756 void
757 _DtHelpCeInitSdlVolume (
758      _DtHelpVolumeHdl    volume)
759 {
760     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
761
762     if (sdlVol != NULL)
763         *sdlVol = DefaultSdlVolume;
764
765 }
766
767 /*******************************************************************************
768  * Function:    void _DtHelpCeOpenSdlVolume (_DtHelpVolume vol);
769  *
770  * Parameters:  vol     Specifies the loaded volume.
771  *
772  * Return Value:        0 if successful, -1 if a failure occurs
773  *
774  * errno Values:        None
775  *
776  * Purpose:     When the volume is no longer needed, it should be unloaded
777  *              with this call.  Unloading it frees the memory (which means
778  *              any handles on the volume become invalid.)
779  *
780  ******************************************************************************/
781 int
782 _DtHelpCeOpenSdlVolume (
783      _DtHelpVolumeHdl    volume)
784 {
785     CESDLVolume *sdlVol;
786     _DtHelpVolume  vol = (_DtHelpVolume) volume;
787
788     sdlVol  = (CESDLVolume *) calloc (1, sizeof(CESDLVolume));
789     if (sdlVol != NULL)
790       {
791         vol->vols.sdl_vol = (SdlVolumeHandle) sdlVol;
792         _DtHelpCeInitSdlVolume(volume);
793         if (_DtHelpCeFrmtSdlVolumeInfo(vol->volFile,
794                                         vol, &(vol->check_time)) == 0)
795           {
796             vol->sdl_flag = True;
797             return 0;
798           }
799
800         vol->vols.sdl_vol = NULL;
801         free(sdlVol);
802       }
803
804     return -1;
805 }
806
807 /*******************************************************************************
808  * Function:    void _DtHelpCeCleanSdlVolume (_DtHelpVolume vol);
809  *
810  * Parameters:  vol     Specifies the loaded volume.
811  *
812  * Return Value:        0 if successful, -1 if a failure occurs
813  *
814  * errno Values:        None
815  *
816  * Purpose:     When the volume is no longer needed, it should be unloaded
817  *              with this call.  Unloading it frees the memory (which means
818  *              any handles on the volume become invalid.)
819  *
820  ******************************************************************************/
821 void
822 _DtHelpCeCleanSdlVolume (
823      _DtHelpVolumeHdl    volume)
824 {
825     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
826
827     if (sdlVol != NULL)
828       {
829         _DtHelpFreeSegments(sdlVol->snb  , _DtCvFALSE, sdlVol->destroy_region,
830                                                         sdlVol->client_data);
831         _DtHelpFreeSegments(sdlVol->title, _DtCvFALSE, sdlVol->destroy_region,
832                                                         sdlVol->client_data);
833
834         /*
835          * free the index information
836          */
837         FreeEntryInfo(sdlVol->index);
838         _DtHelpFreeSegments(sdlVol->index, _DtCvFALSE, NULL, NULL);
839
840         /*
841          * free the toss information.
842          */
843         FreeTossInfo(sdlVol->toss);
844         _DtHelpFreeSegments(sdlVol->toss , _DtCvFALSE, NULL, NULL);
845
846         /*
847          * free the ids
848          */
849         FreeIds(sdlVol->loids);
850         _DtHelpFreeSegments(sdlVol->loids, _DtCvFALSE, NULL, NULL);
851
852         /*
853          * free the document information.
854          */
855         if (NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
856             free(_SdlDocInfoPtrLanguage(sdlVol->sdl_info));
857
858         if (NULL != _SdlDocInfoPtrCharSet(sdlVol->sdl_info))
859             free(_SdlDocInfoPtrCharSet(sdlVol->sdl_info));
860
861         if (NULL != _SdlDocInfoPtrDocId(sdlVol->sdl_info))
862             free(_SdlDocInfoPtrDocId(sdlVol->sdl_info));
863
864         if (NULL != _SdlDocInfoPtrFirstPg(sdlVol->sdl_info))
865             free(_SdlDocInfoPtrFirstPg(sdlVol->sdl_info));
866
867         if (NULL != _SdlDocInfoPtrSdlDtd(sdlVol->sdl_info))
868             free(_SdlDocInfoPtrSdlDtd(sdlVol->sdl_info));
869
870         if (NULL != _SdlDocInfoPtrStamp(sdlVol->sdl_info))
871             free(_SdlDocInfoPtrStamp(sdlVol->sdl_info));
872
873         free(sdlVol->sdl_info);
874       }
875 }
876
877 /*******************************************************************************
878  * Function:    int _DtHelpCeRereadSdlVolume (_DtHelpVolume vol);
879  *
880  * Parameters:  vol     Specifies the loaded volume.
881  *
882  * Return Value:        0 if successful, -1 if a failure occurs
883  *
884  * errno Values:        None
885  *
886  * Purpose:     When the volume is no longer needed, it should be unloaded
887  *              with this call.  Unloading it frees the memory (which means
888  *              any handles on the volume become invalid.)
889  *
890  ******************************************************************************/
891 int
892 _DtHelpCeRereadSdlVolume (
893      _DtHelpVolumeHdl    volume)
894 {
895     _DtHelpCeCleanSdlVolume(volume);
896     _DtHelpCeInitSdlVolume(volume);
897     if (_DtHelpCeFrmtSdlVolumeInfo(_DtHelpCeGetVolumeName(volume),
898                                         volume, NULL) == 0)
899             return 0;
900
901     return -1;
902 }
903
904 /*******************************************************************************
905  * Function:    void _DtHelpCeCloseSdlVolume (_DtHelpVolume vol);
906  *
907  * Parameters:  vol     Specifies the loaded volume.
908  *
909  * Return Value:        0 if successful, -1 if a failure occurs
910  *
911  * errno Values:        None
912  *
913  * Purpose:     When the volume is no longer needed, it should be unloaded
914  *              with this call.  Unloading it frees the memory (which means
915  *              any handles on the volume become invalid.)
916  *
917  ******************************************************************************/
918 void
919 _DtHelpCeCloseSdlVolume (
920      _DtHelpVolumeHdl    volume)
921 {
922     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
923
924     if (sdlVol != NULL)
925       {
926         _DtHelpCeCleanSdlVolume(volume);
927         free(sdlVol);
928       }
929 }
930
931 /*****************************************************************************
932  * Function: Boolean _DtHelpCeGetSdlHomeTopicId (_DtHelpVolume vol,
933  *                                      char *target_id,
934  *                                      char *ret_name, int *ret_offset)
935  *
936  * Parameters:  vol             Specifies the loaded volume
937  *              target_id       Specifies target location ID
938  *              ret_name        Returns a null terminated string
939  *                              containing a fully qualified path to
940  *                              the file that contains 'target_id'.
941  *              ret_offset      Returns the offset into 'ret_name'
942  *                              to the topic that contains 'target_id'.
943  *
944  * Memory own by caller:
945  *              ret_name
946  *
947  * Returns:     True if successful, False if a failure occurs
948  *
949  * errno Values:        EINVAL          Specifies an invalid parameter was
950  *                                      used.
951  *                      CEErrorMalloc
952  *                      CEErrorLocIdNotFound
953  *                                      Specifies that 'locId' was not
954  *                                      found.
955  *
956  * Purpose:     Find which topic contains a specified locationID.
957  *
958  *****************************************************************************/
959 char *
960 _DtHelpCeGetSdlHomeTopicId (
961         _DtHelpVolumeHdl         volume)
962 {
963     _DtCvSegment *idSegs;
964     CESDLVolume  *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
965
966     if (sdlVol->sdl_info != NULL)
967       {
968         /*
969          * Was the first page topic declared in the header?
970          */
971         if (NULL != _SdlDocInfoPtrFirstPg(sdlVol->sdl_info))
972             return (_SdlDocInfoPtrFirstPg(sdlVol->sdl_info));
973
974         /*
975          * have to search the list of ids for the home topic.  This is a
976          * bit of a kludge since we are looking for a specific string in
977          * the rssi.  But this is for backwards compatibility since the
978          * Snapshot release of the help system were released with out
979          * the first-page attribute and relied on _hometopic.
980          *
981          * Plus, first-page is #IMPLIED, which means that the parser
982          * that generated this SDL document does not have to use this
983          * attribute.
984          */
985         if (_DtHelpCeGetSdlVolIds(volume, -1, &idSegs) != 0)
986             return NULL;
987
988         while (idSegs != NULL)
989           {
990             if (SdlIdVirpage == _SdlSegToSdlIdInfoType(idSegs) &&
991                 _DtHelpCeStrCaseCmpLatin1(_SdlIdInfoPtrRssi(
992                                                 _SdlSegToSdlIdInfoPtr(idSegs)),
993                                 "_hometopic") == 0)
994                 return _DtCvContainerIdOfSeg(idSegs);
995
996             idSegs = idSegs->next_seg;
997           }
998       }
999
1000     return NULL;
1001 }
1002
1003 /*****************************************************************************
1004  * Function: Boolean _DtHelpCeFindSdlId (_DtHelpVolume vol, char *target_id,
1005  *                                      char *ret_name, int *ret_offset)
1006  *
1007  * Parameters:  vol             Specifies the loaded volume
1008  *              target_id       Specifies target location ID
1009  *              ret_name        Returns a null terminated string
1010  *                              containing a fully qualified path to
1011  *                              the file that contains 'target_id'.
1012  *              ret_offset      Returns the offset into 'ret_name'
1013  *                              to the topic that contains 'target_id'.
1014  *
1015  * Memory own by caller:
1016  *              ret_name
1017  *
1018  * Returns:     True if successful, False if a failure occurs
1019  *
1020  * errno Values:        EINVAL          Specifies an invalid parameter was
1021  *                                      used.
1022  *                      CEErrorMalloc
1023  *                      CEErrorLocIdNotFound
1024  *                                      Specifies that 'locId' was not
1025  *                                      found.
1026  *
1027  * Purpose:     Find which topic contains a specified locationID.
1028  *
1029  *****************************************************************************/
1030 int
1031 _DtHelpCeFindSdlId (
1032         _DtHelpVolumeHdl         volume,
1033         char            *target_id,
1034         int              fd,
1035         char            **ret_name,
1036         int             *ret_offset )
1037 {
1038     _DtHelpVolume   vol    = (_DtHelpVolume) volume;
1039     _DtCvSegment        *pEl;
1040
1041     pEl = _DtHelpCeMapSdlIdToSegment(volume, target_id, fd);
1042
1043     if (pEl != NULL)
1044       {
1045         if (ret_name != NULL)
1046             *ret_name   = strdup(vol->volFile);
1047         *ret_offset = _SdlIdInfoPtrOffset(_SdlSegToSdlIdInfoPtr(pEl));
1048         return True;
1049       }
1050
1051     return False;
1052 }
1053
1054 /*****************************************************************************
1055  * Function: int _DtHelpCeGetSdlKeywordList (
1056  *
1057  * Parameters:
1058  *
1059  * Returns:     0 if successful, -1 if not.
1060  *
1061  * errno Values:
1062  *
1063  * Purpose:     Get the KeywordList for an SDL volume.
1064  *
1065  *****************************************************************************/
1066 int
1067 _DtHelpCeGetSdlKeywordList (
1068         _DtHelpVolumeHdl         volume)
1069 {
1070     CESDLVolume *sdlVol =  _DtHelpCeGetSdlVolumePtr(volume);
1071
1072     if (_DtHelpCeGetSdlVolIndex(volume) != 0 || NULL == sdlVol->index
1073                         || NULL == _DtCvContainerListOfSeg(sdlVol->index))
1074         return -1;
1075
1076     return(ProcessEntry(((_DtHelpVolume) volume),
1077                         _DtCvContainerListOfSeg(sdlVol->index), NULL));
1078 }
1079
1080 /*****************************************************************************
1081  * Function: int _DtHelpCeGetSdlVolumeAsciiAbstract(volume);
1082  *
1083  * Parameters:
1084  *
1085  * Returns:     0 if successful, -1 if not.
1086  *
1087  * errno Values:
1088  *
1089  * Purpose:     Get the KeywordList for an SDL volume.
1090  *
1091  *****************************************************************************/
1092 char *
1093 _DtHelpCeGetSdlVolumeAsciiAbstract(
1094     _DtHelpVolumeHdl    volume)
1095 {
1096     return(_DtHelpCeFrmtSdlVolumeAbstractToAscii(volume));
1097 }
1098
1099 /*****************************************************************************
1100  * Function: int _DtHelpCeGetSdlIdPath(volume, target_id, ret_ids);
1101  *
1102  * Parameters:
1103  *
1104  * Returns:     > 0 if successful, -1 if not.
1105  *
1106  * Memory:      The memory returned is owned by the caller.
1107  *
1108  * Purpose:     Get the list of location ids between the top and the
1109  *              target_id.
1110  *
1111  *****************************************************************************/
1112 int
1113 _DtHelpCeGetSdlIdPath(
1114     _DtHelpVolumeHdl       volume,
1115     char                  *target_id,
1116     char                ***ret_ids)
1117 {
1118     _DtCvSegment   *idSegs;
1119     _DtCvSegment   *targetEl;
1120     int             hiddenNo = -1;
1121
1122     targetEl = _DtHelpCeMapSdlIdToSegment(volume, target_id, -1);
1123
1124     if (targetEl == NULL)
1125         return -1;
1126
1127     *ret_ids = NULL;
1128
1129     if (_DtHelpCeGetSdlVolIds(volume, -1, &idSegs) != 0)
1130         return NULL;
1131
1132     if (_SdlVolumeMinorNumber(_DtHelpCeGetSdlVolumePtr(volume)) >= SDL_DTD_1_1)
1133         hiddenNo = 0;
1134
1135     return (MapPath(&idSegs, targetEl, -1, 0, hiddenNo, ret_ids));
1136 }
1137
1138 /*****************************************************************************
1139  * Function: _DtCvSegment *_DtHelpCeMapSdlIdToSegment(volume, target_id);
1140  *
1141  * Parameters:
1142  *
1143  * Returns:     > 0 if successful, -1 if not.
1144  *
1145  * errno Values:
1146  *
1147  * Purpose:     Get the list of location ids between the top and the
1148  *              target_id.
1149  *
1150  *****************************************************************************/
1151 _DtCvSegment *
1152 _DtHelpCeMapSdlIdToSegment(
1153     _DtHelpVolumeHdl       volume,
1154     const char            *target_id,
1155     int                    fd)
1156 {
1157     int             underScore = False;
1158     short           minorNo;
1159     _DtCvSegment   *idSegs;
1160     char           *idString;
1161     char            resStr[128] = "SDL-RESERVED-";
1162
1163     minorNo = _SdlVolumeMinorNumber(_DtHelpCeGetSdlVolumePtr(volume));
1164
1165     if (*target_id == '_')
1166       {
1167         /*
1168          * parsers generating SDL_DTD_1_0 and earlier put the special
1169          * access points (_hometopic, _abstract, _copyright, etc.) in
1170          * the SSI.
1171          */
1172         if (minorNo < SDL_DTD_1_1)
1173             underScore = True;
1174         else
1175           {
1176             target_id++;
1177             strcat(resStr, target_id);
1178             target_id = resStr;
1179           }
1180       }
1181
1182     if (_DtHelpCeGetSdlVolIds(volume, fd, &idSegs) != 0)
1183         return NULL;
1184
1185     while (idSegs != NULL)
1186       {
1187         if (underScore == True)
1188             idString = _SdlIdInfoPtrRssi(_SdlSegToSdlIdInfoPtr(idSegs));
1189         else
1190             idString = _DtCvContainerIdOfSeg(idSegs);
1191
1192         if (idString != NULL &&
1193                         _DtHelpCeStrCaseCmpLatin1(idString, target_id) == 0)
1194             return idSegs;
1195
1196         idSegs = idSegs->next_seg;
1197       }
1198
1199     return NULL;
1200 }
1201
1202 /*****************************************************************************
1203  * Function: int _DtHelpCeMapIdToSdlTopicId(volume, target_id);
1204  *
1205  * Parameters:
1206  *
1207  * Returns:     > 0 if successful, -1 if not.
1208  *
1209  * errno Values:
1210  *
1211  * Purpose:     Get the id of the virpage containing the target_id.
1212  *
1213  *****************************************************************************/
1214 int
1215 _DtHelpCeMapIdToSdlTopicId(
1216     _DtHelpVolumeHdl       volume,
1217     const char            *target_id,
1218     char                 **ret_id)
1219 {
1220     int                  found = -1;
1221     _DtCvSegment        *idList;
1222     _DtCvSegment        *idSeg;
1223     SDLIdInfo           *idInfo;
1224
1225     if (_DtHelpCeGetSdlVolIds(volume, -1, &idList) == 0)
1226       {
1227         idSeg = _DtHelpCeMapSdlIdToSegment(volume, target_id, -1);
1228         if (idSeg != NULL)
1229           {
1230             while (found == -1 && idList != NULL)
1231               {
1232                 idInfo = _SdlSegToSdlIdInfoPtr(idList);
1233                 if (_SdlIdInfoPtrType(idInfo) == SdlIdVirpage)
1234                     *ret_id = _DtCvContainerIdOfSeg(idList);
1235
1236                 if (idList == idSeg)
1237                     found = 0;
1238                 else
1239                     idList = idList->next_seg;
1240               }
1241           }
1242       }
1243
1244     return found;
1245 }
1246
1247 /*****************************************************************************
1248  * Function: char * _DtHelpCeGetSdlVolCharSet(volume);
1249  *
1250  * Parameters:
1251  *
1252  * Returns:     the pointer to the locale string. Null otherwise.
1253  *
1254  * errno Values:
1255  *
1256  * Purpose:     Get the locale of the volume.
1257  *
1258  *****************************************************************************/
1259 const char *
1260 _DtHelpCeGetSdlVolCharSet(
1261     _DtHelpVolumeHdl       volume)
1262 {
1263     const char     *charSet = IsoString;
1264     CESDLVolume    *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
1265
1266     if (sdlVol->sdl_info != NULL &&
1267                         NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
1268         charSet = _SdlDocInfoPtrCharSet(sdlVol->sdl_info);
1269
1270     return charSet;
1271 }
1272
1273 /*****************************************************************************
1274  * Function: char * _DtHelpCeGetSdlVolLanguage(volume);
1275  *
1276  * Parameters:
1277  *
1278  * Returns:     the pointer to the language used in the volume.
1279  *
1280  * errno Values:
1281  *
1282  * Purpose:     Get the locale of the volume.
1283  *
1284  *****************************************************************************/
1285 char *
1286 _DtHelpCeGetSdlVolLanguage(
1287     _DtHelpVolumeHdl       volume)
1288 {
1289     char           *language = "C";
1290     CESDLVolume    *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
1291
1292     if (sdlVol->sdl_info != NULL &&
1293                         NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
1294         language = _SdlDocInfoPtrLanguage(sdlVol->sdl_info);
1295
1296     return language;
1297 }
1298
1299 /*****************************************************************************
1300  * Function: char * _DtHelpCeGetSdlVolumeLocale(volume);
1301  *
1302  * Parameters:
1303  *
1304  * Returns:     the pointer to the locale string. Null otherwise.
1305  *
1306  * errno Values:
1307  *
1308  * Purpose:     Get the locale of the volume.
1309  *
1310  *****************************************************************************/
1311 char *
1312 _DtHelpCeGetSdlVolumeLocale(
1313     _DtHelpVolumeHdl       volume)
1314 {
1315     int             langLen;
1316     char           *locale;
1317     char           *lang;
1318     const char     *charSet;
1319
1320     lang    = _DtHelpCeGetSdlVolLanguage(volume);
1321     charSet = _DtHelpCeGetSdlVolCharSet(volume);
1322
1323     langLen = strlen(lang);
1324     locale  = (char *) malloc (langLen + strlen(charSet) + 2);
1325     if (locale != NULL)
1326       {
1327         strcpy(locale, lang);
1328         if (langLen != 0 && *charSet != '\0')
1329           {
1330             locale[langLen++] = '.';
1331             strcpy(&(locale[langLen]), charSet);
1332           }
1333       }
1334
1335     return locale;
1336 }
1337
1338 /*****************************************************************************
1339  * Function: int _DtHelpCeGetSdlDocStamp(volume, ret_doc, ret_time);
1340  *
1341  * Parameters:
1342  *
1343  * Returns:     0 if successful, -2 if the volume does not contain
1344  *              one or the other, -1 if any other failure.
1345  *
1346  * Memory:      The Caller owns the memory returned in ret_doc and ret_time.
1347  *
1348  * Purpose:     Get the doc id and time stamp of a volume.
1349  *
1350  *****************************************************************************/
1351 int
1352 _DtHelpCeGetSdlDocStamp(
1353     _DtHelpVolumeHdl       volume,
1354     char                **ret_doc,
1355     char                **ret_time)
1356 {
1357     int             result    = -1;
1358     char           *docId     = NULL;
1359     char           *timestamp = NULL;
1360     CESDLVolume    *sdlVol    =  _DtHelpCeGetSdlVolumePtr(volume);
1361
1362     if (sdlVol->sdl_info != NULL)
1363       {
1364         result = 0;
1365         if (NULL != _SdlDocInfoPtrDocId(sdlVol->sdl_info))
1366             docId = strdup(_SdlDocInfoPtrDocId(sdlVol->sdl_info));
1367         else
1368             result = -2;
1369
1370         if (NULL != _SdlDocInfoPtrStamp(sdlVol->sdl_info))
1371             timestamp = strdup(_SdlDocInfoPtrStamp(sdlVol->sdl_info));
1372         else
1373             result = -2;
1374       }
1375
1376     if (ret_doc != NULL)
1377         *ret_doc = docId;
1378     if (ret_time != NULL)
1379         *ret_time = timestamp;
1380
1381     if (result == 0 && (docId == NULL || timestamp == NULL))
1382         return -1;
1383
1384     return result;
1385 }
1386
1387 /*****************************************************************************
1388  * Function: int _DtHelpCeGetSdlTopicChildren(
1389  *
1390  * Parameters:
1391  *
1392  * Returns:     pointer to the element, Null otherwise.
1393  *
1394  * errno Values:
1395  *
1396  * Purpose:     Find the specified element.
1397  *
1398  *****************************************************************************/
1399 int
1400 _DtHelpCeGetSdlTopicChildren(
1401     _DtHelpVolumeHdl     volume,
1402     char                *target,
1403     char                ***ret_ids)
1404 {
1405     int           done   = False;
1406     int          count  = 0;
1407     int          segLev;
1408     _DtCvSegment *idSeg;
1409     SDLIdInfo    *idInfo;
1410
1411     /*
1412      * Find the target id.
1413      */
1414     idSeg = _DtHelpCeMapSdlIdToSegment(volume, target, -1);
1415
1416     /*
1417      * save this level and start looking for its children at the next seg.
1418      */
1419     *ret_ids = NULL;
1420     if (idSeg != NULL)
1421       {
1422         idInfo = _SdlSegToSdlIdInfoPtr(idSeg);
1423         segLev = _SdlIdInfoPtrRlevel(idInfo) + 1;
1424         idSeg  = idSeg->next_seg;
1425       }
1426
1427     /*
1428      * process any virpage that has the correct level
1429      */
1430     while (idSeg != NULL && done == False)
1431       {
1432         idInfo = _SdlSegToSdlIdInfoPtr(idSeg);
1433         if (_SdlIdInfoPtrType(idInfo) == SdlIdVirpage)
1434           {
1435             /*
1436              * If greater, we're at the next sibling.
1437              */
1438             if (segLev > _SdlIdInfoPtrRlevel(idInfo))
1439                 done = True;
1440             else if (segLev == _SdlIdInfoPtrRlevel(idInfo))
1441               {
1442                 *ret_ids = (char **) _DtHelpCeAddPtrToArray( (void **) *ret_ids,
1443                         (void *)(strdup(_DtCvContainerIdOfSeg(idSeg))));
1444                 if ((*ret_ids) == NULL)
1445                     return -1;
1446
1447                 count++;
1448               }
1449           }
1450         idSeg = idSeg->next_seg;
1451       }
1452
1453     return count;
1454 }