/*
 *  filedes.cxx from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#include <string.h>
#include <stream.h>
#include <stdio.h>

#include "filename.h"
#include "filedes.h"
#include "package.h"
#include "bits.h"
#include "outtok.h"
#include "dirdes.h"
#include "specarth.h"

void TestAlloc(const char * msg);

void HeaderFile::set_inc_dir_name(const char * buf)
{
	inc_dir_name = buf ;
}


void FileDesc::SetBit(int Bit)
{
	int word = Bit >> 5 ;
	int Dist = Bit - (word << 5) ;
	unsigned Value = ((unsigned) 1) << (31 - Dist) ;
	Dependencies[word] |= Value ;
}


// #define DEBUG_SET_DEP
void HeaderFile::Display()
{
	int chout = 32;
	cout <<GetDir() << "/"  << GetName() << ":\n"  ;
	for (int i = 0 ; i< HeaderWords ; i++) {
		char buf[32];
		sprintf(buf,"0x%08x",Dependencies[i]);
		cout << " 0x" << buf ;
		if (i%5 == 4) cout << "\n" ;
	}
	cout << "\n" ;
}




void FileDesc::GetDependencies(const char * DirName, PackageDesc * Package)
{
	const int BufferSize = 1024;
	const char * Include  = "include" ;
	char Buffer[BufferSize];

	int NumberWords = Package->GetNumFlagWords();
	// cout << "NumberWords = " << NumberWords << "\n" ;
	// Dependencies = new uint32[NumberWords];
	for (int i = 0 ; i < NumberWords;i++) Dependencies[i]=0;
	
	char * Tname = MakeFullName(DirName,Name) ;
	FILE * File = fopen(Tname,"r");
	// cerr << "Getting dependencies for `" << Tname << "'\n" ;
	if (!File)  {
		cerr << "Can't open file " << Tname << ".\n" ;
		return ;
	}
	int LineNo = 0;
	while (fgets(Buffer,BufferSize,File)) {
		LineNo ++ ;
		if (Buffer[0] == '#') {
		int i = 1;
		while (Buffer[i] == ' ' || Buffer[i] == '\t') i++;
		if (strncmp(&Buffer[i],Include,strlen(Include))) continue;
		i += strlen(Include);
		while (Buffer[i] == ' ' || Buffer[i] == '\t') i++;
		if (Buffer[i++] != '"' ) continue ;
		int StartString = i ;
		while (Buffer[i] != '"' && i < BufferSize-1) i++;
		if (i == BufferSize -1) {
			cerr << "Missing `\"' in file " << Tname <<
				" line " << LineNo << "\n" ;
			continue ;
		}
		int StrLen = i - StartString ;
		if (StrLen < 1) {
			cerr << "NULL include name in file " <<
			Tname << " at line " << LineNo ;
			continue ;
		}
		if (Package->IsArith())
			if (!strncmp(Buffer+StartString,SpecArithIncludeFile,
				strlen("arth_spc.h"))) continue ;
		char * IncName = new char [StrLen+1];
		strncpy(IncName,&Buffer[StartString],StrLen);
		IncName[StrLen]= '\0' ;
		int FlagBit = Package->GetIndex(IncName);
		// cerr << "Index for " << IncName << " is " << FlagBit << ".\n" ;
		if (FlagBit < 0) {
			cerr << "Reference to unknown include file (" <<
			IncName << ") at line " << LineNo << " in file " <<
			Tname << "\n" ;
			continue ;
		}
		SetBit(FlagBit) ;
	}
	}
	// cout << "READ Depend for file " << Name ;
	// for (i = 0 ; i < NumberWords;i++)
	//	cout << " 0x" <<  hex(Dependencies[i],8) <<"\n";
	delete Tname ;
	fclose(File);
}

static const char * HD_Dir(PackageDesc * pkg,HeaderFile *head, const char * Loc)
{
	const char *dir = head->inc_dir();
	if (!dir) dir = head->GetDir();
	if (!strcmp(dir,Loc)) return "LOCAL_DIR" ;
	static char Buf[32];
	sprintf(Buf,"HD_%d",head->GetDirIndex());
	return Buf ;
}
const MakeLimit = 30 ;

void FileDesc::WriteCDependant(OutTokens& TokOut, const char * Name)
{
	TokOut.NextConcat(Name);
	TokOut.NextConcat(" : ");
}

void FileDesc::WriteCDepen(ostream * MakeOut, PackageDesc * pkg,
	const char * dir)
{
	TestAlloc("FileDesc::WriteCDepen enter");
	const char * MakeTail = "Makefile_tail" ;
	const char * Sub = pkg->CDirs->GetSubDir() ;

	char * TempBuf = MakeObjName(Name) ;
	TestAlloc("FileDesc::WriteCDepen b");
	// TempBuf[0] = '\0' ;
	// strcat(TempBuf,Name);
	// TempBuf[strlen(TempBuf)-1] = 'o' ;

	OutTokens TokOut(LongPage(MakeOut));
	TestAlloc("FileDesc::WriteCDepen c");
	WriteCDependant(TokOut,TempBuf) ;
	TestAlloc("FileDesc::WriteCDepen d");
/*
 *	TokOut.NextConcat(TempBuf);
 *	TokOut.NextConcat(" : ");
 */
	if (Sub) TokOut.NextConcat("${LOCAL_DIR}/");
	TestAlloc("FileDesc::WriteCDepen e");
	TokOut.NextConcat(Name);
	TestAlloc("FileDesc::WriteCDepen f");
	const char * SaveDir=pkg->CDirs->GetDirName(0);
	const char * Tail = MakeFullName(SaveDir,MakeTail,Sub);
	TestAlloc("FileDesc::WriteCDepen g");
	FILE * fd = fopen(Tail,"r");
	if (fd) {
		TokOut.NextOut(Tail);
		fclose(fd);
		TestAlloc("FileDesc::WriteCDepen h");
	}
	// delete Tail ;
	TestAlloc("FileDesc::WriteCDepen i");
	if (SaveDir) if (strcmp(dir,SaveDir)) {
		const char * Tail = MakeFullName(dir,MakeTail,Sub);
		TestAlloc("FileDesc::WriteCDepen j");
		fd = fopen(Tail,"r");
		if (fd) {
			TokOut.NextOut(MakeTail);
			fclose(fd);
		}
	}
	GetBits * Bits = new GetBits(pkg->GetNumHEntries(), Dependencies) ;
	TestAlloc("FileDesc::WriteCDepen k");
	int HeadInc ;

	char NameBuf[32];
	// strcpy(NameBuf,"${HD_");
	strcpy(NameBuf,"${");
	int Count = 0 ;
	TestAlloc("FileDesc::WriteCDepen l");
	while ((HeadInc = Bits->NextBit())> -1) {
		// cerr << "HeadInc = " << HeadInc << "\n" ;
		HeaderFile * head = pkg->GetAllHeaders()[HeadInc] ;
		// cerr << "HeadInc = " << HeadInc << "\n" ;
		if (!head->GetName()) continue ;
		// strcpy(&NameBuf[5],dec(head->GetDirIndex()));
		strcpy(NameBuf+2,HD_Dir(pkg,head,dir));
		// cerr << "HeadInc = " << HeadInc << "\n" ;
		strcat(NameBuf,"}");
		TestAlloc("FileDesc::WriteCDepen m");
		char * name = MakeFullName(NameBuf,head->Name);
		TestAlloc("FileDesc::WriteCDepen n");
		TokOut.NextOut(name) ;
		delete name ;
		if (Count++ > MakeLimit) {
			// Kludge to keep make from crashing!!!
			TokOut.NewLine() ;
			TokOut.NewLine() ;
			WriteCDependant(TokOut,TempBuf) ;
			TestAlloc("FileDesc::WriteCDepen o");
			Count = 0 ;
		}
		TestAlloc("FileDesc::WriteCDepen p");
	}
	TestAlloc("FileDesc::WriteCDepen q");
	delete TempBuf ;
	TestAlloc("FileDesc::WriteCDepen r");
	TokOut.NewLine() ;
	int OutCC = 1;
	if (OmitCCLine) {
		for (const char ** pt = OmitCCLine ; *pt; pt++) if (!strcmp(*pt,Name)) {
			OutCC = 0;
			break ;
		}
	}
	if (ArithFlags) {
	    for (int i = 0 ; i < ArithType::MaxArithCapabilities; i++)
		if (ArithFlags & (1 << i))
		    CC_Out(OutCC,*MakeOut,Sub,ArithType::ClassSuffix[i]);
	} else CC_Out(OutCC,*MakeOut,Sub);
	// delete Bits ;
}

void FileDesc::CC_Out(int OutCC,ostream& MakeOut,const char * Sub,
	const char * ArithDir)
{
        if (OutCC) if (Sub) {
                MakeOut << "\t${CC} ${CFLAGS} ${INC_DIRS}" ;
                if (ArithDir) MakeOut << " -I../" << ArithDir ;
                MakeOut << " ${LOCAL_DIR}/" << Name << "\n\n" ;

        } else {
		MakeOut << "\t${CC} ${CFLAGS} ${INC_DIRS}" ;
                if (ArithDir) MakeOut << " -I" << ArithDir ;
		MakeOut << " " << Name << "\n" ;
	}
        // if(Sub&&pkg->IsdbXtra()) MakeOut <<"\tmv " << Name << "..dbx ..\n";
        MakeOut << "\n" ;
}

void FileDesc::SetDependencies(PackageDesc * pkg)
{
	int num = pkg->GetNumHEntries();
	int nwrds = (num+31) >> 5 ;
#ifdef DEBUG_SET_DEP
	cout << "INIT Dependencies for " << Name << " are:\n" ;
	for (int j=0;j< nwrds;j++) {
		cout << " 0x" << hex(Dependencies[j],8) ;
		if (j%5 == 4) cout << "\n" ;
	}
	cout << "\n" ;
#endif
	GetBits * Bits = new GetBits(num, Dependencies ) ;
	int HeadInc ;
	while ((HeadInc=Bits->NextBit()) > -1) {
		const uint32 * NewWords =
			pkg->GetAllHeaders()[HeadInc]->GetHeaderWords() ;
#ifdef DEBUG_SET_DEP
		pkg->GetAllHeaders()[HeadInc]->Display();
#endif
		for (int j=0 ; j < nwrds; j++) Dependencies[j] |= NewWords[j] ;
		// We can speed this up by not updating until we finish
		// oring in all dependencies
	}
#ifdef DEBUG_SET_DEP
	cout << "Dependencies for " << Name << " are:\n" ;
	for (j=0;j< nwrds;j++) {
		cout << " 0x" << hex(Dependencies[j],8) ;
		if (j%5 == 4) cout << "\n" ;
	}
	cout << "\n" ;
#endif
}

