FileUtils.c: fix CERT VU#575804
[oweals/cde.git] / cde / lib / DtHelp / FormatCCDF.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 /* $TOG: FormatCCDF.c /main/23 1999/10/14 15:06:28 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:     FormatCCDF.c
28  **
29  **   Project:    Unix Desktop Help
30  **
31  **   Description: This code formats an file in CCDF (Cache Creek
32  **                Distribution Format) into internal format.
33  **
34  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
35  **
36  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
37  **  (c) Copyright 1993, 1994 International Business Machines Corp.
38  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  **  (c) Copyright 1993, 1994 Novell, Inc.
40  **
41  **
42  **
43  ****************************************************************************
44  ************************************<+>*************************************/
45
46 /*
47  * system includes
48  */
49 #include <ctype.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #if defined(sun)
53 #include <sys/utsname.h>
54 #endif
55 #include <limits.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <stdio.h>
60
61 #include <X11/Xlib.h>
62 #include <X11/Xresource.h>
63
64 #ifdef X_NOT_STDC_ENV
65 extern int errno;
66 #endif
67
68 /*
69  * Canvas Engine includes
70  */
71 #include "CanvasP.h"
72 #include "CanvasSegP.h"
73 #include "LinkMgrP.h"
74
75 /*
76  * private includes
77  */
78 #include "bufioI.h"
79 #include "Access.h"
80 #include "AccessI.h"
81 #include "AccessP.h"
82 #include "AccessCCDFI.h"
83 #include "CanvasError.h"
84 #include "CleanUpI.h"
85 #include "CvStringI.h"
86 #include "CvtToArrayP.h"
87 #include "FontAttrI.h"
88 #include "FormatUtilI.h"
89 #include "FormatCCDFI.h"
90 #include "CCDFUtilI.h"
91 #include "HelpXlate.h"
92 #include "StringFuncsI.h"
93
94 extern char *_DtHelpGetLocale(void);
95
96 #ifdef NLS16
97 #endif
98
99 /******************************************************************************
100  * Private variables and defines.
101  *****************************************************************************/
102 #define BUFF_SIZE       1024
103 #define GROW_SIZE       10
104 #define INFO_GROW       256
105
106 #define CCDF_LINK_JUMP_REUSE    0
107 #define CCDF_LINK_JUMP_NEW      1
108 #define CCDF_LINK_DEFINITION    2
109 #define CCDF_LINK_EXECUTE       3
110 #define CCDF_LINK_MAN_PAGE      4
111 #define CCDF_LINK_APP_DEFINE    5
112
113 #define IsTypeHyperText(x)      (((x) & _DtCvHYPER_TEXT) ? 1 : 0)
114 #define IsTypeNewLine(x)        (((x) & _DtCvNEW_LINE) ? 1 : 0)
115 #define NextAvailSeg(x)         (NULL != x.list ? &(x.list[x.cnt]) : NULL)
116
117 /******************************************************************************
118  * Private structures
119  ******************************************************************************/
120 typedef struct  _segList {
121         int              cnt;
122         int              max;
123         _DtCvSegment    *list;
124 } SegList;
125
126 typedef struct _formatVariables {
127
128         int              last_was_space;
129         int              last_was_mb;
130         int              last_was_nl;
131
132         char            *rd_buf;
133         char            *rd_ptr;
134         char            *fmt_buf;
135         char            *my_path;
136         char            *vol_name;
137         char            *topic_id;
138         char            *topic_char_set;
139         char            *topic_lang;
140
141         int              rd_size;
142         int              rd_flag;
143
144         int              topic_mb_max;
145         int              cur_mb_max;
146
147         int              fmt_buf_max;
148         int              fmt_size;
149         int              cell_cnt;
150
151         BufFilePtr       my_file;
152         SegList          my_list;
153         _DtCvLinkDb      my_links;
154         _FrmtUiInfo     *ui_info;
155 } FormatVariables;
156
157
158 enum    _processState
159   {
160     NormalState,
161     LabelBody
162   };
163
164 typedef enum _processState      ProcessState;
165
166 /******************************************************************************
167  * Private Function Declarations
168  ******************************************************************************/
169 static  _DtCvSegment    *AllocateSegments(
170                                 _DtCvSegment      *p_seg,
171                                 int              original_size,
172                                 int              new_size );
173 static  int              AppendCharToInfo(
174                                 FormatVariables  *cur_vars,
175                                 char            **src );
176 static  int              AppendOctalToInfo(
177                                 FormatVariables *cur_vars,
178                                 char            *src );
179 static  int              AppendSpaceToInfo ( 
180                                 FormatVariables  *cur_vars,
181                                 char            **src,
182                                 _DtCvFrmtOption   type );
183 static  int              AppendToInfo (
184                                 FormatVariables  *cur_vars,
185                                 char            **src,
186                                 const char       *scan_string );
187 static  int              ChangeFont(
188                                 int               whichOne,
189                                 unsigned long     seg_flags,
190                                 _DtCvFrmtOption   frmt_type,
191                                 _DtHelpFontHints *font_attr,
192                                 int               linkspec,
193                                 FormatVariables  *cur_vars,
194                                 ProcessState      cur_state,
195                                 int               flags,
196                                 int               ret_on_nl,
197                                 int               fnt_flag);
198 static  int              CheckIdString(
199                                 FormatVariables  *cur_vars,
200                                 ProcessState      cur_state,
201                                 unsigned long     seg_flags,
202                                 _DtCvFrmtOption   frmt_type,
203                                 _DtHelpFontHints *font_attr,
204                                 int               linkspec,
205                                 int               flags,
206                                 int               ret_on_nl,
207                                 int               fnt_flag);
208 static  int              CheckSaveSegment (
209                                 unsigned long     seg_flags,
210                                 _DtHelpFontHints *font_attr,
211                                 int              link_spec,
212                                 FormatVariables  *cur_vars );
213 static  int              CreateSaveGraphic (
214                                 FormatVariables *cur_vars,
215                                 int              type,
216                                 char            *file_name,
217                                 int              link_spec );
218 static  int              CheckSegList (
219                                 FormatVariables *cur_vars);
220 static  int              Format(
221                                 FormatVariables *cur_vars,
222                                 _FrmtUiInfo     *ui_info,
223                                 char            *id_string,
224                                 _DtCvTopicPtr   *ret_handle);
225 static  int              GetNextBuffer (
226                                 FormatVariables *cur_vars);
227 static  int              GetStringParameter(
228                                 FormatVariables  *cur_vars,
229                                 _DtCvValue        flag,
230                                 _DtCvValue        eat_escape,
231                                 _DtCvValue        ignore_quotes,
232                                 _DtCvValue        less_test,
233                                 char            **ret_string );
234 static  int              GetValueParameter(
235                                 FormatVariables *cur_vars,
236                                 _DtCvValue       flag,
237                                 int             *ret_value );
238 static  int              InitStructure(
239                                 FormatVariables *cur_vars,
240                                 _FrmtUiInfo     *ui_info,
241                                 char            *rd_buf,
242                                 int              rd_size);
243 static  int              Parse(
244                                 int               cur_cmd,
245                                 ProcessState      cur_state,
246                                 FormatVariables  *cur_vars,
247                                 unsigned long     seg_flags,
248                                 _DtCvFrmtOption   frmt_type,
249                                 _DtHelpFontHints *font_attr,
250                                 int               linkspec,
251                                 const char       *scan_string,
252                                 int               allowed,
253                                 int               ret_on_nl,
254                                 int               fnt_flag);
255 static  int              ProcessFigureCmd(
256                                 FormatVariables  *cur_vars,
257                                 ProcessState      cur_state,
258                                 _DtCvFrmtOption   frmt_type,
259                                 _DtHelpFontHints *font_attr,
260                                 int               ret_on_nl,
261                                 int               fnt_flag);
262 static  int              ProcessHypertext(
263                                 FormatVariables  *cur_vars,
264                                 ProcessState      cur_state,
265                                 unsigned long     seg_flags,
266                                 _DtCvFrmtOption   frmt_type,
267                                 _DtHelpFontHints *font_attr,
268                                 int               flags,
269                                 int               ret_on_nl,
270                                 int               fnt_flag);
271 static  int              ProcessInLine(
272                                 FormatVariables *cur_vars,
273                                 int              seg_type,
274                                 int              link_spec );
275 static  int              ProcessLabelCmd(
276                                 FormatVariables  *cur_vars,
277                                 unsigned long     seg_flags,
278                                 _DtCvFrmtOption   frmt_type,
279                                 _DtHelpFontHints *font_attr,
280                                 int               link_spec,
281                                 int               flags,
282                                 int               ret_on_nl,
283                                 int               fnt_flag,
284                                 _DtCvSegment    **ret_list);
285 static  int              ProcessParagraph (
286                                 FormatVariables *cur_vars,
287                                 ProcessState     cur_state,
288                                 int              fnt_flag);
289 static  int              SaveNewLine(
290                                 FormatVariables  *cur_vars,
291                                 int               cur_cmd,
292                                 _DtHelpFontHints *font_attr,
293                                 int               link_spec );
294 static  int              SaveStringAsSegments (
295                                 FormatVariables  *cur_vars,
296                                 unsigned long     seg_flags,
297                                 _DtHelpFontHints *font_attr,
298                                 int               link_spec);
299 static  int              SkipToNextToken (
300                                 FormatVariables *cur_vars,
301                                 _DtCvValue       flag );
302 static  void             TerminateSegList (
303                                 SegList         *list,
304                                 int              flag);
305 static  int              SegmentSave(
306                                 FormatVariables *cur_vars,
307                                 unsigned long    seg_type,
308                                 _DtHelpFontHints *font_attr,
309                                 char            *string,
310                                 int              str_size,
311                                 int              num_chars,
312                                 int              link_spec);
313
314 /********    End Public Function Declarations    ********/
315
316 /******************************************************************************
317  * Private variables
318  *****************************************************************************/
319 static  const char      *Specials = "<\n\\ ";
320 static  const char      *SpaceString = "        ";
321 static  const char      *CString = "C";
322 static  const char      *Period  = ".";
323 static  const char      *Slash   = "/";
324
325 static const FormatVariables DefVars = {
326         True,           /* int           last_was_space;        */
327         False,          /* int           last_was_mb;           */
328         False,          /* int           last_was_nl;           */
329
330         NULL,           /* char         *rd_buf;                */
331         NULL,           /* char         *rd_ptr;                */
332         NULL,           /* char         *fmt_buf;               */
333         NULL,           /* char         *my_path;               */
334         NULL,           /* char         *vol_name;              */
335         NULL,           /* char         *topic_id;              */
336         NULL,           /* char         *topic_char_set;        */
337         NULL,           /* char         *topic_lang;            */
338
339         0,              /* int           rd_size;               */
340         0,              /* int           rd_flag;               */
341
342         1,              /* int           topic_mb_max;          */
343         1,              /* int           cur_mb_max;            */
344
345         0,              /* int           fmt_buf_max;           */
346         0,              /* int           fmt_size;              */
347         0,              /* int           cell_cnt;              */
348
349         NULL,           /* BufFilePtr    my_file;               */
350           {             /* SegList       my_list;               */
351             0,              /* int               cnt;   */
352             0,              /* int               max;   */
353             NULL,           /* _DtCvSegment     *list;  */
354           },            /* SegList       my_list;               */
355         NULL,           /* _DtCvLinkDb   my_links;              */
356         NULL,           /* _FrmtUiInfo   ui_info;               */
357 };
358
359 static  const   SegList         InitList =
360   {
361     0,          /* int           cnt;   */
362     0,          /* int           max;   */
363     NULL,       /* _DtCvSegment *list;  */
364   };
365
366 static  const   _DtCvContainer  DefContainer =
367   {
368         NULL,                   /* char                 *id;            */
369         NULL,                   /* char                 *justify_char;  */
370         _DtCvDYNAMIC,           /* _DtCvFrmtOption       type;          */
371         _DtCvBORDER_NONE,       /* _DtCvFrmtOption       border;        */
372         _DtCvJUSTIFY_LEFT,      /* _DtCvFrmtOption       justify;       */
373         _DtCvJUSTIFY_TOP,       /* _DtCvFrmtOption       vjustify;      */
374         _DtCvJUSTIFY_LEFT_MARGIN,/* _DtCvFrmtOption      orient;        */
375         _DtCvJUSTIFY_TOP,       /* _DtCvFrmtOption       vorient;       */
376         _DtCvWRAP_NONE,         /* _DtCvFrmtOption       flow;          */
377         10000,                  /* int                   percent;       */
378         0,                      /* _DtCvUnit             leading;       */
379         0,                      /* _DtCvUnit             fmargin;       */
380         0,                      /* _DtCvUnit             lmargin;       */
381         0,                      /* _DtCvUnit             rmargin;       */
382         0,                      /* _DtCvUnit             tmargin;       */
383         1,                      /* _DtCvUnit             bmargin;       */
384         {0, NULL},              /* _DtCvLine             bdr_info;      */
385         NULL,                   /* _DtCvSegment          seg_list;      */
386   };
387
388 static const FrmtPrivateInfo DefPrivInfo =
389   {
390         (char) False,           /* char          top_block;     */
391         (char) False,           /* char          dup_flag;      */
392         0,                      /* int           sdl_type;      */
393         NULL,                   /* void         *match_info;    */
394         NULL,                   /* void         *id_info;       */
395         NULL,                   /* void         *tmp_info;      */
396   };
397
398 /******************************************************************************
399  *
400  * Private Functions
401  *
402  *****************************************************************************/
403 /******************************************************************************
404  * Function:    int CreateMarker (
405  *
406  * Parameters:
407  *              cur_vars        Specifies the current setting of
408  *                              formatting variables.
409  *              id_string       The id string for the marker.
410  *
411  * Returns:     0 if successful, -1 if failure.
412  *
413  * Purpose:     To create a marker id.
414  *
415  *****************************************************************************/
416 static  int
417 CreateMarker (
418     FormatVariables     *cur_vars,
419     char                *id_string)
420 {
421     int result;
422
423     /*
424      * make sure there is room for the marker segment
425      */
426     result = CheckSegList(cur_vars);
427     if (-1 != result)
428       {
429         int              cnt  = cur_vars->my_list.cnt;
430         _DtCvSegment    *list = cur_vars->my_list.list;
431
432         /*
433          * now make a mark segment here.
434          */
435         list[cnt].type = _DtCvSetTypeToMarker(list[cnt].type);
436         _DtCvIdOfMarkerSeg(&list[cnt]) = id_string;
437         cur_vars->my_list.cnt++;
438       }
439
440     return result;
441 }
442
443 /******************************************************************************
444  * Function:    void GetMbLen (
445  *
446  * Parameters:
447  *              cur_vars        Specifies the current setting of
448  *                              formatting variables.
449  *              font_str        Specifies the CCDF string for a
450  *                              CHARACTERSET change.  The string is
451  *                              modified by this routine.
452  *              lang_ptr        Returns the language and territory
453  *                              value.  The caller owns this memory.
454  *              set_ptr         Returns the code set of the language.
455  *                              The caller owns this memory.
456  *
457  * Returns:     Nothing
458  *
459  * Purpose:     1) To decompose the font_string into a language and code set
460  *                 portions.
461  *              2) To set the mb_cur_len variable in cur_vars.
462  *
463  *****************************************************************************/
464 static  void
465 GetMbLen (
466     FormatVariables      *cur_vars,
467     char                 *font_str,
468     char                **lang_ptr,
469     char                **set_ptr)
470 {
471     int   i;
472     char *ptr;
473     char *langPart = NULL;
474     char *codePart = NULL;
475
476     /*
477      * strip spaces
478      */
479     while (*font_str == ' ')
480         font_str++;
481
482     for (i = strlen(font_str) - 1; i > -1 && font_str[i] == ' '; i--)
483         font_str[i] = '\0';
484
485     /*
486      * check for locale.codeset
487      */
488     if (_DtHelpCeStrchr(font_str, ".", 1, &ptr) == 0)
489       {
490         /*
491          * make font_str two seperate strings by replacing
492          * the dot with a end of line.
493          */
494         *ptr++ = '\0';
495         langPart = strdup(font_str);
496         codePart = strdup(ptr);
497       }
498
499     /*
500      * old CCDF volume
501      */
502     else
503       {
504         _DtHelpCeXlateOpToStdLocale(DtLCX_OPER_CCDF, font_str,
505                                                 NULL, &langPart, &codePart);
506         /*
507          * if the language is not specified for the code set,
508          * get the environment's.
509          */
510         if (strcmp(langPart, "?") == 0)
511           {
512             free(langPart);
513
514             langPart = _DtHelpGetLocale();
515             if (langPart == NULL || *langPart == '\0')
516               langPart = strdup((char *) CString);
517             else if (_DtHelpCeStrrchr(langPart, "_", MB_CUR_MAX, &ptr) == 0)
518                 *ptr = '\0';
519             else if (_DtHelpCeStrrchr(langPart, Period, MB_CUR_MAX, &ptr) == 0)
520                 *ptr = '\0';
521           }
522       }
523
524     cur_vars->cur_mb_max = _DtHelpCeGetMbLen(langPart, codePart);
525
526     /*
527      * now set the return variables
528      */
529     if (lang_ptr != NULL)
530         *lang_ptr = langPart;
531     else
532         free(langPart);
533
534     if (set_ptr != NULL)
535         *set_ptr = codePart;
536     else
537         free(codePart);
538 }
539
540 /******************************************************************************
541  * Function:    int ReturnLinkWinHint (int ccdf_type)
542  *
543  * Parameters:
544  *
545  * Returns:
546  *
547  * errno Values:
548  *
549  * Purpose:
550  *****************************************************************************/
551 static  int
552 ReturnLinkWinHint (
553     int   ccdf_type)
554 {
555     int  winHint = _DtCvWindowHint_CurrentWindow;
556
557     if (ccdf_type == CCDF_LINK_JUMP_NEW)
558         winHint = _DtCvWindowHint_NewWindow;
559
560     else if (ccdf_type == CCDF_LINK_DEFINITION)
561         winHint = _DtCvWindowHint_PopupWindow;
562
563     return winHint;
564 }
565
566 /******************************************************************************
567  * Function:    int ReturnLinkType (int ccdf_type, char *spec)
568  *
569  * Parameters:
570  *
571  * Returns:
572  *
573  * errno Values:
574  *
575  * Purpose:
576  *****************************************************************************/
577 static  int
578 ReturnLinkType (
579     int   ccdf_type,
580     char *spec)
581 {
582     int  trueType = _DtCvLinkType_SameVolume;
583
584     switch(ccdf_type)
585       {
586         case CCDF_LINK_JUMP_NEW:
587         case CCDF_LINK_JUMP_REUSE:
588         case CCDF_LINK_DEFINITION:
589                 if (strchr(spec, ' ') != NULL)
590                     trueType = _DtCvLinkType_CrossLink;
591                 break;
592
593         case CCDF_LINK_EXECUTE:
594                 trueType = _DtCvLinkType_Execute;
595                 break;
596
597         case CCDF_LINK_MAN_PAGE:
598                 trueType = _DtCvLinkType_ManPage;
599                 break;
600         
601         case CCDF_LINK_APP_DEFINE:
602                 trueType = _DtCvLinkType_AppDefine;
603                 break;
604
605       }
606
607     return trueType;
608 }
609
610 /******************************************************************************
611  * Function:    int CheckSegList (FormatVariables *cur_vars)
612  *
613  * Parameters:
614  *
615  * Returns:     0 for success, -1 for errors.
616  *
617  * errno Values:
618  *              CEErrorReported
619  *
620  * Purpose:     Check the global variable 'SegCount' against 'SegMax' and
621  *              realloc/malloc more memory for the global variable 'SegList'
622  *              if necessary. If memory is realloc'ed/malloc'ed, the entry
623  *              'para_entry->seg_list' is set to 'SegList'.
624  *
625  *****************************************************************************/
626 static  int
627 CheckSegList (
628     FormatVariables     *cur_vars )
629 {
630     if (cur_vars->my_list.cnt >= cur_vars->my_list.max)
631       {
632         cur_vars->my_list.list = AllocateSegments (cur_vars->my_list.list,
633                                 cur_vars->my_list.max,
634                                 (cur_vars->my_list.max + GROW_SIZE));
635
636         if (NULL == cur_vars->my_list.list)
637             return -1;
638
639         cur_vars->my_list.max += GROW_SIZE;
640       }
641
642     return 0;
643 }
644
645 /******************************************************************************
646  * Function: static _DtCvSegment *AllocateSegments (_DtCvSegment p_seg,
647  *                                      int original_size, int new_size)
648  *
649  * Parameters:
650  *              p_seg           Specifies a pointer to the old list
651  *                              of _DtCvSegments.
652  *              original_size   Specifies the current size of 'p_seg'.
653  *              new_size        Specifies the new size of 'p_seg'.
654  *
655  * Returns:     A pointer to the new list of structures.
656  *              A NULL indicates an error.
657  *
658  * Purpose:     (Re)Allocates _DtCvSegment structures and initializes
659  *              them to the default segment which is type _DtCvNOOP
660  *              and the container values set to default values.
661  *
662  *****************************************************************************/
663 static _DtCvSegment *
664 AllocateSegments (
665         _DtCvSegment    *p_seg,
666         int              original_size,
667         int              new_size )
668 {
669     FrmtPrivateInfo *priv = NULL;
670
671     if (NULL != p_seg)
672       {
673         int count = 0;
674
675         /*
676          * reallocate the segments.
677          */
678         p_seg = (_DtCvSegment *) realloc ((void *) p_seg,
679                                         (sizeof(_DtCvSegment) * new_size));
680         /*
681          * reallocate the private formatting information.
682          */
683         priv = p_seg->client_use;
684         priv = (FrmtPrivateInfo *) realloc ((void *) priv,
685                                         sizeof(FrmtPrivateInfo) * new_size);
686         if (NULL == priv)
687             return NULL;
688
689         /*
690          * reattach the private information with their segments.
691          */
692         while (count < original_size)
693             p_seg[count++].client_use = priv++;
694       }
695     else
696         p_seg = _DtHelpAllocateSegments (new_size);
697
698     if (NULL != p_seg)
699       {
700         /*
701          * want to 'empty' the type.
702          */
703         while (original_size < new_size)
704           {
705             /*
706              * if we went through _DtHelpAllocateSegments, then the
707              * priv pointer will be NULL. But that's okay since the
708              * _DtHelpAllocateSegments routine will initalized the
709              * variables for us. The only reason we have to do it
710              * is if we've reallocated the list.
711              */
712             if (NULL != priv)
713               {
714                 *priv = DefPrivInfo;
715
716                 p_seg[original_size  ].client_use   = priv++;
717                 p_seg[original_size  ].type         = _DtCvNOOP;
718                 p_seg[original_size  ].link_idx     = -1;
719                 p_seg[original_size  ].next_seg     = NULL;
720                 p_seg[original_size  ].next_disp    = NULL;
721               }
722
723             p_seg[original_size++].handle.container = DefContainer;
724           }
725       }
726
727     return p_seg;
728 }
729
730 /******************************************************************************
731  * Function: static int CheckList (
732  *                              FormatVariables cur_vars, int count, int grow)
733  *
734  * Parameters:
735  *              cur_vars        Specifies a structure containing the list
736  *                              of _DtCvSegments.
737  *              count           Specifies the amount needed.
738  *              grow            Specifies the amount to grow by.
739  *
740  * Returns:     0 if successful, -1 if failure.
741  *
742  * Purpose:     Makes sure there is 'grow' size number of segments
743  *              available.  If not, it calls AllocateSegments to 'grow'
744  *              the segment list.  cur_vars->seg_list is set to the new
745  *              pointer, cur_vars->seg_max indicates the maximum number
746  *              of segments in the list.
747  *
748  *****************************************************************************/
749 static int
750 CheckList (
751     SegList     *seg_list,
752     int          count,
753     int          grow )
754 {
755     /*
756      * what's the new count?
757      */
758     count += seg_list->cnt;
759
760     /*
761      * is it larger than the current max?
762      */
763     if (count > seg_list->max)
764       {
765         /*
766          * grow the list by the indicated amount.
767          */
768         grow += seg_list->max;
769
770         /*
771          * check to see if it is enough. If not, force the grow value
772          * to be the required count.
773          */
774         if (count > grow)
775             grow = count;
776
777         /*
778          * (re)allocate
779          */
780         seg_list->list = AllocateSegments(seg_list->list, seg_list->max, grow);
781
782         /*
783          * return an code if no list allocated.
784          */
785         if (NULL == seg_list->list)
786             return -1;
787
788         /*
789          * set the max count
790          */
791         seg_list->max = grow;
792       }
793                         
794     return 0;
795 }
796
797 /******************************************************************************
798  * Function: int SegmentSave (int type,
799  *                      char **font_attr, char *string, int linkspec,
800  *                      _DtCvSegment *p_seg)
801  * 
802  * Parameters:
803  *              type            Specifies the segment type.
804  *              font_attr       Specifies the resource list of quarks for the
805  *                                      font to associate with the segment.
806  *              string          Specifies the string segment.
807  *              link_spec       Specifies the link specification for the
808  *                                      segment.
809  *              p_seg           Specifies the _DtCvSegment structure to
810  *                                      initialize with the data.
811  *
812  * Returns:     0 if successful, -1 if errors.
813  *
814  * errno Values:
815  *              CEErrorReported
816  *
817  * Purpose:     Creates a new segment with the given data.
818  *
819  *****************************************************************************/
820 static int
821 SegmentSave (
822     FormatVariables     *cur_vars,
823     unsigned long        seg_type,
824     _DtHelpFontHints    *font_attr,
825     char                *string,
826     int                  str_size,
827     int                  num_chars,
828     int                  linkspec)
829 {
830     int           result = 0;
831     _DtCvSegment *pSeg   = NextAvailSeg(cur_vars->my_list);
832
833     pSeg->type     = _DtCvSetTypeToNoop(seg_type);
834     pSeg->link_idx = linkspec;
835
836     /*
837      * We use this routine for many things.
838      * If we want an newline in here, we may not have any data.
839      */
840     if (str_size)
841       {
842         pSeg->type = _DtCvSetTypeToString(pSeg->type);
843
844         /*
845          * if a wide character representation is required,
846          * convert to wchar_t
847          */
848         if (seg_type & _DtCvWIDE_CHAR)
849           {
850             wchar_t *pwcs;
851
852             /*
853              * include the null byte in the multibyte to widechar
854              * conversion.
855              */
856             num_chars++;
857
858             /*
859              * malloc the memory
860              */
861             pwcs = (wchar_t *) malloc(sizeof(wchar_t) * num_chars);
862             if (NULL != pwcs)
863               {
864                 /* convert */
865                 str_size = mbstowcs(pwcs, string, ((size_t) num_chars));
866
867                 /* check to see if it converted everything */
868                 if (str_size + 1 == num_chars)
869                     _DtCvStringOfStringSeg(pSeg) = (void *) pwcs;
870                 else
871                     free(pwcs);
872               }
873           }
874         else
875             _DtCvStringOfStringSeg(pSeg) = (void *) strdup(string);
876
877         if (NULL == _DtCvStringOfStringSeg(pSeg))
878             return -1;
879
880         /*
881          * set the default font. This should really be passed in via
882          * the format entry point (or the ui_info structure).
883          */
884         _DtCvFontOfStringSeg(pSeg)   = 0;
885
886         /*
887          * load the font
888          */
889         if (NULL != cur_vars->ui_info->load_font)
890             (*(cur_vars->ui_info->load_font))(
891                             cur_vars->ui_info->client_data,
892                             _DtHelpFontHintsLang(*font_attr),
893                             _DtHelpFontHintsCharSet(*font_attr),
894                             *font_attr,
895                             &(_DtCvFontOfStringSeg(pSeg)));
896       }
897
898     return result;
899 }
900
901 /******************************************************************************
902  * Function: int SaveStringAsSegments (FormatVariables, int type, char **font_attr,
903  *                              int link_spec)
904  * 
905  * Parameters:
906  *              type            Specifies the segment type.
907  *              font_attr       Specifies the resource list of quarks for the
908  *                                      font to associate with the segment.
909  *              link_spec       Specifies the link specification for the
910  *                                      segment.
911  *
912  * Returns:     0 if successful, -1 if errors.
913  *
914  * errno Values:
915  *
916  * Purpose:     Saves a segment into the global 'SegList'. This is
917  *              a wrapper around SegmentSave that adds specific
918  *              information relative to this module.
919  *
920  *****************************************************************************/
921 static  int
922 SaveStringAsSegments (
923     FormatVariables     *cur_vars,
924     unsigned long        seg_flags,
925     _DtHelpFontHints    *font_attr,
926     int                  link_spec)
927 {
928     int     len;
929     int     size;
930     int     numChars;
931     int     newLine = False;
932     char    tmpChar;
933     char   *ptr;
934
935     seg_flags = _DtCvSetTypeToNoop(seg_flags);
936     if (cur_vars->cur_mb_max != 1 && cur_vars->fmt_size > 1)
937       {
938         if (IsTypeNewLine(seg_flags))
939           {
940             newLine = True;
941             seg_flags = seg_flags & ~(_DtCvNEW_LINE);
942           }
943
944         ptr = cur_vars->fmt_buf;
945         do
946           {
947             /*
948              * what type of character is this?
949              */
950             len = mblen (ptr, cur_vars->cur_mb_max);
951
952             /*
953              * How many of the following characters are of the same size?
954              */
955             size = _DtHelpFmtFindBreak (ptr, len, &numChars);
956
957             /*
958              * save off the character that doesn't match
959              */
960             tmpChar = ptr[size];
961
962             /*
963              * put in the null byte for the string.
964              * and set to wide char if not doing multi-byte sequence.
965              */
966             ptr[size] = '\0';
967             if (1 != len)
968                seg_flags = _DtCvSetTypeToWideChar (seg_flags);
969
970             /*
971              * does this segment get the newline flag?
972              */
973             if (True == newLine && size >= cur_vars->fmt_size)
974                 seg_flags = _DtCvSetTypeToNewLine(seg_flags);
975
976             /*
977              * save the segment.
978              */
979             if (CheckSegList(cur_vars) == -1 ||
980                 SegmentSave (cur_vars, seg_flags, font_attr, ptr, size,
981                                                 numChars, link_spec) == -1)
982                 return -1;
983
984             /*
985              * remove the wide char flag
986              */
987             seg_flags &= ~(_DtCvWIDE_CHAR);
988
989             /*
990              * Bump the segment list count.
991              */
992             cur_vars->my_list.cnt++;
993
994             /*
995              * replace the character that didn't match.
996              * and bump the pointer to it.
997              */
998             ptr[size] = tmpChar;
999             ptr      += size;
1000             cur_vars->fmt_size -= size;
1001           } while (0 < cur_vars->fmt_size);
1002       }
1003     else
1004       {
1005         if (CheckSegList (cur_vars) == -1 ||
1006                         SegmentSave (cur_vars, seg_flags, font_attr,
1007                                 cur_vars->fmt_buf, cur_vars->fmt_size,
1008                                 cur_vars->fmt_size,
1009                                 link_spec) == -1)
1010             return -1;
1011         cur_vars->my_list.cnt++;
1012       }
1013
1014     cur_vars->fmt_size = 0;
1015     if (cur_vars->fmt_buf)
1016       cur_vars->fmt_buf[0] = '\0';
1017
1018     return 0;
1019 }
1020
1021 /******************************************************************************
1022  * Function: int CheckSaveSegment (int type, char **font_attr, int link_spec,
1023  *                                      FormatVariables cur_vars)
1024  * 
1025  * Parameters:
1026  *              type            Specifies the segment type.
1027  *              font_attr       Specifies the resource list of quarks for the
1028  *                                      font to associate with the segment.
1029  *              link_spec       Specifies the link specification for the
1030  *                                      segment.
1031  *
1032  * Returns:     0 if successful, -1 if errors.
1033  *
1034  * errno Values:
1035  *
1036  * Purpose:     Checks 'cur_vars->fmt_size' for a non-zero value. If it is,
1037  *              calls SaveSegment.
1038  *
1039  *****************************************************************************/
1040 static  int
1041 CheckSaveSegment (
1042     unsigned long        seg_flags,
1043     _DtHelpFontHints    *font_attr,
1044     int                  link_spec,
1045     FormatVariables     *cur_vars)
1046 {
1047     int   result = 0;
1048
1049     if (cur_vars->fmt_size)
1050         result = SaveStringAsSegments (cur_vars, seg_flags, font_attr, link_spec);
1051
1052     return result;
1053 }
1054
1055 /******************************************************************************
1056  * Function: void TerminateSegList (
1057  * 
1058  * Parameters:
1059  *
1060  * Returns:     0 if successful, -1 if errors.
1061  *
1062  * Purpose:     Links the segments together.
1063  *
1064  *****************************************************************************/
1065 static  void
1066 TerminateSegList (
1067     SegList     *seg_list,
1068     int          flag)
1069 {
1070     int count;
1071     _DtCvSegment *lastDisp = NULL;
1072     _DtCvSegment *pSeg;
1073
1074     if (True == flag && 0 == seg_list->cnt && NULL != seg_list->list)
1075       {
1076         free(seg_list->list);
1077         *seg_list = InitList;
1078       }
1079
1080     /*
1081      * set the next segment and display segment pointers.
1082      */
1083     for (count = 1, pSeg = seg_list->list; count < seg_list->cnt;
1084                                                         count++, pSeg++)
1085       {
1086         /*
1087          * link this segment to the next segment
1088          */
1089         pSeg->next_seg  = &(pSeg[1]);
1090
1091         /*
1092          * is this a displayable segment?
1093          * If so, link it into the displayable list.
1094          */
1095         if (_DtCvIsSegNoop(pSeg) || _DtCvIsSegRegion(pSeg)
1096                                                 || _DtCvIsSegString(pSeg))
1097           {
1098             /*
1099              * Is there a displayable segment yet?
1100              * If so, set its next displayable link to this segment.
1101              */
1102             if (NULL != lastDisp)
1103                 lastDisp->next_disp = pSeg;
1104
1105             /*
1106              * this segment becomes the last displayable segment.
1107              */
1108             lastDisp = pSeg;
1109           }
1110         else
1111            lastDisp = NULL;
1112       }
1113
1114     if (NULL != pSeg && NULL != lastDisp
1115         && (_DtCvIsSegNoop(pSeg) || _DtCvIsSegRegion(pSeg)
1116                                                 || _DtCvIsSegString(pSeg)))
1117         lastDisp->next_disp = pSeg;
1118
1119 }
1120
1121 /******************************************************************************
1122  * Function:    int InitStructure (FormatVariables *cur_vars,
1123  *                              char *rd_buf, int rd_size,
1124  * 
1125  * Parameters:
1126  *              rd_buffer       Specifies the buffer all reads use.
1127  *              id_string       Specifies the location ID to search for.
1128  *
1129  * Returns:     0 if successful, -1 if errors.
1130  *
1131  * errno Values:
1132  *
1133  * Purpose:     Attach formatting information to the structure that gets
1134  *              passed around by, among other things, setting the global
1135  *              variable 'cur_vars->rd_ptr' to 'rd_buffer', and
1136  *              remembering the location id.
1137  *
1138  *****************************************************************************/
1139 static  int
1140 InitStructure(
1141     FormatVariables     *cur_vars,
1142     _FrmtUiInfo         *ui_info,
1143     char                *rd_buf,
1144     int                  rd_size)
1145 {
1146     cur_vars->ui_info  = ui_info;
1147     cur_vars->rd_size  = rd_size;
1148     cur_vars->rd_buf   = rd_buf;
1149     cur_vars->rd_ptr   = cur_vars->rd_buf;
1150
1151     cur_vars->fmt_size = 0;
1152     if (cur_vars->fmt_buf)
1153         cur_vars->fmt_buf[0] = '\0';
1154
1155     /*
1156      * allocate the link data base.
1157      */
1158     cur_vars->my_links = _DtLinkDbCreate();
1159     if (NULL == cur_vars->my_links)
1160         return -1;
1161
1162     return 0;
1163 }
1164
1165 /******************************************************************************
1166  * Function:    int AppendToInfo (FormatVariables *cur_vars,
1167  *                                      char **src, const char *scan_string)
1168  *
1169  * Parameters:
1170  *              src             Specifies the source string to read.
1171  *                              Returns pointing at a special character,
1172  *                                      an invalid character or the
1173  *                                      end of string.
1174  *              scan_string     Specifies the special characters to
1175  *                              look for in 'src'.
1176  *
1177  * Returns:      0      if stopped on a special character.
1178  *               1      if found the end of string.
1179  *               2      if found an invalid character.
1180  *              -1      if errors.
1181  *
1182  * errno Values:
1183  * 
1184  * Purpose:     Appends onto 'cur_vars->fmt_buf' the number of characters
1185  *              found in 'src' that does not match any character in
1186  *              'scan_string'.
1187  *
1188  *              Sets 'cur_vars->last_was_space' to false (assumes that one
1189  *              of the special characters is a space).
1190  *
1191  *****************************************************************************/
1192 static  int
1193 AppendToInfo (
1194     FormatVariables      *cur_vars,
1195     char                **src,
1196     const char           *scan_string )
1197 {
1198     int    spnResult;
1199     int    size;
1200
1201     cur_vars->last_was_space = False;
1202     spnResult = _DtHelpCeStrcspn(*src, scan_string, cur_vars->cur_mb_max,
1203                                                                         &size);
1204     if (0 < size)
1205       {
1206         if (_DtHelpCeAddStrToBuf(src,&(cur_vars->fmt_buf),&(cur_vars->fmt_size),
1207                                 &(cur_vars->fmt_buf_max),size,INFO_GROW) == -1)
1208             return -1;
1209         cur_vars->last_was_space = False;
1210       }
1211
1212     if (spnResult == -1)
1213         spnResult = 2;
1214
1215     if (0 == size && 1 == spnResult)
1216         spnResult = 0;
1217
1218     return spnResult;
1219 }
1220
1221 /******************************************************************************
1222  * Function:    int AppendOctalToInfo (FormatVariables *cur_vars, char *src)
1223  * 
1224  * Parameters:
1225  *              src             Specifies the source string to read.
1226  *
1227  * Returns:      0      if successful, -1 if errors.
1228  *
1229  * errno Values:
1230  *              CEErrorFormattingValue
1231  *              CEErrorMalloc
1232  * 
1233  * Purpose:     Convert the octal representation pointed to by 'src' and
1234  *              change it into a character byte. The routine only allows
1235  *              a number between the values 1-255.
1236  *
1237  *              Append the byte onto the global variable 'Info'.
1238  *              Set 'cur_vars->last_was_space' to false.
1239  *
1240  *****************************************************************************/
1241 static  int
1242 AppendOctalToInfo(
1243     FormatVariables     *cur_vars,
1244     char                *src)
1245 {
1246     /*
1247      * must have 0xXX
1248      */
1249     if (((int)strlen(src)) < 4 && cur_vars->my_file != NULL)
1250       {
1251         if (GetNextBuffer (cur_vars) == -1)
1252             return -1;
1253
1254         src = cur_vars->rd_ptr;
1255       }
1256
1257     if (_DtHelpCeAddOctalToBuf(src,&(cur_vars->fmt_buf),&(cur_vars->fmt_size),
1258                                 &(cur_vars->fmt_buf_max),INFO_GROW) == -1)
1259         return -1;
1260
1261     cur_vars->last_was_space = False;
1262
1263     return 0;
1264 }
1265
1266 /******************************************************************************
1267  * Function:    int AppendCharToInfo (FormatVariables *cur_vars, char **src)
1268  * 
1269  * Parameters:
1270  *              src             Specifies the source string to read.
1271  *                              Returns pointing at the next character
1272  *                                      the string.
1273  *
1274  * Returns:      0      if successful, -1 if errors.
1275  *
1276  * errno Values:
1277  *
1278  * Purpose:     Appends the character pointed to by 'src' onto the
1279  *              global buffer 'Info', updating the pointers associated
1280  *              with 'Info' accordingly.
1281  *
1282  *              Sets 'cur_vars->last_was_space' to False;
1283  * 
1284  *****************************************************************************/ static  int
1285 AppendCharToInfo(
1286     FormatVariables     *cur_vars,
1287     char                **src)
1288 {
1289     cur_vars->last_was_space = False;
1290     return (_DtHelpCeAddCharToBuf (src, &(cur_vars->fmt_buf),
1291                                 &(cur_vars->fmt_size),
1292                                 &(cur_vars->fmt_buf_max), INFO_GROW));
1293 }
1294
1295 /******************************************************************************
1296  * Function:    int AppendSpaceToInfo (char **src, int type)
1297  *
1298  * Parameters:
1299  *              src             Specifies the source string to read.
1300  *                              Returns pointing at the next character
1301  *                                      the string.
1302  *              type            Specifies the type of the segment being
1303  *                                      processed.
1304  *
1305  * Returns:      0      if successful, -1 if errors.
1306  *
1307  * errno Values:
1308  *
1309  * Purpose:     Appends a space onto the global buffer 'Info', if
1310  *              the variable 'cur_vars->last_was_space' is false or the
1311  *              static string flag is set in 'type'.
1312  *
1313  *              Sets 'cur_vars->last_was_space' to true.
1314  *
1315  *****************************************************************************/
1316 static  int
1317 AppendSpaceToInfo ( 
1318     FormatVariables      *cur_vars,
1319     char                **src,
1320     _DtCvFrmtOption       type)
1321 {
1322     int   result = 0;
1323     char *space = (char *) SpaceString;
1324
1325     if (!cur_vars->last_was_space || _DtCvLITERAL == type) {
1326
1327         result = _DtHelpCeAddCharToBuf (&space, &(cur_vars->fmt_buf),
1328                                         &(cur_vars->fmt_size),
1329                                         &(cur_vars->fmt_buf_max), INFO_GROW);
1330         cur_vars->last_was_space = True;
1331     }
1332
1333     if (src != NULL)
1334         *src = *src + 1;
1335     return result;
1336 }
1337
1338 /******************************************************************************
1339  * Function:    int FindEndMarker (FormatVariables *cur_vars)
1340  * 
1341  * Returns:      0 if successful, -1 if errors.
1342  *
1343  * errno Values:
1344  *
1345  * Purpose:     Wrapper around __DtHelpFindEndMarker.
1346  *              Find the '>' token.
1347  *
1348  *****************************************************************************/
1349 static int
1350 FindEndMarker(
1351     FormatVariables     *cur_vars)
1352 {
1353     return (_DtHelpCeGetCcdfEndMark (cur_vars->my_file, cur_vars->rd_buf,
1354                 &(cur_vars->rd_ptr),cur_vars->rd_size,1));
1355 }
1356
1357 /******************************************************************************
1358  * Function:    int GetNextBuffer (FormatVariables *cur_vars)
1359  *
1360  * Returns:      0      if successful, -1 if errors.
1361  *
1362  * errno Values:
1363  *
1364  * Purpose:     Wrapper around __DtHelpGetNextBuffer.
1365  *              Read the next buffer's worth of information.
1366  * 
1367  *****************************************************************************/
1368 static  int
1369 GetNextBuffer (
1370     FormatVariables *cur_vars)
1371 {
1372     cur_vars->rd_flag = _DtHelpCeGetNxtBuf (cur_vars->my_file,
1373                                         cur_vars->rd_buf,
1374                                         &(cur_vars->rd_ptr),
1375                                         cur_vars->rd_size);
1376     return (cur_vars->rd_flag);
1377 }
1378
1379 /******************************************************************************
1380  * Function:    int SaveNewLine (FormatVariables *cur_vars, int cur_type,
1381  *                                      char **font_attr,
1382  *                                      int link_spec)
1383  *
1384  * Parameters:
1385  *              cur_cmd         Specifies the type of segment being processed.
1386  *              font_attr       Specifies the list of font quarks associated
1387  *                              with the current segment.
1388  *              link_spec       Specifies the hypertext link specification
1389  *                              associated with the current segment.
1390  *
1391  * Returns:      0      if successful, -1 if errors.
1392  *
1393  * errno Values:
1394  *
1395  * Purpose:     Sets the newline flag on a segment and saves it by calling
1396  *                      'SaveStringAsSegments'.
1397  *              If the current segment is non-null, save it with the
1398  *                      newline flag set.
1399  *              Otherwise if there are no segments saved, create one with the
1400  *                      a type of CE_old_NOOP.
1401  *              Otherwise there are other segments, but the current segment is
1402  *                      empty. Look back at the previous segment.
1403  *                      If it doesn't have the newline set on it,
1404  *                      its newline flag is enabled.
1405  *              Otherwise the previous segment had the newline set, so
1406  *                      create another segment just like it with a 
1407  *                      null length and the newline flag set (if the
1408  *                      previous segment is a graphic, create it
1409  *                      with a type of CE_old_NOOP).
1410  * 
1411  *****************************************************************************/
1412 static  int
1413 SaveNewLine(
1414     FormatVariables     *cur_vars,
1415     int                  cur_type,
1416     _DtHelpFontHints    *font_attr,
1417     int                  link_spec )
1418 {
1419     int         result = 0;
1420     _DtCvSegment   *pSeg;
1421
1422     /*
1423      * If there is information in the buffer, save it with the newline flag
1424      */
1425     if (cur_vars->fmt_size)
1426         result = SaveStringAsSegments (cur_vars, _DtCvSetTypeToNewLine (cur_type),
1427                                         font_attr, link_spec);
1428     /*
1429      * check to see if there is any segments. If not create a new one
1430      * with the type NOOP.
1431      */
1432     else if (0 == cur_vars->my_list.cnt)
1433         result = SaveStringAsSegments (cur_vars, _DtCvSetTypeToNewLine(_DtCvNOOP),
1434                                         font_attr, link_spec);
1435     /*
1436      * There was not any information in the buffer and we have one or
1437      * more segments. Try placing the flag on the previous segment.
1438      */
1439     else 
1440       {
1441         pSeg = NextAvailSeg(cur_vars->my_list);
1442         pSeg--;
1443
1444         /*
1445          * Does the previous segment already have a newline flag?
1446          * If so, create a new NOOP segment with the newline set.
1447          */
1448         if (_DtCvIsSegNewLine (pSeg))
1449             result = SaveStringAsSegments (cur_vars, _DtCvSetTypeToNewLine (_DtCvNOOP),
1450                                         font_attr, link_spec);
1451         else
1452             pSeg->type = _DtCvSetTypeToNewLine (pSeg->type);
1453       }
1454
1455     cur_vars->last_was_space = True;
1456     return result;
1457 }
1458
1459 /******************************************************************************
1460  * Function:    int CreateSaveGraphic (FormatVariables cur_vars,
1461  *                              int type,
1462  *                                      char *file_name, int link_spec )
1463  * 
1464  * Parameters:
1465  *              type            Specifies the type of graphic segment
1466  *                              being processed.
1467  *              file_name       Specifies the file name of the graphic.
1468  *              link_spec       Specifies the hypertext link specification
1469  *                              associated with the graphic.
1470  *
1471  * Returns:      0      if successful, -1 if errors.
1472  *
1473  * Purpose:     Save a graphic segment.
1474  *              If 'file_name' is not an absolute path, resolve it to
1475  *              a full path by using the path to the volume.
1476  *
1477  *****************************************************************************/
1478 static  int
1479 CreateSaveGraphic (
1480     FormatVariables     *cur_vars,
1481     int                  type,
1482     char                *file_name,
1483     int                  link_spec)
1484 {
1485     char         *fullName;
1486     _DtCvSegment *cvRegion;
1487
1488     if (CheckList (&(cur_vars->my_list), 1, 1) == -1)
1489         return -1;
1490
1491     /*
1492      * create the path to the file name
1493      */
1494     if (*file_name == '/')
1495         fullName = strdup (file_name);
1496     else
1497       {
1498         fullName = (char *) malloc (strlen (cur_vars->my_path) +
1499                                                 strlen (file_name) + 2);
1500         if (fullName == NULL)
1501             return -1;
1502
1503         strcpy (fullName, cur_vars->my_path);
1504         strcat (fullName, "/");
1505         strcat (fullName, file_name);
1506       }
1507
1508     /*
1509      * load the graphic into the current segment
1510      */
1511     cvRegion = NextAvailSeg(cur_vars->my_list);
1512     if (NULL != cur_vars->ui_info->load_graphic &&
1513                 (*(cur_vars->ui_info->load_graphic))(
1514                                 cur_vars->ui_info->client_data,
1515                                 cur_vars->vol_name,
1516                                 cur_vars->topic_id,
1517                                 fullName,
1518                                 NULL,
1519                                 NULL,
1520                                 &(_DtCvWidthOfRegionSeg(cvRegion)),
1521                                 &(_DtCvHeightOfRegionSeg(cvRegion)),
1522                                 &(_DtCvInfoOfRegionSeg(cvRegion))) == 0)
1523       {
1524         /*
1525          * set the type and index.
1526          * and indicate that this segment has been used.
1527          */
1528         _DtCvAscentOfRegionSeg(cvRegion) = -1;
1529         cvRegion->type     = _DtCvSetTypeToRegion(type);
1530         cvRegion->link_idx = link_spec;
1531         cur_vars->my_list.cnt++;
1532       }
1533
1534     /*
1535      * free the file name path
1536      */
1537     free (fullName);
1538
1539     return 0;
1540 }
1541
1542 /******************************************************************************
1543  * Function:    int ChangeFont (int whichOne, int segType,
1544  *                              char **font_attr, int linkspec,
1545  *                              FormatVariables *cur_vars, int flags)
1546  * 
1547  * Parameters:
1548  *              whichOne        Specifies the index into 'font_attr' to
1549  *                              change.
1550  *              segType         Specifies the type of segment currently
1551  *                              being processed.
1552  *              font_attr       Specifies the list of font quarks associated
1553  *                              with the current segment.
1554  *              linkspec        Specifies the hypertext link specification
1555  *                              associated with the segment.
1556  *              flags           Specifies the routines flags.
1557  *
1558  * Returns:     The value returned from 'routine' if successful, -1 if errors.
1559  *
1560  * errno Values:
1561  *
1562  * Purpose:     Saves any segment with the current font type and
1563  *              process the next segment using the new font type.
1564  *
1565  *****************************************************************************/
1566 static  int
1567 ChangeFont(
1568     int                  whichOne,
1569     unsigned long        seg_flags,
1570     _DtCvFrmtOption      frmt_type,
1571     _DtHelpFontHints    *font_attr,
1572     int                  linkspec,
1573     FormatVariables     *cur_vars,
1574     ProcessState         cur_state,
1575     int                  flags,
1576     int                  ret_on_nl,
1577     int                  fnt_flag)
1578 {
1579     int    result;
1580     int    oldMb_Len = cur_vars->cur_mb_max;
1581     char  *fontString;
1582     _DtHelpFontHints oldFontStruct;
1583
1584     if (CheckSaveSegment (seg_flags, font_attr, linkspec, cur_vars) == -1)
1585         return -1;
1586
1587     oldFontStruct = *font_attr;
1588
1589     if (GetStringParameter(cur_vars, _DtCvTRUE, _DtCvTRUE, _DtCvFALSE,
1590                                                 _DtCvFALSE, &fontString) == -1)
1591         return -1;
1592
1593     /*
1594      * Is this font change allowed to go through?
1595      */
1596     if (!(fnt_flag & (1 << whichOne)))
1597       {
1598         switch (whichOne)
1599           {
1600             case _CEFONT_SPACING:
1601                         font_attr->spacing = _DtHelpFontSpacingProp;
1602                         if (fontString[0] == 'm')
1603                             font_attr->spacing = _DtHelpFontSpacingMono;
1604                         break;
1605             case _CEFONT_SIZE:
1606                         font_attr->pointsz = atoi(fontString);
1607                         break;
1608             case _CEFONT_ANGLE:
1609                         font_attr->slant = _DtHelpFontSlantRoman;
1610                         if (fontString[0] == 'i')
1611                             font_attr->slant = _DtHelpFontSlantItalic;
1612                         break;
1613             case _CEFONT_WEIGHT:
1614                         font_attr->weight = _DtHelpFontWeightMedium;
1615                         if (fontString[0] == 'b')
1616                             font_attr->weight = _DtHelpFontWeightBold;
1617                         break;
1618             case _CEFONT_TYPE:
1619                         font_attr->style = _DtHelpFontStyleSanSerif;
1620                         if (*fontString == 's')
1621                           {
1622                             if (fontString[1] == 'e')
1623                                 font_attr->style = _DtHelpFontStyleSerif;
1624                             else if (fontString[1] == 'y')
1625                                 font_attr->style = _DtHelpFontStyleSymbol;
1626                           }
1627                         break;
1628             case _CEFONT_CHAR_SET:
1629                         /*
1630                          * Change to the correct mb_len.
1631                          */
1632                         GetMbLen(cur_vars, fontString,
1633                                         &(_DtHelpFontHintsLang(*font_attr)),
1634                                         &(_DtHelpFontHintsCharSet(*font_attr)));
1635                         break;
1636           }
1637       }
1638
1639     result = FindEndMarker (cur_vars);
1640     if (!result)
1641         result = Parse (CCDF_FONT_CMD, cur_state, cur_vars,
1642                                 seg_flags, frmt_type,
1643                                 font_attr, linkspec,
1644                                 Specials, flags, ret_on_nl, fnt_flag);
1645     /*
1646      * free the lanugage and code sets strings.
1647      */
1648     if (!(fnt_flag & (1 << whichOne)) && whichOne == _CEFONT_CHAR_SET)
1649       {
1650         free(_DtHelpFontHintsLang(*font_attr));
1651         free(_DtHelpFontHintsCharSet(*font_attr));
1652       }
1653
1654     /*
1655      * reset the old quark
1656      * if necessary, reset the MB_LEN
1657      */
1658     *font_attr = oldFontStruct;
1659     cur_vars->cur_mb_max = oldMb_Len;
1660
1661     /*
1662      * free the memory
1663      */
1664     free (fontString);
1665
1666     if (result == -1)
1667         return -1;
1668
1669     return 0;
1670
1671 } /* ChangeFont */
1672
1673 /******************************************************************************
1674  * Function:    int SkipToNextToken (FormatVariables *cur_vars, int      flag)
1675  * 
1676  * Parameters:
1677  *              flag    Specifies whether the routine returns a -1
1678  *                              if '>' is the next token.
1679  *
1680  * Returns:     The value from __DtHelpSkipToNextToken:
1681  *                      -1  If problems encountered finding the next token.
1682  *                       0  If no problems encountered finding the next token.
1683  *                       1  If flag is true and the next token is a > character.
1684  *
1685  * errno Values:
1686  *
1687  * Purpose:     Wrapper around __DtHelpSkipToNextToken.
1688  *              Skip the current string and any spaces or newline
1689  *              characters after it.
1690  *
1691  *****************************************************************************/
1692 static  int
1693 SkipToNextToken (
1694     FormatVariables      *cur_vars,
1695     _DtCvValue            flag)
1696 {
1697     return (_DtHelpCeSkipToNextCcdfToken (cur_vars->my_file, cur_vars->rd_buf,
1698                 cur_vars->rd_size, 1, &(cur_vars->rd_ptr), flag));
1699 }
1700
1701 /******************************************************************************
1702  * Function:    int GetStringParameter (FormatVariables *cur_vars,
1703  *                              int      flag, int       eat_escape,
1704  *                              int      ignore_quotes, int      less_test,
1705  *                              char **ret_string)
1706  * 
1707  * Parameters:
1708  *              flag            Specifies whether the routine returns
1709  *                                      a -1 if '>' is the next token.
1710  *              eat_secape      Specifies whether the backslash is not
1711  *                                      placed in the returned string.
1712  *                                      True - it is skipped.
1713  *                                      False - it is saved in 'ret_string'.
1714  *              ignore_quotes   Specifies whether quotes are to be included
1715  *                                      in the returned string.
1716  *              less_test       Specifies whether the routine should
1717  *                                      stop when it finds a '<' character.
1718  *              ret_string      Returns the string found.
1719  *                              If NULL, throws the information away.
1720  *
1721  * Returns:     The value from __DtHelpFormatGetStringParameter:
1722  *                      -1  If problems encountered.
1723  *                       0  If no problems encountered getting the string.
1724  *                       1  If flag is false and the no string was found.
1725  *
1726  * errno Values:
1727  *
1728  * Purpose:     Wrapper around __DtHelpFormatGetStringParameter.
1729  *              Skip the current string and any spaces or newline
1730  *              characters after it. Get the next quoted/unquoted
1731  *              string after that.
1732  *
1733  *****************************************************************************/
1734 static  int
1735 GetStringParameter(
1736     FormatVariables      *cur_vars,
1737     _DtCvValue            flag,
1738     _DtCvValue            eat_escape,
1739     _DtCvValue            ignore_quotes,
1740     _DtCvValue            less_test,
1741     char                **ret_string)
1742 {
1743     return (_DtHelpCeGetCcdfStrParam (cur_vars->my_file,
1744                 cur_vars->rd_buf, cur_vars->rd_size, cur_vars->cur_mb_max,
1745                 &(cur_vars->rd_ptr),
1746                 flag, eat_escape, ignore_quotes, less_test, ret_string));
1747 }
1748
1749 /******************************************************************************
1750  * Function:    int GetValueParameter (FormatVariables *cur_vars,
1751  *                              int      flag, int *ret_value)
1752  * 
1753  * Parameters:
1754  *              flag            Specifies whether the routine returns
1755  *                                      a -2 if '>' is the next token.
1756  *              ret_value       Returns the atoi conversion
1757  *                              of the string found.
1758  *
1759  * Returns:     The value from __DtHelpFormatGetValueParameter:
1760  *                      -1  If problems encountered.
1761  *                       0  If no problems encountered getting the string.
1762  *                      -2  If flag is true and the next token is a >
1763  *                              character.
1764  *
1765  * errno Values:
1766  *
1767  * Purpose:     Wrapper around __DtHelpFormatGetValueParameter.
1768  *              Skip the current string and any spaces or newline
1769  *              characters after it. Process the next string as
1770  *              a numeric value.
1771  *
1772  *****************************************************************************/
1773 static  int
1774 GetValueParameter(
1775     FormatVariables     *cur_vars,
1776     _DtCvValue           flag,
1777     int                 *ret_value )
1778 {
1779     return (_DtHelpCeGetCcdfValueParam (cur_vars->my_file, cur_vars->rd_buf,
1780                         cur_vars->rd_size,
1781                         &(cur_vars->rd_ptr), flag, cur_vars->cur_mb_max,
1782                         ret_value));
1783 }
1784
1785 /******************************************************************************
1786  * Function:    int GetParagraphParameters (FormatVariables *cur_vars,
1787  *                              int seg_type, int graphic_type,
1788  *                              char **label, char **file_name,
1789  *                              char **link_string, int *link_type,
1790  *                              char **description)
1791  *
1792  * Parameters:
1793  *              seg_type        Specifies the default type for the segment.
1794  *                              Returns the new type for the segment.
1795  *              graphic_type    Specifies the default type for a graphic
1796  *                                      if a justified graphic is
1797  *                                      encountered in the paragraph options.
1798  *                              Returns the new type for a graphic
1799  *                                      if a justified graphic was 
1800  *                                      encountered in the paragraph options.
1801  *              label           Returns the label if one is specified
1802  *                                      in the paragraph options.
1803  *              file_name       Returns the file name of a graphic if
1804  *                                      one is specified in the paragraph
1805  *                                      options.
1806  *              link_string     Returns the hypertext specification if one
1807  *                                      is specified in the paragraph options.
1808  *              link_type       Returns the hypertext link type if one is
1809  *                                      specified.
1810  *              description     Returns the hypertext description if one
1811  *                                      is specified.
1812  * 
1813  * Returns:     0 if successfult, -1 if errors.
1814  *
1815  * errno Values:
1816  *
1817  * Purpose:     Wrapper around __DtHelpParagraphGetOptions.
1818  *              Process the options found in <PARAGRAPH> syntax.
1819  *              Test to see if the id specified in the <PARAGRAPH>
1820  *              is the one we are looking at.
1821  *
1822  *****************************************************************************/
1823 static  int
1824 GetParagraphParameters(
1825     FormatVariables      *cur_vars,
1826     _DtCvSegment         *para,
1827     _DtCvFrmtOption      *frmt_type,
1828     _DtCvFrmtOption      *gpos,
1829     char                **glink,
1830     int                  *glinktype,
1831     _DtCvUnit            *gspace,
1832     char                **ret_label,
1833     char                **file_name,
1834     char                **description)
1835 {
1836     int          done   = False;
1837     int          result = 0;
1838     int          optionCount = 0;
1839     int          value;
1840     char        *tmpString = NULL;
1841
1842     /*
1843      * initialize string variables if valid addresses
1844      */
1845     *ret_label   = NULL;
1846     *file_name   = NULL;
1847     *glink       = NULL;
1848     *description = NULL;
1849
1850     *gpos       = _DtCvJUSTIFY_LEFT;
1851     *glinktype  = -1;
1852     *gspace     = 0;
1853
1854     while (False == done && result != -1)
1855       {
1856         if (SkipToNextToken (cur_vars, _DtCvFALSE) == -1)
1857             return -1;
1858
1859         switch (_DtCvToLower(*(cur_vars->rd_ptr)))
1860           {
1861             /*
1862              * end of paragraph spec
1863              */
1864             case '>':
1865                 (cur_vars->rd_ptr)++;
1866                 done = True;
1867                 break;
1868
1869             /*
1870              * after value
1871              */
1872             case 'a':
1873                 if (GetValueParameter (cur_vars, _DtCvFALSE, &value) == -1)
1874                     return -1;
1875
1876                 _DtCvContainerBMarginOfSeg(para) = 0;
1877                 if (value > 0 && 0 < cur_vars->ui_info->line_height)
1878                     _DtCvContainerBMarginOfSeg(para) = value *
1879                                         (cur_vars->ui_info->line_height / 2);
1880                 break;
1881
1882             /*
1883              * before value
1884              */
1885             case 'b':
1886                 if (GetValueParameter (cur_vars, _DtCvFALSE, &value) == -1)
1887                     return -1;
1888
1889                 _DtCvContainerTMarginOfSeg(para) = 0;
1890                 if (value > 0 && 0 < cur_vars->ui_info->line_height)
1891                     _DtCvContainerTMarginOfSeg(para) = value *
1892                                         (cur_vars->ui_info->line_height / 2);
1893                 break;
1894
1895             /*
1896              * description [string | "string" | 'string']
1897              */
1898             case 'd':
1899                 result = GetStringParameter(cur_vars, _DtCvTRUE, _DtCvTRUE,
1900                                         _DtCvFALSE, _DtCvFALSE, description);
1901                 break;
1902
1903             /*
1904              * firstindent value
1905              */
1906             case 'f':
1907                 if (GetValueParameter (cur_vars, _DtCvFALSE, &value) == -1)
1908                     return -1;
1909
1910                 _DtCvContainerFMarginOfSeg(para) =
1911                                         value * cur_vars->ui_info->avg_char;
1912                 break;
1913
1914             /*
1915              * glink      [string | "string" | 'string']
1916              * gpos       value_string
1917              * graphic    string
1918              * gspace     value
1919              * gtypelink  value
1920              */
1921             case 'g':
1922                 /*
1923                  * to determine what token this is we must look at the
1924                  * second character.
1925                  */
1926                 (cur_vars->rd_ptr)++;
1927
1928                 /*
1929                  * do we need to read more?
1930                  */
1931                 if (*(cur_vars->rd_ptr) == '\0'
1932                                         && GetNextBuffer(cur_vars) == -1)
1933                     return -1;
1934
1935                 /*
1936                  * check for the next permutation
1937                  */
1938                 switch (_DtCvToLower(*(cur_vars->rd_ptr)))
1939                   {
1940                     /*
1941                      * glink [string | "string" | 'string']
1942                      */
1943                     case 'l':
1944                         result = GetStringParameter(cur_vars, _DtCvTRUE,
1945                                 _DtCvTRUE, _DtCvFALSE, _DtCvFALSE, glink);
1946                         break;
1947
1948                     /*
1949                      * gpos value_string
1950                      */
1951                     case 'p':
1952                         result = GetStringParameter(cur_vars, _DtCvTRUE,
1953                                 _DtCvTRUE, _DtCvFALSE, _DtCvFALSE, &tmpString);
1954
1955                         if (-1 != result && _DtCvToLower (*tmpString) == 'r')
1956                             *gpos = _DtCvJUSTIFY_RIGHT;
1957
1958                         if (tmpString)
1959                             free (tmpString);
1960                         break;
1961
1962                     /*
1963                      * graphic    string
1964                      */
1965                     case 'r':
1966                         result = GetStringParameter(cur_vars, _DtCvTRUE,
1967                                 _DtCvTRUE, _DtCvFALSE, _DtCvFALSE, file_name);
1968                         break;
1969
1970                     /*
1971                      * gspace     value
1972                      */
1973                     case 's':
1974                         if (GetValueParameter(cur_vars,_DtCvFALSE,&value) == -1
1975                                                                 || value < 0)
1976                             return -1;
1977
1978                         *gspace = value * cur_vars->ui_info->avg_char;
1979                         break;
1980
1981                     /*
1982                      * gtypelink  value
1983                      */
1984                     case 't':
1985                         if (GetValueParameter(cur_vars,_DtCvFALSE,glinktype) == -1
1986                                                         || *glinktype < 0)
1987                             return -1;
1988
1989                         break;
1990                   }
1991                 break;
1992
1993             /*
1994              * id string
1995              */
1996             case 'i':
1997                 /*
1998                  * get the id string
1999                  */
2000                 if (GetStringParameter(cur_vars, _DtCvTRUE, _DtCvTRUE,
2001                                 _DtCvFALSE, _DtCvFALSE, &tmpString) == -1)
2002                     return -1;
2003
2004                 _DtCvContainerIdOfSeg(para) = tmpString;
2005                 break;
2006
2007             /*
2008              * label [string | "string" | 'string']
2009              * leftindent value
2010              */
2011             case 'l':
2012                 /*
2013                  * to determine what token this is we must look at the
2014                  * second and possibly the third characters.
2015                  */
2016                 (cur_vars->rd_ptr)++;
2017
2018                 /*
2019                  * do we need to read more?
2020                  */
2021                 if (*(cur_vars->rd_ptr) == '\0'
2022                                         && GetNextBuffer(cur_vars) == -1)
2023                     return -1;
2024
2025                 /*
2026                  * check for the next permutation
2027                  */
2028                 if (_DtCvToLower(*(cur_vars->rd_ptr)) == 'a')
2029                   {
2030                     /*
2031                      * label
2032                      */
2033                     if (GetStringParameter(cur_vars, _DtCvTRUE, _DtCvFALSE,
2034                                 _DtCvFALSE, _DtCvFALSE, &tmpString) == -1)
2035                         return -1;
2036
2037                     /*
2038                      * If we got a label process it.
2039                      */
2040                     if (ret_label == NULL || *ret_label)
2041                       {
2042                         /*
2043                          * we've already processed a label!
2044                          * ignore this one!
2045                          */
2046                         if (tmpString)
2047                             free (tmpString);
2048                       }
2049                     else
2050                         *ret_label = tmpString;
2051                   }
2052                 else if (_DtCvToLower(*(cur_vars->rd_ptr)) == 'e')
2053                   {
2054                     /*
2055                      * leftindent
2056                      */
2057                     if (GetValueParameter (cur_vars, _DtCvFALSE, &value) == -1)
2058                         return -1;
2059
2060                     _DtCvContainerLMarginOfSeg(para) =
2061                                         value * cur_vars->ui_info->avg_char;
2062                   }
2063                 else
2064                     result = -1;
2065                 break;
2066
2067             /*
2068              * nowrap
2069              */
2070             case 'n':
2071                 _DtCvContainerTypeOfSeg(para) = _DtCvLITERAL;
2072                 *frmt_type = _DtCvLITERAL;
2073                 break;
2074
2075             /*
2076              * rightindent value
2077              */
2078             case 'r':
2079                 if (GetValueParameter (cur_vars, _DtCvFALSE, &value) == -1)
2080                     return -1;
2081
2082                 _DtCvContainerRMarginOfSeg(para) =
2083                                         value * cur_vars->ui_info->avg_char;
2084                 break;
2085
2086             /*
2087              * wrap
2088              */
2089             case 'w':
2090                 _DtCvContainerTypeOfSeg(para) = _DtCvDYNAMIC;
2091                 *frmt_type = _DtCvDYNAMIC;
2092                 break;
2093
2094             /*
2095              * Found an option we don't understand.
2096              */
2097             default:
2098                 result = -1;
2099           }
2100         optionCount++;
2101       }
2102
2103     /*
2104      * adjust the first margin to correctly indicate the offset from the
2105      * left margin. In the old CCDF, the first margin indicated left plus
2106      * and additional indent. For the new Canvas Engine, it is suppose
2107      * to be an addition on top of the left margin.
2108      */
2109     _DtCvContainerFMarginOfSeg(para) = _DtCvContainerLMarginOfSeg(para) -
2110                                         _DtCvContainerFMarginOfSeg(para);
2111     if (-1 == result)
2112         optionCount = 0;
2113
2114     return (optionCount - 1);
2115
2116 } /* End GetParagraphParameters */
2117
2118 /******************************************************************************
2119  * Function:    int FlowingParagraph (
2120  *
2121  * Parameters:
2122  *
2123  * Returns:
2124  *
2125  * errno Values:
2126  *
2127  * Purpose:     Process the <PARAGRAPH> specification.
2128  *
2129  *****************************************************************************/
2130 static  int
2131 FlowingParagraph(
2132     FormatVariables     *cur_vars,
2133     ProcessState         cur_state,
2134     _DtCvFrmtOption      frmt_flags,
2135     int                  allowed,
2136     int                  link_idx,
2137     int                  ret_on_nl,
2138     int                  fnt_flag,
2139     _DtCvFrmtOption      gpos,
2140     _DtCvUnit            gspace,
2141     char                *file_name,
2142     _DtHelpFontHints    *font_attr)
2143 {
2144     int         type     = 0;
2145     int         result   = -1;
2146     _DtCvSegment *graphSeg;
2147     _DtCvSegment *bodySeg;
2148     SegList     flowList = InitList;
2149
2150     /*
2151      * reset current list
2152      */
2153     cur_vars->my_list = InitList;
2154
2155     /*
2156      * create two containers.
2157      */
2158     if (0 == CheckList(&(flowList), 2, 2))
2159       {
2160         /*
2161          * point to the containers for the graphic and body.
2162          */
2163         graphSeg = flowList.list;
2164         bodySeg  = flowList.list;
2165         bodySeg++;
2166
2167         /*
2168          * set the bottom margins to zero.
2169          */
2170         graphSeg->type = _DtCvSetTypeToContainer(graphSeg->type);
2171         bodySeg->type  = _DtCvSetTypeToContainer(bodySeg->type);
2172         _DtCvContainerBMarginOfSeg(graphSeg) = 0;
2173         _DtCvContainerBMarginOfSeg(bodySeg) = 0;
2174
2175         /*
2176          * so the first segment is the container for the graphic.
2177          * set the controller flag and values.
2178          */
2179         graphSeg->type = _DtCvSetTypeToController(graphSeg->type);
2180         _DtCvContainerFlowOfSeg(graphSeg)    = _DtCvWRAP;
2181         _DtCvContainerPercentOfSeg(graphSeg) = 0;
2182         _DtCvContainerOrientOfSeg(graphSeg)  = gpos;
2183         if (_DtCvJUSTIFY_LEFT == gpos)
2184           {
2185             _DtCvContainerJustifyOfSeg(graphSeg) = gpos;
2186             _DtCvContainerRMarginOfSeg(graphSeg) = gspace;
2187           }
2188         else
2189           {
2190             _DtCvContainerJustifyOfSeg(graphSeg) = gpos;
2191             _DtCvContainerLMarginOfSeg(graphSeg) = gspace;
2192           }
2193
2194         /*
2195          * mark the first segment as used.
2196          */
2197         flowList.cnt++;
2198
2199         /*
2200          * check for hypertext link.
2201          */
2202         if (link_idx > -1)
2203             type = _DtCvHYPER_TEXT;
2204
2205         /*
2206          * re-set the segment list and create the graphic.
2207          */
2208         if (0 == CreateSaveGraphic(cur_vars, type, file_name, link_idx))
2209           {
2210             /*
2211              * so the first segment in cur_vars is a region.
2212              * attach it to the graphic container.
2213              */
2214             _DtCvContainerListOfSeg(graphSeg) = cur_vars->my_list.list;
2215
2216             /*
2217              * now process the following information as the body of
2218              * the paragraph as the list for the non-controller
2219              * container.
2220              */
2221             cur_vars->my_list = InitList;
2222             if (-1 != Parse (CCDF_PARAGRAPH_CMD, cur_state, cur_vars,
2223                                                 0, frmt_flags,
2224                                                 font_attr, -1,
2225                                                 Specials, allowed,
2226                                                 ret_on_nl, fnt_flag))
2227               {
2228                 /*
2229                  * establish the links between the segments
2230                  */
2231                 TerminateSegList(&(cur_vars->my_list), True);
2232
2233                 /*
2234                  * if there was a segment list generated,
2235                  * attach the it to the non-controller
2236                  * container and mark it as used.
2237                  */
2238                 if (NULL != cur_vars->my_list.list)
2239                   {
2240                     _DtCvContainerListOfSeg(bodySeg) = cur_vars->my_list.list;
2241                     flowList.cnt++;
2242                   }
2243                 result = 0;
2244               }
2245           }
2246       }
2247
2248     cur_vars->my_list        = flowList;
2249     TerminateSegList(&(cur_vars->my_list), True);
2250     return result;
2251 }
2252
2253 /******************************************************************************
2254  * Function:    int ProcessParagraph (
2255  *
2256  * Parameters:
2257  *
2258  * Returns:
2259  *
2260  * errno Values:
2261  *
2262  * Purpose:     Process the <PARAGRAPH> specification.
2263  *
2264  *****************************************************************************/
2265 static  int
2266 ProcessParagraph(
2267     FormatVariables     *cur_vars,
2268     ProcessState         cur_state,
2269     int                  fnt_flag)
2270 {
2271     int          result   = 0;
2272     int          labelFnd = False;
2273     int          allowed = ~(CCDF_TOPIC_CMD | CCDF_TITLE_CMD | CCDF_ABBREV_CMD);
2274     int          oldMbLenMax = cur_vars->cur_mb_max;
2275     int          glinktype   = -1;
2276     int          linkIndex   = -1;
2277     _DtCvUnit    gspace      = 0;
2278     char        *glinkSpec   = NULL;
2279     char        *label       = NULL;
2280     char        *fileName    = NULL;
2281     char        *description = NULL;
2282     char         numChar[16];
2283
2284     ProcessState         myState = NormalState;
2285     _DtCvFrmtOption      gpos;
2286     _DtCvFrmtOption      frmtType = _DtCvDYNAMIC;
2287     _DtCvSegment        *paraSeg;
2288     _DtCvSegment        *labelSeg = NULL;
2289     _DtCvSegment        *col1     = NULL;
2290     _DtCvSegment        *col2     = NULL;
2291     _DtCvSegment        **childList;
2292     SegList              oldList;
2293     SegList              tableList = InitList;
2294     _DtHelpFontHints     fontAttrs;
2295
2296     /*
2297      * remember the old font list.
2298      * initialize the font quark list
2299      * and use the char set specified for this topic.
2300      */
2301     _DtHelpCeCopyDefFontAttrList (&fontAttrs);
2302     cur_vars->cur_mb_max               = cur_vars->topic_mb_max;
2303     _DtHelpFontHintsLang(fontAttrs)    = cur_vars->topic_lang;
2304     _DtHelpFontHintsCharSet(fontAttrs) = cur_vars->topic_char_set;
2305
2306     /*
2307      * Make next segment in my parent's list for a container for this
2308      * paragraph.
2309      */
2310     if (-1 == CheckSegList(cur_vars))
2311         return -1;
2312
2313     /*
2314      * remember the parent list
2315      * make sure the defaults are set
2316      */
2317     oldList           = cur_vars->my_list;
2318     paraSeg           = NextAvailSeg(cur_vars->my_list);
2319     paraSeg->handle.container = DefContainer;
2320     paraSeg->type     = _DtCvSetTypeToContainer(paraSeg->type);
2321     _DtCvContainerLeadingOfSeg(paraSeg) = cur_vars->ui_info->leading;
2322     cur_vars->my_list = InitList;
2323
2324     /*
2325      * get the parameters on the paragraph
2326      * and set the default for the bottom.
2327      */
2328     result = GetParagraphParameters (cur_vars, paraSeg, &frmtType,
2329                                 &gpos, &glinkSpec, &glinktype, &gspace,
2330                                 &label, &fileName, &description);
2331
2332     /*
2333      * for lists, we will inherit our parent's bottom margin
2334      * when we return to the loop processing the list. Therefore,
2335      * set our bottom margin to zero if we are part of a label body.
2336      */
2337     if (0 == result && LabelBody == cur_state)
2338         _DtCvContainerBMarginOfSeg(paraSeg) = 0;
2339     else if (result > 0)
2340         result = 0;
2341
2342     /*
2343      * check for a label specification. Either as a 'label' parameter
2344      * or a the <LABEL> command.
2345      */
2346     if (-1 != result)
2347       {
2348         /*
2349          * check for the parameter
2350          */
2351         if (NULL != label)
2352           {
2353             FormatVariables   oldVars = *cur_vars;
2354
2355             cur_vars->rd_buf  = label;
2356             cur_vars->rd_flag = 0;
2357             cur_vars->rd_ptr  = label;
2358             cur_vars->my_file = NULL;
2359
2360             result = Parse (CCDF_LABEL_CMD, NormalState, cur_vars,
2361                                         0, frmtType,
2362                                         &fontAttrs, -1,
2363                                         Specials,
2364                                         (CCDF_FONT_CMD | CCDF_OCTAL_CMD),
2365                                         False, fnt_flag);
2366
2367             if (result != -1)
2368                 result = CheckSaveSegment (_DtCvSTRING, &fontAttrs,
2369                                                                 -1, cur_vars);
2370
2371             TerminateSegList(&(cur_vars->my_list), True);
2372             cur_vars->rd_buf  = oldVars.rd_buf;
2373             cur_vars->rd_flag = oldVars.rd_flag;
2374             cur_vars->rd_ptr  = oldVars.rd_ptr;
2375             cur_vars->my_file = oldVars.my_file;
2376             cur_vars->last_was_space = True;
2377
2378             labelSeg = cur_vars->my_list.list;
2379             cur_vars->my_list = InitList;
2380             labelFnd = True;
2381           }
2382         /*
2383          * check for the command.
2384          */
2385         else if (0 == _DtHelpCeCheckNextCcdfCmd("lab", cur_vars->my_file,
2386                                                 cur_vars->rd_buf,
2387                                                 cur_vars->rd_size, 1,
2388                                                 &(cur_vars->rd_ptr)))
2389           {
2390             result = ProcessLabelCmd(cur_vars, 0, frmtType,
2391                                                 &fontAttrs, -1,
2392                                                 allowed, False, fnt_flag,
2393                                                 &labelSeg);
2394             labelFnd = True;
2395           }
2396
2397         /*
2398          * if a label was processed, create the containers for it.
2399          */
2400         if (-1 != result && True == labelFnd)
2401           {
2402             /*
2403              * set the correct state.
2404              */
2405             myState = LabelBody;
2406
2407             /*
2408              * create containers for the label and it's body
2409              */
2410             result = CheckList(&tableList, 2, 2);
2411             if (-1 != result)
2412               {
2413                 /*
2414                  * set the top and bottom margins on both the child
2415                  * containers (so they are the same) to reflect
2416                  * the list's before/after values.
2417                  */
2418                 /*
2419                  * set the pointer to the first column
2420                  * overwrite the left and right margin values.
2421                  */
2422                 col1       = NextAvailSeg(tableList);
2423                 col1->type = _DtCvSetTypeToContainer(col1->type);
2424                 _DtCvContainerTMarginOfSeg(col1) =
2425                                         _DtCvContainerTMarginOfSeg(paraSeg);
2426                 _DtCvContainerBMarginOfSeg(col1) =
2427                                         _DtCvContainerBMarginOfSeg(paraSeg);
2428                 _DtCvContainerLMarginOfSeg(col1) = 0;
2429                 _DtCvContainerRMarginOfSeg(col1) = cur_vars->ui_info->avg_char;
2430                 tableList.cnt++;
2431
2432                 /*
2433                  * set the pointer for the second column
2434                  * and set the top/bottom values.
2435                  */
2436                 col2       = NextAvailSeg(tableList);
2437                 col2->type = _DtCvSetTypeToContainer(col2->type);
2438                 _DtCvContainerTMarginOfSeg(col2) =
2439                                         _DtCvContainerTMarginOfSeg(paraSeg);
2440                 _DtCvContainerBMarginOfSeg(col2) =
2441                                         _DtCvContainerBMarginOfSeg(paraSeg);
2442                 tableList.cnt++;
2443
2444                 /*
2445                  * create an id for this label
2446                  */
2447                 sprintf(numChar, "%d", cur_vars->cell_cnt++);
2448                 _DtCvContainerIdOfSeg(col1) = (char *) malloc (
2449                                 strlen("&CCDF_RES_") + strlen(numChar) + 1);
2450                 if (NULL != _DtCvContainerIdOfSeg(col1))
2451                   {
2452                     /*
2453                      * copy over the id and attach the list.
2454                      */
2455                     strcpy(_DtCvContainerIdOfSeg(col1), "&CCDF_RES_");
2456                     strcat(_DtCvContainerIdOfSeg(col1), numChar);
2457                     _DtCvContainerListOfSeg(col1) = labelSeg;
2458
2459                     /*
2460                      * set the id for the second column.
2461                      */
2462                     sprintf(numChar, "%d", cur_vars->cell_cnt++);
2463                     _DtCvContainerIdOfSeg(col2) = (char *) malloc (
2464                                 strlen("&CCDF_RES_") + strlen(numChar) + 1);
2465                     if (NULL != _DtCvContainerIdOfSeg(col2))
2466                       {
2467                         strcpy(_DtCvContainerIdOfSeg(col2), "&CCDF_RES_");
2468                         strcat(_DtCvContainerIdOfSeg(col2), numChar);
2469                       }
2470                     else
2471                         result = -1;
2472                   }
2473                 else
2474                     result = -1;
2475               }
2476           }
2477       }
2478
2479     /*
2480      * disallow labels from here on out. Either one was found and processed
2481      * or not.
2482      */
2483     allowed &= (~(CCDF_LABEL_CMD));
2484
2485     /*
2486      * Now check and process the graphic specification.
2487      */
2488     if (-1 != result)
2489       {
2490         /*
2491          * initialize the segment list for the children of the paragraph.
2492          */
2493         cur_vars->my_list = InitList;
2494
2495         /*
2496          * check for a graphic in the specification.
2497          * If so, then we need to create, as the list for the
2498          * paragraph container, two containers; one container
2499          * that is a controller and has the graphic and the
2500          * other contains the rest of the content of the
2501          * paragraph.
2502          *
2503          * First, create the link index for the graphic.
2504          */
2505         if (NULL != glinkSpec)
2506           {
2507             /*
2508              * but if there isn't a graphic, throw away the link
2509              * specifications since they are useless!
2510              */
2511             if (NULL != fileName && strlen (glinkSpec))
2512               {
2513                 linkIndex = _DtLinkDbAddLink (cur_vars->my_links,
2514                                         NULL,
2515                                         glinkSpec,
2516                                         ReturnLinkType(glinktype, glinkSpec),
2517                                         ReturnLinkWinHint(glinktype),
2518                                         description);
2519
2520                 /*
2521                  * had problems creating the link index, bail
2522                  */
2523                 if (linkIndex == -1)
2524                     result = -1;
2525               }
2526           }
2527
2528         /*
2529          * now create the graphic and process the graphic body..
2530          * or just process the rest of the paragraph....
2531          */
2532         if (0 == result)
2533           {
2534             if (NULL != fileName)
2535                 result = FlowingParagraph(cur_vars,
2536                                         myState,
2537                                         frmtType,
2538                                         allowed, linkIndex,
2539                                         False, fnt_flag,
2540                                         gpos, gspace, fileName,
2541                                         &fontAttrs);
2542             else
2543               {
2544                 result = Parse (CCDF_PARAGRAPH_CMD, myState, cur_vars,
2545                                         0, frmtType,
2546                                         &fontAttrs, -1,
2547                                         Specials, allowed,
2548                                         False, fnt_flag);
2549                 if (-1 != result)
2550                   {
2551                     /*
2552                      * establish the links
2553                      */
2554                     TerminateSegList (&(cur_vars->my_list), True);
2555                   }
2556               }
2557           }
2558
2559         if (-1 != result)
2560           {
2561              char       **colW;
2562              _DtCvFrmtOption    *colJ;
2563
2564             if (True == labelFnd)
2565               {
2566                 char *colW1 = "1";              /* default bulletted list */
2567                 char *colW2 = "99,0,98";        /* default bulletted list */
2568                 char *ids;
2569
2570                 /*
2571                  * set the body of the label in it's container.
2572                  */
2573                 _DtCvContainerListOfSeg(col2) = cur_vars->my_list.list;
2574
2575                 /*
2576                  * figure out which column widths should be used.
2577                  */
2578                 if (14 * cur_vars->ui_info->avg_char
2579                                         == _DtCvContainerLMarginOfSeg(paraSeg))
2580                   {
2581                     /* Labeled lists */
2582                     colW1 = "20,20,10";
2583                     colW2 = "80,10,20";
2584                   }
2585                 else if (3 * cur_vars->ui_info->avg_char
2586                                         == _DtCvContainerLMarginOfSeg(paraSeg))
2587                     /* Ordered lists */
2588                     colW1 = "1,98,0";
2589                 else if (0 == _DtCvContainerLMarginOfSeg(paraSeg))
2590                     /* Plain lists */
2591                     colW1 = "0";
2592
2593                 /*
2594                  * create the column width strings.
2595                  */
2596                 colW = NULL;
2597                 colW = (char **) _DtCvAddPtrToArray((void **) colW,
2598                                                 ((void *) strdup(colW1)));
2599                 if (NULL != colW)
2600                     colW = (char **) _DtCvAddPtrToArray((void **) colW,
2601                                                 ((void *) strdup (colW2)));
2602
2603                 /*
2604                  * create the array for column justification.
2605                  */
2606                 colJ = (_DtCvFrmtOption *) malloc (sizeof(_DtCvFrmtOption) * 2);
2607                 if (NULL != colJ)
2608                   {
2609                     colJ[0] = _DtCvJUSTIFY_LEFT;
2610                     colJ[1] = _DtCvJUSTIFY_LEFT;
2611                   }
2612
2613                 /*
2614                  * set this segment's type to a table and fill in all
2615                  * the relevant information.
2616                  */
2617                 paraSeg->type                        = _DtCvTABLE;
2618                 _DtCvNumColsOfTableSeg(paraSeg)      = 2;
2619                 _DtCvColWOfTableSeg(paraSeg)         = colW;
2620                 _DtCvColJustifyOfTableSeg(paraSeg)   = colJ;
2621                 _DtCvJustifyCharsOfTableSeg(paraSeg) = NULL;
2622
2623                 /*
2624                  * now create the list of ids in this table.
2625                  */
2626                 ids = (char *) malloc (
2627                                 strlen(_DtCvContainerIdOfSeg(col1)) +
2628                                 strlen(_DtCvContainerIdOfSeg(col2)) + 2);
2629                 if (NULL != ids)
2630                   {
2631                     strcpy(ids, _DtCvContainerIdOfSeg(col1));
2632                     strcat(ids, " ");
2633                     strcat(ids, _DtCvContainerIdOfSeg(col2));
2634                   }
2635                 _DtCvCellIdsOfTableSeg(paraSeg) = NULL;
2636                 _DtCvCellIdsOfTableSeg(paraSeg) = (char **)
2637                         _DtCvAddPtrToArray(
2638                                 (void **) _DtCvCellIdsOfTableSeg(paraSeg),
2639                                 (void *) ids);
2640
2641                 /*
2642                  * now create the list of cells in the table.
2643                  */
2644                 _DtCvCellsOfTableSeg(paraSeg) = NULL;
2645                 _DtCvCellsOfTableSeg(paraSeg) = (_DtCvSegment **)
2646                                 _DtCvAddPtrToArray(
2647                                         (void **) _DtCvCellsOfTableSeg(paraSeg),
2648                                         (void  *) col1);
2649                 if (NULL != _DtCvCellsOfTableSeg(paraSeg))
2650                     _DtCvCellsOfTableSeg(paraSeg) = (_DtCvSegment **)
2651                                 _DtCvAddPtrToArray(
2652                                         (void **) _DtCvCellsOfTableSeg(paraSeg),
2653                                         (void  *) col2);
2654
2655                 if (NULL == colW || NULL == colJ || NULL == ids
2656                                 || NULL == _DtCvCellIdsOfTableSeg(paraSeg)
2657                                 || NULL == _DtCvCellsOfTableSeg(paraSeg))
2658                     result = -1;
2659               }
2660             else
2661               {
2662                 _DtCvSegment *pSeg;
2663
2664                 /*
2665                  * attach the list to my container.
2666                  */
2667                 _DtCvContainerListOfSeg(paraSeg) = cur_vars->my_list.list;
2668
2669                 /*
2670                  * consolidate any table children I have.
2671                  */
2672                 for (pSeg = cur_vars->my_list.list, labelSeg = NULL;
2673                                 -1 != result && NULL != pSeg;
2674                                                         pSeg = pSeg->next_seg)
2675                   {
2676                     if (_DtCvIsSegTable(pSeg))
2677                       {
2678                         if (NULL != labelSeg)
2679                           {
2680                             /*
2681                              * bypass this segment since it will no
2682                              * longer be 'used' by consolidating it
2683                              * with another label set.
2684                              */
2685                             labelSeg->next_seg = pSeg->next_seg;
2686
2687                             /*
2688                              * free the other justification and width info.
2689                              */
2690                             free((void *) _DtCvColJustifyOfTableSeg(pSeg));
2691                             colW = _DtCvColWOfTableSeg(pSeg);
2692                             free(*colW++);
2693                             free(*colW);
2694                             free(_DtCvColWOfTableSeg(pSeg));
2695
2696                             /*
2697                              * add the segments to the list
2698                              */
2699                             childList = _DtCvCellsOfTableSeg(pSeg);
2700                             _DtCvCellsOfTableSeg(labelSeg) = (_DtCvSegment **)
2701                                 _DtCvAddPtrToArray(
2702                                     (void **) _DtCvCellsOfTableSeg(labelSeg),
2703                                         *childList);
2704                             childList++;
2705                             if (NULL != _DtCvCellsOfTableSeg(labelSeg))
2706                                 _DtCvCellsOfTableSeg(labelSeg) = (_DtCvSegment **)
2707                                     _DtCvAddPtrToArray(
2708                                         (void **)_DtCvCellsOfTableSeg(labelSeg),
2709                                         *childList);
2710                             free((void *) _DtCvCellsOfTableSeg(pSeg));
2711
2712                             /*
2713                              * add the ids to the list
2714                              */
2715                             _DtCvCellIdsOfTableSeg(labelSeg) = (char **)
2716                                 _DtCvAddPtrToArray(
2717                                     (void **)_DtCvCellIdsOfTableSeg(labelSeg),
2718                                     (void  *)(*(_DtCvCellIdsOfTableSeg(pSeg))));
2719
2720                             free((void *) _DtCvCellIdsOfTableSeg(pSeg));
2721
2722                             if (NULL == _DtCvCellIdsOfTableSeg(labelSeg)
2723                                 || NULL == _DtCvCellsOfTableSeg(labelSeg))
2724                                 result = -1;
2725                           }
2726                         else
2727                           {
2728                             /*
2729                              * this segment becomes the segment holding
2730                              * the consolidated table.
2731                              */
2732                             labelSeg = pSeg;
2733                           }
2734                       }
2735                     else
2736                         labelSeg = NULL;
2737                   }
2738               }
2739           }
2740       }
2741
2742     /*
2743      * restore the font MB_CUR_MAX
2744      */
2745     cur_vars->cur_mb_max = oldMbLenMax;
2746
2747     /*
2748      * free all the strings
2749      */
2750     if (label != NULL)
2751         free (label);
2752     if (fileName != NULL)
2753         free (fileName);
2754
2755     /*
2756      * free the linkSpec and description,
2757      */
2758     if (NULL != description)
2759         free(description);
2760     if (NULL != glinkSpec)
2761         free(glinkSpec);
2762
2763     if (result == -1)
2764         return -1;
2765
2766     oldList.cnt++;
2767     cur_vars->my_list        = oldList;
2768     cur_vars->last_was_space = True;
2769     return 0;
2770
2771 } /* End ProcessParagraph */
2772
2773 /******************************************************************************
2774  * Function:    int ProcessHypertext (
2775  *                                      FormatVariables *cur_vars, int segType,
2776  *                                      char **font_attr, int flags )
2777  *
2778  * Parameters:
2779  *              segType         Specifies the type of segment currently
2780  *                              being processed.
2781  *              font_attr               Specifies the list of font quarks to
2782  *                              associate with the string.
2783  *              flags           Specifies the formatting commands allowed.
2784  * 
2785  * Returns:     0 if successful, -1 if errors.
2786  *
2787  * errno Values:
2788  *
2789  * Purpose:     Process the <LINK> specification.
2790  *
2791  *****************************************************************************/
2792 static  int
2793 ProcessHypertext(
2794     FormatVariables     *cur_vars,
2795     ProcessState         cur_state,
2796     unsigned long        seg_flags,
2797     _DtCvFrmtOption      frmt_type,
2798     _DtHelpFontHints    *font_attr,
2799     int                  flags,
2800     int                  ret_on_nl,
2801     int                  fnt_flag)
2802 {
2803     int    result = 0;
2804     int    hyperType;
2805     int    hyperIndex;
2806     char  *description = NULL;
2807     char  *hyperlink = NULL;
2808
2809     /*
2810      * is a <LINK> command allowed here?
2811      */
2812     if (CCDF_NOT_ALLOW_CMD(flags, CCDF_LINK_CMD))
2813         return -1;
2814
2815     /*
2816      * get the hypertext type
2817      */
2818     if (GetValueParameter (cur_vars, _DtCvTRUE, &hyperType) < 0)
2819         return -1;
2820
2821     if (hyperType < 0)
2822       {
2823         errno = CEErrorHyperType;
2824         return -1;
2825       }
2826
2827     /*
2828      * get the hypertext link spec.
2829      */
2830     result = GetStringParameter(cur_vars, _DtCvTRUE, _DtCvTRUE, _DtCvFALSE,
2831                                                         _DtCvFALSE, &hyperlink);
2832     if (0 == result)
2833       {
2834         /*
2835          * See if we have the optional description string
2836          */
2837         result = GetStringParameter (cur_vars, _DtCvFALSE, _DtCvTRUE,
2838                                         _DtCvFALSE, _DtCvFALSE, &description);
2839         if (result == 1)
2840             description = NULL;
2841
2842         result = _DtLinkDbAddLink (cur_vars->my_links,
2843                                         NULL,
2844                                         hyperlink,
2845                                         ReturnLinkType(hyperType, hyperlink),
2846                                         ReturnLinkWinHint(hyperType),
2847                                         description);
2848         if (NULL != description)
2849             free(description);
2850
2851         free(hyperlink);
2852       }
2853
2854     /*
2855      * if no problems encountered, start parsing with this
2856      * hypertext link.
2857      */
2858     if (result != -1)
2859       {
2860         hyperIndex = result;
2861         result = FindEndMarker (cur_vars);
2862         if (!result)
2863           {
2864             /*
2865              * set the hypertext flag and type.
2866              */
2867             seg_flags = _DtCvSetTypeToHyperText(seg_flags);
2868
2869             result = Parse (CCDF_LINK_CMD, cur_state, cur_vars,
2870                                                 seg_flags, frmt_type,
2871                                                 font_attr,
2872                                                 hyperIndex,
2873                                                 Specials, flags,
2874                                                 ret_on_nl, fnt_flag);
2875           }
2876       }
2877
2878     /*
2879      * Don't free the hypertext string or description.
2880      * It is now owned by the Link List.
2881      */
2882
2883     if (result == -1)
2884         return -1;
2885
2886     return 0;
2887
2888 } /* End ProcessHypertext */
2889
2890 /******************************************************************************
2891  * Function:    int ProcessLabelCmd (
2892  *                              FormatVariables *cur_vars, int seg_type,
2893  *                              char **font_attr, int link_spec,
2894  *                              int flags )
2895  *
2896  * Parameters:
2897  *              font_attr       Specifies the list of font quarks to
2898  *                              associate with the string.
2899  *              link_spec       Specifies the hypertext link to associate
2900  *                              with the string.
2901  *              flags           Specifies the formatting commands allowed.
2902  * 
2903  * Returns:     0 if successful, -1 if errors.
2904  *
2905  * errno Values:
2906  *
2907  * Purpose:     Process the <LABEL> specification.
2908  *
2909  *****************************************************************************/
2910 static  int
2911 ProcessLabelCmd(
2912     FormatVariables     *cur_vars,
2913     unsigned long        seg_flags,
2914     _DtCvFrmtOption      frmt_type,
2915     _DtHelpFontHints    *font_attr,
2916     int                  link_spec,
2917     int                  flags,
2918     int                  ret_on_nl,
2919     int                  fnt_flag,
2920     _DtCvSegment        **ret_list)
2921 {
2922     SegList     oldList = cur_vars->my_list;
2923
2924     /*
2925      * is a <LABEL> command allowed?
2926      */
2927     if (CCDF_NOT_ALLOW_CMD(flags, CCDF_LABEL_CMD))
2928         return -1;
2929
2930     /*
2931      * can't have another <LABEL> command inside this one
2932      */
2933     flags &= (~(CCDF_LABEL_CMD));
2934
2935     /*
2936      * Find the end marker
2937      */
2938     if (FindEndMarker (cur_vars) != 0)
2939         return -1;
2940
2941     cur_vars->my_list = InitList;
2942     if (Parse (CCDF_LABEL_CMD, NormalState, cur_vars, 
2943                                         seg_flags,
2944                                         frmt_type,
2945                                         font_attr,
2946                                         link_spec,
2947                                         Specials, flags,
2948                                         ret_on_nl, fnt_flag) == -1)
2949         return -1;
2950
2951     /*
2952      * set the links, return the segment list and restore the old list.
2953      */
2954     TerminateSegList(&(cur_vars->my_list), True);
2955     *ret_list = cur_vars->my_list.list;
2956     cur_vars->my_list = oldList;
2957
2958     /*
2959      * Indicate that preceding space on the next text should be ignored
2960      */
2961     cur_vars->last_was_space = True;
2962
2963     return 0;
2964
2965 } /* End ProcessLabelCmd */
2966
2967 /******************************************************************************
2968  * Function:    int ProcessFigureCmd (
2969  *                                      FormatVariables *cur_vars,
2970  *                                      char **font_attr)
2971  *
2972  * Parameters:
2973  *              font_attr               Specifies the list of font quarks to
2974  *                              associate with the string.
2975  * 
2976  * Returns:     0 if successful, -1 if errors.
2977  *
2978  * errno Values:
2979  *
2980  * Purpose:     Process the <FIGURE> specification.
2981  *
2982  *****************************************************************************/
2983 static  int
2984 ProcessFigureCmd(
2985     FormatVariables     *cur_vars,
2986     ProcessState         cur_state,
2987     _DtCvFrmtOption      frmt_type,
2988     _DtHelpFontHints    *font_attr,
2989     int                  ret_on_nl,
2990     int                  fnt_flag)
2991 {
2992     int         cnt;
2993     int         done         = False;
2994     int         result       = 0;
2995     int         linkType     = CCDF_LINK_JUMP_REUSE;
2996     int         linkIndex    = -1;
2997     int         segType      = _DtCvREGION;
2998     char        *description = NULL;
2999     char        *idString    = NULL;
3000     char        *filename    = NULL;
3001     char        *linkspec    = NULL;
3002     _DtCvFrmtOption     vertOrientCap  = _DtCvJUSTIFY_BOTTOM;
3003     _DtCvFrmtOption     horzOrientCap  = _DtCvJUSTIFY_CENTER;
3004     _DtCvFrmtOption     justifyCap     = _DtCvJUSTIFY_CENTER;
3005     _DtCvFrmtOption     justifyGraphic = _DtCvJUSTIFY_CENTER;
3006     _DtCvSegment        *figContainer;
3007     SegList             oldList;
3008     SegList             capList;
3009     SegList             figList = InitList;
3010
3011     /*
3012      * create a container for this figure (and possibly a caption)
3013      */
3014     if (-1 == CheckSegList(cur_vars))
3015         return -1;
3016
3017     figContainer       = NextAvailSeg(cur_vars->my_list);
3018     figContainer->handle.container = DefContainer;
3019     figContainer->type = _DtCvSetTypeToContainer(figContainer->type);
3020     _DtCvContainerLeadingOfSeg(figContainer) = cur_vars->ui_info->leading;
3021
3022     /*
3023      * remember the old list and initialize for the figure.
3024      */
3025     oldList = cur_vars->my_list;
3026     cur_vars->my_list = InitList;
3027
3028     /*
3029      * process the parameters of the figure cmd.
3030      */
3031     while (!done && result != -1)
3032       {
3033         if (SkipToNextToken (cur_vars, _DtCvFALSE) == -1)
3034           {
3035             result = -1;
3036             continue;
3037           }
3038
3039         switch (_DtCvToLower(*(cur_vars->rd_ptr)))
3040           {
3041             /*
3042              * end of figure spec
3043              */
3044             case '>':
3045                 /*
3046                  * move past the end of token marker
3047                  * and skip the leading blanks in the caption.
3048                  */
3049                 (cur_vars->rd_ptr)++;
3050                 while (result != -1 && !done)
3051                   {
3052                     if (*(cur_vars->rd_ptr) == '\0')
3053                         result = GetNextBuffer (cur_vars);
3054                     else if ((cur_vars->cur_mb_max == 1 ||
3055                         mblen(cur_vars->rd_ptr, cur_vars->cur_mb_max) == 1)
3056                                                 && *(cur_vars->rd_ptr) == ' ')
3057                         (cur_vars->rd_ptr)++;
3058                     else
3059                         done = True;
3060                   }
3061                 break;
3062
3063             /*
3064              * ccenter
3065              * center
3066              * cbottom
3067              * cleft
3068              * cright
3069              * ctop
3070              */
3071             case 'c':
3072                 /*
3073                  * Go to the next character.
3074                  */
3075                 (cur_vars->rd_ptr)++;
3076
3077                 /*
3078                  * Do we need to read more information?
3079                  */
3080                 if (*(cur_vars->rd_ptr) == '\0' && GetNextBuffer (cur_vars) == -1)
3081                     result = -1;
3082
3083                 if (result != -1)
3084                   {
3085                     /*
3086                      * look at the next charager to determine the token.
3087                      */
3088                     switch (_DtCvToLower(*(cur_vars->rd_ptr)))
3089                       {
3090                         case 'c': /* caption center */
3091                             justifyCap    = _DtCvJUSTIFY_CENTER;
3092                             horzOrientCap = _DtCvJUSTIFY_CENTER;
3093                             break;
3094
3095                         case 'e': /* graphic centered */
3096                             justifyGraphic = _DtCvJUSTIFY_CENTER;
3097                             break;
3098
3099                         case 'b': /* caption below graphic */
3100                             vertOrientCap = _DtCvJUSTIFY_BOTTOM;
3101                             break;
3102
3103                         case 'l': /* caption justified left */
3104                             justifyCap    = _DtCvJUSTIFY_LEFT;
3105                             horzOrientCap = _DtCvJUSTIFY_LEFT_MARGIN;
3106                             break;
3107
3108                         case 'r': /* caption right justified */
3109                             justifyCap    = _DtCvJUSTIFY_RIGHT;
3110                             horzOrientCap = _DtCvJUSTIFY_RIGHT_MARGIN;
3111                             break;
3112
3113                         case 't': /* caption at top */
3114                             vertOrientCap = _DtCvJUSTIFY_TOP;
3115                             break;
3116                       }
3117                   }
3118                 break;
3119
3120             /*
3121              * description [string | "string" | 'string']
3122              */
3123             case 'd':
3124                 result = GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3125                                         _DtCvFALSE, _DtCvFALSE, &description);
3126                 break;
3127
3128             /*
3129              * file
3130              */
3131             case 'f':
3132                 result = GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3133                                         _DtCvFALSE, _DtCvFALSE, &filename);
3134                 break;
3135
3136             /*
3137              * id string
3138              */
3139             case 'i':
3140                 /*
3141                  * get the id string
3142                  */
3143                 result = GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3144                                         _DtCvFALSE, _DtCvFALSE, &idString);
3145                 /*
3146                  * if this figure had an id associated with it, create
3147                  * marker segment for it.
3148                  */
3149                 if (-1 != result && NULL != idString && '\0' != *idString)
3150                   {
3151                     /*
3152                      * create the marker. If there is an error, free the
3153                      * string.
3154                      */
3155                     result = CreateMarker(cur_vars, idString);
3156                     if (-1 == result)
3157                         free (idString);
3158                   }
3159                 break;
3160
3161             /*
3162              * left
3163              * link [string | "string" | 'string']
3164              */
3165             case 'l':
3166                 /*
3167                  * Go to the next character.
3168                  */
3169                 (cur_vars->rd_ptr)++;
3170
3171                 /*
3172                  * Do we need to read more information?
3173                  */
3174                 if (*(cur_vars->rd_ptr) == '\0' && GetNextBuffer (cur_vars) == -1)
3175                     result = -1;
3176
3177                 if (result != -1)
3178                   {
3179                     /*
3180                      * look at the next charager to determine the token.
3181                      */
3182                     switch (_DtCvToLower(*(cur_vars->rd_ptr)))
3183                       {
3184                         case 'e':
3185                             justifyGraphic = _DtCvJUSTIFY_LEFT;
3186                             break;
3187
3188                         case 'i':
3189                             segType = _DtCvSetTypeToHyperText (segType);
3190                             result = GetStringParameter (cur_vars, _DtCvTRUE,
3191                                         _DtCvTRUE, _DtCvFALSE, _DtCvFALSE,
3192                                         &linkspec);
3193                             break;
3194
3195                         default:
3196                             result = -1;
3197                       }
3198                   }
3199                 break;
3200
3201             /*
3202              * right
3203              */
3204             case 'r':
3205                 justifyGraphic = _DtCvJUSTIFY_RIGHT;
3206                 break;
3207
3208             /*
3209              * typelink value
3210              */
3211             case 't':
3212                 if (GetValueParameter (cur_vars, _DtCvTRUE, &linkType) == -1)
3213                     result = -1;
3214                 else if (linkType < 0)
3215                   {
3216                     errno = CEErrorHyperType;
3217                     result = -1;
3218                   }
3219                 break;
3220
3221             default:
3222                 result = -1;
3223           }
3224       }
3225
3226     if (result != -1 && (filename == NULL || strlen(filename) == 0))
3227         result = -1;
3228
3229     if (result != -1)
3230       {
3231         /*
3232          * check to see if the hypertext flag is set but we don't
3233          * have a link specification.
3234          */
3235         if (IsTypeHyperText(segType) && !linkspec)
3236           {
3237             segType = segType & ~(_DtCvHYPER_TEXT);
3238
3239             if (NULL != description)
3240                 free (description);
3241             description = NULL;
3242           }
3243
3244         /*
3245          * do we still have a good hypertext?
3246          * if so, create a link index for it.
3247          */
3248         if (IsTypeHyperText(segType))
3249           {
3250             linkIndex = _DtLinkDbAddLink (cur_vars->my_links,
3251                                         NULL,
3252                                         linkspec,
3253                                         ReturnLinkType(linkType, linkspec),
3254                                         ReturnLinkWinHint(linkType),
3255                                         description);
3256             if (linkIndex == -1)
3257                 result = -1;
3258           }
3259       }
3260
3261     if (result != -1)
3262       {
3263         /*
3264          * parse the caption.  If there is a caption, we will need to
3265          * wrap it and the figure in containers with the appropriate
3266          * controller flags set to get the correct layout.
3267          */
3268         result = Parse (CCDF_FIGURE_CMD, cur_state, cur_vars,
3269                                  0, frmt_type,
3270                                  font_attr, -1,
3271                                 Specials,
3272                                 (CCDF_NEWLINE_CMD | CCDF_LINK_CMD |
3273                                  CCDF_FONT_CMD    | CCDF_ID_CMD),
3274                                  ret_on_nl, fnt_flag);
3275
3276         /*
3277          * save the caption List.
3278          */
3279         TerminateSegList(&(cur_vars->my_list), True);
3280         capList = cur_vars->my_list;
3281
3282         /*
3283          * is there a caption? If so, create two segments instead
3284          * of one.
3285          */
3286         cnt = 1;
3287         if (-1 != result && 0 != capList.cnt)
3288             cnt = 2;
3289
3290         /*
3291          * allocate room for the figure (and caption)
3292          */
3293         if (-1 != result)
3294             result = CheckList(&figList, cnt, cnt);
3295
3296         if (-1 != result)
3297           {
3298             /*
3299              * process any caption that was specified
3300              */
3301             if (0 != capList.cnt)
3302               {
3303                 _DtCvSegment *pSeg = figList.list;
3304
3305                 /*
3306                  * create a controller for the caption.
3307                  */
3308                 pSeg->type = _DtCvSetTypeToController(
3309                                         _DtCvSetTypeToContainer(pSeg->type));
3310
3311                 /*
3312                  * set its orientation and justification.
3313                  */
3314                 _DtCvContainerOrientOfSeg(pSeg)  = horzOrientCap;
3315                 _DtCvContainerVOrientOfSeg(pSeg) = vertOrientCap;
3316                 _DtCvContainerJustifyOfSeg(pSeg) = justifyCap;
3317                 _DtCvContainerBMarginOfSeg(pSeg) = 0;
3318
3319                 /*
3320                  * attach the caption to the container.
3321                  */
3322                 _DtCvContainerListOfSeg(pSeg) = capList.list;
3323
3324                 /*
3325                  * indicate this segment has been used.
3326                  */
3327                 figList.cnt++;
3328               }
3329
3330             /*
3331              * now load the graphic into the next available segment
3332              * allocated for the figure.
3333              */
3334             cur_vars->my_list = figList;
3335             result = CreateSaveGraphic (cur_vars, segType, filename, linkIndex);
3336
3337             /*
3338              * if no problems, attach the figure (and caption) to the
3339              * wrapper container
3340              */
3341             if (-1 != result)
3342               {
3343                 /*
3344                  * set the links
3345                  */
3346                 TerminateSegList(&(cur_vars->my_list), True);
3347
3348                 /*
3349                  * attach the figure (and caption) to the wrapper
3350                  */
3351                 _DtCvContainerListOfSeg(figContainer) = cur_vars->my_list.list;
3352
3353                 /*
3354                  * set the justify to the correct value to act on the
3355                  * figure.
3356                  */
3357                 _DtCvContainerJustifyOfSeg(figContainer) = justifyGraphic;
3358
3359                 /*
3360                  * indicate that this segment has been used 
3361                  */
3362                 oldList.cnt++;
3363               }
3364           }
3365       }
3366
3367     /*
3368      * restore the segment list.
3369      * and free memory.
3370      */
3371     cur_vars->my_list = oldList;
3372     free (filename);
3373
3374     /*
3375      * don't free the link string or description,
3376      * the link list owns them now.
3377      */
3378
3379     return result;
3380
3381 } /* End ProcessFigureCmd */
3382
3383 /******************************************************************************
3384  * Function:    int ProcessInLine (FormatVariables cur_vars,
3385  *                                      int seg_type, int link_spec )
3386  *
3387  * Parameters:
3388  *              seg_type        Specifes the type of segment currently
3389  *                              being processed.
3390  *              link_spec       Specifies the hypertext link associated
3391  *                              with this segment.
3392  * 
3393  * Returns:     0 if successful, -1 if errors.
3394  *
3395  * errno Values:
3396  *
3397  * Purpose:     Process a <GRAPHIC> specification.
3398  *
3399  *****************************************************************************/
3400 static  int
3401 ProcessInLine(
3402     FormatVariables     *cur_vars,
3403     int                 seg_type,
3404     int                 link_spec )
3405 {
3406     int         done = False;
3407     int         result = 0;
3408     char        *idString = NULL;
3409     char        *filename = NULL;
3410
3411     /*
3412      * process the graphic parameters
3413      */
3414     while (!done && result != -1)
3415       {
3416         if (SkipToNextToken (cur_vars, _DtCvFALSE) == -1)
3417             return -1;
3418
3419         switch (_DtCvToLower(*(cur_vars->rd_ptr)))
3420           {
3421             /*
3422              * end of in line spec
3423              */
3424             case '>':
3425                 /*
3426                  * move past the end of token marker
3427                  */
3428                 (cur_vars->rd_ptr)++;
3429                 done = True;
3430                 break;
3431
3432             /*
3433              * file
3434              */
3435             case 'f':
3436                 result = GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3437                                         _DtCvFALSE, _DtCvFALSE, &filename);
3438                 break;
3439
3440             /*
3441              * id string
3442              */
3443             case 'i':
3444                 /*
3445                  * get the id string
3446                  */
3447                 result = GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3448                                         _DtCvFALSE, _DtCvFALSE, &idString);
3449                 /*
3450                  * if this graphic had an id associated with it, create
3451                  * marker segment for it.
3452                  */
3453                 if (-1 != result && NULL != idString && '\0' != *idString)
3454                   {
3455                     /*
3456                      * create the marker. If there is an error, free the
3457                      * string.
3458                      */
3459                     result = CreateMarker(cur_vars, idString);
3460                     if (-1 == result)
3461                         free (idString);
3462                   }
3463
3464                 break;
3465
3466             default:
3467                 result = -1;
3468           }
3469       }
3470
3471     if (result != -1 && (filename == NULL || strlen(filename) == 0))
3472         result = -1;
3473
3474     if (result != -1)
3475       {
3476         /*
3477          * create the graphic.
3478          */
3479         result = CreateSaveGraphic (cur_vars,
3480                                         _DtCvSetTypeToInLine(seg_type),
3481                                         filename, link_spec);
3482         cur_vars->last_was_space = False;
3483       }
3484
3485     free (filename);
3486
3487     return result;
3488
3489 } /* End ProcessInLine */
3490
3491 /******************************************************************************
3492  * Function:    int CheckIdString (
3493  *                              FormatVariables *cur_vars, int segType,
3494  *                              char **font_attr, int linkspec,
3495  *                              int flags)
3496  * 
3497  * Parameters:
3498  *              segType         Specifies the type of segment currently
3499  *                              being processed.
3500  *              font_attr               Specifies the list of font quarks to
3501  *                              associate with the string.
3502  *              linkspec        Specifies the hypertext link associated
3503  *                              with the segment.
3504  *              flags           Specifies the formatting commands allowed.
3505  * 
3506  * Returns:     0 if successful, -1 if errors.
3507  *
3508  * errno Values:
3509  *
3510  * Purpose:     Create a marker at this location.
3511  * 
3512  *****************************************************************************/
3513 static  int
3514 CheckIdString(
3515     FormatVariables     *cur_vars,
3516     ProcessState         cur_state,
3517     unsigned long        seg_flags,
3518     _DtCvFrmtOption      frmt_type,
3519     _DtHelpFontHints    *font_attr,
3520     int                  linkspec,
3521     int                  flags,
3522     int                  ret_on_nl,
3523     int                  fnt_flag)
3524 {
3525     int    result = -1;
3526     char  *ptr    = NULL;
3527
3528     /*
3529      * is it legal to have a <ID> command at this point?
3530      */
3531     if (CCDF_NOT_ALLOW_CMD (flags, CCDF_ID_CMD))
3532         return -1;
3533
3534     /*
3535      * get the id string
3536      * clear out any current information in the buffer
3537      * and make sure there is a segment available.
3538      */
3539     if (-1 != GetStringParameter (cur_vars, _DtCvTRUE, _DtCvTRUE,
3540                                                 _DtCvFALSE, _DtCvFALSE, &ptr)
3541                                 &&
3542         -1 != CheckSaveSegment (seg_flags, font_attr, linkspec, cur_vars))
3543       {
3544         /*
3545          * create the marker. If there is an error, free the
3546          * string.
3547          */
3548         result = CreateMarker(cur_vars, ptr);
3549         if (-1 == result)
3550             free (ptr);
3551
3552         /*
3553          * find the end of the <ID> syntax
3554          * and parse the data between the begin <ID> and </ID>.
3555          */
3556         if (0 == result && -1 != FindEndMarker (cur_vars) &&
3557                 -1 != Parse (CCDF_ID_CMD, cur_state, cur_vars,
3558                                                 seg_flags, frmt_type,
3559                                                 font_attr,
3560                                                 linkspec,
3561                                                 Specials, flags,
3562                                                 ret_on_nl, fnt_flag))
3563             result = 0;
3564       }
3565
3566     /*
3567      * return an error code if necessary
3568      */
3569     return result;
3570
3571 } /* End CheckIdString */
3572
3573 /******************************************************************************
3574  * Function:    int     Parse (int cur_cmd, 
3575  *                              FormatVariables *cur_vars, int segType,
3576  *                              char **font_attr,
3577  *                              int  linkspec, int allowed)
3578  * 
3579  * Parameters:
3580  *              cur_cmd         Specifies the current formatting command
3581  *                              being processed.
3582  *              parent          Specifies the parent paragraph.
3583  *              segType         Specifies the type of segment currently
3584  *                              being processed.
3585  *              font_attr               Specifies the list of font quarks to
3586  *                              associate with the string.
3587  *              linkspec        Specifies the hypertext link associated
3588  *                              with the segment.
3589  *              allowed         Specifies the formatting commands allowed.
3590  * 
3591  * Returns:
3592  *              1 if ran into a </> specification.
3593  *              -1 if errors.
3594  *
3595  * errno Values:
3596  *
3597  * Purpose:     Parse the data.
3598  *
3599  *****************************************************************************/
3600 static  int
3601 Parse(
3602     int                   cur_cmd,
3603     ProcessState          cur_state,
3604     FormatVariables      *cur_vars,
3605     unsigned long         seg_flags,
3606     _DtCvFrmtOption       frmt_type,
3607     _DtHelpFontHints    *font_attr,
3608     int                   linkspec,
3609     const char           *scan_string,
3610     int                   allowed,
3611     int                   ret_on_nl,
3612     int                   fnt_flag)
3613 {
3614     int      charSize = 1;
3615     int      leftOver = 0;
3616     int      done = False;
3617     int      fontType = False;
3618     int      cmdType  = False;
3619     char    *ptr;
3620
3621     while (!done)
3622       {
3623         if (cur_vars->cur_mb_max != 1)
3624             charSize = mblen(cur_vars->rd_ptr, cur_vars->cur_mb_max);
3625
3626         if (charSize == 1)
3627           {
3628             /*
3629              * check to see if a newline was the previous character.
3630              * If so, it may need to be replaced with a space.
3631              */
3632             if (cur_vars->last_was_nl == True &&
3633                         AppendSpaceToInfo(cur_vars, NULL, frmt_type) == -1)
3634                 return -1;
3635
3636             cur_vars->last_was_nl = False;
3637             cur_vars->last_was_mb = False;
3638
3639             switch (*(cur_vars->rd_ptr))
3640               {
3641                 case '<':
3642                     /*
3643                      * Go to the next character.
3644                      */
3645                     (cur_vars->rd_ptr)++;
3646
3647                     /*
3648                      * determine the cmd
3649                      */
3650                     cmdType = _DtHelpCeGetCcdfCmd (cur_cmd, cur_vars->rd_buf,
3651                                                         &(cur_vars->rd_ptr),
3652                                                         cur_vars->my_file,
3653                                                         cur_vars->rd_size,
3654                                                         allowed);
3655                     switch (cmdType)
3656                       {
3657                         /*
3658                          * <figure>
3659                          */
3660                         case CCDF_FIGURE_CMD:
3661                                 if (CheckSaveSegment(seg_flags, font_attr,
3662                                         linkspec, cur_vars) == -1
3663                                                 ||
3664                                         ProcessFigureCmd(cur_vars,
3665                                                 cur_state,
3666                                                 frmt_type,
3667                                                 font_attr,
3668                                                 ret_on_nl, fnt_flag) == -1)
3669                                     return -1;
3670                                 break;
3671
3672                         /*
3673                          * <angle>
3674                          * <characterset>
3675                          * <size>
3676                          * <spacing>
3677                          * <type>
3678                          * <weight>
3679                          */
3680                         case CCDF_FONT_CMD:
3681                                 fontType = _DtHelpCeGetCcdfFontType (cur_vars->rd_ptr);
3682                                 done     = ChangeFont(fontType, seg_flags,
3683                                                         frmt_type,
3684                                                         font_attr , linkspec,
3685                                                         cur_vars,
3686                                                         cur_state,
3687                                                         allowed,
3688                                                         ret_on_nl,
3689                                                         fnt_flag);
3690
3691                                 break;
3692
3693                         /*
3694                          * </>
3695                          */
3696                         case CCDF_FORMAT_END:
3697                                 if (CheckSaveSegment(seg_flags, font_attr,
3698                                                 linkspec, cur_vars) == -1 ||
3699                                         FindEndMarker (cur_vars) == -1)
3700                                     return -1;
3701
3702                                 return 1;
3703
3704                         /*
3705                          * <graphic>
3706                          */
3707                         case CCDF_GRAPHIC_CMD:
3708                                 /*
3709                                  * clear out any information
3710                                  * in the buffer and then
3711                                  * process the figure.
3712                                  */
3713                                 if (CheckSaveSegment (seg_flags, font_attr,
3714                                                 linkspec, cur_vars) == -1
3715                                                         ||
3716                                         ProcessInLine (cur_vars, seg_flags,
3717                                                                 linkspec) == -1)
3718                                     done = -1;
3719                                 break;
3720
3721                         /*
3722                          * <id>
3723                          */
3724                         case CCDF_ID_CMD:
3725                                 done = CheckIdString (cur_vars,
3726                                                       cur_state,
3727                                                       seg_flags,
3728                                                       frmt_type,
3729                                                       font_attr,
3730                                                       linkspec,
3731                                                       allowed,
3732                                                       ret_on_nl, fnt_flag);
3733                                 break;
3734
3735                         /*
3736                          * <link>
3737                          */
3738                         case CCDF_LINK_CMD:
3739                                 if (CheckSaveSegment (seg_flags, font_attr,
3740                                                 linkspec, cur_vars) == -1
3741                                         ||
3742                                      ProcessHypertext(cur_vars, cur_state,
3743                                                         seg_flags, frmt_type,
3744                                                   font_attr, allowed,
3745                                                   ret_on_nl, fnt_flag) == -1)
3746                                     done = -1;
3747                                 break;
3748
3749                         /*
3750                          * <newline>
3751                          */
3752                         case CCDF_NEWLINE_CMD:
3753                                 if (SaveNewLine (cur_vars, seg_flags, font_attr,
3754                                                 linkspec) == -1
3755                                                 ||
3756                                         FindEndMarker (cur_vars) == -1)
3757                                     done = -1;
3758                                 break;
3759
3760                         case CCDF_OCTAL_CMD:
3761                                 if (AppendOctalToInfo(cur_vars,
3762                                                         cur_vars->rd_ptr) == -1
3763                                         || FindEndMarker (cur_vars) == -1)
3764                                     done = -1;
3765                                 break;
3766
3767                         /*
3768                          * <paragraph>
3769                          */
3770                         case CCDF_PARAGRAPH_CMD:
3771                                 if (CheckSaveSegment (seg_flags, font_attr,
3772                                                 linkspec, cur_vars) == -1
3773                                                 ||
3774                                       ProcessParagraph(cur_vars, cur_state,
3775                                                         fnt_flag) == -1)
3776                                     done = -1;
3777                                 break;
3778
3779                         /*
3780                          * <label>
3781                          * this should never be hit if the markup is
3782                          * correct. Processing labels is through the
3783                          * the paragraph processor now.
3784                          */
3785                         case CCDF_LABEL_CMD:
3786
3787                         /*
3788                          * unknown command.
3789                          */
3790                         default:
3791                                 return -1;
3792                       }
3793                     break;
3794
3795                 case '\n':
3796                         /*
3797                          * Go to the next character
3798                          */
3799                         (cur_vars->rd_ptr)++;
3800
3801                         /*
3802                          * If processing a static segment, we want to
3803                          * keep the author defined end-of-lines.
3804                          *
3805                          * Otherwise, we throw them away.
3806                          */
3807                         if (_DtCvLITERAL == frmt_type || True == ret_on_nl)
3808                           {
3809                             done = SaveStringAsSegments (cur_vars,
3810                                         _DtCvSetTypeToNewLine(seg_flags),
3811                                         font_attr, linkspec);
3812
3813                             if (ret_on_nl)
3814                                 return 0;
3815                           }
3816                         else if (cur_vars->last_was_space == False)
3817                             cur_vars->last_was_nl = True;
3818
3819                         break;
3820
3821                 case '\t':
3822                         /*
3823                          * go past this character.
3824                          */
3825                         (cur_vars->rd_ptr)++;
3826
3827                         /*
3828                          * append 1-8 characters on the end of the buffer.
3829                          */
3830                         _DtHelpCeCountChars(cur_vars->fmt_buf, MB_CUR_MAX,
3831                                                                 &leftOver);
3832                         leftOver = leftOver % 8;
3833                         ptr = ((char *) SpaceString) + leftOver;
3834                         done = _DtHelpCeAddStrToBuf (&ptr,
3835                                                 &(cur_vars->fmt_buf),
3836                                                 &(cur_vars->fmt_size),
3837                                                 &(cur_vars->fmt_buf_max),
3838                                                 (8 - leftOver),
3839                                                 INFO_GROW);
3840                         break;
3841
3842                 case '\\':
3843                         /*
3844                          * The author has escaped a character.
3845                          * Increment to the escaped character.
3846                          */
3847                         (cur_vars->rd_ptr)++;
3848
3849                         /*
3850                          * Do we need to read more information?
3851                          */
3852                         if (*(cur_vars->rd_ptr) == '\0' &&
3853                                                 GetNextBuffer (cur_vars) == -1)
3854                             return -1;
3855                         /*
3856                          * If we didn't read more information or
3857                          * was successful on the read, save the
3858                          * escaped character.
3859                          */
3860                         done = AppendCharToInfo (cur_vars, &(cur_vars->rd_ptr));
3861                         break;
3862
3863                 case ' ':
3864                         /*
3865                          * Put a space in the segment.
3866                          */
3867                         done = AppendSpaceToInfo (cur_vars,
3868                                                 &(cur_vars->rd_ptr), frmt_type);
3869                         break;
3870
3871                 default:
3872                         /*
3873                          * put the information in the buffer
3874                          */
3875                         if (AppendToInfo (cur_vars, &(cur_vars->rd_ptr),
3876                                                         scan_string) == -1)
3877                             return -1;
3878               }
3879
3880           }
3881         else if (charSize > 1)
3882           {
3883             if ((cur_vars->ui_info->nl_to_space == 1 ||
3884                         (cur_vars->last_was_mb == False
3885                                         && cur_vars->last_was_nl == True))
3886                  && AppendSpaceToInfo(cur_vars, NULL, frmt_type) == -1)
3887                 done = -1;
3888                 
3889             cur_vars->last_was_nl = False;
3890             cur_vars->last_was_mb = True;
3891             if (AppendToInfo (cur_vars, &(cur_vars->rd_ptr), scan_string) == -1)
3892                 return -1;
3893           }
3894         else if (charSize < 0)
3895           {
3896             /*
3897              * we have either invalid characters or part of a multi-byte
3898              * character. Read the next buffer for more info.
3899              */
3900              leftOver = strlen (cur_vars->rd_ptr);
3901              if (leftOver < ((int) MB_CUR_MAX))
3902                {
3903                 if (GetNextBuffer (cur_vars) == -1)
3904                     done = -1;
3905                }
3906              else
3907                {
3908                  /*
3909                   * In trouble brothers and sisters. We have garbage in the
3910                   * buffer - BAIL OUT!
3911                   */
3912                  done = -1;
3913                }
3914           }
3915         if (!done && *(cur_vars->rd_ptr) == '\0')
3916           {
3917             /*
3918              * We're at the end of the buffer, can we read more?
3919              */
3920             if (cur_vars->rd_flag > 0 && GetNextBuffer (cur_vars) == -1)
3921                 return -1;
3922
3923             if (cur_vars->rd_flag == 0)
3924                 done = True;
3925           }
3926       }
3927
3928     /*
3929      * DO NOT MODIFY 'done' HERE
3930      * If you do, the caller is unable to test for return value == 1!!!!
3931      */
3932     if (done == -1 ||
3933         CheckSaveSegment (seg_flags, font_attr, linkspec, cur_vars) == -1)
3934         return -1;
3935
3936     return done;
3937 }
3938
3939 /*****************************************************************************
3940  * Function:    int ParseTitle (FormatVariables cur_vars)
3941  *
3942  * Parameters:
3943  *              cur_vars        Specifies the current values for formatting.
3944  *
3945  * Returns:     0 if successful, -1 if failure.
3946  *
3947  * errno Values:
3948  *
3949  * Purpose:     ParseTitle gets the data between a <TITLE> and </TITLE>
3950  *              pair; putting it in a controlling container.
3951  *
3952  *****************************************************************************/
3953 static  int
3954 ParseTitle(
3955     FormatVariables     *cur_vars,
3956     int                  cont_flag,
3957     int                  skip_abbrev,
3958     int                  fnt_flag,
3959     _DtHelpFontHints    *fontAttrs)
3960 {
3961     int result = -1;
3962     SegList oldList = cur_vars->my_list;
3963
3964     /*
3965      * rest the current segment list
3966      */
3967     cur_vars->my_list  = InitList;
3968
3969     /*
3970      * check for the <TITLE> directive.
3971      */
3972     if (_DtHelpCeCheckNextCcdfCmd ("ti", cur_vars->my_file, cur_vars->rd_buf,
3973                         cur_vars->rd_size, 1, &(cur_vars->rd_ptr)) != 0
3974                 || FindEndMarker (cur_vars) != 0)
3975         return -1;
3976
3977     /*
3978      * Parse will return
3979      *    1 when a </> is found,
3980      *    0 if the data runs out before we finish parsing,
3981      *   -1 if errors.
3982      *
3983      * A return of 1 is required from Parse
3984      */
3985     if (1 == Parse (CCDF_TITLE_CMD, NormalState, cur_vars,
3986                         0, _DtCvDYNAMIC,
3987                         fontAttrs, -1, Specials,
3988                         ~(CCDF_TOPIC_CMD | CCDF_TITLE_CMD | CCDF_ABBREV_CMD |
3989                         CCDF_PARAGRAPH_CMD | CCDF_FIGURE_CMD | CCDF_LABEL_CMD),
3990                         False, fnt_flag))
3991       {
3992         /*
3993          * skip the any abbreviation that might be there
3994          */
3995         result = 0;
3996         if (skip_abbrev)
3997             result = _DtHelpCeSkipCcdfAbbrev (cur_vars->my_file,
3998                                 cur_vars->rd_buf,
3999                                 &(cur_vars->rd_ptr), cur_vars->rd_size,
4000                                 cur_vars->cur_mb_max);
4001
4002         /*
4003          * if we successfully skipped the abbreviation and there is
4004          * a title - then attach the title body to the controlling
4005          * container (and make the container a controller).
4006          */
4007         if (result != -1 && cur_vars->my_list.list)
4008           {
4009             _DtCvSegment        *list = oldList.list;
4010             int                  cnt  = oldList.cnt;
4011
4012             TerminateSegList (&(cur_vars->my_list), True);
4013
4014             /*
4015              * when this segment was allocated, it was initialized
4016              * to the correct vertical and horizontal orientation
4017              * for a CCDF title.  Simply set the type to container
4018              * and controller to get it to act properly.
4019              */
4020             if (NULL != list)
4021               {
4022                 list[cnt].type = _DtCvSetTypeToContainer(list[cnt].type);
4023                 if (True == cont_flag)
4024                     list[cnt].type = _DtCvSetTypeToController(list[cnt].type);
4025
4026                 /*
4027                  * attach the title body to the controller container.
4028                  */
4029                 _DtCvContainerListOfSeg(&list[cnt]) = cur_vars->my_list.list;
4030
4031                 /*
4032                  * and count this segment as used.
4033                  */
4034                 oldList.cnt++;
4035               }
4036             /*
4037              * otherwise, a container hasn't been created for this list.
4038              * but we don't want to loose the information.
4039              */
4040             else
4041                 oldList.list = cur_vars->my_list.list;
4042           }
4043       }
4044
4045     /*
4046      * restore segment usage information.
4047      */
4048     cur_vars->my_list = oldList;
4049
4050     return result;
4051 }
4052
4053 /*****************************************************************************
4054  * Function:    int Format (FormatVariables cur_vars, char *id_string,
4055  *
4056  * Parameters:
4057  *
4058  * Returns:
4059  *
4060  * errno Values:
4061  *
4062  * Purpose:     Format is the top entry point for formating Help Files with
4063  *              formatting information into a form understood by a display area.
4064  *              It will keep calling Parse, until the entire topic is read
4065  *              or an error  occurs.
4066  *
4067  *****************************************************************************/
4068 static  int
4069 Format(
4070     FormatVariables     *cur_vars,
4071     _FrmtUiInfo         *ui_info,
4072     char                *id_string,
4073     _DtCvTopicPtr       *ret_topic )
4074 {
4075     int                  cnt;
4076     int                  result  = 0;
4077     int                  done    = 0;
4078     char                *charSet = NULL;
4079     char                 readBuf[BUFF_SIZE];
4080     _DtHelpFontHints     fontAttrs;
4081     _DtCvTopicInfo      *topicHandle;
4082     SegList              myList = InitList;
4083
4084     /*
4085      * malloc space for the topic handle.
4086      */
4087     topicHandle = (_DtCvTopicInfo *) malloc (sizeof(_DtCvTopicInfo));
4088     if (topicHandle == NULL)
4089         return -1;
4090
4091     /*
4092      * initialize the font attributes to the default hints
4093      */
4094     _DtHelpCeCopyDefFontAttrList (&fontAttrs);
4095
4096     /*
4097      * set up the formatting variable structure
4098      */
4099     if (InitStructure (cur_vars, ui_info, readBuf, BUFF_SIZE) == -1)
4100         return -1;
4101
4102     /*
4103      * read the first buffer's worth of the topic.
4104      */
4105     cur_vars->rd_flag = _DtHelpCeReadBuf (cur_vars->my_file, cur_vars->rd_buf,
4106                                                 cur_vars->rd_size);
4107     if (cur_vars->rd_flag == -1)
4108         return -1;
4109
4110     /*
4111      * The first command in the buffer MUST be the <TOPIC> command.
4112      * It is in a one byte charset.
4113      */
4114     if (_DtHelpCeGetCcdfTopicCmd (((void *) NULL), cur_vars->my_file,
4115                         cur_vars->rd_buf, &(cur_vars->rd_ptr),
4116                         cur_vars->rd_size, 1, &charSet) == -1)
4117         return -1;
4118
4119     /*
4120      * change the character set to the returned character set
4121      * Assume that the charset is 'iso8859' if not specified.
4122      */
4123     cur_vars->cur_mb_max = 1;
4124     if (NULL != charSet)
4125         GetMbLen(cur_vars, charSet, &(_DtHelpFontHintsLang(fontAttrs)),
4126                                         &(_DtHelpFontHintsCharSet(fontAttrs)));
4127
4128     /*
4129      * Remember the topic code set and MB_CUR_MAX.
4130      */
4131     cur_vars->topic_char_set = _DtHelpFontHintsCharSet(fontAttrs);
4132     cur_vars->topic_lang     = _DtHelpFontHintsLang(fontAttrs);
4133     cur_vars->topic_mb_max   = cur_vars->cur_mb_max;
4134
4135     /*
4136      * allocate two segments for the topic - one for the <title>
4137      * and one for the body of the topic.
4138      */
4139     if (0 != CheckList(&(cur_vars->my_list), 2, 2))
4140       {
4141         if (NULL != charSet)
4142           {
4143             free(_DtHelpFontHintsLang(fontAttrs));
4144             free(_DtHelpFontHintsCharSet(fontAttrs));
4145             free(charSet);
4146           }
4147         return -1;
4148       }
4149
4150     /*
4151      * get the title and skip the abbreviation.
4152      */
4153     if (0 != ParseTitle(cur_vars, True, True, 0, &fontAttrs))
4154       {
4155         if (NULL != charSet)
4156           {
4157             free(_DtHelpFontHintsLang(fontAttrs));
4158             free(_DtHelpFontHintsCharSet(fontAttrs));
4159             free(charSet);
4160           }
4161         return -1;
4162       }
4163
4164     /*
4165      * remember this current list since we will be attaching any more
4166      * information as a child of these segments.
4167      */
4168     myList = cur_vars->my_list;
4169
4170     /*
4171      * process the rest of the information
4172      */
4173     while (0 == result && !done)
4174       {
4175         /*
4176          * reset the segment count before processing the information
4177          * for this paragraph
4178          */
4179         cur_vars->my_list = InitList;
4180
4181         /*
4182          * make sure we've got a container for this paragraph
4183          */
4184         done = CheckList(&myList, 1, GROW_SIZE);
4185
4186         /*
4187          * now process the information while finding paragraphs.
4188          */
4189         if (0 == done)
4190             do {
4191                 done = Parse (CCDF_PARAGRAPH_CMD, NormalState, cur_vars,
4192                         0, _DtCvDYNAMIC,
4193                         &fontAttrs, -1, Specials,
4194                         ~(CCDF_TOPIC_CMD | CCDF_TITLE_CMD | CCDF_ABBREV_CMD),
4195                         False, 0);
4196             } while (0 == done);
4197
4198         /*
4199          * if no errors, attach the resulting child information to the
4200          * paragraph container.
4201          */
4202         if (done != -1)
4203           {
4204             /*
4205              * clean up the last segment.
4206              */
4207             if (cur_vars->my_list.list)
4208               {
4209                 _DtCvSegment    *list = NextAvailSeg(myList);
4210
4211                 TerminateSegList (&(cur_vars->my_list), True);
4212
4213                 /*
4214                  * make it a container.
4215                  */
4216                 list->type = _DtCvSetTypeToContainer(list->type);
4217
4218                 /*
4219                  * attach the information to the container
4220                  */
4221                 _DtCvContainerListOfSeg(list) = cur_vars->my_list.list;
4222
4223                 /*
4224                  * and count this container as used.
4225                  */
4226                 myList.cnt++;
4227               }
4228           }
4229         else
4230             result = -1;
4231       }
4232
4233     /*
4234      * If we had errors, deallocate the memory.
4235      */
4236     if (result == -1)
4237         _DtHelpFreeSegments(myList.list, _DtCvFALSE, ui_info->destroy_region, 
4238                                                         ui_info->client_data);
4239     else
4240       {
4241         /*
4242          * Tighten up the paragraph structures if too many allocated.
4243          */
4244         if (0 != myList.cnt)
4245             TerminateSegList (&(myList), True);
4246         else
4247           {
4248             free ((char *) myList.list);
4249             myList.list = NULL;
4250           }
4251       }
4252
4253     /*
4254      * return the values, even if they are null and zero.
4255      */
4256
4257     if (id_string == NULL)
4258         topicHandle->id_str = id_string;
4259     else
4260         topicHandle->id_str = strdup(id_string);
4261
4262     topicHandle->seg_list  = myList.list;
4263     topicHandle->mark_list = NULL;
4264     topicHandle->link_data = cur_vars->my_links;
4265
4266     *ret_topic = (void *) topicHandle;
4267
4268     /*
4269      * free memory
4270      */
4271     if (NULL != charSet)
4272       {
4273         free(_DtHelpFontHintsLang(fontAttrs));
4274         free(_DtHelpFontHintsCharSet(fontAttrs));
4275         free(charSet);
4276       }
4277
4278     if (result == -1)
4279         return -1;
4280
4281     return 0;
4282 }
4283
4284 /*****************************************************************************
4285  * Function:    int FormatCCDFTitle (FormatVariables cur_vars
4286  *
4287  * Parameters:
4288  *              cur_vars        Specifies the current values for formatting.
4289  *              id_string       Specifies the id to look for or NULL.
4290  *              ret_para        Returns a pointer to a list of _DtCvSegment
4291  *                              structures.
4292  *              ret_num         Specifies the number of structures in
4293  *                              'ret_para'.
4294  *              ret_seg         Specifies the segment containing 'id_string'
4295  *                              or NULL.
4296  *
4297  * Returns:
4298  *
4299  * errno Values:
4300  *
4301  * Purpose:     Format is the top entry point for formating Help Files with
4302  *              formatting information into a form understood by a display area.
4303  *              It will keep calling Parse, until the entire topic is read
4304  *              or an error  occurs.
4305  *
4306  *****************************************************************************/
4307 static  int
4308 FormatCCDFTitle(
4309     FormatVariables     *cur_vars,
4310     _DtHelpFontHints     fontAttrs,
4311     char                *filename,
4312     int                  offset,
4313     int                  level,
4314     int                  fnt_flags,
4315     int                  want_abbrev)
4316 {
4317     char    *strPtr;
4318     char    *charSet   = NULL;
4319     int      result    = 0;
4320     int      origCnt   = cur_vars->my_list.cnt;
4321     int      len;
4322     _DtCvSegment        *titleSeg;
4323     _DtCvSegment        *list;
4324
4325     cur_vars->rd_buf[0] = '\0';
4326     cur_vars->rd_ptr    = cur_vars->rd_buf;
4327
4328     if (_DtHelpCeFileOpenAndSeek(filename, offset, -1,
4329                                         &(cur_vars->my_file), NULL) != 0)
4330         return -1;
4331
4332     cur_vars->rd_flag = _DtHelpCeReadBuf (cur_vars->my_file, cur_vars->rd_buf,
4333                                                 cur_vars->rd_size);
4334
4335     if (cur_vars->rd_flag == -1)
4336       {
4337         _DtHelpCeBufFileClose (cur_vars->my_file, True);
4338         return -1;
4339       }
4340
4341     /*
4342      * The first command in the buffer MUST be the <TOPIC> command.
4343      * It is in a one byte charset.
4344      */
4345     if (_DtHelpCeGetCcdfTopicCmd (((void *) NULL), cur_vars->my_file,
4346                         cur_vars->rd_buf, &(cur_vars->rd_ptr),
4347                         cur_vars->rd_size, 1, &charSet) == -1)
4348       {
4349         _DtHelpCeBufFileClose (cur_vars->my_file, True);
4350         return -1;
4351       }
4352
4353     /*
4354      * change the character set to the returned character set
4355      * Assume that the charset is 'iso8859' if not specified.
4356      */
4357     cur_vars->cur_mb_max = 1;
4358     if (NULL != charSet)
4359         GetMbLen(cur_vars, charSet, &(_DtHelpFontHintsLang(fontAttrs)),
4360                                         &(_DtHelpFontHintsCharSet(fontAttrs)));
4361
4362     /*
4363      * Remember the topic code set and MB_CUR_MAX.
4364      */
4365     cur_vars->topic_char_set = _DtHelpFontHintsCharSet(fontAttrs);
4366     cur_vars->topic_lang     = _DtHelpFontHintsLang(fontAttrs);
4367     cur_vars->topic_mb_max   = cur_vars->cur_mb_max;
4368
4369     /*
4370      * allocate another segment for this title.
4371      */
4372     if (0 != CheckSegList(cur_vars))
4373       {
4374         if (NULL != charSet)
4375           {
4376             free(_DtHelpFontHintsLang(fontAttrs));
4377             free(_DtHelpFontHintsCharSet(fontAttrs));
4378             free(charSet);
4379           }
4380         _DtHelpCeBufFileClose(cur_vars->my_file, True);
4381         return -1;
4382       }
4383
4384     /*
4385      * set the left margin correctly.
4386      */
4387     titleSeg  = NextAvailSeg(cur_vars->my_list);
4388     titleSeg->handle.container = DefContainer;
4389     titleSeg->type = _DtCvSetTypeToContainer(titleSeg->type);
4390     _DtCvContainerLMarginOfSeg(titleSeg) = level*2*cur_vars->ui_info->avg_char;
4391     _DtCvContainerBMarginOfSeg(titleSeg) = 0;
4392     _DtCvContainerTypeOfSeg(titleSeg)    = _DtCvLITERAL;
4393     _DtCvContainerLeadingOfSeg(titleSeg) = cur_vars->ui_info->leading;
4394
4395     /*
4396      * Parse the title.
4397      */
4398     if (-1 == ParseTitle(cur_vars, False, False, fnt_flags, &fontAttrs))
4399       {
4400         if (NULL != charSet)
4401           {
4402             free(_DtHelpFontHintsLang(fontAttrs));
4403             free(_DtHelpFontHintsCharSet(fontAttrs));
4404             free(charSet);
4405           }
4406         _DtHelpCeBufFileClose(cur_vars->my_file, True);
4407         return -1;
4408       }
4409
4410     /*
4411      * We've parsed the title. see if we want the abbrev.
4412      */
4413     /*
4414      * if the title is null or we want the abbrev,
4415      * process the abbreviation.
4416      */
4417     if (NULL == _DtCvContainerListOfSeg(titleSeg) || want_abbrev)
4418       {
4419         SegList titleList = cur_vars->my_list;
4420
4421         /*
4422          * reset the buffer to get the abbreviation
4423          */
4424         if (cur_vars->fmt_buf != NULL)
4425           {
4426             free(cur_vars->fmt_buf);
4427             cur_vars->fmt_buf     = NULL;
4428             cur_vars->fmt_size    = 0;
4429             cur_vars->fmt_buf_max = 0;
4430           }
4431
4432         result = _DtHelpCeGetCcdfAbbrevCmd (cur_vars->my_file, cur_vars->rd_buf,
4433                                 cur_vars->rd_size, cur_vars->cur_mb_max,
4434                                 &(cur_vars->rd_ptr), &(cur_vars->fmt_buf));
4435
4436         /*
4437          * If no errors getting the abbreviation, save it
4438          */
4439         if (result != -1)
4440           {
4441             /*
4442              * save the abbreviation
4443              */
4444             if (cur_vars->fmt_buf != NULL)
4445               {
4446                 /*
4447                  * If there was a title, free it
4448                  */
4449                 if (NULL != _DtCvContainerListOfSeg(titleSeg))
4450                     _DtHelpFreeSegments(_DtCvContainerListOfSeg(titleSeg),
4451                                         _DtCvFALSE, 
4452                                         cur_vars->ui_info->destroy_region,
4453                                                 cur_vars->ui_info->client_data);
4454
4455                 /*
4456                  * save the abbreviation
4457                  */
4458                 cur_vars->my_list      = InitList;
4459                 cur_vars->fmt_size     = strlen (cur_vars->fmt_buf);
4460                 cur_vars->fmt_buf_max  = cur_vars->fmt_size + 1;
4461                 if (cur_vars->fmt_size > 0)
4462                     result = SaveStringAsSegments (cur_vars, 0, &fontAttrs, -1);
4463
4464                 if (result != -1)
4465                     TerminateSegList(&(cur_vars->my_list), True);
4466
4467                 titleSeg->type = _DtCvSetTypeToContainer(titleSeg->type);
4468                 _DtCvContainerListOfSeg(titleSeg) = cur_vars->my_list.list;
4469                 titleList.cnt++;
4470               }
4471           }
4472
4473         /*
4474          * eliminate this segment if no title or abbrev was found.
4475          */
4476         if (NULL == _DtCvContainerListOfSeg(titleSeg))
4477           {
4478             titleList.cnt = origCnt;
4479             _DtCvContainerTypeOfSeg(titleSeg) = _DtCvDYNAMIC;
4480           }
4481
4482         /*
4483          * reset the title list
4484          */
4485         cur_vars->my_list = titleList;
4486       }
4487     else
4488         result = _DtHelpCeSkipCcdfAbbrev (cur_vars->my_file, cur_vars->rd_buf,
4489                                 &(cur_vars->rd_ptr), cur_vars->rd_size,
4490                                 cur_vars->cur_mb_max);
4491
4492     if (cur_vars->fmt_buf != NULL)
4493         cur_vars->fmt_buf[0] = '\0';
4494     cur_vars->fmt_size     = 0;
4495
4496     /*
4497      * remove the newline from the lists and
4498      * change all the newlines on the segments into a space.
4499      */
4500     for (list = _DtCvContainerListOfSeg(titleSeg);
4501                                         NULL != list; list = list->next_seg)
4502       {
4503         if (_DtCvIsSegNewLine(list))
4504           {
4505             /*
4506              * clear the newline flag.
4507              */
4508             list->type &= ~(_DtCvNEW_LINE);
4509
4510             /*
4511              * check to see if the last character of this segment or
4512              * the first character of the next segment is a space.
4513              * if not, add one.
4514              */
4515             if (NULL != list->next_disp && _DtCvIsSegString(list)
4516                                                 && _DtCvIsSegRegChar(list))
4517               {
4518                 /*
4519                  * is the last character of the string a space?
4520                  * if so do nothing.
4521                  */
4522                 len = strlen((char *) _DtCvStringOfStringSeg(list)) - 1;
4523                 if (' ' != ((char *) _DtCvStringOfStringSeg(list))[len])
4524                   {
4525                     /*
4526                      * is the next segment a one byte string?
4527                      * and if so, is the first character a space?
4528                      * if so, do nothing.
4529                      */
4530                     if (_DtCvIsSegString(list->next_disp)
4531                         && _DtCvIsSegRegChar(list->next_disp)
4532                         && ' ' != *((char *)_DtCvStringOfStringSeg(list->next_disp)))
4533                       {
4534                         /*
4535                          * need to add a space to one of these strings.
4536                          */
4537                         len += 3;
4538                         _DtCvStringOfStringSeg(list) = (char *) realloc(
4539                                         (void *) _DtCvStringOfStringSeg(list),
4540                                         sizeof(char *) * len);
4541                         if (NULL == _DtCvStringOfStringSeg(list))
4542                             return -1;
4543
4544                         strPtr = (char *) _DtCvStrPtr(
4545                                                 _DtCvStringOfStringSeg(list),
4546                                                 0,
4547                                                 len - 3);
4548                         *strPtr++ = ' ';
4549                         *strPtr   = '\0';
4550                       }
4551                   }
4552               }
4553           }
4554       }
4555
4556     _DtHelpCeBufFileClose (cur_vars->my_file, True);
4557
4558     /*
4559      * free memory
4560      */
4561     if (NULL != charSet)
4562       {
4563         free(_DtHelpFontHintsLang(fontAttrs));
4564         free(_DtHelpFontHintsCharSet(fontAttrs));
4565         free(charSet);
4566       }
4567
4568     if (result == -1)
4569         return -1;
4570
4571     return 0;
4572 }
4573
4574 /******************************************************************************
4575  * Function:    int FormatEntryInToc (
4576  *
4577  * Parameters:
4578  *
4579  * Returns:     0 if successful, -1 if errors
4580  *
4581  * errno Values:
4582  *
4583  * Purpose:
4584  *
4585  ******************************************************************************/
4586 static int
4587 FormatEntryInToc(
4588     _DtHelpVolumeHdl      volume,
4589     char                 *loc_id,
4590     FormatVariables      *cur_vars,
4591     _DtHelpFontHints      font_attrs,
4592     int                   level)
4593 {
4594     int           result    = -1;
4595     int           tocLen    = 0;
4596     int           offset;
4597     int           num;
4598     char         *strPtr = NULL;
4599     _DtCvSegment *pSeg;
4600     _DtCvSegment *titleSeg;
4601     SegList       titleList;
4602
4603     /*
4604      * check to see that there is a segment for this title.
4605      */
4606     if (0 != CheckSegList(cur_vars))
4607         return -1;
4608
4609     /*
4610      * The next segment in the list will become the next title.
4611      * Get a pointer to it for later use.
4612      */
4613     titleList = cur_vars->my_list;
4614     titleSeg  = NextAvailSeg(titleList);
4615     titleSeg->handle.container = DefContainer;
4616     titleSeg->type = _DtCvSetTypeToContainer(titleSeg->type);
4617     _DtCvContainerBMarginOfSeg(titleSeg) = 0;
4618     _DtCvContainerLeadingOfSeg(titleSeg) = cur_vars->ui_info->leading;
4619
4620     /*
4621      * Get the file and offset for the topic.
4622      * and process the topic's title, ignoring most font changes.
4623      */
4624     if (True == _DtHelpCeFindId(volume, loc_id, -1, &strPtr, &offset) &&
4625         -1 != FormatCCDFTitle(cur_vars, font_attrs, strPtr, offset, level,
4626   ((1<<_CEFONT_SIZE)|(1<<_CEFONT_WEIGHT)|(1<<_CEFONT_ANGLE)|(1<<_CEFONT_TYPE)),
4627                                     False))
4628       {
4629         /*
4630          * now create the hypertext link index for the ghostlink.
4631          */
4632         num    = _DtLinkDbAddLink(cur_vars->my_links, NULL, loc_id,
4633                                             _DtCvLinkType_SameVolume,
4634                                             _DtCvWindowHint_CurrentWindow,
4635                                             NULL);
4636         /*
4637          * if a link index was successfully created, process the item.
4638          */
4639         if (num != -1)
4640           {
4641             result = 0;
4642
4643             /*
4644              * check to see if this title had any segments.
4645              */
4646             pSeg = _DtCvContainerListOfSeg(titleSeg);
4647             if (NULL != pSeg)
4648               {
4649                 while (NULL != pSeg)
4650                   {
4651                     /*
4652                      * If this segment has a hypertext link, remove it.
4653                      */
4654                     if (pSeg->link_idx != -1)
4655                         _DtLinkDbRemoveLink(cur_vars->my_links, pSeg->link_idx);
4656     
4657                     /*
4658                      * change the link index and flag to the ghost link.
4659                      */
4660                     pSeg->link_idx  = num;
4661                     pSeg->type     &= ~(_DtCvHYPER_TEXT);
4662                     pSeg->type      = _DtCvSetTypeToGhostLink(pSeg->type);
4663
4664                     /*
4665                      * go to the next segment.
4666                      */
4667                     pSeg = pSeg->next_seg;
4668                   }
4669               }
4670             else
4671               {
4672                 /*
4673                  * no title or abbreviation, so use the location id.
4674                  * allocate room for it and put it between parens.
4675                  */
4676                 tocLen = strlen (loc_id) + 9;
4677                 if (tocLen > cur_vars->fmt_buf_max)
4678                   {
4679                     if (NULL == cur_vars->fmt_buf)
4680                         cur_vars->fmt_buf = (char *) malloc (tocLen);
4681                     else
4682                         cur_vars->fmt_buf = (char *) realloc(
4683                                             cur_vars->fmt_buf,
4684                                             tocLen);
4685                     cur_vars->fmt_buf_max = tocLen;
4686                   }
4687     
4688                 cur_vars->fmt_size = tocLen - 1;
4689                 strcpy (cur_vars->fmt_buf, "...(");
4690                 strcat (cur_vars->fmt_buf, loc_id);
4691                 strcat (cur_vars->fmt_buf, ")...");
4692     
4693                 /*
4694                  * don't overwrite the title's
4695                  */
4696                 cur_vars->my_list = InitList;
4697
4698                 /*
4699                  * save the string off and then attach to the title
4700                  * container.
4701                  */
4702                 result = SaveStringAsSegments(cur_vars, _DtCvGHOST_LINK,
4703                                                         &font_attrs, num);
4704                 if (-1 != result)
4705                     _DtCvContainerListOfSeg(titleSeg) = cur_vars->my_list.list;
4706
4707                 /*
4708                  * restore the title list.
4709                  */
4710                 cur_vars->my_list = titleList;
4711               }
4712           }
4713       }
4714
4715    if (NULL != strPtr)
4716        free(strPtr);
4717
4718    return result;
4719
4720 }  /* End FormatEntryInToc */
4721
4722 /******************************************************************************
4723  * Function:    int FormatExpandToc (
4724  *                              _DtHelpVolumeHdl volume,
4725  *
4726  * Purpose:
4727  ******************************************************************************/
4728 static int
4729 FormatExpandedToc(
4730     _DtHelpVolumeHdl      volume,
4731     char                  *cur_id,
4732     char                 **path_lst,
4733     FormatVariables      *cur_vars,
4734     _DtHelpFontHints      font_attrs,
4735     int                   level)
4736 {
4737     int    result = 0;
4738
4739     if (*path_lst != NULL)
4740       {
4741         font_attrs.weight = _DtHelpFontWeightMedium;
4742         if (_DtCvStrCaseCmpLatin1(*path_lst, cur_id) == 0)
4743             font_attrs.weight = _DtHelpFontWeightBold;
4744
4745         result = FormatEntryInToc(volume, *path_lst, cur_vars,
4746                                 font_attrs, level);
4747
4748         if (result != -1)
4749           {
4750             char **children;
4751             char **childLst;
4752             int    count = _DtHelpCeGetCcdfTopicChildren(volume,
4753                                                         *path_lst, &children);
4754
4755             /*
4756              * if there are children, format them
4757              */
4758             level++;
4759             path_lst++;
4760             childLst = children;
4761             font_attrs.weight = _DtHelpFontWeightMedium;
4762             while (result != -1 && count > 0)
4763               {
4764                 /*
4765                  * found the next item in the list
4766                  */
4767                 if (*path_lst != NULL &&
4768                         _DtCvStrCaseCmpLatin1(*path_lst, *childLst) == 0)
4769                     result = FormatExpandedToc(volume,
4770                                         cur_id, path_lst,
4771                                         cur_vars, font_attrs, level);
4772                 else
4773                     result = FormatEntryInToc(volume, *childLst,
4774                                         cur_vars, font_attrs, level);
4775
4776                 childLst++;
4777                 count--;
4778               }
4779
4780             if (children != NULL)
4781                 _DtCvFreeArray((void **) children);
4782           }
4783       }
4784
4785     return result;
4786 }
4787
4788 /******************************************************************************
4789  *
4790  * Semi-Public Functions
4791  *
4792  *****************************************************************************/
4793 /******************************************************************************
4794  * Function:    VarHandle *__DtHelpCeSetUpVars (char *rd_buf, grow_size)
4795  *
4796  * Parameters:
4797  *
4798  * Returns:     NULL if unsuccessful.
4799  *
4800  * errno Values:
4801  *
4802  * Purpose:     
4803  *
4804  ******************************************************************************/
4805 VarHandle
4806 __DtHelpCeSetUpVars(
4807     char        *lang,
4808     char        *code_set,
4809     _FrmtUiInfo *ui_info)
4810 {
4811     FormatVariables    *newVars;
4812
4813     newVars = (FormatVariables *) malloc (sizeof(FormatVariables));
4814     *newVars = DefVars;
4815     newVars->ui_info = ui_info;
4816
4817     newVars->topic_mb_max = _DtHelpCeGetMbLen(lang, code_set);
4818     newVars->cur_mb_max   = newVars->topic_mb_max;
4819
4820     return ((VarHandle) newVars);
4821
4822 }  /* End __DtHelpCeSetUpVars */
4823
4824 /******************************************************************************
4825  * Function:    int __DtHelpCeProcessString (char *in_string, int seg_type,
4826  *                                              char **font_attr)
4827  *
4828  * Parameters:
4829  *
4830  * Returns:     0 if successful, -1 if errors.
4831  *
4832  * errno Values:
4833  *
4834  * Purpose:     
4835  *
4836  ******************************************************************************/
4837 int
4838 __DtHelpCeProcessString(
4839     VarHandle            var_handle,
4840     BufFilePtr           my_file,
4841     _DtCvFrmtOption      frmt_type,
4842     char                *scan_string,
4843     char                *in_string,
4844     int                  in_size,
4845     int                  fnt_flag,
4846     int                  ret_on_nl,
4847     _DtHelpFontHints    *font_attr )
4848 {
4849     int                  done = 0;
4850     FormatVariables     *myVars = (FormatVariables *) var_handle;
4851     SegList              oldList = myVars->my_list;
4852
4853     myVars->rd_buf  = in_string;
4854     myVars->rd_size = in_size;
4855     myVars->rd_ptr  = in_string;
4856     myVars->my_file = my_file;
4857
4858     if (my_file == NULL)
4859         myVars->rd_flag = 0;
4860     else
4861         myVars->rd_flag = strlen(in_string);
4862
4863     while (!done)
4864       {
4865         if (True == ret_on_nl)
4866             myVars->my_list = InitList;
4867
4868         done = Parse (CCDF_FONT_CMD, NormalState, myVars,
4869                 0, frmt_type,
4870                 font_attr,
4871                 -1, scan_string, (CCDF_FONT_CMD | CCDF_OCTAL_CMD), ret_on_nl,
4872                 fnt_flag);
4873
4874         if (done != -1 && True == ret_on_nl)
4875           {
4876             TerminateSegList (&(myVars->my_list), True);
4877             if (NULL != myVars->my_list.list)
4878               {
4879                 done = CheckList (&oldList, 1, GROW_SIZE);
4880                 if (-1 != done)
4881                   {
4882                     _DtCvSegment *newSeg = NextAvailSeg(oldList);
4883
4884                     newSeg->type = _DtCvSetTypeToContainer(newSeg->type);
4885                     _DtCvContainerListOfSeg(newSeg) = myVars->my_list.list;
4886                     _DtCvContainerTypeOfSeg(newSeg) = _DtCvDYNAMIC;
4887
4888                     oldList.cnt++;
4889
4890                     TerminateSegList(&oldList, False);
4891                   }
4892               }
4893           }
4894       }
4895
4896     if (False == ret_on_nl)
4897         oldList = myVars->my_list;
4898
4899     myVars->my_list = oldList;
4900     return done;
4901
4902 }  /* End __DtHelpCeProcessString */
4903
4904 /*****************************************************************************
4905  * Function:    int __DtHelpCeGetParagraphList (
4906  *
4907  * Parameters:
4908  *
4909  * Returns:     0 if successful, -1 if errors.
4910  *
4911  * errno Values:
4912  *
4913  * Purpose:     _DtHelpFormatGetParagraphList places a terminator on the
4914  *              last segment in the current paragraph and returns the
4915  *              segment list included in the topic information structure.
4916  *
4917  *              If make_cont is true, the segment list is first included
4918  *              in a container with the specified type.
4919  *
4920  *****************************************************************************/
4921 int
4922 __DtHelpCeGetParagraphList (
4923     VarHandle            var_handle,
4924     int                  make_cont,
4925     _DtCvFrmtOption      type,
4926     _DtCvTopicPtr       *ret_handle)
4927 {
4928     int                  result = -1;
4929     FormatVariables     *myVars = (FormatVariables *) var_handle;
4930     _DtCvTopicInfo      *topicHandle;
4931
4932     /*
4933      * check the parameters.
4934      */
4935     if (ret_handle == NULL || myVars == NULL)
4936       {
4937         errno = EINVAL;
4938         return -1;
4939       }
4940
4941     TerminateSegList(&(myVars->my_list), True);
4942
4943     topicHandle = (_DtCvTopicInfo *) malloc (sizeof(_DtCvTopicInfo));
4944     if (topicHandle != NULL)
4945       {
4946         result = 0;
4947
4948         if (True == make_cont)
4949           {
4950             _DtCvSegment *myCont = AllocateSegments(NULL, 0, 1);
4951
4952             if (NULL != myCont)
4953               {
4954                 myCont->type = _DtCvSetTypeToContainer(myCont->type);
4955                 _DtCvContainerTypeOfSeg(myCont) = type;
4956                 _DtCvContainerListOfSeg(myCont) = myVars->my_list.list;
4957
4958                 myVars->my_list.list = myCont;
4959                 myVars->my_list.cnt  = 1;
4960                 myVars->my_list.max  = 1;
4961              }
4962             else
4963                 result = -1;
4964           }
4965
4966         topicHandle->id_str    = NULL;
4967         topicHandle->seg_list  = myVars->my_list.list;
4968         topicHandle->mark_list = NULL;
4969         topicHandle->link_data = myVars->my_links;
4970
4971         *ret_handle = (_DtCvTopicPtr) topicHandle;
4972       }
4973
4974     if (myVars->fmt_buf != NULL)
4975         free(myVars->fmt_buf);
4976
4977     return result;
4978 }
4979
4980 /******************************************************************************
4981  * Function:    int _DtHelpCeFrmtCcdfTopic (_DtHelpVolumeHdl volume, char *filename,
4982  *                              int offset, char *id_string,
4983  *                              _DtCvTopicPtr *ret_handle)
4984  *
4985  * Parameters:
4986  *              volume          Specifies the Help Volume the information
4987  *                              is associated with.
4988  *              filename        Specifies the file containing the Help Topic
4989  *                              desired.
4990  *              offset          Specifies the offset into 'filename' to
4991  *                              the Help Topic desired.
4992  *              id_string       Specifies the location id to look for or NULL.
4993  *              ret_handle      Returns a handle to the topic information
4994  *                              including the number of paragraphs and the
4995  *                              id match segment.
4996  *
4997  * Returns:     0 if successful, -1 if errors
4998  *
4999  * errno Values:
5000  *
5001  * Purpose:     _DtHelpCeFrmtCcdfTopic formats Help Files with formatting
5002  *              information into a Canvas Engine structure.
5003  *
5004  ******************************************************************************/
5005 int
5006 _DtHelpCeFrmtCcdfTopic(
5007     _DtHelpVolumeHdl     volume,
5008     char                *filename,
5009     int                  offset,
5010     char                *id_string,
5011     _FrmtUiInfo         *ui_info,
5012     _DtCvTopicPtr       *ret_handle )
5013 {
5014     int          result = -1;
5015     char        *ptr;
5016     FormatVariables     variables;
5017
5018     /*
5019      * Check the parameters
5020      */
5021     if (volume == NULL || filename == NULL || offset < 0 || ret_handle == NULL)
5022       {
5023         errno = EINVAL;
5024         return -1;
5025       }
5026
5027     /*
5028      * get the current file path.
5029      */
5030     variables = DefVars;
5031     variables.topic_id = id_string;
5032     if (volume)
5033       {
5034         variables.vol_name = _DtHelpCeGetVolumeName(volume);
5035         variables.my_path  = strdup (variables.vol_name);
5036         if (variables.my_path == NULL)
5037             return -1;
5038
5039         result = _DtHelpCeStrrchr (variables.my_path, Slash, MB_CUR_MAX, &ptr);
5040         if (result == -1)
5041             ptr = strrchr (variables.my_path, '/');
5042
5043         if (ptr)
5044             *ptr = '\0';
5045       }
5046
5047     /*
5048      * open the file and seek to the correct place.
5049      */
5050     result = _DtHelpCeFileOpenAndSeek (filename, offset, -1,
5051                                                 &(variables.my_file), NULL);
5052     if (result != -1)
5053       {
5054         /*
5055          * Initialize the X variables.
5056          */
5057         result = Format (&variables, ui_info, id_string, ret_handle);
5058
5059         _DtHelpCeBufFileClose (variables.my_file, True);
5060       }
5061
5062     if (variables.fmt_buf != NULL)
5063         free (variables.fmt_buf);
5064
5065     if (variables.my_path != NULL)
5066         free (variables.my_path);
5067
5068     return result;
5069
5070 }  /* End _DtHelpCeFrmtCcdfTopic */
5071
5072 /******************************************************************************
5073  * Function:    int _DtHelpCeFrmtCcdfPathAndChildren (
5074  *                              _DtHelpVolumeHdl volume,
5075  *                              _DtCvTopicPtr *ret_handle)
5076  *
5077  * Parameters:
5078  *              ret_handle      Returns a handle to the topic information
5079  *                              including the number of paragraphs and the
5080  *                              id match segment.
5081  *
5082  * Returns:     0 if successful, -1 if errors, 1 if there the path is empty.
5083  *
5084  * errno Values:
5085  *
5086  * Purpose:     _DtHelpCeFormatCcdfToc formats Table of Contents for
5087  *              a CCDF Help File.
5088  *
5089  ******************************************************************************/
5090 int
5091 _DtHelpCeFrmtCcdfPathAndChildren(
5092     _DtHelpVolumeHdl      volume,
5093     char                 *loc_id,
5094     _FrmtUiInfo          *ui_info,
5095     _DtCvTopicPtr        *ret_handle )
5096 {
5097     int           result    = 0;
5098     int           pathCnt;
5099     char         *ptr;
5100     char        **pathHead;
5101     char          readBuf[BUFF_SIZE];
5102     FormatVariables     myVars;
5103     _DtHelpFontHints    fontAttrs;
5104
5105     _DtHelpCeCopyDefFontAttrList (&fontAttrs);
5106     fontAttrs.pointsz = 10;
5107     fontAttrs.weight  = _DtHelpFontWeightMedium;
5108     fontAttrs.style   = _DtHelpFontStyleSanSerif;
5109
5110     /*
5111      * Check the parameters
5112      */
5113     if (volume == NULL || ret_handle == NULL)
5114       {
5115         errno = EINVAL;
5116         return -1;
5117       }
5118
5119     readBuf[0] = '\0';
5120     myVars     = DefVars;
5121     if (InitStructure (&myVars, ui_info, readBuf, BUFF_SIZE) == -1)
5122         return -1;
5123
5124     /*
5125      * get the list of topics in the volume.
5126      */
5127     pathCnt = _DtHelpCeGetCcdfIdPath(volume, loc_id, &pathHead);
5128     if (pathCnt == -1)
5129         return -1;
5130
5131     /*
5132      * Check to see if this topic is in the topic list.
5133      * I.e. if a count of 1 is returned this should match the
5134      * top topic, otherwise this is an hidden topic.
5135      */
5136     if (pathCnt == 1)
5137       {
5138         if (_DtHelpCeGetCcdfTopTopic(volume, &ptr) == -1)
5139             result = -1;
5140         else if (_DtCvStrCaseCmpLatin1(ptr, *pathHead) != 0)
5141             result = 1;
5142       }
5143
5144     /*
5145      * if result is non-zero, we had problems or this is a hidden topic
5146      */
5147     if (result == 0)
5148       {
5149         fontAttrs.slant   = _DtHelpFontSlantRoman;
5150
5151         myVars.topic_id = loc_id;
5152         myVars.vol_name = _DtHelpCeGetVolumeName(volume);
5153         myVars.my_path  = strdup (myVars.vol_name);
5154         if (myVars.my_path == NULL)
5155             return -1;
5156
5157         if (-1 == _DtHelpCeStrrchr (myVars.my_path, Slash, MB_CUR_MAX, &ptr))
5158             ptr = strrchr (myVars.my_path, '/');
5159
5160         if (ptr)
5161             *ptr = '\0';
5162
5163         result = FormatExpandedToc(volume, loc_id, pathHead,
5164                                                 &myVars, fontAttrs, 0);
5165         _DtCvFreeArray((void **) pathHead);
5166       }
5167
5168     if (result != -1)
5169         result = __DtHelpCeGetParagraphList (&myVars, False, _DtCvDYNAMIC,
5170                                                                 ret_handle);
5171
5172     /*
5173      * check for an empty path.
5174      */
5175     if (-1 != result && NULL == ((_DtCvTopicInfo *) *ret_handle)->seg_list)
5176         result = 1;
5177
5178     if (myVars.my_path != NULL)
5179         free(myVars.my_path);
5180
5181     return result;
5182
5183 }  /* End _DtHelpCeFrmtCcdfPathAndChildren */
5184
5185 /******************************************************************************
5186  * Function:    int _DtHelpCeGetCcdfTitleChunks (
5187  *                              _DtHelpVolumeHdl volume,
5188  *                              _DtCvTopicPtr *ret_handle)
5189  *
5190  * Parameters:
5191  *              ret_handle      Returns a handle to the topic information
5192  *                              including the number of paragraphs and the
5193  *                              id match segment.
5194  *
5195  * Returns:     0 if successful, -1 if errors
5196  *
5197  * errno Values:
5198  *
5199  * Purpose:     _DtHelpCeFormatCcdfToc formats Table of Contents for
5200  *              a CCDF Help File.
5201  *
5202  ******************************************************************************/
5203 int
5204 _DtHelpCeGetCcdfTitleChunks(
5205     _DtHelpVolumeHdl       volume,
5206     char                  *loc_id,
5207     _FrmtUiInfo           *ui_info,
5208     void                ***ret_chunks)
5209 {
5210     int           type   = 0;
5211     int           result = 0;
5212     int           offset;
5213     char         *fileName;
5214     char         *ptr;
5215     char          readBuf[BUFF_SIZE];
5216     _DtCvSegment        *titleSeg;
5217     _DtCvSegment        *list    = NULL;
5218     FormatVariables     myVars;
5219     _DtHelpFontHints    fontAttrs;
5220     _DtHelpCeLockInfo lockInfo;
5221
5222     /*
5223      * Check the parameters
5224      */
5225     if (volume == NULL || ret_chunks == NULL)
5226       {
5227         errno = EINVAL;
5228         return -1;
5229       }
5230
5231     /*
5232      * init the return value
5233      */
5234     *ret_chunks = NULL;
5235
5236     /*
5237      * get the topic in the volume.
5238      */
5239     if (_DtHelpCeLockVolume(volume, &lockInfo) != 0)
5240         return -1;
5241
5242     if (_DtHelpCeFindId(volume, loc_id, -1, &fileName, &offset) == False)
5243       {
5244         _DtHelpCeUnlockVolume(lockInfo);
5245         return -1;
5246       }
5247
5248     _DtHelpCeCopyDefFontAttrList (&fontAttrs);
5249     myVars = DefVars;
5250     if (InitStructure (&myVars, ui_info, readBuf, BUFF_SIZE) == -1)
5251       {
5252         _DtHelpCeUnlockVolume(lockInfo);
5253         return -1;
5254       }
5255
5256     /*
5257      * initialize my variables.
5258      */
5259     myVars.topic_id = loc_id;
5260     myVars.vol_name = _DtHelpCeGetVolumeName(volume);
5261     myVars.my_path  = strdup (myVars.vol_name);
5262     if (myVars.my_path == NULL)
5263       {
5264         _DtHelpCeUnlockVolume(lockInfo);
5265         return -1;
5266       }
5267
5268     if (-1 == _DtHelpCeStrrchr (myVars.my_path, Slash, MB_CUR_MAX, &ptr))
5269         ptr = strrchr (myVars.my_path, '/');
5270
5271     if (ptr)
5272         *ptr = '\0';
5273
5274     result = FormatCCDFTitle(&myVars, fontAttrs, fileName,
5275                                 offset, 0, (1 << _CEFONT_SIZE), True);
5276     free(fileName);
5277
5278     if (-1 != result && 0 < myVars.my_list.cnt)
5279       {
5280         titleSeg = &(myVars.my_list.list[myVars.my_list.cnt - 1]);
5281         list     = _DtCvContainerListOfSeg(titleSeg);
5282       }
5283
5284     if (result != -1 && NULL != list)
5285       {
5286         _DtCvSegment *pSeg = list;
5287
5288         while (-1 != result && NULL != pSeg)
5289           {
5290             /*
5291              * create the types and add the informatio to the array.
5292              */
5293             type = DT_HELP_CE_FONT_PTR | DT_HELP_CE_STRING;
5294             if (_DtCvIsSegNewLine(pSeg))
5295                 type |= DT_HELP_CE_NEWLINE;
5296
5297             if (_DtCvIsSegString(pSeg))
5298               {
5299                 *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5300                                         (void *) type);
5301                 if (NULL != *ret_chunks)
5302                     *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5303                                         (void *) _DtCvFontOfStringSeg(pSeg));
5304
5305                 if (NULL != *ret_chunks)
5306                   {
5307                     if (_DtCvIsSegWideChar(pSeg))
5308                       {
5309                         offset = _DtCvStrLen(_DtCvStringOfStringSeg(pSeg), 1)
5310                                         * MB_CUR_MAX + 1;
5311                         ptr    = (char *) malloc (sizeof(char) * offset);
5312                         if (NULL != ptr)
5313                             wcstombs(ptr,
5314                                         (wchar_t *)_DtCvStringOfStringSeg(pSeg),
5315                                         offset);
5316                       }
5317                     else
5318                         ptr = strdup((char *) _DtCvStringOfStringSeg(pSeg));
5319
5320                     if (NULL != ptr)
5321                         *ret_chunks = (void **)_DtCvAddPtrToArray(
5322                                         *ret_chunks, (void *) ptr);
5323                   }
5324
5325                 if (NULL == *ret_chunks || NULL == ptr)
5326                     result = -1;
5327               }
5328
5329             /*
5330              * go to the next segment
5331              */
5332             pSeg = pSeg->next_seg;
5333           }
5334       }
5335     else
5336       {
5337         char  buf[128];
5338         char *idStr;
5339         int   idLen = strlen (loc_id) + 9;
5340
5341         /*
5342          * create the location id string.
5343          */
5344         idStr  = (char *) malloc (idLen);
5345         if (NULL != idStr)
5346           {
5347             /*
5348              * format the location id
5349              */
5350             strcpy (idStr, "...(");
5351             strcat (idStr, loc_id);
5352             strcat (idStr, ")...");
5353         
5354             /*
5355              * format the language and codeset
5356              */
5357             strcpy(buf, _DtHelpFontHintsLang(fontAttrs));
5358             strcat(buf, ".");
5359             strcpy(buf, _DtHelpFontHintsCharSet(fontAttrs));
5360
5361             /*
5362              * creat a chunk table
5363              */
5364             *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5365                         (void *) (DT_HELP_CE_CHARSET | DT_HELP_CE_STRING));
5366             if (NULL != *ret_chunks)
5367                 *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5368                                                 (void *) strdup(buf));
5369             if (NULL != *ret_chunks)
5370                 *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5371                                                 (void *) idStr);
5372           }
5373       }
5374
5375     if (NULL != *ret_chunks)
5376         *ret_chunks = (void **) _DtCvAddPtrToArray(*ret_chunks,
5377                                                 (void *) DT_HELP_CE_END);
5378
5379     /*
5380      * free the list
5381      */
5382     if (0 < myVars.my_list.cnt)
5383         _DtHelpFreeSegments(myVars.my_list.list, _DtCvFALSE,
5384                                                 ui_info->destroy_region, 
5385                                                 ui_info->client_data);
5386
5387     /*
5388      * free the link database
5389      */
5390     _DtLinkDbDestroy(myVars.my_links);
5391
5392     /*
5393      * free memory
5394      */
5395     if (myVars.my_path != NULL)
5396         free(myVars.my_path);
5397     if (myVars.fmt_buf != NULL)
5398         free(myVars.fmt_buf);
5399
5400     _DtHelpCeUnlockVolume(lockInfo);
5401
5402     /*
5403      * indicate an error if problems.
5404      */
5405     result = 0;
5406     if (NULL == *ret_chunks)
5407         result = -1;
5408
5409     return result;
5410
5411 }  /* End _DtHelpCeGetCcdfTitleChunks */
5412
5413 /******************************************************************************
5414  * Function:    int _DtHelpCeGetCcdfVolTitleChunks (
5415  *                              _DtHelpVolumeHdl volume,
5416  *                              void ***ret_chunks)
5417  *
5418  * Parameters:
5419  *              ret_chunks      Returns a ptr to the title information chunks
5420  *                              The title chunks are stored in allocated memory
5421  *                              that is owned by the caller and should be
5422  *                              freed when no longer needed.
5423  *                              id match segment.
5424  *
5425  * Returns:     0 if successful, -1 if errors
5426  *
5427  * errno Values:
5428  *
5429  * Purpose:     _DtHelpCeFormatCcdfVolTitleChunks formats volume title for
5430  *              a CCDF Help File.
5431  *
5432  ******************************************************************************/
5433 int
5434 _DtHelpCeGetCcdfVolTitleChunks(
5435     _DtHelpVolumeHdl       volume,
5436     _FrmtUiInfo           *ui_info,
5437     void                ***ret_chunks)
5438 {
5439     char    *charSet;
5440     char    *titleStr;
5441
5442     /*
5443      * get the title of the volume (we own the memory).
5444      */
5445     charSet = _DtHelpCeGetCcdfVolLocale(volume);
5446     if (charSet == NULL)
5447         charSet = strdup("C.ISO-8859-1");
5448
5449     titleStr = _DtHelpCeGetCcdfVolTitle(volume);
5450     if (titleStr != NULL)
5451       {
5452         *ret_chunks = (void **) malloc(sizeof(void *) * 4);
5453         if (*ret_chunks == NULL)
5454             return -1;
5455
5456         (*ret_chunks)[0] = (void *) (DT_HELP_CE_CHARSET | DT_HELP_CE_STRING);
5457         (*ret_chunks)[1] = (void *) strdup(charSet);
5458         (*ret_chunks)[2] = (void *) strdup(titleStr);
5459         (*ret_chunks)[3] = (void *) DT_HELP_CE_END;
5460       }
5461     else 
5462       {
5463         free(charSet);
5464         if (_DtHelpCeGetCcdfTitleChunks(volume, "_title",
5465                                                 ui_info, ret_chunks) != 0
5466                 &&
5467             _DtHelpCeGetCcdfTitleChunks(volume, "_hometopic",
5468                                                 ui_info, ret_chunks) != 0)
5469             return -1;
5470       }
5471
5472     return 0;
5473
5474 }  /* End _DtHelpCeGetCcdfVolTitleChunks */