summaryrefslogtreecommitdiffstats
path: root/doc/tools/bmenu/main.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1997-05-27 12:40:11 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1997-05-27 12:40:11 +0000
commitae68ff085724dd35d60151bd153e80b8b0776873 (patch)
tree2f1535a0497f5b872a4744ae13c9264b77e89c11 /doc/tools/bmenu/main.c
parentThis commit was generated by cvs2svn to compensate for changes in r832, (diff)
downloadrtems-ae68ff085724dd35d60151bd153e80b8b0776873.tar.bz2
Initial revision
Diffstat (limited to 'doc/tools/bmenu/main.c')
-rw-r--r--doc/tools/bmenu/main.c985
1 files changed, 985 insertions, 0 deletions
diff --git a/doc/tools/bmenu/main.c b/doc/tools/bmenu/main.c
new file mode 100644
index 0000000000..1a9a309831
--- /dev/null
+++ b/doc/tools/bmenu/main.c
@@ -0,0 +1,985 @@
+/*
+ * main.c
+ *
+ * This program takes a texinfo file without node and menu commands,
+ * build those commands and inserts them.
+ *
+ * It works by reading the input file into a linked list of lines
+ * and then performing sweeps on that list until all formatting is
+ * complete. After the program is run, there is still a little
+ * clean up to be performed by hand. The following have to be fixed
+ * by hand:
+ * + previous of the first node
+ * + next of the last node
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* XXX -- just for testing -- these should be set by options */
+char DocsNextNode[] = "";
+char DocsPreviousNode[] = "Top";
+char DocsUpNode[] = "Top";
+
+extern int optind; /* Why is this not in <stdlib.h>? */
+extern char *optarg; /* Why is this not in <stdlib.h>? */
+
+#ifndef NAME_MAX
+#define NAME_MAX 14 /* Why is the one in limits.h not showing up? */
+#endif
+#define INIT_DATA
+#define EXTERN
+
+#include "base.h"
+
+FILE *OutFile = stdout;
+
+/*************************************************************************
+ *************************************************************************
+ ***** DATA TYPES AND CONSTANT TABLES *****
+ *************************************************************************
+ *************************************************************************/
+/*
+ * Usage Information
+ */
+
+char *Usage_Strings[] = {
+ "\n",
+ "usage: cmd [-bv] files ...\n",
+ "\n",
+ "EOF"
+};
+
+/*
+ * The page separator is not really a keyword and will be purged before
+ * it is seen elsewhere.
+ */
+
+#define PAGE_SEPARATOR "#PAGE"
+
+/*
+ * Section Delimiter Keywords
+ */
+
+#define MAXIMUM_KEYWORD_LENGTH 32
+
+/*
+ * Level indicates where in the format the delimiter is allowed to occur.
+ * 1 indicates a major section divider (e.g. "ATTRIBUTE DESCRIPTIONS:").
+ * 2 indicates a subsection (e.g. "ATTRIBUTE:").
+ * 3 indicates a heading (e.g. "DESCRIPTION:").
+ */
+
+#define TEXT 0
+#define SECTION 1
+#define SUBSECTION 2
+#define HEADING 3
+
+typedef enum {
+ UNUSED, /* dummy 0 slot */
+ KEYWORD_CHAPTER,
+ KEYWORD_CHAPHEADING,
+ KEYWORD_SECTION,
+ KEYWORD_SUBSECTION,
+ KEYWORD_OTHER,
+ KEYWORD_END
+
+} Keyword_indices_t;
+
+#define KEYWORD_FIRST KEYOWRD_CHAPTER
+#define KEYWORD_LAST KEYWORD_END
+
+/*
+ * Line Management Structure
+ */
+
+typedef enum {
+ NO_EXTRA_FORMATTING_INFO,
+ RAW_OUTPUT,
+ PARAGRAPH_OUTPUT
+} ExtraFormat_info_t;
+
+typedef struct {
+ Chain_Node Node;
+ Keyword_indices_t keyword; /* unused is unknown/undecided */
+ ExtraFormat_info_t format;
+ int number;
+ char Contents[ PARAGRAPH_SIZE ];
+} Line_Control;
+
+typedef enum {
+ RT_FORBIDDEN, /* no text to right allowed */
+ RT_OPTIONAL, /* text to right optional -- none below */
+ RT_NONE, /* text to right is "none" or nothing -- none below */
+ RT_REQUIRED, /* text to right required -- none below */
+ RT_BELOW, /* text to right forbidden -- text below required */
+ RT_NONE_OR_BELOW, /* text to right is "none" OR there is text below */
+ RT_EITHER, /* text to right OR below */
+ RT_BOTH /* text to right AND below */
+} Keywords_text_mode_t;
+
+typedef enum {
+ BL_FORBIDDEN, /* text below forbidden */
+ BL_FORMATTED, /* text below is to be formatted as paragraphs */
+ BL_RAW, /* text below is to be unprocessed by this program */
+} Keywords_text_below_t;
+
+typedef (*Keyword_validater_t)( Line_Control * );
+
+typedef struct {
+ char Name[ MAXIMUM_KEYWORD_LENGTH ];
+ int level;
+ Keywords_text_mode_t text_mode;
+ Keywords_text_below_t text_below_mode;
+ Keyword_validater_t keyword_validation_routine;
+} Keyword_info_t;
+
+Keyword_info_t Keywords[] = {
+ { "unused",
+ 0, 0, 0, NULL }, /* so 0 can be invalid */
+ { "@chapter", SECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
+ { "@chapheading",SECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
+ { "@section", SECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
+ { "@subsection", SUBSECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
+ { "", HEADING, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
+ { "END OF FILE", SECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL }
+};
+
+#define NUMBER_OF_KEYWORDS \
+ ( sizeof( Keywords ) / sizeof( Keyword_info_t ) ) - 2
+
+/*
+ * exit_application
+ */
+
+void exit_application(
+ int status
+)
+{
+ fprintf( stderr, "*** Error encountered ***\n" );
+/*
+ fprintf( stderr, "*** Error encountered on line %d ***\n", CurrentLine );
+*/
+ fclose( OutFile );
+ exit( status );
+}
+
+/*************************************************************************
+ *************************************************************************
+ ***** LINE MANIPULATION ROUTINES *****
+ *************************************************************************
+ *************************************************************************/
+
+/*
+ * PrintLine
+ */
+
+void PrintLine(
+ Line_Control *line
+)
+{
+ assert( line );
+
+ if ( line->number == -1 )
+ fprintf( stderr, " " );
+ else
+ fprintf( stderr, "%5d", line->number );
+
+#if 0
+ fprintf( stderr, "%s\n", line->Contents );
+#else
+ /*
+ * Include some debugging information
+ */
+ fprintf(
+ stderr,
+ "<%d,%d>:%s\n",
+ line->keyword,
+ line->format,
+ line->Contents
+ );
+#endif
+}
+
+Chain_Control Line_Pool;
+
+/*
+ * FillLinePool
+ */
+
+void FillLinePool( void )
+{
+ void *pool;
+
+#define LINE_POOL_FILL_COUNT 100
+
+ pool = malloc( sizeof( Line_Control ) * LINE_POOL_FILL_COUNT );
+ assert( pool );
+
+ _Chain_Initialize(
+ &Line_Pool,
+ pool,
+ LINE_POOL_FILL_COUNT,
+ sizeof( Line_Control )
+ );
+}
+
+/*
+ * AllocateLine
+ */
+
+Line_Control *AllocateLine( void )
+{
+ Line_Control *new_line;
+
+ new_line = (Line_Control *) _Chain_Get( &Line_Pool );
+ if ( !new_line ) {
+ FillLinePool();
+ new_line = (Line_Control *) _Chain_Get( &Line_Pool );
+ assert( new_line );
+ }
+
+/*
+ * This is commented out because although it is helpful during debug,
+ * it consumes a significant percentage of the program's execution time.
+
+ memset( new_line->Contents, '\0', sizeof( new_line->Contents ) );
+*/
+ new_line->number = -1;
+
+ new_line->keyword = UNUSED;
+ new_line->format = NO_EXTRA_FORMATTING_INFO;
+
+ new_line->Node.next = NULL;
+ new_line->Node.previous = NULL;
+
+ return new_line;
+}
+
+/*
+ * FreeLine
+ */
+
+void FreeLine(
+ Line_Control *line
+)
+{
+ fflush( stdout );
+ _Chain_Append( &Line_Pool, &line->Node );
+}
+
+/*
+ * DeleteLine
+ */
+
+Line_Control *DeleteLine(
+ Line_Control *line
+)
+{
+ Line_Control *next;
+
+ next = (Line_Control *)line->Node.next;
+ _Chain_Extract( &line->Node );
+ FreeLine( line );
+ return next;
+}
+
+/*
+ * PrintSurroundingLines
+ */
+
+void PrintSurroundingLines(
+ Line_Control *line,
+ int backward,
+ int forward
+)
+{
+ int i;
+ int real_backward;
+ Line_Control *local;
+
+ for ( local=line, real_backward=0, i=1 ;
+ i<=backward ;
+ i++, real_backward++ ) {
+ if ( &local->Node == Lines.first )
+ break;
+ local = (Line_Control *) local->Node.previous;
+ }
+
+ for ( i=1 ; i<=real_backward ; i++ ) {
+ PrintLine( local );
+ local = (Line_Control *) local->Node.next;
+ }
+
+ PrintLine( local );
+
+ for ( i=1 ; i<=forward ; i++ ) {
+ local = (Line_Control *) local->Node.next;
+ if ( _Chain_Is_last( &local->Node ) )
+ break;
+ PrintLine( local );
+ }
+
+}
+
+/*
+ * SetLineFormat
+ */
+
+void SetLineFormat(
+ Line_Control *line,
+ ExtraFormat_info_t format
+)
+{
+ if ( line->format != NO_EXTRA_FORMATTING_INFO ) {
+ fprintf( stderr, "Line %d is already formatted\n", line->number );
+ PrintLine( line );
+ assert( FALSE );
+ }
+
+ line->format = format;
+}
+
+/*
+ * LineCopyFromRight
+ */
+
+void LineCopyFromRight(
+ Line_Control *line,
+ char *dest
+)
+{
+ char *p;
+
+ for ( p=line->Contents ; *p != ' ' ; p++ )
+ ;
+ p++; /* skip the ' ' */
+ for ( ; isspace( *p ) ; p++ )
+ ;
+
+ strcpy( dest, p );
+
+}
+
+/*
+ * LineCopySectionName
+ */
+
+void LineCopySectionName(
+ Line_Control *line,
+ char *dest
+)
+{
+ char *p;
+ char *d;
+
+ p = line->Contents;
+ d = dest;
+
+ if ( *p == '@' ) { /* skip texinfo command */
+ while ( !isspace( *p++ ) )
+ ;
+ }
+
+ for ( ; *p ; )
+ *d++ = *p++;
+
+ *d = '\0';
+}
+
+/*************************************************************************
+ *************************************************************************
+ ***** END OF LINE MANIPULATION ROUTINES *****
+ *************************************************************************
+ *************************************************************************/
+
+/*
+ * main
+ */
+
+int main(
+ int argc,
+ char **argv
+)
+{
+ int c;
+ int index;
+ boolean single_file_mode;
+
+ Verbose = FALSE;
+
+ while ((c = getopt(argc, argv, "bv")) != EOF) {
+ switch (c) {
+ case 'v':
+ Verbose = TRUE;
+ break;
+ case '?':
+ usage();
+ return 0;
+ }
+ }
+
+ if ( Verbose )
+ fprintf( stderr, "Arguments successfully parsed\n" );
+
+ FillLinePool();
+
+ for ( index=optind ; index < argc ; index++ ) {
+ ProcessFile( argv[ index ], NULL );
+ }
+
+ if ( Verbose )
+ fprintf( stderr, "Exitting\n" );
+
+ return 0;
+}
+
+/*
+ * ProcessFile
+ */
+
+void ProcessFile(
+ char *inname,
+ char *outname
+)
+{
+ char out[ 256 ];
+ int index;
+
+ /*
+ * Automatically generate the output file name.
+ */
+
+ if ( outname == NULL ) {
+ for( index=0 ; inname[index] && inname[index] != '.' ; index++ ) {
+ out[ index ] = inname[ index ];
+ }
+
+ out[ index++ ] = '.';
+ out[ index++ ] = 't';
+ out[ index++ ] = 'x';
+ out[ index++ ] = 't';
+ out[ index ] = '\0';
+
+ }
+
+ /*
+ * Read the file into our internal data structure
+ */
+
+ if ( Verbose )
+ printf( "Processing (%s) -> (%s)\n", inname, out );
+
+ ReadFileIntoChain( inname );
+
+ if ( Verbose )
+ fprintf( stderr, "-------->FILE READ IN\n" );
+
+ /*
+ * Remove any spaces before the keyword and mark each keyword line as
+ * such. Also remove extra white space at the end of lines.
+ */
+
+ StripBlanks();
+
+ if ( Verbose )
+ fprintf( stderr, "-------->BLANKS BEFORE KEYWORDS STRIPPED\n" );
+
+
+ FormatToTexinfo();
+
+ if ( Verbose )
+ fprintf( stderr, "-------->FILE FORMATTED TO TEXINFO\n" );
+
+ /*
+ * Print the file
+ */
+
+ PrintFile( out );
+
+ if ( Verbose )
+ fprintf( stderr, "-------->FILE PRINTED\n" );
+
+ /*
+ * Clean Up
+ */
+
+ ReleaseFile();
+
+ if ( Verbose )
+ fprintf( stderr, "-------->FILE RELEASED\n" );
+}
+
+/*
+ * usage
+ */
+
+void usage( void )
+{
+ int index;
+
+ for ( index=0 ; strcmp( Usage_Strings[ index ], "EOF" ) ; index++ )
+ fprintf( stderr, Usage_Strings[ index ] );
+}
+
+/*
+ * ReadFileIntoChain
+ */
+
+void ReadFileIntoChain(
+ char *inname
+)
+{
+ FILE *InFile;
+ int line_count;
+ int max_length;
+ char *line;
+ char Buffer[ BUFFER_SIZE ];
+ Line_Control *new_line;
+
+ InFile = fopen( inname, "r" );
+
+ if ( !InFile ) {
+ fprintf( stderr, "Unable to open (%s)\n", inname );
+ exit( 1 );
+ }
+ assert( InFile );
+
+ max_length = 0;
+ line_count = 0;
+
+ _Chain_Initialize_empty( &Lines );
+
+ for ( ;; ) {
+ line = fgets( Buffer, BUFFER_SIZE, InFile );
+ if ( !line )
+ break;
+
+ Buffer[ strlen( Buffer ) - 1 ] = '\0';
+
+ new_line = AllocateLine();
+
+ strcpy( new_line->Contents, Buffer );
+
+ new_line->number = ++line_count;
+
+ _Chain_Append( &Lines, &new_line->Node );
+ }
+
+ fclose( InFile );
+}
+
+/*
+ * StripBlanks
+ */
+
+void StripBlanks( void )
+{
+ Line_Control *line;
+ Keyword_indices_t index;
+ int indentation;
+ int length;
+
+ for ( line = (Line_Control *) Lines.first ;
+ !_Chain_Is_last( &line->Node ) ;
+ line = (Line_Control *) line->Node.next
+ ) {
+
+ /*
+ * Strip white space from the end of each line
+ */
+
+ length = strlen( line->Contents );
+
+ while ( isspace( line->Contents[ --length ] ) )
+ line->Contents[ length ] = '\0';
+
+ if ( strstr( line->Contents, "@chapter" ) )
+ line->keyword = KEYWORD_CHAPTER;
+ else if ( strstr( line->Contents, "@chapheading" ) )
+ line->keyword = KEYWORD_CHAPHEADING;
+ else if ( strstr( line->Contents, "@section" ) )
+ line->keyword = KEYWORD_SECTION;
+ else if ( strstr( line->Contents, "@subsection" ) )
+ line->keyword = KEYWORD_SUBSECTION;
+ else
+ line->keyword = KEYWORD_OTHER;
+
+ }
+ line = AllocateLine();
+ line->keyword = KEYWORD_END;
+ _Chain_Append( &Lines, &line->Node );
+}
+
+/*
+ * strIsAllSpace
+ */
+
+boolean strIsAllSpace(
+ char *s
+)
+{
+ char *p;
+
+ for ( p = s ; *p ; p++ )
+ if ( !isspace( *p ) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * BuildTexinfoNodes
+ */
+
+void BuildTexinfoNodes( void )
+{
+ Line_Control *line;
+ Line_Control *new_line;
+ Line_Control *next_node;
+ char Buffer[ BUFFER_SIZE ];
+ char ChapterName[ BUFFER_SIZE ];
+ char NodeName[ BUFFER_SIZE ];
+ char NextNode[ BUFFER_SIZE ];
+ char NextNodeName[ BUFFER_SIZE ];
+ char PreviousNodeName[ BUFFER_SIZE ];
+ char UpNodeName[ BUFFER_SIZE ];
+ char SectionName[ BUFFER_SIZE ];
+ char MenuBuffer[ BUFFER_SIZE ];
+ Line_Control *node_insert_point;
+ Line_Control *menu_insert_point;
+ Line_Control *node_line;
+ boolean next_found;
+ int menu_items;
+
+ strcpy( PreviousNodeName, DocsPreviousNode );
+
+ for ( line = (Line_Control *) Lines.first ;
+ !_Chain_Is_last( &line->Node ) ;
+ line = (Line_Control *) line->Node.next
+ ) {
+
+ menu_insert_point = (Line_Control *) line->Node.next;
+
+ switch ( Keywords[ line->keyword ].level ) {
+ case TEXT:
+ case HEADING:
+ break;
+ case SECTION:
+ if ( line->keyword == KEYWORD_END )
+ goto bottom;
+
+ if ( line->keyword == KEYWORD_CHAPTER ||
+ line->keyword == KEYWORD_CHAPHEADING ) {
+ LineCopyFromRight( line, ChapterName );
+ strcpy( UpNodeName, DocsUpNode );
+ strcpy( NodeName, ChapterName );
+ } else {
+ LineCopySectionName( line, Buffer );
+ sprintf( NodeName, "%s %s", ChapterName, Buffer );
+ strcpy( UpNodeName, ChapterName );
+ }
+ strcpy( SectionName, NodeName );
+
+ /*
+ * Go ahead and put it on the chain in the right order (ahead of
+ * the menu) and we can fill it in later (after the menu is built).
+ */
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@ifinfo" );
+ _Chain_Insert( line->Node.previous, &new_line->Node );
+
+ node_line = AllocateLine();
+ _Chain_Insert( line->Node.previous, &node_line->Node );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@end ifinfo" );
+ _Chain_Insert( line->Node.previous, &new_line->Node );
+
+ menu_items = 0;
+
+ if ( line->keyword == KEYWORD_CHAPTER || line->keyword == KEYWORD_CHAPHEADING ) {
+ next_node = (Line_Control *) line->Node.next;
+ next_found = FALSE;
+ for ( ; ; ) {
+ if ( next_node->keyword == KEYWORD_END )
+ break;
+ if ( Keywords[ next_node->keyword ].level == SECTION ) {
+ LineCopySectionName( next_node, Buffer );
+ if ( !next_found ) {
+ next_found = TRUE;
+ sprintf( NextNodeName, "%s %s", ChapterName, Buffer );
+ }
+
+ if ( menu_items == 0 ) {
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@ifinfo" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@menu" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+ }
+
+ menu_items++;
+
+ new_line = AllocateLine();
+ sprintf( new_line->Contents, "* %s %s::", ChapterName, Buffer );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+ }
+ next_node = (Line_Control *) next_node->Node.next;
+ }
+ } else {
+ next_node = (Line_Control *) line->Node.next;
+
+ next_found = FALSE;
+ for ( ; ; ) {
+ if ( Keywords[ next_node->keyword ].level == SECTION ) {
+ if ( !next_found ) {
+ if ( next_node->keyword == KEYWORD_END ) {
+ strcpy( NextNodeName, DocsNextNode );
+ } else {
+ LineCopySectionName( next_node, Buffer );
+ sprintf( NextNodeName, "%s %s", ChapterName, Buffer );
+ }
+ next_found = TRUE;
+ }
+ break;
+ } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
+ LineCopySectionName( next_node, MenuBuffer ); /* has next node */
+
+ if ( menu_items == 0 ) {
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@ifinfo" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@menu" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+ }
+
+ menu_items++;
+
+ new_line = AllocateLine();
+ sprintf( new_line->Contents, "* %s::", MenuBuffer );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+
+ if ( !next_found ) {
+ next_found = TRUE;
+ strcpy( NextNodeName, MenuBuffer );
+ }
+ }
+ next_node = (Line_Control *) next_node->Node.next;
+ }
+ }
+
+ if ( menu_items ) {
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@end menu" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@end ifinfo" );
+ _Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
+ }
+#if 0
+ fprintf(
+ stderr,
+ "@node %s, %s, %s, %s\n",
+ NodeName,
+ NextNodeName,
+ PreviousNodeName,
+ UpNodeName
+ );
+#endif
+ /* node_line was previously inserted */
+ sprintf(
+ node_line->Contents,
+ "@node %s, %s, %s, %s",
+ NodeName,
+ NextNodeName,
+ PreviousNodeName,
+ UpNodeName
+ );
+
+ strcpy( PreviousNodeName, NodeName );
+ break;
+
+ case SUBSECTION:
+ strcpy( UpNodeName, SectionName );
+
+ LineCopyFromRight( line, NodeName );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@ifinfo" );
+ _Chain_Insert( line->Node.previous, &new_line->Node );
+
+ next_node = (Line_Control *) line->Node.next;
+ for ( ; ; ) {
+ if ( Keywords[ next_node->keyword ].level == SECTION ) {
+ if ( next_node->keyword == KEYWORD_END ) {
+ strcpy( NextNodeName, DocsNextNode );
+ } else {
+ LineCopySectionName( next_node, Buffer );
+ sprintf( NextNodeName, "%s %s", ChapterName, Buffer );
+ }
+ break;
+ } else if ( Keywords[ next_node->keyword ].level == SUBSECTION ) {
+ LineCopyFromRight( next_node, NextNodeName );
+ break;
+ }
+ next_node = (Line_Control *) next_node->Node.next;
+ }
+
+#if 0
+ fprintf(
+ stderr,
+ "@node %s, %s, %s, %s\n",
+ NodeName,
+ NextNodeName,
+ PreviousNodeName,
+ UpNodeName
+ );
+#endif
+ new_line = AllocateLine();
+ sprintf(
+ new_line->Contents,
+ "@node %s, %s, %s, %s",
+ NodeName,
+ NextNodeName,
+ PreviousNodeName,
+ UpNodeName
+ );
+ _Chain_Insert( line->Node.previous, &new_line->Node );
+
+ new_line = AllocateLine();
+ strcpy( new_line->Contents, "@end ifinfo" );
+ _Chain_Insert( line->Node.previous, &new_line->Node );
+
+ strcpy( PreviousNodeName, NodeName );
+ break;
+ }
+ }
+bottom:
+}
+
+/*
+ * FormatToTexinfo
+ */
+
+void FormatToTexinfo( void )
+{
+ if ( Verbose )
+ fprintf( stderr, "-------->INSERTING TEXINFO MENUS\n" );
+
+ BuildTexinfoNodes();
+}
+
+/*
+ * PrintFile
+ */
+
+void PrintFile(
+ char *out
+)
+{
+ Line_Control *line;
+
+ OutFile = fopen( out, "w+" );
+
+ if ( !OutFile ) {
+ fprintf( stderr, "Unable to open (%s) for output\n", out );
+ exit_application( 1 );
+ }
+ assert( OutFile );
+
+ for ( line = (Line_Control *) Lines.first ;
+ !_Chain_Is_last( &line->Node ) ;
+ line = (Line_Control *) line->Node.next ) {
+ fprintf( OutFile, "%s\n", line->Contents );
+/*
+ fprintf(
+ OutFile,
+ "(%d,%d)%s\n",
+ line->keyword,
+ line->format,
+ line->Contents
+ );
+*/
+ }
+}
+
+/*
+ * DumpList
+ */
+
+void DumpList(
+ Chain_Control *the_list
+)
+{
+ Line_Control *line;
+
+ fprintf( stderr, "---> Dumping list (%p)\n", the_list );
+
+ for ( line = (Line_Control *) the_list->first ;
+ !_Chain_Is_last( &line->Node ) ;
+ line = (Line_Control *) line->Node.next ) {
+ fprintf( stderr, "%s\n", line->Contents );
+ }
+}
+
+/*
+ * ReleaseFile
+ */
+
+void ReleaseFile()
+{
+ Line_Control *line;
+ Line_Control *next;
+
+ for ( line = (Line_Control *) Lines.first ;
+ !_Chain_Is_last( &line->Node ) ;
+ ) {
+ next = (Line_Control *) line->Node.next;
+ line = next;
+ }
+}
+
+/*
+ * strtoInitialCaps
+ */
+
+void strtoInitialCaps(
+ char *dest,
+ char *src
+)
+{
+ char *source = src;
+ char *destination = dest;
+
+ source = src;
+ destination = (dest) ? dest : src;
+
+ while ( *source ) {
+ while ( isspace( *source ) )
+ *destination++ = *source++;
+
+ if ( !*source )
+ break;
+
+ *destination++ = toupper( *source++ );
+
+ for ( ; *source && !isspace( *source ) ; source++ )
+ *destination++ = tolower( *source );
+
+ if ( !*source )
+ break;
+ }
+
+ *destination = '\0';
+}