/*
 *  dirdes.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 <unistd.h>
#ifdef __NT_VC__
#include <windows.h>
#endif
#include <stream.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ctype.h>
#include "sysconst.h"
#include "copyright.h"
#include "cmdline.h"
#include "files.h"
#ifdef BACKWARDS_COMPATABILITY
#include <sys/ndir.h>
#define dirent direct
#else
#include <dirent.h>
#endif

//#include <sys/dir.h>
#include <stream.h>
#include <fstream.h>
#include <string.h>

#include "portable.h"
const uint32 PrintDirBit = 0x80000000 ;
#include "makedir.h"
#include "dirdes.h"

#include "filedes.h"
#include "package.h"
#include "bits.h"
#include "outtok.h"
#include "mkstr.h"

const char * LibSuffix = "${OPD_LIB_SUF}" ;
const char * ExeSuffix = "${OPD_EXE_SUF}" ;
char * ObjSuffix = OBJ_SUFFIX ;

void TestAlloc(const char * msg);

static const char * Makefile_head = "Makefile_head" ;
// all found are added more specific is added last

static const char * Makefile_inc = "Makefile_inc" ;
// all found are added more specific is added last

static const char * Makefile_tail = "Makefile_tail" ;
// only one is added most sepcific checked first

const char * SourceSuffix = CPP_SUFFIX ;
int Use_makemake_link = 0 ;

char * MakeObjName(const char *Name)
{
	char * base = RemoveSuffix(Name,SourceSuffix);
	char * Return = Concatenate(base,".",ObjSuffix);
	delete base ;
	return Return ;
}

char * TailUpName(const char * FullName)
{
	const char * LastSlash = FullName ;
	const char * LastLastSlash = FullName ;
	for (const char * Pt = FullName; *Pt; Pt++) if (*Pt == '/') {
		LastLastSlash = LastSlash ;
		LastSlash = Pt+1;
	}

	if (LastSlash == LastLastSlash) {
		char * Return = new char[strlen(LastSlash)+1] ;
		strcpy (Return,LastSlash);
		return Return ;
	}
	int Count;
	for (Count=0 ; LastLastSlash[Count] != '/';Count++);
	char * Return = new char[Count+1] ;
	for (int i = 0 ; i < Count ; i++) Return[i] = LastLastSlash[i];
	Return[Count] = '\0' ;
	return Return ;
}

const char * TailName(const char * FullName)
{
	const char * LastSlash = FullName ;
	for (const char * Pt = FullName; *Pt; Pt++)
		if (*Pt == '/') LastSlash = Pt+1;
	return LastSlash ;
}

DirContents::DirContents (const char *name, const char * suf, int mn, int index,
	int lib_flg):
		FileEntry(0),
		BaseLibFlag(lib_flg),
		MakeWritten(0),
		InLocalCollect(0),
		KeepDirs(0),
		DirName(name),
		Suffix(suf),
		MainDir(mn),
		LibFlag(lib_flg),
		MakeFileName(0),
		Index(index)
{
}

void DirContents::WriteCDepen(PackageDesc *pkg)
{
	TestAlloc("DirContents::WriteCDepen enter");
	if (!contains_directories()) return ;
	for (int i = 0; i< NumFiles; i++)
		FileEntry[i].WriteCDepen(MakeOut, pkg, DirName) ;
	*MakeOut << "\n" ;
	TestAlloc("DirContents::WriteCDepen exit");
}

const char * GetBaseName(const char * Name)
{
	const BufSize = 256 ;
	static char Buf[BufSize];
	if (strlen(Name) > BufSize) {
		cerr << "File name (" << Name << ") too long.\n" ;
		exit(1);
	}
	char * Bptr = Buf ;
	for (const char * Ptr = Name ; *Ptr && *Ptr != '.' ; *Bptr++ = *Ptr++) ;
	*Bptr = '\0' ;
	return Buf ;
}

DirContents * DirContents::GetUsrContents(PackageDesc * pkg)
{
	if (!pkg) return 0;
	return pkg->GetUsrContents(DirName);
}

int DirContents::IsMenuDir(PackageDesc * pkg)
{
	// cerr << pkg->GetMenuDir() << "::" << DirName << "\n" ;
	if (!pkg->GetMenuDir()) return 0 ;
	if (strcmp(pkg->GetMenuDir(),DirName)) return 0 ;
	return 1;
}


void DirContents::OutAllNodFiles(OutTokens& Out, PackageDesc * pkg)
{
	const BufSize = 1024;
	char Buffer[BufSize+1] ;
	DirContents * UsrFiles = GetUsrContents(pkg);
	if (!UsrFiles) return ;
	const char * Suffix = ".nod" ;
	const char * Prefix = pkg->GetMenuIncDir();
	if (!Prefix) Prefix = "" ;
	int MaxLength = BufSize - strlen(Suffix) ;
	if (Prefix) MaxLength -= strlen(Prefix) + 1;
	for (int i = 0 ; i < UsrFiles->Size(); i++) {
		const char * Name = UsrFiles->GetName(i);
		const char * BaseName = GetBaseName(Name);
		if (strlen(BaseName) > MaxLength) {
			cerr << "File base name `" << BaseName  <<
				"' is greater than " << MaxLength <<
				"characters long.\n" ;
			exit(10);
		}
		if (Prefix) {
			strcpy(Buffer,Prefix);
			strcat(Buffer,"/");
		} else Buffer[0] = '\0' ;
		strcat(Buffer,BaseName);
		strcat(Buffer,Suffix);
		Out.NextOut(Buffer);
	}
}


void DirContents::WriteMenuDependsMacro(PackageDesc * pkg)
{
	if (!IsMenuDir(pkg)) return ;
	pkg->SetMenuMakeFileCreated();
	OutTokens * ListOut = new OutTokens(LongPage(MakeOut));
	ListOut->NextConcat("ALL_MENU_NOD_FILES =") ;
	pkg->OutAllNodFiles(*ListOut);
	ListOut->NewLine();
	ListOut->NewLine();

	ListOut->NextConcat("ALL_MENU_CREATED_FILES = ");
	pkg->OutMenuMakes(*ListOut);
	ListOut->NewLine();
	ListOut->NewLine();
	delete ListOut ;
}

void DirContents::WriteUsrDependsMacro(PackageDesc * pkg)
{
	DirContents * UsrFiles = GetUsrContents(pkg);
	if (!UsrFiles) return ;

	const int ObjClasses = 4;
	static const char * Prefix[ObjClasses] = {"${USR_H_DIR}/",
		"${LOCAL_DIR}/"} ;
	int Limit = 2 ;
	const char * PrefixNod = pkg->GetMenuIncDir();
	char * ToDelete = 0;
	if (PrefixNod) {
		Prefix[Limit++] = ToDelete = new char[strlen(PrefixNod) + 2];
		strcpy(ToDelete,PrefixNod);
		strcat(ToDelete,"/");
	} else Prefix[2] = "" ;
	static const char * Suf[ObjClasses] = {".h",CPP_SUFFIX,".nod"};
	static char * UsrObjs[ObjClasses] =
		{"USR_OBJS_H","USR_OBJS_C","USR_OBJS_NOD"} ;
	for (int j = 0; j < Limit; j++) {
		*MakeOut << UsrObjs[j] << " = " ;

		int LineUse = strlen(UsrObjs[j]) + 3 ;
		for (int i = 0 ; i < UsrFiles->Size(); i++) {
			const char * Name = UsrFiles->GetName(i);
			const char * BaseName = GetBaseName(Name);
			int leng = strlen(BaseName) ;
			int AddedLength = strlen(Prefix[j])+strlen(Suf[j])+1;
			if ((LineUse+=leng+AddedLength)> 77) {
				*MakeOut << "\\\n    " ;
				LineUse = 4 ;
			}
			*MakeOut << Prefix[j] << BaseName << Suf[j] << " " ;
		}
		*MakeOut << "\n\n" ;
	}
	*MakeOut << "USR_C_H_NOD =" ;
	for (j = 0 ; j < Limit; j++) *MakeOut << " ${" << UsrObjs[j] << "}" ;
	*MakeOut << "\n\n" ;
	delete ToDelete ;
}

static const char * MakeLocalUsr = "MakeLocalUsrDepends" ;

const char * Created = "ALL_MENU_CREATED_FILES" ;
const char * NodFiles = "ALL_MENU_NOD_FILES" ;
const char * LocalUsrMakes = "LocalUsrMakes" ;

static const char * MakeMacro(const char * Name)
{
	const BufSize = 512 ;
	static char Buf[BufSize+1];
	if (strlen(Name)+3 > BufSize) {
		cerr << "Internal limit exceeded: MakeMacro.\n" ;
		exit(11);
	}
	strcpy(Buf,"${");
	strcat(Buf,Name);
	strcat(Buf,"}");
	return Buf ;
}

int DirContents::OutMakeLocalUsr(PackageDesc * pkg,const char * Object)
{
	if (pkg->GetMenuFlag())
	    if (!strcmp(pkg->GetMenuFlag(),"l")) if (pkg->GetMakeNodDir()) {
		*MakeOut << Object << " :\n" ;
		*MakeOut << "\tbash -c \"cd " << pkg->GetMakeNodDir() <<
			"; ${OPD_MAKE} -f Makefile " << LocalUsrMakes << "\"\n\n" ;
		return 1;
	}
	return 0;
}

void DirContents::WriteMenuDepends(PackageDesc * pkg)
{
	if (!IsMenuDir(pkg)) return ;
	OutMakeLocalUsr(pkg,MakeMacro(NodFiles)) ;
	*MakeOut << "MakeLocalMenuDepends : " << MakeMacro(Created) << "\n" ;

	const char * IncDir = pkg->GetMenuIncDir() ;
	const char * CatFile = 0;
	const char * concat = "/concat" ;
	const char * init_file = "${LOCAL_DIR}/initinc.h" ;
	if (IncDir) CatFile = Concatenate(IncDir,concat,"/ALL.nod.menu");

	if (IncDir) {
		*MakeOut << "${" << Created << "} " ;
		if (pkg->GetMenuFlag())
			if (!strcmp(pkg->GetMenuFlag(),"r"))
				*MakeOut << init_file ;
		*MakeOut << " :" << MakeMacro(NodFiles) << " "
			<< pkg->GetMenuInput() << "\n" ;
		*MakeOut << "\t${OPD_ROOT}/bin/nod_sort -m " << pkg->GetMenuInput()
			<< " " << CatFile << " " << IncDir << "\n" ;
		if (pkg->GetMenuFlag())
			if (!strcmp(pkg->GetMenuFlag(),"r")) { // remote menu make
			*MakeOut << "\t${OPD_ROOT}/bin/cp_update_legal -c " <<
				init_file << "\n" ;
			*MakeOut << "\t${OPD_SHELL} ${OPD_ROOT}/scripts/make_init " << IncDir
				<< " " << init_file << "\n" ;
			
		}

	}
	*MakeOut << "\t" ;
	if (pkg->IsSubDir()) *MakeOut << "bash -c \"cd ${LOCAL_DIR} ; " ;
	*MakeOut << pkg->bin_directory() << "domenus " ;
	if (pkg->GetMenuFlag()) *MakeOut << "-" << pkg->GetMenuFlag() << " " ;
	if (IncDir) *MakeOut << " " << CatFile << "\"\n" ;
#ifndef __NT_VC__
	*MakeOut << "\t${OPD_SHELL} " << pkg->script_directory() << "spell.sh " ;
	if (pkg->IsSubDir()) *MakeOut << "${LOCAL_DIR}/" ;
	*MakeOut << "spell.names spellerr.e" << "\n" ;
#endif
/*
 *	*MakeOut << "\t ${OPD_SHELL} " <<
 *		pkg->script_directory() << "dict.sh " ;
 *	if (pkg->IsSubDir()) *MakeOut << "${LOCAL_DIR}/" ;
 *	*MakeOut << "spell.names spellerr.e\n\n" ;
 */
	
}

void DirContents::WriteUsrDepends(PackageDesc * pkg)
{
	DirContents * UsrFiles =GetUsrContents(pkg);
	if (!UsrFiles) return ;
	const char * Sub = pkg->CDirs->GetSubDir() ;
	*MakeOut << MakeLocalUsr << " : ${USR_C_H_NOD}\n\n" ;
	for (int i = 0 ; i < UsrFiles->Size(); i++) {
		const char * Name = UsrFiles->GetName(i);
		const char * BaseName = GetBaseName(Name);
		*MakeOut << "${USR_H_DIR}" << "/" << BaseName << ".h ";
		if (Sub) *MakeOut << "${LOCAL_DIR}/" ;
		*MakeOut << BaseName << CPP_SUFFIX << " " ;
	
	const char * IncDir = pkg->GetMenuIncDir() ;
		if (IncDir) *MakeOut << IncDir << "/" ;
		*MakeOut << BaseName << ".nod" ;
		*MakeOut << " : " ;
		if (Sub) *MakeOut << "${LOCAL_DIR}/" ;
		*MakeOut << Name << "\n" ;
		*MakeOut << "\t" << pkg->bin_directory() 
			<< "mknode -t ../target -d ../tex " ;
		if (Sub) *MakeOut << " -m .. ${LOCAL_DIR}/" ;
		*MakeOut << Name << "\n" ;

/*
 *		*MakeOut << "\tDebugFilter " ;
 *		if (Sub) *MakeOut << "${LOCAL_DIR}/" ;
 *		*MakeOut << "target/" << BaseName << ".cxx\n" ;
 *
 *		*MakeOut << "\tDebugFilter " ;
 *		if (Sub) *MakeOut << "${LOCAL_DIR}/" ;
 *		*MakeOut << "target/" << BaseName << ".h\n" ;
 */

		if (IncDir)
			*MakeOut << "\tmv " << BaseName << ".nod " << IncDir << "\n" ;
		*MakeOut << "\tmv " << BaseName << "I.h ..\n" ;
/*
 *		*MakeOut << "\t" << pkg->bin_directory() << "dbgcnv " ;
 *		if (Sub) *MakeOut << "${LOCAL_DIR}/" ;
 *		*MakeOut << BaseName << ".cxx\n" ;
 *		*MakeOut << "\tbash -c \"cd ../target; " << pkg->bin_directory() << "dbgcnv " <<
 *			BaseName <<".cxx\"\n";
 */
		// Above is option to remove strings from DbgErr messages on target
#ifndef __NT_VC__

		*MakeOut << "\t${OPD_SHELL} " << pkg->script_directory() <<
			"spell.sh " << BaseName << ".s " << BaseName << ".e\n" ;
#endif
/*
 *		*MakeOut << " \t${OPD_SHELL} " << pkg->script_directory() << "dict.sh " <<
 *			BaseName << ".s " << BaseName <<
 *			".e\n\ttouch " << BaseName << ".e\n\tcat " << BaseName <<
 *			".e\n\n" ;
 */
	}
}
void DirContents::EmitObjs(ostream& Out, int& LineUse, const char * SubDir)
{
	if (!NumFiles) return ;
	for (int i = 0 ; i < NumFiles ; i++) {
		char * savec = MakeObjName(GetName(i)) ;
		char * saved ;
		if (SubDir) if (!strlen(SubDir)) SubDir = 0 ;
		if (SubDir) saved = Concatenate(DirName, "/",SubDir,"/",savec);
		else saved = Concatenate(DirName, "/",savec);
		delete savec ;
		int leng = strlen(saved) + 1 ;
		int NoSkip = LineUse > 4 ;
		if ((LineUse+=leng)> 77) if (NoSkip) {
			Out << "\\\n    " ;
			LineUse = 4 + leng  ;
		}
		Out << saved << " " ;
		delete saved;
	}
		
}

void DirContents::WriteObjs()
{
	if (!NumFiles) return ;
	const char * OBJS = "OBJS = " ;
	*MakeOut << OBJS ;
	int LineUse = strlen(OBJS);
	for (int i = 0 ; i < NumFiles ; i++) {
		char * savec = MakeObjName(GetName(i)) ;
		int leng = strlen(savec) ;
		if ((LineUse+=leng)> 77) {
			*MakeOut << "\\\n    " ;
			LineUse = 4 ;
		}
		*MakeOut << savec << " " ;
		delete savec;
	}
	*MakeOut << "\n" ;
		
}


void DirContents::SetName(int index, char * name)
{
	if (index >=  NumFiles )
		InternalError("DirContents::SetName");
	// cerr << "Setting `" << name << "'\n" ;
	char * StrTemp = new char [strlen(name)+1] ;
	strcpy(StrTemp,name);
	FileEntry[index].SetFileDesc(StrTemp) ;
}


int DirContents::ValidFile(char * name)
{
	if (!name) return 0;
	int end = strlen(name);
	for (int i = end; i > -1; i--) if (name[i] == '.')
		return (!strcmp(&name[i],Suffix));
	return 0;
}

void DirContents::Display()
{
	cout << DirName << "\n" ;
	for (int i=0;i<NumFiles;i++) cout << "    " << FileEntry[i].GetName() <<
		"\n" ;
}


void DirContents::FindFiles()
{

	DIR * Directory =  opendir((char *) DirName) ;
	if (!Directory) {
		cerr << "Can't open directory `" << DirName << "'.\n" ;
		exit (4) ;
	}
	int NDirs = 0;
	struct dirent * DirRead ;
	while (DirRead = readdir(Directory) )
#ifndef __NT_VC__
		if(DirRead->d_ino)
#endif
			if(ValidFile(DirRead->d_name)) NDirs++;
	rewinddir(Directory) ;
	SetDirContents(NDirs) ;		
	int j=0;
	// cout << " In directory `" << DirName << "'\n" ;
	while (DirRead = readdir(Directory) )
#ifndef __NT_VC__
		if(DirRead->d_ino)
#endif
		if(ValidFile(DirRead->d_name))
			SetName(j++,DirRead->d_name);
	closedir (Directory);
}


int DirContents::CheckDir(DirNames * Dirs, const char * name)
{
	if (!name) {
		for (int i = 0; i < Dirs->Size(); i++ ) {
			DirContents * HeadDir = Dirs->GetDirEntry(i);
			if (HeadDir->TestPrintDir()) continue ;
			HeadDir->SetPrintDir();
			*MakeOut << "HD_" << i << " = " << HeadDir->GetDir()
				  << "\n" ;
		}
		return -1 ;
	}
	for (int i = 0; i < Dirs->Size(); i++ ) {
		DirContents * HeadDir = Dirs->GetDirEntry(i);
		if (!HeadDir) break ;
		if (!HeadDir->GetDir()) break ;
		// cerr << i << ":" << name << ":" << HeadDir->GetDir() <<"\n" ;
		if (!strcmp(name, HeadDir->GetDir())) {
			if (HeadDir->TestPrintDir()) return i ;
			HeadDir->SetPrintDir();
			*MakeOut << "HD_" << i << " = " << name  << "\n" ;
			return i ;
		}
	}
	return -1 ;
}

DirNames::DirNames (int n, const char * suf):
	CollLibName(0)
{
	Sub[0]= '\0' ;
	TheNext=0;
	MaxSize=n;
	SubDir = 0;
	Suffix=suf;
	if (n) {
		DirEntrys = new (DirContents * [n]) ;
		for (int i = 0 ; i < n ; i ++) DirEntrys[i]=0 ;
	} else DirEntrys = 0;
}

const char * DirNames::GetDirName(int i) const
{
	if (i >= MaxSize) return 0 ;
	if (!GetDirEntry(i)) return 0 ;
	return GetDirEntry(i)->GetDir();
}

static const char * handle_dots(const char *dir)
{
	static char * ret = 0 ;
	static size = 0 ;
	const min_size = 256 ;

	static const char ** slash_pointers = 0 ;
	static char * dot_dot_flag = 0 ;
	static slash_pointers_size = 0 ;
	const min_slash_pointers_size = 32 ;
	
	int slash_count = 0 ;
	for (const char * pdir=dir+1 ; *pdir; pdir++) 
		if (*pdir == '/' ) slash_count++ ;
	if (!slash_count) return dir ;
	if (++slash_count > slash_pointers_size) {
		slash_pointers_size = slash_count + 4 ;
		if (slash_pointers_size < min_slash_pointers_size)
			slash_pointers_size = min_slash_pointers_size ;
		delete slash_pointers ;
		delete dot_dot_flag ;
		slash_pointers = new const char *[slash_pointers_size];
		dot_dot_flag = new char[slash_pointers_size];
	}
	int do_transform = 0 ;
	slash_count = 0 ;
	slash_pointers[slash_count++]=dir ;
	int all_dots = !strncmp(dir,"../",3) ;
	for (pdir=dir+1 ; *pdir; pdir++) 
      if (*pdir == '/' ) {
		dot_dot_flag[slash_count] = 0 ;
		if (!strcmp(pdir,"/.")) {
			do_transform = 1 ;
			break ;		  // remove trailing `\.'
		}
		if (!strncmp(pdir,"/./",3)) {
			do_transform = 1 ;
			continue ; // remove intermideate `/.' 
		}
		if (!strncmp(pdir,"/../",4) || !strncmp(pdir,"/..",3)) {
			if (!all_dots) {
				do_transform = 1 ;
				dot_dot_flag[slash_count] = 1 ;
			}
		} else all_dots = 0 ;
		slash_pointers[slash_count++] = pdir ;
	}
	if (!do_transform) return dir ;
	int max_length = strlen(dir) + 1;
	if (max_length > size) {
		size = max_length ;
		if (max_length < min_size) max_length = min_size ;
		delete ret ;
		ret = new char[size] ;
	}
	for (int ls = 0; ls < slash_count ; ls++) {
		if (dot_dot_flag[ls]) if (ls) if (!dot_dot_flag[ls-1]) {
			for (int xs = ls+1; xs < slash_count; xs++) {
				slash_pointers[xs-2] = slash_pointers[xs] ;
				dot_dot_flag[xs-2] = dot_dot_flag[xs] ;
			}
			ls-=2 ;
			slash_count-=2 ;
		}
	}
	char * dest = ret ;
	for (ls = 0; ls < slash_count ; ls++) {
		const char * pt = slash_pointers[ls] ;
		*dest++ = *pt++ ;
		while (*pt && *pt != '/' ) *dest++ = *pt++ ;
	}
	*dest = '\0' ;
	return ret ;
}

int DirNames::OpAddName(const char * name, int Main, int LibFlag) 
{
	if (TheNext >= MaxSize) InternalError("DirNames::OpAddName");
	DirEntrys[TheNext] = new DirContents(Concatenate(handle_dots(name)),
			Suffix,Main,TheNext, LibFlag);
	DirEntrys[TheNext]->SetIndex(TheNext) ;
	return TheNext++ ;
}

DirContents * DirNames::GetUsrContents(const char * Name)
{
	for (int i = 0 ; i < TheNext ; i++) if (!strcmp(Name,GetDirName(i)))
		return GetDirEntry(i);
	return 0;
}

void DirNames::ListObjsNotCollected(const char * name, OutTokens * out,
	PackageDesc * pkg, MakeDirOption Opt)
{
	const char ** Exclude = pkg->GetNoCollNames() ;
	for (int i = 0 ; i < TheNext ; i++) {
		const char * DirName = GetDirName(i);
		if (!strcmp(name,DirName)) continue ;
		if (!pkg->IsCollectLibrarys()) {
			// cerr << "Before ListForeignObjs 1\n" ;
			GetDirEntry(i)->ListForeignObjs(out,i,Opt,pkg) ;
			// cerr << "After ListForeignObjs 1\n" ;
			continue ;
		}
		if (Exclude) for (const char ** Check = Exclude; *Check;Check++) {
			if(!strcmp(*Check,DirName)) {
				// cerr << "Before ListForeignObjs 2\n" ;
				GetDirEntry(i)->ListForeignObjs(out,i,Opt,pkg) ;
				// cerr << "Before ListForeignObjs 2\n" ;
				break ;
			}
		}
	}
}

void DirNames::ListCollObjs(const char * name, const char ** Exclude,
	OutTokens * out, MakeDirOption Opt,PackageDesc * pkg)
{
	for (int i = 0 ; i < TheNext ; i++) {
		const char ** Check ;
		const char * DirName = GetDirName(i);
		if (pkg->InCollectedLib(DirName)) continue ;
		if (!strcmp(name,DirName)) continue ;
		if (Exclude) for (Check = Exclude; *Check;
			Check++) if(!strcmp(*Check,DirName)) break ;
		if (*Check) continue ;
		GetDirEntry(i)->ListForeignObjs(out,i,Opt,pkg) ;
	}
}

void DirNames::ListForeignObjs(const char * name, OutTokens * out,
	MakeDirOption Opt, PackageDesc * pkg)
{
	for (int i = 0 ; i < TheNext ; i++) {
		if (!strcmp(name,GetDirName(i))) continue ;
		if (pkg->InCollectedLib(GetDirName(i))) continue ;
		GetDirEntry(i)->ListForeignObjs(out,i,Opt,pkg) ;
	}
}

void DirNames::ListForeignLibs(const char * name, OutTokens * out,
	PackageDesc * pkg, MakeDirOption Opt)
{
	for (int i = 0 ; i < TheNext ; i++) {
		if (!strcmp(name,GetDirName(i))) continue ;
		if (pkg->InCollectedLib(GetDirName(i))) continue ;
		GetDirEntry(i)->ListForeignLibs(out,i,pkg,Opt) ;
	}
}

char * StrLowerCpy(char * Dest, const char * Source)
{
	char * Pt = Dest ;
	while(*Source) *Pt++ = tolower(*Source++);
	*Pt++ = '\0' ;
	return Dest ;
}

const char * DirContents::MakeLibName(PackageDesc * pkg, int CollectFlag)
{
	const char * move = pkg->moveable_lib_name(DirName);
	if (move) return move ;
	char * UpTailDirName = 0 ;
	const char * TailDirName = pkg->IsUpLibraryName() ?
            (UpTailDirName = TailUpName(DirName)):TailName(DirName);

	const NameBufSize = 128 ;
	const char * CollPre = "LibColl" ;
	const int MaxAdd = strlen(CollPre);
	if (strlen(TailDirName) + MaxAdd >= NameBufSize) {
		cerr << "TailDirName too long `" << TailDirName << "'\n" ;
		exit(1);
	}
	static char NameBuf[NameBufSize];
	if (TiC30Option) {
		StrLowerCpy(NameBuf,TailDirName);
		if (CollectFlag) strcat(NameBuf,".lbc");
		else strcat(NameBuf,".lib");
		delete UpTailDirName ;
		return NameBuf ;
	}
	if (CollectFlag) strcpy(NameBuf,CollPre);
	else strcpy (NameBuf,"Lib");
	strcat (NameBuf,TailDirName);
	strcat (NameBuf,LibSuffix);
	delete UpTailDirName ;
	return NameBuf ;
}

void DirContents::ListForeignLibs(OutTokens * Out,int DirIndex,
	PackageDesc *pkg, MakeDirOption Opt)
{
	if (LibFlag) {
		const char * Temp = MakeLibName(pkg);
		char * name = MakeDirName(DirIndex,Temp,Opt);
		Out->NextOut(name) ;
		delete name ;
		return ;
	}
}

void DirContents::ListForeignObjs(OutTokens * Out,int DirIndex,
	MakeDirOption Opt, PackageDesc * pkg)
{
	if (LibFlag) return ;
	if (pkg->InCollectedLib(pkg->CDirs->GetDirName(DirIndex))) return ;
	for (int i = 0 ; i < NumFiles ; i ++) {
		char * name = MakeObjName(MakeDirName(DirIndex,GetName(i),Opt));
		Out->NextOut(name) ;
		delete name ; 
	}
}

void DirNames::ClearAllPrintFlags()
{
	for (int i = 0; i< TheNext ; i ++) GetDirEntry(i)->ClearPrintDir();
}

void DirNames::WriteMake(PackageDesc * pkg)
{
	TestAlloc("DirNames::WriteMake enter");
	for (int i = 0 ; i < TheNext ; i++) {
		TestAlloc("DirNames::WriteMake a");
		DirEntrys[i]->WriteMake(pkg) ;
	}

	if (pkg->GetMenuDir()) if (!pkg->IsMenuMakeFileCreated()) {
		cerr << "Warning: the directory for making the menus\n " ;
		cerr << "must also be specifed as a `.cxx' source directory.\n" ;
	}
	TestAlloc("DirNames::WriteMake exit");
}

void DirNames::SetDependencies(PackageDesc *pkg)
{
	for (int i =0; i< TheNext ;i++)
		DirEntrys[i]->SetDependencies(pkg) ;
}

void DirNames::Display()
{
	for (int i = 0; i < TheNext ; i ++ ) DirEntrys[i]->Display() ;
}

void DirNames::FindFiles()
{
	for (int i = 0; i < TheNext ; i++ ) DirEntrys[i]->FindFiles() ;
}


char * MakeDirName(int DirIndex, const char * FileName,
	MakeDirOption opt, DirNames * Dirs)
{
	char Buffer[256] ;
	Buffer[0] = '\0' ;
	int MacroFlag = 1;
	switch (opt) {
case MakeDirExpand:
		if (!Dirs) {
			cerr << "Bad call to MakeDirName.\n" ;
			exit (1);
		}
		strcpy(Buffer,Dirs->GetDirName(DirIndex));
		MacroFlag = 0;
		break ;
case MakeDirH:
		strcpy(Buffer,"${HD_");
		break ;
case MakeDirUsr:
case MakeDirC:
		strcpy(Buffer,"${C_DIR_");
		break ;
case MakeDirBase:
		strcpy(Buffer,"${C_DIR_B_");
		break ;
default:
		cerr << "MakeDirName: bad option\n" ;
		exit(1);
	} ;
	if (MacroFlag) {
		char buf[32];
		sprintf(buf,"%d",DirIndex);
		strcat(Buffer,buf);
		strcat(Buffer,"}");
	}
	return MakeFullName(Buffer,FileName);
}

void DirNames::PrintMacro(ostream * out, const char * Obj, MakeDirOption Opt)
{
	int Clean = !strcmp("ALL_OBJS",Obj);
	OutTokens * ListOut = 0;
	ostream * FileOut = 0;
	if (GlobalMacrosInMake) {
		ListOut = new OutTokens(LongPage(out));
		ListOut->NextConcat(Obj);
		ListOut->NextConcat(" = ");
	} else if (MacrosFilesOptions == GlobalMacrosFilesNone) return ;
	else FileOut = &(OpenFile(Obj));
	for (int i = 0; i < TheNext ; i++) {
		DirContents * DirPt = GetDirEntry(i) ;
		if (!DirPt->contains_directories()) continue ;
		if (Opt == MakeDirH) if (!DirPt->TestPrintDir()) continue;
		// Skip unreferenced header directory
		for (int j = 0 ; j < DirPt->Size() ; j++ ) {
			if (ListOut) {
				char * temp =
					MakeDirName(i,DirPt->GetName(j), Opt);
				if (Clean) {
					char * nm = MakeObjName( temp );
					ListOut->NextOut(nm);
					delete nm ;
				} else ListOut->NextOut(temp);
				delete temp;
			}
			if (FileOut) {
				char * temp = MakeDirName(i,DirPt->GetName(j),
						MakeDirExpand, this);
				if (Clean) {
					char * nm = MakeObjName(temp);
					delete temp ;
					temp = nm ;
				}
				switch (MacrosFilesOptions) {
case GlobalMacrosFilesNone:
default:
					cerr <<
					"Bad option in DirNames::PrintMacro\n";
					return ;
case GlobalMacrosFiles:
					*FileOut << temp << "\n" ;
					break ;
case GlobalMacrosFilesBackSlash:
					*FileOut << temp << " \\\n" ;
					break ;
case GlobalMacrosFilesOneLine:
					*FileOut << temp << " " ;
					break ;
				}
				delete temp ;
			}
		}
	}
	if (ListOut) {
		delete ListOut ;
		*out << "\n\n" ;
	}
	delete FileOut ;
}

void DirNames::PrintMake(ostream * out, const char * Obj,
	const char * Command, MakeDirOption Opt)
{
	int Clean = !strcmp("CLEAN",Obj);
	OutTokens ListOut(LongPage(out));
	ListOut.NextConcat(Obj);
	if (Clean) {
		ListOut.NextConcat(".");
		ListOut.NextConcat(ObjSuffix);
	} else ListOut.NextConcat(Suffix);
	ListOut.NextConcat(" :");
	for (int i = 0; i < TheNext ; i++) {
		DirContents * DirPt = GetDirEntry(i) ;
		if (Opt == MakeDirH) if (!DirPt->TestPrintDir()) continue;
		// Skip unreferenced header directory
		for (int j = 0 ; j < DirPt->Size() ; j++ ) {
			char * temp ;
			temp= MakeDirName(i,DirPt->GetName(j), Opt);
			if (Clean) {
				char * nm = MakeObjName(temp) ;
				ListOut.NextOut(nm);
				delete nm ;
			} else ListOut.NextOut(temp);
			delete temp ;
		}
	}
	*out << "\n	" << Command << " $?\n" ;
}

const char * DirNames::GetSubSuffix()
{
	if (Sub[0]) return Sub ;
	if (!GetSubDir()) return Sub ;
	int Sz = 1 ;
	Sz+=strlen(GetSubDir())+1;
	if (Sz > BufSize) {
		cerr << "Name `/" <<  GetSubDir() << "' is greater than " <<
			(int) BufSize << " characters.\n" ;
		exit(10);
	}	
	Sub[0] = '\0' ;
	strcpy(Sub,"/");
	strcat(Sub,GetSubDir());
	return Sub ;
}

void DirNames::WriteMakeDir(ostream& Out, const char * Name,
	const char *Objective)
{
		Out << "\tbash -c \"cd " << Name << GetSubSuffix() << "; ${OPD_MAKE} " <<
			"-f Makefile " ;
		if (Objective) Out << Objective ;
		Out << "\"\n" ;
}

void DirNames::WriteCDirs(ostream * Out, const char * dirname,
	const char *Objective, PackageDesc * pkg)
{
	TestAlloc("DirContents::WriteCDirs 2 enter");
	const char * Sub = GetSubSuffix();
	// cerr << "Sub = `" << Sub << "'\n" ;
	// cerr << "SubDir = `" << SubDir << "'\n" ;
	// const char * Sub = SubDir ; // different suffix for usr files maybe
	for (int i = 0; i< TheNext ;i++) if (strcmp(dirname,GetDirName(i))) {
		TestAlloc("DirContents::WriteCDirs 2a");
		if (Objective) if (!strcmp(Objective,MakeLocalUsr))
			if (!GetDirEntry(i)->GetUsrContents(pkg)) continue ;
		TestAlloc("DirContents::WriteCDirs 2b");
		WriteMakeDir(*Out,GetDirName(i),Objective);
	}
	TestAlloc("DirContents::WriteCDirs 2 exit");
}

void DirNames::WriteCDirMacros(ostream * Out)
{
	const char * Sub = GetSubSuffix();
	for (int i = 0; i< TheNext ;i++) 
		*Out << "C_DIR_" << i << " = " << GetDirName(i) << Sub << "\n" ;
	for (i = 0; i< TheNext ;i++) 
		*Out << "C_DIR_B_" << i << " = " << GetDirName(i) << "\n" ;
}

int DirNames::Included(const char * Name)
{
	for (int i = 0 ; i < TheNext ; i++) if (!strcmp(Name,GetDirName(i)))
		return 1;
	return 0;
}

void DirContents::SetDependencies(PackageDesc * pkg)
{
	int NumberWords = pkg->GetNumFlagWords();
	// cout << "NumberWords = " << NumberWords  << "\n" ;
	for (int i =0; i< NumFiles ;i++) {
		uint32 * DepAr = new uint32[NumberWords];
		for (int j = 0 ; j < NumberWords;j++) DepAr[j]=0;
		FileEntry[i].SetDepend(DepAr) ;
		FileEntry[i].GetDependencies(DirName, pkg);
		FileEntry[i].SetDependencies(pkg);
	}
}



void DirContents::MainUsrOut(PackageDesc *pkg)
{
	if (!OutMakeLocalUsr(pkg,LocalUsrMakes))  {
		if (!pkg->AnyUsrObjects()) return ;
		*MakeOut << LocalUsrMakes << " :\n" ;
		// cerr << "Writing, `"<< pkg->UsrDirs->GetSubDir() << "'\n" ;
		pkg->UsrDirs->WriteCDirs(MakeOut,DirName,MakeLocalUsr,pkg) ;
	}
}

void DirContents::EmitExecutable(PackageDesc * pkg, OutTokens& ListOut)
{
	int LineOut = 1 ;
	const char * Objective = pkg->GetObject() ;
	if (!Objective) Objective = "a.out" ;
	*MakeOut << "LocalTarget : " << Objective << "\n\n" ;
	if (pkg->make_dir_list()) {
		*MakeOut << "CheckMakes:\n" ;
		for (const char ** pt = *pkg->make_dir_list(); *pt; pt++) {
			*MakeOut << "\tbash -c \"cd " << *pt << "; ${OPD_MAKE}\"\n" ;
		}
		*MakeOut << "\n" ;
	}
	if (pkg->makeable_libs().Size()) {
		MakeableLibListIterator Next(pkg->makeable_libs()) ;
        MakeableLib * lb ;
        while(lb = Next()) *MakeOut << lb->name << "::\n\tbash -c \"cd " <<
			lb->directory << "; ${OPD_MAKE}\"\n" ;
		*MakeOut << "\n" ;
	}
	if (pkg->LibCollDirList) {
		const char * CollName = "TheCollectLibraries" ;
		*MakeOut << "Target : " << CollName << " " << Objective << "\n";
		*MakeOut << CollName << " :\n" ;
		for (const char *** Col = pkg->LibCollDirList; *Col ; Col++)
			pkg->CDirs->WriteMakeDir(*MakeOut,**Col);
	} else *MakeOut << "Target : " << Objective << "\n" ;
	*MakeOut << "\n" ;
	*MakeOut << Objective << ":" ;
	LineOut += strlen(Objective) ;
	int Collect = pkg->IsCollectLibrarys() ;
	const char * LOCAL_LINK = "${LOCAL_LINK}" ;
	if (Collect) {
		const char * LibName = MakeLibName(pkg,1);
		char * FullLink = Concatenate(LOCAL_LINK," ",LibName," ");
		*MakeOut << FullLink ;
		LineOut += strlen(FullLink);
		delete FullLink ;
	} else {
		char * Objs = Concatenate(" ","${OBJS} ", LOCAL_LINK," ");
		*MakeOut << Objs ;
		LineOut += strlen(Objs) ;
		delete Objs ;
	}
	// ListOut.SetCharactersInLine(LineOut);
	pkg->CDirs->ListObjsNotCollected(DirName,&ListOut,pkg,MakeDirC) ;
	pkg->CDirs->ListForeignLibs(DirName,&ListOut,pkg) ;
	pkg->OutLibrarys(ListOut);
	pkg->EmitCollectLibDirectories(ListOut);
	if (pkg->makeable_libs().Size()) {
		MakeableLibListIterator Next(pkg->makeable_libs()) ;
       	MakeableLib * lb ;
       	while(lb = Next()) ListOut.NextOut(lb->name);
	}
	ListOut.NewLine();
	
	char * DoCC = Concatenate(" ${C_LINK} ${OBJS} ", LOCAL_LINK, " ") ;

	OutTokens& UseListOut = ListOut ;
	if (Use_makemake_link) {
		*MakeOut <<
			"\techo \". ${develop}/scripts/clean ; " << DoCC
			<< "\\\\\" > makemake_link\n" ;
		UseListOut = *(new OutTokens(MakeOut,0," \\\\\" makemake_link",
			" ","\tapec \"",80,0x7fffffff));
		UseListOut.InitiateLine();
	} else *MakeOut << "\t" << DoCC << "\\\n" ;
	UseListOut.InitiateLine();
	delete DoCC ;
	pkg->CDirs->ListObjsNotCollected(DirName,&UseListOut,pkg) ;
	for (int i = 0 ; i < pkg->HowManyLibraryRepeats(); i++) {
		const char * CollLib = 0 ;
		if (Collect) {
			CollLib = MakeLibName(pkg,1);
			UseListOut.InitiateLine();
			UseListOut.NextOut(CollLib);
			UseListOut.InitiateLine();
		}
		pkg->CDirs->ListForeignLibs(DirName,&UseListOut,pkg) ;
 		if (Collect) {
			CollLib = MakeLibName(pkg,1);
			UseListOut.InitiateLine();
			UseListOut.NextOut(CollLib);
			UseListOut.InitiateLine();
		}
		pkg->OutLibrarys(UseListOut);
		pkg->EmitCollectLibDirectories(UseListOut);
		if (pkg->LibSearchList) for (const char ** l = pkg->LibSearchList;
			*l; l++) UseListOut.NextOut(*l) ;
		if (pkg->makeable_libs().Size()) {
			MakeableLibListIterator Next(pkg->makeable_libs()) ;
        	MakeableLib * lb ;
        	while(lb = Next()) UseListOut.NextOut(lb->name);
		}
	}
	UseListOut.NextOut(" ");
	UseListOut.NextOut(LOCAL_LINK) ;
	UseListOut.NextOut("${LKFLAGS} -o ");
	UseListOut.NextOut(Objective);
	if (Use_makemake_link) {
		*MakeOut << " \" makemake_link\n" ;
		*MakeOut << "\t${OPD_SHELL} makemake_link\n" ;
	} else *MakeOut << "\n" ;
	*MakeOut << "\t${LAST_ACTION}\n" ;
}

static const char * GetArchiveCmd()
{
	if (TiC30Option) return "tic30ar" ;
	return "${OPD_LIB}" ;
}

const char * DirListFileName = "source_dir.lst" ;

int DirContents::IsLibraryDirectory(const PackageDesc *pkg) const
{
	if (LibFlag) return 1 ;
	if (pkg->GetLinkDirectoryList(DirName)) return 1 ;
	if (MainDir) if (pkg->IsCollectLibrarys()) return 1 ;
	return 0 ;
}

char * DirContents::MakeTargetDirName(const PackageDesc * pkg,
	const char *FileName)
{
	const char * TailSlash = "/" ;
	const char * Sub = pkg->GetSubDir();
	if (!FileName) TailSlash = 0 ;
	if (Sub) return Concatenate(DirName,"/",Sub,TailSlash,FileName);
	else return Concatenate(DirName,TailSlash,FileName);
}

void DirContents::WriteCollectSourceDirectoryList(ostream& Out,
	const PackageDesc *pkg)
{
	// cerr << "WriteCollectSourceDirectroyList\n" ;
	pkg->CDirs->WriteSourceDirs(Out,DirName,pkg->GetNoCollNames(),pkg,
		*KeepDirs) ;
}

void DirNames::WriteSourceDirectoryList(const PackageDesc * pkg)
{
	if (!pkg->IsCreateSourceDirList()) return ;
	for (int i = 0 ; i < TheNext ;  i++)
		GetDirEntry(i)->WriteSourceDirectoryList(pkg); 

}

void DirContents::WriteSourceDirectoryList(const PackageDesc * pkg)
{
	KeepDirs->Reset();
	if (!IsLibraryDirectory(pkg)) return ;
	char * FileName = MakeTargetDirName(pkg,DirListFileName);
	ofstream DirListOut(FileName);
	pkg->EmitLinkDirectories(DirListOut,DirName,*KeepDirs);
	if (MainDir) if (pkg->IsCollectLibrarys())
		WriteCollectSourceDirectoryList(DirListOut,pkg);
	delete FileName ;
}

void DirContents::ReadDependentLibraryFiles()
{
	// NEED CODE
}

void DirContents::WriteExecutableDirectoryList()
{
	ReadDependentLibraryFiles(); 
	// NEED CODE
}


const char * DirNames::GetCollLibName(PackageDesc * pkg)
{
	if (CollLibName) return CollLibName ;
	CollLibName = DirEntrys[0]->MakeLibName(pkg,1) ;
	// CollLibName = Concatenate(CollLibName,LibSuffix);
	return CollLibName ;
}

void DirContents::MainOut(PackageDesc *pkg)
{
	TestAlloc("DirContents::MainOut enter");
	pkg->CDirs->WriteCDirMacros(MakeOut) ;
	TestAlloc("DirContents::MainOut a");
	const char * Objective = pkg->GetObject() ;
	if (!Objective) Objective = "a.out" ;
	static const char * LinkSuf = "_Link" ;
	char * ObjLink = new char[strlen(Objective)+strlen(LinkSuf)+1];
	TestAlloc("DirContents::MainOut a");
	strcpy(ObjLink,Objective);
	TestAlloc("DirContents::MainOut a");
	strcat(ObjLink,LinkSuf);
	TestAlloc("DirContents::MainOut a");
	int Collect = pkg->IsCollectLibrarys() ;

	const char * CollectLibName = 0;
	if (Collect) CollectLibName = pkg->CDirs->GetCollLibName(pkg);
	TestAlloc("DirContents::MainOut a");

	// THE FOLLOWING MUST BE THE FIRST (DEFAULT) OBJECTIVE
	*MakeOut << ObjLink << " : " ;
	if (pkg->make_dir_list()) *MakeOut << "CheckMakes" ;
	if (pkg->makeable_libs().Size()) {
		*MakeOut << " \\\n\t" ;
		MakeableLibListIterator Next(pkg->makeable_libs()) ;
		MakeableLib * lb ;
		while(lb = Next()) *MakeOut << lb->name << 
		" \\\n\t" ;
	}
	*MakeOut << " UsrMakes LocalMakes ${OBJS} \\\n\t" ;
	if (!pkg->IsNoExecutable()) *MakeOut << Objective  ;
	else if (Collect) {
		if (pkg->IsNoExecutable() && pkg->GetObject())
			*MakeOut << pkg->GetObject() << LibSuffix ;
		else *MakeOut << CollectLibName ;
	}
	*MakeOut << "\n\n" ;
	TestAlloc("DirContents::MainOut a");


	*MakeOut << "UsrMakes : " ;
	if (pkg->AnyUsrObjects()) *MakeOut << LocalUsrMakes << " " ;
	if (pkg->GetMenuDir()) * MakeOut << "LocalMenuMake" << " " ;
	*MakeOut << "\n" ;

	OutTokens ListOut(LongPage(MakeOut)) ;

	TestAlloc("DirContents::MainOut b");
	if (Collect) {
		*MakeOut << "COLL_OBJS = ${OBJS} \\\n" ;
		pkg->CDirs->ListCollObjs(DirName,pkg->GetNoCollNames(),
			&ListOut,MakeDirC,pkg) ;
		*MakeOut << "\n" ;
		// if (!pkg->IsNoExecutable()) *MakeOut << Objective << " " ;
		if (pkg->IsNoExecutable() && pkg->GetObject()) *MakeOut <<
			pkg->GetObject() << LibSuffix << " : " ;
		else *MakeOut << CollectLibName << " :" ;
		*MakeOut << " ${COLL_OBJS} \n" ;
		*MakeOut << "\ttouch " << CollectLibName << "\n" ;
		*MakeOut << "\trm " << CollectLibName << "\n" ;
		*MakeOut << "\t" << GetArchiveCmd() << CollectLibName <<
			"  ${COLL_OBJS}\n"  ;
		if (pkg->ranlib_set()) *MakeOut << "\tranlib " <<
			CollectLibName << "\n" ;
		if (pkg->IsNoExecutable()) {
			if (pkg->GetObject()) *MakeOut << "\tmv " << CollectLibName <<
				" " << pkg->GetObject() << LibSuffix << "\n" ;
			*MakeOut << "\t${LAST_ACTION}\n" ;
		}
		*MakeOut << "\n" ;
	} 

	TestAlloc("DirContents::MainOut c");
	if (!pkg->IsNoExecutable()) EmitExecutable(pkg,ListOut);
	else if (Collect)
	    *MakeOut << "Target LocalTarget : " << CollectLibName << "\n\n" ;
		
	MainUsrOut(pkg);

	const char * Sub = pkg->CDirs->GetSubSuffix();
	if (pkg->GetMenuDir()) *MakeOut << "LocalMenuMake :\n\tbash -c \"cd " <<
		pkg->GetMenuDir() << Sub <<
		"; ${OPD_MAKE} -f Makefile MakeLocalMenuDepends\"\n\n" ;

	*MakeOut << "LocalMakes :\n" ;
	pkg->CDirs->WriteCDirs(MakeOut,DirName);

	delete ObjLink ;
}

void DirContents::EmitDirObjList(ostream * MakeOut, PackageDesc *pkg)
{
	const char ** DirectoriesToLink = pkg->GetLinkDirectoryList(DirName);
	if (DirectoriesToLink) {
		int LineUse = 1000 ; // force new line immediately
		*MakeOut << " " ;
		pkg->AddObjsFromDirectories(MakeOut,DirectoriesToLink,
			LineUse);
		if (LineUse > 4) *MakeOut << "\n" ;
	} else *MakeOut << "\n" ;
}

ostream ** debug_make_out = 0 ;

void DirContents::WriteMake(PackageDesc * pkg) 
{
	// cout << "WriteMake for `" << DirName << "'\n" ;
	TestAlloc("DirContents::WriteMake enter");
	if (pkg->IsSubDir())
		if (!CheckSubDir(MakeFullName(DirName,
			pkg->CDirs->GetSubDir()))) exit(1) ;

	// Create `target' subdirectory if needed
	if (pkg->IsUsrDir(DirName)) {
		if (!CheckSubDir(MakeFullName(DirName,"target"))) exit(1);
		if (!CheckSubDir(MakeFullName(DirName,"tex"))) exit(1);
		if (!CheckSubDir(MakeFullName(DirName,"texs"))) exit(1);
	}
	MakeFileName = MakeFullName(DirName, "Makefile", pkg->CDirs->GetSubDir());
	TestAlloc("DirContents::WriteMake a");
	// cout << "Before open\n" ;
	MakeOut = new ofstream(MakeFileName) ;
	debug_make_out = &MakeOut ;
	// cout << "Before after\n" ;
	if (!MakeOut->good()) {
		cerr << "Can't create makefile " << MakeFileName << ".\n" ;
		delete (char*) MakeFileName ;
		MakeFileName = 0 ;
		delete MakeOut ;
		MakeOut = 0 ;
		TestAlloc("DirContents::WriteMake b");
		return ;
	}
	TestAlloc("DirContents::WriteMake c");
	AddCopyright& add = AddCopyright::add_copyright() ;
	TestAlloc("DirContents::WriteMake cc");
	add.write_short(*MakeOut,MakeFileName, pkg->user_copyright(), DirName);
	TestAlloc("DirContents::WriteMake d");
	write_make_head(pkg);
	// cout << "Macros done.\n" ;
	WriteDirs(pkg,MainDir) ;
	TestAlloc("DirContents::WriteMake e");
	//    *MakeOut << "LOCAL_DIR = " << DirName << "\n" ;
	{
		*MakeOut << "LOCAL_DIR = "  ;
		if (pkg->IsSubDir())  *MakeOut << ".." ;
		else *MakeOut << "." ;
		*MakeOut << "\n" ;
	}
	*MakeOut << "MAIN_DIR = " ;
	if (MainDir) {
		if (pkg->IsSubDir())  *MakeOut << ".." ;
		else *MakeOut << "." ;
	} else *MakeOut << pkg->GetMainDir() ;
	*MakeOut << "\n" ;
	*MakeOut <<
	     "USR_H_DIR  = ${OPD_ROOT}/src/include/ObjProDSPint/ObjProUsr\n\n" ;
	*MakeOut << "SUB_DIR = " << pkg->GetSubDir() << "\n\n" ;
	TestAlloc("DirContents::WriteMake f");
	WriteObjs() ;  
	TestAlloc("DirContents::WriteMake g");
	WriteUsrDependsMacro(pkg);
	TestAlloc("DirContents::WriteMake h");
	WriteMenuDependsMacro(pkg);
	TestAlloc("DirContents::WriteMake i");
	if (MainDir) {
		 MainOut(pkg) ; 
		TestAlloc("DirContents::WriteMake j");
	} else if (IsLibraryDirectory(pkg)) {
		LibFlag = 1 ; // insure directoy gets picked up in master link
		const char * LibName = MakeLibName(pkg) ;
		TestAlloc("DirContents::WriteMake k");
		*MakeOut << "\nMakeLocalObjects : " << LibName << "\n\n" ;
		*MakeOut << LibName << " : ${OBJS}" ;
		EmitDirObjList(MakeOut,pkg);
		TestAlloc("DirContents::WriteMake k");
		*MakeOut << "\ttouch " << LibName << "\n" ;
		*MakeOut << "\trm " << LibName << "\n" ;
		*MakeOut << "\t" << GetArchiveCmd() << LibName
			<< "  ${OBJS}"  ;
		EmitDirObjList(MakeOut,pkg);
		TestAlloc("DirContents::WriteMake l");
		if (pkg->ranlib_set()) *MakeOut << "\tranlib " <<
			LibName << "\n" ;
		*MakeOut << "\t${LAST_ACTION}\n" ;
	} else *MakeOut << "\nMakeLocalObjects : ${OBJS}\n\n" ;
	TestAlloc("DirContents::WriteMake m");
	WriteUsrDepends(pkg);
	TestAlloc("DirContents::WriteMake n");
	WriteMenuDepends(pkg);
	TestAlloc("DirContents::WriteMake o");
	WriteCDepen(pkg); 
	TestAlloc("DirContents::WriteMake p");
	if (MainDir  && pkg->list_files()) {
		pkg->HDirs->PrintMacro(MakeOut,"ALL_HEADS", MakeDirH);
		TestAlloc("DirContents::WriteMake q");
		pkg->CDirs->PrintMacro(MakeOut,"ALL_C_FILES",MakeDirBase);
		TestAlloc("DirContents::WriteMake r");
		pkg->UsrDirs->PrintMacro(MakeOut,"ALL_USR_FILES",MakeDirUsr);
		TestAlloc("DirContents::WriteMake s");
		pkg->CDirs->PrintMacro(MakeOut,"ALL_OBJS",MakeDirC);
		TestAlloc("DirContents::WriteMake t");
	}
	AppendTail(pkg);
	TestAlloc("DirContents::WriteMake u");
	if (MainDir) {
		if (pkg->makemake_depend()) {
			const char * cre = "OPD_MAKEFILE_CREATOR" ;
			*MakeOut << cre << ":=$(wildcard ${OPD_ROOT}/bin/makemake"
				<< ExeSuffix << ")\n" ;
			*MakeOut << "ifdef " << cre << "\n" ;
			*MakeOut << "Makefile:" ;
				for (const char ** pt = pkg->makemake_depend() + 1 ; *pt; pt++)
					*MakeOut << " " <<  *pt  ;
				*MakeOut << "\n\t${OPD_SHELL} " << *(pkg->makemake_depend()) <<
					"\nendif\n\n" ;
/*
 *				"\nelse\n${OPD_ROOT}/scripts/Makefile_flt.sh > opd_sed_edit\n"
 *				<< "bash opd_sed_edit < Makefile > Makefile.new\n" <<
 *				"mv Makefile.new Makefile\nendif\n\n" ;
 */
		}
		if (pkg->include_main())
			*MakeOut << "include " << pkg->include_main() << "\n\n" 
			<< pkg->include_main() << ":\n\tdomakemake\n\n" ;
	}
	if (pkg->include_all()) *MakeOut << "include " << pkg->include_all()
		<< "\n" << pkg->include_all() << ":\n\tdomakemake\n\n" ;
	TestAlloc("DirContents::WriteMake v");
	delete MakeOut ; 
	TestAlloc("DirContents::WriteMake y");
	delete (char*) MakeFileName ;
	TestAlloc("DirContents::WriteMake z");
	MakeFileName = 0 ;
	TestAlloc("DirContents::WriteMake exit");
}


void DirContents::copy_file(istream * from, ostream * to, const char * to_name,
	const char * from_name)
{
	const buf_size = 4096 ;
	char buf[buf_size];
	if (from_name)
		*to << "############### From `" << from_name << "' ###############\n";
	while (from->good() && to->good()) {
		from->read(buf,buf_size);
		to->write(buf,from->gcount());
    }
	if (from_name)
		*to << "############### End  `" << from_name << "' ###############\n";
    if (!to->good()) cerr << "Error writing `" << to_name << ".\n" ;

}

int DirContents::cond_append(const char * dir, const char * base,
	const char * suf)
{
	char * name = 0 ;
	istream * in = PackageDesc::get_file(dir,base, suf, &name);
	if (in) {
		copy_file(in, MakeOut, MakeFileName,name);
		delete in ;
		delete name ;
		return 1 ;
	}
	return 0 ;
}

int DirContents::cond_append_base(const char * dir, const char * base,
	const char * sub_dir, const char * suf, add_flags flags)
{
	const last_case = 3 ;
	int total_done = 0 ;
	static int invert[last_case+1] = { last_case, 2, 1, 0} ;
	char * sub_base = 0 ;
	if (sub_dir) sub_base = Concatenate(sub_dir,"/",base);
	for (int i = 0 ; i < last_case + 1 ; i++) {
		int index ;
		if (flags & specific_first) index = i ;
		else index = invert[i] ;
		int done = 0 ;
		switch (index) {
case 0 :
			if (suf && sub_dir) done = cond_append( dir, sub_base,suf);
			break ;
case 1 :
			if (suf) done = cond_append ( dir, base, suf);
			break ;
case 2 :
			if (sub_dir) done = cond_append( dir, sub_base) ;
			break ;
case 3 :
			done = cond_append(dir,base);
			break ;
		}
		total_done += done ;
   		if (done && (flags & only_once)) break ;
	}
	delete sub_base ;
	return total_done ;
}

int DirContents::add_files(const char * base, add_flags flags,
	PackageDesc * pkg)
{
	const last_case = 3 ;
	int total_done = 0 ;
	const char * suf = pkg->system_suffix() ;
	const char * sub_dir = pkg->CDirs->GetSubDir();
	static int invert[last_case+1] = { last_case, 2, 1, 0} ;
	for (int i = 0 ; i < last_case + 1 ; i++) {
		int index ;
		if (flags & specific_first) index = i ;
		else index = invert[i] ;
		int done = 0 ;
		switch (index) {
case 0 :
			if (strcmp(DirName,pkg->CDirs->GetDirName(0)))
				done = cond_append_base(DirName,base,sub_dir,suf,flags);
			break ;
case 1 :
			done = cond_append_base(pkg->CDirs->GetDirName(0),
				base,sub_dir,suf,flags);
			break ;
case 2 :
			if (suf) done = cond_append(pkg->script_dir(),base,suf);
			break ;
case last_case :
			done = cond_append(pkg->script_dir(),base);
			break ;
		}
		total_done += done ;
		if (done && (flags & only_once)) break ;
	}
	return total_done ;
}

void DirContents::write_make_head(PackageDesc * pkg) 
{
	add_files(Makefile_head,null_flags,pkg);
}


void DirContents::AppendTail(PackageDesc * pkg) 
{
	// first add as many Make_include files as we find
	add_files(Makefile_inc,null_flags,pkg);

	// Add a single Makefile_tail checking for more specific first
	if (add_files(Makefile_tail,
		(DirContents::add_flags) (specific_first | only_once),pkg)) return ;
	
	const char * suf = pkg->system_suffix() ;
	cerr << "Cannot find any `" << Makefile_tail << "' file in directories:\n" ;
	cerr << "`" << DirName << "' or \n`" << pkg->CDirs->GetDirName(0) <<
		"' or \n`" << pkg->script_dir() << "'.\n" ;
	if (suf) cerr << "The system suffix is `" << suf << "'.\n" ;
	else cerr << "There is no system suffix in `" << pkg->script_dir()
		<< "/" << pkg->system_file_name() << "'.\n" ;
}

#ifdef not_defined
	struct filebuf * TailFile = new filebuf ;
	char *TailName = MakeFullName(DirName, Makefile_tail,
		pkg->CDirs->GetSubDir());
	istream * TailIn = new istream(TailFile) ;
	static int DidWarning = 0 ;
	const char * use_tail_name = 0 ;
	if (!TailFile->open(TailName,input)) {
		delete TailName ;
		char * SaveTailName = TailName =
			MakeFullName(pkg->CDirs->GetDirName(0),
			Makefile_tail, pkg->CDirs->GetSubDir());
		filebuf * IsOpen = TailFile->open(TailName,input) ;
		if (!IsOpen) if (pkg->CDirs->GetSubDir()) {
			TailName = MakeFullName(pkg->CDirs->GetDirName(0),
				Makefile_tail);
			IsOpen = TailFile->open(TailName,input) ;
		}
		if (!IsOpen) {
			if (!DidWarning) {
				cerr << "Warning: cannot read tail file:\n`"
					<< TailName ;
				if (strcmp(SaveTailName,TailName))
					cerr << "'\nor:\n`" << SaveTailName ;
				cerr << "'.\n";
			}
	
			if (strcmp(SaveTailName,TailName)) delete SaveTailName;
			SaveTailName = 0 ;
			delete TailName ;
			TailName = 0 ;
			char * NewTailName =
				"/usr/local/lib/makemake/Makefile_tail" ;
			if (!TailFile->open(NewTailName,input)) {
				delete TailFile ;
				delete TailIn ;
				cerr << "Cannot open any tail file.\n" ;
				exit(1);
				return ;
			}
			use_tail_name = NewTailName ;
			if (!DidWarning) {
				cerr << "Using system default file: `"
					<< NewTailName << "'.\n";
				DidWarning = 1 ;
			}
		}
	}
	char Buffer[2];
	char& cp = Buffer[0] ;
	Buffer[1]= '\0' ;
	int state ;
	if (!use_tail_name) use_tail_name = TailName ;
	*MakeOut << "############### From `" << use_tail_name << "' ###############\n";
	while ((state = TailIn->rdstate()) == _good) {
		TailIn->get(cp) ;
		*MakeOut << Buffer ;
	}
	*MakeOut << "############### End  `" << use_tail_name << "' ###############\n";
 	if (!(state & ios::eofbit))
		cerr << "Error in file `" << TailName << "' (state = " <<
		state << ")\n";
	delete TailName ;
	delete TailFile ;
	delete TailIn ;
}
#endif

void DirContents::WriteDirs(PackageDesc * pkg,int MainDir)
{
// #define DEBUG_INC
#ifdef DEBUG_INC
	cerr <<DirName << "::DirContents::WriteDirs\n";
#endif
	int i, Limit ;
	pkg->HDirs->ClearAllPrintFlags() ;
	uint32 * DataDirs = new uint32[Limit=(pkg->GetNumHDirs()+31)>>5];
	uint32 * inc_dirs = new uint32[Limit];
	for (i = 0 ; i < Limit ; i++) inc_dirs[i] = DataDirs[i] = 0 ;
	KeepDirs = new GetBits(pkg->GetNumHDirs(),DataDirs);
	GetBits * inc_dir = new GetBits(pkg->GetNumHDirs(),inc_dirs);
	for (i = 0; i < NumFiles ; i++ )  {
		GetBits * Bits = new GetBits(pkg->GetNumHEntries(),
			FileEntry[i].GetDepend()) ;
		int HeadInc ;

#ifdef DEBUG_INC
		cerr << "Searching dependencies for `" << FileEntry[i].GetName() <<
			"'.\n" ;
#endif
		while ((HeadInc = Bits->NextBit())> -1) {
			HeaderFile * file = pkg->GetAllHeaders()[HeadInc];
			if (!file) continue ;
			const char * DirName = file->GetDir();
			const char * inc_dir_name =  file->inc_dir();

#ifdef DEBUG_INC
			cerr << "Include file is `" << file->GetName() << "'\n" ;
			cerr << DirName << ": " << HeadInc << "  A dir name to check\n" ;
			cerr << inc_dir_name << ": An include dir name to check\n" ;
#endif

	 		int DirIndex = CheckDir(pkg->HDirs, DirName);
			// cerr << "inc_dir_name:" << inc_dir_name << "\n" ;
			int inc_index = CheckDir(pkg->HDirs, inc_dir_name) ;

#ifdef DEBUG_INC
			cerr << "DirIndex = " << DirIndex << ", inc_index = " << inc_index
				<< "\n" ;
#endif
			if (DirIndex > -1) KeepDirs->SetBit(DirIndex);
			if (inc_index == -1) inc_index = DirIndex;
			if (inc_index > -1) inc_dir->SetBit(inc_index);
		}
		delete Bits ;
	}
	if (MainDir) (void) CheckDir(pkg->HDirs, 0);
	const char * IncDirs = "INC_DIRS =" ;
	*MakeOut << IncDirs ;
	int LineOut = strlen(IncDirs);
	int BitNo ;
	while ((BitNo = inc_dir->NextBit())> -1) {
		// cerr << "Out:Set " << BitNo << "\n" ;
		if (LineOut + 12 > 77) {
			LineOut = 12 ;
			*MakeOut << " \\\n" ;
		}
		*MakeOut << " -I${HD_" << BitNo << "}" ;
	}
	*MakeOut << "\n" ;
}

const char *DirContents::GetName (int i) {
	return FileEntry[i].GetName() ;
}


char * DirContents::GetFullName(int i) 
{
	return MakeFullName(DirName,FileEntry[i].GetName());
}

void DirContents::SetDirContents(int num)
{
	NumFiles=num;
	// FileEntry = NEW(FileDesc, num);
	FileEntry = new FileDesc[num] ;
}


void DirContents::ClearPrintDir() {Flags &= ~PrintDirBit;}

void DirContents::SetPrintDir() {Flags |= PrintDirBit;}

int DirContents::TestPrintDir()  { return Flags & PrintDirBit;}


int DirNames::GetMemberIndex(const char * Name) const
{
	for (int i = 0 ; i < TheNext;i++)
		if (!strcmp(GetDirName(i),Name)) return i;
	return -1 ;
}

int DirNames::IsMember(const char * Name) const
{
	if (GetMemberIndex(Name) < 0) return 0;
	return 1 ;
}

void DirNames::Init()
{
	for (int i = 0 ; i < Size(); i++) GetDirEntry(i)->SetIndex(i);
}

void DirNames::WriteSourceDirs(ostream& Out, const char * DirName,
	const char ** NoCollNames, const PackageDesc * pkg, GetBits& Bits) const
{
	Out << DirName  << "\n" ;
	for (int i = 0 ; i < TheNext ; i++) {
		const char * dir_name = GetDirName(i);
		if (pkg->InCollectedLib(dir_name)) continue ;
		if (!strcmp(DirName,dir_name)) continue ;
		if (NoCollNames) {
			for (const char ** Check = NoCollNames; *Check;Check++)
				if(!strcmp(*Check,dir_name)) break ;
			if (*Check) continue ;
		}
		pkg->AddSourceDirectories(Out,Bits,dir_name);
	}
	pkg->WriteSourceDirectories(Out,Bits);
}


int DirNames::check_add(const char * name)
{
	const char * nm = handle_dots(name);
	for (int i = 0 ; i < TheNext;i++) if (!strcmp(nm,GetDirName(i))) return i ;
	return AddName(name);
}

void DirNames::MakeSureDependentCdirsAreFirst(int index, const char **DirList)
{
	if (index >= Size()) {
		cerr << "DirNames::MakeSureDependentCdirsAreFirst: bad index\n";
		exit(1);
	}
	int Max = index ;
	for (int j = 0 ; j <= Size() ; j++)
		for (const char **Dir = DirList; *Dir; Dir++)
			if (!strcmp(GetDirName(j),*Dir)) if (Max < j) Max = j ;
	// cerr << "Max = " << Max << "\n" ;
	if (Max > index) {
		DirContents * Temp = DirEntrys[index] ;
		DirEntrys[index] = DirEntrys[Max] ;
		DirEntrys[Max] = Temp ;
	}
}

