Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[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 libraries 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                   {
419                     free(goodStr);
420                     return NULL;
421                   }
422
423                 len += newLen;
424           }
425             else
426                 strcpy(&goodStr[len - newLen - 1],
427                                 (char *) _DtCvStringOfStringSeg(p_list));
428           }
429
430         /*
431          * the only containers in an <entry> that should have a non-null
432          * internal pointer should be a sub <entry>. Therefore, if null,
433          * process since it could be a <key>, <sphrase>, etc.
434          */
435         else if (_DtCvIsSegContainer(p_list) &&
436                                         NULL == _SdlSegEntryInfo(p_list))
437           {
438             goodStr = AsciiKeyword(_DtCvContainerListOfSeg(p_list), goodStr,
439                                                                 str_size);
440             if (goodStr == NULL)
441                 return NULL;
442
443             len = strlen(goodStr) + 1;
444           }
445
446         p_list = p_list->next_seg;
447       }
448
449     return goodStr;
450 }
451
452 /******************************************************************************
453  * Function:    int ProcessLocations (
454  *
455  * Parameters:
456  *
457  * Return Value:
458  *
459  * errno Values:
460  *
461  * Purpose:
462  *
463  ******************************************************************************/
464 static int 
465 ProcessLocations (
466     char        *locs,
467     char        ***list)
468 {
469     char  **myList = NULL;
470     char   *nextLoc;
471
472     while (locs != NULL && *locs != '\0')
473       {
474         locs = _DtHelpGetNxtToken(locs, &nextLoc);
475         if (nextLoc == NULL)
476             return -1;
477
478         if (*nextLoc != '\0')
479           {
480             myList = (char **) _DtHelpCeAddPtrToArray ((void **) myList,
481                                                         (void *) nextLoc);
482             if (myList == NULL)
483                 return -1;
484           }
485       }
486
487     *list = myList;
488     return 0;
489 }
490
491 /******************************************************************************
492  * Function:    int ProcessEntry (_DtHelpVolume vol)
493  *
494  * Parameters:  vol     Specifies the volume whose keywords need to be
495  *                      loaded from disk.  Once loaded, they can be 
496  *                      accessed through the fields of the volume structure.
497  *
498  * Return Value:        0 if successful, -1 if a failure occurs
499  *
500  * errno Values:        CEErrorMalloc
501  *                      CEErrorIllegalDatabaseFile
502  *                                      Specifies that the keyword file is
503  *                                      invalid or corrupt.
504  *                      CEErrorMissingKeywordsRes
505  *                                      Specifies that the keyword file does
506  *                                      not contain the 'Keywords/keywords'
507  *                                      resource or the resource is NULL
508  *
509  *
510  * Purpose:     Load the keywords associated with a volume.
511  *
512  ******************************************************************************/
513 static int 
514 ProcessEntry (
515     _DtHelpVolume        vol,
516     _DtCvSegment        *p_seg,
517     char                *parent_key)
518 {
519     int           strSize;
520     char        **topics;
521     char         *nextKey = NULL;
522
523     /* Now parse the string into the appropriate arrays.  The string has the 
524        following syntax:
525
526         <!ELEMENT entry     - - ((%simple; | #PCDATA)*, entry*)       >
527         <!ATTLIST entry         id      ID     #IMPLIED
528                                 main    IDREFS #IMPLIED
529                                 locs    IDREFS #IMPLIED
530                                 syns    IDREFS #IMPLIED
531                                 sort    CDATA  #IMPLIED               >
532      */
533
534 #define MAIN_STRINGS    (_SdlSegToSdlEntryInfo(p_seg))->main
535 #define LOCS_STRINGS    (_SdlSegToSdlEntryInfo(p_seg))->locs
536
537     while (p_seg != NULL)
538       {
539         strSize = 0;
540         nextKey = AsciiKeyword(_DtCvContainerListOfSeg(p_seg),
541                                                         parent_key, &strSize);
542
543         if (nextKey == NULL)
544             return -1;
545
546         /* We have the next keyword.  Hang onto it and add it to the list
547            once we get the array of topics.  We don't add it yet because if
548            there are no topics we want to throw it away.  (Silently ignoring
549            keywords which specify no topics is an undocumented feature.) */
550
551         /* Now get the list of topics. */
552         topics = NULL;
553         if (NULL != FrmtPrivInfoPtr(p_seg) && NULL != _SdlSegEntryInfo(p_seg)
554                 && (ProcessLocations(MAIN_STRINGS, &topics) == -1 ||
555                         ProcessLocations(LOCS_STRINGS, &topics) == -1))
556           {
557             free(nextKey);
558             return -1;
559           }
560
561         if (topics != NULL)
562           {
563             vol->keywords = (char **) _DtHelpCeAddPtrToArray (
564                                                 (void **) vol->keywords,
565                                                 (void *) nextKey);
566             vol->keywordTopics = (char ***) _DtHelpCeAddPtrToArray (
567                                                 (void **) vol->keywordTopics,
568                                                 (void *) topics);
569             /*
570              * If we just malloc'ed ourselves out of existence...
571              * stop here.
572              */
573             if (vol->keywords == 0 || vol->keywordTopics == 0)
574               {
575                 if (vol->keywords != NULL)
576                   {
577                     free(nextKey);
578                     _DtHelpCeFreeStringArray (vol->keywords);
579                     _DtHelpCeFreeStringArray (topics);
580                     vol->keywords = NULL;
581                   }
582                 if (vol->keywordTopics)
583                   {
584                     char ***topicList;
585
586                     for (topicList = vol->keywordTopics; topicList; topicList++)
587                         _DtHelpCeFreeStringArray (*topicList);
588                     free (vol->keywordTopics);
589                     vol->keywordTopics = NULL;
590                   }
591                 return -1;
592               }
593           }
594
595         if (_DtCvContainerListOfSeg(p_seg) != NULL &&
596             ProcessSubEntries(vol,_DtCvContainerListOfSeg(p_seg),nextKey) == -1)
597             return -1;
598
599         if (topics == NULL)
600             free (nextKey);
601
602         p_seg = p_seg->next_seg;
603       }
604
605     return (0);
606 }
607
608 /******************************************************************************
609  * Function:    int MapPath (_DtCvSegment *cur_id, int level, char ***ret_ids)
610  *
611  * Parameters:
612  *
613  * Return Value:        0 if successful, -1 if failure.
614  *
615  * Memory:      The memory returned in ret_ids is owned by the caller.
616  *
617  * Purpose:     To come up with a path from the top of the volume to the
618  *              target id.
619  *
620  ******************************************************************************/
621 static int 
622 MapPath (
623     _DtCvSegment  **cur_id,
624     _DtCvSegment   *target_el,
625     int             stop_lev,
626     int             lev_cnt,
627     int             hidden_no,
628     char        ***ret_ids)
629 {
630     _DtCvSegment        *mySeg  = *cur_id;
631     int          count  = -1;
632     int          myLev;
633     SDLIdInfo   *info;
634
635     while (mySeg != NULL)
636       {
637         /*
638          * Does this match the target id?
639          * And, is the element a child of the current path?
640          */
641         info  = _SdlSegToSdlIdInfoPtr(mySeg);
642         myLev = _SdlIdInfoPtrRlevel(info);
643         if (target_el == mySeg && (myLev == -1 || myLev > stop_lev))
644           {
645             /*
646              * matched the target id.
647              * allocate memory and return.
648              */
649             count = 0;
650             if (_SdlIdInfoPtrType(info) == SdlIdVirpage)
651               {
652                 count++;
653                 lev_cnt++;
654               }
655
656             *ret_ids = (char **) malloc (sizeof(char *) * (lev_cnt + 1));
657             if ((*ret_ids) == NULL)
658                 return -1;
659
660             (*ret_ids)[lev_cnt] = NULL;
661
662             if (_SdlIdInfoPtrType(info) == SdlIdVirpage)
663                 (*ret_ids)[lev_cnt - 1] = strdup(_DtCvContainerIdOfSeg(mySeg));
664
665             return count;
666           }
667         else if (myLev != -1 && myLev != hidden_no
668                                 && _SdlIdInfoPtrType(info) == SdlIdVirpage)
669           {
670             char *myId = _DtCvContainerIdOfSeg(mySeg);
671
672             /*
673              * If we've hit a virpage that is a sibling or an aunt
674              * set the search pointer to this segment (since this
675              * is where we want to start searching again) and return
676              * a negative on the successful search.
677              */
678             if (myLev <= stop_lev)
679               {
680                 *cur_id = mySeg;
681                 return -1;
682               }
683
684             /*
685              * this virpage is a child of mine, so look at it's children
686              * for the target id.
687              */
688             mySeg = mySeg->next_seg;
689             count = MapPath(&mySeg, target_el, myLev, lev_cnt + 1, hidden_no,
690                                 ret_ids);
691
692             /*
693              * successful response on finding the target id in the virpage's
694              * children. Duplicate the virpage's id string and return to
695              * my parent.
696              */
697             if (count != -1)
698               {
699                 (*ret_ids)[lev_cnt] = strdup(myId);
700
701                 count++;
702                 return count;
703               }
704           }
705         else /* did not match the target id and is not a virpage
706               * or is a hidden virpage */
707             mySeg = mySeg->next_seg;
708       }
709
710     *cur_id = mySeg;
711     return -1;
712 }
713
714 /******************************************************************************
715  *                          Semi-Private Functions
716  ******************************************************************************/
717 /*******************************************************************************
718  * Function:    CESDLVolume *_DtHelpCeGetSdlVolumePtr (_DtHelpVolumeHdl vol);
719  *
720  * Parameters:  vol     Specifies the loaded volume.
721  *
722  * Return Value:        0 if successful, -1 if a failure occurs
723  *
724  * errno Values:        None
725  *
726  * Purpose:     When the volume is no longer needed, it should be unloaded
727  *              with this call.  Unloading it frees the memory (which means
728  *              any handles on the volume become invalid.)
729  *
730  ******************************************************************************/
731 CESDLVolume *
732 _DtHelpCeGetSdlVolumePtr (
733      _DtHelpVolumeHdl    volume)
734 {
735     _DtHelpVolume vol = (_DtHelpVolume) volume;
736
737     if (vol != NULL)
738         return ((CESDLVolume *) vol->vols.sdl_vol);
739     return NULL;
740 }
741
742 /******************************************************************************
743  *                          Semi-Public Functions
744  ******************************************************************************/
745 /*******************************************************************************
746  * Function:    void _DtHelpCeInitSdlVolume (_DtHelpVolume vol);
747  *
748  * Parameters:  vol     Specifies the loaded volume.
749  *
750  * Return Value:        0 if successful, -1 if a failure occurs
751  *
752  * errno Values:        None
753  *
754  * Purpose:     When the volume is no longer needed, it should be unloaded
755  *              with this call.  Unloading it frees the memory (which means
756  *              any handles on the volume become invalid.)
757  *
758  ******************************************************************************/
759 void
760 _DtHelpCeInitSdlVolume (
761      _DtHelpVolumeHdl    volume)
762 {
763     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
764
765     if (sdlVol != NULL)
766         *sdlVol = DefaultSdlVolume;
767
768 }
769
770 /*******************************************************************************
771  * Function:    void _DtHelpCeOpenSdlVolume (_DtHelpVolume vol);
772  *
773  * Parameters:  vol     Specifies the loaded volume.
774  *
775  * Return Value:        0 if successful, -1 if a failure occurs
776  *
777  * errno Values:        None
778  *
779  * Purpose:     When the volume is no longer needed, it should be unloaded
780  *              with this call.  Unloading it frees the memory (which means
781  *              any handles on the volume become invalid.)
782  *
783  ******************************************************************************/
784 int
785 _DtHelpCeOpenSdlVolume (
786      _DtHelpVolumeHdl    volume)
787 {
788     CESDLVolume *sdlVol;
789     _DtHelpVolume  vol = (_DtHelpVolume) volume;
790
791     sdlVol  = (CESDLVolume *) calloc (1, sizeof(CESDLVolume));
792     if (sdlVol != NULL)
793       {
794         vol->vols.sdl_vol = (SdlVolumeHandle) sdlVol;
795         _DtHelpCeInitSdlVolume(volume);
796         if (_DtHelpCeFrmtSdlVolumeInfo(vol->volFile,
797                                         vol, &(vol->check_time)) == 0)
798           {
799             vol->sdl_flag = True;
800             return 0;
801           }
802
803         vol->vols.sdl_vol = NULL;
804         free(sdlVol);
805       }
806
807     return -1;
808 }
809
810 /*******************************************************************************
811  * Function:    void _DtHelpCeCleanSdlVolume (_DtHelpVolume vol);
812  *
813  * Parameters:  vol     Specifies the loaded volume.
814  *
815  * Return Value:        0 if successful, -1 if a failure occurs
816  *
817  * errno Values:        None
818  *
819  * Purpose:     When the volume is no longer needed, it should be unloaded
820  *              with this call.  Unloading it frees the memory (which means
821  *              any handles on the volume become invalid.)
822  *
823  ******************************************************************************/
824 void
825 _DtHelpCeCleanSdlVolume (
826      _DtHelpVolumeHdl    volume)
827 {
828     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
829
830     if (sdlVol != NULL)
831       {
832         _DtHelpFreeSegments(sdlVol->snb  , _DtCvFALSE, sdlVol->destroy_region,
833                                                         sdlVol->client_data);
834         _DtHelpFreeSegments(sdlVol->title, _DtCvFALSE, sdlVol->destroy_region,
835                                                         sdlVol->client_data);
836
837         /*
838          * free the index information
839          */
840         FreeEntryInfo(sdlVol->index);
841         _DtHelpFreeSegments(sdlVol->index, _DtCvFALSE, NULL, NULL);
842
843         /*
844          * free the toss information.
845          */
846         FreeTossInfo(sdlVol->toss);
847         _DtHelpFreeSegments(sdlVol->toss , _DtCvFALSE, NULL, NULL);
848
849         /*
850          * free the ids
851          */
852         FreeIds(sdlVol->loids);
853         _DtHelpFreeSegments(sdlVol->loids, _DtCvFALSE, NULL, NULL);
854
855         /*
856          * free the document information.
857          */
858         if (NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
859             free(_SdlDocInfoPtrLanguage(sdlVol->sdl_info));
860
861         if (NULL != _SdlDocInfoPtrCharSet(sdlVol->sdl_info))
862             free(_SdlDocInfoPtrCharSet(sdlVol->sdl_info));
863
864         if (NULL != _SdlDocInfoPtrDocId(sdlVol->sdl_info))
865             free(_SdlDocInfoPtrDocId(sdlVol->sdl_info));
866
867         if (NULL != _SdlDocInfoPtrFirstPg(sdlVol->sdl_info))
868             free(_SdlDocInfoPtrFirstPg(sdlVol->sdl_info));
869
870         if (NULL != _SdlDocInfoPtrSdlDtd(sdlVol->sdl_info))
871             free(_SdlDocInfoPtrSdlDtd(sdlVol->sdl_info));
872
873         if (NULL != _SdlDocInfoPtrStamp(sdlVol->sdl_info))
874             free(_SdlDocInfoPtrStamp(sdlVol->sdl_info));
875
876         free(sdlVol->sdl_info);
877       }
878 }
879
880 /*******************************************************************************
881  * Function:    int _DtHelpCeRereadSdlVolume (_DtHelpVolume vol);
882  *
883  * Parameters:  vol     Specifies the loaded volume.
884  *
885  * Return Value:        0 if successful, -1 if a failure occurs
886  *
887  * errno Values:        None
888  *
889  * Purpose:     When the volume is no longer needed, it should be unloaded
890  *              with this call.  Unloading it frees the memory (which means
891  *              any handles on the volume become invalid.)
892  *
893  ******************************************************************************/
894 int
895 _DtHelpCeRereadSdlVolume (
896      _DtHelpVolumeHdl    volume)
897 {
898     _DtHelpCeCleanSdlVolume(volume);
899     _DtHelpCeInitSdlVolume(volume);
900     if (_DtHelpCeFrmtSdlVolumeInfo(_DtHelpCeGetVolumeName(volume),
901                                         volume, NULL) == 0)
902             return 0;
903
904     return -1;
905 }
906
907 /*******************************************************************************
908  * Function:    void _DtHelpCeCloseSdlVolume (_DtHelpVolume vol);
909  *
910  * Parameters:  vol     Specifies the loaded volume.
911  *
912  * Return Value:        0 if successful, -1 if a failure occurs
913  *
914  * errno Values:        None
915  *
916  * Purpose:     When the volume is no longer needed, it should be unloaded
917  *              with this call.  Unloading it frees the memory (which means
918  *              any handles on the volume become invalid.)
919  *
920  ******************************************************************************/
921 void
922 _DtHelpCeCloseSdlVolume (
923      _DtHelpVolumeHdl    volume)
924 {
925     CESDLVolume *sdlVol = _DtHelpCeGetSdlVolumePtr(volume);
926
927     if (sdlVol != NULL)
928       {
929         _DtHelpCeCleanSdlVolume(volume);
930         free(sdlVol);
931       }
932 }
933
934 /*****************************************************************************
935  * Function: Boolean _DtHelpCeGetSdlHomeTopicId (_DtHelpVolume vol,
936  *                                      char *target_id,
937  *                                      char *ret_name, int *ret_offset)
938  *
939  * Parameters:  vol             Specifies the loaded volume
940  *              target_id       Specifies target location ID
941  *              ret_name        Returns a null terminated string
942  *                              containing a fully qualified path to
943  *                              the file that contains 'target_id'.
944  *              ret_offset      Returns the offset into 'ret_name'
945  *                              to the topic that contains 'target_id'.
946  *
947  * Memory own by caller:
948  *              ret_name
949  *
950  * Returns:     True if successful, False if a failure occurs
951  *
952  * errno Values:        EINVAL          Specifies an invalid parameter was
953  *                                      used.
954  *                      CEErrorMalloc
955  *                      CEErrorLocIdNotFound
956  *                                      Specifies that 'locId' was not
957  *                                      found.
958  *
959  * Purpose:     Find which topic contains a specified locationID.
960  *
961  *****************************************************************************/
962 char *
963 _DtHelpCeGetSdlHomeTopicId (
964         _DtHelpVolumeHdl         volume)
965 {
966     _DtCvSegment *idSegs;
967     CESDLVolume  *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
968
969     if (sdlVol->sdl_info != NULL)
970       {
971         /*
972          * Was the first page topic declared in the header?
973          */
974         if (NULL != _SdlDocInfoPtrFirstPg(sdlVol->sdl_info))
975             return (_SdlDocInfoPtrFirstPg(sdlVol->sdl_info));
976
977         /*
978          * have to search the list of ids for the home topic.  This is a
979          * bit of a kludge since we are looking for a specific string in
980          * the rssi.  But this is for backwards compatibility since the
981          * Snapshot release of the help system were released with out
982          * the first-page attribute and relied on _hometopic.
983          *
984          * Plus, first-page is #IMPLIED, which means that the parser
985          * that generated this SDL document does not have to use this
986          * attribute.
987          */
988         if (_DtHelpCeGetSdlVolIds(volume, -1, &idSegs) != 0)
989             return NULL;
990
991         while (idSegs != NULL)
992           {
993             if (SdlIdVirpage == _SdlSegToSdlIdInfoType(idSegs) &&
994                 _DtHelpCeStrCaseCmpLatin1(_SdlIdInfoPtrRssi(
995                                                 _SdlSegToSdlIdInfoPtr(idSegs)),
996                                 "_hometopic") == 0)
997                 return _DtCvContainerIdOfSeg(idSegs);
998
999             idSegs = idSegs->next_seg;
1000           }
1001       }
1002
1003     return NULL;
1004 }
1005
1006 /*****************************************************************************
1007  * Function: Boolean _DtHelpCeFindSdlId (_DtHelpVolume vol, char *target_id,
1008  *                                      char *ret_name, int *ret_offset)
1009  *
1010  * Parameters:  vol             Specifies the loaded volume
1011  *              target_id       Specifies target location ID
1012  *              ret_name        Returns a null terminated string
1013  *                              containing a fully qualified path to
1014  *                              the file that contains 'target_id'.
1015  *              ret_offset      Returns the offset into 'ret_name'
1016  *                              to the topic that contains 'target_id'.
1017  *
1018  * Memory own by caller:
1019  *              ret_name
1020  *
1021  * Returns:     True if successful, False if a failure occurs
1022  *
1023  * errno Values:        EINVAL          Specifies an invalid parameter was
1024  *                                      used.
1025  *                      CEErrorMalloc
1026  *                      CEErrorLocIdNotFound
1027  *                                      Specifies that 'locId' was not
1028  *                                      found.
1029  *
1030  * Purpose:     Find which topic contains a specified locationID.
1031  *
1032  *****************************************************************************/
1033 int
1034 _DtHelpCeFindSdlId (
1035         _DtHelpVolumeHdl         volume,
1036         char            *target_id,
1037         int              fd,
1038         char            **ret_name,
1039         int             *ret_offset )
1040 {
1041     _DtHelpVolume   vol    = (_DtHelpVolume) volume;
1042     _DtCvSegment        *pEl;
1043
1044     pEl = _DtHelpCeMapSdlIdToSegment(volume, target_id, fd);
1045
1046     if (pEl != NULL)
1047       {
1048         if (ret_name != NULL)
1049             *ret_name   = strdup(vol->volFile);
1050         *ret_offset = _SdlIdInfoPtrOffset(_SdlSegToSdlIdInfoPtr(pEl));
1051         return True;
1052       }
1053
1054     return False;
1055 }
1056
1057 /*****************************************************************************
1058  * Function: int _DtHelpCeGetSdlKeywordList (
1059  *
1060  * Parameters:
1061  *
1062  * Returns:     0 if successful, -1 if not.
1063  *
1064  * errno Values:
1065  *
1066  * Purpose:     Get the KeywordList for an SDL volume.
1067  *
1068  *****************************************************************************/
1069 int
1070 _DtHelpCeGetSdlKeywordList (
1071         _DtHelpVolumeHdl         volume)
1072 {
1073     CESDLVolume *sdlVol =  _DtHelpCeGetSdlVolumePtr(volume);
1074
1075     if (_DtHelpCeGetSdlVolIndex(volume) != 0 || NULL == sdlVol->index
1076                         || NULL == _DtCvContainerListOfSeg(sdlVol->index))
1077         return -1;
1078
1079     return(ProcessEntry(((_DtHelpVolume) volume),
1080                         _DtCvContainerListOfSeg(sdlVol->index), NULL));
1081 }
1082
1083 /*****************************************************************************
1084  * Function: int _DtHelpCeGetSdlVolumeAsciiAbstract(volume);
1085  *
1086  * Parameters:
1087  *
1088  * Returns:     0 if successful, -1 if not.
1089  *
1090  * errno Values:
1091  *
1092  * Purpose:     Get the KeywordList for an SDL volume.
1093  *
1094  *****************************************************************************/
1095 char *
1096 _DtHelpCeGetSdlVolumeAsciiAbstract(
1097     _DtHelpVolumeHdl    volume)
1098 {
1099     return(_DtHelpCeFrmtSdlVolumeAbstractToAscii(volume));
1100 }
1101
1102 /*****************************************************************************
1103  * Function: int _DtHelpCeGetSdlIdPath(volume, target_id, ret_ids);
1104  *
1105  * Parameters:
1106  *
1107  * Returns:     > 0 if successful, -1 if not.
1108  *
1109  * Memory:      The memory returned is owned by the caller.
1110  *
1111  * Purpose:     Get the list of location ids between the top and the
1112  *              target_id.
1113  *
1114  *****************************************************************************/
1115 int
1116 _DtHelpCeGetSdlIdPath(
1117     _DtHelpVolumeHdl       volume,
1118     char                  *target_id,
1119     char                ***ret_ids)
1120 {
1121     _DtCvSegment   *idSegs;
1122     _DtCvSegment   *targetEl;
1123     int             hiddenNo = -1;
1124
1125     targetEl = _DtHelpCeMapSdlIdToSegment(volume, target_id, -1);
1126
1127     if (targetEl == NULL)
1128         return -1;
1129
1130     *ret_ids = NULL;
1131
1132     if (_DtHelpCeGetSdlVolIds(volume, -1, &idSegs) != 0)
1133         return 0;
1134
1135     if (_SdlVolumeMinorNumber(_DtHelpCeGetSdlVolumePtr(volume)) >= SDL_DTD_1_1)
1136         hiddenNo = 0;
1137
1138     return (MapPath(&idSegs, targetEl, -1, 0, hiddenNo, ret_ids));
1139 }
1140
1141 /*****************************************************************************
1142  * Function: _DtCvSegment *_DtHelpCeMapSdlIdToSegment(volume, target_id);
1143  *
1144  * Parameters:
1145  *
1146  * Returns:     > 0 if successful, -1 if not.
1147  *
1148  * errno Values:
1149  *
1150  * Purpose:     Get the list of location ids between the top and the
1151  *              target_id.
1152  *
1153  *****************************************************************************/
1154 _DtCvSegment *
1155 _DtHelpCeMapSdlIdToSegment(
1156     _DtHelpVolumeHdl       volume,
1157     const char            *target_id,
1158     int                    fd)
1159 {
1160     int             underScore = False;
1161     short           minorNo;
1162     _DtCvSegment   *idSegs;
1163     char           *idString;
1164     char            resStr[128] = "SDL-RESERVED-";
1165
1166     minorNo = _SdlVolumeMinorNumber(_DtHelpCeGetSdlVolumePtr(volume));
1167
1168     if (*target_id == '_')
1169       {
1170         /*
1171          * parsers generating SDL_DTD_1_0 and earlier put the special
1172          * access points (_hometopic, _abstract, _copyright, etc.) in
1173          * the SSI.
1174          */
1175         if (minorNo < SDL_DTD_1_1)
1176             underScore = True;
1177         else
1178           {
1179             target_id++;
1180             strcat(resStr, target_id);
1181             target_id = resStr;
1182           }
1183       }
1184
1185     if (_DtHelpCeGetSdlVolIds(volume, fd, &idSegs) != 0)
1186         return NULL;
1187
1188     while (idSegs != NULL)
1189       {
1190         if (underScore == True)
1191             idString = _SdlIdInfoPtrRssi(_SdlSegToSdlIdInfoPtr(idSegs));
1192         else
1193             idString = _DtCvContainerIdOfSeg(idSegs);
1194
1195         if (idString != NULL &&
1196                         _DtHelpCeStrCaseCmpLatin1(idString, target_id) == 0)
1197             return idSegs;
1198
1199         idSegs = idSegs->next_seg;
1200       }
1201
1202     return NULL;
1203 }
1204
1205 /*****************************************************************************
1206  * Function: int _DtHelpCeMapIdToSdlTopicId(volume, target_id);
1207  *
1208  * Parameters:
1209  *
1210  * Returns:     > 0 if successful, -1 if not.
1211  *
1212  * errno Values:
1213  *
1214  * Purpose:     Get the id of the virpage containing the target_id.
1215  *
1216  *****************************************************************************/
1217 int
1218 _DtHelpCeMapIdToSdlTopicId(
1219     _DtHelpVolumeHdl       volume,
1220     const char            *target_id,
1221     char                 **ret_id)
1222 {
1223     int                  found = -1;
1224     _DtCvSegment        *idList;
1225     _DtCvSegment        *idSeg;
1226     SDLIdInfo           *idInfo;
1227
1228     if (_DtHelpCeGetSdlVolIds(volume, -1, &idList) == 0)
1229       {
1230         idSeg = _DtHelpCeMapSdlIdToSegment(volume, target_id, -1);
1231         if (idSeg != NULL)
1232           {
1233             while (found == -1 && idList != NULL)
1234               {
1235                 idInfo = _SdlSegToSdlIdInfoPtr(idList);
1236                 if (_SdlIdInfoPtrType(idInfo) == SdlIdVirpage)
1237                     *ret_id = _DtCvContainerIdOfSeg(idList);
1238
1239                 if (idList == idSeg)
1240                     found = 0;
1241                 else
1242                     idList = idList->next_seg;
1243               }
1244           }
1245       }
1246
1247     return found;
1248 }
1249
1250 /*****************************************************************************
1251  * Function: char * _DtHelpCeGetSdlVolCharSet(volume);
1252  *
1253  * Parameters:
1254  *
1255  * Returns:     the pointer to the locale string. Null otherwise.
1256  *
1257  * errno Values:
1258  *
1259  * Purpose:     Get the locale of the volume.
1260  *
1261  *****************************************************************************/
1262 const char *
1263 _DtHelpCeGetSdlVolCharSet(
1264     _DtHelpVolumeHdl       volume)
1265 {
1266     const char     *charSet = IsoString;
1267     CESDLVolume    *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
1268
1269     if (sdlVol->sdl_info != NULL &&
1270                         NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
1271         charSet = _SdlDocInfoPtrCharSet(sdlVol->sdl_info);
1272
1273     return charSet;
1274 }
1275
1276 /*****************************************************************************
1277  * Function: char * _DtHelpCeGetSdlVolLanguage(volume);
1278  *
1279  * Parameters:
1280  *
1281  * Returns:     the pointer to the language used in the volume.
1282  *
1283  * errno Values:
1284  *
1285  * Purpose:     Get the locale of the volume.
1286  *
1287  *****************************************************************************/
1288 char *
1289 _DtHelpCeGetSdlVolLanguage(
1290     _DtHelpVolumeHdl       volume)
1291 {
1292     char           *language = "C";
1293     CESDLVolume    *sdlVol  =  _DtHelpCeGetSdlVolumePtr(volume);
1294
1295     if (sdlVol->sdl_info != NULL &&
1296                         NULL != _SdlDocInfoPtrLanguage(sdlVol->sdl_info))
1297         language = _SdlDocInfoPtrLanguage(sdlVol->sdl_info);
1298
1299     return language;
1300 }
1301
1302 /*****************************************************************************
1303  * Function: char * _DtHelpCeGetSdlVolumeLocale(volume);
1304  *
1305  * Parameters:
1306  *
1307  * Returns:     the pointer to the locale string. Null otherwise.
1308  *
1309  * errno Values:
1310  *
1311  * Purpose:     Get the locale of the volume.
1312  *
1313  *****************************************************************************/
1314 char *
1315 _DtHelpCeGetSdlVolumeLocale(
1316     _DtHelpVolumeHdl       volume)
1317 {
1318     int             langLen;
1319     char           *locale;
1320     char           *lang;
1321     const char     *charSet;
1322
1323     lang    = _DtHelpCeGetSdlVolLanguage(volume);
1324     charSet = _DtHelpCeGetSdlVolCharSet(volume);
1325
1326     langLen = strlen(lang);
1327     locale  = (char *) malloc (langLen + strlen(charSet) + 2);
1328     if (locale != NULL)
1329       {
1330         strcpy(locale, lang);
1331         if (langLen != 0 && *charSet != '\0')
1332           {
1333             locale[langLen++] = '.';
1334             strcpy(&(locale[langLen]), charSet);
1335           }
1336       }
1337
1338     return locale;
1339 }
1340
1341 /*****************************************************************************
1342  * Function: int _DtHelpCeGetSdlDocStamp(volume, ret_doc, ret_time);
1343  *
1344  * Parameters:
1345  *
1346  * Returns:     0 if successful, -2 if the volume does not contain
1347  *              one or the other, -1 if any other failure.
1348  *
1349  * Memory:      The Caller owns the memory returned in ret_doc and ret_time.
1350  *
1351  * Purpose:     Get the doc id and time stamp of a volume.
1352  *
1353  *****************************************************************************/
1354 int
1355 _DtHelpCeGetSdlDocStamp(
1356     _DtHelpVolumeHdl       volume,
1357     char                **ret_doc,
1358     char                **ret_time)
1359 {
1360     int             result    = -1;
1361     char           *docId     = NULL;
1362     char           *timestamp = NULL;
1363     CESDLVolume    *sdlVol    =  _DtHelpCeGetSdlVolumePtr(volume);
1364
1365     if (sdlVol->sdl_info != NULL)
1366       {
1367         result = 0;
1368         if (NULL != _SdlDocInfoPtrDocId(sdlVol->sdl_info))
1369             docId = strdup(_SdlDocInfoPtrDocId(sdlVol->sdl_info));
1370         else
1371             result = -2;
1372
1373         if (NULL != _SdlDocInfoPtrStamp(sdlVol->sdl_info))
1374             timestamp = strdup(_SdlDocInfoPtrStamp(sdlVol->sdl_info));
1375         else
1376             result = -2;
1377       }
1378
1379     if (ret_doc != NULL)
1380         *ret_doc = docId;
1381     if (ret_time != NULL)
1382         *ret_time = timestamp;
1383
1384     if (result == 0 && (docId == NULL || timestamp == NULL)) {
1385         free(docId);     /* Incase only one of them is NULL */
1386         free(timestamp); /*  " */
1387         return -1;
1388     }
1389
1390     return result;
1391 }
1392
1393 /*****************************************************************************
1394  * Function: int _DtHelpCeGetSdlTopicChildren(
1395  *
1396  * Parameters:
1397  *
1398  * Returns:     pointer to the element, Null otherwise.
1399  *
1400  * errno Values:
1401  *
1402  * Purpose:     Find the specified element.
1403  *
1404  *****************************************************************************/
1405 int
1406 _DtHelpCeGetSdlTopicChildren(
1407     _DtHelpVolumeHdl     volume,
1408     char                *target,
1409     char                ***ret_ids)
1410 {
1411     int           done   = False;
1412     int          count  = 0;
1413     int          segLev;
1414     _DtCvSegment *idSeg;
1415     SDLIdInfo    *idInfo;
1416
1417     /*
1418      * Find the target id.
1419      */
1420     idSeg = _DtHelpCeMapSdlIdToSegment(volume, target, -1);
1421
1422     /*
1423      * save this level and start looking for its children at the next seg.
1424      */
1425     *ret_ids = NULL;
1426     if (idSeg != NULL)
1427       {
1428         idInfo = _SdlSegToSdlIdInfoPtr(idSeg);
1429         segLev = _SdlIdInfoPtrRlevel(idInfo) + 1;
1430         idSeg  = idSeg->next_seg;
1431       }
1432
1433     /*
1434      * process any virpage that has the correct level
1435      */
1436     while (idSeg != NULL && done == False)
1437       {
1438         idInfo = _SdlSegToSdlIdInfoPtr(idSeg);
1439         if (_SdlIdInfoPtrType(idInfo) == SdlIdVirpage)
1440           {
1441             /*
1442              * If greater, we're at the next sibling.
1443              */
1444             if (segLev > _SdlIdInfoPtrRlevel(idInfo))
1445                 done = True;
1446             else if (segLev == _SdlIdInfoPtrRlevel(idInfo))
1447               {
1448                 *ret_ids = (char **) _DtHelpCeAddPtrToArray( (void **) *ret_ids,
1449                         (void *)(strdup(_DtCvContainerIdOfSeg(idSeg))));
1450                 if ((*ret_ids) == NULL)
1451                     return -1;
1452
1453                 count++;
1454               }
1455           }
1456         idSeg = idSeg->next_seg;
1457       }
1458
1459     return count;
1460 }