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

4.104.114.84.95
Last change on this file since d4bc481 was d4bc481, checked in by Joel Sherrill <joel.sherrill@…>, on 06/16/97 at 21:30:07

Initial revision

  • Property mode set to 100644
File size: 78.6 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( status );
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  IncompletesAreErrors = TRUE;
991  InsertTBDs = FALSE;
992
993  while ((c = getopt(argc, argv, "istv?n:p:u:")) != EOF) {
994    switch (c) {
995      case 'i':
996        IncompletesAreErrors = FALSE;
997        break;
998      case 't':
999        InsertTBDs = TRUE;
1000        break;
1001      case 'v':
1002        Verbose = TRUE;
1003        break;
1004      case 'n':
1005         strcpy( DocsNextNode, optarg );
1006         break;
1007      case 'p':
1008         strcpy( DocsPreviousNode, optarg );
1009         break;
1010      case 'u':
1011         strcpy( DocsUpNode, optarg );
1012         break;
1013      case 's':
1014         Statistics = TRUE;
1015         break;
1016      case '?':
1017        usage();
1018        return 0;
1019    }
1020  }
1021
1022  if ( Verbose ) {
1023    fprintf( stderr, "Arguments successfully parsed\n" );
1024    fprintf( stderr, "Next Node = (%s)\n", DocsNextNode );
1025    fprintf( stderr, "Previous Node = (%s)\n", DocsPreviousNode );
1026    fprintf( stderr, "Up Node = (%s)\n", DocsUpNode );
1027  }
1028
1029  FillLinePool();
1030
1031  for ( index=optind ; index < argc ; index++ ) {
1032    ProcessFile( argv[ index ], NULL );
1033  }
1034   
1035  if ( Verbose )
1036    fprintf( stderr, "Exitting\n" );
1037
1038  return 0;
1039}
1040
1041/*
1042 *  ProcessFile
1043 */
1044
1045void ProcessFile(
1046  char   *inname,
1047  char   *outname
1048)
1049{
1050   char            out[ 256 ];
1051   int             index;
1052   int             out_index;
1053
1054   /*
1055    *  Automatically generate the output file name.
1056    */
1057
1058   if ( outname == NULL ) {
1059     out_index = 0;
1060     for( index=0 ; inname[index] && inname[index] != '.' ; index++ ) {
1061/*
1062       if ( inname[ index ] != '_' )
1063*/
1064         out[ out_index++ ] = inname[ index ];
1065     }
1066
1067     out[ out_index++ ] = '.';
1068     out[ out_index++ ] = 't';
1069     out[ out_index++ ] = 'e';
1070     out[ out_index++ ] = 'x';
1071     out[ out_index++ ] = 'i';
1072     out[ out_index ] = '\0';
1073
1074   }
1075
1076   /*
1077    *  Read the file into our internal data structure
1078    */
1079
1080   if ( Verbose )
1081     printf( "Processing (%s) -> (%s)\n", inname, out );
1082
1083   ReadFileIntoChain( inname );
1084
1085   if ( Verbose )
1086     fprintf( stderr, "-------->FILE READ IN\n" );
1087
1088   /*
1089    *  Remove any spaces before the keyword and mark each keyword line as
1090    *  such.  Also remove extra white space at the end of lines.
1091    */
1092
1093   StripBlanks();
1094
1095   if ( Verbose )
1096     fprintf( stderr, "-------->BLANKS BEFORE KEYWORDS STRIPPED\n" );
1097
1098   /*
1099    *  Count the number of each type of thing
1100    */
1101
1102   NumberOfAttributes    = CountKeywordOccurrences( ATTRIBUTE );
1103   NumberOfAssociations  = CountKeywordOccurrences( ASSOCIATION );
1104   NumberOfAbstractTypes = CountKeywordOccurrences( ABSTRACT_TYPE );
1105   NumberOfDataItems     = CountKeywordOccurrences( DATA_ITEM );
1106   NumberOfMethods       = CountKeywordOccurrences( METHOD );
1107   NumberOfTasks         = CountKeywordOccurrences( TASK );
1108
1109   if ( Verbose || Statistics ) {
1110     fprintf( stderr, "NUMBER OF ATTRIBUTES = %d\n", NumberOfAttributes );
1111     fprintf( stderr, "NUMBER OF ASSOCIATIONS = %d\n", NumberOfAssociations );
1112     fprintf( stderr, "NUMBER OF ABSTRACT TYPES = %d\n", NumberOfAbstractTypes);
1113     fprintf( stderr, "NUMBER OF DATA ITEMS = %d\n", NumberOfDataItems );
1114     fprintf( stderr, "NUMBER OF METHODS = %d\n", NumberOfMethods );
1115     fprintf( stderr, "NUMBER OF TASKS = %d\n", NumberOfTasks );
1116   }
1117
1118   /*
1119    *  1.  Merge paragraphs entered as multiple lines into a single node
1120    *      on the chain.
1121    *  2.  Clean up "colon lines".
1122    */
1123
1124   if ( MergeText() == -1 )
1125     exit_application( 1 );
1126
1127   if ( Verbose )
1128     fprintf( stderr, "-------->PARAGRAPHS MERGED\n" );
1129
1130   RemovePagebreaks();
1131   
1132   /*
1133    *  Remove extraneous white space
1134    */
1135
1136   if ( Verbose )
1137     fprintf( stderr, "-------->PAGEBREAKS REMOVED\n" );
1138
1139   /*
1140    *  At this point, the only unmarked lines should be empty or errors.
1141    *  This deletes empty unmarked lines and flags the others as errors.
1142    */
1143
1144   if ( RemoveExtraBlankLines() == -1 )
1145     exit_application( 1 );
1146 
1147   if ( Verbose )
1148     fprintf( stderr, "-------->EXTRA BLANK LINES REMOVED\n" );
1149
1150   /*
1151    *  Now report which lines do not appear to be complete
1152    */
1153
1154   if ( CheckForIncomplete() == -1 )
1155     exit_application( 1 );
1156
1157   if ( Verbose )
1158     fprintf( stderr, "-------->CHECKED FOR INCOMPLETE KEYWORDS\n" );
1159
1160   /*
1161    *  Check that all the required sections are present.
1162    */
1163
1164   if ( CheckOutline() == -1 )
1165     exit_application( 1 );
1166 
1167   if ( Verbose )
1168     fprintf( stderr, "-------->CHECKED FOR HIGH LEVEL SECTION PROBLEMS\n" );
1169
1170   /*
1171    *  Check for problems in each section.
1172    */
1173
1174   if ( CheckSections() == -1 )
1175     exit_application( 1 );
1176
1177   if ( Verbose )
1178     fprintf( stderr, "-------->CHECKED FOR INTERNAL SECTION PROBLEMS\n" );
1179
1180   /*
1181    *  Look for Internal Consistencies
1182    */
1183
1184   if ( Verbose )
1185     fprintf( stderr, "-------->LOOKING FOR ERRORS\n" );
1186
1187   LookForInternalInconsistencies();
1188
1189   /*
1190    *  Formatting the file
1191    */
1192
1193   FormatToTexinfo();
1194
1195   if ( Verbose )
1196     fprintf( stderr, "-------->FILE FORMATTED TO TEXINFO\n" );
1197
1198   /*
1199    *  Print the file
1200    */
1201
1202   PrintFile( out );
1203
1204   if ( Verbose )
1205     fprintf( stderr, "-------->FILE PRINTED\n" );
1206
1207   /*
1208    *  Clean Up
1209    */
1210
1211   ReleaseFile();
1212
1213   if ( Verbose )
1214     fprintf( stderr, "-------->FILE RELEASED\n" );
1215}
1216
1217/*
1218 *  LookForInternalInconsistencies
1219 *
1220 *  This routine looks for lines with no formatting information and
1221 *  lines with too much formatting information.
1222 */
1223
1224void LookForInternalInconsistencies( void )
1225{
1226  Line_Control  *line;
1227  int            i;
1228  int            errors = 0;
1229  char          *src;
1230
1231  for ( line = (Line_Control *) Lines.first ;
1232        !_Chain_Is_last( &line->Node ) ;
1233        line = (Line_Control *)line->Node.next
1234        ) {
1235    if ( !line->keyword && line->format == NO_EXTRA_FORMATTING_INFO ) {
1236      fprintf(
1237        stderr,
1238        "\nLine %d has no keyword or formatting:\n",
1239        line->number
1240      );
1241      PrintSurroundingLines( line, 3,  3 );
1242      errors++;
1243    }
1244  }
1245 
1246  if ( errors )
1247    exit_application( 1 );
1248}
1249
1250/*
1251 *  usage
1252 */
1253
1254void usage( void )
1255{
1256  int index;
1257
1258  for ( index=0 ; strcmp( Usage_Strings[ index ], "EOF" ) ; index++ )
1259    fprintf( stderr, Usage_Strings[ index ] );
1260}
1261
1262/*
1263 *  ReadFileIntoChain
1264 */
1265
1266void ReadFileIntoChain(
1267  char *inname
1268)
1269{
1270   FILE *InFile;
1271   int   line_count;
1272   int   max_length;
1273   char *line;
1274   char  Buffer[ BUFFER_SIZE ];
1275   Line_Control *new_line;
1276
1277   InFile = fopen( inname, "r" );
1278
1279   if ( !InFile ) {
1280     fprintf( stderr, "Unable to open (%s)\n", inname );
1281     exit( 1 );
1282   }
1283   assert( InFile );
1284
1285   max_length = 0;
1286   line_count = 0;
1287
1288   _Chain_Initialize_empty( &Lines );
1289
1290   for ( ;; ) {
1291      line = fgets( Buffer, BUFFER_SIZE, InFile );
1292      if ( !line )
1293        break;
1294
1295      Buffer[ strlen( Buffer ) - 1 ] = '\0';
1296
1297      new_line = AllocateLine();
1298 
1299      strcpy( new_line->Contents, Buffer );
1300
1301      new_line->number = ++line_count;
1302 
1303      _Chain_Append( &Lines, &new_line->Node );
1304   }
1305
1306   fclose( InFile );
1307}
1308
1309/*
1310 *  StripBlanks
1311 */
1312
1313void StripBlanks( void )
1314{
1315  Line_Control      *line;
1316  Keyword_indices_t  index;
1317  int                indentation;
1318  int                length;
1319  Keyword_info_t    *key;
1320 
1321  for ( line = (Line_Control *) Lines.first ;
1322        !_Chain_Is_last( &line->Node ) ;
1323        line = (Line_Control *) line->Node.next
1324        ) {
1325
1326    /*
1327     *  Strip white space from the end of each line
1328     */
1329
1330    length = strlen( line->Contents );
1331
1332    while ( isspace( line->Contents[ --length ] ) )
1333      line->Contents[ length ] = '\0';
1334
1335    /*
1336     *  Strip white space from the front of each keyword line.
1337     */
1338
1339    for ( index=KEYWORD_FIRST ; index <= KEYWORD_LAST ; index++ ) {
1340      key = &Keywords[ index ];
1341
1342      switch ( key->level ) {
1343        case SECTION:    indentation = 0; break;
1344        case SUBSECTION: indentation = 0; break;
1345        case HEADING:    indentation = 2; break;
1346        default:         assert( FALSE );
1347      }
1348
1349      if ( !strncmp( &line->Contents[ indentation ], key->Name,
1350                    strlen( key->Name ) ) ) {
1351        if ( indentation )
1352          strcpy( line->Contents,  &line->Contents[ indentation ] );
1353        line->keyword = index;
1354        break;
1355      }
1356    }
1357  }
1358}
1359
1360/*
1361 *  CrunchRight
1362 */
1363
1364boolean CrunchRight(
1365  Line_Control *line
1366)
1367{
1368  char  Buffer[ PARAGRAPH_SIZE ];
1369  char *src;
1370  char *dest;
1371  boolean is_text_to_right = FALSE;
1372
1373  src  = line->Contents;
1374  dest = Buffer;
1375
1376  while( *src != ':' ) {
1377    if ( !*src ) {
1378      fprintf(
1379        stderr,
1380        "Line %d should have had a colon\n",
1381        line->number
1382      );
1383      exit_application( 1 );
1384    }
1385    *dest++ = *src++;
1386  }
1387 
1388  *dest++ = *src++;    /* this is the ':' */
1389 
1390  if ( *src ) {
1391    *dest++ = ' ';
1392    while ( *src && isspace( *src ) )
1393      src++;
1394 
1395    if ( *src )
1396      is_text_to_right = TRUE;
1397 
1398    while ( *src )
1399      *dest++ = *src++;
1400  }
1401 
1402  *dest = '\0';
1403
1404  strcpy( line->Contents, Buffer );
1405
1406  return is_text_to_right;
1407}
1408
1409/*
1410 *  CrunchBelow
1411 */
1412
1413void CrunchBelow(
1414  Line_Control          *start_line,
1415  Keywords_text_below_t  text_below_mode
1416)
1417{
1418  Line_Control      *line;
1419  int                i;
1420  int                leading_white;
1421  int                length;
1422 
1423  switch ( text_below_mode ) {
1424    case BL_FORBIDDEN:
1425      assert( FALSE );
1426    case BL_FORMATTED:
1427      (void) FormatMultipleParagraphs( start_line );
1428      break;
1429    case BL_RAW:
1430      for ( line = (Line_Control *) start_line->Node.next;
1431            !_Chain_Is_last( &line->Node ) ;
1432          ) {
1433         if ( strlen( line->Contents ) )
1434           break;
1435         line = DeleteLine( line );
1436      } 
1437
1438      for ( i=0 ; isspace( line->Contents[ i ] ) ; i++ )
1439        ;
1440     
1441      leading_white = i;
1442
1443      for ( ;
1444            !_Chain_Is_last( &line->Node ) ;
1445            ) {
1446 
1447         assert( line );
1448
1449         if ( line->keyword )
1450           break;
1451
1452         assert( !_Chain_Is_last( &line->Node ) );
1453
1454         length = strlen( line->Contents );
1455
1456         if ( length ) {
1457           if ( length < leading_white ) {
1458             fprintf(
1459               stderr,
1460               "\nLine %d %s:\n",
1461               line->number,
1462               "has inconsistent spacing -- is too short -- see 1st line of text"
1463             );
1464             PrintSurroundingLines( line, 0,  0 );
1465             fprintf( stderr, "\n" );
1466
1467           }
1468           for ( i=0 ; i < leading_white ; i++ ) {
1469             if ( !isspace( line->Contents[ i ] ) ) {
1470               fprintf(
1471                 stderr,
1472                 "\nLine %d %s:\n",
1473                 line->number,
1474                 "has inconsistent spacing -- see 1st line of text"
1475               );
1476               PrintSurroundingLines( line, 0,  0 );
1477               fprintf( stderr, "\n" );
1478               break;
1479             }
1480           }
1481
1482           strcpy( line->Contents, &line->Contents[ leading_white ] );
1483
1484           SetLineFormat( line, RAW_OUTPUT );
1485           line = (Line_Control *) line->Node.next;
1486         } else {
1487           SetLineFormat( line, RAW_OUTPUT );
1488           /* line = DeleteLine( line ); */
1489           line = (Line_Control *) line->Node.next;
1490         }
1491      }
1492      break;
1493  }
1494}
1495
1496/*
1497 *  MergeText
1498 */
1499 
1500/* XXX expand this and address the error numbers */
1501char *Format_Errors[] = {
1502  /* unused */             "no formatting error",
1503  /* RT_FORBIDDEN     */   "no text allowed to right or below",
1504  /* RT_OPTIONAL      */   "text to right optional -- none below",
1505  /* RT_NONE          */   "text to right is \"none\" or nothing -- none below",
1506  /* RT_REQUIRED      */   "text to right required -- none below",
1507  /* RT_BELOW         */   "text to right forbidden -- text below required",
1508  /* RT_NONE_OR_BELOW */   "text to right is \"none\" OR there is text below",
1509  /* RT_MAYBE_BELOW   */   "text to right required -- text below optional",
1510  /* RT_EITHER        */   "text to right OR below",
1511  /* RT_BOTH          */   "text to right AND below"
1512};
1513
1514
1515int MergeText( void )
1516{
1517  Line_Control      *line;
1518  Line_Control      *next;
1519  Line_Control      *new_line;
1520  Keyword_info_t    *key;
1521  boolean            is_text_to_right;
1522  boolean            is_text_below;
1523  boolean            add_text_to_right;
1524  boolean            add_text_below;
1525  int                errors = 0;
1526  int                error_code = 0;
1527 
1528  for ( line = (Line_Control *) Lines.first ;
1529        !_Chain_Is_last( &line->Node ) ;
1530        ) {
1531 
1532    if ( error_code ) {
1533
1534      fprintf(
1535        stderr,
1536        "\nLine %d %s:\n",
1537        line->number,
1538        Format_Errors[ error_code ]
1539      );
1540      PrintSurroundingLines( line, 0,  3 );
1541      fprintf( stderr, "\n" );
1542      error_code = 0;
1543      line = (Line_Control *) line->Node.next;
1544    }
1545
1546    key = &Keywords[ line->keyword ];
1547
1548    if ( !line->keyword ) {
1549      line = (Line_Control *) line->Node.next;
1550      continue;
1551    }
1552
1553    /*
1554     *  Figure out where the text is for this keyword.  It is a pretty
1555     *  ugly thing to look ahead for text below because of intermediate
1556     *  blank lines which we are not allowed to remove.
1557     */
1558
1559    add_text_to_right = FALSE;
1560    add_text_below = FALSE;
1561
1562    is_text_to_right = CrunchRight( line );
1563
1564    is_text_below = FALSE;
1565
1566    for ( next = (Line_Control *) line->Node.next ;
1567          !_Chain_Is_last( &next->Node ) ;
1568          next = (Line_Control *) next->Node.next ) {
1569
1570      if ( next->keyword )
1571        break;
1572
1573      if ( strlen( next->Contents ) ) {
1574        is_text_below = TRUE;
1575        break;
1576      }
1577    }
1578
1579    switch ( key->text_mode ) {
1580      case RT_FORBIDDEN: /* no text to right or below allowed */
1581        if ( is_text_to_right || is_text_below ) {
1582          error_code = 1;
1583          errors++;
1584          continue;
1585        }
1586        break;
1587
1588      case RT_OPTIONAL:  /* text to right optional -- none below */
1589        if ( is_text_below ) {
1590          error_code = 2;
1591          errors++;
1592          continue;
1593        }
1594        break;
1595
1596      case RT_NONE:      /* text to right is "none" or nothing -- none below */
1597        if ( (is_text_to_right && !strstr( line->Contents, "none" )) ||
1598             is_text_below ) {
1599          error_code = 3;
1600          errors++;
1601          continue;
1602        }
1603        break;
1604
1605      case RT_REQUIRED:  /* text to right required -- none below */
1606        if ( is_text_below ) {
1607          error_code = 4;
1608          errors++;
1609          continue;
1610        }
1611
1612        if ( !is_text_to_right ) {
1613          if ( !InsertTBDs ) {
1614            error_code = 4;
1615            errors++;
1616            continue;
1617          } else
1618            add_text_to_right = TRUE;
1619        }
1620        break;
1621
1622      case RT_BELOW:     /* text to right forbidden -- text below required */
1623        if ( is_text_to_right ) {
1624          error_code = 5;
1625          errors++;
1626          continue;
1627        }
1628
1629        if ( !is_text_below ) {
1630          if ( !InsertTBDs ) {
1631            error_code = 5;
1632            errors++;
1633            continue;
1634          } else
1635            add_text_below = TRUE;
1636        }
1637        break;
1638
1639      case RT_NONE_OR_BELOW: /* text to right is "none" OR text below */
1640
1641        if ( is_text_to_right ) {
1642          if ( strstr( line->Contents, "none" ) )
1643            break;
1644          error_code = 6;
1645          errors++;
1646          continue;
1647        }
1648
1649        if ( !is_text_below ) {
1650          if ( !InsertTBDs ) {
1651            error_code = 6;
1652            errors++;
1653            continue;
1654          } else
1655            add_text_to_right = TRUE;
1656        }
1657        break;
1658                          /* text to right required -- text below optional */
1659      case RT_MAYBE_BELOW:
1660        if ( !is_text_to_right ) {
1661          error_code = 7;
1662          errors++;
1663          continue;
1664        }
1665        break;
1666
1667      case RT_EITHER:    /* text to right OR below */
1668        if ( !(is_text_to_right || is_text_below) ) {
1669          if ( !InsertTBDs ) {
1670            error_code = 8;
1671            errors++;
1672            continue;
1673          } else
1674            add_text_to_right = TRUE;
1675        }
1676        break;
1677
1678      case RT_BOTH:      /* text to right AND below */
1679        if ( !(is_text_to_right && is_text_below) ) {
1680          if ( !InsertTBDs ) {
1681            error_code = 9;
1682            errors++;
1683            continue;
1684          } else {
1685            add_text_to_right = TRUE;
1686            add_text_below = TRUE;
1687          }
1688        }
1689        break;
1690    }
1691
1692    if ( add_text_to_right )
1693      strcat( line->Contents, " TBD" );
1694
1695    if ( add_text_below ) {
1696      new_line = AllocateLine();
1697      strcpy( new_line->Contents, "TBD" );
1698      _Chain_Insert( &line->Node, &new_line->Node );
1699      is_text_below = TRUE;
1700    }
1701
1702    if ( is_text_below )
1703      CrunchBelow( line, key->text_below_mode );
1704
1705    line = (Line_Control *) line->Node.next;
1706  }
1707  return (errors) ? -1 : 0;
1708}
1709
1710/*
1711 *  CheckForIncomplete
1712 */
1713
1714char *IncompleteMarkers[] = {
1715  "??",
1716  "xxx",
1717  "XXX",
1718  "xyz",
1719  "XYZ"
1720};
1721
1722int CheckForIncomplete()
1723{
1724  Line_Control *line;
1725  int           i;
1726  int           errors = 0;
1727
1728  for ( line = (Line_Control *) Lines.first ;
1729        !_Chain_Is_last( &line->Node ) ;
1730        line = (Line_Control *) line->Node.next
1731        ) {
1732    for ( i=0 ; i < NUMBER_ELEMENTS( IncompleteMarkers ) ; i++ ) {
1733      if ( !strstr( line->Contents, IncompleteMarkers[ i ] ) )
1734        continue;
1735
1736      fprintf(
1737        stderr,
1738        "\nLine %d %s:\n",
1739        line->number,
1740        "appears to be incomplete"
1741      );
1742      PrintSurroundingLines( line, 0,  0 );
1743      fprintf( stderr, "\n" );
1744      if ( IncompletesAreErrors )
1745        errors++;
1746      break;
1747    }
1748  }
1749  return ( errors ) ? -1 : 0;
1750}
1751
1752/*
1753 *  CheckOutline
1754 *
1755 *  Insure all section headers are present.
1756 *  Check sections which say "none", really have subsections.
1757 *  Check sections which have subsections, don't say none.
1758 */
1759
1760int CheckOutline( void )
1761{
1762  Line_Control      *line;
1763  int                count;
1764  int                errors = 0;
1765  void              *none_present;
1766  boolean            KeywordsPresent[ KEYWORD_LAST + 1 ];
1767  Keyword_indices_t  keyword;
1768
1769  for ( keyword=0 ; keyword <= KEYWORD_LAST ; keyword++ )
1770    KeywordsPresent[ keyword ] = FALSE;
1771
1772  for ( line = (Line_Control *) Lines.first ;
1773        !_Chain_Is_last( &line->Node ) ;
1774        line = (Line_Control *) line->Node.next
1775        ) {
1776
1777    KeywordsPresent[ line->keyword ] = TRUE;
1778
1779    switch ( line->keyword ) {
1780      case ATTRIBUTE_DESCRIPTIONS:
1781        count = NumberOfAttributes;
1782        break;
1783      case ASSOCIATION_DESCRIPTIONS:
1784        count = NumberOfAssociations;
1785        break;
1786      case ABSTRACT_TYPE_DESCRIPTIONS:
1787        count = NumberOfAbstractTypes;
1788        break;
1789      case DATA_ITEM_DESCRIPTIONS:
1790        count = NumberOfDataItems;
1791        break;
1792      case METHOD_DESCRIPTIONS:
1793        count = NumberOfMethods;
1794        break;
1795      case TASK_DESCRIPTIONS:
1796        count = NumberOfTasks;
1797        break;
1798      default:
1799        count = -1;
1800        break;
1801    }
1802    if ( count == -1 )
1803      continue;
1804
1805    none_present = strstr( line->Contents, "none" );
1806
1807    /* valid cases are (none_present && !count) AND (!none_present && count) */
1808    if ( none_present && count ) {
1809      fprintf(
1810        stderr,
1811        "\nLine %d : %s\n",
1812        line->number,
1813        "section header says \"none\" and there are subsections"
1814      );
1815      PrintSurroundingLines( line, 0,  0 );
1816      fprintf( stderr, "\n" );
1817      errors++;
1818    }
1819    if ( !none_present && !count ) {
1820      fprintf(
1821        stderr,
1822        "\nLine %d : %s\n",
1823        line->number,
1824        "section header does not say \"none\" and there are no subsections"
1825      );
1826      PrintSurroundingLines( line, 0,  0 );
1827      fprintf( stderr, "\n" );
1828      errors++;
1829    }
1830  }
1831
1832  for ( keyword=0 ; keyword <= KEYWORD_LAST ; keyword++ ) {
1833    if ( Keywords[ keyword ].level != SECTION )
1834      continue;
1835
1836    if ( !KeywordsPresent[ keyword ] ) {
1837      fprintf(
1838        stderr,
1839        "Section (%s) is missing\n",
1840        Keywords[ keyword ].Name
1841      );
1842      errors++;
1843    }
1844  }
1845
1846  return (errors) ? -1 : 0;
1847}
1848
1849/*
1850 *  ReportMissingKeywords
1851 */
1852
1853int ReportMissingKeywords(
1854  Section_info_t  *section,
1855  Line_Control    *line,
1856  int              elements_present[ MAXIMUM_ELEMENTS ]
1857)
1858{
1859  int       i;
1860  int       errors = 0;
1861  int       last_found;
1862
1863#ifdef SECTION_DEBUG
1864  PrintLine( line );
1865  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ )
1866    fprintf( stderr, "%d ", elements_present[ i ] );
1867  fprintf( stderr, "\n" );
1868#endif
1869 
1870  /*
1871   *  Check for missing sections
1872   */
1873
1874  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ ) {
1875    if ( section->Description[ i ].keyword == UNUSED )
1876      break;
1877
1878#ifdef SECTION_DEBUG
1879    fprintf(
1880      stderr,
1881      "%d %d %s\n",
1882      section->Description[ i ].is_required,
1883      elements_present[ i ],
1884      Keywords[ section->Description[ i ].keyword ].Name
1885    );
1886#endif
1887
1888    if ( section->Description[ i ].is_required && elements_present[i] == -1 ) {
1889      fprintf(
1890        stderr,
1891        "Section starting at line %d is missing the %s keyword\n",
1892        line->number,
1893        Keywords[ section->Description[ i ].keyword ].Name
1894      );
1895      errors++;
1896    }
1897  }
1898
1899  last_found = -1;
1900
1901  for ( i=0 ; i < MAXIMUM_ELEMENTS ; i++ ) {
1902    if ( section->Description[ i ].keyword == UNUSED )
1903      break;
1904
1905    if ( elements_present[i] == -1 )
1906      continue;
1907
1908    if ( elements_present[i] > last_found ) {
1909      last_found = elements_present[i];
1910      continue;
1911    }
1912
1913    fprintf(
1914      stderr,
1915      "Keywords in the section starting at line %d are in the wrong order\n",
1916      line->number
1917    );
1918    errors++;
1919    break;
1920
1921  }
1922
1923  return errors;
1924}
1925
1926/*
1927 *  ScanForNextSection
1928 */
1929
1930Line_Control *ScanForNextSection(
1931  Line_Control   *start_line,
1932  Section_info_t *section
1933)
1934{
1935  Line_Control   *line;
1936  Element_info_t *Elements;
1937
1938  line = start_line;
1939  Elements = section->Description;
1940
1941  for ( ;; ) {
1942    line = (Line_Control *) line->Node.next;
1943
1944    if ( line->keyword == END_OBJECT )
1945      break;
1946
1947    assert( line );
1948    assert( !_Chain_Is_last( &line->Node ) );
1949
1950    if ( Keywords[ line->keyword ].level == SECTION &&
1951         section->Next_section != line->keyword ) {
1952
1953        fprintf(
1954          stderr,
1955          "Sections appear to be out of order at line %d\n",
1956          start_line->number
1957        );
1958        return NULL;
1959    }
1960
1961    if ( section->Next_section == line->keyword )   /* next section */
1962      break;
1963
1964    if ( Elements[ 0 ].keyword == line->keyword )   /* repeating subsection */
1965      break;
1966  }
1967
1968  return line;
1969}
1970
1971/*
1972 *  CheckSections
1973 */
1974
1975int CheckSections( void )
1976{
1977  Line_Control   *line;
1978  Line_Control   *scan_line;
1979  Section_info_t *section;
1980  Keyword_info_t *key;
1981  Element_info_t *Elements;
1982  int             elements_present[ MAXIMUM_ELEMENTS ];
1983  boolean         stay_in_subsection;
1984  int             i;
1985  int             errors;
1986  int             subsection;
1987  int             element;
1988  int             keyword_count;
1989  Line_Control   *next_section;
1990
1991  errors = 0;
1992  line = (Line_Control *) Lines.first;
1993
1994  for ( i=0 ; i < NUMBER_ELEMENTS( Sections ) ; i++ ) {
1995    section = Sections[ i ];
1996    Elements = section->Description;
1997    subsection = 0;
1998
1999    if ( strstr( line->Contents, "none" ) ) {
2000      next_section = ScanForNextSection( line, section );
2001      if ( !next_section ) {
2002        errors++;
2003        goto end_object;
2004      }
2005      line = next_section;
2006      if ( line->keyword == END_OBJECT )
2007        goto end_object;
2008      continue;
2009    }
2010
2011    while ( Elements[ 0 ].keyword != line->keyword ) {
2012      if ( line->keyword == END_OBJECT )
2013        goto end_object;
2014
2015      if( !line || _Chain_Is_last( &line->Node ) ) {
2016        fprintf( stderr, "out of sync -- aborting\n" );
2017        errors++;
2018        goto end_object;
2019      }
2020      line = (Line_Control *) line->Node.next;
2021    }
2022
2023repeating_subsection:
2024
2025#ifdef SECTION_DEBUG
2026    fprintf( stderr, "Checking Section %d Subsection %d\n", i, subsection );
2027#endif
2028    assert( line );
2029    assert( !_Chain_Is_last( &line->Node ) );
2030 
2031    /*
2032     *  Per Subsection Initialization
2033     */
2034
2035    subsection++;
2036
2037    keyword_count = 0;
2038
2039    next_section = ScanForNextSection( line, section );
2040    if ( !next_section ) {
2041      errors++;
2042      goto end_object;
2043    }
2044
2045    for ( element=0 ; element < MAXIMUM_ELEMENTS ; element++ )
2046      elements_present[ element ] = -1;
2047
2048    /* 
2049     *  Do a subsection
2050     */
2051
2052    /*  validate each keyword */
2053
2054    for ( scan_line = line ; ; ) {
2055
2056      if ( !scan_line->keyword ) {
2057        scan_line = (Line_Control *) scan_line->Node.next;
2058        continue;
2059      }
2060
2061      if ( scan_line == next_section )
2062        break;
2063
2064      if ( *Keywords[ scan_line->keyword ].keyword_validation_routine ) {
2065        if ( (*Keywords[ scan_line->keyword ].keyword_validation_routine )(
2066               scan_line
2067              ) ) errors++;
2068      }
2069
2070      scan_line = (Line_Control *) scan_line->Node.next;
2071    }
2072
2073    /* scan subsection for keywords */
2074
2075    for ( scan_line = line ; ; ) {
2076
2077      if ( !scan_line->keyword ) {
2078        scan_line = (Line_Control *) scan_line->Node.next;
2079        continue;
2080      }
2081
2082      if ( scan_line == next_section )
2083        break;
2084
2085      for ( element=0 ; element < MAXIMUM_ELEMENTS ; element++ ) {
2086        if ( scan_line->keyword == Elements[ element ].keyword ) {
2087          if ( elements_present[ element ] != -1 ) {
2088            fprintf(
2089              stderr,
2090              "Section starting at line %d has the %s keyword more than once\n",
2091              line->number,
2092              Keywords[ Elements[ i ].keyword ].Name
2093            );
2094            errors++;
2095          }
2096         
2097#ifdef SECTION_DEBUG
2098          fprintf( stderr, "FOUND %s %d %d\n",
2099            Keywords[ Elements[ element ].keyword ].Name,
2100            element, keyword_count );
2101#endif
2102          elements_present[ element ] = keyword_count++;
2103          break;
2104        }
2105        if ( Elements[ element ].keyword == UNUSED )
2106          break;
2107      }
2108
2109      scan_line = (Line_Control *) scan_line->Node.next;
2110    }
2111    errors += ReportMissingKeywords( section, line, elements_present );
2112
2113    /*
2114     *  Validate the section as a whole
2115     */
2116     
2117    if ( section->section_validation_routine ) {
2118      if ( (*section->section_validation_routine)(section, line, next_section) )
2119        errors++;
2120    }
2121
2122scan_for_next_section:
2123    /*
2124     *  Scan forward until next subsection or next section
2125     */
2126
2127#ifdef SECTION_DEBUG
2128    fprintf( stderr, "End of Subsection\n" );
2129#endif
2130    line = next_section;
2131    if ( line->keyword == END_OBJECT ) {
2132      goto end_object;
2133    }
2134
2135    if ( Elements[ 0 ].keyword == line->keyword ) { /* repeating subsection */
2136      if ( !section->repeats ) {
2137        fprintf(
2138          stderr,
2139          "Invalid repeating subsection starting at line %d\n",
2140          line->number
2141        );
2142        errors++;
2143        goto end_object;
2144      }
2145      goto repeating_subsection;
2146    }
2147 
2148  }
2149
2150end_object:
2151  return (errors) ? -1 : 0;
2152}
2153/*
2154 *  RemovePagebreaks
2155 */
2156
2157void RemovePagebreaks()
2158{
2159  Line_Control *line;
2160
2161  for ( line = (Line_Control *) Lines.first ;
2162        !_Chain_Is_last( &line->Node ) ;
2163        ) {
2164    if ( !strcmp( line->Contents, PAGE_SEPARATOR ) )
2165        line = DeleteLine( line );
2166    else
2167      line = (Line_Control *) line->Node.next;
2168  }
2169}
2170
2171/*
2172 *  strIsAllSpace
2173 */
2174
2175boolean strIsAllSpace(
2176  char *s
2177)
2178{
2179  char *p;
2180
2181  for ( p = s ; *p ; p++ )
2182    if ( !isspace( *p ) )
2183      return FALSE;
2184
2185  return TRUE;
2186}
2187
2188/*
2189 *  RemoveExtraBlankLines
2190 *
2191 *  NOTE:  Be careful not remove to remove white space in raw text.
2192 */
2193
2194int RemoveExtraBlankLines()
2195{
2196  Line_Control *line;
2197  Line_Control *previous;
2198  int errors;
2199
2200  errors = 0;
2201
2202  for ( line = (Line_Control *) Lines.first ;
2203        !_Chain_Is_last( &line->Node ) ;
2204        line = (Line_Control *) line->Node.next
2205        ) {
2206    if ( line->keyword || line->format )
2207      continue;
2208
2209    if ( !strlen( line->Contents ) ) {
2210      line = DeleteLine( line );
2211      line = (Line_Control *) line->Node.previous;
2212      continue;
2213    }
2214
2215    fprintf(
2216      stderr,
2217      "\nLine %d is not associated with a keyword:\n",
2218      line->number
2219    );
2220    PrintSurroundingLines( line, 0,  0 );
2221    fprintf( stderr, "\n" );
2222    errors++;
2223  }
2224  return ( errors ) ? -1 : 0;
2225}
2226
2227/*
2228 *  strCopyToColon
2229 */
2230
2231void strCopyToColon(
2232  char *src,
2233  char *dest
2234)
2235{
2236  char *s = src;
2237  char *d = dest;
2238
2239  for ( ; *s && *s != ':' ; )
2240    *d++ = *s++;
2241  *d ='\0';
2242}
2243
2244/*
2245 *  BuildTexinfoNodes
2246 */
2247
2248void BuildTexinfoNodes( void )
2249{
2250  Line_Control *line;
2251  Line_Control *new_line;
2252  Line_Control *next_node;
2253  char          Buffer[ BUFFER_SIZE ];
2254  char          ObjectName[ BUFFER_SIZE ];
2255  char          NodeName[ BUFFER_SIZE ];
2256  char          NextNode[ BUFFER_SIZE ];
2257  char          NextNodeName[ BUFFER_SIZE ];
2258  char          PreviousNodeName[ BUFFER_SIZE ];
2259  char          UpNodeName[ BUFFER_SIZE ];
2260  char          SectionName[ BUFFER_SIZE ];
2261  char          MenuBuffer[ BUFFER_SIZE ];
2262  Line_Control *menu_insert_point;
2263  Line_Control *node_line;
2264  boolean       next_found;
2265  int           menu_items;
2266
2267  strcpy( PreviousNodeName, DocsPreviousNode );
2268
2269  for ( line = (Line_Control *) Lines.first ;
2270        !_Chain_Is_last( &line->Node ) ;
2271        line = (Line_Control *) line->Node.next
2272      ) {
2273    menu_insert_point = (Line_Control *) line->Node.next;
2274
2275    switch ( Keywords[ line->keyword ].level ) {
2276      case TEXT:
2277      case HEADING:
2278        break;
2279      case SECTION:
2280        if ( line->keyword == END_OBJECT )
2281          goto bottom;
2282
2283        if ( line->keyword == OBJECT ) {
2284          LineCopyFromRight( line, Buffer );
2285          sprintf( ObjectName, "%s Object", Buffer );
2286          strcpy( NodeName, ObjectName );
2287          strcpy( UpNodeName, DocsUpNode );
2288        } else {
2289          LineCopySectionName( line, Buffer );
2290          sprintf( NodeName, "%s %s", ObjectName, Buffer );
2291          strcpy( UpNodeName, ObjectName );
2292        }
2293        strtoInitialCaps( NULL, NodeName );
2294        strtoInitialCaps( NULL, UpNodeName );
2295        strcpy( SectionName, NodeName );
2296
2297        /*
2298         *  Go ahead and put it on the chain in the right order (ahead of
2299         *  the menu) and we can fill it in later (after the menu is built).
2300         */
2301
2302        new_line = AllocateLine();
2303        strcpy( new_line->Contents, "@ifinfo" );
2304        _Chain_Insert( line->Node.previous, &new_line->Node );
2305
2306        node_line = AllocateLine();
2307        _Chain_Insert( line->Node.previous, &node_line->Node );
2308
2309        new_line = AllocateLine();
2310        strcpy( new_line->Contents, "@end ifinfo" );
2311        _Chain_Insert( line->Node.previous, &new_line->Node );
2312
2313        menu_items = 0;
2314       
2315        if ( line->keyword == OBJECT ) {
2316          next_node = (Line_Control *) line->Node.next;
2317          next_found = FALSE;
2318          for ( ; ; ) {
2319            if ( next_node->keyword == END_OBJECT )
2320              break;
2321            if ( Keywords[ next_node->keyword ].level == SECTION ) {
2322              LineCopySectionName( next_node, Buffer );
2323              strtoInitialCaps( NULL, Buffer );     
2324
2325              if ( !next_found ) {
2326                next_found = TRUE;
2327                sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2328              }
2329              if ( menu_items == 0 ) {
2330                new_line = AllocateLine();
2331                strcpy( new_line->Contents, "@ifinfo" );
2332                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2333 
2334                new_line = AllocateLine();
2335                strcpy( new_line->Contents, "@menu" );
2336                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2337              }
2338
2339              menu_items++;
2340
2341              new_line = AllocateLine();
2342              sprintf( new_line->Contents, "* %s %s::", ObjectName, Buffer );
2343              _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node);
2344            }
2345            next_node = (Line_Control *) next_node->Node.next;
2346          }
2347        } else {
2348          next_node = (Line_Control *) line->Node.next;
2349       
2350          next_found = FALSE;
2351          for ( ; ; ) {
2352            if ( Keywords[ next_node->keyword ].level == SECTION ) {
2353              if ( !next_found ) {
2354                if ( next_node->keyword == END_OBJECT ) {
2355                  strcpy( NextNodeName, DocsNextNode );
2356                } else {
2357                  LineCopySectionName( next_node, Buffer );
2358                  sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2359                  strtoInitialCaps( NULL, NextNodeName );
2360                }
2361                next_found = TRUE;
2362              }
2363              break;
2364            } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
2365              LineCopySectionName( next_node, Buffer );
2366              strtoInitialCaps( NULL, Buffer );
2367              sprintf( MenuBuffer, "%s %s - ", ObjectName, Buffer );
2368              LineCopyFromRight( next_node, Buffer );
2369              strcat( MenuBuffer, Buffer );
2370
2371              if ( menu_items == 0 ) {
2372                new_line = AllocateLine();
2373                strcpy( new_line->Contents, "@ifinfo" );
2374                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2375 
2376                new_line = AllocateLine();
2377                strcpy( new_line->Contents, "@menu" );
2378                _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2379              }
2380
2381              menu_items++;
2382
2383              new_line = AllocateLine();
2384              sprintf( new_line->Contents, "* %s::", MenuBuffer );
2385              _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2386
2387              if ( !next_found ) {
2388                next_found = TRUE;
2389                strcpy( NextNodeName, MenuBuffer );
2390              }
2391            }
2392            next_node = (Line_Control *) next_node->Node.next;
2393          }
2394        }
2395
2396        if ( menu_items ) {
2397          new_line = AllocateLine();
2398          strcpy( new_line->Contents, "@end menu" );
2399          _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2400 
2401          new_line = AllocateLine();
2402          strcpy( new_line->Contents, "@end ifinfo" );
2403          _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
2404        }
2405
2406#if 0
2407        fprintf(
2408          stderr,
2409          "@node %s, %s, %s, %s\n",
2410          NodeName,
2411          NextNodeName,
2412          PreviousNodeName,
2413          UpNodeName
2414        );
2415#endif
2416        /* node_line was previously inserted */
2417        sprintf(
2418          node_line->Contents,
2419          "@node %s, %s, %s, %s",
2420          NodeName,
2421          NextNodeName,
2422          PreviousNodeName,
2423          UpNodeName
2424        );
2425
2426        strcpy( PreviousNodeName, NodeName );
2427        break;
2428
2429      case SUBSECTION:
2430        strcpy( UpNodeName, SectionName );
2431
2432        LineCopySectionName( line, Buffer );
2433        strtoInitialCaps( NULL, Buffer );
2434        sprintf( NodeName, "%s %s - ", ObjectName, Buffer );
2435        LineCopyFromRight( line, Buffer );
2436        strcat( NodeName, Buffer );
2437
2438        new_line = AllocateLine();
2439        strcpy( new_line->Contents, "@ifinfo" );
2440        _Chain_Insert( line->Node.previous, &new_line->Node );
2441
2442        next_node = (Line_Control *) line->Node.next;
2443        for ( ; ; ) {
2444          if ( Keywords[ next_node->keyword ].level == SECTION ) {
2445            if ( next_node->keyword == END_OBJECT ) {
2446              strcpy( NextNodeName, DocsNextNode );
2447            } else {
2448              LineCopySectionName( next_node, Buffer );
2449              sprintf( NextNodeName, "%s %s", ObjectName, Buffer );
2450              strtoInitialCaps( NULL, NextNodeName );
2451            }
2452            break;
2453          } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
2454            LineCopySectionName( next_node, Buffer );
2455            strtoInitialCaps( NULL, Buffer );
2456            sprintf( NextNodeName, "%s %s - ", ObjectName, Buffer );
2457            LineCopyFromRight( next_node, Buffer );
2458            strcat( NextNodeName, Buffer );
2459            break;
2460          }
2461          next_node = (Line_Control *) next_node->Node.next;
2462        }
2463
2464#if 0
2465        fprintf(
2466          stderr,
2467          "@node %s, %s, %s, %s\n",
2468          NodeName,
2469          NextNodeName,
2470          PreviousNodeName,
2471          UpNodeName
2472        );
2473#endif
2474        new_line = AllocateLine();
2475        sprintf(
2476          new_line->Contents,
2477          "@node %s, %s, %s, %s",
2478          NodeName,
2479          NextNodeName,
2480          PreviousNodeName,
2481          UpNodeName
2482        );
2483        _Chain_Insert( line->Node.previous, &new_line->Node );
2484
2485        new_line = AllocateLine();
2486        strcpy( new_line->Contents, "@end ifinfo" );
2487        _Chain_Insert( line->Node.previous, &new_line->Node );
2488
2489        strcpy( PreviousNodeName, NodeName );
2490        break;
2491    }
2492  }
2493bottom:
2494}
2495
2496/*
2497 *  FormatToTexinfo
2498 */
2499
2500char *Texinfo_Headers[] = {
2501  "\\input texinfo   @c -*-texinfo-*-",
2502  "@c %**start of header",
2503  "@setfilename ",
2504  "@settitle ",
2505  "@paragraphindent 0",
2506  "@c %**end of header",
2507  "",
2508  "@c",
2509  "@c  COPYRIGHT (c) 1996.",
2510  "@c  On-Line Applications Research Corporation (OAR).",
2511  "@c  All rights reserved.",
2512  "@c",
2513  "@c  This file is automatically generated.  DO NOT EDIT!!",
2514  "@c",
2515  "",
2516  "@c  This prevents a black box from being printed on overfull lines.",
2517  "@c  The alternative is to rework a sentence to avoid this problem.",
2518  "@finalout",
2519  "",
2520  "@tex",
2521  "\\global\\parindent 0in",
2522  "\\global\\chapheadingskip = 15pt plus 4pt minus 2pt",
2523  "\\global\\secheadingskip = 12pt plus 4pt minus 2pt",
2524  "\\global\\subsecheadingskip = 9pt plus 4pt minus 2pt",
2525  "",
2526  "@ifclear smallbook",
2527  "\\global\\parskip 6pt plus 1pt",
2528  "@end ifclear",
2529  "@end tex",
2530  "@setchapternewpage odd",
2531  "@ifinfo",
2532  "@top ",
2533  "@node Top, (dir), (dir), (dir)",
2534  "@end ifinfo",
2535  "@c ",
2536  "@c This is the end of the header block",
2537  "@c "
2538};
2539
2540void FormatToTexinfo( void )
2541{
2542  Line_Control *line;
2543  Line_Control *new_line;
2544  char          Buffer[ PARAGRAPH_SIZE ];
2545  int           i;
2546  char          ChapterTitle[ PARAGRAPH_SIZE ];
2547  char          InfoFile[ PARAGRAPH_SIZE ];
2548  char          *p;
2549  boolean        new_section;
2550  boolean        in_bullets;
2551
2552  for ( line = (Line_Control *) Lines.first ;
2553        !_Chain_Is_last( &line->Node ) ;
2554      ) {
2555
2556    switch ( line->keyword ) {
2557      case UNUSED:
2558        line = (Line_Control *) line->Node.next;
2559        break;
2560
2561      case OBJECT:
2562        LineCopyFromRight( line, ChapterTitle );
2563        strcpy( InfoFile, ChapterTitle );
2564
2565        for ( p=InfoFile ; *p ; *p++ )   /* turn this into a file name */
2566          if ( isspace( *p ) )
2567            *p = '_';             
2568
2569        sprintf( Buffer, "@chapter %s", line->Contents );
2570        strcpy( line->Contents, Buffer );
2571        line = (Line_Control *) line->Node.next;
2572        break;
2573
2574      case ATTRIBUTE_DESCRIPTIONS:
2575      case ASSOCIATION_DESCRIPTIONS:
2576      case ABSTRACT_TYPE_DESCRIPTIONS:
2577      case DATA_ITEM_DESCRIPTIONS:
2578      case METHOD_DESCRIPTIONS:
2579      case TASK_DESCRIPTIONS:
2580        sprintf( Buffer, "@section %s", line->Contents );
2581        strcpy( line->Contents, Buffer );
2582
2583        new_line = AllocateLine();
2584        strcpy( new_line->Contents, "@page" );
2585        _Chain_Insert( line->Node.previous, &new_line->Node );
2586
2587        line = (Line_Control *) line->Node.next;
2588        new_section = TRUE;
2589        break;
2590
2591      case END_OBJECT:
2592        line->Contents[ 0 ] = '\0';
2593        goto bottom;
2594
2595      case ATTRIBUTE:
2596      case ASSOCIATION:
2597      case ABSTRACT_TYPE:
2598      case DATA_ITEM:
2599        if ( !new_section ) {
2600          new_line = AllocateLine();
2601          strcpy( new_line->Contents, "@need 4000" );
2602          _Chain_Insert( line->Node.previous, &new_line->Node );
2603        }
2604        new_section = FALSE;
2605        sprintf( Buffer, "@subsection %s", line->Contents );
2606        strcpy( line->Contents, Buffer );
2607        line = (Line_Control *) line->Node.next;
2608         break;
2609
2610      case METHOD:
2611      case TASK:
2612        if ( !new_section ) {
2613          new_line = AllocateLine();
2614          strcpy( new_line->Contents, "@page" );
2615          _Chain_Insert( line->Node.previous, &new_line->Node );
2616        }
2617        new_section = FALSE;
2618        sprintf( Buffer, "@subsection %s", line->Contents );
2619        strcpy( line->Contents, Buffer );
2620        line = (Line_Control *) line->Node.next;
2621        break;
2622
2623      case DESCRIPTION:
2624      case COPYRIGHT:
2625      case PORTING:
2626      case THEORY_OF_OPERATION:
2627      case DEPENDENCIES:
2628      case NOTES:
2629        sprintf( Buffer, "@subheading %s\n", line->Contents );
2630        strcpy( line->Contents, Buffer );
2631        line = (Line_Control *) line->Node.next;
2632
2633        /* now take care of the paragraphs which are here */
2634
2635        in_bullets = FALSE;
2636        do {
2637          line = (Line_Control *) line->Node.next;
2638          if ( line->format == BULLET_OUTPUT ) {
2639            if ( !in_bullets ) {
2640              in_bullets = TRUE;
2641
2642              new_line = AllocateLine();
2643              _Chain_Insert( line->Node.previous, &new_line->Node );
2644
2645              new_line = AllocateLine();
2646              strcpy( new_line->Contents, "@itemize @bullet" );
2647              _Chain_Insert( line->Node.previous, &new_line->Node );
2648            }
2649            sprintf( Buffer, "@item %s\n", line->Contents );
2650            strcpy( line->Contents, Buffer );
2651          } else if ( in_bullets ) {
2652            in_bullets = FALSE;
2653
2654            new_line = AllocateLine();
2655            strcpy( new_line->Contents, "@end itemize" );
2656            _Chain_Insert( line->Node.previous, &new_line->Node );
2657
2658            new_line = AllocateLine();
2659            _Chain_Insert( line->Node.previous, &new_line->Node );
2660          } else {
2661            new_line = AllocateLine();
2662            _Chain_Insert( line->Node.previous, &new_line->Node );
2663          }
2664        } while ( !line->keyword );
2665
2666        break;
2667
2668      case DERIVATION:
2669      case TYPE:
2670      case RANGE:
2671      case UNITS:
2672      case SCALE_FACTOR:
2673      case TOLERANCE:
2674      case VISIBILITY:
2675      case ASSOCIATED_WITH:
2676      case MULTIPLICITY:
2677      case TIMING:
2678        sprintf( Buffer, "@subheading %s\n", line->Contents );
2679        strcpy( line->Contents, Buffer );
2680        line = (Line_Control *) line->Node.next;
2681        break;
2682
2683      case MEMBERS:
2684      case DEFAULT:
2685      case REQUIREMENTS:
2686      case REFERENCES:
2687      case INPUTS:
2688      case OUTPUTS:
2689      case PDL:
2690      case SYNCHRONIZATION:
2691        sprintf( Buffer, "@subheading %s\n", line->Contents );
2692        strcpy( line->Contents, Buffer );
2693
2694        /* now take care of the raw text which is here */
2695
2696        new_line = AllocateLine();
2697        strcpy( new_line->Contents, "@example" );
2698        _Chain_Insert( &line->Node, &new_line->Node );
2699
2700        do {
2701          line = (Line_Control *) line->Node.next;
2702          if ( !strlen( line->Contents ) ) {
2703            new_line = AllocateLine();
2704            strcpy( new_line->Contents, "@end example" );
2705            _Chain_Insert( line->Node.previous, &new_line->Node );
2706
2707            new_line = AllocateLine();
2708            strcpy( new_line->Contents, "@example" );
2709            _Chain_Insert( &line->Node, &new_line->Node );
2710
2711          }
2712        } while ( !line->keyword );
2713
2714        new_line = AllocateLine();
2715        strcpy( new_line->Contents, "@end example" );
2716        _Chain_Insert( line->Node.previous, &new_line->Node );
2717        /* at this point line points to the next keyword */
2718        break;
2719    }   
2720  }
2721
2722bottom:
2723#if 0
2724  for ( i=NUMBER_ELEMENTS( Texinfo_Headers ) - 1 ; i >= 0 ; i-- ) {
2725    new_line = AllocateLine();
2726    strcpy( new_line->Contents, Texinfo_Headers[ i ] );
2727    if ( !strcmp( "@setfilename ", new_line->Contents ) )
2728      strcat( new_line->Contents, ChapterTitle );
2729    else if ( !strcmp( "@settitle ", new_line->Contents ) )
2730      strcat( new_line->Contents, InfoFile );
2731    else if ( !strcmp( "@top ", new_line->Contents ) )
2732      strcat( new_line->Contents, InfoFile );
2733    _Chain_Insert( _Chain_Head( &Lines ), &new_line->Node );
2734  }
2735
2736  /*
2737   *  Remove the special end of object string.  No one wants to see
2738   *  it in the printed output and the node is already marked "END_OBJECT".
2739   */
2740
2741  ((Line_Control *)Lines.last)->Contents[ 0 ] = '\0';
2742
2743  new_line = AllocateLine();
2744  strcpy( new_line->Contents, "@bye" );
2745  _Chain_Append( &Lines, &new_line->Node );
2746
2747#endif
2748  if ( Verbose )
2749    fprintf( stderr, "-------->INSERTING TEXINFO MENUS\n" );
2750
2751  BuildTexinfoNodes();
2752}
2753
2754/*
2755 *  PrintFile
2756 */
2757
2758void PrintFile(
2759  char *out
2760)
2761{
2762  Line_Control *line;
2763
2764  OutFile = fopen( out, "w+" );
2765
2766  if ( !OutFile ) {
2767    fprintf( stderr, "Unable to open (%s) for output\n", out );
2768    exit_application( 1 );
2769  }
2770  assert( OutFile );
2771
2772  for ( line = (Line_Control *) Lines.first ;
2773        !_Chain_Is_last( &line->Node ) ;
2774        line = (Line_Control *) line->Node.next ) {
2775    fprintf( OutFile, "%s\n", line->Contents );
2776/*
2777    fprintf(
2778      OutFile,
2779      "(%d,%d)%s\n",
2780      line->keyword,
2781      line->format,
2782      line->Contents
2783    );
2784*/
2785  }
2786}
2787
2788/*
2789 *  DumpList
2790 */
2791
2792void DumpList(
2793  Chain_Control  *the_list
2794)
2795{
2796  Line_Control  *line;
2797
2798  fprintf( stderr, "---> Dumping list (%p)\n", the_list );
2799
2800  for ( line = (Line_Control *) the_list->first ;
2801      !_Chain_Is_last( &line->Node ) ;
2802      line = (Line_Control *) line->Node.next ) {
2803    fprintf( stderr, "%s\n", line->Contents );
2804  }
2805}
2806
2807/*
2808 * ReleaseFile
2809 */
2810
2811void ReleaseFile()
2812{
2813   Line_Control *line;
2814   Line_Control *next;
2815
2816   for ( line = (Line_Control *) Lines.first ;
2817         !_Chain_Is_last( &line->Node ) ;
2818       ) {
2819     next = (Line_Control *) line->Node.next;
2820     line = next;
2821   }
2822}
2823
2824/*
2825 *  strtoInitialCaps
2826 */
2827
2828void strtoInitialCaps(
2829  char *dest,
2830  char *src
2831)
2832{
2833  char *source = src;
2834  char *destination = dest;
2835
2836  if ( !dest )
2837    return;
2838  strcpy( dest, src );
2839#if 0
2840  source = src;
2841  destination = (dest) ? dest : src;
2842
2843  while ( *source ) {
2844    while ( isspace( *source ) )
2845      *destination++ = *source++;
2846
2847    if ( !*source )
2848      break;
2849
2850    *destination++ = toupper( *source++ );
2851
2852    for ( ; *source && !isspace( *source ) ; source++ )
2853      *destination++ = tolower( *source );
2854     
2855    if ( !*source )
2856      break;
2857  }
2858
2859  *destination = '\0';
2860#endif
2861}
2862
2863/*
2864 *  Validate_visibility
2865 */
2866 
2867char *Valid_visibilities[] = {
2868  "public",
2869  "private"
2870};
2871 
2872int Validate_visibility(
2873  Line_Control   *line
2874)
2875{
2876  char   *s;
2877  char   *d;
2878  char    Buffer[ BUFFER_SIZE ];
2879  char    Visibility[ BUFFER_SIZE ];
2880  int     i;
2881  boolean found;
2882  int     errors = 0;
2883 
2884  LineCopyFromRight( line, Buffer );
2885 
2886  memset( Visibility, '\0', sizeof( Visibility ) );
2887  s = Buffer;
2888 
2889  for ( d=Visibility ; ; s++, d++ ) {
2890    *d = *s;
2891    if ( !*s || isspace(*s) )
2892      break;
2893  }
2894  *d = '\0';
2895 
2896  if ( isspace(*s) ) {
2897    fprintf(
2898       stderr,
2899       "Unexpected white space on line %d -- are there multiple words?\n",
2900       line->number
2901     );
2902     errors++;
2903  }
2904 
2905  /*
2906   *  Check out the type part of this keyword
2907   */
2908 
2909  for ( found=FALSE, i=0 ; i<NUMBER_ELEMENTS(Valid_visibilities) ; i++ ) {
2910    if ( !strcmp( Valid_visibilities[ i ], Visibility ) ) {
2911      found = TRUE;
2912      break;
2913    }
2914  }
2915 
2916  if ( !found ) {
2917    if ( !(InsertTBDs && !strcmp( Visibility, "TBD" )) ) {
2918      fprintf(
2919        stderr,
2920        "Invalid visibility type (%s) on line %d\n",
2921        Visibility,
2922        line->number
2923      );
2924      errors++;
2925    }
2926  }
2927 
2928  return (errors) ? -1 : 0;
2929}
2930
2931/*
2932 *  Validate_synchronization
2933 */
2934 
2935char *Valid_synchronization[] = {
2936  "delay",
2937  "event",
2938  "mutex",
2939  "semaphore",
2940  "message",
2941  "signal",
2942  "period"
2943};
2944 
2945boolean Valid_synchronization_text_below[] = {
2946  FALSE,   /* delay */
2947  TRUE,    /* event */
2948  TRUE,    /* mutex */
2949  TRUE,    /* semaphore */
2950  TRUE,    /* message */
2951  TRUE,    /* signal */
2952  FALSE    /* period */
2953};
2954
2955int Validate_synchronization(
2956  Line_Control   *line
2957)
2958{
2959  char   *s;
2960  char   *d;
2961  char    Buffer[ BUFFER_SIZE ];
2962  char    Synchronization[ BUFFER_SIZE ];
2963  int     i;
2964  boolean found;
2965  int     errors = 0;
2966 
2967  LineCopyFromRight( line, Buffer );
2968 
2969  memset( Synchronization, '\0', sizeof( Synchronization ) );
2970  s = Buffer;
2971 
2972  for ( d=Synchronization ; ; s++, d++ ) {
2973    *d = *s;
2974    if ( !*s || isspace(*s) )
2975      break;
2976  }
2977  *d = '\0';
2978 
2979  if ( isspace(*s) ) {
2980    fprintf(
2981       stderr,
2982       "Unexpected white space on line %d -- invalid use of multiple words\n",
2983       line->number
2984     );
2985     errors++;
2986  }
2987 
2988  /*
2989   *  Check out the type part of this keyword
2990   */
2991 
2992  for ( found=FALSE, i=0 ; i<NUMBER_ELEMENTS(Valid_synchronization) ; i++ ) {
2993    if ( !strcmp( Valid_synchronization[ i ], Synchronization ) ) {
2994      found = TRUE;
2995      break;
2996    }
2997  }
2998 
2999  if ( !found ) {
3000    fprintf(
3001       stderr,
3002       "Invalid synchronization type (%s) on line %d\n",
3003       Synchronization,
3004       line->number
3005     );
3006     errors++;
3007  }
3008
3009  if ( line->keyword && !Valid_synchronization_text_below[ i ] ) {
3010    fprintf(
3011       stderr,
3012       "Expected text below synchronization type (%s) on line %d\n",
3013       Synchronization,
3014       line->number
3015     );
3016     errors++;
3017  }
3018 
3019  return (errors) ? -1 : 0;
3020}
3021
3022/*
3023 *  Validate_abstract_type
3024 *
3025 * presence of range or members but not both
3026 */
3027
3028int Validate_abstract_type(
3029  Section_info_t *section,
3030  Line_Control   *start,
3031  Line_Control   *next_section
3032)
3033{
3034  boolean       range_found = FALSE;
3035  boolean       members_found = FALSE;
3036  boolean       enumerated_found = FALSE;
3037  boolean       true_found = FALSE;
3038  boolean       false_found = FALSE;
3039  Line_Control *line;
3040  int           errors = 0;
3041
3042  for ( line = start;
3043        line != next_section ;
3044        line = (Line_Control *) line->Node.next ) {
3045    if ( line->keyword == RANGE )
3046      range_found = TRUE;
3047    else if ( line->keyword == MEMBERS ) {
3048      members_found = TRUE;
3049    } else if ( line->keyword == TYPE || line->keyword == DERIVATION ) {
3050      if ( strstr( line->Contents, "enumerated" ) ||
3051           strstr( line->Contents, "structure" ) )
3052        enumerated_found = TRUE;
3053    }
3054  }
3055
3056  if ( !range_found && !members_found ) {
3057    fprintf(
3058       stderr,
3059       "Neither range nor members keyword present in "
3060         "subsection starting at line %d\n",
3061       start->number
3062     );
3063     errors++;
3064  }
3065
3066  if ( !InsertTBDs ) {
3067    if ( range_found && members_found ) {
3068      fprintf(
3069         stderr,
3070         "Both range and members keyword present in "
3071           "subsection starting at line %d\n",
3072         start->number
3073       );
3074       errors++;
3075    }
3076  } 
3077
3078  if ( enumerated_found  && !members_found ) {
3079    fprintf(
3080       stderr,
3081       "Enumerated type without list of members in "
3082         "subsection starting at line %d\n",
3083       start->number
3084     );
3085     errors++;
3086  }
3087
3088  if ( !enumerated_found  && !range_found ) {
3089    fprintf(
3090       stderr,
3091       "Type does not have range specified in "
3092         "subsection starting at line %d\n",
3093       start->number
3094     );
3095     errors++;
3096  }
3097
3098  return (errors) ? -1 : 0;
3099}
3100
3101/*
3102 *  Validate_attribute
3103 *
3104 * presence of range or members but not both
3105 */
3106 
3107int Validate_attribute(
3108  Section_info_t *section,
3109  Line_Control   *start,
3110  Line_Control   *next_section
3111)
3112{
3113  boolean       range_found = FALSE;
3114  boolean       members_found = FALSE;
3115  boolean       enumerated_found = FALSE;
3116  boolean       boolean_found = FALSE;
3117  boolean       true_found = FALSE;
3118  boolean       false_found = FALSE;
3119  Line_Control *line;
3120  int           errors = 0;
3121 
3122  for ( line = start;
3123        line != next_section ;
3124        line = (Line_Control *) line->Node.next ) {
3125    if ( line->keyword == RANGE )
3126      range_found = TRUE;
3127    else if ( line->keyword == MEMBERS ) {
3128      members_found = TRUE;
3129      if ( boolean_found == TRUE ) {
3130        line = (Line_Control *) line->Node.next;
3131        while ( !_Chain_Is_last( &line->Node ) ) {
3132          if ( line->keyword )
3133            break;
3134          if ( strstr( line->Contents, "FALSE" ) )
3135            false_found = TRUE;
3136          else if ( strstr( line->Contents, "TRUE" ) )
3137            true_found = TRUE;
3138          line = (Line_Control *) line->Node.next;
3139        }
3140        line = (Line_Control *) line->Node.previous;
3141      }
3142    } else if ( line->keyword == TYPE || line->keyword == DERIVATION ) {
3143      if ( strstr( line->Contents, "enumerated" ) )
3144        enumerated_found = TRUE;
3145      else if ( strstr( line->Contents, "boolean" ) ) {
3146        enumerated_found = TRUE;
3147        boolean_found = TRUE;
3148      }
3149    }
3150  }
3151 
3152  if ( !range_found && !members_found ) {
3153    fprintf(
3154       stderr,
3155       "Neither range nor members keyword present in "
3156         "subsection starting at line %d\n",
3157       start->number
3158     );
3159     errors++;
3160  }
3161 
3162  if ( !InsertTBDs ) {
3163    if ( range_found && members_found ) {
3164      fprintf(
3165         stderr,
3166         "Both range and members keyword present in "
3167           "subsection starting at line %d\n",
3168         start->number
3169       );
3170       errors++;
3171    }
3172  }
3173 
3174  if ( enumerated_found  && !members_found ) {
3175    fprintf(
3176       stderr,
3177       "Enumerated type without list of members in "
3178         "subsection starting at line %d\n",
3179       start->number
3180     );
3181     errors++;
3182  }
3183 
3184  if ( !enumerated_found  && !range_found ) {
3185    fprintf(
3186       stderr,
3187       "Type does not have range specified in "
3188         "subsection starting at line %d\n",
3189       start->number
3190     );
3191     errors++;
3192  }
3193 
3194  if ( boolean_found && !true_found ) {
3195    fprintf(
3196       stderr,
3197       "Boolean without a TRUE case specified in "
3198         "subsection starting at line %d\n",
3199       start->number
3200     );
3201     errors++;
3202  }
3203 
3204  if ( boolean_found && !false_found ) {
3205    fprintf(
3206       stderr,
3207       "Boolean without a FALSE case specified in "
3208         "subsection starting at line %d\n",
3209       start->number
3210     );
3211     errors++;
3212  }
3213 
3214  return (errors) ? -1 : 0;
3215}
3216
3217/*
3218 *  Validate_object
3219 *
3220 * presence of range or members but not both
3221 */
3222 
3223int Validate_object(
3224  Section_info_t *section,
3225  Line_Control   *start,
3226  Line_Control   *next_section
3227)
3228{
3229  char          ObjectName[ BUFFER_SIZE ];
3230  char          EndObjectName[ BUFFER_SIZE ];
3231  Line_Control *line;
3232  int           errors = 0;
3233 
3234 
3235  LineCopyFromRight( start, ObjectName );
3236
3237  for ( line = start;
3238        !_Chain_Is_last( &line->Node ) ;
3239        line = (Line_Control *) line->Node.next ) {
3240    if ( line->keyword == END_OBJECT ) {
3241      LineCopyFromRight( line, EndObjectName );
3242      break;
3243    }
3244  }
3245 
3246  if ( strcmp( ObjectName, EndObjectName ) ) {
3247    fprintf(
3248       stderr,
3249       "Object and End Object names do not match\n"
3250     );
3251     errors++;
3252  }
3253
3254  return (errors) ? -1 : 0;
3255}
3256
Note: See TracBrowser for help on using the repository browser.