source: rtems/doc/tools/pdl2texi/main.c @ b4767da

4.104.114.84.95
Last change on this file since b4767da was b4767da, checked in by Joel Sherrill <joel.sherrill@…>, on 01/30/98 at 19:17:25

Modified output of @Example style in MsWord? output routine so it would
be one paragraph with manual line breaks rather than multiple paragraphs..

  • Property mode set to 100644
File size: 84.9 KB
Line 
1/*
2 *  main.c
3 * 
4 *  This program error checks the OAR PDL and converts it into
5 *  It works by reading the input file into a linked list of lines
6 *  and then performing sweeps on that list until all formatting is
7 *  complete.
8 *
9 *  FEATURES:
10 *    + rudimentary statistics
11 *    + forgiveness features
12 *
13 *  CHECKS PERFORMED:
14 *    + unable to open file
15 *    + unexpected end of file
16 *    + line should have a colon
17 *    + basic text (to right or below) associated with keyword improperly placed
18 *    + an "incomplete marker" is still in place
19 *    + missing keywords within a subsection
20 *    + duplicated keywords withing a subsection
21 *    + subsections in correct order
22 *    + section header indicates no subsections and there are subsections
23 *    + section header indicates subsections and there are no subsections
24 *    + inconsistent spacing in RAW text.  This tends to be 1st line with
25 *      text is indented further than a subsequent line.
26 *    + missing components on line (incomplete)
27 *    + invalid repitition of a subsection
28 *    + type keyword validated for class, type, and spacing between
29 *    + both members and range are present
30 *    + neither members and range are present
31 *    + enumerated types and attributes have members
32 *    + non-enumerated types and attributes have ranges.
33 *    + Object name and end object have the same name
34 *    + booleans in attribute section list both true and false
35 *    + task synchronization keyword is checked.  There must be a valid
36 *      type of synchronization primitive and a description when expected.
37 *    + sections in correct order
38 *
39 *  INTERNAL ERRORS:
40 *    + attempting to reformat an already formatted line
41 *    + end of processing reached and no formatting assigned to line
42 *
43 *  CHECKS NOT PERFORMED:
44 *
45 *  TODO:
46 *
47 *  IDEAS NOT IMPLEMENTED:
48 *    + smarter reporting of sections not in the right order
49 *    + task which uses multiple synchronization types
50 *    + improved error messages
51 *    + no introductions inserted to sections
52 *    + recognize special "symbols" like infinity, +-, etc.
53 *
54 *  QUESTIONS:
55 *    + "what do I know" is actually a table and should not be reformatted.
56 *
57 *  COPYRIGHT (c) 1997.
58 *  On-Line Applications Research Corporation (OAR).
59 *  All rights reserved.
60 *
61 *  $Id$
62 */
63
64#include <assert.h>
65#include <ctype.h>
66#include <limits.h>
67#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70
71/* XXX -- just for testing -- these should be set by options */
72char DocsNextNode[256]     = "";
73char DocsPreviousNode[256] = "";
74char DocsUpNode[256]       = "";
75
76extern int   optind;     /* Why is this not in <stdlib.h>? */
77extern char *optarg;     /* Why is this not in <stdlib.h>? */
78
79#ifndef NAME_MAX
80#define NAME_MAX      14 /* Why is the one in limits.h not showing up? */
81#endif
82#define INIT_DATA
83#define EXTERN
84
85#include "base.h"
86
87FILE           *OutFile = stdout;
88
89/*************************************************************************
90 *************************************************************************
91 *****                 DATA TYPES AND CONSTANT TABLES                *****
92 *************************************************************************
93 *************************************************************************/
94/*
95 *  Usage Information
96 */
97
98char *Usage_Strings[] = {
99  "\n",
100  "usage: cmd [-vti?] [-p previous_node] [-u up_node] files ...\n",
101  "\n",
102  "EOF"
103};
104
105/*
106 *  The page separator is not really a keyword and will be purged before
107 *  it is seen elsewhere.
108 */
109
110#define PAGE_SEPARATOR                            "#PAGE"
111
112/*
113 *  Section Delimiter Keywords
114 */
115
116#define MAXIMUM_KEYWORD_LENGTH   32
117
118/*
119 *  Level indicates where in the format the delimiter is allowed to occur.
120 *    1 indicates a major section divider (e.g. "ATTRIBUTE DESCRIPTIONS:").
121 *    2 indicates a subsection (e.g. "ATTRIBUTE:").
122 *    3 indicates a heading (e.g. "DESCRIPTION:").
123 */
124
125#define TEXT         0
126#define SECTION      1
127#define SUBSECTION   2
128#define HEADING      3
129 
130typedef enum {
131  UNUSED,                            /* dummy 0 slot */
132  OBJECT,                            /* sections */
133  ATTRIBUTE_DESCRIPTIONS,
134  ASSOCIATION_DESCRIPTIONS,
135  ABSTRACT_TYPE_DESCRIPTIONS,
136  DATA_ITEM_DESCRIPTIONS,
137  METHOD_DESCRIPTIONS,
138  TASK_DESCRIPTIONS,
139  END_OBJECT,
140 
141  ATTRIBUTE,                         /* subsections */
142  ASSOCIATION,
143  ABSTRACT_TYPE,
144  DATA_ITEM,
145  METHOD,
146  TASK,
147 
148  DESCRIPTION,                       /* headings */
149  COPYRIGHT,
150  PORTING,
151  THEORY_OF_OPERATION,
152  DERIVATION,
153  DEPENDENCIES,
154  NOTES,
155  TYPE,
156  RANGE,
157  MEMBERS,
158  UNITS,
159  SCALE_FACTOR,
160  DEFAULT,
161  TOLERANCE,
162  REQUIREMENTS,
163  REFERENCES,
164  VISIBILITY,
165  ASSOCIATED_WITH,
166  MULTIPLICITY,
167  INPUTS,
168  OUTPUTS,
169  PDL,
170  SYNCHRONIZATION,
171  TIMING
172}  Keyword_indices_t;
173
174#define KEYWORD_FIRST OBJECT
175#define KEYWORD_LAST  TIMING
176
177/*
178 *  Line Management Structure
179 */
180
181typedef enum {
182  NO_EXTRA_FORMATTING_INFO,
183  RAW_OUTPUT,
184  PARAGRAPH_OUTPUT,
185  BULLET_OUTPUT,
186}  ExtraFormat_info_t;
187
188typedef struct {
189  Chain_Node         Node;
190  Keyword_indices_t  keyword;   /* unused is unknown/undecided */
191  ExtraFormat_info_t format;
192  int                number;
193  char               Contents[ PARAGRAPH_SIZE ];
194} Line_Control;
195
196typedef enum {
197  RT_FORBIDDEN,     /* no text to right allowed */
198  RT_OPTIONAL,      /* text to right optional -- none below */
199  RT_NONE,          /* text to right is "none" or nothing -- none below */
200  RT_REQUIRED,      /* text to right required -- none below */
201  RT_BELOW,         /* text to right forbidden -- text below required */
202  RT_NONE_OR_BELOW, /* text to right is "none" OR there is text below  */
203  RT_MAYBE_BELOW,   /* text to right required -- text below optional */
204  RT_EITHER,        /* text to right OR below */
205  RT_BOTH           /* text to right AND below */
206}  Keywords_text_mode_t;
207
208typedef enum {
209  BL_FORBIDDEN,     /* text below forbidden */
210  BL_FORMATTED,     /* text below is to be formatted as paragraphs */
211  BL_RAW,           /* text below is to be unprocessed by this program */
212}  Keywords_text_below_t;
213
214typedef int (*Keyword_validater_t)( Line_Control * );
215
216typedef struct {
217  char                      Name[ MAXIMUM_KEYWORD_LENGTH ];
218  int                       level;
219  Keywords_text_mode_t      text_mode;
220  Keywords_text_below_t     text_below_mode;
221  Keyword_validater_t       keyword_validation_routine;
222}  Keyword_info_t;
223
224/*
225 *  Keyword Validation Routines
226 */
227
228int Validate_visibility(
229  Line_Control   *line
230);
231
232int Validate_synchronization(
233  Line_Control   *line
234);
235
236Keyword_info_t Keywords[] = {
237  { "unused",
238        0,          0,                0, NULL }, /* so 0 can be invalid */
239  { "OBJECT:",
240        SECTION,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
241  { "ATTRIBUTE DESCRIPTIONS:",
242        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
243  { "ASSOCIATION DESCRIPTIONS:",
244        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
245  { "ABSTRACT TYPE DESCRIPTIONS:",
246        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
247  { "DATA ITEM DESCRIPTIONS:",
248        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
249  { "METHOD DESCRIPTIONS:",
250        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
251  { "TASK DESCRIPTIONS:",
252        SECTION,    RT_NONE,          BL_FORBIDDEN, NULL },
253  { "ENDOBJECT:",
254        SECTION,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
255
256  { "ATTRIBUTE:",
257        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
258  { "ASSOCIATION:",
259        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
260  { "ABSTRACT TYPE:",
261        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
262  { "DATA ITEM:",
263        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
264  { "METHOD:",
265        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
266  { "TASK:",
267        SUBSECTION, RT_REQUIRED,      BL_FORBIDDEN, NULL },
268
269  { "DESCRIPTION:",
270        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
271  { "COPYRIGHT:",
272        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
273  { "PORTING:",
274        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
275  { "THEORY OF OPERATION:",
276        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
277  { "DERIVATION:",
278        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
279  { "DEPENDENCIES:",
280        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
281  { "NOTES:",
282        HEADING,    RT_BELOW,         BL_FORMATTED, NULL },
283  { "TYPE:",
284        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
285  { "RANGE:",
286        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
287  { "MEMBERS:",
288        HEADING,    RT_BELOW,         BL_RAW,       NULL },
289  { "UNITS:",
290        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
291  { "SCALE FACTOR:",
292        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
293  { "DEFAULT:",
294        HEADING,    RT_EITHER,        BL_RAW, NULL },
295  { "TOLERANCE:",
296        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
297  { "REQUIREMENTS:",
298        HEADING,    RT_BELOW,         BL_RAW,       NULL },
299  { "REFERENCES:",
300        HEADING,    RT_BELOW,         BL_RAW,       NULL },
301  { "VISIBILITY:",
302        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, Validate_visibility },
303  { "ASSOCIATED WITH:",
304        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
305  { "MULTIPLICITY:",
306        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL },
307  { "INPUTS:",
308        HEADING,    RT_NONE_OR_BELOW, BL_RAW,       NULL },
309  { "OUTPUTS:",
310        HEADING,    RT_NONE_OR_BELOW, BL_RAW,       NULL },
311  { "PDL:",
312        HEADING,    RT_BELOW,         BL_RAW,       NULL },
313  { "SYNCHRONIZATION:",
314        HEADING,    RT_MAYBE_BELOW,   BL_RAW,    Validate_synchronization },
315  { "TIMING:",
316        HEADING,    RT_REQUIRED,      BL_FORBIDDEN, NULL }
317};
318
319#define NUMBER_OF_KEYWORDS \
320  ( sizeof( Keywords ) / sizeof( Keyword_info_t ) ) - 2
321
322/*
323 *  Section Descriptions
324 */
325
326#define MAXIMUM_ELEMENTS 16
327
328typedef struct {
329  Keyword_indices_t  keyword;
330  boolean            is_required;
331}  Element_info_t;
332
333typedef struct Section_info_struct_t Section_info_t;
334
335typedef (*Section_validater_t)(
336  Section_info_t *,
337  Line_Control *,  /* start */
338  Line_Control *   /* next_section */
339);
340
341struct Section_info_struct_t {
342  boolean              repeats;
343  Keyword_indices_t    This_section;
344  Keyword_indices_t    Next_section;
345  Section_validater_t  section_validation_routine;
346  Element_info_t       Description[MAXIMUM_ELEMENTS];
347};
348
349int Validate_object(
350  Section_info_t *section,
351  Line_Control   *start,
352  Line_Control   *next_section
353);
354 
355int Validate_attribute(
356  Section_info_t *section,
357  Line_Control   *start,
358  Line_Control   *next_section
359);
360 
361int Validate_abstract_type(
362  Section_info_t *section,
363  Line_Control   *start,
364  Line_Control   *next_section
365);
366 
367
368Section_info_t ObjectSection = {
369  FALSE,                        /* subsections repeat */
370  OBJECT,                       /* this section */
371  ATTRIBUTE_DESCRIPTIONS,       /* next section */
372  Validate_object,              /* validation routine */
373  {
374    { OBJECT,              TRUE },     /*  0 */
375    { DESCRIPTION,         TRUE },     /*  1 */
376    { COPYRIGHT,           FALSE },    /*  2 */
377    { PORTING,             FALSE },    /*  3 */
378    { THEORY_OF_OPERATION, TRUE },     /*  4 */
379    { DERIVATION,          FALSE },    /*  5 */
380    { DEPENDENCIES,        FALSE },    /*  6 */
381    { REQUIREMENTS,        FALSE },    /*  7 */
382    { REFERENCES,          FALSE },    /*  8 */
383    { NOTES,               FALSE },    /*  9 */
384    { UNUSED,              FALSE },    /* 10 */
385    { UNUSED,              FALSE },    /* 11 */
386    { UNUSED,              FALSE },    /* 12 */
387    { UNUSED,              FALSE },    /* 13 */
388    { UNUSED,              FALSE },    /* 14 */
389    { UNUSED,              FALSE },    /* 15 */
390  }
391};
392
393Section_info_t AttributeSection = {
394  TRUE,                         /* subsections repeat */
395  ATTRIBUTE_DESCRIPTIONS,       /* this section */
396  ASSOCIATION_DESCRIPTIONS,     /* next section */
397  Validate_attribute,           /* validation routine */
398  {
399    { ATTRIBUTE,           TRUE },     /*  0 */
400    { DESCRIPTION,         TRUE },     /*  1 */
401    { TYPE,                TRUE },     /*  2 */
402    { MEMBERS,             FALSE },    /*  3 */
403    { RANGE,               FALSE },    /*  4 */
404    { UNITS,               FALSE },    /*  5 */
405    { SCALE_FACTOR,        FALSE },    /*  6 */
406    { DEFAULT,             FALSE },    /*  7 */
407    { TOLERANCE,           FALSE },    /*  8 */
408    { REQUIREMENTS,        FALSE },    /*  9 */
409    { REFERENCES,          FALSE },    /* 10 */
410    { NOTES,               FALSE },    /* 11 */
411    { UNUSED,              FALSE },    /* 12 */
412    { UNUSED,              FALSE },    /* 13 */
413    { UNUSED,              FALSE },    /* 14 */
414    { UNUSED,              FALSE },    /* 15 */
415  }
416};
417
418Section_info_t AssociationSection = {
419  TRUE,                         /* subsections repeat */
420  ASSOCIATION_DESCRIPTIONS,     /* this section */
421  ABSTRACT_TYPE_DESCRIPTIONS,   /* next section */
422  NULL,                         /* validation routine */
423  {
424    { ASSOCIATION,         TRUE },     /*  0 */
425    { DESCRIPTION,         TRUE },     /*  1 */
426    { VISIBILITY,          TRUE },     /*  2 */
427    { ASSOCIATED_WITH,     TRUE },     /*  3 */
428    { MULTIPLICITY,        TRUE },     /*  4 */
429    { REQUIREMENTS,        FALSE },    /*  5 */
430    { REFERENCES,          FALSE },    /*  6 */
431    { NOTES,               FALSE },    /*  7 */
432    { UNUSED,              FALSE },    /*  8 */
433    { UNUSED,              FALSE },    /*  9 */
434    { UNUSED,              FALSE },    /* 10 */
435    { UNUSED,              FALSE },    /* 11 */
436    { UNUSED,              FALSE },    /* 12 */
437    { UNUSED,              FALSE },    /* 13 */
438    { UNUSED,              FALSE },    /* 14 */
439    { UNUSED,              FALSE },    /* 15 */
440  }
441};
442
443Section_info_t AbstractTypeSection = {
444  TRUE,                         /* subsections repeat */
445  ABSTRACT_TYPE_DESCRIPTIONS,   /* this section */
446  DATA_ITEM_DESCRIPTIONS,       /* next section */
447  Validate_abstract_type,       /* validation routine */
448  {
449    { ABSTRACT_TYPE,       TRUE },     /*  0 */
450    { DESCRIPTION,         TRUE },     /*  1 */
451    { VISIBILITY,          TRUE },     /*  2 */
452    { DERIVATION,          TRUE },     /*  3 */
453    { MEMBERS,             FALSE },    /*  4 */
454    { RANGE,               FALSE },    /*  5 */
455    { UNITS,               FALSE },    /*  6 */
456    { SCALE_FACTOR,        FALSE },    /*  7 */
457    { DEFAULT,             FALSE },    /*  8 */
458    { TOLERANCE,           FALSE },    /*  9 */
459    { REQUIREMENTS,        FALSE },    /* 10 */
460    { REFERENCES,          FALSE },    /* 11 */
461    { NOTES,               FALSE },    /* 12 */
462    { UNUSED,              FALSE },    /* 13 */
463    { UNUSED,              FALSE },    /* 14 */
464    { UNUSED,              FALSE },    /* 15 */
465  }
466};
467
468Section_info_t DataItemSection = {
469  TRUE,                         /* subsections repeat */
470  DATA_ITEM_DESCRIPTIONS,       /* this section */
471  METHOD_DESCRIPTIONS,          /* next section */
472  NULL,                         /* validation routine */
473  {
474    { DATA_ITEM,           TRUE },     /*  0 */
475    { DESCRIPTION,         TRUE },     /*  1 */
476    { TYPE,                TRUE },     /*  2 */
477    { UNITS,               FALSE },    /*  3 */
478    { SCALE_FACTOR,        FALSE },    /*  4 */
479    { DEFAULT,             FALSE },    /*  5 */
480    { TOLERANCE,           FALSE },    /*  6 */
481    { NOTES,               FALSE },    /*  7 */
482    { UNUSED,              FALSE },    /*  8 */
483    { UNUSED,              FALSE },    /*  9 */
484    { UNUSED,              FALSE },    /* 10 */
485    { UNUSED,              FALSE },    /* 11 */
486    { UNUSED,              FALSE },    /* 12 */
487    { UNUSED,              FALSE },    /* 13 */
488    { UNUSED,              FALSE },    /* 14 */
489    { UNUSED,              FALSE },    /* 15 */
490  }
491};
492
493Section_info_t MethodSection = {
494  TRUE,                         /* subsections repeat */
495  METHOD_DESCRIPTIONS,          /* this section */
496  TASK_DESCRIPTIONS,            /* next section */
497  NULL,                         /* validation routine */
498  {
499    { METHOD,              TRUE },     /*  0 */
500    { DESCRIPTION,         TRUE },     /*  1 */
501    { VISIBILITY,          TRUE },     /*  2 */
502    { INPUTS,              TRUE },     /*  3 */
503    { OUTPUTS,             TRUE },     /*  4 */
504    { REQUIREMENTS,        FALSE },    /*  5 */
505    { REFERENCES,          FALSE },    /*  6 */
506    { NOTES,               FALSE },    /*  7 */
507    { PDL,                 TRUE },     /*  8 */
508    { UNUSED,              FALSE },    /*  9 */
509    { UNUSED,              FALSE },    /* 10 */
510    { UNUSED,              FALSE },    /* 11 */
511    { UNUSED,              FALSE },    /* 12 */
512    { UNUSED,              FALSE },    /* 13 */
513    { UNUSED,              FALSE },    /* 14 */
514    { UNUSED,              FALSE },    /* 15 */
515  }
516};
517
518Section_info_t TaskSection = {
519  TRUE,                         /* subsections repeat */
520  TASK_DESCRIPTIONS,            /* this section */
521  END_OBJECT,                   /* next section */
522  NULL,                         /* validation routine */
523  {
524    { METHOD,              TRUE },     /*  0 */
525    { DESCRIPTION,         TRUE },     /*  1 */
526    { VISIBILITY,          TRUE },     /*  2 */
527    { INPUTS,              TRUE },     /*  3 */
528    { SYNCHRONIZATION,     TRUE },     /*  4 */
529    { TIMING,              TRUE },     /*  5 */
530    { REQUIREMENTS,        FALSE },    /*  6 */
531    { REFERENCES,          FALSE },    /*  7 */
532    { NOTES,               FALSE },    /*  8 */
533    { PDL,                 TRUE },     /*  9 */
534    { UNUSED,              FALSE },    /* 10 */
535    { UNUSED,              FALSE },    /* 11 */
536    { UNUSED,              FALSE },    /* 12 */
537    { UNUSED,              FALSE },    /* 13 */
538    { UNUSED,              FALSE },    /* 14 */
539    { UNUSED,              FALSE },    /* 15 */
540  }
541};
542
543
544Section_info_t *Sections[] = {
545  &ObjectSection,
546  &AttributeSection,
547  &AssociationSection,
548  &AbstractTypeSection,
549  &DataItemSection,
550  &MethodSection,
551  &TaskSection
552};
553
554/*
555 *  exit_application
556 */
557
558void exit_application(
559  int status
560)
561{
562  fprintf( stderr, "*** Error encountered ***\n" );
563/*
564  fprintf( stderr, "*** Error encountered on line %d ***\n", CurrentLine );
565*/
566  fclose( OutFile );
567  exit( 1 );
568}
569
570/*************************************************************************
571 *************************************************************************
572 *****                LINE MANIPULATION ROUTINES                     *****
573 *************************************************************************
574 *************************************************************************/
575
576/*
577 * PrintLine
578 */
579
580void PrintLine(
581  Line_Control *line
582)
583{
584  assert( line );
585
586  if ( line->number == -1 )
587    fprintf( stderr, "     " );
588  else
589    fprintf( stderr, "%5d", line->number );
590
591#if 0
592  fprintf( stderr, "%s\n", line->Contents );
593#else
594  /*
595   *  Include some debugging information
596   */
597  fprintf(
598    stderr,
599    "<%d,%d>:%s\n",
600    line->keyword,
601    line->format,
602    line->Contents
603  );
604#endif
605}
606
607Chain_Control Line_Pool;
608
609/*
610 *  FillLinePool
611 */
612
613void FillLinePool( void )
614{
615  void *pool;
616
617#define LINE_POOL_FILL_COUNT 100
618
619  pool = malloc( sizeof( Line_Control ) * LINE_POOL_FILL_COUNT );
620  assert( pool );
621
622  _Chain_Initialize(
623    &Line_Pool,
624    pool,
625    LINE_POOL_FILL_COUNT,
626    sizeof( Line_Control )
627  );
628}
629
630/*
631 * AllocateLine
632 */
633
634Line_Control *AllocateLine( void )
635{
636  Line_Control  *new_line;
637
638  new_line = (Line_Control *) _Chain_Get( &Line_Pool );
639  if ( !new_line ) {
640    FillLinePool();
641    new_line = (Line_Control *) _Chain_Get( &Line_Pool );
642    assert( new_line );
643  }
644 
645/*
646 *  This is commented out because although it is helpful during debug,
647 *  it consumes a significant percentage of the program's execution time.
648 */
649
650  memset( new_line->Contents, '\0', sizeof( new_line->Contents ) );
651  new_line->number = -1;
652
653  new_line->keyword = UNUSED;
654  new_line->format = NO_EXTRA_FORMATTING_INFO;
655
656  new_line->Node.next     = NULL;
657  new_line->Node.previous = NULL;
658
659  return new_line;
660}
661
662/*
663 * FreeLine
664 */
665
666void FreeLine(
667  Line_Control *line
668)
669{
670  fflush( stdout );
671  _Chain_Append( &Line_Pool, &line->Node );
672}
673
674/*
675 * DeleteLine
676 */
677
678Line_Control *DeleteLine(
679  Line_Control *line
680)
681{
682  Line_Control *next;
683 
684  next = (Line_Control *)line->Node.next;
685  _Chain_Extract( &line->Node );
686  FreeLine( line );
687  return next;
688}
689
690/*
691 *  PrintSurroundingLines
692 */
693
694void PrintSurroundingLines(
695  Line_Control *line,
696  int           backward,
697  int           forward
698)
699{
700  int           i;
701  int           real_backward;
702  Line_Control *local;
703
704  for ( local=line, real_backward=0, i=1 ;
705        i<=backward ;
706        i++, real_backward++ ) {
707    if ( &local->Node == Lines.first )
708      break;
709    local = (Line_Control *) local->Node.previous;
710  }
711
712  for ( i=1 ; i<=real_backward ; i++ ) {
713    PrintLine( local );
714    local = (Line_Control *) local->Node.next;
715  }
716 
717  PrintLine( local );
718
719  for ( i=1 ; i<=forward ; i++ ) {
720    local = (Line_Control *) local->Node.next;
721    if ( _Chain_Is_last( &local->Node ) )
722      break;
723    PrintLine( local );
724  }
725 
726}
727
728/*
729 *  SetLineFormat
730 */
731
732void SetLineFormat(
733  Line_Control       *line,
734  ExtraFormat_info_t  format
735)
736{
737  if ( line->format != NO_EXTRA_FORMATTING_INFO ) {
738    fprintf( stderr, "Line %d is already formatted\n", line->number );
739    PrintLine( line );
740    assert( FALSE );
741  }
742
743  line->format = format;
744}
745
746/*
747 *  LineCopyFromRight
748 */
749
750void LineCopyFromRight(
751  Line_Control *line,
752  char         *dest
753)
754{
755  char *p;
756
757  for ( p=line->Contents ; *p != ':' ; p++ )
758    ;
759  p++;  /* skip the ':' */
760  for ( ; isspace( *p ) ; p++ )
761    ;
762
763  strcpy( dest, p );
764
765}
766
767/*
768 *  LineCopySectionName
769 */
770
771void LineCopySectionName(
772  Line_Control *line,
773  char         *dest
774)
775{
776  char *p;
777  char *d;
778
779  p = line->Contents;
780  d = dest;
781
782  if ( *p == '@' ) {                /* skip texinfo command */
783    while ( !isspace( *p++ ) )
784      ;
785  }
786
787  for ( ; *p != ':' ; )
788    *d++ = *p++;
789
790  *d = '\0';
791}
792
793/*
794 *  FormatParagraph
795 */
796
797Line_Control *FormatParagraph(
798  Line_Control *starting
799)
800{
801  Chain_Node   *insert_after;
802  Line_Control *to_add;
803  Line_Control *new_line;
804  char          Paragraph[ PARAGRAPH_SIZE ];
805  int           starting_line;
806  char         *src;
807  char         *dest;
808  boolean       do_loop;
809  boolean       is_bullet;
810  int           length;
811
812  length = 0;
813
814  starting_line = starting->number;
815  insert_after = starting->Node.previous;
816  to_add = starting;
817
818  dest = Paragraph;
819
820  is_bullet = FALSE;
821
822  for ( ; ; ) {
823    src = to_add->Contents;
824
825    for ( ; *src && isspace( *src ) ; src++ ); /* skip leading spaces */
826
827    if ( *src == '+' ) {
828      if ( is_bullet == TRUE )
829        break;
830      is_bullet = TRUE;
831      for ( src++ ; isspace(*src) ; src++ ) ;
832    }
833
834    do_loop = TRUE;
835    while ( *src && do_loop == TRUE ) {
836                   
837      if ( isspace( *src ) ) {         /* convert multiple spaces to 1 */
838
839        if ( *(dest-1) == '.' ) {      /* two spaces after period */
840          *dest++ = ' ';
841          length++;
842        }
843
844        assert( length < PARAGRAPH_SIZE );
845
846        *dest++ = ' ';
847        length++;
848
849        assert( length < PARAGRAPH_SIZE );
850 
851        for (  ; isspace( *src ) ; src++ )
852          if ( !*src ) {
853            do_loop = FALSE;
854            break;
855          }
856 
857        continue;
858 
859      } else {
860        *dest++ = *src;
861        length++;
862        assert( length < PARAGRAPH_SIZE );
863        src++;
864      }
865    }
866
867    to_add = DeleteLine( to_add );
868
869    if ( _Chain_Is_last( &to_add->Node ) )
870      break;
871
872    if ( !strlen( to_add->Contents ) )
873      break;
874
875    if ( to_add->keyword )
876      break;
877
878    if ( !isspace( *(dest-1) ) ) {
879      if ( *(dest-1) == '.' ) {
880        *dest++ = ' ';
881        length++;
882        assert( length < PARAGRAPH_SIZE );
883      }
884      *dest++ = ' ';
885      length++;
886      assert( length < PARAGRAPH_SIZE );
887    }
888  }
889
890  new_line = AllocateLine();
891 
892  SetLineFormat( new_line, (is_bullet) ? BULLET_OUTPUT : PARAGRAPH_OUTPUT );
893
894  *dest = '\0';
895
896  strcpy( new_line->Contents, Paragraph );
897
898  new_line->number = starting_line;
899 
900  _Chain_Insert( insert_after, &new_line->Node );
901
902  return new_line;
903}
904
905/*
906 *  FormatMultipleParagraphs
907 */
908
909Line_Control *FormatMultipleParagraphs(
910  Line_Control *starting
911)
912{
913  Line_Control *line = starting;
914
915  if ( _Chain_Is_last( &line->Node ) ) {
916    fprintf( stderr, "end of file reached when expecting text\n" );
917    exit_application( 0 );
918  }
919
920  if ( line->keyword ) {
921    line = (Line_Control *) line->Node.next;
922
923    if ( _Chain_Is_last( &line->Node ) ) {
924      fprintf( stderr, "end of file reached when expecting text\n" );
925      exit_application( 0 );
926    }
927  }
928   
929  for ( ;; ) {
930    assert( line );
931
932    if ( _Chain_Is_last( &line->Node ) )
933      break;
934
935    if ( line->keyword )
936      break;
937   
938    if ( !strlen( line->Contents ) ) {
939      line = DeleteLine( line );
940      continue;
941    }
942
943    line = FormatParagraph( line );
944    line = (Line_Control *) line->Node.next;
945  }
946}
947
948/*************************************************************************
949 *************************************************************************
950 *****              END OF LINE MANIPULATION ROUTINES                *****
951 *************************************************************************
952 *************************************************************************/
953
954/*
955 *  CountKeywordOccurrences
956 */
957
958int CountKeywordOccurrences(
959  Keyword_indices_t  keyword
960)
961{
962  int           count = 0;
963  Line_Control *line;
964
965  for ( line = (Line_Control *) Lines.first ;
966        !_Chain_Is_last( &line->Node ) ;
967        line = (Line_Control *) line->Node.next ) {
968    if ( line->keyword == keyword )
969      count += 1;
970  }
971
972  return count;
973}
974
975/*
976 *  main
977 */
978
979int main(
980  int    argc,
981  char **argv
982)
983{
984  int      c;
985  int      index;
986  boolean  single_file_mode;
987
988  Verbose = FALSE;
989  Statistics = FALSE;
990  OutputWord = FALSE;
991  IncompletesAreErrors = TRUE;
992  InsertTBDs = FALSE;
993
994  while ((c = getopt(argc, argv, "istvw?n:p:u:")) != EOF) {
995    switch (c) {
996      case 'i':
997        IncompletesAreErrors = FALSE;
998        break;
999      case 't':
1000        InsertTBDs = TRUE;
1001        break;
1002      case 'v':
1003        Verbose = TRUE;
1004        break;
1005      case 'n':
1006         strcpy( DocsNextNode, optarg );
1007         break;
1008      case 'p':
1009         strcpy( DocsPreviousNode, optarg );
1010         break;
1011      case 'u':
1012         strcpy( DocsUpNode, optarg );
1013         break;
1014      case 's':
1015         Statistics = TRUE;
1016         break;
1017      case 'w':
1018         OutputWord = TRUE;
1019         break;
1020      case '?':
1021        usage();
1022        return 0;
1023    }
1024  }
1025
1026  if ( Verbose ) {
1027    fprintf( stderr, "Arguments successfully parsed\n" );
1028    fprintf( stderr, "Next Node = (%s)\n", DocsNextNode );
1029    fprintf( stderr, "Previous Node = (%s)\n", DocsPreviousNode );
1030    fprintf( stderr, "Up Node = (%s)\n", DocsUpNode );
1031    fprintf( stderr, "Output Format = (%s)\n", (OutputWord) ? "Word" : "Texi" );
1032  }
1033
1034  FillLinePool();
1035
1036  for ( index=optind ; index < argc ; index++ ) {
1037    ProcessFile( argv[ index ], NULL );
1038  }
1039   
1040  if ( Verbose )
1041    fprintf( stderr, "Exitting\n" );
1042
1043  return 0;
1044}
1045
1046/*
1047 *  ProcessFile
1048 */
1049
1050void ProcessFile(
1051  char   *inname,
1052  char   *outname
1053)
1054{
1055   char            out[ 256 ];
1056   int             index;
1057   int             out_index;
1058
1059   /*
1060    *  Automatically generate the output file name.
1061    */
1062
1063   if ( outname == NULL ) {
1064     out_index = 0;
1065     for( index=0 ; inname[index] && inname[index] != '.' ; index++ ) {
1066/*
1067       if ( inname[ index ] != '_' )
1068*/
1069         out[ out_index++ ] = inname[ index ];
1070     }
1071
1072     if ( OutputWord ) {
1073       out[ out_index++ ] = '.';
1074       out[ out_index++ ] = 't';
1075       out[ out_index++ ] = 'x';
1076       out[ out_index++ ] = 't';
1077     } else {
1078       out[ out_index++ ] = '.';
1079       out[ out_index++ ] = 't';
1080       out[ out_index++ ] = 'e';
1081       out[ out_index++ ] = 'x';
1082       out[ out_index++ ] = 'i';
1083     }
1084     out[ out_index ] = '\0';
1085
1086   }
1087
1088   /*
1089    *  Read the file into our internal data structure
1090    */
1091
1092   if ( Verbose )
1093     printf( "Processing (%s) -> (%s)\n", inname, out );
1094
1095   ReadFileIntoChain( inname );
1096
1097   if ( Verbose )
1098     fprintf( stderr, "-------->FILE READ IN\n" );
1099
1100   /*
1101    *  Remove any spaces before the keyword and mark each keyword line as
1102    *  such.  Also remove extra white space at the end of lines.
1103    */
1104
1105   StripBlanks();
1106
1107   if ( Verbose )
1108     fprintf( stderr, "-------->BLANKS BEFORE KEYWORDS STRIPPED\n" );
1109
1110   /*
1111    *  Count the number of each type of thing
1112    */
1113
1114   NumberOfAttributes    = CountKeywordOccurrences( ATTRIBUTE );
1115   NumberOfAssociations  = CountKeywordOccurrences( ASSOCIATION );
1116   NumberOfAbstractTypes = CountKeywordOccurrences( ABSTRACT_TYPE );
1117   NumberOfDataItems     = CountKeywordOccurrences( DATA_ITEM );
1118   NumberOfMethods       = CountKeywordOccurrences( METHOD );
1119   NumberOfTasks         = CountKeywordOccurrences( TASK );
1120
1121   if ( Verbose || Statistics ) {
1122     fprintf( stderr, "NUMBER OF ATTRIBUTES = %d\n", NumberOfAttributes );
1123     fprintf( stderr, "NUMBER OF ASSOCIATIONS = %d\n", NumberOfAssociations );
1124     fprintf( stderr, "NUMBER OF ABSTRACT TYPES = %d\n", NumberOfAbstractTypes);
1125     fprintf( stderr, "NUMBER OF DATA ITEMS = %d\n", NumberOfDataItems );
1126     fprintf( stderr, "NUMBER OF METHODS = %d\n", NumberOfMethods );
1127     fprintf( stderr, "NUMBER OF TASKS = %d\n", NumberOfTasks );
1128   }
1129
1130   /*
1131    *  1.  Merge paragraphs entered as multiple lines into a single node
1132    *      on the chain.
1133    *  2.  Clean up "colon lines".
1134    */
1135
1136   if ( MergeText() == -1 )
1137     exit_application( 1 );
1138
1139   if ( Verbose )
1140     fprintf( stderr, "-------->PARAGRAPHS MERGED\n" );
1141
1142   RemovePagebreaks();
1143   
1144   /*
1145    *  Remove extraneous white space
1146    */
1147
1148   if ( Verbose )
1149     fprintf( stderr, "-------->PAGEBREAKS REMOVED\n" );
1150
1151   /*
1152    *  At this point, the only unmarked lines should be empty or errors.
1153    *  This deletes empty unmarked lines and flags the others as errors.
1154    */
1155
1156   if ( RemoveExtraBlankLines() == -1 )
1157     exit_application( 1 );
1158 
1159   if ( Verbose )
1160     fprintf( stderr, "-------->EXTRA BLANK LINES REMOVED\n" );
1161
1162   /*
1163    *  Now report which lines do not appear to be complete
1164    */
1165
1166   if ( CheckForIncomplete() == -1 )
1167     exit_application( 1 );
1168
1169   if ( Verbose )
1170     fprintf( stderr, "-------->CHECKED FOR INCOMPLETE KEYWORDS\n" );
1171
1172   /*
1173    *  Check that all the required sections are present.
1174    */
1175
1176   if ( CheckOutline() == -1 )
1177     exit_application( 1 );
1178 
1179   if ( Verbose )
1180     fprintf( stderr, "-------->CHECKED FOR HIGH LEVEL SECTION PROBLEMS\n" );
1181
1182   /*
1183    *  Check for problems in each section.
1184    */
1185
1186   if ( CheckSections() == -1 )
1187     exit_application( 1 );
1188
1189   if ( Verbose )
1190     fprintf( stderr, "-------->CHECKED FOR INTERNAL SECTION PROBLEMS\n" );
1191
1192   /*
1193    *  Look for Internal Consistencies
1194    */
1195
1196   if ( Verbose )
1197     fprintf( stderr, "-------->LOOKING FOR ERRORS\n" );
1198
1199   LookForInternalInconsistencies();
1200
1201   /*
1202    *  Formatting the file
1203    */
1204
1205   if ( OutputWord ) {
1206     FormatToWord();
1207     if ( Verbose )
1208       fprintf( stderr, "-------->FILE FORMATTED TO WORD\n" );
1209   } else {
1210     FormatToTexinfo();
1211     if ( Verbose )
1212       fprintf( stderr, "-------->FILE FORMATTED TO TEXINFO\n" );
1213   }
1214
1215   /*
1216    *  Print the file
1217    */
1218
1219   PrintFile( out );
1220
1221   if ( Verbose )
1222     fprintf( stderr, "-------->FILE PRINTED\n" );
1223
1224   /*
1225    *  Clean Up
1226    */
1227
1228   ReleaseFile();
1229
1230   if ( Verbose )
1231     fprintf( stderr, "-------->FILE RELEASED\n" );
1232}
1233
1234/*
1235 *  LookForInternalInconsistencies
1236 *
1237 *  This routine looks for lines with no formatting information and
1238 *  lines with too much formatting information.
1239 */
1240
1241void LookForInternalInconsistencies( void )
1242{
1243  Line_Control  *line;
1244  int            i;
1245  int            errors = 0;
1246  char          *src;
1247
1248  for ( line = (Line_Control *) Lines.first ;
1249        !_Chain_Is_last( &line->Node ) ;
1250        line = (Line_Control *)line->Node.next
1251        ) {
1252    if ( !line->keyword && line->format == NO_EXTRA_FORMATTING_INFO ) {
1253      fprintf(
1254        stderr,
1255        "\nLine %d has no keyword or formatting:\n",
1256        line->number
1257      );
1258      PrintSurroundingLines( line, 3,  3 );
1259      errors++;
1260    }
1261  }
1262 
1263  if ( errors )
1264    exit_application( 1 );
1265}
1266
1267/*
1268 *  usage
1269 */
1270
1271void usage( void )
1272{
1273  int index;
1274
1275  for ( index=0 ; strcmp( Usage_Strings[ index ], "EOF" ) ; index++ )
1276    fprintf( stderr, Usage_Strings[ index ] );
1277}
1278
1279/*
1280 *  ReadFileIntoChain
1281 */
1282
1283void ReadFileIntoChain(
1284  char *inname
1285)
1286{
1287   FILE *InFile;
1288   int   line_count;
1289   int   max_length;
1290   char *line;
1291   char  Buffer[ BUFFER_SIZE ];
1292   Line_Control *new_line;
1293
1294   InFile = fopen( inname, "r" );
1295
1296   if ( !InFile ) {
1297     fprintf( stderr, "Unable to open (%s)\n", inname );
1298     exit( 1 );
1299   }
1300   assert( InFile );
1301
1302   max_length = 0;
1303   line_count = 0;
1304
1305   _Chain_Initialize_empty( &Lines );
1306
1307   for ( ;; ) {
1308      line = fgets( Buffer, BUFFER_SIZE, InFile );
1309      if ( !line )
1310        break;
1311
1312      Buffer[ strlen( Buffer ) - 1 ] = '\0';
1313
1314      new_line = AllocateLine();
1315 
1316      strcpy( new_line->Contents, Buffer );
1317
1318      new_line->number = ++line_count;
1319 
1320      _Chain_Append( &Lines, &new_line->Node );
1321   }
1322
1323   fclose( InFile );
1324}
1325
1326/*
1327 *  StripBlanks
1328 */
1329
1330void StripBlanks( void )
1331{
1332  Line_Control      *line;
1333  Keyword_indices_t  index;
1334  int                indentation;
1335  int                length;
1336  Keyword_info_t    *key;
1337 
1338  for ( line = (Line_Control *) Lines.first ;
1339        !_Chain_Is_last( &line->Node ) ;
1340        line = (Line_Control *) line->Node.next
1341        ) {
1342
1343    /*
1344     *  Strip white space from the end of each line
1345     */
1346
1347    length = strlen( line->Contents );
1348
1349    while ( isspace( line->Contents[ --length ] ) )
1350      line->Contents[ length ] = '\0';
1351
1352    /*
1353     *  Strip white space from the front of each keyword line.
1354     */
1355
1356    for ( index=KEYWORD_FIRST ; index <= KEYWORD_LAST ; index++ ) {
1357      key = &Keywords[ index ];
1358
1359      switch ( key->level ) {
1360        case SECTION:    indentation = 0; break;
1361        case SUBSECTION: indentation = 0; break;
1362        case HEADING:    indentation = 2; break;
1363        default:         assert( FALSE );
1364      }
1365
1366      if ( !strncmp( &line->Contents[ indentation ], key->Name,
1367                    strlen( key->Name ) ) ) {
1368        if ( indentation )
1369          strcpy( line->Contents,  &line->Contents[ indentation ] );
1370        line->keyword = index;
1371        break;
1372      }
1373    }
1374  }
1375}
1376
1377/*
1378 *  CrunchRight
1379 */
1380
1381boolean CrunchRight(
1382  Line_Control *line
1383)
1384{
1385  char  Buffer[ PARAGRAPH_SIZE ];
1386  char *src;
1387  char *dest;
1388  boolean is_text_to_right = FALSE;
1389
1390  src  = line->Contents;
1391  dest = Buffer;
1392
1393  while( *src != ':' ) {
1394    if ( !*src ) {
1395      fprintf(
1396        stderr,
1397        "Line %d should have had a colon\n",
1398        line->number
1399      );
1400      exit_application( 1 );
1401    }
1402    *dest++ = *src++;
1403  }
1404 
1405  *dest++ = *src++;    /* this is the ':' */
1406 
1407  if ( *src ) {
1408    *dest++ = ' ';
1409    while ( *src && isspace( *src ) )
1410      src++;
1411 
1412    if ( *src )
1413      is_text_to_right = TRUE;
1414 
1415    while ( *src )
1416      *dest++ = *src++;
1417  }
1418 
1419  *dest = '\0';
1420
1421  strcpy( line->Contents, Buffer );
1422
1423  return is_text_to_right;
1424}
1425
1426/*
1427 *  CrunchBelow
1428 */
1429
1430void CrunchBelow(
1431  Line_Control          *start_line,
1432  Keywords_text_below_t  text_below_mode
1433)
1434{
1435  Line_Control      *line;
1436  int                i;
1437  int                leading_white;
1438  int                length;
1439 
1440  switch ( text_below_mode ) {
1441    case BL_FORBIDDEN:
1442      assert( FALSE );
1443    case BL_FORMATTED:
1444      (void) FormatMultipleParagraphs( start_line );
1445      break;
1446    case BL_RAW:
1447      for ( line = (Line_Control *) start_line->Node.next;
1448            !_Chain_Is_last( &line->Node ) ;
1449          ) {
1450         if ( strlen( line->Contents ) )
1451           break;
1452         line = DeleteLine( line );
1453      } 
1454
1455      for ( i=0 ; isspace( line->Contents[ i ] ) ; i++ )
1456        ;
1457     
1458      leading_white = i;
1459
1460      for ( ;
1461            !_Chain_Is_last( &line->Node ) ;
1462            ) {
1463 
1464         assert( line );
1465
1466         if ( line->keyword )
1467           break;
1468
1469         assert( !_Chain_Is_last( &line->Node ) );
1470
1471         length = strlen( line->Contents );
1472
1473         if ( length ) {
1474           if ( length < leading_white ) {
1475             fprintf(
1476               stderr,
1477               "\nLine %d %s:\n",
1478               line->number,
1479               "has inconsistent spacing -- is too short -- see 1st line of text"
1480             );
1481             PrintSurroundingLines( line, 0,  0 );
1482             fprintf( stderr, "\n" );
1483
1484           }
1485           for ( i=0 ; i < leading_white ; i++ ) {
1486             if ( !isspace( line->Contents[ i ] ) ) {
1487               fprintf(
1488                 stderr,
1489                 "\nLine %d %s:\n",
1490                 line->number,
1491                 "has inconsistent spacing -- see 1st line of text"
1492               );
1493               PrintSurroundingLines( line, 0,  0 );
1494               fprintf( stderr, "\n" );
1495               break;
1496             }
1497           }
1498
1499           strcpy( line->Contents, &line->Contents[ leading_white ] );
1500
1501           SetLineFormat( line, RAW_OUTPUT );
1502           line = (Line_Control *) line->Node.next;
1503         } else {
1504           SetLineFormat( line, RAW_OUTPUT );
1505           /* line = DeleteLine( line ); */
1506           line = (Line_Control *) line->Node.next;
1507         }
1508      }
1509      break;
1510  }
1511}
1512
1513/*
1514 *  MergeText
1515 */
1516 
1517/* XXX expand this and address the error numbers */
1518char *Format_Errors[] = {
1519  /* unused */             "no formatting error",
1520  /* RT_FORBIDDEN     */   "no text allowed to right or below",
1521  /* RT_OPTIONAL      */   "text to right optional -- none below",
1522  /* RT_NONE          */   "text to right is \"none\" or nothing -- none below",
1523  /* RT_REQUIRED      */   "text to right required -- none below",
1524  /* RT_BELOW         */   "text to right forbidden -- text below required",
1525  /* RT_NONE_OR_BELOW */   "text to right is \"none\" OR there is text below",
1526  /* RT_MAYBE_BELOW   */   "text to right required -- text below optional",
1527  /* RT_EITHER        */   "text to right OR below",
1528  /* RT_BOTH          */   "text to right AND below"
1529};
1530
1531
1532int MergeText( void )
1533{
1534  Line_Control      *line;
1535  Line_Control      *next;
1536  Line_Control      *new_line;
1537  Keyword_info_t    *key;
1538  boolean            is_text_to_right;
1539  boolean            is_text_below;
1540  boolean            add_text_to_right;
1541  boolean            add_text_below;
1542  int                errors = 0;
1543  int                error_code = 0;
1544 
1545  for ( line = (Line_Control *) Lines.first ;
1546        !_Chain_Is_last( &line->Node ) ;
1547        ) {
1548 
1549    if ( error_code ) {
1550
1551      fprintf(
1552        stderr,
1553        "\nLine %d %s:\n",
1554        line->number,
1555        Format_Errors[ error_code ]
1556      );
1557      PrintSurroundingLines( line, 0,  3 );
1558      fprintf( stderr, "\n" );
1559      error_code = 0;
1560      line = (Line_Control *) line->Node.next;
1561    }
1562
1563    key = &Keywords[ line->keyword ];
1564
1565    if ( !line->keyword ) {
1566      line = (Line_Control *) line->Node.next;
1567      continue;
1568    }
1569
1570    /*
1571     *  Figure out where the text is for this keyword.  It is a pretty
1572     *  ugly thing to look ahead for text below because of intermediate
1573     *  blank lines which we are not allowed to remove.
1574     */
1575
1576    add_text_to_right = FALSE;
1577    add_text_below = FALSE;
1578
1579    is_text_to_right = CrunchRight( line );
1580
1581    is_text_below = FALSE;
1582
1583    for ( next = (Line_Control *) line->Node.next ;
1584          !_Chain_Is_last( &next->Node ) ;
1585          next = (Line_Control *) next->Node.next ) {
1586
1587      if ( next->keyword )
1588        break;
1589
1590      if ( strlen( next->Contents ) ) {
1591        is_text_below = TRUE;
1592        break;
1593      }
1594    }
1595
1596    switch ( key->text_mode ) {
1597      case RT_FORBIDDEN: /* no text to right or below allowed */
1598        if ( is_text_to_right || is_text_below ) {
1599          error_code = 1;
1600          errors++;
1601          continue;
1602        }
1603        break;
1604
1605      case RT_OPTIONAL:  /* text to right optional -- none below */
1606        if ( is_text_below ) {
1607          error_code = 2;
1608          errors++;
1609          continue;
1610        }
1611        break;
1612
1613      case RT_NONE:      /* text to right is "none" or nothing -- none below */
1614        if ( (is_text_to_right && !strstr( line->Contents, "none" )) ||
1615             is_text_below ) {
1616          error_code = 3;
1617          errors++;
1618          continue;
1619        }
1620        break;
1621
1622      case RT_REQUIRED:  /* text to right required -- none below */
1623        if ( is_text_below ) {
1624          error_code = 4;
1625          errors++;
1626          continue;
1627        }
1628
1629        if ( !is_text_to_right ) {
1630          if ( !InsertTBDs ) {
1631            error_code = 4;
1632            errors++;
1633            continue;
1634          } else
1635            add_text_to_right = TRUE;
1636        }
1637        break;
1638
1639      case RT_BELOW:     /* text to right forbidden -- text below required */
1640        if ( is_text_to_right ) {
1641          error_code = 5;
1642          errors++;
1643          continue;
1644        }
1645
1646        if ( !is_text_below ) {
1647          if ( !InsertTBDs ) {
1648            error_code = 5;
1649            errors++;
1650            continue;
1651          } else
1652            add_text_below = TRUE;
1653        }
1654        break;
1655
1656      case RT_NONE_OR_BELOW: /* text to right is "none" OR text below */
1657
1658        if ( is_text_to_right ) {
1659          if ( strstr( line->Contents, "none" ) )
1660            break;
1661          error_code = 6;
1662          errors++;
1663          continue;
1664        }
1665
1666        if ( !is_text_below ) {
1667          if ( !InsertTBDs ) {
1668            error_code = 6;
1669            errors++;
1670            continue;
1671          } else
1672            add_text_to_right = TRUE;
1673        }
1674        break;
1675                          /* text to right required -- text below optional */
1676      case RT_MAYBE_BELOW:
1677        if ( !is_text_to_right ) {
1678          error_code = 7;
1679          errors++;
1680          continue;
1681        }
1682        break;
1683
1684      case RT_EITHER:    /* text to right OR below */
1685        if ( !(is_text_to_right || is_text_below) ) {
1686          if ( !InsertTBDs ) {
1687            error_code = 8;
1688            errors++;
1689            continue;
1690          } else
1691            add_text_to_right = TRUE;
1692        }
1693        break;
1694
1695      case RT_BOTH:      /* text to right AND below */
1696        if ( !(is_text_to_right && is_text_below) ) {
1697          if ( !InsertTBDs ) {
1698            error_code = 9;
1699            errors++;
1700            continue;
1701          } else {
1702            add_text_to_right = TRUE;
1703            add_text_below = TRUE;
1704          }
1705        }
1706        break;
1707    }
1708
1709    if ( add_text_to_right )
1710      strcat( line->Contents, " TBD" );
1711
1712    if ( add_text_below ) {
1713      new_line = AllocateLine();
1714      strcpy( new_line->Contents, "TBD" );
1715      _Chain_Insert( &line->Node, &new_line->Node );
1716      is_text_below = TRUE;
1717    }
1718
1719    if ( is_text_below )
1720      CrunchBelow( line, key->text_below_mode );
1721
1722    line = (Line_Control *) line->Node.next;
1723  }
1724  return (errors) ? -1 : 0;
1725}
1726
1727/*
1728 *  CheckForIncomplete
1729 */
1730
1731char *IncompleteMarkers[] = {
1732  "??",
1733  "xxx",
1734  "XXX",
1735  "xyz",
1736  "XYZ"
1737};
1738
1739int CheckForIncomplete()
1740{
1741  Line_Control *line;
1742  int           i;
1743  int           errors = 0;
1744
1745  for ( line = (Line_Control *) Lines.first ;
1746        !_Chain_Is_last( &line->Node ) ;
1747        line = (Line_Control *) line->Node.next
1748        ) {
1749    for ( i=0 ; i < NUMBER_ELEMENTS( IncompleteMarkers ) ; i++ ) {
1750      if ( !strstr( line->Contents, IncompleteMarkers[ i ] ) )
1751        continue;
1752
1753      fprintf(
1754        stderr,
1755        "\nLine %d %s:\n",
1756        line->number,
1757        "appears to be incomplete"
1758      );
1759      PrintSurroundingLines( line, 0,  0 );
1760      fprintf( stderr, "\n" );
1761      if ( IncompletesAreErrors )
1762        errors++;
1763      break;
1764    }
1765  }
1766  return ( errors ) ? -1 : 0;
1767}
1768
1769/*
1770 *  CheckOutline
1771 *
1772 *  Insure all section headers are present.
1773 *  Check sections which say "none", really have subsections.
1774 *  Check sections which have subsections, don't say none.
1775 */
1776
1777int CheckOutline( void )
1778{
1779  Line_Control      *line;
1780  int                count;
1781  int                errors = 0;
1782  void              *none_present;
1783  boolean            KeywordsPresent[ KEYWORD_LAST + 1 ];
1784  Keyword_indices_t  keyword;
1785
1786  for ( keyword=0 ; keyword <= KEYWORD_LAST ; keyword++ )
1787    KeywordsPresent[ keyword ] = FALSE;
1788
1789  for ( line = (Line_Control *) Lines.first ;
1790        !_Chain_Is_last( &line->Node ) ;
1791        line = (Line_Control *) line->Node.next
1792        ) {
1793
1794    KeywordsPresent[ line->keyword ] = TRUE;
1795
1796    switch ( line->keyword ) {
1797      case ATTRIBUTE_DESCRIPTIONS:
1798        count = NumberOfAttributes;
1799        break;
1800      case ASSOCIATION_DESCRIPTIONS:
1801        count = NumberOfAssociations;
1802        break;
1803      case ABSTRACT_TYPE_DESCRIPTIONS:
1804        count = NumberOfAbstractTypes;
1805        break;
1806      case DATA_ITEM_DESCRIPTIONS:
1807        count = NumberOfDataItems;
1808        break;
1809      case METHOD_DESCRIPTIONS:
1810        count = NumberOfMethods;
1811        break;
1812      case TASK_DESCRIPTIONS:
1813        count = NumberOfTasks;
1814        break;
1815      default:
1816        count = -1;
1817        break;
1818    }
1819    if ( count == -1 )
1820      continue;
1821
1822    none_present = strstr( line->Contents, "none" );
1823
1824    /* valid cases are (none_present && !count) AND (!none_present && count) */
1825    if ( none_present && count ) {
1826      fprintf(
1827        stderr,
1828        "\nLine %d : %s\n",
1829        line->number,
1830        "section header says \"none\" and there are subsections"
1831      );
1832      PrintSurroundingLines( line, 0,  0 );
1833      fprintf( stderr, "\n" );
1834      errors++;
1835    }
1836    if ( !none_present && !count ) {
1837      fprintf(
1838        stderr,
1839        "\nLine %d : %s\n",
1840        line->number,
1841        "section header does not say \"none\" and there are no subsections"
1842      );
1843      PrintSurroundingLines( line, 0,  0 );
1844      fprintf( stderr, "\n" );
1845      errors++;
1846    }
1847  }
1848
1849  for ( keyword=0 ; keyword <= KEYWORD_LAST ; keyword++ ) {
1850    if ( Keywords[ keyword ].level != SECTION )
1851      continue;
1852
1853    if ( !KeywordsPresent[ keyword ] ) {
1854      fprintf(
1855        stderr,
1856        "Section (%s) is missing\n",
1857        Keywords[ keyword ].Name
1858      );
1859      errors++;
1860    }
1861  }
1862
1863  return (errors) ? -1 : 0;
1864}
1865
1866/*
1867 *  ReportMissingKeywords
1868 */
1869
1870int ReportMissingKeywords(
1871  Section_info_t  *section,
1872  Line_Control    *line,
1873  int              elements_present[ MAXIMUM_ELEMENTS ]
1874)
1875{
1876  int       i;
1877  int       errors = 0;
1878  int       last_found;
1879
1880#ifdef SECTION_DEBUG
1881  PrintLine( line );
1882  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ )
1883    fprintf( stderr, "%d ", elements_present[ i ] );
1884  fprintf( stderr, "\n" );
1885#endif
1886 
1887  /*
1888   *  Check for missing sections
1889   */
1890
1891  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ ) {
1892    if ( section->Description[ i ].keyword == UNUSED )
1893      break;
1894
1895#ifdef SECTION_DEBUG
1896    fprintf(
1897      stderr,
1898      "%d %d %s\n",
1899      section->Description[ i ].is_required,
1900      elements_present[ i ],
1901      Keywords[ section->Description[ i ].keyword ].Name
1902    );
1903#endif
1904
1905    if ( section->Description[ i ].is_required && elements_present[i] == -1 ) {
1906      fprintf(
1907        stderr,
1908        "Section starting at line %d is missing the %s keyword\n",
1909        line->number,
1910        Keywords[ section->Description[ i ].keyword ].Name
1911      );
1912      errors++;
1913    }
1914  }
1915
1916  last_found = -1;
1917
1918  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ ) {
1919    if ( section->Description[ i ].keyword == UNUSED )
1920      break;
1921
1922    if ( elements_present[i] == -1 )
1923      continue;
1924
1925    if ( elements_present[i] > last_found ) {
1926      last_found = elements_present[i];
1927      continue;
1928    }
1929
1930    fprintf(
1931      stderr,
1932      "Keywords in the section starting at line %d are in the wrong order\n",
1933      line->number
1934    );
1935    errors++;
1936    break;
1937
1938  }
1939
1940  return errors;
1941}
1942
1943/*
1944 *  ScanForNextSection
1945 */
1946
1947Line_Control *ScanForNextSection(
1948  Line_Control   *start_line,
1949  Section_info_t *section
1950)
1951{
1952  Line_Control   *line;
1953  Element_info_t *Elements;
1954
1955  line = start_line;
1956  Elements = section->Description;
1957
1958  for ( ;; ) {
1959    line = (Line_Control *) line->Node.next;
1960
1961    if ( line->keyword == END_OBJECT )
1962      break;
1963
1964    assert( line );
1965    assert( !_Chain_Is_last( &line->Node ) );
1966
1967    if ( Keywords[ line->keyword ].level == SECTION &&
1968         section->Next_section != line->keyword ) {
1969
1970        fprintf(
1971          stderr,
1972          "Sections appear to be out of order at line %d\n",
1973          start_line->number
1974        );
1975        return NULL;
1976    }
1977
1978    if ( section->Next_section == line->keyword )   /* next section */
1979      break;
1980
1981    if ( Elements[ 0 ].keyword == line->keyword )   /* repeating subsection */
1982      break;
1983  }
1984
1985  return line;
1986}
1987
1988/*
1989 *  CheckSections
1990 */
1991
1992int CheckSections( void )
1993{
1994  Line_Control   *line;
1995  Line_Control   *scan_line;
1996  Section_info_t *section;
1997  Keyword_info_t *key;
1998  Element_info_t *Elements;
1999  int             elements_present[ MAXIMUM_ELEMENTS ];
2000  boolean         stay_in_subsection;
2001  int             i;
2002  int             errors;
2003  int             subsection;
2004  int             element;
2005  int             keyword_count;
2006  Line_Control   *next_section;
2007
2008  errors = 0;
2009  line = (Line_Control *) Lines.first;
2010
2011  for ( i=0 ; i < NUMBER_ELEMENTS( Sections ) ; i++ ) {
2012    section = Sections[ i ];
2013    Elements = section->Description;
2014    subsection = 0;
2015
2016    if ( strstr( line->Contents, "none" ) ) {
2017      next_section = ScanForNextSection( line, section );
2018      if ( !next_section ) {
2019        errors++;
2020        goto end_object;
2021      }
2022      line = next_section;
2023      if ( line->keyword == END_OBJECT )
2024        goto end_object;
2025      continue;
2026    }
2027
2028    while ( Elements[ 0 ].keyword != line->keyword ) {
2029      if ( line->keyword == END_OBJECT )
2030        goto end_object;
2031
2032      if( !line || _Chain_Is_last( &line->Node ) ) {
2033        fprintf( stderr, "out of sync -- aborting\n" );
2034        errors++;
2035        goto end_object;
2036      }
2037      line = (Line_Control *) line->Node.next;
2038    }
2039
2040repeating_subsection:
2041
2042#ifdef SECTION_DEBUG
2043    fprintf( stderr, "Checking Section %d Subsection %d\n", i, subsection );
2044#endif
2045    assert( line );
2046    assert( !_Chain_Is_last( &line->Node ) );
2047 
2048    /*
2049     *  Per Subsection Initialization
2050     */
2051
2052    subsection++;
2053
2054    keyword_count = 0;
2055
2056    next_section = ScanForNextSection( line, section );
2057    if ( !next_section ) {
2058      errors++;
2059      goto end_object;
2060    }
2061
2062    for ( element=0 ; element < MAXIMUM_ELEMENTS ; element++ )
2063      elements_present[ element ] = -1;
2064
2065    /* 
2066     *  Do a subsection
2067     */
2068
2069    /*  validate each keyword */
2070
2071    for ( scan_line = line ; ; ) {
2072
2073      if ( !scan_line->keyword ) {
2074        scan_line = (Line_Control *) scan_line->Node.next;
2075        continue;
2076      }
2077
2078      if ( scan_line == next_section )
2079        break;
2080
2081      if ( *Keywords[ scan_line->keyword ].keyword_validation_routine ) {
2082        if ( (*Keywords[ scan_line->keyword ].keyword_validation_routine )(
2083               scan_line
2084              ) ) errors++;
2085      }
2086
2087      scan_line = (Line_Control *) scan_line->Node.next;
2088    }
2089
2090    /* scan subsection for keywords */
2091
2092    for ( scan_line = line ; ; ) {
2093
2094      if ( !scan_line->keyword ) {
2095        scan_line = (Line_Control *) scan_line->Node.next;
2096        continue;
2097      }
2098
2099      if ( scan_line == next_section )
2100        break;
2101
2102      for ( element=0 ; element < MAXIMUM_ELEMENTS ; element++ ) {
2103        if ( scan_line->keyword == Elements[ element ].keyword ) {
2104          if ( elements_present[ element ] != -1 ) {
2105            fprintf(
2106              stderr,
2107              "Section starting at line %d has the %s keyword more than once\n",
2108              line->number,
2109              Keywords[ Elements[ i ].keyword ].Name
2110            );
2111            errors++;
2112          }
2113         
2114#ifdef SECTION_DEBUG
2115          fprintf( stderr, "FOUND %s %d %d\n",
2116            Keywords[ Elements[ element ].keyword ].Name,
2117            element, keyword_count );
2118#endif
2119          elements_present[ element ] = keyword_count++;
2120          break;
2121        }
2122        if ( Elements[ element ].keyword == UNUSED )
2123          break;
2124      }
2125
2126      scan_line = (Line_Control *) scan_line->Node.next;
2127    }
2128    errors += ReportMissingKeywords( section, line, elements_present );
2129
2130    /*
2131     *  Validate the section as a whole
2132     */
2133     
2134    if ( section->section_validation_routine ) {
2135      if ( (*section->section_validation_routine)(section, line, next_section) )
2136        errors++;
2137    }
2138
2139scan_for_next_section:
2140    /*
2141     *  Scan forward until next subsection or next section
2142     */
2143
2144#ifdef SECTION_DEBUG
2145    fprintf( stderr, "End of Subsection\n" );
2146#endif
2147    line = next_section;
2148    if ( line->keyword == END_OBJECT ) {
2149      goto end_object;
2150    }
2151
2152    if ( Elements[ 0 ].keyword == line->keyword ) { /* repeating subsection */
2153      if ( !section->repeats ) {
2154        fprintf(
2155          stderr,
2156          "Invalid repeating subsection starting at line %d\n",
2157          line->number
2158        );
2159        errors++;
2160        goto end_object;
2161      }
2162      goto repeating_subsection;
2163    }
2164 
2165  }
2166
2167end_object:
2168  return (errors) ? -1 : 0;
2169}
2170/*
2171 *  RemovePagebreaks
2172 */
2173
2174void RemovePagebreaks()
2175{
2176  Line_Control *line;
2177
2178  for ( line = (Line_Control *) Lines.first ;
2179        !_Chain_Is_last( &line->Node ) ;
2180        ) {
2181    if ( !strcmp( line->Contents, PAGE_SEPARATOR ) )
2182        line = DeleteLine( line );
2183    else
2184      line = (Line_Control *) line->Node.next;
2185  }
2186}
2187
2188/*
2189 *  strIsAllSpace
2190 */
2191
2192boolean strIsAllSpace(
2193  char *s
2194)
2195{
2196  char *p;
2197
2198  for ( p = s ; *p ; p++ )
2199    if ( !isspace( *p ) )
2200      return FALSE;
2201
2202  return TRUE;
2203}
2204
2205/*
2206 *  RemoveExtraBlankLines
2207 *
2208 *  NOTE:  Be careful not remove to remove white space in raw text.
2209 */
2210
2211int RemoveExtraBlankLines()
2212{
2213  Line_Control *line;
2214  Line_Control *previous;
2215  int errors;
2216
2217  errors = 0;
2218
2219  for ( line = (Line_Control *) Lines.first ;
2220        !_Chain_Is_last( &line->Node ) ;
2221        line = (Line_Control *) line->Node.next
2222        ) {
2223    if ( line->keyword || line->format )
2224      continue;
2225
2226    if ( !strlen( line->Contents ) ) {
2227      line = DeleteLine( line );
2228      line = (Line_Control *) line->Node.previous;
2229      continue;
2230    }
2231
2232    fprintf(
2233      stderr,
2234      "\nLine %d is not associated with a keyword:\n",
2235      line->number
2236    );
2237    PrintSurroundingLines( line, 0,  0 );
2238    fprintf( stderr, "\n" );
2239    errors++;
2240  }
2241  return ( errors ) ? -1 : 0;
2242}
2243
2244/*
2245 *  strCopyToColon
2246 */
2247
2248void strCopyToColon(
2249  char *src,
2250  char *dest
2251)
2252{
2253  char *s = src;
2254  char *d = dest;
2255
2256  for ( ; *s && *s != ':' ; )
2257    *d++ = *s++;
2258  *d ='\0';
2259}
2260
2261/*
2262 *  BuildTexinfoNodes
2263 */
2264
2265void BuildTexinfoNodes( void )
2266{
2267  Line_Control *line;
2268  Line_Control *new_line;
2269  Line_Control *next_node;
2270  char          Buffer[ BUFFER_SIZE ];
2271  char          ObjectName[ BUFFER_SIZE ];
2272  char          NodeName[ BUFFER_SIZE ];
2273  char          NextNode[ BUFFER_SIZE ];
2274  char          NextNodeName[ BUFFER_SIZE ];
2275  char          PreviousNodeName[ BUFFER_SIZE ];
2276  char          UpNodeName[ BUFFER_SIZE ];
2277  char          SectionName[ BUFFER_SIZE ];
2278  char          MenuBuffer[ BUFFER_SIZE ];
2279  Line_Control *menu_insert_point;
2280  Line_Control *node_line;
2281  boolean       next_found;
2282  int           menu_items;
2283
2284  strcpy( PreviousNodeName, DocsPreviousNode );
2285
2286  for ( line = (Line_Control *) Lines.first ;
2287        !_Chain_Is_last( &line->Node ) ;
2288        line = (Line_Control *) line->Node.next
2289      ) {
2290    menu_insert_point = (Line_Control *) line->Node.next;
2291
2292    switch ( Keywords[ line->keyword ].level ) {
2293      case TEXT:
2294      case HEADING:
2295        break;
2296      case SECTION:
2297        if ( line->keyword == END_OBJECT )
2298          goto bottom;
2299
2300        if ( line->keyword == OBJECT ) {
2301          LineCopyFromRight( line, Buffer );
2302          sprintf( ObjectName, "%s Object", Buffer );
2303          strcpy( NodeName, ObjectName );
2304          strcpy( UpNodeName, DocsUpNode );
2305        } else {
2306          LineCopySectionName( line, Buffer );
2307          sprintf( NodeName, "%s %s", ObjectName, Buffer );
2308          strcpy( UpNodeName, ObjectName );
2309        }
2310        strtoInitialCaps( NULL, NodeName );
2311        strtoInitialCaps( NULL, UpNodeName );
2312        strcpy( SectionName, NodeName );
2313
2314        /*
2315         *  Go ahead and put it on the chain in the right order (ahead of
2316         *  the menu) and we can fill it in later (after the menu is built).
2317         */
2318
2319        new_line = AllocateLine();
2320        strcpy( new_line->Contents, "@ifinfo" );
2321        _Chain_Insert( line->Node.previous, &new_line->Node );
2322
2323        node_line = AllocateLine();
2324        _Chain_Insert( line->Node.previous, &node_line->Node );
2325
2326        new_line = AllocateLine();
2327        strcpy( new_line->Contents, "@end ifinfo" );
2328        _Chain_Insert( line->Node.previous, &new_line->Node );
2329
2330        menu_items = 0;
2331       
2332        if ( line->keyword == OBJECT ) {
2333          next_node = (Line_Control *) line->Node.next;
2334          next_found = FALSE;
2335          for ( ; ; ) {
2336            if ( next_node->keyword == END_OBJECT )
2337              break;
2338            if ( Keywords[ next_node->keyword ].level == SECTION ) {
2339              LineCopySectionName( next_node, Buffer );
2340              strtoInitialCaps( NULL, Buffer );     
2341
2342              if ( !next_found ) {
2343                next_found = TRUE;
2344                sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2345              }
2346              if ( menu_items == 0 ) {
2347                new_line = AllocateLine();
2348                strcpy( new_line->Contents, "@ifinfo" );
2349                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2350 
2351                new_line = AllocateLine();
2352                strcpy( new_line->Contents, "@menu" );
2353                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2354              }
2355
2356              menu_items++;
2357
2358              new_line = AllocateLine();
2359              sprintf( new_line->Contents, "* %s %s::", ObjectName, Buffer );
2360              _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node);
2361            }
2362            next_node = (Line_Control *) next_node->Node.next;
2363          }
2364        } else {
2365          next_node = (Line_Control *) line->Node.next;
2366       
2367          next_found = FALSE;
2368          for ( ; ; ) {
2369            if ( Keywords[ next_node->keyword ].level == SECTION ) {
2370              if ( !next_found ) {
2371                if ( next_node->keyword == END_OBJECT ) {
2372                  strcpy( NextNodeName, DocsNextNode );
2373                } else {
2374                  LineCopySectionName( next_node, Buffer );
2375                  sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2376                  strtoInitialCaps( NULL, NextNodeName );
2377                }
2378                next_found = TRUE;
2379              }
2380              break;
2381            } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
2382              LineCopySectionName( next_node, Buffer );
2383              strtoInitialCaps( NULL, Buffer );
2384              sprintf( MenuBuffer, "%s %s - ", ObjectName, Buffer );
2385              LineCopyFromRight( next_node, Buffer );
2386              strcat( MenuBuffer, Buffer );
2387
2388              if ( menu_items == 0 ) {
2389                new_line = AllocateLine();
2390                strcpy( new_line->Contents, "@ifinfo" );
2391                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2392 
2393                new_line = AllocateLine();
2394                strcpy( new_line->Contents, "@menu" );
2395                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2396              }
2397
2398              menu_items++;
2399
2400              new_line = AllocateLine();
2401              sprintf( new_line->Contents, "* %s::", MenuBuffer );
2402              _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2403
2404              if ( !next_found ) {
2405                next_found = TRUE;
2406                strcpy( NextNodeName, MenuBuffer );
2407              }
2408            }
2409            next_node = (Line_Control *) next_node->Node.next;
2410          }
2411        }
2412
2413        if ( menu_items ) {
2414          new_line = AllocateLine();
2415          strcpy( new_line->Contents, "@end menu" );
2416          _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2417 
2418          new_line = AllocateLine();
2419          strcpy( new_line->Contents, "@end ifinfo" );
2420          _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2421        }
2422
2423#if 0
2424        fprintf(
2425          stderr,
2426          "@node %s, %s, %s, %s\n",
2427          NodeName,
2428          NextNodeName,
2429          PreviousNodeName,
2430          UpNodeName
2431        );
2432#endif
2433        /* node_line was previously inserted */
2434        sprintf(
2435          node_line->Contents,
2436          "@node %s, %s, %s, %s",
2437          NodeName,
2438          NextNodeName,
2439          PreviousNodeName,
2440          UpNodeName
2441        );
2442
2443        strcpy( PreviousNodeName, NodeName );
2444        break;
2445
2446      case SUBSECTION:
2447        strcpy( UpNodeName, SectionName );
2448
2449        LineCopySectionName( line, Buffer );
2450        strtoInitialCaps( NULL, Buffer );
2451        sprintf( NodeName, "%s %s - ", ObjectName, Buffer );
2452        LineCopyFromRight( line, Buffer );
2453        strcat( NodeName, Buffer );
2454
2455        new_line = AllocateLine();
2456        strcpy( new_line->Contents, "@ifinfo" );
2457        _Chain_Insert( line->Node.previous, &new_line->Node );
2458
2459        next_node = (Line_Control *) line->Node.next;
2460        for ( ; ; ) {
2461          if ( Keywords[ next_node->keyword ].level == SECTION ) {
2462            if ( next_node->keyword == END_OBJECT ) {
2463              strcpy( NextNodeName, DocsNextNode );
2464            } else {
2465              LineCopySectionName( next_node, Buffer );
2466              sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2467              strtoInitialCaps( NULL, NextNodeName );
2468            }
2469            break;
2470          } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
2471            LineCopySectionName( next_node, Buffer );
2472            strtoInitialCaps( NULL, Buffer );
2473            sprintf( NextNodeName, "%s %s - ", ObjectName, Buffer );
2474            LineCopyFromRight( next_node, Buffer );
2475            strcat( NextNodeName, Buffer );
2476            break;
2477          }
2478          next_node = (Line_Control *) next_node->Node.next;
2479        }
2480
2481#if 0
2482        fprintf(
2483          stderr,
2484          "@node %s, %s, %s, %s\n",
2485          NodeName,
2486          NextNodeName,
2487          PreviousNodeName,
2488          UpNodeName
2489        );
2490#endif
2491        new_line = AllocateLine();
2492        sprintf(
2493          new_line->Contents,
2494          "@node %s, %s, %s, %s",
2495          NodeName,
2496          NextNodeName,
2497          PreviousNodeName,
2498          UpNodeName
2499        );
2500        _Chain_Insert( line->Node.previous, &new_line->Node );
2501
2502        new_line = AllocateLine();
2503        strcpy( new_line->Contents, "@end ifinfo" );
2504        _Chain_Insert( line->Node.previous, &new_line->Node );
2505
2506        strcpy( PreviousNodeName, NodeName );
2507        break;
2508    }
2509  }
2510bottom:
2511}
2512
2513/*
2514 *  FormatToTexinfo
2515 */
2516
2517char *Texinfo_Headers[] = {
2518  "\\input texinfo   @c -*-texinfo-*-",
2519  "@c %**start of header",
2520  "@setfilename ",
2521  "@settitle ",
2522  "@paragraphindent 0",
2523  "@c %**end of header",
2524  "",
2525  "@c",
2526  "@c  COPYRIGHT (c) 1996.",
2527  "@c  On-Line Applications Research Corporation (OAR).",
2528  "@c  All rights reserved.",
2529  "@c",
2530  "@c  This file is automatically generated.  DO NOT EDIT!!",
2531  "@c",
2532  "",
2533  "@c  This prevents a black box from being printed on overfull lines.",
2534  "@c  The alternative is to rework a sentence to avoid this problem.",
2535  "@finalout",
2536  "",
2537  "@tex",
2538  "\\global\\parindent 0in",
2539  "\\global\\chapheadingskip = 15pt plus 4pt minus 2pt",
2540  "\\global\\secheadingskip = 12pt plus 4pt minus 2pt",
2541  "\\global\\subsecheadingskip = 9pt plus 4pt minus 2pt",
2542  "",
2543  "@ifclear smallbook",
2544  "\\global\\parskip 6pt plus 1pt",
2545  "@end ifclear",
2546  "@end tex",
2547  "@setchapternewpage odd",
2548  "@ifinfo",
2549  "@top ",
2550  "@node Top, (dir), (dir), (dir)",
2551  "@end ifinfo",
2552  "@c ",
2553  "@c This is the end of the header block",
2554  "@c "
2555};
2556
2557void FormatToTexinfo( void )
2558{
2559  Line_Control *line;
2560  Line_Control *new_line;
2561  char          Buffer[ PARAGRAPH_SIZE ];
2562  int           i;
2563  char          ChapterTitle[ PARAGRAPH_SIZE ];
2564  char          InfoFile[ PARAGRAPH_SIZE ];
2565  char          *p;
2566  boolean        new_section;
2567  boolean        in_bullets;
2568
2569  for ( line = (Line_Control *) Lines.first ;
2570        !_Chain_Is_last( &line->Node ) ;
2571      ) {
2572
2573    switch ( line->keyword ) {
2574      case UNUSED:
2575        line = (Line_Control *) line->Node.next;
2576        break;
2577
2578      case OBJECT:
2579        LineCopyFromRight( line, ChapterTitle );
2580        strcpy( InfoFile, ChapterTitle );
2581
2582        for ( p=InfoFile ; *p ; *p++ )   /* turn this into a file name */
2583          if ( isspace( *p ) )
2584            *p = '_';             
2585
2586        sprintf( Buffer, "@chapter %s", line->Contents );
2587        strcpy( line->Contents, Buffer );
2588        line = (Line_Control *) line->Node.next;
2589        break;
2590
2591      case ATTRIBUTE_DESCRIPTIONS:
2592      case ASSOCIATION_DESCRIPTIONS:
2593      case ABSTRACT_TYPE_DESCRIPTIONS:
2594      case DATA_ITEM_DESCRIPTIONS:
2595      case METHOD_DESCRIPTIONS:
2596      case TASK_DESCRIPTIONS:
2597        sprintf( Buffer, "@section %s", line->Contents );
2598        strcpy( line->Contents, Buffer );
2599
2600        new_line = AllocateLine();
2601        strcpy( new_line->Contents, "@page" );
2602        _Chain_Insert( line->Node.previous, &new_line->Node );
2603
2604        line = (Line_Control *) line->Node.next;
2605        new_section = TRUE;
2606        break;
2607
2608      case END_OBJECT:
2609        line->Contents[ 0 ] = '\0';
2610        goto bottom;
2611
2612      case ATTRIBUTE:
2613      case ASSOCIATION:
2614      case ABSTRACT_TYPE:
2615      case DATA_ITEM:
2616        if ( !new_section ) {
2617          new_line = AllocateLine();
2618          strcpy( new_line->Contents, "@need 4000" );
2619          _Chain_Insert( line->Node.previous, &new_line->Node );
2620        }
2621        new_section = FALSE;
2622        sprintf( Buffer, "@subsection %s", line->Contents );
2623        strcpy( line->Contents, Buffer );
2624        line = (Line_Control *) line->Node.next;
2625         break;
2626
2627      case METHOD:
2628      case TASK:
2629        if ( !new_section ) {
2630          new_line = AllocateLine();
2631          strcpy( new_line->Contents, "@page" );
2632          _Chain_Insert( line->Node.previous, &new_line->Node );
2633        }
2634        new_section = FALSE;
2635        sprintf( Buffer, "@subsection %s", line->Contents );
2636        strcpy( line->Contents, Buffer );
2637        line = (Line_Control *) line->Node.next;
2638        break;
2639
2640      case DESCRIPTION:
2641      case COPYRIGHT:
2642      case PORTING:
2643      case THEORY_OF_OPERATION:
2644      case DEPENDENCIES:
2645      case NOTES:
2646        sprintf( Buffer, "@subheading %s\n", line->Contents );
2647        strcpy( line->Contents, Buffer );
2648        line = (Line_Control *) line->Node.next;
2649
2650        /* now take care of the paragraphs which are here */
2651
2652        in_bullets = FALSE;
2653        do {
2654          line = (Line_Control *) line->Node.next;
2655          if ( line->format == BULLET_OUTPUT ) {
2656            if ( !in_bullets ) {
2657              in_bullets = TRUE;
2658
2659              new_line = AllocateLine();
2660              _Chain_Insert( line->Node.previous, &new_line->Node );
2661
2662              new_line = AllocateLine();
2663              strcpy( new_line->Contents, "@itemize @bullet" );
2664              _Chain_Insert( line->Node.previous, &new_line->Node );
2665            }
2666            sprintf( Buffer, "@item %s\n", line->Contents );
2667            strcpy( line->Contents, Buffer );
2668          } else if ( in_bullets ) {
2669            in_bullets = FALSE;
2670
2671            new_line = AllocateLine();
2672            strcpy( new_line->Contents, "@end itemize" );
2673            _Chain_Insert( line->Node.previous, &new_line->Node );
2674
2675            new_line = AllocateLine();
2676            _Chain_Insert( line->Node.previous, &new_line->Node );
2677          } else {
2678            new_line = AllocateLine();
2679            _Chain_Insert( line->Node.previous, &new_line->Node );
2680          }
2681        } while ( !line->keyword );
2682
2683        break;
2684
2685      case DERIVATION:
2686      case TYPE:
2687      case RANGE:
2688      case UNITS:
2689      case SCALE_FACTOR:
2690      case TOLERANCE:
2691      case VISIBILITY:
2692      case ASSOCIATED_WITH:
2693      case MULTIPLICITY:
2694      case TIMING:
2695        sprintf( Buffer, "@subheading %s\n", line->Contents );
2696        strcpy( line->Contents, Buffer );
2697        line = (Line_Control *) line->Node.next;
2698        break;
2699
2700      case MEMBERS:
2701      case DEFAULT:
2702      case REQUIREMENTS:
2703      case REFERENCES:
2704      case INPUTS:
2705      case OUTPUTS:
2706      case PDL:
2707      case SYNCHRONIZATION:
2708        sprintf( Buffer, "@subheading %s\n", line->Contents );
2709        strcpy( line->Contents, Buffer );
2710
2711        /* now take care of the raw text which is here */
2712
2713        new_line = AllocateLine();
2714        strcpy( new_line->Contents, "@example" );
2715        _Chain_Insert( &line->Node, &new_line->Node );
2716
2717        do {
2718          line = (Line_Control *) line->Node.next;
2719          if ( !strlen( line->Contents ) ) {
2720            new_line = AllocateLine();
2721            strcpy( new_line->Contents, "@end example" );
2722            _Chain_Insert( line->Node.previous, &new_line->Node );
2723
2724            new_line = AllocateLine();
2725            strcpy( new_line->Contents, "@example" );
2726            _Chain_Insert( &line->Node, &new_line->Node );
2727
2728          }
2729        } while ( !line->keyword );
2730
2731        new_line = AllocateLine();
2732        strcpy( new_line->Contents, "@end example" );
2733        _Chain_Insert( line->Node.previous, &new_line->Node );
2734        /* at this point line points to the next keyword */
2735        break;
2736    }   
2737  }
2738
2739bottom:
2740#if 0
2741  for ( i=NUMBER_ELEMENTS( Texinfo_Headers ) - 1 ; i >= 0 ; i-- ) {
2742    new_line = AllocateLine();
2743    strcpy( new_line->Contents, Texinfo_Headers[ i ] );
2744    if ( !strcmp( "@setfilename ", new_line->Contents ) )
2745      strcat( new_line->Contents, ChapterTitle );
2746    else if ( !strcmp( "@settitle ", new_line->Contents ) )
2747      strcat( new_line->Contents, InfoFile );
2748    else if ( !strcmp( "@top ", new_line->Contents ) )
2749      strcat( new_line->Contents, InfoFile );
2750    _Chain_Insert( _Chain_Head( &Lines ), &new_line->Node );
2751  }
2752
2753  /*
2754   *  Remove the special end of object string.  No one wants to see
2755   *  it in the printed output and the node is already marked "END_OBJECT".
2756   */
2757
2758  ((Line_Control *)Lines.last)->Contents[ 0 ] = '\0';
2759
2760  new_line = AllocateLine();
2761  strcpy( new_line->Contents, "@bye" );
2762  _Chain_Append( &Lines, &new_line->Node );
2763
2764#endif
2765  if ( Verbose )
2766    fprintf( stderr, "-------->INSERTING TEXINFO MENUS\n" );
2767
2768  BuildTexinfoNodes();
2769}
2770
2771/*
2772 *  FormatToWord
2773 */
2774
2775void FormatToWord( void )
2776{
2777  Line_Control *line;
2778  Line_Control *new_line;
2779  char          Buffer[ PARAGRAPH_SIZE ];
2780  int           i;
2781  int           length;
2782  char          ChapterTitle[ PARAGRAPH_SIZE ];
2783  char          InfoFile[ PARAGRAPH_SIZE ];
2784  char         *p;
2785  boolean       new_section;
2786  boolean       in_bullets;
2787
2788  for ( line = (Line_Control *) Lines.first ;
2789        !_Chain_Is_last( &line->Node ) ;
2790      ) {
2791
2792    switch ( line->keyword ) {
2793      case UNUSED:
2794        line = (Line_Control *) line->Node.next;
2795        break;
2796
2797      case OBJECT:
2798        LineCopyFromRight( line, ChapterTitle );
2799        strcpy( InfoFile, ChapterTitle );
2800
2801        for ( p=InfoFile ; *p ; *p++ )   /* turn this into a file name */
2802          if ( isspace( *p ) )
2803            *p = '_';             
2804
2805        sprintf( Buffer, "@Chapter = %s", line->Contents );
2806        strcpy( line->Contents, Buffer );
2807        line = (Line_Control *) line->Node.next;
2808        break;
2809
2810      case ATTRIBUTE_DESCRIPTIONS:
2811      case ASSOCIATION_DESCRIPTIONS:
2812      case ABSTRACT_TYPE_DESCRIPTIONS:
2813      case DATA_ITEM_DESCRIPTIONS:
2814      case METHOD_DESCRIPTIONS:
2815      case TASK_DESCRIPTIONS:
2816        sprintf( Buffer, "@Section = %s", line->Contents );
2817        strcpy( line->Contents, Buffer );
2818
2819        new_line = AllocateLine();
2820        strcpy( new_line->Contents, "@Page" );
2821        _Chain_Insert( line->Node.previous, &new_line->Node );
2822
2823        line = (Line_Control *) line->Node.next;
2824        new_section = TRUE;
2825        break;
2826
2827      case END_OBJECT:
2828        line->Contents[ 0 ] = '\0';
2829        goto bottom;
2830
2831      case ATTRIBUTE:
2832      case ASSOCIATION:
2833      case ABSTRACT_TYPE:
2834      case DATA_ITEM:
2835        if ( !new_section ) {
2836          /*
2837           *  Do something with the style to keep subsection
2838           *  contents together
2839           */
2840          ;
2841        }
2842        new_section = FALSE;
2843        sprintf( Buffer, "@Subsection = %s", line->Contents );
2844        strcpy( line->Contents, Buffer );
2845        line = (Line_Control *) line->Node.next;
2846        break;
2847
2848      case METHOD:
2849      case TASK:
2850        if ( !new_section ) {
2851          new_line = AllocateLine();
2852          strcpy( new_line->Contents, "@Page" );
2853          _Chain_Insert( line->Node.previous, &new_line->Node );
2854        }
2855        new_section = FALSE;
2856        sprintf( Buffer, "@Subsection = %s", line->Contents );
2857        strcpy( line->Contents, Buffer );
2858        line = (Line_Control *) line->Node.next;
2859        break;
2860
2861      case DESCRIPTION:
2862      case COPYRIGHT:
2863      case PORTING:
2864      case THEORY_OF_OPERATION:
2865      case DEPENDENCIES:
2866      case NOTES:
2867        sprintf( Buffer, "@Subheading = %s\n", line->Contents );
2868        strcpy( line->Contents, Buffer );
2869        line = (Line_Control *) line->Node.next;
2870
2871        /* now take care of the paragraphs which are here */
2872
2873        in_bullets = FALSE;
2874        do {
2875          line = (Line_Control *) line->Node.next;
2876          if ( line->format == BULLET_OUTPUT ) {
2877            if ( !in_bullets ) {
2878              in_bullets = TRUE;
2879
2880              new_line = AllocateLine();
2881              _Chain_Insert( line->Node.previous, &new_line->Node );
2882            }
2883            sprintf( Buffer, "@Bullet = %s\n", line->Contents );
2884            strcpy( line->Contents, Buffer );
2885          } else if ( in_bullets ) {
2886            in_bullets = FALSE;
2887
2888            new_line = AllocateLine();
2889            _Chain_Insert( line->Node.previous, &new_line->Node );
2890          } else {
2891            new_line = AllocateLine();
2892            _Chain_Insert( line->Node.previous, &new_line->Node );
2893          }
2894        } while ( !line->keyword );
2895
2896        break;
2897
2898      case DERIVATION:
2899      case TYPE:
2900      case RANGE:
2901      case UNITS:
2902      case SCALE_FACTOR:
2903      case TOLERANCE:
2904      case VISIBILITY:
2905      case ASSOCIATED_WITH:
2906      case MULTIPLICITY:
2907      case TIMING:
2908        sprintf( Buffer, "@Subheading = %s\n", line->Contents );
2909        strcpy( line->Contents, Buffer );
2910        line = (Line_Control *) line->Node.next;
2911        break;
2912
2913      case MEMBERS:
2914      case DEFAULT:
2915      case REQUIREMENTS:
2916      case REFERENCES:
2917      case INPUTS:
2918      case OUTPUTS:
2919      case PDL:
2920      case SYNCHRONIZATION:
2921        sprintf( Buffer, "@Subheading = %s\n", line->Contents );
2922        strcpy( line->Contents, Buffer );
2923        line = (Line_Control *) line->Node.next;
2924
2925        /* now take care of the raw text which is here */
2926
2927#if 0
2928        while ( !line->keyword ) {
2929          sprintf( Buffer, "@Example = %s\n", line->Contents );
2930          strcpy( line->Contents, Buffer );
2931          line = (Line_Control *) line->Node.next;
2932        }
2933
2934        /* at this point line points to the next keyword */
2935#endif
2936
2937        /* now take care of the raw text which is here */
2938
2939        new_line = AllocateLine();
2940        _Chain_Insert( line->Node.previous, &new_line->Node );
2941        strcpy( new_line->Contents, "@Example = " );
2942
2943        do {
2944          if ( strlen( line->Contents ) ) {
2945            new_line->keyword = line->keyword;
2946            new_line->format = line->format;
2947            length = strlen(new_line->Contents);
2948            if ( (length + strlen(line->Contents) + 12) > PARAGRAPH_SIZE ) {
2949              fprintf( stderr, "Output line too long at %d\n", line->number );
2950              exit_application( 1 );
2951            }
2952
2953            strcat( new_line->Contents, line->Contents );
2954            strcat( new_line->Contents, "<@ManualCR>" );
2955            line = DeleteLine( line );
2956          } else {
2957            line = (Line_Control *) line->Node.next;
2958            new_line = AllocateLine();
2959            _Chain_Insert( line->Node.previous, &new_line->Node );
2960            strcpy( new_line->Contents, "@Example = " );
2961          }
2962        } while ( !line->keyword );
2963
2964        /* at this point line points to the next keyword */
2965        break;
2966    }   
2967  }
2968
2969bottom:
2970}
2971
2972/*
2973 *  PrintFile
2974 */
2975
2976void PrintFile(
2977  char *out
2978)
2979{
2980  Line_Control *line;
2981
2982  OutFile = fopen( out, "w+" );
2983
2984  if ( !OutFile ) {
2985    fprintf( stderr, "Unable to open (%s) for output\n", out );
2986    exit_application( 1 );
2987  }
2988  assert( OutFile );
2989
2990  for ( line = (Line_Control *) Lines.first ;
2991        !_Chain_Is_last( &line->Node ) ;
2992        line = (Line_Control *) line->Node.next ) {
2993    fprintf( OutFile, "%s\n", line->Contents );
2994/*
2995    fprintf(
2996      OutFile,
2997      "(%d,%d)%s\n",
2998      line->keyword,
2999      line->format,
3000      line->Contents
3001    );
3002*/
3003  }
3004}
3005
3006/*
3007 *  DumpList
3008 */
3009
3010void DumpList(
3011  Chain_Control  *the_list
3012)
3013{
3014  Line_Control  *line;
3015
3016  fprintf( stderr, "---> Dumping list (%p)\n", the_list );
3017
3018  for ( line = (Line_Control *) the_list->first ;
3019      !_Chain_Is_last( &line->Node ) ;
3020      line = (Line_Control *) line->Node.next ) {
3021    fprintf( stderr, "%s\n", line->Contents );
3022  }
3023}
3024
3025/*
3026 * ReleaseFile
3027 */
3028
3029void ReleaseFile()
3030{
3031   Line_Control *line;
3032   Line_Control *next;
3033
3034   for ( line = (Line_Control *) Lines.first ;
3035         !_Chain_Is_last( &line->Node ) ;
3036       ) {
3037     next = (Line_Control *) line->Node.next;
3038     line = next;
3039   }
3040}
3041
3042/*
3043 *  strtoInitialCaps
3044 */
3045
3046void strtoInitialCaps(
3047  char *dest,
3048  char *src
3049)
3050{
3051  char *source = src;
3052  char *destination = dest;
3053
3054  if ( !dest )
3055    return;
3056  strcpy( dest, src );
3057#if 0
3058  source = src;
3059  destination = (dest) ? dest : src;
3060
3061  while ( *source ) {
3062    while ( isspace( *source ) )
3063      *destination++ = *source++;
3064
3065    if ( !*source )
3066      break;
3067
3068    *destination++ = toupper( *source++ );
3069
3070    for ( ; *source && !isspace( *source ) ; source++ )
3071      *destination++ = tolower( *source );
3072     
3073    if ( !*source )
3074      break;
3075  }
3076
3077  *destination = '\0';
3078#endif
3079}
3080
3081/*
3082 *  Validate_visibility
3083 */
3084 
3085char *Valid_visibilities[] = {
3086  "public",
3087  "private"
3088};
3089 
3090int Validate_visibility(
3091  Line_Control   *line
3092)
3093{
3094  char   *s;
3095  char   *d;
3096  char    Buffer[ BUFFER_SIZE ];
3097  char    Visibility[ BUFFER_SIZE ];
3098  int     i;
3099  boolean found;
3100  int     errors = 0;
3101 
3102  LineCopyFromRight( line, Buffer );
3103 
3104  memset( Visibility, '\0', sizeof( Visibility ) );
3105  s = Buffer;
3106 
3107  for ( d=Visibility ; ; s++, d++ ) {
3108    *d = *s;
3109    if ( !*s || isspace(*s) )
3110      break;
3111  }
3112  *d = '\0';
3113 
3114  if ( isspace(*s) ) {
3115    fprintf(
3116       stderr,
3117       "Unexpected white space on line %d -- are there multiple words?\n",
3118       line->number
3119     );
3120     errors++;
3121  }
3122 
3123  /*
3124   *  Check out the type part of this keyword
3125   */
3126 
3127  for ( found=FALSE, i=0 ; i<NUMBER_ELEMENTS(Valid_visibilities) ; i++ ) {
3128    if ( !strcmp( Valid_visibilities[ i ], Visibility ) ) {
3129      found = TRUE;
3130      break;
3131    }
3132  }
3133 
3134  if ( !found ) {
3135    if ( !(InsertTBDs && !strcmp( Visibility, "TBD" )) ) {
3136      fprintf(
3137        stderr,
3138        "Invalid visibility type (%s) on line %d\n",
3139        Visibility,
3140        line->number
3141      );
3142      errors++;
3143    }
3144  }
3145 
3146  return (errors) ? -1 : 0;
3147}
3148
3149/*
3150 *  Validate_synchronization
3151 */
3152 
3153char *Valid_synchronization[] = {
3154  "delay",
3155  "event",
3156  "mutex",
3157  "semaphore",
3158  "message",
3159  "signal",
3160  "period"
3161};
3162 
3163boolean Valid_synchronization_text_below[] = {
3164  FALSE,   /* delay */
3165  TRUE,    /* event */
3166  TRUE,    /* mutex */
3167  TRUE,    /* semaphore */
3168  TRUE,    /* message */
3169  TRUE,    /* signal */
3170  FALSE    /* period */
3171};
3172
3173int Validate_synchronization(
3174  Line_Control   *line
3175)
3176{
3177  char   *s;
3178  char   *d;
3179  char    Buffer[ BUFFER_SIZE ];
3180  char    Synchronization[ BUFFER_SIZE ];
3181  int     i;
3182  boolean found;
3183  int     errors = 0;
3184 
3185  LineCopyFromRight( line, Buffer );
3186 
3187  memset( Synchronization, '\0', sizeof( Synchronization ) );
3188  s = Buffer;
3189 
3190  for ( d=Synchronization ; ; s++, d++ ) {
3191    *d = *s;
3192    if ( !*s || isspace(*s) )
3193      break;
3194  }
3195  *d = '\0';
3196 
3197  if ( isspace(*s) ) {
3198    fprintf(
3199       stderr,
3200       "Unexpected white space on line %d -- invalid use of multiple words\n",
3201       line->number
3202     );
3203     errors++;
3204  }
3205 
3206  /*
3207   *  Check out the type part of this keyword
3208   */
3209 
3210  for ( found=FALSE, i=0 ; i<NUMBER_ELEMENTS(Valid_synchronization) ; i++ ) {
3211    if ( !strcmp( Valid_synchronization[ i ], Synchronization ) ) {
3212      found = TRUE;
3213      break;
3214    }
3215  }
3216 
3217  if ( !found ) {
3218    fprintf(
3219       stderr,
3220       "Invalid synchronization type (%s) on line %d\n",
3221       Synchronization,
3222       line->number
3223     );
3224     errors++;
3225  }
3226
3227  if ( line->keyword && !Valid_synchronization_text_below[ i ] ) {
3228    fprintf(
3229       stderr,
3230       "Expected text below synchronization type (%s) on line %d\n",
3231       Synchronization,
3232       line->number
3233     );
3234     errors++;
3235  }
3236 
3237  return (errors) ? -1 : 0;
3238}
3239
3240/*
3241 *  Validate_abstract_type
3242 *
3243 * presence of range or members but not both
3244 */
3245
3246int Validate_abstract_type(
3247  Section_info_t *section,
3248  Line_Control   *start,
3249  Line_Control   *next_section
3250)
3251{
3252  boolean       range_found = FALSE;
3253  boolean       members_found = FALSE;
3254  boolean       enumerated_found = FALSE;
3255  boolean       true_found = FALSE;
3256  boolean       false_found = FALSE;
3257  Line_Control *line;
3258  int           errors = 0;
3259
3260  for ( line = start;
3261        line != next_section ;
3262        line = (Line_Control *) line->Node.next ) {
3263    if ( line->keyword == RANGE )
3264      range_found = TRUE;
3265    else if ( line->keyword == MEMBERS ) {
3266      members_found = TRUE;
3267    } else if ( line->keyword == TYPE || line->keyword == DERIVATION ) {
3268      if ( strstr( line->Contents, "enumerated" ) ||
3269           strstr( line->Contents, "structure" ) )
3270        enumerated_found = TRUE;
3271    }
3272  }
3273
3274  if ( !range_found && !members_found ) {
3275    fprintf(
3276       stderr,
3277       "Neither range nor members keyword present in "
3278         "subsection starting at line %d\n",
3279       start->number
3280     );
3281     errors++;
3282  }
3283
3284  if ( !InsertTBDs ) {
3285    if ( range_found && members_found ) {
3286      fprintf(
3287         stderr,
3288         "Both range and members keyword present in "
3289           "subsection starting at line %d\n",
3290         start->number
3291       );
3292       errors++;
3293    }
3294  } 
3295
3296  if ( enumerated_found  && !members_found ) {
3297    fprintf(
3298       stderr,
3299       "Enumerated type without list of members in "
3300         "subsection starting at line %d\n",
3301       start->number
3302     );
3303     errors++;
3304  }
3305
3306  if ( !enumerated_found  && !range_found ) {
3307    fprintf(
3308       stderr,
3309       "Type does not have range specified in "
3310         "subsection starting at line %d\n",
3311       start->number
3312     );
3313     errors++;
3314  }
3315
3316  return (errors) ? -1 : 0;
3317}
3318
3319/*
3320 *  Validate_attribute
3321 *
3322 * presence of range or members but not both
3323 */
3324 
3325int Validate_attribute(
3326  Section_info_t *section,
3327  Line_Control   *start,
3328  Line_Control   *next_section
3329)
3330{
3331  boolean       range_found = FALSE;
3332  boolean       members_found = FALSE;
3333  boolean       enumerated_found = FALSE;
3334  boolean       boolean_found = FALSE;
3335  boolean       true_found = FALSE;
3336  boolean       false_found = FALSE;
3337  Line_Control *line;
3338  int           errors = 0;
3339 
3340  for ( line = start;
3341        line != next_section ;
3342        line = (Line_Control *) line->Node.next ) {
3343    if ( line->keyword == RANGE )
3344      range_found = TRUE;
3345    else if ( line->keyword == MEMBERS ) {
3346      members_found = TRUE;
3347      if ( boolean_found == TRUE ) {
3348        line = (Line_Control *) line->Node.next;
3349        while ( !_Chain_Is_last( &line->Node ) ) {
3350          if ( line->keyword )
3351            break;
3352          if ( strstr( line->Contents, "FALSE" ) )
3353            false_found = TRUE;
3354          else if ( strstr( line->Contents, "TRUE" ) )
3355            true_found = TRUE;
3356          line = (Line_Control *) line->Node.next;
3357        }
3358        line = (Line_Control *) line->Node.previous;
3359      }
3360    } else if ( line->keyword == TYPE || line->keyword == DERIVATION ) {
3361      if ( strstr( line->Contents, "enumerated" ) )
3362        enumerated_found = TRUE;
3363      else if ( strstr( line->Contents, "boolean" ) ) {
3364        enumerated_found = TRUE;
3365        boolean_found = TRUE;
3366      }
3367    }
3368  }
3369 
3370  if ( !range_found && !members_found ) {
3371    fprintf(
3372       stderr,
3373       "Neither range nor members keyword present in "
3374         "subsection starting at line %d\n",
3375       start->number
3376     );
3377     errors++;
3378  }
3379 
3380  if ( !InsertTBDs ) {
3381    if ( range_found && members_found ) {
3382      fprintf(
3383         stderr,
3384         "Both range and members keyword present in "
3385           "subsection starting at line %d\n",
3386         start->number
3387       );
3388       errors++;
3389    }
3390  }
3391 
3392  if ( enumerated_found  && !members_found ) {
3393    fprintf(
3394       stderr,
3395       "Enumerated type without list of members in "
3396         "subsection starting at line %d\n",
3397       start->number
3398     );
3399     errors++;
3400  }
3401 
3402  if ( !enumerated_found  && !range_found ) {
3403    fprintf(
3404       stderr,
3405       "Type does not have range specified in "
3406         "subsection starting at line %d\n",
3407       start->number
3408     );
3409     errors++;
3410  }
3411 
3412  if ( boolean_found && !true_found ) {
3413    fprintf(
3414       stderr,
3415       "Boolean without a TRUE case specified in "
3416         "subsection starting at line %d\n",
3417       start->number
3418     );
3419     errors++;
3420  }
3421 
3422  if ( boolean_found && !false_found ) {
3423    fprintf(
3424       stderr,
3425       "Boolean without a FALSE case specified in "
3426         "subsection starting at line %d\n",
3427       start->number
3428     );
3429     errors++;
3430  }
3431 
3432  return (errors) ? -1 : 0;
3433}
3434
3435/*
3436 *  Validate_object
3437 *
3438 * presence of range or members but not both
3439 */
3440 
3441int Validate_object(
3442  Section_info_t *section,
3443  Line_Control   *start,
3444  Line_Control   *next_section
3445)
3446{
3447  char          ObjectName[ BUFFER_SIZE ];
3448  char          EndObjectName[ BUFFER_SIZE ];
3449  Line_Control *line;
3450  int           errors = 0;
3451 
3452 
3453  LineCopyFromRight( start, ObjectName );
3454
3455  for ( line = start;
3456        !_Chain_Is_last( &line->Node ) ;
3457        line = (Line_Control *) line->Node.next ) {
3458    if ( line->keyword == END_OBJECT ) {
3459      LineCopyFromRight( line, EndObjectName );
3460      break;
3461    }
3462  }
3463 
3464  if ( strcmp( ObjectName, EndObjectName ) ) {
3465    fprintf(
3466       stderr,
3467       "Object and End Object names do not match\n"
3468     );
3469     errors++;
3470  }
3471
3472  return (errors) ? -1 : 0;
3473}
3474
Note: See TracBrowser for help on using the repository browser.