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