/*  includ.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <fstream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portable.h"
#include "y.tab.h"
#include "slist.h"
#include "mknodey.h"
#include "fileios.h"

const TotalIncludes = 12 ;

static int TokenToIndex(int Token )
{
	int Return = 0 ;
	switch(Token) {
default:
		cerr << "MapTokenToIndex bad index: " << Token << ".\n" ;
		exit(1);
case IC_INCLUDE:
		Return++;
case IH_INCLUDE:
		Return++;
case Ic_INCLUDE:
		Return++;
case Ih_INCLUDE:
		Return++;
case TC_INCLUDE:
		Return++;
case TH_INCLUDE:
		Return++;
case Tc_INCLUDE:
		Return++;
case Th_INCLUDE:
		Return++ ;
case C_INCLUDE:
		Return++;
case H_INCLUDE:
		Return++;
case c_INCLUDE:
		Return++;
case h_INCLUDE:
		if (Return < 0 || Return > TotalIncludes) {
			cerr << "MapTokenToIndex bad Return: " <<
				Return << ".\n" ;
			exit(1) ;
		}
		return Return ;
	}
}
	
enum TheFileOut {TOut,IOut,BothOut};
enum WhenOut {HFirst,HLast,CFirst,CLast};
struct IncludeList {
	ConstStringList TheList ;
	TheFileOut Where ;
	WhenOut When ;
	IncludeList(TheFileOut x_where, WhenOut when);
	ErrCode Append(const char * str) {return TheList.Append(str);}
};

IncludeList::IncludeList(TheFileOut where, WhenOut when):Where(where),
	When(when)
{
}

static IncludeList * TheIncludes[TotalIncludes] ;

void InitTheIncludes()
{
	TheIncludes[TokenToIndex(C_INCLUDE)] = new IncludeList(BothOut,CFirst);
	TheIncludes[TokenToIndex(H_INCLUDE)] = new IncludeList(BothOut,HFirst);
	TheIncludes[TokenToIndex(c_INCLUDE)] = new IncludeList(BothOut,CLast);
	TheIncludes[TokenToIndex(h_INCLUDE)] = new IncludeList(BothOut,HLast);
	TheIncludes[TokenToIndex(IC_INCLUDE)] = new IncludeList(IOut,CFirst);
	TheIncludes[TokenToIndex(IH_INCLUDE)] = new IncludeList(IOut,HFirst);
	TheIncludes[TokenToIndex(Ic_INCLUDE)] = new IncludeList(IOut,CLast);
	TheIncludes[TokenToIndex(Ih_INCLUDE)] = new IncludeList(IOut,HLast);
	TheIncludes[TokenToIndex(TC_INCLUDE)] = new IncludeList(TOut,CFirst);
	TheIncludes[TokenToIndex(TH_INCLUDE)] = new IncludeList(TOut,HFirst);
	TheIncludes[TokenToIndex(Tc_INCLUDE)] = new IncludeList(TOut,CLast);
	TheIncludes[TokenToIndex(Th_INCLUDE)] = new IncludeList(TOut,HLast);
}
	

void FoundInclude(const char * Inc, int Type)
{
	TheIncludes[TokenToIndex(Type)]->Append(Inc);
}

static void AddHeaders(ConstStringList& Includes, MofStream *Out)
{
	const char * IncludeName ;
	ConstStringList Backwards ;
	while (IncludeName=Includes.Get()) Backwards.Append(IncludeName);
	
	while (IncludeName = Backwards.Get()) {
		int Length = strlen(IncludeName);
		if (Length < 1) {
			cerr << "Null include name.\n" ;
			continue ;
		}
		*Out << "#include " ;
		if (IncludeName[0] == '<')  {
			*Out << IncludeName ;
			if (IncludeName[Length-1] != '>' || Length < 3) cerr
				<< "Bad system include name `" << IncludeName
				<< "'\n" ;
		} else *Out << "\"" << IncludeName << "\"" ;
		*Out << "\n" ;
	}
}

void EmitIncludeFiles(MofStream& Header, MofStream& Cpp, int FirstFlag)
{
	for (int i = 0 ; i < TotalIncludes;i++) {
		MofStream * TheStream = 0 ;
		IncludeList& TheInclude = *(TheIncludes[i]) ;
		switch(TheInclude.When) {
case HFirst:
			if (!FirstFlag) continue ;
			TheStream = &Header ;
			break ;
case HLast:
			if (FirstFlag) continue ;
			TheStream = &Header ;
			break ;
case CFirst:
			if (!FirstFlag) continue ;
			TheStream = &Cpp ;
			break ;
case CLast:
			if (FirstFlag) continue ;
			TheStream = &Cpp ;
			break ;
default:
			cerr << "EmitIncludeFiles bad WhenOut: " <<
				(int) TheInclude.When << "\n" ;
			exit(1);
		}
		switch(TheInclude.Where) {
case TOut:
			TheStream->PushFirstFileSelect(BaseStreamBuf::Off);
			break ;
case IOut:
			TheStream->PushSecondFileSelect(BaseStreamBuf::Off);
			break ;
case BothOut:
			break ;
default:
			cerr << "EmitIncludeFiles bad TheFileOut: " <<
				(int) TheInclude.Where << "\n" ;
			exit(1);
		}
		AddHeaders(TheInclude.TheList,TheStream);
		switch(TheInclude.Where) {
case TOut:
			TheStream->PopFirstFileSelect();
			break ;
case IOut:
			TheStream->PopSecondFileSelect();
			break ;
case BothOut:
			break ;
default:
			cerr << "EmitIncludeFiles bad TheFileOut: " <<
				(int) TheInclude.Where << "\n" ;
			exit(1);
		}
	}
}

	

