/*
	RTF.c  Output file to generate RTF for Windows 3.0 help system

    10-06-1989 Matt Saettler
     ...
    10-11-1989 MHS Block output instead of specific output
     ...
    10-15-1989 MHS Autodoc
    10-16-1989 MHS Added support for rtnregs
    01-24-1990 MHS Added support for masm Callbacks
    01-31-1990 MHS Added support for conditionals
    03-12-1990 MHS added support for Structs/Unions

 Copyright 1989, 1990 Microsoft Corp.  All Rights Reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#include "types.h"
#include "docfmt.h"
#include "process.h"
#include "RTF.h"
#include "errstr.h"
#include "misc.h"

#include "head.h"
#include "tail.h"

#define FUNCHELP 1
#define MSGHELP  2
#define CBHELP	 3
#define FUNCDOC  4
#define MSGDOC	 5
#define CBDOC	 6
#define INTDOC	 7
#define INTHELP  8
#define MASMDOC  9
#define MASMHELP 10
#define MASMCBDOC  CBDOC		// HACK HACK
#define MASMCBHELP CBHELP		// PRETEND it is just another CB
#define STRUCTHELP 11
#define STRUCTDOC  12
#define UNIONHELP  13
#define UNIONDOC   14

void RTFLineOut(FILE * fpoutfile, char * pch);
void RTFGenIndex(FILE * file, files curfile);
void RTFParmOut(FILE *file, aParm *pparm, int hselect);
void copylines(FILE * phoutfile, char **lines);
void RTFRegOut(FILE *file, aReg *reg, int hselect);
void RTFFieldOut(FILE *file, aBlock *pBlock, int hselect);
void RTFOtherOut(FILE *file, aOther *other, int hselect);
void RTFCondOut(FILE *file, aCond *cond, int hselect);
void RTFSUOut1(FILE *file, aSU *SU, int hselect, int wType);
void RTFTypeOut1(FILE *file, aType *type, int hselect);
void RTFsubFieldOut1(FILE *file, aField *field , int hselect);
void RTFSUOut2(FILE *file, aSU *SU, int hselect, int wType);
void RTFTypeOut2(FILE *file, aType *type, int hselect);
void RTFsubFieldOut2(FILE *file, aField *field , int hselect);

void RTFDoneText( FILE *fpoutfile );

#define FLAGRTN   1
#define FLAGPARM  2
#define FLAGREG   3

void RTFFlagOut(FILE *file, aFlag *flag, int hselect, int flags);
void RTFDumpParms(FILE *file, aBlock *pBlock, int hselect);
void RTFDumpLevel(FILE *file, aLine *pLine, int hselect);
void RTFDumpX(FILE *file, char *ach);

int fSubBlock=0;

char	*pchparm="<p>"; 	    // 'old' style attributes
char	*pchfunc="<f>";
char	*pchdefault="<d>";

char	*pchrtfparm="{\\i ";	    // attributes for parameter
char	*pchrtffunc="{\\b ";	    // attributes for function
char	*pchrtftype="{\\b ";	    // attributes for type
char	*pchrtfmsg ="{ ";			// attributes for message
char	*pchrtfelem="{\\b ";	    // attributes for element
char	*pchrtfnone  ="{ ";			// attributes for unknown style
char	*pchrtfdefault="}";			// how to restore to default attributes


int blocksprocessed=0;

char *flagdoc ="\\par\n\\pard\\%s\\f26\\fs20\\li%d\\sa60\\sb60\\sl0\\fi%d\\tx5760\\tx6480\n";

char *sepsynhelp="\\tab\n";
char *sepsyndoc ="\\tab\n";

char *synhelp="\\pard\\plain\\f26\\fs20\\fi-1440\\sl0\\li1440\\tx1440\\tx3600\\tx5760\\tx6480\\par\n";
char *syndoc ="\\par\\pard\\plain\\f26\\fs20\\li0000\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *sephohelp="\\tab\n";
char *sephodoc ="\\par\n\\pard\\plain\\f26\\fs20\\li1080\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *hcbhelp="\\pard\\plain\\f26\\fs20\\fi0000\\li0000\\tx1440\\tx6480\\par\n";
char *hcbdoc ="\\par\\pard\\plain\\f26\\fs20\\fi0000\\li0000\\tx1080\\tx4320\\tx6480\n";

char *ecbhelp="\\par\\pard\n";
char *ecbdoc ="\\par\\pard\n";

char *head0help="\\pard\\f26\\fs28\\fi0000\\li0000\\tx1440\\tx6480{\\b\n";
char *head0doc ="\\par\\pard\\brdrt\\brdrs\\f26\\fs28\\fi0000\\li0000\\tx1080\\tx4320\\tx6480\n\\v\\f26\\fs20 {\\tc \\plain{\\b \\f26\\fs20 ";

char *ehead0help="}";
char *ehead0doc ="}}\\plain\\f26\\fs20\\li0000\\sl0\\fi0000\n";

char *hohelp="\\par\\pard\\plain\\f26\\fs20\\fi-1440\\sl0\\li1440\\tx1440\\tx3600\\tx5760\\tx6480\n";
char *hodoc ="\\par\\pard\\plain\\f26\\fs20\\li0000\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *hparmhelp="\\par\\pard\\plain\\f26\\sl0\\sb60\\sa60\\fs20\\fi-2160\\li3600\\tx1440\\tx3600\\tx5760\\tx6480\n";
char *hparmdoc ="\\par\\pard\\sbys\\f26\\fs20\\ri3200\\li1080\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *sepreghelp="\\tab\n";
char *sepregdoc ="\\par\n\\pard\\sbys\\f26\\fs20\\li3240\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *hreghelp="\\par\\pard\\plain\\f26\\fs20\\fi-1440\\li3600\\tx1440\\tx3600\\tx5760\\tx6480\n";
char *hregdoc ="\\par\\pard\\sbys\\f26\\fs20\\ri3200\\li1080\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *hvalhelp="\\par\\pard\\plain\\f26\\sl0\\sb60\\sa60\\fs20\\fi-2160\\li5760\\tx5760\\tx6480\n";
char *sepvalhelp="\\tab\n";

char *hvaldoc="\\par\\pard\\plain\\f26\\sl0\\sb60\\sa60\\fs20\\fi-2160\\li5760\\tx5760\\tx6480\n";
char *sepvaldoc="\\tab\n";

char *sepparmhelp="\\tab\n";
char *sepparmdoc ="\\par\n\\pard\\sbys\\f26\\fs20\\li3240\\sl0\\fi0000\\tx2160\\tx3240\\tx4320\\tx6480\n";

char *hdeschelp="\\par\\pard\\plain\\f26\\fs20\\fi0000\\li1440\\tx1440\\tx3600\\tx5760\n";
char *hdescdoc ="\\par\\pard\\plain\\f26\\fs20\\fi0000\\li1080\\tx1080\\tx2160\\tx3240\\tx4320\n";

char *SUpar ="\\par\\pard\\plain\\f1\\fs20\\fi-3600\\li5760\\tx5760\n";

char *hSUelements="\\par\\pard\\plain\\f26\\fs20\\fi-3600\\li5760\\tx5760\\tx6480\n";


char *preg2a= "{\\b\\ulw Register}";

char *p2a= "{\\b\\ulw Type/Parameter}";
char *p2ahelp= "{\\b\\ulw Parameter}";
char *p2b= "{\\b\\ulw Description}\\par\n";
char *p2bhelp= "{\\b\\ulw Type/Description}\n";
char *p3a= "{\\b\\ulw Value}";
char *p3b= "{\\b\\ulw Meaning}\n";


///////////////////////////////////////////////////////////////////////////
char achindex[256];

struct _repl 
{
	char *from;
	char *to;
	int state;
	int size;
};

char ach2[100];

#define DEFAULT 1
#define TYPE	15
#define ELEMENT 16
#define FUNC 17
#define MSG 18
#define PARM	19

struct _repl reps[]= 
{
	"<t>", "", TYPE,			0,
	"<e>", "", ELEMENT,			0,
	"<f>", "", FUNC,			0,
	"<m>", "", MSG, 			0,
	"<p>", "", PARM,			0,
	"<d>", "", DEFAULT,			0,
	"<t", "", TYPE,				0,
	"<e", "", ELEMENT,			0,
	"<f", "", FUNC,				0,
	"<m", "", MSG,				0,
	"<p", "", PARM,				0,
	    
// fence	    
	    NULL, NULL, 0, 0
	    
};


static	int state=0;
static	int i=0;

void RTFtextOut( FILE * file,aLine * line);

/*
 *	@doc INTERNAL
 *
 *	@func void | RTFtextOut | This outputs the given text lines.
 *
 *	@parm aLine * | line | Specifies the text to output.
 */
void RTFtextOut( file, line )
FILE * file;
aLine * line;
{
    assert(!state);
    i=0;
    while( line != NULL ) 
    {
	if(!line->next && !line->text[0])
	    break;	// stop at trailing blank lines
	    
        RTFLineOut(file, line->text);
	//
	//  Should we put out a trailing space?
	//
	//  if the previous line ends in a word, or a <D> then splat on
	//  a space so words will not run together.
	//
	//
	if(line->next)
	{
	    int len;
	    char ch;

	    len = strlen(line->text);
	    ch	= line->text[len-1];

            if ( len>=2 && !state &&
		( isalpha(ch) || isdigit(ch) || ch == '.' ||
		  (ch == '>' && line->text[len-2] == 'D') 
		) 
	       )
		fprintf( file, " ");
        }
	fprintf(file,"\n");
	line = line->next;
    }
    RTFDoneText(file);
    state=0;
}


void RTFDoneText( FILE *fpoutfile )
{
//    IndexTag *pIndex;
    // close off any processing that was in progress.
    char *pch;
    
    if(state)
    {
	achindex[i]=0;
	
	// strip leading spaces.
	i=0;
	while(isspace(achindex[i]))
	    i++;
    
	if(outputType==RTFHELP && state != PARM)
	{
	    /* output crossreference if in HELP, but not for parameters */
	    if(state!=ELEMENT)
	    {

		if((state == FUNC) || (state == TYPE))
			fprintf( fpoutfile, "{\\b\\uldb\\f26\\fs20 ");
		else
			fprintf( fpoutfile, "{\\uldb\\f26\\fs20 ");
		fprintf( fpoutfile, "%s", achindex + i);
		fprintf( fpoutfile, "}{\\v\\f26\\fs20 ");
		fprintf( fpoutfile, "%s",achindex + i);
		fprintf( fpoutfile, "}\\plain\\f26\\fs20 ");
	    }
	    else
	    {
		pch=achindex+i;
		while(*pch)		// just leave element name
		{
		    if(*pch=='.')
		    {
			pch++;
			break;
		    }
		    pch++;
		}
		if(!*pch)
		    fprintf(errfp,"warning: bad element reference in %s\n",achindex);
		 
		fprintf( fpoutfile, "{\\uldb\\b\\f26\\fs20 ");
		fprintf( fpoutfile, "%s", pch);
		fprintf( fpoutfile, "}{\\v\\f26\\fs20 ");
	    
		pch=achindex+i;
		while(*pch)		// just leave struct name
		{
		    if(*pch=='.')
		    {
			*pch=0;
			break;
		    }
		    pch++;
		}
		fprintf( fpoutfile, "%s",achindex + i);
		fprintf( fpoutfile, "}\\plain\\f26\\fs20 ");
	    
	    }
	    
	}
	else
	{
		switch  (state)
		{
			case PARM:
				fprintf( fpoutfile, pchrtfparm );
				break;
			case FUNC:
				fprintf( fpoutfile, pchrtffunc );
				break;
			case MSG:
				fprintf( fpoutfile, pchrtfmsg );
				break;
			case TYPE:
				fprintf( fpoutfile, pchrtftype );
				break;
			case ELEMENT:
				fprintf( fpoutfile, pchrtfelem );
				break;
			default:
				fprintf( fpoutfile, pchrtfnone );
				break;
		}
		
	    fprintf( fpoutfile,achindex +i);
	    fprintf( fpoutfile,pchrtfdefault);
	}
	
        state=0;
	i=0;
    }
	
}
#define ERRORMARK(w)	for(j=0;j<w;j++) fprintf(errfp," "); fprintf(errfp,"^\n");

/*
 *	@doc INTERNAL
 *
 *	@func void | RTFLineOut | This outputs the given text line.
 *
 *	@parm char * | line | Specifies the text to output.
*/
void
RTFLineOut(FILE * fpoutfile, char * pch)
{
    int j;

    int k;
    int flag;
    char *pchs=pch;
    
    
    // first time init
    if(reps[0].size==0)
	for(j=0;reps[j].from; j++)
	    reps[j].size=strlen(reps[j].from);

/* check for and process blank lines */
    if(!*pch)
    {
	// need to set cur par sep formatting
	
	//  HACK.  Doing a 'tab' should get us to column indent.
	//            (assumes fi is set to -x and tx at indent)
	//
	// the tab puts in a blank line also
	
	if(fSubBlock)		// if in sub-block
	    fprintf(fpoutfile, "\\par\\tab");
	else
	    fprintf(fpoutfile, "\\par\\par\\tab");
    }

    while(*pch)
    {
	if(state)
	{
	    // Handles <x>yyy<d> and <x yyy>
	    
	    if(*pch!='>' && *pch!='<')
	    {
		if(*pch!='\n')
		    achindex[i++]=*pch;
		pch++;
	    }
	    else
	    {
		RTFDoneText(fpoutfile);
		if(*pch=='<')
		{	// it was a <
		    pch++;
		    if(*pch=='d' || *pch=='D')
		    {
			// it's OK, it's <d
			pch++;
			if(*pch!='>')
			{
			    fprintf(errfp, 
	"non-fatal error: Badly formed formatting code in text: %s\n",pchs);
			    ERRORMARK(pch-pchs);			    
			}
			pch++;
		    }
		    else
		    {
			// we don't know what it is.  Skip it.
			
			fprintf(errfp, 
	"non-fatal error: Unexpected formatting code in text: %s\n",pchs);
			ERRORMARK(pch-pchs);			    
			
			while(*pch && *pch!='>')
			    pch++;
			    
			if(*pch)
			    pch++;
		    }
		}
		else	// it's just >
		    pch++;
	    }
	    continue;	    
	}
    
	if(*pch == '\t')
	{
	    fprintf(fpoutfile," ");
	    pch++;
	    continue;
	}
	    
	if(*pch == '\\')
	{
	    pch++;
	    
	    if (*pch == '|' || *pch == '@')
		    fprintf(fpoutfile, "%c", *pch);
	    else
	    {
		pch--;
		fprintf(fpoutfile,"\\%c",*pch);	// output '\\'
	    }
	    pch++;
	    continue;
	}
    
	if(*pch == '{' || *pch == '}')
	{
	    fprintf(fpoutfile,"\\%c",*pch);
	    pch++;
	    continue;
	}
    
	if(*pch=='<' && pch[1]!='<')
	{
	    for(j=0; reps[j].from!=NULL; j++)
	    {
		if(!strnicmp(pch,reps[j].from,reps[j].size))
		{
		    if(reps[j].state==DEFAULT )
		    {
			if(!state)
			{

		    fprintf(errfp, "Ending without start. Ignored.\n");

			}
			else
			{
			    // reset state and take care of business
			    RTFDoneText(fpoutfile);
			}
			    
		    } 
		    state=reps[j].state;
		    pch+=reps[j].size;
		    break; // the for loop
		}
	    }

	    if(reps[j].from==NULL)  // we didn't find it in table
	    {
                fprintf(errfp, 
	"non-fatal error: Unknown formatting code in text: %s\n",pch);
		putc(*pch, fpoutfile);
		pch++;
	    }
	}
	else
	{
            putc(*pch, fpoutfile);
            pch++;
        }
    }

    RTFDoneText(fpoutfile);
}
///////////////////////////////////////////////////////////////////////////

/*
 *	@doc INTERNAL
 *
 *	@func void | RTFXrefOut | This outputs the given Xref lines.
 *	(lines are seperated by <new-line>)
 *
 *	@parm aLine * | line | Specifies the text to output.
 */
void RTFXrefOut(FILE * file,aLine * line);
void RTFXrefOut( file, line )
FILE * file;
aLine * line;
{
    char ach[80];
    int i;
    char *pch;

    while( line != NULL )
    {

	pch=line->text;

	while(isspace(*pch))
	    pch++;

	while(*pch)
	{
	    i=0;
	    while(*pch && !(*pch ==',' || isspace(*pch) ) )
		ach[i++]=*pch++;

	    if(i>0)
	    {
		ach[i]=0;
		RTFDumpX(file, ach);
	    }

	    while(*pch && (*pch == ',' || isspace(*pch)))
	    {
		pch++;
	    }
//	    if(*pch && outputType == RTFDOC )
	    // put commas between items
		fprintf(file, ", ");

	}

	fprintf( file, "\n" );
	line = line->next;
	if(line)
	    fprintf( file, " ");

    }
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFDumpX | This function outputs a Crossreference.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm char * | pch | Specifies the name of the Crossreference.
 *
 */
void
RTFDumpX(FILE *file, char *pch)
{
    if(outputType==RTFHELP)
    {
	fprintf( file, "{\\uldb\\f26\\fs20 ");
	fprintf( file, "%s",pch);
	fprintf( file, "}{\\v\\f26\\fs20 ");
	fprintf( file, "%s",pch);
	fprintf( file, "}\n\\plain\\f26\\fs20 ");
    }
    else
	fprintf( file, "%s", pch);
}


/*
 *  @doc INTERNAL RTF
 *
 *  @func void | RTFtextOutLn | This outputs the given text lines.
 *  (lines are seperated by <new-line>)
 *
 *  @parm FILE * | file | Specifies the output file.
 *
 *  @parm aLine * | line | Specifies the text to output.
 */
void RTFtextOutLn( FILE * file,aLine * line);
void RTFtextOutLn( file, line )
FILE * file;
aLine * line;
{
    RTFtextOut(file,line);
}

/*
 *	@doc INTERNAL
 *
 *	@func void | RTFBlockOut | This outputs the block information in
 *			       RTF Format.
 *
 *	@parm aFuncBlock * | func | Specifies a pointer to the function
 *		information
 *
 *	@parm FILE * | file | File to send output to.
 */
void RTFBlockOut(aBlock * pBlock, FILE * file)
{
    aParm * parm;
    aFlag * flag;
    aBlock *pcurBlock;
    aCond *cond;
    int iblock ;
    
    int hselect;

    blocksprocessed++;
    
/* add to hselect the block type */
    if( !pBlock || !file )
    {
	fprintf(errfp,"XXX:RTFBlockOut: parameter error\n");
	return;
    }

    if( pBlock->blockType == FUNCTION)
	hselect= (outputType == RTFHELP) ? FUNCHELP : FUNCDOC;
    else if( pBlock->blockType == MESSAGE )
	hselect= (outputType == RTFHELP) ? MSGHELP : MSGDOC;
    else if( pBlock->blockType == CALLBACK )
	hselect= (outputType == RTFHELP) ? CBHELP : CBDOC;
    else if( pBlock->blockType == MASMBLOCK )
	hselect= (outputType == RTFHELP) ? MASMHELP : MASMDOC;
    else if( pBlock->blockType == MASMCBBLOCK )
	hselect= (outputType == RTFHELP) ? MASMCBHELP : MASMCBDOC;
    else if( pBlock->blockType == CALLBACK )
	hselect= (outputType == RTFHELP) ? INTHELP : INTDOC;
    else if( pBlock->blockType == STRUCTBLOCK )
	hselect= (outputType == RTFHELP) ? STRUCTHELP : STRUCTDOC;
    else if( pBlock->blockType == UNIONBLOCK )
	hselect= (outputType == RTFHELP) ? UNIONHELP : UNIONDOC;
    else
    {
	fprintf(errfp,"Unknown block type in RTFBlockOut\n");
	return;
    }

    switch(hselect)
    {
	case FUNCHELP:
	case MASMHELP:
	case INTHELP:
	case MSGHELP:
	case STRUCTHELP:
	case UNIONHELP:
	    fprintf( file, "\\par\\page K{\\footnote{\\up6 K} "); /* keyword */
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, "} ${\\footnote{\\up6 $} "); /* section Title */
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, "} +{\\footnote{\\up6 +} "); /* order */
	    fprintf( file, "T");
//	    RTFtextOut( file, pBlock->name );
	    fprintf( file, "} #{\\footnote{\\up6 #} "); /* make target */
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, "}\n");
	    break;
    }

    /* process name */
    switch(hselect)
    {
	case MASMHELP:
	case INTHELP:
	case FUNCHELP:
	case MSGHELP:
	case STRUCTHELP:
	case UNIONHELP:
	    fprintf( file, head0help);
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, ehead0help);

	    break;

	case CBHELP:
	case CBDOC:
	    /* nothing */
	    break;
	case FUNCDOC:
	case MSGDOC:
	case INTDOC:
	case MASMDOC:
	case STRUCTDOC:
	case UNIONDOC:
	    fprintf( file, head0doc);
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, ehead0doc);

	    break;

    }

    if(pBlock->doclevel && dumplevels)
	RTFDumpLevel(file, pBlock->doclevel, hselect);

    if(outputType!= RTFHELP)
	fprintf(file, "\\par\\pard\n");	// blank line

    /* handle outputting syntax */
    switch(hselect)
    {
	case CBHELP:
	    fprintf( file, synhelp );
	    fprintf( file, "{\\b %s}\\tab \n","Callback");
		
	    fprintf( file, " {\\b ");
	    RTFtextOut( file, pBlock->type );
	    fprintf( file, "}");

	    fprintf( file, " {\\i ");
	    RTFtextOut( file, pBlock->name );
	    fprintf( file, "}");
	    fprintf( file, "\\par\n" );
	    
	    fprintf( file, sepsynhelp );

	    if( pBlock->parm )
	    {
		parm = pBlock->parm;
		while( parm )
		{
		    fprintf( file, "{\\b ");
		    RTFtextOut( file, parm->type );
		    fprintf( file, "} " ); // << note the trailing space
		    
		    fprintf( file, "{\\i ");
		    RTFtextOut( file, parm->name );
		    fprintf( file, ";}" ); // << note the ';'
		    parm = parm->next;
		    if( parm )
		    {
			fprintf( file, "\\par\\tab\n" );
		    }
		}
		parm=NULL;
	    }

	    fprintf( file, "\\par\n" );

	    break;
	case MASMHELP:
	case INTHELP:
	case FUNCHELP:
	    fprintf( file, synhelp );
	    fprintf( file, "{\\b %s}\n","Syntax" );
	    fprintf( file, sepsynhelp );

	    RTFDumpParms(file, pBlock, hselect);

	fprintf( file, "\\par\n" );

	    break;
	case UNIONHELP:
	case STRUCTHELP:
	case MSGHELP:
	    break;

	case INTDOC:
	case MASMDOC:
	case FUNCDOC:
	case CBDOC:
	    fprintf( file, syndoc );
	    fprintf( file, "{\\b %s}\n",
		     (hselect==CBDOC) ? "Callback" : "Syntax" );
	    fprintf( file, sepsyndoc );

	    RTFDumpParms(file, pBlock, hselect);

	    fprintf( file, "\\par\n" );
	    break;

	case UNIONDOC:
	case STRUCTDOC:
	case MSGDOC:
	    break;
    }

    /* description block */
    switch(hselect)
    {
	case MASMHELP:
	case INTHELP:
	case FUNCHELP:
	case CBHELP:
	case MSGHELP:
	case UNIONHELP:
	case STRUCTHELP:
	    fprintf( file, hdeschelp );
	    RTFtextOutLn( file, pBlock->desc );
	    fprintf( file, "\\par\n" );

	    break;

	case INTDOC:
	case MASMDOC:
	case FUNCDOC:
	case CBDOC:
	case MSGDOC:
	case UNIONDOC:
	case STRUCTDOC:
	    fprintf( file, hdescdoc );
	    RTFtextOutLn( file, pBlock->desc );
	    fprintf( file, "\\par\n" );
	    break;
    }

    if( pBlock->reg  )
    {
	RTFRegOut( file, pBlock->reg, hselect);
	if(pBlock->parm)
  fprintf(errfp,"Warning: Block contains BOTH Registers and API parms.\n");
    }

    if( pBlock->parm  )
    {
	RTFParmOut( file, pBlock->parm, hselect);
    }

    if( pBlock->field )
	RTFFieldOut( file, pBlock, hselect);
	
    if( pBlock->other)
	RTFOtherOut( file, pBlock->other, hselect);
	
    /* return description */
    if( pBlock->rtndesc  )
    {
	switch(hselect)
	{
	    case FUNCHELP:
	    case MASMHELP:
	    case INTHELP:
	    case CBHELP:
	    case MSGHELP:
		// leave extra blank line before return value
		fprintf(file,"\n\\par");
		fprintf( file, hohelp );

		fprintf( file, "{\\b Return Value}" );
		fprintf( file, sephohelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hodoc );

		fprintf( file, "{\\b Return Value}" );
		fprintf( file, sephodoc);

		break;

	}   // switch

	RTFtextOutLn( file, pBlock->rtndesc );

	if(pBlock->rtnflag)
	{
	    RTFFlagOut(file, pBlock->rtnflag, hselect, FLAGRTN);
	}
	if(pBlock->rtnreg)
	{
	    RTFRegOut(file, pBlock->rtnreg, hselect);
	}
	fprintf( file, "\\par\n" );
	
    }	// if rtndesc
    else
	if(pBlock->rtnflag)
	    fprintf(errfp,"XXX: Return flags without return desc\n");

    for( cond = pBlock->cond; cond; cond = cond->next )
    {
	switch(hselect)
	{
	case MASMHELP:
	case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hohelp );

		fprintf( file, "{\\b Conditional}" );
		fprintf( file, sephohelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hodoc );

		fprintf( file, "{\\b Conditional}" );
		fprintf( file, sephodoc);

		break;
	}
	RTFCondOut(file, cond, hselect);

	fprintf( file, "\\par\n" );
    }

    if( pBlock->comment )
    {
	switch(hselect)
	{
	case MASMHELP:
	case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hohelp );

		fprintf( file, "{\\b Comments}" );
		fprintf( file, sephohelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hodoc );

		fprintf( file, "{\\b Comments}" );
		fprintf( file, sephodoc);

		break;
	}
	RTFtextOutLn( file, pBlock->comment );
	fprintf( file, "\\par\n" );
    }

    if( pBlock->uses )
    {
	switch(hselect)
	{
	case MASMHELP:
	case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hohelp );

		fprintf( file, "{\\b Uses}" );
		fprintf( file, sephohelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hodoc );

		fprintf( file, "{\\b Uses}" );
		fprintf( file, sephodoc);

		break;
	}
	RTFtextOutLn( file, pBlock->uses );
	fprintf( file, "\\par\n" );
    }

    if( pBlock->cb)
    {
	pcurBlock=pBlock->cb;
	while(pcurBlock)
	{
	    RTFBlockOut(pcurBlock, file );
	    pcurBlock=pcurBlock->next;
	}
    }

    if( pBlock->xref )
    {
	switch(hselect)
	{
	    case MASMHELP:
	    case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hohelp );

		fprintf( file, "{\\b See Also}" );
		fprintf( file, sephohelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hodoc );

		fprintf( file, "{\\b Related Functions}" );
		fprintf( file, sephodoc);

		break;
	}

	RTFXrefOut( file, pBlock->xref );
	fprintf( file, "\\par\n" );
    }

}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFDumpLevel | This function outputs the DOC Level.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aLine * | pLine | Specifies the list of Doc Levels.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 */
void
RTFDumpLevel(FILE *file, aLine *pLine, int hselect)
{
    fprintf(file, "\\tab ");

    while(pLine)
    {
	if(pLine->text)
	{
	    fprintf( file, "{\\scaps %s}", pLine->text);
	    pLine=pLine->next;
	    if(pLine)
		fprintf(file, ", ");
	}

    }

}


/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFDumpParms | This functions outputs the Parameters
 *  for a declaration in the specfied mode to the output file.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aLine * | pLine | Specifies the list of Doc Levels.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 */
void
RTFDumpParms(FILE *file, aBlock *pBlock, int hselect)
{
    aParm *parm;

    assert(hselect!=CBHELP);
    
    fprintf( file, " {\\b ");
    RTFtextOut( file, pBlock->type );
    fprintf( file, "}");

    fprintf( file, " {\\b ");
    RTFtextOut( file, pBlock->name );
    fprintf( file, "}");

    switch(hselect)
    {
	case CBDOC:
	    if( pBlock->blockType == MASMCBBLOCK )
		break;
	case FUNCHELP:
	case FUNCDOC:
	    fprintf( file, "(" );
	    break;
	case CBHELP:
	    break;
    }
    if( pBlock->parm )
    {
	parm = pBlock->parm;
	while( parm )
	{
	    fprintf( file, "{\\i ");
	    RTFtextOut( file, parm->name );
	    fprintf( file, "}" );
	    parm = parm->next;
	    if( parm )
	    {
		    fprintf( file, ", " );
	    }
	}
    }

    switch(hselect)
    {
	case CBDOC:
	case CBHELP:
	    if( pBlock->blockType == MASMCBBLOCK )
		break;
	case FUNCHELP:
	case FUNCDOC:
	    fprintf( file, ")" );
	    break;
    }

    return;
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFRegOut | This function outputs the specified Register
 *  structure in the specifed mode to the output file.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aReg * | reg | Specifies the list of Registers.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 */
void
RTFRegOut(FILE *file, aReg *reg, int hselect)
{
    switch(hselect)
    {
	case MASMHELP:
	case INTHELP:
	case FUNCHELP:
	case CBHELP:
	case MSGHELP:
	    fprintf( file, hreghelp );
	    fprintf( file, preg2a );
	    fprintf( file, sepreghelp);
	    fprintf( file, p2b );

	    break;

	    case INTDOC:
	    case MASMDOC:
	case FUNCDOC:
	case CBDOC:
	case MSGDOC:
	    fprintf( file, hregdoc );
	    fprintf( file, preg2a );
	    fprintf( file, sepregdoc);
	    fprintf( file, p2b );
	    break;
    }

    while( reg )
    {
	switch(hselect)
	{
	    case MASMHELP:
	    case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hreghelp );
		fprintf( file, "{\\i ");
		RTFtextOut( file, reg->name );
		fprintf( file, "} " );
		fprintf( file, sepreghelp);

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hregdoc );
		fprintf( file, "{\\i ");
		RTFtextOut( file, reg->name );
		fprintf( file, "} " );
		fprintf( file, sepregdoc);
		break;
	}

	RTFtextOutLn( file, reg->desc );
	fprintf( file, "\n" );

	if(reg->flag)
	    RTFFlagOut(file, reg->flag, hselect, FLAGREG);


	fprintf( file, "\\par\n");
	reg = reg->next;
    }

}

void RTFFieldOut(FILE *file, aBlock *pBlock , int hselect)
{
    aLine *tag;
    aField *curfield;
    aField *field;
    
    field=pBlock->field;
    tag=pBlock->tagname;
    
    // recursively dump fields

    // output structure definition
    fprintf(file, "%stypedef struct %s \\{\n", SUpar, tag ? tag->text : "" );
    fprintf(file, "%s",SUpar);

    curfield=pBlock->field;
    while(curfield)
    {
	switch(curfield->wType)
	{
	    case FIELD_TYPE:
		RTFTypeOut1(file, (aType *)curfield->ptr, hselect);
		break;
	    case FIELD_STRUCT:
	    case FIELD_UNION:
		RTFSUOut1(file, (aSU *)curfield->ptr, 
			    hselect, curfield->wType);
		break;
	    default:
		assert(FALSE);
		break;
	}
	curfield=curfield->next;
    }
    fprintf(file,"\\} %s;\\par",pBlock->name->text);

    fprintf(file,"%s\\par The {\\b %s} structure contains the following fields:\\par\\par",
	    hdescdoc, pBlock->name->text);
	    
    fprintf(file,"%s{\\ul Field}\\tab{\\ul Description}\\par\n",hSUelements);
    // output element definitions.
    
    curfield=pBlock->field;
    while(curfield)
    {
	switch(curfield->wType)
	{
	    case FIELD_TYPE:
		RTFTypeOut2(file, (aType *)curfield->ptr, hselect);
		break;
	    case FIELD_STRUCT:
	    case FIELD_UNION:
		RTFSUOut2(file, (aSU *)curfield->ptr, hselect, curfield->wType);
		break;
	    default:
		assert(FALSE);
		break;
	}
	curfield=curfield->next;
    }
    
}

void RTFsubFieldOut1(FILE *file, aField *field , int hselect)
{
    aLine *tag;
    aField *curfield;
    
    // recursively dump fields

    curfield=field;
    while(curfield)
    {
	switch(curfield->wType)
	{
	    case FIELD_TYPE:
		RTFTypeOut1(file, (aType *)curfield->ptr, hselect);
		break;
	    case FIELD_STRUCT:
	    case FIELD_UNION:
		RTFSUOut1(file, (aSU *)curfield->ptr, 
				    hselect, curfield->wType);
		break;
	    default:
		assert(FALSE);
		break;
	}
	curfield=curfield->next;
    }
    
}

void RTFSUOut1(FILE *file, aSU *SU, int hselect, int wType)
{
    aSU *curSU;
    
    int level;
    
    
    for(level=SU->level ; level>0; level--)
	fprintf(file, "    "); // four spaces per indent.
	
    fprintf(file, "%s \\{\\par\n", wType == FIELD_STRUCT ? "struct" : "union");
    if(SU->field)
	RTFsubFieldOut1(file, SU->field, hselect);
    
    for(level=SU->level ; level>0; level--)
	fprintf(file, "    "); // four spaces per indent.
	
    fprintf(file, "\\} %s;\\par\n",SU->name->text);
    
}

void RTFTypeOut1(FILE *file, aType *type, int hselect)
{
    int level;
    
    for(level=type->level +1 ; level>0; level--)
	fprintf(file, "    "); // four spaces per indent.
	
    RTFtextOut(file, type->type);
    fprintf(file,"\\tab ");
    RTFtextOut(file, type->name);
    
    fprintf( file, ";\\par\n" );	// note the ; <<<<
    
    if(type->flag)
    {
	RTFFlagOut(file, type->flag, hselect, FLAGPARM);
	fprintf(file, "%s", SUpar);
    }
    
}

void RTFSUOut2(FILE *file, aSU *SU, int hselect, int wType)
{
    aSU *curSU;
    
    int level;
    
    if(SU->field)
	RTFsubFieldOut2(file, SU->field, hselect);
    
    fprintf( file, "\\par\n" );
    
}

void RTFTypeOut2(FILE *file, aType *type, int hselect)
{
    
    RTFtextOut(file, type->name);
    fprintf(file,"\\tab ");
    RTFtextOut(file, type->desc);
    
    fprintf( file, "\\par\n" );
    
}

void RTFsubFieldOut2(FILE *file, aField *field , int hselect)
{
    aLine *tag;
    aField *curfield;
    
    // recursively dump fields

    curfield=field;
    while(curfield)
    {
	switch(curfield->wType)
	{
	    case FIELD_TYPE:
		RTFTypeOut2(file, (aType *)curfield->ptr, hselect);
		break;
	    case FIELD_STRUCT:
	    case FIELD_UNION:
		RTFSUOut2(file, (aSU *)curfield->ptr, hselect, curfield->wType);
		break;
	    default:
		assert(FALSE);
		break;
	}
	curfield=curfield->next;
    }
    
}


void RTFOtherOut(FILE *file, aOther *other, int hselect)
{
    aOther *curo;
    
    switch(hselect)
    {
	case MASMHELP:
	case INTHELP:
	case FUNCHELP:
	case CBHELP:
	case MSGHELP:
	    // what the hell are we doing here?
	    break;
	    
	case STRUCTHELP:
	case UNIONHELP:
	    fprintf( file, hohelp );

	    fprintf( file, "{\\b Synonyms}" );
	    fprintf( file, sephohelp);

	break;

	case INTDOC:
	case MASMDOC:
	case FUNCDOC:
	case CBDOC:
	case MSGDOC:
	    // what the hell are we doing here?
	    break;
	    
	case STRUCTDOC:
	case UNIONDOC:
	    fprintf( file, hodoc );

	    fprintf( file, "{\\b Other names}" );
	    fprintf( file, sephodoc);

	break;
    }
    
    curo=other;
    while(curo)
    {
	if(hselect == STRUCTHELP || hselect == UNIONHELP)
	{
	    fprintf( file, "K{\\footnote{\\up6 K} "); /* make target */
	    RTFtextOut( file, curo->name);
	    fprintf( file, "}\n");
	    
	}
	RTFtextOut( file, curo->type );
	fprintf(file,"\\tab ");
	RTFtextOut( file, curo->name);
	if(curo->desc)
	    RTFtextOut( file, curo->desc);
	fprintf( file, "\\par\n" );
	curo=curo->next;
    }
    fprintf( file, "\\par\n" );
    
}


/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFCondOut | This function outputs the specified Conditional
 *  structure in the specifed mode to the output file.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aCond * | pCond | Specifies the list of Conditionals.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 */
void
RTFCondOut(FILE *file, aCond *cond, int hselect)
{
	RTFtextOutLn( file, cond->desc );
	fprintf( file, "\\par\n" );

	RTFRegOut(file, cond->regs,hselect);
	    
	// fprintf( file, "\\par\n" );	    
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFParmOut | This function outputs the Parameters in the
 *  mode to the output file.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aParm * | parm | Specifies the list of Parameters.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 */
void
RTFParmOut(FILE *file, aParm *parm, int hselect)
{
    fSubBlock++;
    
    switch(hselect)
    {

	case CBHELP:	case MASMHELP:
	case INTHELP:	case FUNCHELP:
	case MSGHELP:
	    fprintf( file, hparmhelp );
	    fprintf( file, p2ahelp );
	    fprintf( file, sepparmhelp);
	    fprintf( file, p2bhelp );

	    break;

	case INTDOC:
	case MASMDOC:
	case FUNCDOC:
	case CBDOC:
	case MSGDOC:
	    fprintf( file, hparmdoc );
	    fprintf( file, p2a );
	    fprintf( file, sepparmdoc);
	    fprintf( file, p2b );
	    break;
    }

    while( parm )
    {
	switch(hselect)
	{
	    case MASMHELP:
	    case INTHELP:
	    case FUNCHELP:
	    case CBHELP:
	    case MSGHELP:
		fprintf( file, hparmhelp );
		fprintf( file, "{\\i ");
		RTFtextOut( file, parm->name );
		fprintf( file, "} " );
		fprintf( file, sepparmhelp);
		fprintf( file, "{\\b ");
		RTFtextOut( file, parm->type );
		fprintf( file, "} ");		// << note ' '

		break;

	    case INTDOC:
	    case MASMDOC:
	    case FUNCDOC:
	    case CBDOC:
	    case MSGDOC:
		fprintf( file, hparmdoc );
		fprintf( file, "{\\b ");
		RTFtextOut( file, parm->type );
		fprintf( file, "} {\\i ");
		RTFtextOut( file, parm->name );
		fprintf( file, "} " );
		fprintf( file, sepparmdoc);
		break;
	}

	fprintf( file, "\n" );
//	RTFtextOutLn( file, parm->desc );
	RTFtextOut( file, parm->desc );

	if(parm->flag)
	{
//	    fprintf(file, "\\par\n");	    // blank line before flags
	    RTFFlagOut(file, parm->flag, hselect, FLAGPARM);
	}

	if(outputType!=RTFHELP)
	    fprintf( file, "\\par\n");
	    
	parm = parm->next;
    }

    fSubBlock--;
}


/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFFlagOut | This function output a list of flags to
 *  the output file based on the current mode of output and where
 *  the flags are attached.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm aFlag * | flag | Specifies the list of flags.
 *
 * @parm int | hselect | Specifies the current mode of output.
 *
 * @flag FUNCHELP |  Specifies the current block is a Function,
 *  and the mode is RTFHELP.
 *
 * @flag MSGHELP  |  Specifies the current block is a Message,
 *  and the mode is RTFHELP.
 *
 * @flag CBHELP   |  Specifies the current block is a Call Back,
 *  and the mode is RTFHELP.
 *
 * @flag FUNCDOC  |  Specifies the current block is a Function,
 *  and the mode is RTFDOC.
 *
 * @flag MSGDOC   |  Specifies the current block is a Message,
 *  and the mode is RTFDOC.
 *
 * @flag CBDOC	  |  Specifies the current block is a Call Back,
 *  and the mode is RTFDOC.
 *
 * @flag INTDOC   |  Specifies the current block is an Interrupt,
 *  and the mode is RTFDOC.
 *
 * @flag INTHELP  |  Specifies the current block is an Interrupt,
 *  and the mode is RTFHELP.
 *
 * @flag MASMDOC  |  Specifies the current block is a MASM,
 *  and the mode is RTFDOC.
 *
 * @flag MASMHELP |  Specifies the current block is a MASM,
 *  and the mode is RTFHELP.
 *
 * @parm int | flags | Specifies where the flags are attached.
 *
 * @flag FLAGPARM | Flags are attached to Parameters.
 *
 * @flag FLAGRTN | Flags are attached to Return Description.
 *
 * @flag FLAGREG | Flags are attached to Register Description.
 *
 */
void
RTFFlagOut(FILE *file, aFlag *flag, int hselect, int flags)
{
    int lih,lisep,fih,fisep;
    char *parh,*parsep;
    
    fSubBlock++;

    assert(flag);

// everything should look more like this....

    switch(hselect)
    {


	case MASMHELP:
	case INTHELP:
	case CBHELP:

	case FUNCHELP:
	case MSGHELP:
	case UNIONHELP:
	case STRUCTHELP:
	    if(flags==FLAGRTN)
	    {
		fprintf( file, hparmhelp );
		fprintf( file, p3a);
		fprintf( file, sepparmhelp);
		fprintf( file, p3b);
	    }
	    else
	    {
		fprintf( file, hvalhelp );
		fprintf( file, p3a);
		fprintf( file, sepvalhelp);
		fprintf( file, p3b);
	    }
//	    lih=5760;
//	    lisep=5760;
//	    fih=-2160;
//	    fisep=0;
//	    parh="plain";
//	    parsep="plain";
    while( flag )
    {
#if 1	
	fprintf(file,"\\par ");
#else	
	if(flags==FLAGRTN)
	    fprintf( file, hparmhelp );
	else
	    fprintf( file, hvalhelp );
#endif

	RTFtextOut( file, flag->name );

	if(flags==FLAGRTN)
	    fprintf( file, sepparmhelp );
	else
	    fprintf( file, sepvalhelp);

	RTFtextOut( file, flag->desc );
	
//	if(flag)
//	    fprintf( file, "\\par " );

	flag = flag->next;
	}

	    break;


	case INTDOC:
	case MASMDOC:
	case CBDOC:

	case FUNCDOC:
	case MSGDOC:
	case STRUCTDOC:
	case UNIONDOC:
		fprintf( file, hvaldoc );
		fprintf( file, p3a);
		fprintf( file, sepvaldoc);
		fprintf( file, p3b);


//	    lih= (flags==FLAGRTN) ? 1080 : 2160;
//	    lisep=(flags==FLAGRTN) ? 3240 : 4320;
//	    fih=0;
//	    fisep=0;
//	    parh=(flags==FLAGRTN) ? "sbys\\ri3200" : "sbys\\ri4280";
//	    parsep="sbys";
    while( flag )
    {
	fprintf( file, hvaldoc );
	RTFtextOut( file, flag->name );

	fprintf( file, sepvaldoc);

	RTFtextOutLn( file, flag->desc );
	fprintf( file, "\\par " );

	flag = flag->next;
    }

	    break;
    }


    fSubBlock--;
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFFileInit | This routine is called before a list of files
 *  in a log structure are processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm files | headfile | Specifies the list of files.
 *
 * @xref RTFGenIndex
 */
void
RTFFileInit(FILE * phoutfile, logentry *curlog)
{
    files curfile;
    files headfile;
    

    copylines(phoutfile,headrtf);

    if(outputType==RTFDOC)
    {
	fprintf(phoutfile,"{\\header \\pard \\qc\\ri-1800\\li-1800\\sl0 ");
	fprintf(phoutfile,"\\plain \\ul\\sl240 \\plain \\f26\\fs20 "
		    "Microsoft Confidential\\plain \\par}\n");
	fprintf(phoutfile,"{\\footer \\pard \\qc\\ri-1800\\li-1800\\sl0"
		     "\\plain \\f26\\fs20 Page \\chpgn \\par}\n");
    }
    else if(outputType==RTFHELP && !fMMUserEd)
    {

	fprintf(phoutfile,"\\plain\\f26\\fs20\n");
	fprintf(phoutfile,"#{\\footnote \\pard \\sl240 \\plain \\f26 #\\plain \\f26 ");
	fprintf(phoutfile,"%s_index}\n","");
	fprintf(phoutfile,"${\\footnote \\pard \\sl240 \\plain \\f26 $\\plain \\f26 ");
	fprintf(phoutfile,"%s Index}\n","");

	fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	fprintf(phoutfile,"For information on how to use Help, press F1 or choose\n");
	fprintf(phoutfile," Using Help from the Help menu.\\par\n");


	headfile=curlog->outheadFile;
	if(headfile)
	{
    
	    fprintf(phoutfile,"\\plain\\f26\\fs24\\par\\par\n");
	    fprintf(phoutfile,"{\\b Functions Index}\n");

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	    curfile=headfile;
	    while(curfile)
	    {
		if(curfile->name)
		    RTFGenIndex(phoutfile, curfile);
		curfile=curfile->next;
	    }

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	}
	headfile=curlog->outheadMFile;
	if(headfile)
	{
    
	    fprintf(phoutfile,"\\plain\\f26\\fs24\\par\\par\n");
	    fprintf(phoutfile,"{\\b Messages Index}\n");

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	    curfile=headfile;
	    while(curfile)
	    {
		if(curfile->name)
		    RTFGenIndex(phoutfile, curfile);
		curfile=curfile->next;
	    }

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	}
	headfile=curlog->outheadSUFile;
	if(headfile)
	{
    
	    fprintf(phoutfile,"\\plain\\f26\\fs24\\par\\par\n");
	    fprintf(phoutfile,"{\\b Data Structures Index}\n");

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	    curfile=headfile;
	    while(curfile)
	    {
		if(curfile->name)
		    RTFGenIndex(phoutfile, curfile);
		curfile=curfile->next;
	    }

	    fprintf(phoutfile,"\\plain\\f26\\fs20\\par\\par\n");
	}
    
	fprintf(phoutfile,"\\par Entire contents Copyright 1990, "
	    "Microsoft Crop. All rights reserved.\\par\\par\n");
	 
    }

    return;
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFGenIndex | This function outputs a reference to a block name.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm files | curfile | Specifies the file structure with the block name.
 *
 */
void
RTFGenIndex(FILE * file, files curfile)
{
    fprintf( file, "\\tab {\\uldb\\f26\\fs20 ");
    fprintf( file, "%s",curfile->name);
    fprintf( file, "}{\\v\\f26\\fs20 ");
    fprintf( file, "%s",curfile->name);
    fprintf( file, "}\\plain\\f26\\fs20\\par\n");

}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFFileProcess | This function is called for each file that
 *  is being processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm files | curfile | Specifies the file.
 *
 */
void
RTFFileProcess(FILE * phoutfile, files curfile)
{
    copyfile(phoutfile,curfile->filename);
    return;

}

	
/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFFileDone | This function is called when all files in a list
 *  of files have been processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm files | headfile | Specifies the file.
 *
 */
void
RTFFileDone(FILE * phoutfile, files headfile)
{
#if 0    
    if(blocksprocessed > 100 && outputType==RTFHELP)
    {
	fprintf( phoutfile, "\\par\\page K{\\footnote{\\up6 K} "); /* keyword */
	fprintf( phoutfile, "mmGetCredits" );
	fprintf( phoutfile, "} ${\\footnote{\\up6 $} "); /* section Title */
	fprintf( phoutfile, "Credits" );
	fprintf( phoutfile, "} +{\\footnote{\\up6 +} "); /* order */
	fprintf( phoutfile, "CREDITS");
	fprintf( phoutfile, "}\n");
	
	fprintf( phoutfile, head0help);
	fprintf( phoutfile,  "Credits");
	fprintf( phoutfile, ehead0help);
	fprintf( phoutfile,  "\\parAutomatic documentation Tool by\\par");
	fprintf( phoutfile,
,		" Russell Wiliams, Mark McCulley and Matt Saettler\\par\n");
	fprintf( phoutfile, "\\par Windows SDK and Multimedia MDK documentation and generation program by Matt Saettler\n");
	fprintf( phoutfile, "\\par Windows SDK layout and processing by Todd Laney and Matt Saettler\\par\n");
	
    }
#endif    
    copylines(phoutfile,tailrtf);
    return;
}


/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFLogInit | This function is called before a list of log
 *  files are to be processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm logentry ** | pheadlog | Specifies the head of the log list.
 *
 */
void
RTFLogInit(FILE * phoutfile, logentry * * pheadlog)
{
    FILE *fp;
    char achbuf[180];
    int j;
    
    if(outputType==RTFHELP)
    {
	j=findlshortname(outputFile);
	strncpy(achbuf,outputFile,j);
	achbuf[j]=0;
	strcat(achbuf,".hpj");
	fp=fopen(achbuf,"r");
	
	if(!fp)	// file doesn't exist
	{
	    fp=fopen(achbuf,"w");
	    assert(fp);
	    
	    fprintf(fp,"; HPJ file automagically generated by DOCFMT\n");
	    fprintf(fp,"[files]\n");
	    fprintf(fp," %s\n",outputFile);
	}
	fclose(fp);
    }
    return;
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFLogProcess | This function is called for each log to be processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm logentry * | curlog | Specifies the current log.
 *
 */
void
RTFLogProcess(FILE * phoutfile, logentry * curlog)
{
    return;
}

/*
 * @doc INTERNAL RTF
 *
 * @func void | RTFLogDone | This function is called after a list of logs
 *  has been processed.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm logentry * | headlog | Specifies the head of the log list.
 *
 */
void
RTFLogDone(FILE * phoutfile, logentry * headlog)
{
    return;
}


/*
 * @doc INTERNAL RTF
 *
 * @func void | copylines |  This function appends the array of lines
 *  to the output file.
 *
 * @parm FILE * | file | Specifies the output file.
 *
 * @parm char ** | papch | Specifies the array of lines.
 *
 * @comm The list is terminated by a NULL pointer.
 *
 */
void
copylines(FILE * phoutfile, char **lines)
{
    assert(lines);
    while(*lines)
    {
	fprintf(phoutfile, "%s",*lines);
	lines++;
    }
    return;
}