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