forked from Imagelibrary/rtems
* SUPPORT, LICENSE: New files. * Numerous files touched as part of merging the 4.5 branch onto the mainline development trunk and ensuring that the script that cuts snapshots and releases works on the documentation.
1046 lines
22 KiB
C
1046 lines
22 KiB
C
/*
|
|
* 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
|
|
*
|
|
* COPYRIGHT (c) 1988-2002.
|
|
* On-Line Applications Research Corporation (OAR).
|
|
* All rights reserved.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#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 TopString[] = "Top";
|
|
char EmptyString[] = "";
|
|
|
|
char *DocsNextNode;
|
|
char *DocsPreviousNode;
|
|
char *DocsUpNode;
|
|
int NodeNameIncludesChapter = 1;
|
|
|
|
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;
|
|
|
|
static void ProcessFile2(
|
|
FILE *infile,
|
|
FILE *outfile );
|
|
static void PrintFile2(
|
|
FILE *outfile );
|
|
static void ReadFileIntoChain2(
|
|
FILE *InFile );
|
|
|
|
/*************************************************************************
|
|
*************************************************************************
|
|
***** DATA TYPES AND CONSTANT TABLES *****
|
|
*************************************************************************
|
|
*************************************************************************/
|
|
/*
|
|
* Usage Information
|
|
*/
|
|
|
|
char *Usage_Strings[] = {
|
|
"\n",
|
|
"usage: cmd [-cv] [-p prev] [-n next] [-u up] \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 SUBSUBSECTION 3
|
|
#define HEADING 4
|
|
|
|
typedef enum {
|
|
UNUSED, /* dummy 0 slot */
|
|
KEYWORD_CHAPTER,
|
|
KEYWORD_APPENDIX,
|
|
KEYWORD_PREFACE,
|
|
KEYWORD_CHAPHEADING,
|
|
KEYWORD_SECTION,
|
|
KEYWORD_SUBSECTION,
|
|
KEYWORD_SUBSUBSECTION,
|
|
KEYWORD_RAISE,
|
|
KEYWORD_LOWER,
|
|
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;
|
|
int level;
|
|
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 },
|
|
{ "@appendix", SECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
|
|
{ "@preface", 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 },
|
|
{ "@subsubsection", SUBSUBSECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
|
|
{ "@raise", SUBSECTION, RT_FORBIDDEN, BL_FORBIDDEN, NULL },
|
|
{ "@lower", 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,%d>:%s\n",
|
|
line->keyword,
|
|
line->format,
|
|
line->level,
|
|
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->level = -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;
|
|
|
|
OutFile = stdout;
|
|
Verbose = FALSE;
|
|
DocsNextNode = EmptyString;
|
|
DocsPreviousNode = TopString;
|
|
DocsUpNode = TopString;
|
|
|
|
while ((c = getopt(argc, argv, "vcp:n:u:")) != EOF) {
|
|
switch (c) {
|
|
case 'v':
|
|
Verbose = TRUE;
|
|
break;
|
|
case 'c':
|
|
NodeNameIncludesChapter = 0;
|
|
break;
|
|
case 'p':
|
|
DocsPreviousNode = strdup(optarg);
|
|
break;
|
|
case 'n':
|
|
DocsNextNode = strdup(optarg);
|
|
break;
|
|
case 'u':
|
|
DocsUpNode = strdup(optarg);
|
|
break;
|
|
|
|
case '?':
|
|
usage();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( optind != argc )
|
|
{
|
|
usage();
|
|
return 0 ;
|
|
}
|
|
|
|
if ( Verbose )
|
|
fprintf( stderr, "Arguments successfully parsed\n" );
|
|
|
|
FillLinePool();
|
|
|
|
ProcessFile2( stdin, stdout );
|
|
|
|
if ( Verbose )
|
|
fprintf( stderr, "Exitting\n" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ProcessFile
|
|
*/
|
|
|
|
void ProcessFile2(
|
|
FILE *infile,
|
|
FILE *outfile
|
|
)
|
|
{
|
|
int index;
|
|
|
|
/*
|
|
* Read the file into our internal data structure
|
|
*/
|
|
|
|
if ( Verbose )
|
|
printf( "Processing (%s) -> (%s)\n", "stdin", "stdout" );
|
|
|
|
ReadFileIntoChain2( infile );
|
|
|
|
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
|
|
*/
|
|
|
|
PrintFile2( outfile );
|
|
|
|
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 ReadFileIntoChain2(
|
|
FILE *InFile
|
|
)
|
|
{
|
|
int line_count;
|
|
int max_length;
|
|
char *line;
|
|
char Buffer[ BUFFER_SIZE ];
|
|
Line_Control *new_line;
|
|
|
|
if ( !InFile ) {
|
|
fprintf( stderr, "Unable to open (%s)\n", "stdin" );
|
|
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, "@appendix" ) )
|
|
line->keyword = KEYWORD_APPENDIX;
|
|
else if ( strstr( line->Contents, "@preface" ) )
|
|
line->keyword = KEYWORD_PREFACE;
|
|
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 if ( strstr( line->Contents, "@subsubsection" ) )
|
|
line->keyword = KEYWORD_SUBSUBSECTION;
|
|
else if ( strstr( line->Contents, "@raise" ) )
|
|
line->keyword = KEYWORD_RAISE;
|
|
else if ( strstr( line->Contents, "@lower" ) )
|
|
line->keyword = KEYWORD_LOWER;
|
|
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 )
|
|
{
|
|
char Buffer[ BUFFER_SIZE ];
|
|
Line_Control *line;
|
|
Line_Control *next_node;
|
|
Line_Control *up_node;
|
|
Line_Control *new_line;
|
|
Line_Control *menu_insert_point;
|
|
Line_Control *node_line;
|
|
int next_found;
|
|
int menu_items;
|
|
Keyword_indices_t index;
|
|
char ChapterName[ BUFFER_SIZE ];
|
|
char NodeName[ BUFFER_SIZE ];
|
|
char UpNodeName[ BUFFER_SIZE ];
|
|
char NextNodeName[ BUFFER_SIZE ];
|
|
char PreviousNodeName[ BUFFER_SIZE ];
|
|
|
|
/*
|
|
* Set Initial Previous Node Name
|
|
*/
|
|
|
|
strcpy( PreviousNodeName, DocsPreviousNode );
|
|
|
|
for ( line = (Line_Control *) Lines.first ;
|
|
!_Chain_Is_last( &line->Node ) ;
|
|
line = (Line_Control *) line->Node.next
|
|
) {
|
|
|
|
if ( line->level == -1 )
|
|
continue;
|
|
|
|
LineCopyFromRight( line, NodeName );
|
|
|
|
if ( line->keyword == KEYWORD_CHAPTER ||
|
|
line->keyword == KEYWORD_APPENDIX ||
|
|
line->keyword == KEYWORD_PREFACE ||
|
|
line->keyword == KEYWORD_CHAPHEADING ) {
|
|
|
|
strcpy( ChapterName, NodeName );
|
|
|
|
} else if ( NodeNameIncludesChapter ) {
|
|
|
|
sprintf( Buffer, "%s %s", ChapterName, NodeName );
|
|
strcpy( NodeName, Buffer );
|
|
}
|
|
|
|
/*
|
|
* Set Default Next Node Name
|
|
*/
|
|
|
|
next_found = FALSE;
|
|
strcpy( NextNodeName, DocsNextNode );
|
|
|
|
/*
|
|
* 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 );
|
|
|
|
next_node = (Line_Control *) line->Node.next;
|
|
menu_insert_point = next_node;
|
|
menu_items = 0;
|
|
|
|
for ( ; ; ) {
|
|
if ( next_node->keyword == KEYWORD_END )
|
|
break;
|
|
|
|
if ( next_node->level == -1 )
|
|
goto continue_menu_loop;
|
|
|
|
LineCopySectionName( next_node, Buffer );
|
|
if ( !next_found ) {
|
|
next_found = TRUE;
|
|
if (NodeNameIncludesChapter)
|
|
sprintf( NextNodeName, "%s %s", ChapterName, Buffer );
|
|
else
|
|
sprintf( NextNodeName, "%s", Buffer );
|
|
}
|
|
|
|
if ( next_node->level <= line->level )
|
|
break;
|
|
|
|
if ( next_node->level != (line->level + 1) )
|
|
goto continue_menu_loop;
|
|
|
|
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();
|
|
if (NodeNameIncludesChapter)
|
|
sprintf( new_line->Contents, "* %s %s::", ChapterName, Buffer );
|
|
else
|
|
sprintf( new_line->Contents, "* %s::", Buffer );
|
|
_Chain_Insert( menu_insert_point->Node.previous, &new_line->Node );
|
|
|
|
continue_menu_loop:
|
|
next_node = (Line_Control *) next_node->Node.next;
|
|
}
|
|
|
|
/*
|
|
* If menu items were generated, then insert the end of menu stuff.
|
|
*/
|
|
|
|
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 );
|
|
}
|
|
|
|
/*
|
|
* Find the UpNodeName
|
|
*/
|
|
|
|
/* DumpList( &Lines ); */
|
|
|
|
if ( line->level == 0 ) {
|
|
strcpy( UpNodeName, DocsUpNode );
|
|
} else {
|
|
for ( up_node = line;
|
|
up_node && !_Chain_Is_first((Chain_Node *)up_node) ;
|
|
up_node = (Line_Control *) up_node->Node.previous
|
|
) {
|
|
|
|
if ( (up_node->level == -1) )
|
|
continue;
|
|
|
|
if ( up_node->level == (line->level - 1) ) {
|
|
LineCopySectionName( up_node, Buffer );
|
|
if (NodeNameIncludesChapter) {
|
|
if (!strcmp(ChapterName, Buffer))
|
|
sprintf( UpNodeName, "%s", Buffer );
|
|
else
|
|
sprintf( UpNodeName, "%s %s", ChapterName, Buffer );
|
|
} else
|
|
sprintf( UpNodeName, "%s", Buffer );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update the node information
|
|
*/
|
|
|
|
#if 0
|
|
fprintf(
|
|
stderr,
|
|
"@node %s, %s, %s, %s\n",
|
|
NodeName,
|
|
NextNodeName,
|
|
PreviousNodeName,
|
|
UpNodeName
|
|
);
|
|
#endif
|
|
|
|
/* node_line was previously inserted */
|
|
if (!NodeNameIncludesChapter) {
|
|
sprintf(
|
|
node_line->Contents,
|
|
"@node %s, %s, %s, %s",
|
|
NodeName,
|
|
NextNodeName,
|
|
PreviousNodeName,
|
|
UpNodeName
|
|
);
|
|
} else {
|
|
sprintf(
|
|
node_line->Contents,
|
|
"@node %s, %s, %s, %s",
|
|
NodeName,
|
|
NextNodeName,
|
|
PreviousNodeName,
|
|
UpNodeName
|
|
);
|
|
}
|
|
|
|
strcpy( PreviousNodeName, NodeName );
|
|
|
|
/* PrintLine( line ); */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* FormatToTexinfo
|
|
*/
|
|
|
|
void FormatToTexinfo( void )
|
|
{
|
|
Line_Control *line;
|
|
int baselevel = 0;
|
|
int currentlevel;
|
|
|
|
if ( Verbose )
|
|
fprintf( stderr, "-------->INSERTING TEXINFO MENUS\n" );
|
|
|
|
for ( line = (Line_Control *) Lines.first ;
|
|
!_Chain_Is_last( &line->Node ) ;
|
|
line = (Line_Control *) line->Node.next ) {
|
|
|
|
switch (line->keyword) {
|
|
case UNUSED:
|
|
case KEYWORD_OTHER:
|
|
case KEYWORD_END:
|
|
line->level = -1;
|
|
break;
|
|
case KEYWORD_CHAPTER:
|
|
case KEYWORD_APPENDIX:
|
|
case KEYWORD_PREFACE:
|
|
case KEYWORD_CHAPHEADING:
|
|
currentlevel = 0;
|
|
line->level = baselevel + currentlevel;
|
|
break;
|
|
case KEYWORD_SECTION:
|
|
currentlevel = 1;
|
|
line->level = baselevel + currentlevel;
|
|
break;
|
|
case KEYWORD_SUBSECTION:
|
|
currentlevel = 2;
|
|
line->level = baselevel + currentlevel;
|
|
break;
|
|
case KEYWORD_SUBSUBSECTION:
|
|
currentlevel = 3;
|
|
line->level = baselevel + currentlevel;
|
|
break;
|
|
case KEYWORD_RAISE:
|
|
assert( baselevel );
|
|
baselevel--;
|
|
line->level = -1;
|
|
break;
|
|
case KEYWORD_LOWER:
|
|
baselevel++;
|
|
line->level = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
BuildTexinfoNodes();
|
|
}
|
|
|
|
/*
|
|
* PrintFile
|
|
*/
|
|
|
|
void PrintFile2(
|
|
FILE *OutFile
|
|
)
|
|
{
|
|
Line_Control *line;
|
|
|
|
if ( !OutFile ) {
|
|
fprintf( stderr, "Unable to open (%s) for output\n", "stdout" );
|
|
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 ) {
|
|
/* if (line->level != -1) */
|
|
PrintLine( line );
|
|
/* 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';
|
|
}
|