/*  package.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include <stdlib.h>
#include <stream.h>
#include <fstream.h>

#include "portable.h"
#include "package.h"
#include "bits.h"
#include "filename.h"
#include "filedes.h"
#include "dirdes.h"
#include "strgck.h"
#include "outtok.h"
#include "linlist.h"
#include "mkstr.h"
#include "flist.h"
#include "sysconst.h"

const char * default_root_directory = "/usr/local/lib/opd_root" ;

extern const char * LibSuffix ;

const char * DotC = CPP_SUFFIX;
const char * DotH = ".h";
const char * DotUsr = ".usr" ;

const char ** OmitCCLine = 0 ;

int PackageDesc::Set_dbXtra()
{
	int Return = dbXtraFlag ;
	dbXtraFlag = 1 ;
	return Return ;
}

void PackageDesc::SetCreateSourceDirList()
{
	CreateSourceDirList=1 ;
}

void PackageDesc::SetNoSourceNoWarnList(const char ** Names)
{
	NoSourceNoWarnList= Names ;
}


void PackageDesc::OutAllNodFiles(OutTokens& Out)
{
	if (!GetMenuDir()) {
		if (GetMenuFlag()) {
		cerr <<
		"Warning : `-menuflag' specified with no menu directory.\n" ;
			cerr << "-menuflag will be ingnored.\n" ;
		}
		return ;
	}
	for (int i = 0 ; i < UsrDirs->Size(); i++)
		UsrDirs->GetDirEntry(i)->OutAllNodFiles(Out,this) ;
}

void PackageDesc::OutMenuMakes(OutTokens& Out)
{
	for (int i = 3 ; i < TotalMenuNames; i++) {
		const char * NameOut = GetMenuName(i) ;
		if (CDirs->GetSubDir()) {
			const int BufSize = 512 ;
			static char Buf[BufSize+1];
			static const char * Prefix[] =
				{"${LOCAL_DIR}/","${LOCAL_DIR}/",""};
			for (int j = strlen(NameOut);j;j--)
				if (NameOut[j-1] == '.') break ;
			int Index = 2 ;
			if (NameOut[--j] == '.') if (!strcmp(NameOut+j,".cxx"))
				Index = 0;
			else if (!strcmp(NameOut+j,".h")) Index = 1 ;
			if (strlen(Prefix[Index]) + strlen(NameOut) >
				BufSize) {
				cerr << "File name `" << Prefix[Index] <<
					NameOut << "' is greater than " <<
					BufSize << " characters long.\n" ;
				exit(10);
			}
			strcpy(Buf,Prefix[Index]);
			strcat(Buf,NameOut);
			NameOut = Buf;
		}
		Out.NextOut(NameOut);
	}
}

int PackageDesc::CheckUsrC()
{
	int Return = 1 ;
	for (int i = 0 ; i < UsrDirs->Size(); i++) {
		const char * Check = UsrDirs->GetDirName(i);
		int Found = 0 ;
		for (int j = 0 ; j < CDirs->Size(); j++) 
			if (!strcmp(Check,CDirs->GetDirName(j))) {
				Found=1 ;
				break ;
			}
		if (!Found) {
			Return = 0 ;
			cerr << "`.usr' directory `" <<
			Check << "' is not a `.cxx' directory.\n" ;
		}
	}
	return Return ;
}

int PackageDesc::AnyUsrObjects()
{
	if (!UsrDirs) return 0 ;
	return UsrDirs->Size() != 0 ;
}

DirContents * PackageDesc::GetUsrContents(const char * Name)
{
	return UsrDirs->GetUsrContents(Name);
}

void PackageDesc::SolveDependencies()
{
	int Solved = 0 ;
	while (!Solved) {
	Solved = 1 ;
	for (int i = 0; i < HTotal ; i++) {
		HeaderFile * Head = AllHeaders[i] ;
		uint32 * Words = Head->GetHeaderWords() ;
		GetBits * Bits = new GetBits(HTotal, Words ) ;
		int HeadInc ;
		while ((HeadInc=Bits->NextBit()) > -1) {
			uint32 *HeadWords =
				AllHeaders[HeadInc]->GetHeaderWords();
			for (int j = 0; j < Head->GetNoHeaderWords() ; j++ ) {
				uint32 Save = Words[j] ;
				Words[j] |= HeadWords[j] ;
				if (Words[j] != Save) Solved = 0;
			}
		}
		delete Bits ;
	}
	}
}

inline const char * strend(const char * s)
{
	return strlen(s) + s - 1 ;
}

int PackageDesc::new_header_file(HeaderFile * f,const char * inc_d)
{
    if (dir_total >= total_space - 1) {
        cerr << "Overflowing extra directory space. Use option `dir_space' for more.\n" ;
        exit(5);
    }
    AllHeaders[dir_total] = new HeaderFile(f,HDirs->Size(),inc_d, NumFlagWords);
	HDirs->check_add(inc_d);
	// cout << AllHeaders[dir_total]->inc_dir() << "\n" ;
	// cout << "Include header file `" << inc_d << "' is " << dir_total << "\n";
    return HTotal = dir_total++ ;

}

int PackageDesc::GetIndex(char * name)
{
	const char * first_slash = strchr(name,'/') ;
	HeaderFile * found = 0 ;
	if (first_slash) {
		const char * np = strend(name);
		const char * last_slash = first_slash ;
		for (const char * p = np ; p > first_slash  ; p--) if (*p == '/') {
			last_slash = p ;
			break ;
		}
		for (int i = 0; i < HTotal; i++) {
			HeaderFile * f = AllHeaders[i] ;
			const char * dir = f->GetDir();
			const char * cmp = last_slash - 1 ;
			int differ = 0 ;
			const char * use_slash = strend(dir) + 1;
			for (const char * dp = use_slash - 1; dp >= dir; dp--) {
				if (*cmp != *dp) {
					differ = 1 ;
					break ;
				}
				if (--cmp < name) break ;
				if (*dp == '/') use_slash = dp ;
			}
			if (differ) continue ;
			if (!strcmp(first_slash+1,f->GetName())) {
				static char * buf = 0 ;
				static int size = 0 ;
				const min_size = 128 ;

				int length = dp - dir ;
				if (length > size) {
					size = length + 20 ;
					if (size < min_size) size = min_size ;
					delete buf ;
					buf = new char[size];
				}
				strncpy(buf,dir,length-1);
				buf[length-1] = '\0'; ;
				if (!f->inc_dir()) {
					const char * dir = Concatenate(buf);
					int index = HDirs->check_add(dir);
					f->set_inc_dir_name(dir);
					f->set_inc_dir_index(index);
				}
				else if (strcmp(f->inc_dir(),buf)) return
					new_header_file(f,Concatenate(buf));
				return i ;
			}
		}
	} else for (int i =0; i<HTotal; i++) {
		HeaderFile * f = AllHeaders[i] ;
		if (!strcmp(name,f->GetName())) {
			found = f ;
			if (!f->inc_dir()) f->set_inc_dir_name(f->GetDir());
			else if(strcmp(f->inc_dir(),f->GetDir())) continue ;
			return i;
		}
	}
	if (found) return new_header_file(found,found->GetDir());
	return -1 ;
}

void PackageDesc::GetDependencies()
{
	for (int i =0; i< HTotal;i++) AllHeaders[i]->GetDependencies(this);
}

void PackageDesc::SetCDependencies()
{
	CDirs->SetDependencies(this);
}

void PackageDesc::Display()
{
	cout<< "C Directories:\n" ; CDirs->Display();
	cout<< "Header Directories:\n" ; HDirs->Display();
	if (AllHeaders) {
		cout << "\nMaster Header List:\n" ;
		for (int i = 0; i< HTotal;i++) AllHeaders[i]->Display();
	}
}

int CompareHeaderFiles(const void * a, const void *b)
{
	return strcmp(((HeaderFile *)a)->GetName(),
		((HeaderFile *)b)->GetName());
}


void PackageDesc::SortHeaderTable()
{
	qsort((char *)AllHeaders, HTotal, sizeof(HeaderFile *),
		CompareHeaderFiles);
}

// typedef const char * (PackageDesc::*AllGetIndexed)(int) ;

const char * PackDGetString(int n, PackageDesc * pkg)
{
	static PackageDesc * pg ;
	if (pkg) {
		pg = pkg ;
		return 0;
	}
	return pg->GetHFile(n);
}

const char * PackGetString(int n)
{
	return PackDGetString(n,(PackageDesc *) 0);
}



void PackageDesc::MakeHeaderTable()
{
	
	// AllGetIndexed AllGetIx = &PackageDesc::GetHFile ;
	HTotal=0;
	for (int i = 0 ; i < GetNumHDirs() ; i++ ) 
		HTotal += HDirs->GetDirEntry(i)->Size();
	total_space = HTotal + extra_directory_space + 256 ;
	AllHeaders = new HeaderFile * [total_space] ;
	dir_total = HTotal ;
	NumFlagWords = (total_space + 31) >> 5;
	int j = 0;
	for (i = 0 ; i < GetNumHDirs() ; i++ ) {
		DirContents * DirEntry = HDirs->GetDirEntry(i) ;
		for (int l = 0; l < DirEntry->Size(); l++ ) {
			if (j>= HTotal)
				InternalError("PackageDesc::MakeHeaderTable");
			AllHeaders[j++] = new HeaderFile(DirEntry->GetName(l),
				DirEntry->GetDir(),NumFlagWords,i) ;
		} // loop on l (files)
	} // loop on i (directories)
	(void) PackDGetString(0,this);
	DuplicateStringCheck DupCk(PackGetString, HTotal);
	const char * Dup ;
	int Error = 0;
	while (Dup = DupCk.Ck()) {
		cerr << "Warning : Two header files named `" << Dup << "'.\n" ;
		// Error = 1;
	}
	if (Error) exit(4) ;
} 
	
PackageDesc::PackageDesc(int cfiles, int hfiles, int usrfiles,int NoCollFiles,
	int MenuFiles, const char * flag, const char * dir):
	dbXtraFlag(0),
	CreateSourceDirList(0),
	NoSourceNoWarnList(0),
	LibList(0),
	LibSearchList(0),
	LibDirList(0),
	MakeDirList(0),
	LibUpDirList(0),
	LibCollDirList(0),
	ArithFlag(0),
	Object(0),
	the_script_directory(0),
	the_script_dir(0),
	the_bin_directory(0),
	the_root_directory(0),
	the_system_suffix(0),
	dir_total(0),
	extra_directory_space(64),
	total_space(0),
	include_all_file(0),
	include_main_file(0),
	the_makemake_depends(0),
	use_ranlib(0),
	the_user_copyright(0),
	do_list_files(0)
{

	NoExecutable= 0;
	CollectLibFlag = 0;
	UpLibraryName=0;
	RepeatLibraryCount = 1 ;
	CDirs = new DirNames(cfiles,DotC);
    	HDirs = new DirNames(hfiles+extra_directory_space,DotH);
	UsrDirs = new DirNames(usrfiles,DotUsr);
	MenuFlag = flag ;
	NodDir = dir ;
	TotalMenuNames = MenuFiles ;
	TotalNoCollect = NoCollFiles ;
	NoCollNames = new const char * [TotalNoCollect+1];
	MenuNames = new const char * [TotalMenuNames+1];
	for (int i = 0 ; i < TotalNoCollect+1;i++) NoCollNames[i] = 0;
	for (i = 0 ; i < TotalMenuNames+1;i++) MenuNames[i] = 0;
	MenuMakeFileCreated=0;
	if (MenuFiles == 1) {
		cerr <<
	"At least two arguments (menu directory and menu input file)\n" ;
		cerr << "are required for `-menu'.\n"  ;
		exit(1);
	}
}

void PackageDesc::Init()
{
	if (!root_directory()) root_directory(getenv("OPD_ROOT"));
	if (!root_directory()) root_directory(default_root_directory);
	the_script_dir = Concatenate(root_directory(),"/scripts");
	the_script_directory = Concatenate(script_dir(),"/");
	the_bin_directory = Concatenate(root_directory(),"/bin/");
	
	istream * read_system = get_file(script_dir(),system_file_name());
	if (read_system) {
		const buf_size = 256 ;
		char buf[buf_size] ;
		read_system->get(buf,buf_size-1);
		int num = read_system->gcount();
		buf[num] = '\0' ;
		system_suffix(Concatenate(buf));
		delete read_system ;
		read_system = 0 ;
	}
	CheckLibDirsAreCDirs();
	CDirs->Init();
	HDirs->Init();
	UsrDirs->Init();
}

void PackageDesc::FindFiles()
{
	CDirs->FindFiles();
	HDirs->FindFiles();
	UsrDirs->FindFiles();
	CheckInclude();
}

void PackageDesc::CheckInclude()
{
	if (!GetMenuFlag()) return ;
	if (GetMenuFlag()) if (!strcmp("l",GetMenuFlag())) return ;
	// Make sure all UsrDirs are also Cdirs and Hdirs
	for (int i = 0 ; i < UsrDirs->Size(); i++) {
		const char * ThisDir = UsrDirs->GetDirName(i);
		if (!CDirs->Included(ThisDir)) cerr <<
			"Warning `.usr' directory (" << ThisDir << 
			") is not a `.cxx' directory.\n";
		if (!HDirs->Included(ThisDir)) cerr <<
			"Warning `.usr' directory (" << ThisDir << 
			") is not a `.h' directory.\n";
	}
}


void PackageDesc::WriteMakes() {
	CDirs->WriteMake(this);
}
int PackageDesc::GetNumHDirs()
{
	return HDirs->Size() ;
}

const char * PackageDesc::GetHFile(int i)
{
	return AllHeaders[i]->GetName() ;
}

void PackageDesc::AddUserObjects()
{
	// CDirs->AddUserObjects(UsrDirs);
}

const char * PackageDesc::GetNoCollName(int i) const
{
	// cout << "GetMenuName(" << i << ")\n" ;
	if (i >= TotalNoCollect) return 0;
	// cout << "Returning `" << MenuNames[i] << "'\n" ;
	return NoCollNames[i] ;
}

const char * PackageDesc::GetMenuName(int i) 
{
	// cout << "GetMenuName(" << i << ")\n" ;
	if (i >= TotalMenuNames) return 0;
	// cout << "Returning `" << MenuNames[i] << "'\n" ;
	return MenuNames[i] ;
}

void PackageDesc::AddNoCollectName(const char * Name)
{
	int i = 0;
	for (const char ** Ptr = NoCollNames; *Ptr; Ptr++) {
		i++ ;
		if (!strcmp(*Ptr,Name)) {
			cerr << "Warning no collect entry `" << Name <<
				"' occurs more than once.\n" ;
			cerr << "The second occurence will be ignored.\n" ;
			TotalNoCollect--;
			return ;
		}
	}
	if (i >= TotalNoCollect) {
		cerr << "Internal menu count error.\n" ;
		exit(10);
	}
	NoCollNames[i] = Name ;
}
void PackageDesc::AddMenuName(const char * Name)
{
	int i = 0;
	for (const char ** Ptr = MenuNames; *Ptr; Ptr++) {
		i++ ;
		if (!strcmp(*Ptr,Name)) {
			cerr << "Warning menu entry `" << Name <<
				"' occurs more than once.\n" ;
			cerr << "The second occurence will be ignored.\n" ;
			TotalMenuNames--;
			return ;
		}
	}
	if (i >= TotalMenuNames) {
		cerr << "Internal menu count error.\n" ;
		exit(10);
	}
	MenuNames[i] = Name ;
}

const char * PackageDesc::GetMainDir()
{
	return CDirs->GetDirName(0);
}

int PackageDesc::IsSubDir() const
{
	return CDirs->GetSubDir() ? 1 : 0 ;
}

const char * PackageDesc::GetSubDir() const
{
	const char * Return = CDirs->GetSubDir();
	if (!Return) Return = "" ;
	return Return ;
}

int PackageDesc::IsUsrDir(const char * Name)
{
	return UsrDirs->IsMember(Name);
}

const char * PackageDesc::MakeLibName(const char * DirName)
{
	const char * move = moveable_lib_name(DirName);
    if (move) return move ;
	char * UpTailDirName = 0 ;
    const char * TailDirName = IsUpLibraryName() ?
            (UpTailDirName = TailUpName(DirName)):TailName(DirName);

	const NameBufSize = 128 ;
	static char NameBuf[NameBufSize];

    const char * CollPre = "LibColl" ;
    const int MaxAdd = strlen(CollPre);
    if (strlen(TailDirName) + MaxAdd >= NameBufSize) {
        cerr << "TailDirName too long `" << TailDirName << "'\n" ;
        exit(1);
    }
 	strcpy (NameBuf,"Lib");
    strcat (NameBuf,TailDirName);
    strcat (NameBuf,LibSuffix);
    delete UpTailDirName ;
    return NameBuf ;
}


void PackageDesc::OutLibrarys(OutTokens& ListOut)
{
	const char ** Entry ;
	if (LibList) for (Entry = LibList; *Entry; Entry++)
		ListOut.NextOut(*Entry);
	if (LibDirList) for (Entry = LibDirList; *Entry; Entry++) {
		ListOut.NextConcatToken(*Entry);
		if (IsSubDir()) {
			ListOut.NextConcatToken("/");
			ListOut.NextConcatToken(GetSubDir());
		}
		ListOut.NextConcatToken("/");
		ListOut.NextOutToken(MakeLibName(*Entry));
	}
	if (LibUpDirList) for (Entry = LibUpDirList; *Entry; Entry++) {
		ListOut.NextConcatToken(*Entry);
		if (IsSubDir()) {
			ListOut.NextConcatToken("/");
			ListOut.NextConcatToken(GetSubDir());
		}
		ListOut.NextConcatToken("/");
		ListOut.NextOutToken(MakeLibName(*Entry));
	}
}


/* 
 * void DisplayListOfLists(const char *** Lst)
 * {
 *	if (!Lst) return ;
 *	for (const char *** Ent = Lst ; *Ent; Ent++) {
 *		cerr << **Ent <<"\n" ;
 *		for (const char ** Et = *Ent + 1 ; *Et ; Et++)
 *			cerr << "\t" << *Et << "\n" ;
 *	}
 * }
 */


void PackageDesc::AddMakeDirList(const char ** Names)
{
	const char *** Input = new const char **[2] ;
	Input[0] = Names ;
	Input[1] = 0 ;
	MakeDirList = (const char ***) AddListToListOfLists ((const void **) Names,
		(void ***const) MakeDirList) ;
}

void PackageDesc::AddLibDirList(const char ** Names)
{
	const char *** Input = new const char **[2] ;
	Input[0] = Names ;
	Input[1] = 0 ;
/*
 *	DisplayListOfLists(Input);
 *	cerr << "___\n" ;
 *	DisplayListOfLists(LibCollDirList);
 */
	LibCollDirList = (const char ***) AddListToListOfLists ((const void **) Names,
		(void *** const) LibCollDirList) ;
	// DisplayListOfLists(LibCollDirList);
}

const char ** PackageDesc::GetLinkDirectoryList (const char * Master) const
{
	if (!LibCollDirList) return 0 ;
	for (const char *** OneList = LibCollDirList;  *OneList; OneList++)
		if (!strcmp(Master,**OneList)) return *OneList ;
	return 0 ;
}

void PackageDesc::AddSourceDirectories(ostream& DirListOut, GetBits& Bits,
	const char * DirName) const 
{
	int Index = CDirs->GetMemberIndex(DirName);
	const DirContents* dir ;
	if (Index < 0) goto ErrorQuit ;
	dir = CDirs->GetDirEntry(Index);
	if (!dir) goto ErrorQuit ;
	if (!dir->GetHeaderBits()) goto ErrorQuit;
	Bits |= *(dir->GetHeaderBits());
	Index = HDirs->GetMemberIndex(DirName);
/*
 *	if (Index > -1) cerr << "HDir directory = " <<
 *		HDirs->GetDirName(Index) << "\n" ;
 *	else cerr << "Not an H directory\n" ;
 */
	if (Index > -1) Bits.SetBit(Index);
	else {
		DirListOut << DirName << "\n" ;
		if (GetSubDir()) DirListOut << DirName << "/" << GetSubDir()
			<< "\n" ;
	}
	return ;
ErrorQuit:
	cerr << "PackageDesc::EmitLinkDirectories::bad dir\n" ;
	exit(1);
}

void PackageDesc::EmitLinkDirectories(ostream& DirListOut,
	const char * DirName,const GetBits& bits) const
{
	GetBits AllDirectoryBits(bits);
	if (LibCollDirList)
	    for (const char *** OneList = LibCollDirList; *OneList; OneList++)
		if (!strcmp(DirName,**OneList)) 
			for (const char ** OneMem = *OneList+1;*OneMem;OneMem++) {
			// cerr << "*OneMem = " << *OneMem << "\n" ;
			AddSourceDirectories(DirListOut,AllDirectoryBits,					*OneMem);
	}
	WriteSourceDirectories(DirListOut,AllDirectoryBits);
	return ;
}

int PackageDesc::InCollectedLib(const char * dir) const
{
	if (!LibCollDirList) return 0 ;
	for (const char *** OneList = LibCollDirList; *OneList; OneList++)
		for (const char ** OneMem = *OneList +1; *OneMem; OneMem++) {
			// cerr << dir << "::" << *OneMem << "\n" ;
			if (!strcmp(dir,*OneMem)) return 1 ;
		}
	// cerr << "return 0\n" ;
	return 0 ;
}

void PackageDesc::EmitCollectLibDirectories(OutTokens& ListOut)
{
	if (!LibCollDirList) return ;
	const char * LibPrefix = "Lib" ;
	char * Sub ;
	const char * SubDir = GetSubDir() ;
	if (SubDir) if (!strlen(SubDir)) SubDir = 0 ;
	if (SubDir) Sub = Concatenate("/", SubDir,"/",LibPrefix);
	else Sub = Concatenate("/",LibPrefix);
	int ExtraSize = strlen(LibPrefix) + strlen(Sub) + 1 ;
	for (const char *** OneList = LibCollDirList; *OneList; OneList++) {
		char * TailName = OpdRemoveDirectory(**OneList);
		ListOut.NextConcatToken(**OneList);
		ListOut.NextConcatToken(Sub);
		ListOut.NextConcatToken(TailName);
		ListOut.NextOutToken(LibSuffix);
		delete TailName ;
	}
	delete Sub ;
}


void PackageDesc::BadLibraryDirectory(const char *Dir)
{
	cerr << "Error: Library directory `" << Dir << "'\n" ;
	cerr << "is not a `C' Directory.\n" ;
	cerr << "Can only make librarys in `C' directories.\n" ;
	cerr <<"(There do not need to be any `C' files in a `C' directory.)\n";
	exit(1);
}

 void LibDirMessage(const char * Dir)
{
	cerr << "Error: Directory `" << Dir <<"'\n" ;
	cerr << "is used as both a library directory (-l) and a\n" ;
	cerr << "collected library directory (first argument of -libcolldirlst).\n" ;
}

void PackageDesc::CheckLibDirsAreCDirs()
{
	if (!LibCollDirList) return ;
	int ExitIfLibDir = 0 ;
	for (const char *** Coll = LibCollDirList; *Coll; Coll++) {
		for (int j = 0 ; j < CDirs->Size(); j++)
			if (!strcmp(**Coll,CDirs->GetDirName(j))) {
				// cerr << "Found dir `" << **Coll << "'\n" ;
				if (CDirs->GetDirEntry(j)->IsLibrary()) {
					ExitIfLibDir = 1 ;
					LibDirMessage(**Coll);
				}
				CDirs->MakeSureDependentCdirsAreFirst(j,
					(*Coll)+1);
				break ;
			}
		if (j < CDirs->Size()) continue ;
		BadLibraryDirectory(**Coll);
	}
	if (ExitIfLibDir) exit(1);
}

void PackageDesc::AddObjsFromDirectories(ostream * MakeOut,
	const char ** DirectoriesToLink, int& line_use)
{
	if (DirectoriesToLink)
	for (const char ** Dir = DirectoriesToLink ; *Dir ; Dir++) {
		for (int j = 0 ; j < CDirs->Size(); j++) { 
			if (!strcmp(*Dir,CDirs->GetDirName(j))) {
				CDirs->GetDirEntry(j)->
					EmitObjs(*MakeOut,line_use,
						CDirs->GetSubDir());
				break ;
			}
		}
		if (j < CDirs->Size()) continue ;
		if (Dir == DirectoriesToLink) BadLibraryDirectory(*Dir) ;
		cerr << "Warning directory `" << *Dir << "'\n" ;
		cerr << "is not a C++ source directory.\n" ;
		cerr << "No object files collected from it.\n" ;
	}
}

void PackageDesc::WriteSourceDirectories(ostream& Out,GetBits& TheBits) const
{
	int BitNo ;
	while ((BitNo = TheBits.NextBit())> -1) {
		Out << HDirs->GetDirName(BitNo) << "\n" ;
		if (GetSubDir()) Out << HDirs->GetDirName(BitNo) << "/" <<
			GetSubDir() << "\n" ;
	}
}

void PackageDesc::WriteSourceListings()
{
	CDirs->WriteSourceDirectoryList(this);
	if (!IsdbXtra()) return ;
	int TotalLength = ListLength((const void **)LibList);
	TotalLength += ListLength((const void **)LibDirList);
	TotalLength += ListLength((const void **)LibUpDirList);
	const char ** AllLibDirNames = new const char * [TotalLength+1] ;
	*AllLibDirNames = 0 ;
	const char ** NextAdd = AllLibDirNames ;
	const char ** OneDir ;
	if (LibList) for (OneDir = LibList ; *OneDir ; OneDir++) {
		cerr << "LibList::" << *OneDir << "\n" ;
		char * DirName = FindDirectory(*OneDir);
		cerr << "DirName = " << DirName << "\n" ;
		if (!DirName) continue ;
		if (InList(DirName,NoSourceNoWarnList)) {
			// delete DirName ;
			continue ;
		}
		cerr << "Added " << DirName << "\n" ;
		*NextAdd++ = DirName ;
	}
	if (LibDirList) for (OneDir = LibDirList ; *OneDir ; OneDir++) {
		if (InList(*OneDir,NoSourceNoWarnList)) continue ;
		*NextAdd++ = *OneDir ;
	}
	if (LibUpDirList) for (OneDir = LibUpDirList ; *OneDir ; OneDir++) {
		const char *DirName = Concatenate(*OneDir,"/",GetSubDir());
		if (InList(DirName,NoSourceNoWarnList)) {
			// delete DirName ;
			continue ;
		}
		*NextAdd++ = DirName ;
	}
	*NextAdd++ = 0 ;

	// Collect All directory names
	int LibCount = ListLength((const void **)AllLibDirNames);
	const char *** AllDirs = new const char ** [LibCount+1];
	*AllDirs = 0 ;
	for (OneDir = AllLibDirNames; *OneDir; OneDir++) {
		char * FileName = Concatenate(*OneDir, "/", DirListFileName);
		const char ** TheDirs = FileToList(FileName);
		delete FileName ;
		if (!TheDirs) {
			cerr << "Warning: no source file list `" <<
				DirListFileName <<"' in directory \n`" <<
				*OneDir << "'.\n" ;
			continue ;
		}
		AllDirs = (const char ***)
			AddListToListOfLists((const void**) TheDirs,
				(void ***) AllDirs);
	}

	int Factor = 1 ;
	if (GetSubDir()) Factor = 2 ;
	int TotalDirs = Factor * (CDirs->Size() + HDirs->Size()) + 1 ;
	for (const char *** OneList = AllDirs ; *OneList ; OneList++)
		for (OneDir = *OneList; *OneDir; OneDir++)
			TotalDirs += ListLength((const void **)*OneDir);
	const char ** AllTheDirs = new const char * [TotalDirs];
	*AllTheDirs = 0 ;
	NextAdd = AllTheDirs ;

	for (int i = 0 ; i < CDirs->Size() ; i++) {
		const char * DirName = CDirs->GetDirName(i);
		if (InList(DirName,NoSourceNoWarnList)) continue ;
		*NextAdd++ = DirName ;
		if (GetSubDir()) {
			const char * SubDirName = Concatenate(DirName,"/",
				GetSubDir()) ;
			*NextAdd++ = SubDirName ;
		}
	}

	for (i = 0 ; i < HDirs->Size() ; i++) {
		const char * DirName = HDirs->GetDirName(i);
		if (InList(DirName,NoSourceNoWarnList)) continue ;
		*NextAdd++ = DirName ;
		if (GetSubDir()) {
			const char * SubDirName = Concatenate(DirName,"/",
				GetSubDir()) ;
			*NextAdd++ = SubDirName ;
		}
	}
	for (OneList = AllDirs ; *OneList ; OneList++)
		for (OneDir = *OneList; *OneDir; OneDir++)
			*NextAdd++ = *OneDir ;
	*NextAdd++ = 0 ;
	StringSort(AllTheDirs);
	const char *MainDir = CDirs->GetDirName(0);
	if (IsSubDir()) MainDir = Concatenate(MainDir,"/",GetSubDir());
	char * TheDir = Concatenate(MainDir,"/","dbxtra.cmd");
	const char * PreviousDir = " " ;

	ofstream FileOut(TheDir);
	const char * Obj ;
	if (!FileOut.good()) {
		cerr << "Error: cannot create dbXtra command file:\n`" <<
			TheDir << "'\n" ;
		// goto TheExit;
		return ;
	}	
	FileOut << "dbXtra " ;
	for (OneDir = AllTheDirs; *OneDir; OneDir++) {
		if (!strcmp(PreviousDir,*OneDir)) continue;
		PreviousDir = *OneDir ;
		FileOut << "-I" << *OneDir << " \\\n" ;
	}
	Obj = GetObject();
	if (*Obj == '/') FileOut << " " << Obj << "\n" ;
	else FileOut << MainDir << "/" << Obj ;
		
/*
 * TheExit:
 *	delete (void *) TheDir ;
 *	delete (void *) AllDirs ;
 *	delete (void *) AllTheDirs ;
 */
}

const char * PackageDesc::moveable_lib_name(const char * name) const 
{
	MakeableLibListIterator Next(the_moveable_libs);
	MakeableLib * lb ;
	while (lb = Next()) if (!strcmp(name,lb->directory)) return lb->name ;
	return 0 ;
}

istream * PackageDesc::get_file(const char * dir, const char * base,
	const char * suffix, char ** nm)
{
	char * name = 0 ;
	if (!suffix && (base[strlen(base)-1] == '/')) return 0 ;
	if (suffix)  name = Concatenate(dir,"/",base,".",suffix);
	else name = Concatenate(dir,"/",base);
	// cerr << "Checking for `" << name << "'" ;
#ifdef __NT_VC__
	istream * str = new ifstream(name,ios::nocreate);
#else
	istream * str = new ifstream(name);
#endif
	if (!str->good()) {
		// cerr << " -- not found\n" ;
		delete str ;
		delete name ;
		return 0 ;
	}
	if (nm) *nm = name ;
	else delete name ;
	// cerr << " -- found\n" ;
	return str ;
}

