- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
408 lines
15 KiB
C++
408 lines
15 KiB
C++
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* XREF.CPP */
|
|
/* */
|
|
/* Copyright (c) 1993 Borland International */
|
|
/* All Rights Reserved. */
|
|
/* */
|
|
/* Text cross referencing example */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Containers Used: TBinarySearchTreeImp, TIBinarySearchTreeImp, */
|
|
/* TSVectorImp. */
|
|
/* Other Classes: string. */
|
|
/* */
|
|
/* Data files provided: trivial.dat and text.dat. */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
#include <classlib\binimp.h>
|
|
#include <classlib\vectimp.h>
|
|
#include <cstring.h>
|
|
#include <regexp.h>
|
|
#include <fstream.h>
|
|
#include <strstrea.h>
|
|
#include <iomanip.h>
|
|
#include <dir.h>
|
|
|
|
// MaxRefs is the maximum number of references that a word can have
|
|
// before it is rejected (not put into the cross reference table).
|
|
//
|
|
const unsigned MaxRefs = 6;
|
|
|
|
// Indicates the minimum length a word must have to be a candidate to be
|
|
// put into the cross reference table.
|
|
//
|
|
const unsigned MinWordLength = 3;
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TRecord */
|
|
/* */
|
|
/* Keeps track of the lines that a word appears on. */
|
|
/* */
|
|
/* Public Interface: */
|
|
/* */
|
|
/* TRecord( string word, unsigned lineNum ); */
|
|
/* */
|
|
/* Creates record with given word and line number. */
|
|
/* */
|
|
/* int operator == ( const TRecord& record ) const; */
|
|
/* */
|
|
/* Returns 1 if the Words compare equal, 0 otherwise. */
|
|
/* */
|
|
/* int operator < ( const TRecord& record ) const; */
|
|
/* */
|
|
/* Returns 1 if the Word in this record is lexically before the */
|
|
/* Word in the record parameter. */
|
|
/* */
|
|
/* int AddLineRef( unsigned lineNum ); */
|
|
/* */
|
|
/* Add given page number to word's list of line references. If */
|
|
/* the number of references >= 'MaxRefs' then return 0 and */
|
|
/* do not enter given line number in line ref list, else */
|
|
/* return 1 */
|
|
/* */
|
|
/* string GetWord() const; */
|
|
/* */
|
|
/* Return copy of 'Word' member. */
|
|
/* */
|
|
/* Global functions: */
|
|
/* */
|
|
/* ostream& operator << ( ostream&, const TRecord& ); */
|
|
/* */
|
|
/* Writes the record to the ostream. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class TRecord
|
|
{
|
|
|
|
public:
|
|
|
|
TRecord( const string& word, unsigned lineNum );
|
|
|
|
int operator == ( const TRecord& record ) const;
|
|
int operator < ( const TRecord& record ) const;
|
|
int AddLineRef( unsigned lineNum );
|
|
string GetWord() const;
|
|
unsigned GetPageCount() const;
|
|
friend ostream& operator << ( ostream&, const TRecord& );
|
|
|
|
private:
|
|
|
|
string Word;
|
|
TSVectorImp<unsigned> LineRef;
|
|
|
|
};
|
|
|
|
TRecord::TRecord( const string& word, unsigned lineNum ) :
|
|
Word( word ),
|
|
LineRef(MaxRefs)
|
|
{
|
|
AddLineRef(lineNum);
|
|
}
|
|
|
|
inline int TRecord::operator == ( const TRecord& record ) const
|
|
{
|
|
return Word == record.Word;
|
|
}
|
|
|
|
inline int TRecord::operator < ( const TRecord& record ) const
|
|
{
|
|
return Word < record.Word;
|
|
}
|
|
|
|
int TRecord::AddLineRef( unsigned lineNum )
|
|
{
|
|
if( LineRef.Count() < MaxRefs )
|
|
{
|
|
if( LineRef.Find( lineNum ) == UINT_MAX )
|
|
LineRef.Add( lineNum );
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
string TRecord::GetWord() const
|
|
{
|
|
return Word;
|
|
}
|
|
|
|
unsigned TRecord::GetPageCount() const
|
|
{
|
|
return LineRef.Count();
|
|
}
|
|
|
|
ostream& operator << ( ostream& os, const TRecord& rec )
|
|
{
|
|
char buf[80];
|
|
ostrstream temp( buf, sizeof(buf) );
|
|
temp.setf( ios::left );
|
|
|
|
temp << setw(20) << rec.Word;
|
|
|
|
for( unsigned i = 0; i < rec.LineRef.Count()-1; i++ )
|
|
{
|
|
temp << rec.LineRef[i] << ','; // write all but last line number
|
|
} // followed by a comma
|
|
temp << rec.LineRef[i] << ends; // write last line number
|
|
|
|
os << buf;
|
|
return os;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TCrossRef */
|
|
/* */
|
|
/* Responsible for reading a trivial word file and text file, */
|
|
/* then creating and printing a cross reference list of the words */
|
|
/* in the text file. The trivial word file contains words that will */
|
|
/* not be included in the cross reference. The text file consists */
|
|
/* of ordinary ASCII text. The ouput is an alphabetical list of */
|
|
/* words in the text file and the numbers of the lines on which they */
|
|
/* occur. */
|
|
/* */
|
|
/* Public Interface: */
|
|
/* */
|
|
/* TCrossRef( string trivialWordFileName, string textFileName ); */
|
|
/* */
|
|
/* Read trivial word file and store in a binary search tree. */
|
|
/* Then read each word in from the text file and process it. */
|
|
/* If either file cannot be opened or an error occurs during */
|
|
/* reading a TXFileReadError exception is thrown. */
|
|
/* */
|
|
/* ~TCrossRef(); */
|
|
/* */
|
|
/* Flushes the list of words in the cross reference. */
|
|
/* */
|
|
/* PrintCrossReferences( ostream& ); */
|
|
/* */
|
|
/* Print each word and the lines it appears on in the text file. */
|
|
/* */
|
|
/* Nested class TXFileReadError. */
|
|
/* */
|
|
/* An object of type TXFileReadError is thrown if either the */
|
|
/* trivial word or cross reference file could not be opened or */
|
|
/* read. To find out which file it was use the WhichFile() */
|
|
/* member function. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class TCrossRef
|
|
{
|
|
|
|
public:
|
|
|
|
class TXFileReadError : public xmsg
|
|
{
|
|
public:
|
|
TXFileReadError( const string& file )
|
|
: xmsg( string( "Error reading file: " ) + file ), File(file) {}
|
|
|
|
string WhichFile() const;
|
|
|
|
private:
|
|
string File;
|
|
};
|
|
|
|
TCrossRef( string trivialWordFileName, string textFileName );
|
|
~TCrossRef();
|
|
|
|
void PrintCrossReferences( ostream& );
|
|
|
|
private:
|
|
|
|
void ReadTrivialWords( string trivialWordFileName );
|
|
void ReadWords( string bookWordFileName );
|
|
void ProcessWord( string word, unsigned page );
|
|
|
|
static void PrintRecord( TRecord _BIDSFAR &o, void _BIDSFAR*arg );
|
|
void Reject( string word, string reason );
|
|
|
|
TBinarySearchTreeImp<string> RejectedWords;
|
|
TIBinarySearchTreeImp<TRecord> IndexOfWords;
|
|
unsigned CurrentPage;
|
|
|
|
};
|
|
|
|
//
|
|
// Construct a TCrossRef object, reading words from the file
|
|
// specified by trivialWordFileName into the tree of rejected
|
|
// words, then reading the text from the file specified by
|
|
// testFileName and building the cross reference tree.
|
|
//
|
|
TCrossRef::TCrossRef( string trivialWordFileName, string textFileName ) :
|
|
CurrentPage(1)
|
|
{
|
|
ReadTrivialWords( trivialWordFileName );
|
|
ReadWords( textFileName );
|
|
}
|
|
|
|
//
|
|
// Clean up.
|
|
//
|
|
TCrossRef::~TCrossRef()
|
|
{
|
|
IndexOfWords.Flush(1);
|
|
}
|
|
|
|
//
|
|
// Read trivial words from the specified file, convert them
|
|
// to lower case, and store them in the rejected words tree.
|
|
//
|
|
void TCrossRef::ReadTrivialWords( string trivialWordFileName )
|
|
{
|
|
ifstream TrivialWordFile( trivialWordFileName.c_str() );
|
|
if( !TrivialWordFile )
|
|
throw TXFileReadError( trivialWordFileName );
|
|
|
|
string wordFromFile;
|
|
|
|
while( TrivialWordFile >> wordFromFile )
|
|
{
|
|
wordFromFile.to_lower();
|
|
RejectedWords.Add( wordFromFile );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read words from the specified file and insert them into
|
|
// the cross reference tree. Along the way, convert to lower
|
|
// case and strip out any non-text characters and all text
|
|
// following any such characters within a word. (Quick and
|
|
// dirty hack for dealing with possessives, etc.)
|
|
//
|
|
void TCrossRef::ReadWords( string textFileName )
|
|
{
|
|
ifstream XrefFile( textFileName.c_str() );
|
|
|
|
if( !XrefFile )
|
|
throw TXFileReadError( textFileName );
|
|
|
|
TRegexp WordOnly( "[a-z]+" );
|
|
unsigned currentLine = 1;
|
|
while( XrefFile )
|
|
{
|
|
char buf[128];
|
|
XrefFile.getline( buf, sizeof(buf) );
|
|
if( XrefFile )
|
|
{
|
|
string word;
|
|
istrstream in( buf );
|
|
while( in )
|
|
{
|
|
in >> word;
|
|
if( in )
|
|
{
|
|
word.to_lower(); // store as lower case
|
|
|
|
// use WordOnly as filter to strip out trailing
|
|
// non-text characters and any characters following.
|
|
ProcessWord( word(WordOnly), currentLine );
|
|
}
|
|
}
|
|
currentLine++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out whether a word should be added to the cross
|
|
// reference tree. If not, explain. If so, add it.
|
|
//
|
|
void TCrossRef::ProcessWord( string word, unsigned lineNum )
|
|
{
|
|
|
|
if( RejectedWords.Find( word ) != 0 )
|
|
Reject( word, "found in rejected word file" );
|
|
else if( word.length() < MinWordLength )
|
|
Reject( word, "too short" );
|
|
else
|
|
{
|
|
TRecord *recordToUpdate = IndexOfWords.Find( &TRecord(word,lineNum) );
|
|
if( recordToUpdate == 0 )
|
|
{
|
|
// The word isn't in the tree yet. Add a
|
|
// new record to contain it.
|
|
IndexOfWords.Add( new TRecord(word,lineNum) );
|
|
}
|
|
else if( recordToUpdate->GetPageCount() >= MaxRefs )
|
|
{
|
|
Reject( word, "reference count too large" );
|
|
IndexOfWords.Detach( recordToUpdate, 1 );
|
|
}
|
|
else
|
|
{
|
|
// The word is already in the tree. Add the
|
|
// additional line reference.
|
|
recordToUpdate->AddLineRef( lineNum );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Callback for ForEach() to print a record to the stream
|
|
// pointed to by 'arg'.
|
|
//
|
|
void TCrossRef::PrintRecord( TRecord &o, void *arg )
|
|
{
|
|
(*(ostream*)arg) << o << endl;
|
|
}
|
|
|
|
//
|
|
// Print the cross references to the specified stream.
|
|
//
|
|
void TCrossRef::PrintCrossReferences( ostream& os )
|
|
{
|
|
os << "References:\n\n";
|
|
os.setf( ios::left, ios::adjustfield );
|
|
IndexOfWords.ForEach( PrintRecord, &os );
|
|
}
|
|
|
|
//
|
|
// Process rejected words by adding the word to the
|
|
// rejected words list and printing a message indicating
|
|
// why the word was rejected.
|
|
//
|
|
void TCrossRef::Reject( string word, string reason )
|
|
{
|
|
RejectedWords.Add( word );
|
|
cerr << '\'' << word << "' rejected, " << reason << endl;
|
|
}
|
|
|
|
string TCrossRef::TXFileReadError::WhichFile() const
|
|
{
|
|
return File;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
int main()
|
|
{
|
|
try
|
|
{
|
|
string TrivialWordFile;
|
|
string XrefFile;
|
|
|
|
cerr << "Enter name of trivial word file: ";
|
|
cin >> TrivialWordFile;
|
|
|
|
cerr << "Enter name of file to cross reference: ";
|
|
cin >> XrefFile;
|
|
|
|
TCrossRef CrossRef( TrivialWordFile, XrefFile );
|
|
CrossRef.PrintCrossReferences( cout );
|
|
|
|
}
|
|
catch( const TCrossRef::TXFileReadError& xReadError )
|
|
{
|
|
cout << xReadError.why() << endl;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|