source410: literal 4.10 source reconstruction + BC++ 4.52 fleet toolchain archived
- 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>
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BINIMP.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( CLASSLIB_BINIMP_H )
|
||||
#include <classlib/binimp.h>
|
||||
#endif
|
||||
|
||||
TBinarySearchTreeBase::TBinarySearchTreeBase() :
|
||||
Root(0),
|
||||
ItemsInContainer(0)
|
||||
{
|
||||
}
|
||||
|
||||
int TBinarySearchTreeBase::InsertNode( BinNode *node )
|
||||
{
|
||||
BinNode *Current = Root;
|
||||
BinNode *Parent = 0;
|
||||
while( Current )
|
||||
{
|
||||
Parent = Current;
|
||||
Current = LessThan( node, Current ) ? Current->Left : Current->Right;
|
||||
}
|
||||
if( Parent == 0 )
|
||||
Root = node;
|
||||
else
|
||||
{
|
||||
if( LessThan( node, Parent ) )
|
||||
Parent->Left = node;
|
||||
else
|
||||
Parent->Right = node;
|
||||
}
|
||||
ItemsInContainer++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TBinarySearchTreeBase::RemoveNode( BinNode *node, int del )
|
||||
{
|
||||
BinNode *Current = Root;
|
||||
BinNode *Parent = 0;
|
||||
while( Current )
|
||||
{
|
||||
if( EqualTo( node, Current ) )
|
||||
return RemNode( Current, Parent, del );
|
||||
else
|
||||
{
|
||||
Parent = Current;
|
||||
Current = LessThan( node, Current ) ? Current->Left :
|
||||
Current->Right;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TBinarySearchTreeBase::BinNode *TBinarySearchTreeBase::FindNode( BinNode *node )
|
||||
{
|
||||
BinNode *Current = Root;
|
||||
while( Current )
|
||||
{
|
||||
if( EqualTo( node, Current ) )
|
||||
return Current;
|
||||
else
|
||||
Current = LessThan( node, Current ) ? Current->Left :
|
||||
Current->Right;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TBinarySearchTreeBase::RemNode( BinNode *node, BinNode *parent, int del )
|
||||
{
|
||||
// See R. Sedgewick, "Algorithms, 2nd edition",
|
||||
// Addison-Wesley 1988, p.210.
|
||||
BinNode *Original = node;
|
||||
if( Original->Right == 0 )
|
||||
node = node->Left;
|
||||
else if( Original->Right->Left )
|
||||
{
|
||||
BinNode *Current = Original->Right;
|
||||
while( Current->Left->Left )
|
||||
Current = Current->Left;
|
||||
node = Current->Left;
|
||||
Current->Left = node->Right;
|
||||
node->Left = Original->Left;
|
||||
node->Right = Original->Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->Right;
|
||||
node->Left = Original->Left;
|
||||
}
|
||||
if( parent == 0 )
|
||||
Root = node;
|
||||
else if( LessThan( Original, parent ) )
|
||||
parent->Left = node;
|
||||
else
|
||||
parent->Right = node;
|
||||
|
||||
DeleteNode( Original, del );
|
||||
ItemsInContainer--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
class TBinaryTreeKiller : public TBinaryTreeInternalIteratorBase
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
TBinaryTreeKiller( TBinarySearchTreeBase& tree, int del ) :
|
||||
TBinaryTreeInternalIteratorBase( tree, TBinarySearchTreeBase::PostOrder ),
|
||||
Del(del) {}
|
||||
|
||||
private:
|
||||
|
||||
virtual void Apply( TBinarySearchTreeBase::BinNode _FAR *node,
|
||||
TBinarySearchTreeBase::BinNode _FAR *parent );
|
||||
|
||||
int Del;
|
||||
|
||||
TBinaryTreeKiller( const TBinaryTreeKiller& );
|
||||
const TBinaryTreeKiller& operator = ( const TBinaryTreeKiller& );
|
||||
|
||||
};
|
||||
|
||||
void TBinaryTreeKiller::Apply( TBinarySearchTreeBase::BinNode _FAR *node,
|
||||
TBinarySearchTreeBase::BinNode _FAR *parent )
|
||||
{
|
||||
Tree().RemNode( node, parent, Del );
|
||||
}
|
||||
|
||||
void TBinarySearchTreeBase::Flush( int del )
|
||||
{
|
||||
if( Root != 0 )
|
||||
TBinaryTreeKiller( *this, del ).Iterate();
|
||||
}
|
||||
|
||||
void TBinaryTreeInternalIteratorBase::Iterate()
|
||||
{
|
||||
TBinarySearchTreeBase::BinNode _FAR *Current = Node;
|
||||
TBinarySearchTreeBase::BinNode _FAR *Prev = 0;
|
||||
TBinarySearchTreeBase::BinNode _FAR *Next = 0;
|
||||
step2:
|
||||
if( Order == TBinarySearchTreeBase::PreOrder )
|
||||
Apply( Current, 0 );
|
||||
Next = Current->Left;
|
||||
if( Next != 0 )
|
||||
{
|
||||
Current->Left = Prev;
|
||||
Prev = Current;
|
||||
Current = Next;
|
||||
goto step2;
|
||||
}
|
||||
step4:
|
||||
if( Order == TBinarySearchTreeBase::InOrder )
|
||||
Apply( Current, 0 );
|
||||
Next = Current->Right;
|
||||
if( Next != 0 )
|
||||
{
|
||||
Current->Right = Prev;
|
||||
Prev = Current;
|
||||
Current = Next;
|
||||
goto step2;
|
||||
}
|
||||
step6:
|
||||
if( Prev == 0 )
|
||||
{
|
||||
if( Order == TBinarySearchTreeBase::PostOrder )
|
||||
Apply( Current, 0 );
|
||||
return;
|
||||
}
|
||||
if( Tree().LessThan( Current, Prev ) )
|
||||
{
|
||||
TBinarySearchTreeBase::BinNode _FAR *Temp = Current;
|
||||
Next = Prev->Left;
|
||||
Prev->Left = Current;
|
||||
Current = Prev;
|
||||
Prev = Next;
|
||||
if( Order == TBinarySearchTreeBase::PostOrder )
|
||||
Apply( Temp, Current );
|
||||
goto step4;
|
||||
}
|
||||
else
|
||||
{
|
||||
TBinarySearchTreeBase::BinNode _FAR *Temp = Current;
|
||||
Next = Prev->Right;
|
||||
Prev->Right = Current;
|
||||
Current = Prev;
|
||||
Prev = Next;
|
||||
if( Order == TBinarySearchTreeBase::PostOrder )
|
||||
Apply( Temp, Current );
|
||||
goto step6;
|
||||
}
|
||||
}
|
||||
|
||||
TBinaryTreeExternalIteratorBase::TBinaryTreeExternalIteratorBase( TBinarySearchTreeBase& tree, TBinarySearchTreeBase::IteratorOrder order ) :
|
||||
Stack( new TStackAsList<TBinarySearchTreeBase::BinNode _BIDSFAR *> ),
|
||||
Tree(&tree),
|
||||
Current( tree.Root ),
|
||||
Order( order )
|
||||
{
|
||||
Restart();
|
||||
}
|
||||
|
||||
TBinaryTreeExternalIteratorBase::~TBinaryTreeExternalIteratorBase()
|
||||
{
|
||||
delete Stack;
|
||||
}
|
||||
|
||||
void TBinaryTreeExternalIteratorBase::Restart()
|
||||
{
|
||||
Stack->Flush();
|
||||
Current = Tree->Root;
|
||||
LeftVisited = RightVisited = 0;
|
||||
Processed = 0;
|
||||
}
|
||||
|
||||
TBinarySearchTreeBase::BinNode *TBinaryTreeExternalIteratorBase::Next()
|
||||
{
|
||||
if( Current == 0 )
|
||||
return 0;
|
||||
for(;;)
|
||||
{
|
||||
if( Order == TBinarySearchTreeBase::PreOrder && !Processed )
|
||||
{
|
||||
Processed = 1;
|
||||
return Current;
|
||||
}
|
||||
|
||||
if( Current->Left != 0 && !LeftVisited )
|
||||
{
|
||||
Stack->Push( Current );
|
||||
Current = Current->Left;
|
||||
LeftVisited = RightVisited = 0;
|
||||
Processed = 0;
|
||||
}
|
||||
else if( Current->Right != 0 && !RightVisited )
|
||||
{
|
||||
TBinarySearchTreeBase::BinNode *Res = 0;
|
||||
if( Order == TBinarySearchTreeBase::InOrder )
|
||||
Res = Current;
|
||||
Stack->Push( Current );
|
||||
Current = Current->Right;
|
||||
LeftVisited = RightVisited = 0;
|
||||
Processed = 0;
|
||||
if( Res != 0 )
|
||||
return Res;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( Stack->IsEmpty() )
|
||||
{
|
||||
if( Processed == 0 )
|
||||
{
|
||||
Processed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Current = 0;
|
||||
}
|
||||
return Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
TBinarySearchTreeBase::BinNode *Res;
|
||||
switch( Order )
|
||||
{
|
||||
case TBinarySearchTreeBase::PreOrder:
|
||||
// This node has already been
|
||||
// processed, so we have further to go.
|
||||
Res = 0;
|
||||
|
||||
// This node's parent has
|
||||
// already been processed
|
||||
Processed = 1;
|
||||
|
||||
break;
|
||||
|
||||
case TBinarySearchTreeBase::InOrder:
|
||||
if( IsInOrder() )
|
||||
{
|
||||
// This node needs to be processed.
|
||||
Res = Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node has already been processed.
|
||||
Res = 0;
|
||||
}
|
||||
// If we're the right-hand child, our parent
|
||||
// has already been processed.
|
||||
Processed = Stack->Top()->Right == Current;
|
||||
|
||||
break;
|
||||
|
||||
case TBinarySearchTreeBase::PostOrder:
|
||||
// This node needs to be processed.
|
||||
Res = Current;
|
||||
|
||||
// This node's parent has not been processed.
|
||||
Processed = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LeftVisited = 1;
|
||||
RightVisited = Stack->Top()->Right == Current;
|
||||
Current = Stack->Pop();
|
||||
if( Res != 0 )
|
||||
return Res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* CASTABLE.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1992, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( BI_NO_RTTI )
|
||||
#define BI_NO_RTTI
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_OBJSTRM_H )
|
||||
#include <classlib/objstrm.h>
|
||||
#endif
|
||||
|
||||
TStreamableBase::~TStreamableBase()
|
||||
{
|
||||
}
|
||||
|
||||
void *TStreamableBase::FindBase( Type_id ) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* CLASMAIN.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1991, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/* Provides the LibMain() function for the DLL version */
|
||||
/* of the class libraries */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __WINDOWS_H )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__)
|
||||
|
||||
BOOL DllEntryPoint(HINSTANCE /*hInstance*/, DWORD /*flag*/, LPVOID)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern "C" int FAR PASCAL LibMain( HANDLE, WORD, WORD, LPSTR )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,339 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DATE.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __TIME_H )
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __STRING_H )
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CTYPE_H )
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CSTRING_H )
|
||||
#include <cstring.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DATE_H )
|
||||
#include <classlib/date.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* static constants *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
static const unsigned char DaysInMonth[12] =
|
||||
{ 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
static const DayTy FirstDayOfEachMonth[12] =
|
||||
{ 1,32,60,91,121,152,182,213,244,274,305,335 };
|
||||
static const char *MonthNames[12] =
|
||||
{ "January","February","March","April","May","June",
|
||||
"July","August","September","October","November","December" };
|
||||
static const char *UCMonthNames[12] =
|
||||
{ "JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE",
|
||||
"JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER" };
|
||||
static const char *WeekDayNames[7] =
|
||||
{ "Monday","Tuesday","Wednesday",
|
||||
"Thursday","Friday","Saturday","Sunday" };
|
||||
static const char *UCWeekDayNames[7] =
|
||||
{ "MONDAY","TUESDAY","WEDNESDAY",
|
||||
"THURSDAY","FRIDAY","SATURDAY","SUNDAY" };
|
||||
|
||||
static int _BIDSNEARFUNC
|
||||
FindMatch( const char *str, const char**candidates, int icand );
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// constructors
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// Construct a TDate for today's date.
|
||||
TDate::TDate()
|
||||
{
|
||||
long clk = time(0);
|
||||
struct tm _FAR *now = localtime(&clk);
|
||||
Julnum = Jday(now->tm_mon+1, now->tm_mday, now->tm_year+1900);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a TDate with a given day of the year and a given year. The
|
||||
* base date for this computation is Dec. 31 of the previous year. If
|
||||
* year == 0, Construct a TDate with Jan. 1, 1901 as the "day zero".
|
||||
* i.e., TDate(-1) = Dec. 31, 1900 and TDate(1) = Jan. 2, 1901.
|
||||
*/
|
||||
|
||||
TDate::TDate(DayTy day, YearTy year)
|
||||
{
|
||||
if( year )
|
||||
Julnum = Jday( 12, 31, year-1 ) + (JulTy)day;
|
||||
else
|
||||
Julnum = jul1901 + (JulTy)day;
|
||||
}
|
||||
|
||||
// Construct a TDate for the given day, monthName, and year.
|
||||
TDate::TDate( DayTy day, const char _BIDSFAR *monthName, YearTy year )
|
||||
{
|
||||
Julnum = Jday( IndexOfMonth(monthName), day, year );
|
||||
}
|
||||
|
||||
// Construct a TDate for the given day, month, and year.
|
||||
TDate::TDate( DayTy day, MonthTy month, YearTy year )
|
||||
{
|
||||
Julnum = Jday( month, day, year );
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// static member functions
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// Returns a string name for the weekday number.
|
||||
// Monday == 1, ... , Sunday == 7
|
||||
// Return 0 for weekday number out of range
|
||||
const char _BIDSFAR *TDate::DayName( DayTy weekDayNumber )
|
||||
{
|
||||
return AssertWeekDayNumber(weekDayNumber) ? WeekDayNames[weekDayNumber-1] : 0;
|
||||
}
|
||||
|
||||
// Return the number, 1-7, of the day of the week named nameOfDay.
|
||||
// Return 0 if name doesn't match.
|
||||
DayTy TDate::DayOfWeek( const char _BIDSFAR *nameOfDay )
|
||||
{
|
||||
return (DayTy)(FindMatch( nameOfDay, UCWeekDayNames, 7 )+1);
|
||||
}
|
||||
|
||||
// Is a day (1-31) within a given month?
|
||||
int TDate::DayWithinMonth( MonthTy month, DayTy day, YearTy year )
|
||||
{
|
||||
if( day <= 0 || !AssertIndexOfMonth(month) )
|
||||
return 0;
|
||||
unsigned d = DaysInMonth[month-1];
|
||||
if( LeapYear(year) && month == 2 )
|
||||
d++;
|
||||
return day <= d;
|
||||
}
|
||||
|
||||
// How many days are in the given YearTy year?
|
||||
DayTy TDate::DaysInYear( YearTy year )
|
||||
{
|
||||
return LeapYear(year) ? 366 : 365;
|
||||
}
|
||||
|
||||
// Returns the number, 1-12, of the month named nameOfMonth.
|
||||
// Return 0 for no match.
|
||||
MonthTy TDate::IndexOfMonth( const char _BIDSFAR *nameOfMonth )
|
||||
{
|
||||
return (MonthTy)(FindMatch( nameOfMonth, UCMonthNames, 12 )+1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Gregorian calendar date to the corresponding Julian day
|
||||
* number j. Algorithm 199 from Communications of the ACM, Volume 6, No.
|
||||
* 8, (Aug. 1963), p. 444. Gregorian calendar started on Sep. 14, 1752.
|
||||
* This function not valid before that.
|
||||
* Returns 0 if the date is invalid.
|
||||
*/
|
||||
|
||||
JulTy TDate::Jday( MonthTy m, DayTy d, YearTy y )
|
||||
{
|
||||
unsigned long c, ya;
|
||||
if( y <= 99 )
|
||||
y += 1900;
|
||||
if( !DayWithinMonth(m, d, y) )
|
||||
return (JulTy)0;
|
||||
|
||||
if( m > 2 )
|
||||
m -= 3;
|
||||
else
|
||||
{
|
||||
m += 9;
|
||||
y--;
|
||||
}
|
||||
|
||||
c = y / 100;
|
||||
ya = y - 100*c;
|
||||
return ((146097L*c)>>2) + ((1461*ya)>>2) + (153*m + 2)/5 + d + 1721119L;
|
||||
}
|
||||
|
||||
// Algorithm from K & R, "The C Programming Language", 1st ed.
|
||||
int TDate::LeapYear( YearTy year )
|
||||
{
|
||||
return (year&3) == 0 && year%100 != 0 || year % 400 == 0;
|
||||
}
|
||||
|
||||
// Returns a string name for the month number.
|
||||
// Return 0 if invalid month number.
|
||||
const char _BIDSFAR *TDate::MonthName( MonthTy monthNumber )
|
||||
{
|
||||
return AssertIndexOfMonth(monthNumber) ? MonthNames[monthNumber-1] : 0;
|
||||
}
|
||||
|
||||
// Return index of case-insensitive match; -1 if no match.
|
||||
static int _BIDSNEARFUNC FindMatch( const char *str, const char**candidates, int icand )
|
||||
{
|
||||
unsigned len = strlen(str);
|
||||
|
||||
while(icand--)
|
||||
{
|
||||
if( strnicmp(str, candidates[icand], len) == 0)
|
||||
break;
|
||||
}
|
||||
return icand;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* Member functions *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
// Compare function:
|
||||
int TDate::CompareTo( const TDate _BIDSFAR &d ) const
|
||||
{
|
||||
if( Julnum < d.Julnum )
|
||||
return -1;
|
||||
else if( Julnum > d.Julnum )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
DayTy TDate::Day() const
|
||||
{
|
||||
return DayTy(Julnum - Jday( 12, 31, Year()-1 ));
|
||||
}
|
||||
|
||||
// Returns the day of the month of this TDate.
|
||||
DayTy TDate::DayOfMonth() const
|
||||
{
|
||||
MonthTy m; DayTy d; YearTy y;
|
||||
Mdy( m, d, y );
|
||||
return d;
|
||||
}
|
||||
|
||||
// Return the number of the first day of a given month
|
||||
// Return 0 if "month" is outside of the range 1 through 12, inclusive.
|
||||
DayTy TDate::FirstDayOfMonth( MonthTy month ) const
|
||||
{
|
||||
if ( !AssertIndexOfMonth(month) )
|
||||
return 0;
|
||||
unsigned firstDay = FirstDayOfEachMonth[month-1];
|
||||
if (month > 2 && Leap())
|
||||
firstDay++;
|
||||
return firstDay;
|
||||
}
|
||||
|
||||
unsigned TDate::Hash() const
|
||||
{
|
||||
return (unsigned)Julnum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Julian day number to its corresponding Gregorian calendar
|
||||
* date. Algorithm 199 from Communications of the ACM, Volume 6, No. 8,
|
||||
* (Aug. 1963), p. 444. Gregorian calendar started on Sep. 14, 1752.
|
||||
* This function not valid before that.
|
||||
*/
|
||||
|
||||
void _BIDSNEARFUNC TDate::Mdy( MonthTy _BIDSFAR & m, DayTy _BIDSFAR & D, YearTy _BIDSFAR & y ) const
|
||||
{
|
||||
unsigned long d;
|
||||
JulTy j = Julnum - 1721119L;
|
||||
y = (YearTy) (((j<<2) - 1) / 146097L);
|
||||
j = (j<<2) - 1 - 146097L*y;
|
||||
d = (j>>2);
|
||||
j = ((d<<2) + 3) / 1461;
|
||||
d = (d<<2) + 3 - 1461*j;
|
||||
d = (d + 4)>>2;
|
||||
m = (MonthTy)(5*d - 3)/153;
|
||||
d = 5*d - 3 - 153*m;
|
||||
D = (DayTy)((d + 5)/5);
|
||||
y = (YearTy)(100*y + j);
|
||||
|
||||
if( m < 10 )
|
||||
m += 3;
|
||||
else
|
||||
{
|
||||
m -= 9;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
TDate TDate::Max( const TDate _BIDSFAR & dt ) const
|
||||
{
|
||||
return dt.Julnum > Julnum ? dt : *this;
|
||||
}
|
||||
|
||||
TDate TDate::Min( const TDate _BIDSFAR & dt ) const
|
||||
{
|
||||
return dt.Julnum < Julnum ? dt : *this;
|
||||
}
|
||||
|
||||
// Returns the month of this TDate.
|
||||
MonthTy TDate::Month() const
|
||||
{
|
||||
MonthTy m; DayTy d; YearTy y;
|
||||
Mdy(m, d, y);
|
||||
return m;
|
||||
}
|
||||
|
||||
TDate TDate::Previous( const char _BIDSFAR *dayName) const
|
||||
{
|
||||
return Previous( DayOfWeek(dayName) );
|
||||
}
|
||||
|
||||
TDate TDate::Previous( DayTy desiredDayOfWeek ) const
|
||||
{
|
||||
// Renumber the desired and current day of week to start at 0 (Monday)
|
||||
// and end at 6 (Sunday).
|
||||
|
||||
desiredDayOfWeek--;
|
||||
DayTy thisDayOfWeek = WeekDay() - 1;
|
||||
JulTy j = Julnum;
|
||||
|
||||
// Have to determine how many days difference from current day back to
|
||||
// desired, if any. Special calculation under the 'if' statement to
|
||||
// effect the wraparound counting from Monday (0) back to Sunday (6).
|
||||
|
||||
if( desiredDayOfWeek > thisDayOfWeek )
|
||||
thisDayOfWeek += 7 - desiredDayOfWeek;
|
||||
else
|
||||
thisDayOfWeek -= desiredDayOfWeek;
|
||||
j -= thisDayOfWeek; // Adjust j to set it at the desired day of week.
|
||||
return TDate(j);
|
||||
}
|
||||
|
||||
DayTy TDate::WeekDay() const
|
||||
{
|
||||
return DayTy(((((Julnum+1)%7)+6)%7)+1);
|
||||
}
|
||||
|
||||
// Returns the year of this TDate.
|
||||
YearTy TDate::Year() const
|
||||
{
|
||||
MonthTy m; DayTy d; YearTy y;
|
||||
Mdy(m, d, y);
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DATEIO.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CTYPE_H )
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CSTRING_H )
|
||||
#include <cstring.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DATE_H )
|
||||
#include <classlib/date.h>
|
||||
#endif
|
||||
|
||||
TDate::HowToPrint TDate::PrintOption = TDate::Normal;
|
||||
|
||||
string TDate::AsString() const
|
||||
{
|
||||
char buf[80];
|
||||
ostrstream strtemp(buf, sizeof(buf));
|
||||
strtemp << (*this) << ends;
|
||||
string temp(buf);
|
||||
return temp;
|
||||
}
|
||||
|
||||
TDate::HowToPrint TDate::SetPrintOption( HowToPrint h )
|
||||
{
|
||||
HowToPrint oldoption = PrintOption;
|
||||
PrintOption = h;
|
||||
return oldoption;
|
||||
}
|
||||
|
||||
// Skip any characters except alphanumeric characters
|
||||
static void _BIDSNEARFUNC SkipDelim( istream _BIDSFAR & strm )
|
||||
{
|
||||
char c;
|
||||
if( !strm.good() )
|
||||
return;
|
||||
|
||||
do {
|
||||
strm >> c;
|
||||
} while (strm.good() && !isalnum(c)) ;
|
||||
|
||||
if (strm.good())
|
||||
strm.putback(c);
|
||||
}
|
||||
|
||||
// Parse the name of a month from input stream.
|
||||
static const char* _BIDSNEARFUNC ParseMonth( istream _BIDSFAR & s )
|
||||
{
|
||||
static char month[12];
|
||||
register char* p = month;
|
||||
char c;
|
||||
SkipDelim(s);
|
||||
s.get(c);
|
||||
while (s.good() && isalpha(c) && (p != &month[10]))
|
||||
{
|
||||
*p++ = c;
|
||||
s.get(c);
|
||||
}
|
||||
if( s.good() )
|
||||
s.putback(c);
|
||||
*p = '\0';
|
||||
return month;
|
||||
}
|
||||
|
||||
// Parse a date from the specified input stream.
|
||||
// The date must be in one of the following forms:
|
||||
// dd-mmm-yy, mm/dd/yy, or mmm dd,yy
|
||||
// e.g.: 10-MAR-86, 3/10/86, or March 10, 1986.
|
||||
// Any non-alphanumeric character may be used as a delimiter.
|
||||
|
||||
|
||||
void TDate::ParseFrom( istream _BIDSFAR & s )
|
||||
{
|
||||
unsigned d,m,y;
|
||||
Julnum = 0; // Assume failure
|
||||
|
||||
if (s.good())
|
||||
{
|
||||
SkipDelim(s);
|
||||
s >> m; // try to parse day or month number
|
||||
SkipDelim(s);
|
||||
if (s.eof())
|
||||
return;
|
||||
if( s.fail() ) // parse <monthName><day><year>
|
||||
{
|
||||
s.clear();
|
||||
m = IndexOfMonth(ParseMonth(s)); // parse month name
|
||||
SkipDelim(s);
|
||||
s >> d; // parse day
|
||||
}
|
||||
else // try to parse day number
|
||||
{
|
||||
s >> d;
|
||||
if (s.eof()) return;
|
||||
if (s.fail()) // parse <day><monthName><year>
|
||||
{
|
||||
d = m;
|
||||
s.clear();
|
||||
m = IndexOfMonth(ParseMonth(s)); // parse month name
|
||||
}
|
||||
}
|
||||
SkipDelim(s);
|
||||
s >> y;
|
||||
}
|
||||
Julnum = s.good() ? Jday(m, d, y) : 0;
|
||||
if(Julnum==0)
|
||||
s.clear(ios::badbit);
|
||||
}
|
||||
|
||||
ostream _BIDSFAR & _BIDSFUNC operator << ( ostream _BIDSFAR & s, const TDate _BIDSFAR & d )
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
// we use an ostrstream to format into buf so that
|
||||
// we don't affect the ostream's width setting.
|
||||
ostrstream out( buf, sizeof(buf) );
|
||||
|
||||
switch ( TDate::PrintOption )
|
||||
{
|
||||
case TDate::Normal:
|
||||
out << d.NameOfMonth() << " "
|
||||
<< d.DayOfMonth() << ", "
|
||||
<< d.Year() << ends;
|
||||
break;
|
||||
case TDate::Terse:
|
||||
sprintf(buf,"%2u-%.3s-%.2u",
|
||||
d.DayOfMonth(),
|
||||
d.NameOfMonth(),
|
||||
d.Year() % 100);
|
||||
break;
|
||||
case TDate::Numbers:
|
||||
out << d.Month() << "/"
|
||||
<< d.DayOfMonth() << "/"
|
||||
<< (d.Year() % 100) << ends;
|
||||
break;
|
||||
case TDate::EuropeanNumbers:
|
||||
out << d.DayOfMonth() << "/"
|
||||
<< d.Month() <<"/"
|
||||
<< (d.Year() % 100) << ends;
|
||||
break;
|
||||
case TDate::European:
|
||||
out << d.DayOfMonth() << " "
|
||||
<< d.NameOfMonth() << " "
|
||||
<< d.Year() << ends;
|
||||
break;
|
||||
};
|
||||
|
||||
// now we write out the formatted buffer, and the ostream's
|
||||
// width setting will control the actual width of the field.
|
||||
s << buf;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DATEP.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DATE_H )
|
||||
#include <classlib/date.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_OBJSTRM_H )
|
||||
#include <classlib/objstrm.h>
|
||||
#endif
|
||||
|
||||
opstream _BIDSFAR & _BIDSFUNC operator << ( opstream _BIDSFAR & os, const TDate _BIDSFAR & d )
|
||||
{
|
||||
return os << d.Julnum;
|
||||
}
|
||||
|
||||
ipstream _BIDSFAR & _BIDSFUNC operator >> ( ipstream _BIDSFAR & is, TDate _BIDSFAR & d )
|
||||
{
|
||||
return is >> d.Julnum;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All rights
|
||||
//
|
||||
// TXBase class implementation.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
|
||||
#include <osl/defs.h>
|
||||
#include <osl/except.h>
|
||||
|
||||
int TXBase::InstanceCount = 0;
|
||||
|
||||
TXBase::TXBase(const string& msg)
|
||||
: xmsg(msg)
|
||||
{
|
||||
InstanceCount++;
|
||||
}
|
||||
|
||||
TXBase::TXBase(const TXBase& src)
|
||||
: xmsg(src)
|
||||
{
|
||||
InstanceCount++;
|
||||
}
|
||||
|
||||
TXBase::~TXBase()
|
||||
{
|
||||
InstanceCount--;
|
||||
}
|
||||
|
||||
TXBase*
|
||||
TXBase::Clone()
|
||||
{
|
||||
return new TXBase(*this);
|
||||
}
|
||||
|
||||
void
|
||||
TXBase::Throw()
|
||||
{
|
||||
THROW( *this );
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* FILE.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __LIMITS_H )
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __DIR_H )
|
||||
#include <dir.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __DOS_H )
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DEFS_H )
|
||||
#include <classlib/defs.h>
|
||||
#endif
|
||||
|
||||
#if defined( BI_PLAT_OS2 ) && !defined( __OS2_H )
|
||||
#define INCL_BASE
|
||||
#include <os2.h>
|
||||
#endif
|
||||
|
||||
#if defined( BI_PLAT_WIN32 ) && !defined( __WINDOWS_H )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_FILE_H )
|
||||
#include <classlib/file.h>
|
||||
#endif
|
||||
|
||||
int TFile::Open( const char _BIDSFAR *name, uint16 access, uint16 permission )
|
||||
{
|
||||
const unsigned shareFlags =
|
||||
Compat | DenyNone | DenyRead | DenyWrite | DenyRdWr | NoInherit;
|
||||
if( IsOpen() )
|
||||
return 0;
|
||||
Handle = ::sopen( name,
|
||||
access & ~shareFlags,
|
||||
access & shareFlags,
|
||||
permission );
|
||||
return IsOpen();
|
||||
}
|
||||
|
||||
int TFile::Close()
|
||||
{
|
||||
if( IsOpen() && ::close(Handle) == 0)
|
||||
{
|
||||
Handle = FileNull;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
long TFile::Length() const
|
||||
{
|
||||
return ::filelength( Handle );
|
||||
}
|
||||
|
||||
#if !defined( __OS2__ )
|
||||
int TFile::GetStatus( TFileStatus _BIDSFAR & status ) const
|
||||
{
|
||||
struct ftime ftime;
|
||||
if( ::getftime(Handle, &ftime) != 0 )
|
||||
return 0;
|
||||
TDate fileDate( ftime.ft_day, ftime.ft_month, ftime.ft_year+80 );
|
||||
status.createTime = TTime( fileDate,
|
||||
ftime.ft_hour,
|
||||
ftime.ft_min,
|
||||
ftime.ft_tsec*2 );
|
||||
status.modifyTime = status.createTime;
|
||||
status.accessTime = status.createTime;
|
||||
status.size = Length();
|
||||
status.attribute = 0;
|
||||
status.fullName[0] = '\0';
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
|
||||
TTime MakeTTime( FDATE fdate, FTIME ftime )
|
||||
{
|
||||
TDate fileDate( fdate.day, fdate.month, fdate.year );
|
||||
return TTime( fileDate, ftime.hours, ftime.minutes, ftime.twosecs*2 );
|
||||
}
|
||||
|
||||
int TFile::GetStatus( TFileStatus _BIDSFAR& status ) const
|
||||
{
|
||||
FILESTATUS stat;
|
||||
if( ::DosQueryFileInfo( Handle, FIL_STANDARD, &stat, sizeof(stat) ) != 0 )
|
||||
return 0;
|
||||
status.createTime = MakeTTime( stat.fdateCreation, stat.ftimeCreation );
|
||||
status.modifyTime = MakeTTime( stat.fdateLastWrite, stat.ftimeLastWrite );
|
||||
status.accessTime = MakeTTime( stat.fdateLastAccess, stat.ftimeLastAccess );
|
||||
status.size = stat.cbFile;
|
||||
status.attribute = stat.attrFile;
|
||||
status.fullName[0] = '\0';
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct dos_ftime
|
||||
{
|
||||
unsigned tsec : 5;
|
||||
unsigned min : 6;
|
||||
unsigned hour : 5;
|
||||
};
|
||||
|
||||
struct dos_fdate
|
||||
{
|
||||
unsigned day : 5;
|
||||
unsigned mon : 4;
|
||||
unsigned year : 7;
|
||||
};
|
||||
|
||||
#if !defined( __OS2__ )
|
||||
int TFile::GetStatus( const char _BIDSFAR *name,
|
||||
TFileStatus _BIDSFAR & status )
|
||||
{
|
||||
if( ::_fullpath( status.fullName, name, sizeof(status.fullName) ) == 0 )
|
||||
{
|
||||
status.fullName[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
ffblk blk;
|
||||
const uint16 FA_ALL = FA_RDONLY | FA_HIDDEN | FA_SYSTEM |
|
||||
FA_LABEL | FA_DIREC | FA_ARCH;
|
||||
if( findfirst( status.fullName, &blk, FA_ALL ) != 0 )
|
||||
return 0;
|
||||
|
||||
union
|
||||
{
|
||||
dos_ftime time;
|
||||
dos_fdate date;
|
||||
unsigned value;
|
||||
};
|
||||
|
||||
value = blk.ff_fdate;
|
||||
TDate fileDate( date.day, date.mon, date.year+80 );
|
||||
value = blk.ff_ftime;
|
||||
status.createTime = TTime( fileDate,
|
||||
time.hour,
|
||||
time.min,
|
||||
time.tsec*2 );
|
||||
|
||||
status.modifyTime = status.createTime;
|
||||
status.accessTime = status.createTime;
|
||||
status.size = blk.ff_fsize;
|
||||
status.attribute = blk.ff_attrib;
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int TFile::GetStatus( const char _BIDSFAR *name,
|
||||
TFileStatus _BIDSFAR & status )
|
||||
{
|
||||
if( ::_fullpath( status.fullName, name, sizeof(status.fullName) ) == 0 )
|
||||
{
|
||||
status.fullName[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
const uint16 FA_ALL = FA_RDONLY | FA_HIDDEN | FA_SYSTEM |
|
||||
FA_LABEL | FA_DIREC | FA_ARCH;
|
||||
HDIR Handle;
|
||||
FILEFINDBUF stat;
|
||||
ULONG count;
|
||||
if( ::DosFindFirst( status.fullName,
|
||||
&Handle,
|
||||
FA_ALL,
|
||||
&stat,
|
||||
sizeof(stat),
|
||||
&count,
|
||||
0 ) != 0 )
|
||||
{
|
||||
status.fullName[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
status.createTime = MakeTTime( stat.fdateCreation, stat.ftimeCreation );
|
||||
status.modifyTime = MakeTTime( stat.fdateLastWrite, stat.ftimeLastWrite );
|
||||
status.accessTime = MakeTTime( stat.fdateLastAccess, stat.ftimeLastAccess );
|
||||
status.size = stat.cbFile;
|
||||
status.attribute = stat.attrFile;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined( __OS2__ )
|
||||
int TFile::SetStatus( const char _BIDSFAR *name,
|
||||
const TFileStatus _BIDSFAR & status )
|
||||
{
|
||||
int attr = ::_rtl_chmod( name, 0 );
|
||||
if( attr & TFile::RdOnly )
|
||||
return 0;
|
||||
|
||||
ftime fileTime;
|
||||
fileTime.ft_tsec = status.createTime.Second()/2;
|
||||
fileTime.ft_min = status.createTime.Minute();
|
||||
fileTime.ft_hour = status.createTime.Hour();
|
||||
TDate date( status.createTime );
|
||||
fileTime.ft_day = date.DayOfMonth();
|
||||
fileTime.ft_month = date.Month();
|
||||
fileTime.ft_year = date.Year()-80;
|
||||
|
||||
TFile file( name, ReadWrite | DenyWrite );
|
||||
if( ::setftime( file.GetHandle(), &fileTime ) != 0 )
|
||||
return 0;
|
||||
if( ::chsize( file.GetHandle(), status.size ) != 0 )
|
||||
return 0;
|
||||
if( ::_rtl_chmod( name, 1, status.attribute ) == -1 )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
|
||||
FDATE MakeFDATE( TTime time )
|
||||
{
|
||||
FDATE fdate;
|
||||
fdate.day = TDate(time).Day();
|
||||
fdate.month = TDate(time).Month();
|
||||
fdate.year = TDate(time).Year();
|
||||
return fdate;
|
||||
}
|
||||
|
||||
FTIME MakeFTIME( TTime time )
|
||||
{
|
||||
FTIME ftime;
|
||||
ftime.hours = time.Hour();
|
||||
ftime.minutes = time.Minute();
|
||||
ftime.twosecs = time.Second()/2;
|
||||
return ftime;
|
||||
}
|
||||
|
||||
int TFile::SetStatus( const char _BIDSFAR *name,
|
||||
const TFileStatus _BIDSFAR & status )
|
||||
{
|
||||
FILESTATUS stat;
|
||||
stat.fdateCreation = MakeFDATE( status.createTime );
|
||||
stat.ftimeCreation = MakeFTIME( status.createTime );
|
||||
stat.fdateLastAccess = MakeFDATE( status.accessTime );
|
||||
stat.ftimeLastAccess = MakeFTIME( status.accessTime );
|
||||
stat.fdateLastWrite = MakeFDATE( status.modifyTime );
|
||||
stat.ftimeLastWrite = MakeFTIME( status.modifyTime );
|
||||
stat.cbFile = status.size;
|
||||
stat.cbFileAlloc = status.size;
|
||||
stat.attrFile = status.attribute;
|
||||
TFile file( name, ReadWrite | DenyWrite );
|
||||
return ::DosSetFileInfo( file.GetHandle(),
|
||||
FIL_STANDARD,
|
||||
&stat,
|
||||
sizeof(stat) );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
|
||||
// Implementation of geometry (TPoint, TSize, TRect) classes.
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/defs.h>
|
||||
#include <osl/geometry.h>
|
||||
|
||||
//
|
||||
// Calculate the integer square root of a 32bit signed long. return a 16bit
|
||||
// signed. Is fairly fast, esp. compared to FP versions
|
||||
//
|
||||
int _BIDSFUNC
|
||||
Sqrt(long val)
|
||||
{
|
||||
if (val <= 0)
|
||||
return 0; // Throw a math exception?
|
||||
|
||||
unsigned mask = 1; // Bit mask to shift left
|
||||
int best = 0; // Best estimate so far
|
||||
|
||||
for (; !(mask&0x8000); mask <<= 1)
|
||||
if (((long)best+mask)*(best+mask) <= val)
|
||||
best |= mask;
|
||||
return best;
|
||||
}
|
||||
|
||||
//
|
||||
// Make a duplicate of a C string using new char[]
|
||||
//
|
||||
char* _BIDSFUNC
|
||||
strnewdup(const char* s, size_t allocSize)
|
||||
{
|
||||
if (!s)
|
||||
s = "";
|
||||
int alloc = max(strlen(s)+1, allocSize);
|
||||
return strcpy(new char[alloc], s);
|
||||
}
|
||||
|
||||
//
|
||||
// Make a far duplicate of a C string using new char[] far
|
||||
//
|
||||
#if defined(BI_DATA_NEAR)
|
||||
|
||||
char far* _BIDSFUNC
|
||||
strnewdup(const char far* s, size_t allocSize)
|
||||
{
|
||||
if (!s)
|
||||
s = "";
|
||||
int alloc = max(strlen(s)+1, allocSize);
|
||||
return strcpy(new far char[alloc], s);
|
||||
}
|
||||
|
||||
long
|
||||
atol(const char far* s)
|
||||
{
|
||||
for (long val = 0; *s && isdigit(*s); s++)
|
||||
val = val*10 + *s - '0';
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BI_PLAT_WIN16)
|
||||
//
|
||||
// Make a duplicate of a wide C string using new wchar_t[]
|
||||
//
|
||||
wchar_t* _BIDSFUNC
|
||||
strnewdup(const wchar_t* s, size_t allocSize)
|
||||
{
|
||||
if (!s)
|
||||
s = L"";
|
||||
int alloc = max((size_t)lstrlenW(s)+1, allocSize);
|
||||
return lstrcpyW(new wchar_t[alloc], s);
|
||||
}
|
||||
|
||||
//
|
||||
// Wide string copy function.
|
||||
//
|
||||
wchar_t* _BIDSFUNC
|
||||
strcpy(wchar_t* dst, const wchar_t* src)
|
||||
{
|
||||
wchar_t* p = dst;
|
||||
while ((*p++ = *src++) != 0)
|
||||
;
|
||||
return dst;
|
||||
}
|
||||
|
||||
//
|
||||
// Wide string length function.
|
||||
//
|
||||
size_t _BIDSFUNC
|
||||
strlen(const wchar_t* str)
|
||||
{
|
||||
const wchar_t* p = str;
|
||||
for (; *p; p++)
|
||||
;
|
||||
return p - str;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
TRect&
|
||||
TRect::Normalize()
|
||||
{
|
||||
if (left > right)
|
||||
Swap(left, right);
|
||||
if (top > bottom)
|
||||
Swap(top, bottom);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TRect&
|
||||
TRect::Offset(int dx, int dy)
|
||||
{
|
||||
left += dx;
|
||||
top += dy;
|
||||
right += dx;
|
||||
bottom += dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TRect&
|
||||
TRect::Inflate(int dx, int dy)
|
||||
{
|
||||
left -= dx;
|
||||
top -= dy;
|
||||
right += dx;
|
||||
bottom += dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TRect&
|
||||
TRect::operator &=(const TRect& other)
|
||||
{
|
||||
if (!IsNull()) {
|
||||
if (other.IsNull())
|
||||
SetNull();
|
||||
else {
|
||||
left = Max(left, other.left);
|
||||
top = Max(top, other.top);
|
||||
right = Min(right, other.right);
|
||||
bottom = Min(bottom, other.bottom);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TRect&
|
||||
TRect::operator |=(const TRect& other)
|
||||
{
|
||||
if (!other.IsNull()) {
|
||||
if (IsNull())
|
||||
*this = other;
|
||||
else {
|
||||
left = Min(left, other.left);
|
||||
top = Min(top, other.top);
|
||||
right = Max(right, other.right);
|
||||
bottom = Max(bottom, other.bottom);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// class TCmdLine implementation
|
||||
|
||||
const char whitespace[] = " \t";
|
||||
const char terminator[] = "=/ \t"; // remove /- to dissallow separating there
|
||||
|
||||
TCmdLine::TCmdLine(const char far* cmdLine)
|
||||
{
|
||||
Buffer = new char[strlen(cmdLine)+1];
|
||||
strcpy(Buffer, cmdLine);
|
||||
Reset();
|
||||
}
|
||||
|
||||
void TCmdLine::Reset()
|
||||
{
|
||||
Token = TokenStart = Buffer;
|
||||
TokenLen = 0;
|
||||
Kind = Start;
|
||||
}
|
||||
|
||||
TCmdLine::~TCmdLine()
|
||||
{
|
||||
delete [] Buffer;
|
||||
}
|
||||
|
||||
TCmdLine::TKind TCmdLine::NextToken(bool removeCurrent)
|
||||
{
|
||||
// Done parsing, no more tokens
|
||||
//
|
||||
if (Kind == Done)
|
||||
return Kind;
|
||||
|
||||
// Move Token ptr to next token, by copying over current token, or by ptr
|
||||
// adjustment. TokenStart stays right past previous token
|
||||
//
|
||||
if (removeCurrent) {
|
||||
strcpy(TokenStart, Token+TokenLen);
|
||||
Token = TokenStart;
|
||||
}
|
||||
else {
|
||||
Token += TokenLen;
|
||||
TokenStart = Token;
|
||||
}
|
||||
|
||||
// Adjust token ptr to begining of token & determine kind
|
||||
//
|
||||
Token += strspn(Token, whitespace); // skip leading whitespace
|
||||
switch (*Token) {
|
||||
case 0:
|
||||
Kind = Done;
|
||||
break;
|
||||
case '=':
|
||||
Kind = Value;
|
||||
Token++;
|
||||
break;
|
||||
case '-':
|
||||
case '/':
|
||||
Kind = Option;
|
||||
Token++;
|
||||
break;
|
||||
default:
|
||||
Kind = Name;
|
||||
}
|
||||
Token += strspn(Token, whitespace); // skip any more whitespace
|
||||
TokenLen = strcspn(Token, terminator);
|
||||
return Kind;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
|
||||
// Implementation of geometry streaming support
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
|
||||
#include <osl/defs.h>
|
||||
#include <osl/geometry.h>
|
||||
|
||||
ostream& _BIDSFUNC
|
||||
operator <<(ostream& os, const TRect& r)
|
||||
{
|
||||
return os << '(' << r.left << ',' << r.top << '-'
|
||||
<< r.right << ',' << r.bottom << ')';
|
||||
}
|
||||
|
||||
//
|
||||
// streaming operators for resource Ids
|
||||
//
|
||||
ostream& _BIDSFUNC
|
||||
operator <<(ostream& os, const TResId& id)
|
||||
{
|
||||
bool isNumeric = static_cast<bool>(!id.IsString());
|
||||
|
||||
if (isNumeric)
|
||||
os << (long)id.Id;
|
||||
|
||||
else
|
||||
#if defined(BI_DATA_NEAR)
|
||||
os << string(id.Id);
|
||||
#else
|
||||
os << id.Id;
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
//! Could break this file in half here...
|
||||
|
||||
ipstream& _BIDSFUNC
|
||||
operator >>(ipstream& is, TRect& r)
|
||||
{
|
||||
return is >> r.left >> r.top >> r.right >> r.bottom;
|
||||
}
|
||||
|
||||
opstream& _BIDSFUNC
|
||||
operator <<(opstream& os, const TRect& r)
|
||||
{
|
||||
return os << r.left << r.top << r.right << r.bottom;
|
||||
}
|
||||
|
||||
//
|
||||
// streaming operators for resource Ids
|
||||
//
|
||||
ipstream& _BIDSFUNC
|
||||
operator >>(ipstream& is, TResId& id)
|
||||
{
|
||||
bool isNumeric;
|
||||
is >> isNumeric;
|
||||
|
||||
if (isNumeric) {
|
||||
long nid;
|
||||
is >> nid;
|
||||
id = int(nid);
|
||||
|
||||
} else
|
||||
id = (const char far *)is.freadString();
|
||||
return is;
|
||||
}
|
||||
|
||||
opstream& _BIDSFUNC
|
||||
operator <<(opstream& os, const TResId& id)
|
||||
{
|
||||
bool isNumeric = static_cast<bool>(!id.IsString());
|
||||
os << isNumeric;
|
||||
|
||||
if (isNumeric)
|
||||
os << (long)id.Id;
|
||||
|
||||
else
|
||||
os.fwriteString(id.Id);
|
||||
return os;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* HEAPSEL.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// THeapSelector doesn't have to do anything special under WIN32. It's
|
||||
// only under Windows that we have to worry about multiple heaps.
|
||||
|
||||
#if !defined( __FLAT__ )
|
||||
|
||||
#if !defined( _Windows )
|
||||
#define _Windows
|
||||
#endif
|
||||
|
||||
#if !defined( __WINDOWS_H )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __DOS_H )
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_HEAPSEL_H )
|
||||
#include <classlib/heapsel.h>
|
||||
#endif
|
||||
|
||||
void _BIDSFARDATA *THeapSelector::Allocate( size_t sz ) const
|
||||
{
|
||||
HeapSetup frame(FP_SEG(this));
|
||||
return MK_FP( _DS, LocalAlloc( sz, LMEM_MOVEABLE ) );
|
||||
}
|
||||
|
||||
void THeapSelector::Free( void _BIDSFARDATA *block )
|
||||
{
|
||||
HeapSetup frame(FP_SEG(block));
|
||||
HANDLE hMem = LocalHandle( FP_OFF(block) );
|
||||
if( hMem )
|
||||
LocalFree( hMem );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,418 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
// TLocaleString implementation - localized name support
|
||||
//
|
||||
// NOTE: This code must reside in the same module that the strings are defined
|
||||
// The cache, NativeLangId, HINSTANCE are managed on a per-module basis
|
||||
// TLocaleString::NativeLangId may be user-implemented to symbol langid
|
||||
// TLocaleString::Module may be reset from this to another resource DLL
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/locale.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Module global default values - except for TLocaleString::NativeLangId
|
||||
//
|
||||
TLangId TLocaleString::SystemDefaultLangId = TLocaleString::GetSystemLangId();
|
||||
TLangId TLocaleString::UserDefaultLangId = TLocaleString::GetUserLangId();
|
||||
HINSTANCE TLocaleString::Module = _hInstance;
|
||||
TLocaleString TLocaleString::Null = {""};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// TLocaleCache definitions, private for implementation
|
||||
//
|
||||
|
||||
#define AUTOLANG_CACHEDNEUT 0x02 // prefix indicates cache entry with neutral
|
||||
#define AUTOLANG_CACHEDLOAD 0x01 // prefix indicates Neutral is not a string
|
||||
const TLangId InvalidLangId = 0xFFFF;
|
||||
|
||||
struct TLocaleCache;
|
||||
struct TLocaleCacheBase;
|
||||
|
||||
//
|
||||
// Static object to hold destructable pointer
|
||||
//
|
||||
struct TLocaleCacheList {
|
||||
TLocaleCacheList() : Next(0) {}
|
||||
~TLocaleCacheList(); // releases cache entries
|
||||
TLocaleCache* Lookup(const char* name); // returns cache entry, 0 if failed
|
||||
TLocaleCacheBase* Next; // linked list of cached translations
|
||||
};
|
||||
|
||||
//
|
||||
// This base struct is used to cache failure to find language resource
|
||||
//
|
||||
struct TLocaleCacheBase {
|
||||
long Hash; // hashed original string, for duplicate elimination
|
||||
const char* Neutral; // original string, +1 if resource found and loaded
|
||||
TLocaleCacheBase* Next;// linked list of cached strings, for search, cleanup
|
||||
|
||||
TLocaleCacheBase(const char* name, long hash);
|
||||
static TLocaleCacheList CacheList;
|
||||
};
|
||||
|
||||
//
|
||||
// Buffer follows this header, sized for maximum string + null term.
|
||||
//
|
||||
struct TLocaleCache : public TLocaleCacheBase {
|
||||
void* operator new(unsigned size, unsigned buflen);
|
||||
TLocaleCache(const char* name, long hash, HRSRC rscHdl, HGLOBAL resData);
|
||||
~TLocaleCache() {}
|
||||
const char* Translate(TLangId lang); // (re)translate string
|
||||
|
||||
TLangId ActLangId; // actual language ID of cached string
|
||||
TLangId ReqLangId; // requested language ID of cached string
|
||||
HRSRC ResHdl; // handle returned from ::FindResource()
|
||||
char Buf[1]; // first character is string type
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// TLocaleCache implementation
|
||||
//
|
||||
|
||||
TLocaleCacheBase::TLocaleCacheBase(const char* name, long hash)
|
||||
:
|
||||
Neutral(name),
|
||||
Hash(hash)
|
||||
{
|
||||
Next = CacheList.Next;
|
||||
CacheList.Next = this;
|
||||
}
|
||||
|
||||
void* TLocaleCache::operator new(unsigned size, unsigned buflen)
|
||||
{
|
||||
return ::operator new(size+buflen);
|
||||
}
|
||||
|
||||
TLocaleCache::TLocaleCache(const char* name, long hash,
|
||||
HRSRC resHdl, HGLOBAL resData)
|
||||
:
|
||||
TLocaleCacheBase(name, hash),
|
||||
ResHdl(resHdl)
|
||||
{
|
||||
ReqLangId = ActLangId = InvalidLangId; // indicate initializing state
|
||||
*(HGLOBAL*)(Buf+1) = resData; // store resource pointer temp in buffer
|
||||
}
|
||||
|
||||
TLocaleCache* TLocaleCacheList::Lookup(const char* name)
|
||||
{
|
||||
const char* neut = name + 1; // skip over prefix flag char
|
||||
long hash = 0;
|
||||
const char* pc = name;
|
||||
while (*pc)
|
||||
hash = hash*2 ^ *pc++;
|
||||
for (TLocaleCacheBase* entry = Next; entry; entry = entry->Next) {
|
||||
if (hash == entry->Hash) {
|
||||
const char* pc = entry->Neutral;
|
||||
if (*pc != *neut) // Neutral points to prefix if lookup failed
|
||||
pc++;
|
||||
if (TLocaleString::CompareLang(pc,neut,TLocaleString::NativeLangId) != 0)
|
||||
return pc == entry->Neutral ? (TLocaleCache*)entry : 0;
|
||||
}
|
||||
}
|
||||
pc = name;
|
||||
if (*name != AUTOLANG_RCID)
|
||||
pc++; // '#' part of Id
|
||||
HRSRC resHdl = ::FindResource(TLocaleString::Module, pc, RT_LOCALIZATION);
|
||||
if (!resHdl) {
|
||||
new TLocaleCacheBase(name, hash); // add cache entry for failed lookup
|
||||
return 0;
|
||||
}
|
||||
HGLOBAL resData = ::LoadResource(TLocaleString::Module, resHdl);
|
||||
if (!resData) {
|
||||
return 0; // should throw exception on failure?!!
|
||||
}
|
||||
unsigned char far* pr = (unsigned char far*)::LockResource(resData);
|
||||
int maxLen = sizeof(HGLOBAL); // scan for longest string, including null
|
||||
unsigned char c = *pr; // check first byte of langid or neutral text
|
||||
if (c == 0) { // check for empty resource string
|
||||
::FreeResource(resData);
|
||||
new TLocaleCacheBase(name, hash); // add failed cache entry if null or err
|
||||
return 0;
|
||||
}
|
||||
if (c >= ' ') // check for unprefixed neutral string first
|
||||
pr--; // cancel ++ in for loop initialization
|
||||
else
|
||||
pr++; // start to skip over 2-byte language id
|
||||
do { // loop to check for maximum string length
|
||||
unsigned char far* p = ++pr; // skip over id to start of translation
|
||||
while ((c=*pr++) >= ' ') ; // skip over translation string
|
||||
if ((int)(pr-p) > maxLen) // update maximum, including terminator
|
||||
maxLen = (int)(pr-p);
|
||||
} while(c);
|
||||
TLocaleCache* cache = new(maxLen) TLocaleCache(neut, hash, resHdl, resData);
|
||||
cache->Buf[0] = (*name == AUTOLANG_XLAT ? AUTOLANG_CACHEDNEUT
|
||||
: AUTOLANG_CACHEDLOAD);
|
||||
return cache;
|
||||
}
|
||||
|
||||
const char* TLocaleCache::Translate(TLangId reqLang)
|
||||
{
|
||||
HGLOBAL resData;
|
||||
if (ReqLangId == InvalidLangId) { // if first time called after construction
|
||||
resData = *(HGLOBAL*)(Buf+1);
|
||||
ReqLangId = reqLang;
|
||||
} else {
|
||||
if (Buf[0]==AUTOLANG_CACHEDNEUT && TLocaleString::IsNativeLangId(reqLang))
|
||||
return Neutral;
|
||||
if (reqLang == ActLangId)
|
||||
return Buf+1;
|
||||
if (reqLang == ReqLangId) {
|
||||
if (ActLangId != InvalidLangId)
|
||||
return Buf+1;
|
||||
else if (Buf[0] == AUTOLANG_CACHEDNEUT)
|
||||
return Neutral;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if ((resData = ::LoadResource(TLocaleString::Module, ResHdl)) == 0)
|
||||
return Neutral; // should throw exception on failure?!!
|
||||
}
|
||||
unsigned char far* resBuf = (unsigned char far*)::LockResource(resData);
|
||||
unsigned char far* translation = 0;
|
||||
unsigned char far* pr = resBuf;
|
||||
int actLang = InvalidLangId;
|
||||
unsigned char c;
|
||||
int resLang;
|
||||
while ((c = *pr) != 0) {
|
||||
if (c > ' ') { // check for initial neutral string, used with CACHEDLOAD
|
||||
actLang = resLang = TLocaleString::NativeLangId;
|
||||
translation = pr; // lowest preference match
|
||||
} else {
|
||||
resLang = ((c - 1)<<10) | *++pr,pr++;
|
||||
}
|
||||
if (resLang == reqLang) { // exact match
|
||||
translation = pr;
|
||||
actLang = resLang;
|
||||
break;
|
||||
}
|
||||
if ((char)resLang == (char)reqLang) { // base language match
|
||||
if ((char)actLang != (char)reqLang || resLang == (reqLang & 0x00FF)) {
|
||||
translation = pr;
|
||||
actLang = resLang;
|
||||
}
|
||||
}
|
||||
for ( ; *pr >= ' '; ++pr) ; // skip over translation string till next Id
|
||||
}
|
||||
const char* retVal;
|
||||
if (translation) {
|
||||
while (*translation < ' ') // skip over multiple language IDs
|
||||
translation += 2;
|
||||
if (actLang != ActLangId) { // if same as in buffer, leave alone
|
||||
char* pc;
|
||||
for (pr = translation, pc = Buf + 1; *pr >= ' '; )
|
||||
*pc++ = *pr++;
|
||||
*pc = 0;
|
||||
ActLangId = actLang;
|
||||
if (reqLang != ActLangId)
|
||||
ReqLangId = reqLang;
|
||||
}
|
||||
retVal = Buf+1;
|
||||
} else if (Buf[0] == AUTOLANG_CACHEDNEUT) {
|
||||
retVal = Neutral;
|
||||
} else {
|
||||
retVal = 0;
|
||||
}
|
||||
::FreeResource(resData);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
TLocaleCacheList TLocaleCacheBase::CacheList; // declare module-global cache
|
||||
|
||||
TLocaleCacheList::~TLocaleCacheList()
|
||||
{
|
||||
while (Next) {
|
||||
TLocaleCacheBase* p = Next;
|
||||
Next = Next->Next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// TLocaleString implementation, except for static int CompareLang(s1,s2,lang)
|
||||
//
|
||||
|
||||
const char* TLocaleString::Translate(TLangId reqLang)
|
||||
{
|
||||
if (!Private) // check for null string pointer
|
||||
return Private;
|
||||
|
||||
if (reqLang == LangNeutral)
|
||||
reqLang = NativeLangId;
|
||||
else if (reqLang == LangSysDefault)
|
||||
reqLang = SystemDefaultLangId;
|
||||
else if (reqLang == LangUserDefault)
|
||||
reqLang = UserDefaultLangId;
|
||||
|
||||
TLocaleCache* cache;
|
||||
switch (Private[0])
|
||||
{
|
||||
default: // untranslatable string, no prefix
|
||||
return Private;
|
||||
|
||||
case AUTOLANG_XLAT: // not yet translated
|
||||
if (IsNativeLangId(reqLang))
|
||||
return Private+1; // resource name IS neutral or default name
|
||||
if ((cache = TLocaleCacheBase::CacheList.Lookup(Private)) == 0)
|
||||
return ++Private; // permanently bump pointer to make constant
|
||||
Private = cache->Buf; // point to buffer in cache
|
||||
return cache->Translate(reqLang);
|
||||
|
||||
case AUTOLANG_LOAD: // named resource not accessed yet
|
||||
case AUTOLANG_RCID: // numeric resource not accessed yet
|
||||
if ((cache = TLocaleCacheBase::CacheList.Lookup(Private)) == 0)
|
||||
return (Private = 0); // permanently set pointer to null
|
||||
Private = cache->Buf; // point to buffer in cache
|
||||
return cache->Translate(reqLang);
|
||||
|
||||
case AUTOLANG_CACHEDNEUT: // string in cache with neutral pointer
|
||||
case AUTOLANG_CACHEDLOAD: // string in cache with no neutral pointer
|
||||
cache = (TLocaleCache*)(Private+1) - 1; // backup to point to header
|
||||
return cache->Translate(reqLang);
|
||||
}
|
||||
}
|
||||
|
||||
TLocaleString::operator const char*()
|
||||
{
|
||||
if (Private == 0)
|
||||
return 0;
|
||||
|
||||
switch (Private[0]) {
|
||||
case AUTOLANG_XLAT: // not yet translated
|
||||
case AUTOLANG_CACHEDNEUT: // translated string in cache
|
||||
case AUTOLANG_CACHEDLOAD: // translated or neutral name in cache
|
||||
return Private+1;
|
||||
|
||||
case AUTOLANG_RCID: // resource not accessed yet
|
||||
case AUTOLANG_LOAD: // resource not accessed yet
|
||||
return 0;
|
||||
|
||||
default: // untranslatable string, no prefix
|
||||
return Private;
|
||||
}
|
||||
}
|
||||
|
||||
int TLocaleString::Compare(const char far* str, TLangId lang)
|
||||
{
|
||||
return CompareLang(this->Translate(lang), str, lang);
|
||||
}
|
||||
|
||||
int TLocaleString::IsNativeLangId(TLangId lang)
|
||||
{
|
||||
return lang == NativeLangId || lang == (NativeLangId & 0x00FF);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Registration parameter structures and formatting functions
|
||||
//
|
||||
|
||||
const char* TRegList::Lookup(const char* key, TLangId lang)
|
||||
{
|
||||
for (TRegItem* regItem = Items; regItem->Key != 0; regItem++) {
|
||||
if (strcmp(regItem->Key, key) == 0)
|
||||
if (regItem->Value.Private) // current can't test Value directly
|
||||
return regItem->Value.Translate(lang);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TLocaleString& TRegList::LookupRef(const char* key)
|
||||
{
|
||||
for (TRegItem* regItem = Items; regItem->Key != 0; regItem++) {
|
||||
if (strcmp(regItem->Key, key) == 0)
|
||||
return regItem->Value;
|
||||
}
|
||||
return TLocaleString::Null;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
// Maximum string length for REGFORMAT w/ string arg. String is clipped if too
|
||||
// long.
|
||||
//
|
||||
const int MaxFormatLen = 40;
|
||||
|
||||
char* TRegItem::RegFormat(int f, int a, int t, int d, TRegFormatHeap& heap)
|
||||
{
|
||||
// sprintf into sized auto buffer
|
||||
// ints have a max of 11 digits: -2000000000. Add pad of 8 just in case
|
||||
//
|
||||
char temp[11+1+11+1+11+1+11+1 +8];
|
||||
int len = sprintf(temp, "%d,%d,%d,%d", f,a,t,d);
|
||||
|
||||
// Check for potential overflow
|
||||
//
|
||||
char* str = heap.Data + heap.Used;
|
||||
heap.Used += len + 1;
|
||||
if (heap.Used > heap.Size)
|
||||
return "";
|
||||
|
||||
// Copy into real static buffer & return it
|
||||
//
|
||||
return strcpy(str, temp);
|
||||
}
|
||||
|
||||
char* TRegItem::RegFormat(const char* f, int a, int t, int d, TRegFormatHeap& heap)
|
||||
{
|
||||
// sprintf into sized auto buffer
|
||||
//
|
||||
char temp[MaxFormatLen+1+11+1+11+1+11+1 +8];
|
||||
int len = sprintf(temp, "%.*s,%d,%d,%d", MaxFormatLen,
|
||||
(char far*)f,a,t,d);
|
||||
|
||||
// Check for potential overflow
|
||||
//
|
||||
char* str = heap.Data + heap.Used;
|
||||
heap.Used += len + 1;
|
||||
if (heap.Used > heap.Size)
|
||||
return "";
|
||||
|
||||
// Copy into real static buffer & return it
|
||||
//
|
||||
return strcpy(str, temp);
|
||||
}
|
||||
|
||||
char* TRegItem::RegFlags(long flags, TRegFormatHeap& heap)
|
||||
{
|
||||
// sprintf into sized auto buffer
|
||||
//
|
||||
char temp[11+1 +8];
|
||||
int len = sprintf(temp, "%ld", flags);
|
||||
|
||||
// Check for potential overflow
|
||||
//
|
||||
char* str = heap.Data + heap.Used;
|
||||
heap.Used += len + 1;
|
||||
if (heap.Used > heap.Size)
|
||||
return "";
|
||||
|
||||
// Copy into real static buffer & return it
|
||||
//
|
||||
return strcpy(str, temp);
|
||||
}
|
||||
|
||||
char* TRegItem::RegVerbOpt(int mf, int sf, TRegFormatHeap& heap)
|
||||
{
|
||||
// sprintf into sized auto buffer
|
||||
//
|
||||
char temp[11+1+11+1 +8];
|
||||
int len = sprintf(temp, "%d,%d", mf, sf);
|
||||
|
||||
// Check for potential overflow
|
||||
//
|
||||
char* str = heap.Data + heap.Used;
|
||||
heap.Used += len + 1;
|
||||
if (heap.Used > heap.Size)
|
||||
return "";
|
||||
|
||||
// Copy into real static buffer & return it
|
||||
//
|
||||
return strcpy(str, temp);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
// TLocaleString default NLS compare function - used only if non-OLE
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/locale.h>
|
||||
|
||||
#if defined(BI_PLAT_WIN32)
|
||||
|
||||
TLangId
|
||||
TLocaleString::GetSystemLangId()
|
||||
{
|
||||
return ::GetSystemDefaultLangID();
|
||||
}
|
||||
|
||||
TLangId
|
||||
TLocaleString::GetUserLangId()
|
||||
{
|
||||
return ::GetUserDefaultLangID();
|
||||
}
|
||||
|
||||
int
|
||||
TLocaleString::CompareLang(const char far* s1, const char far* s2, TLangId lang)
|
||||
{
|
||||
typedef int WINAPI (*TCompareStringA)(LCID, DWORD, LPCSTR, int, LPCSTR, int);
|
||||
|
||||
static int WINAPI (*compareStringA)(LCID, DWORD, LPCSTR, int, LPCSTR, int) =
|
||||
(TCompareStringA)::GetProcAddress(::GetModuleHandle("kernel32"), "CompareStringA");
|
||||
|
||||
// Use CompareStringA if it is available
|
||||
//
|
||||
if (compareStringA)
|
||||
return compareStringA(lang, NORM_IGNORECASE | NORM_IGNORENONSPACE,
|
||||
s1,-1, s2,-1) - 2;
|
||||
|
||||
// Otherwise just use RTL function
|
||||
//
|
||||
return _fstricmp(s1, s2); // only permissible if not an OLE application
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <string.h>
|
||||
|
||||
TLangId
|
||||
TLocaleString::GetSystemLangId()
|
||||
{
|
||||
return 0x409; // US English if no OLE or Win32 support
|
||||
}
|
||||
|
||||
TLangId
|
||||
TLocaleString::GetUserLangId()
|
||||
{
|
||||
return 0x409; // US English if no OLE or Win32 support
|
||||
}
|
||||
|
||||
int
|
||||
TLocaleString::CompareLang(const char far* s1, const char far* s2, TLangId)
|
||||
{
|
||||
return _fstricmp(s1, s2); // only permissible if not an OLE application
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
// TLocaleString default native language for symbols, only if not user-defined
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/locale.h>
|
||||
|
||||
TLangId TLocaleString::NativeLangId = TLocaleString::GetSystemLangId();
|
||||
@@ -0,0 +1,638 @@
|
||||
#--------------------------------------------------------------------------#
|
||||
# #
|
||||
# MAKEFILE for Class Libraries #
|
||||
# #
|
||||
# Copyright (c) Borland International 1991, 1994 #
|
||||
# All Rights Reserved #
|
||||
# #
|
||||
# Usage: #
|
||||
# #
|
||||
# maker options #
|
||||
# #
|
||||
# Options: #
|
||||
# #
|
||||
# -DDOS, -DWIN32, -DOS2 Specifies target system #
|
||||
# #
|
||||
# -DMT Build multi-thread version #
|
||||
# #
|
||||
# -DMODEL=x Specifies memory model for DOS library. #
|
||||
# Required when building DOS library. #
|
||||
# Must be s, c, m, l, or h. #
|
||||
# #
|
||||
# -DNAME=xxx Base name of the target library or DLL #
|
||||
# Always required. #
|
||||
# #
|
||||
# -DSUFFIX=xxx Suffix to add to the base name when #
|
||||
# building a DLL. For example, -DSUFFIX=d is #
|
||||
# used when building the DBG DLLs. This puts #
|
||||
# 'd' into the name of the dll and the name #
|
||||
# of the import library. #
|
||||
# #
|
||||
# -DDLL Build a DLL. #
|
||||
# #
|
||||
# -DDBG Build the debugging version of the target. #
|
||||
# #
|
||||
# -DOBJECTS Also build the object-based containers #
|
||||
# #
|
||||
# -DBIDSFARVTABLE moves class vtables out of dgroup #
|
||||
# #
|
||||
# 16-bit non-diagnostic static libraries: #
|
||||
# make -r -DDOS -DMODEL=s -DNAME=bidss #
|
||||
# make -r -DDOS -DMODEL=c -DNAME=bidsc #
|
||||
# make -r -DDOS -DMODEL=m -DNAME=bidsm #
|
||||
# make -r -DDOS -DMODEL=l -DNAME=bidsl #
|
||||
# make -r -DDOS -DMODEL=h -DNAME=bidsh #
|
||||
# #
|
||||
# 16-bit diagnostic static libraries: #
|
||||
# make -r -DDOS -DMODEL=s -DDBG -DNAME=bidsdbs #
|
||||
# make -r -DDOS -DMODEL=c -DDBG -DNAME=bidsdbc #
|
||||
# make -r -DDOS -DMODEL=m -DDBG -DNAME=bidsdbm #
|
||||
# make -r -DDOS -DMODEL=l -DDBG -DNAME=bidsdbl #
|
||||
# make -r -DDOS -DMODEL=h -DDBG -DNAME=bidsdbh #
|
||||
# #
|
||||
# 16-bit DLLs: #
|
||||
# make -r -DDOS -DDLL -DNAME=bids #
|
||||
# make -r -DDOS -DDLL -DDBG -DNAME=bids -DSUFFIX=d #
|
||||
# #
|
||||
# WIN32 libraries: #
|
||||
# make -r -DWIN32 -DNAME=bidsf #
|
||||
# make -r -DWIN32 -DDBG -DNAME=bidsdf #
|
||||
# #
|
||||
# WIN32 DLLs: #
|
||||
# make -r -DWIN32 -DDLL -DNAME=bids -DSUFFIX=f #
|
||||
# make -r -DWIN32 -DDLL -DDBG -DNAME=bids -DSUFFIX=df #
|
||||
# #
|
||||
# OS/2 libraries: #
|
||||
# make -r -DOS2 -DNAME=bids2 #
|
||||
# make -r -DOS2 -DDBG -DNAME=bidsdb2 #
|
||||
# #
|
||||
# OS/2 DLLs: #
|
||||
# make -r -DOS2 -DDLL -DNAME=bids -DSUFFIX=2 #
|
||||
# make -r -DOS2 -DDLL -DDBG -DNAME=bids -DSUFFIX=d2 #
|
||||
# #
|
||||
#--------------------------------------------------------------------------#
|
||||
|
||||
.autodepend
|
||||
.swap
|
||||
|
||||
!if !$d(DOS) && !$d(WIN32) && !$d(OS2)
|
||||
!error Must specify target system DOS, WIN32, or OS2
|
||||
!endif
|
||||
|
||||
!if $d(DOS) && !($d(MODEL) || $d(DLL))
|
||||
!error When building DOS libraries, must specify MODEL or DLL
|
||||
!endif
|
||||
|
||||
!if $d(MODEL) && ($d(OS2) || $d(WIN32))
|
||||
!error When building OS2 or WIN32 libraries, cannot specify MODEL
|
||||
!endif
|
||||
|
||||
!if $d(DLL) && !$d(NAME)
|
||||
!error Must specify a NAME for a DLL.
|
||||
!endif
|
||||
|
||||
!if $d(DOS) && $d(MT)
|
||||
!error Cannot build multi-thread library for DOS.
|
||||
!endif
|
||||
|
||||
!if $d(MODEL)
|
||||
!if $(MODEL)!=s && $(MODEL)!=c && $(MODEL)!=m && $(MODEL)!=l && $(MODEL)!=h
|
||||
!Error MODEL must be s, c, m, l, or h
|
||||
!endif
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Set up the names of the tools to be used. If these macros have #
|
||||
# already been defined in the environment, use those definitions. #
|
||||
# #
|
||||
# BCC is the compiler. #
|
||||
# MAKE is make. #
|
||||
# TLIB is the librarian. #
|
||||
# TLINK is the linker. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
|
||||
!if !$d(BCC)
|
||||
!if $d(WIN32)
|
||||
BCC = bcc32 +turboc.cfg -v- -x
|
||||
!elif $d(OS2)
|
||||
BCC = bcc
|
||||
!else
|
||||
BCC = bcc -2- -x
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$d(MAKE)
|
||||
!if $d(WIN32)
|
||||
MAKE = maker
|
||||
!else
|
||||
MAKE = make
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$d(TLIB)
|
||||
!if $d(WIN32)
|
||||
TLIB = tlib /C
|
||||
!else
|
||||
TLIB = tlib /C
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$d(TLINK)
|
||||
!if $d(WIN32)
|
||||
TLINK = tlink32
|
||||
!else
|
||||
TLINK = tlink
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$d(BRCC)
|
||||
!if $d(WIN32)
|
||||
BRCC = brcc32 -dWIN32
|
||||
!else
|
||||
BRCC = brcc
|
||||
!endif
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Set up options for the various tools #
|
||||
# #
|
||||
# WFLAG does some magic to produce a library that works for both #
|
||||
# DOS and Windows. #
|
||||
# #
|
||||
# WLFLAG is a variation of WFLAG for the implib objs #
|
||||
# #
|
||||
# DFLAG contains the debugging switches that will be passed to the #
|
||||
# compiler through the .CFG file. #
|
||||
# #
|
||||
# LFLAG contains the switches that will be passed to TLIB on the #
|
||||
# command line. #
|
||||
# #
|
||||
# XFLAG handles _RTLDLL, which is passed to the compiler in the #
|
||||
# .CFG file and determines whether classes are to be exported. #
|
||||
# It also handle far vtable options when they are enabled. #
|
||||
# #
|
||||
# LINKOPTS is the list of options for the linker. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
!if $d(DOS) && $d(DLL)
|
||||
WFLAG = -WDE -xc
|
||||
WLFLAG = -Y
|
||||
!elif $d(DOS) && ($(MODEL) == s || $(MODEL) == c )
|
||||
WFLAG = -WE
|
||||
!elif $d(DOS) && ($(MODEL) == m || $(MODEL) == l)
|
||||
WFLAG = -Y
|
||||
!endif
|
||||
|
||||
!if $d(MT)
|
||||
!if $d(OS2)
|
||||
MTFLAG = -sm
|
||||
!else
|
||||
MTFLAG = -WM
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if $d(DBG)
|
||||
DFLAG = -v- -D__DEBUG=2 -D__WARN -D__TRACE
|
||||
LFLAG = /0
|
||||
!else
|
||||
DFLAG = -v- -D__DEBUG=0
|
||||
LFLAG = /0
|
||||
!endif
|
||||
|
||||
!if $d(DLL)
|
||||
XFLAG = -D_RTLDLL -D_BUILDBIDSDLL
|
||||
!endif
|
||||
|
||||
!if $d(BIDSFARVTABLE)
|
||||
XFLAG = $(XFLAG) -D_BIDSFARVTABLE #;_RTLFARVTABLE if RTL is rebuilt too
|
||||
!endif
|
||||
|
||||
!if $d(DOS)
|
||||
!if $d(DLL)
|
||||
MFLAG = -ml
|
||||
!else
|
||||
MFLAG = -m$(MODEL)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if $d(DOS)
|
||||
LINKOPTS = /C/c/s/Twd/Oc/Oi/Oa/Or
|
||||
!elif $d(OS2)
|
||||
LINKOPTS = /c/s/Tod
|
||||
!elif $d(WIN32)
|
||||
LINKOPTS = /c/s/Tpd
|
||||
!endif
|
||||
|
||||
!if $d(DLL)
|
||||
DEFFILE=deffile
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Build the macros to provide the startup code and library names #
|
||||
# for building DLLs. #
|
||||
# #
|
||||
# STARTUP is the startup code. #
|
||||
# #
|
||||
# LINKLIBS is the list of libraries. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
!if !$d(DLL)
|
||||
|
||||
TARGETLIB = $(NAME)
|
||||
|
||||
!else
|
||||
|
||||
VER = 45
|
||||
|
||||
!if $d(DLL) && $d(WIN32) && $d(DBG)
|
||||
TARGETFILE = bds$(VER)$(SUFFIX) # name is too long if we use 'bids'
|
||||
!else
|
||||
TARGETFILE = $(NAME)$(VER)$(SUFFIX)
|
||||
!endif
|
||||
TARGETLIB = $(NAME)$(SUFFIX)i.lib
|
||||
|
||||
!if $d(DOS)
|
||||
|
||||
STARTUP = $(LIB)\c0dl.obj
|
||||
LINKLIBS = $(LIB)\import.lib $(LIB)\crtldll.lib
|
||||
|
||||
!elif $d(OS2)
|
||||
|
||||
STARTUP = $(LIB)\c02d.obj
|
||||
|
||||
!if $d(MT)
|
||||
LINKLIBS = $(LIB)\c2mti.lib $(LIB)\os2.lib
|
||||
!else
|
||||
LINKLIBS = $(LIB)\c2i.lib $(LIB)\os2.lib
|
||||
!endif
|
||||
|
||||
!else
|
||||
|
||||
STARTUP = $(LIB)\c0d32.obj
|
||||
|
||||
!if $d(MT)
|
||||
LINKLIBS = $(LIB)\cw32mti.lib $(LIB)\import32.lib
|
||||
!else
|
||||
LINKLIBS = $(LIB)\cw32i.lib $(LIB)\import32.lib
|
||||
!endif
|
||||
|
||||
!endif
|
||||
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# OBJDIRLIST is the list of subdirectories under the OBJ directory #
|
||||
# #
|
||||
# This is used by dirs to be sure all the subdirectories are #
|
||||
# present and by clean to remove all OBJ files #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
!if $d(DOS)
|
||||
OBJDIRLIST = s ds c dc m dm l dl h dh i di
|
||||
!endif
|
||||
|
||||
!if $d(WIN32)
|
||||
OBJDIRLIST = 32 d32 i32 di32
|
||||
!endif
|
||||
|
||||
!if $d(OS2)
|
||||
OBJDIRLIST = 2 d2 i2 di2
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Set up the paths that will be needed later. #
|
||||
# #
|
||||
# INCLUDE is the full path to the compiler's include files and #
|
||||
# to the classlib's include files. If it is not defined in the #
|
||||
# environment, it is assumed to be under the directory where the #
|
||||
# compiler was installed in the subdirectory INCLUDE. #
|
||||
# #
|
||||
# LIB is the full path to the compiler's libraries. If it is not #
|
||||
# defined in the environment, it is assumed to be under the #
|
||||
# directory where the compiler was installed in the subdirectory #
|
||||
# LIB. #
|
||||
# #
|
||||
# SOURCEDIR is the full path to the source code. If it is not #
|
||||
# defined in the environment, it is assumed to be under the #
|
||||
# directory where the compiler was installed in the subdirectory #
|
||||
# SOURCE\CLASSLIB. #
|
||||
# #
|
||||
# ROOTDIR is the full path to the directory in which the makefile #
|
||||
# is located. If it is not defined in the environment, it is #
|
||||
# assumed to be the same as SOURCEDIR. #
|
||||
# #
|
||||
# LIBDIR is the full path to the directory in which the libraries #
|
||||
# should be placed when they are built. If it is not defined in #
|
||||
# the environment, it is assumed to be the same as the directory #
|
||||
# specified by LIB. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
!if !$d(BCROOT)
|
||||
!if $d(OS2)
|
||||
BCROOT=$(MAKEDIR)\..
|
||||
!else
|
||||
!include $(MAKEDIR)\bcroot.inc
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$d(INCLUDE)
|
||||
INCLUDE = $(BCROOT)\include
|
||||
!endif
|
||||
|
||||
!if !$d(RCINCLUDE)
|
||||
RCINCLUDE = $(BCROOT)\include
|
||||
!endif
|
||||
|
||||
!if !$d(LIB)
|
||||
LIB = $(BCROOT)\lib
|
||||
!endif
|
||||
|
||||
!if !$d(SOURCEDIR)
|
||||
SOURCEDIR = $(BCROOT)\source\classlib
|
||||
!endif
|
||||
|
||||
!if !$d(LIBDIR)
|
||||
LIBDIR = $(LIB)
|
||||
!endif
|
||||
|
||||
!if !$d(ROOTDIR)
|
||||
ROOTDIR = $(SOURCEDIR)
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Set up the various paths that MAKE will use #
|
||||
# #
|
||||
# OBJDIR will only have been defined when we've decide on a target #
|
||||
# platform and a set of options. Since .PATH.obj isn't used in any #
|
||||
# context in which DBG and SUFFIX haven't been defined, it's ok #
|
||||
# to use DBG and SUFFIX to define it. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
.PATH.cpp = $(SOURCEDIR)
|
||||
.PATH.cpo = $(SOURCEDIR)\obsolete
|
||||
|
||||
.PATH.lib = $(LIBDIR)
|
||||
|
||||
.PATH.rc = $(SOURCEDIR)
|
||||
|
||||
!if $d(DOS)
|
||||
OBJDIR=$(MODEL)
|
||||
!elif $d(OS2)
|
||||
OBJDIR=2
|
||||
!else
|
||||
OBJDIR=32
|
||||
!endif
|
||||
|
||||
!if $d(DLL)
|
||||
OBJDIR=i$(OBJDIR)
|
||||
!endif
|
||||
|
||||
!if $d(DBG)
|
||||
.PATH.obj = $(SOURCEDIR)\d$(OBJDIR)
|
||||
!else
|
||||
.PATH.obj = $(SOURCEDIR)\$(OBJDIR)
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# Build the various file lists needed for dependency checking, #
|
||||
# and LIBing. #
|
||||
# #
|
||||
# OBJS is the main list, conditionalized for the various targets #
|
||||
# and options. #
|
||||
# #
|
||||
# OBJS_LIB are the objs that only go in libs & implib, not the dll #
|
||||
# #
|
||||
# OBJS_DLL are the objs that only go in the dll, not the libs #
|
||||
# #
|
||||
# DEPOBJS is the list of object files for dependency checking #
|
||||
# #
|
||||
# LIBOBJS is the list of object files for building the library #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
!if $d(OBJECTS)
|
||||
OBJS = \
|
||||
PFXassoc.obj \
|
||||
PFXbtree.obj \
|
||||
PFXbtreeinn.obj \
|
||||
PFXbtreelfn.obj \
|
||||
PFXcollect.obj \
|
||||
PFXcontain.obj \
|
||||
PFXdbllist.obj \
|
||||
PFXhashtbl.obj \
|
||||
PFXldate.obj \
|
||||
PFXlist.obj \
|
||||
PFXltime.obj \
|
||||
PFXobject.obj
|
||||
!endif
|
||||
|
||||
OBJS = $(OBJS) \
|
||||
PFXbinimp.obj \
|
||||
PFXcastable.obj \
|
||||
PFXdate.obj \
|
||||
PFXdateio.obj \
|
||||
PFXdatep.obj \
|
||||
PFXfile.obj \
|
||||
PFXheapsel.obj \
|
||||
PFXobjstrm.obj \
|
||||
PFXtime.obj \
|
||||
PFXtimep.obj \
|
||||
PFXtimeio.obj \
|
||||
PFXversion.obj
|
||||
|
||||
!if !$d(OS2)
|
||||
OBJS = $(OBJS) \
|
||||
PFXexbase.obj \
|
||||
PFXgeometry.obj \
|
||||
PFXgeomstrm.obj \
|
||||
PFXreglink.obj
|
||||
!endif
|
||||
|
||||
OBJS_LIB = \
|
||||
PFXlocale.obj \
|
||||
PFXlocaleco.obj \
|
||||
PFXlocaleid.obj \
|
||||
PFXregheap.obj \
|
||||
PFXustring.obj
|
||||
|
||||
OBJS_DLL =
|
||||
|
||||
!if $d(DOS) && !$d(DLL)
|
||||
OBJS = $(OBJS) PFXtimer.obj
|
||||
!endif
|
||||
|
||||
!if $d(WIN32) || $d(OS2)
|
||||
OBJS = $(OBJS) PFXthread.obj
|
||||
!endif
|
||||
|
||||
!if $d(OBJECTS)
|
||||
!if $d(TEMPLATES)
|
||||
OBJS = $(OBJS) \
|
||||
PFXbabstary.obj \
|
||||
PFXbdict.obj \
|
||||
PFXbsortary.obj
|
||||
!else
|
||||
OBJS = $(OBJS) \
|
||||
PFXabstarry.obj \
|
||||
PFXarray.obj \
|
||||
PFXdeque.obj \
|
||||
PFXdict.obj \
|
||||
PFXsortarry.obj \
|
||||
PFXstack.obj
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if $d(DLL) && $(DOS)
|
||||
OBJS = $(OBJS) PFXclasmain.obj
|
||||
!endif
|
||||
|
||||
!if $d(DLL) && $d(OBJECTS)
|
||||
|
||||
!if $d(TEMPLATES)
|
||||
OBJS = $(OBJS) PFXtmpl2.obj
|
||||
!else
|
||||
OBJS = $(OBJS) PFXtmpl1.obj
|
||||
!endif
|
||||
|
||||
!endif
|
||||
|
||||
!if $d(DLL) && !$d(OBJECTS) && !$d(OS2)
|
||||
RESFILE = version.res
|
||||
!endif
|
||||
|
||||
#PFXOBJS = $(OBJS:SFX=)
|
||||
#SFXOBJS = $(OBJS:PFX=)
|
||||
|
||||
DEPOBJS = $(OBJS:PFX=) $(OBJS_LIB:PFX=) $(OBJS_DLL:PFX=)
|
||||
!if $d(DLL)
|
||||
LIBOBJS = $(OBJS_LIB:PFX=+)
|
||||
LINKOBJS = $(OBJS:PFX=) $(OBJS_DLL:PFX=)
|
||||
!else
|
||||
LIBOBJS = $(OBJS:PFX=-+) $(OBJS_LIB:PFX=-+)
|
||||
!endif
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# These are the targets that we can make. #
|
||||
# #
|
||||
# target: builds the target file #
|
||||
# #
|
||||
# dirs: makes sure all the necessary subdirectories are present #
|
||||
# #
|
||||
# clean: deletes the .OBJ files #
|
||||
# #
|
||||
# config: builds a .CFG file with the correct flags #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
target: config $(DEFFILE) $(DEPOBJS) $(RESFILE)
|
||||
!if !$d(DLL)
|
||||
cd $(.PATH.obj)
|
||||
$(TLIB) $(LFLAG) $(.PATH.lib)\$(TARGETLIB) @&&!
|
||||
$(LIBOBJS)
|
||||
!
|
||||
cd $(ROOTDIR)
|
||||
!else
|
||||
cd $(.PATH.obj)
|
||||
$(TLINK) @&&!
|
||||
$(STARTUP)+
|
||||
$(LINKOBJS)
|
||||
$(TARGETFILE).dll
|
||||
$(LINKOPTS) $(.PATH.lib)\$(TARGETFILE).map
|
||||
$(LINKLIBS)
|
||||
temp.def
|
||||
$(RESFILE)
|
||||
!
|
||||
!if $(TARGET) == DOS
|
||||
rc -30 $(TARGETFILE)
|
||||
!endif
|
||||
implib $(TARGETLIB) $(TARGETFILE).dll
|
||||
tlib $(LFLAG) $(TARGETLIB) @&&|
|
||||
$(LIBOBJS)
|
||||
|
|
||||
cd $(ROOTDIR)
|
||||
copy $(.PATH.obj)\$(TARGETFILE).dll $(.PATH.lib)
|
||||
del $(.PATH.obj)\$(TARGETFILE).dll
|
||||
copy $(.PATH.obj)\$(TARGETLIB) $(.PATH.lib)
|
||||
del $(.PATH.obj)\$(TARGETLIB)
|
||||
!endif
|
||||
|
||||
|
||||
dirs:
|
||||
-for %d in ($(OBJDIRLIST)) do md $(SOURCEDIR)\%d
|
||||
|
||||
clean:
|
||||
-for %d in ($(OBJDIRLIST)) do del $(SOURCEDIR)\%d\*.obj
|
||||
|
||||
config:
|
||||
@-if not exist $(.PATH.obj)\..\NUL md $(.PATH.obj)\..
|
||||
@-if not exist $(.PATH.obj)\NUL md $(.PATH.obj)
|
||||
@type &&!
|
||||
-c -n$(.PATH.obj) -I$(INCLUDE) $(DFLAG) $(XFLAG) $(MFLAG) $(TFLAG)
|
||||
! >turboc.cfg
|
||||
|
||||
deffile:
|
||||
!if $d(DOS)
|
||||
@echo >$(.PATH.obj)\temp.def LIBRARY $(TARGETFILE)
|
||||
!else
|
||||
@echo >$(.PATH.obj)\temp.def LIBRARY $(TARGETFILE) INITINSTANCE
|
||||
!endif
|
||||
@echo >>$(.PATH.obj)\temp.def DESCRIPTION 'Parametrized Class Library for BC++'
|
||||
!if $d(DOS)
|
||||
@echo >>$(.PATH.obj)\temp.def EXETYPE WINDOWS
|
||||
@echo >>$(.PATH.obj)\temp.def CODE PRELOAD MOVEABLE DISCARDABLE
|
||||
@echo >>$(.PATH.obj)\temp.def DATA PRELOAD MOVEABLE SINGLE
|
||||
!else
|
||||
@echo >>$(.PATH.obj)\temp.def DATA MULTIPLE NONSHARED
|
||||
!endif
|
||||
@echo >>$(.PATH.obj)\temp.def HEAPSIZE 4096
|
||||
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# #
|
||||
# We need an implicit rule for building .OBJ files, and a few #
|
||||
# explicit rules for special cases. #
|
||||
# #
|
||||
# TIMER.OBJ is never built for windows, so doesn't need the #
|
||||
# windows flags. #
|
||||
# #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
timer.obj: timer.cpp
|
||||
$(BCC) $(SOURCEDIR)\timer
|
||||
|
||||
tmpl1.obj: tmplinst.cpp
|
||||
$(BCC) -o$(.PATH.obj)\tmpl1.obj $(WFLAG) $(.PATH.cpp)\tmplinst
|
||||
|
||||
tmpl2.obj: tmplinst.cpp
|
||||
$(BCC) -o$(.PATH.obj)\tmpl2.obj -DTEMPLATES $(WFLAG) $(.PATH.cpp)\tmplinst
|
||||
|
||||
.cpo.obj:
|
||||
$(BCC) $(WFLAG) -P {$< }
|
||||
|
||||
.cpp.obj:
|
||||
$(BCC) $(WFLAG) $(MTFLAG) {$* }
|
||||
|
||||
.rc.res:
|
||||
$(BRCC) -i$(RCINCLUDE) $*.rc
|
||||
copy $*.res $(.PATH.obj)
|
||||
del $*.res
|
||||
|
||||
!if $d(DOS) && $d(DLL)
|
||||
$(OBJS_LIB:PFX=):
|
||||
$(BCC) $(WLFLAG) $(MTFLAG) -D_BIDSDLL -U_BUILDBIDSDLL $(.PATH.cpp)\$&.cpp
|
||||
!endif
|
||||
@@ -0,0 +1 @@
|
||||
/* not needed for version 4.00 */
|
||||
@@ -0,0 +1,786 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* OBJSTRM.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1992, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( _Windows )
|
||||
#define _Windows
|
||||
#endif
|
||||
|
||||
#if !defined( __ALLOC_H )
|
||||
#include <alloc.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CSTRING_H )
|
||||
#include <cstring.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_STREAMBL_H )
|
||||
#include <classlib/streambl.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_OBJSTRM_H )
|
||||
#include <classlib/objstrm.h>
|
||||
#endif
|
||||
|
||||
#if defined( __FLAT__ )
|
||||
#define _fstrncpy strncpy
|
||||
#define _fstrcpy strcpy
|
||||
#define _fstrlen strlen
|
||||
#define _fmemcpy memcpy
|
||||
#define farmalloc malloc
|
||||
#endif
|
||||
|
||||
DIAG_DEFINE_GROUP(Objstrm,1,0);
|
||||
|
||||
const uint32 streamVersion = 0x0101;
|
||||
const char versionIndicator = ':';
|
||||
|
||||
const char EOS = '\0';
|
||||
|
||||
const uint8 oldNullStringLen = UCHAR_MAX;
|
||||
const uint32 nullStringLen = ULONG_MAX;
|
||||
|
||||
TStreamableTypes *pstream::types = 0;
|
||||
|
||||
const char *TStreamer::StreamableName() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TStreamableClass::TStreamableClass( const char *n,
|
||||
BUILDER b,
|
||||
int d,
|
||||
ModuleId id ) :
|
||||
ObjectBuilder( b, d ),
|
||||
ModId(id)
|
||||
{
|
||||
ObjectId = new char[strlen(n)+1];
|
||||
strcpy( CONST_CAST(char *,ObjectId), n );
|
||||
pstream::initTypes();
|
||||
if( id != 0 ) // id == 0 is used only during lookup.
|
||||
// It flags an instance that shouldn't be registered
|
||||
pstream::types->RegisterType( id, *this );
|
||||
}
|
||||
|
||||
TStreamableClass::~TStreamableClass()
|
||||
{
|
||||
if( ModId != 0 )
|
||||
pstream::types->UnRegisterType( ModId, *this );
|
||||
|
||||
delete [] CONST_CAST(char *,ObjectId);
|
||||
}
|
||||
|
||||
void TStreamableTypes::RegisterType( ModuleId, TStreamableClass& ts )
|
||||
{
|
||||
Types.Add(&ts);
|
||||
}
|
||||
|
||||
void TStreamableTypes::UnRegisterType( ModuleId, TStreamableClass& ts )
|
||||
{
|
||||
Types.Detach(&ts);
|
||||
if( Types.Count() == 0 )
|
||||
pstream::releaseTypes();
|
||||
}
|
||||
|
||||
const ObjectBuilder *TStreamableTypes::Lookup( ModuleId,
|
||||
const char *name ) const
|
||||
{
|
||||
unsigned loc = Types.Find(&TStreamableClass(name,0,0,0));
|
||||
if( loc == UINT_MAX )
|
||||
{
|
||||
string msg;
|
||||
msg.reserve(128);
|
||||
msg = "Attempt to stream unregistered type '";
|
||||
msg += name;
|
||||
msg += "'";
|
||||
throw xmsg(msg);
|
||||
}
|
||||
return Types[loc];
|
||||
}
|
||||
|
||||
void TPReadObjects::RemoveAll()
|
||||
{
|
||||
Data.Flush();
|
||||
}
|
||||
|
||||
void TPReadObjects::RegisterObject( TStreamableBase *adr )
|
||||
{
|
||||
Data.Add( adr );
|
||||
}
|
||||
|
||||
TStreamableBase *TPReadObjects::Find( P_id_type id )
|
||||
{
|
||||
return Data[id];
|
||||
}
|
||||
|
||||
TPReadObjects::TPReadObjects() : Data(5,5)
|
||||
{
|
||||
Data.Add(0); // prime it: 0 is not a legal index.
|
||||
}
|
||||
|
||||
TPWrittenObjects::TPWrittenObjects() : CurId(0), Data(5,5)
|
||||
{
|
||||
}
|
||||
|
||||
void TPWrittenObjects::RemoveAll()
|
||||
{
|
||||
CurId = 0; Data.Flush();
|
||||
}
|
||||
|
||||
void TPWrittenObjects::RegisterObject( TStreamableBase *adr )
|
||||
{
|
||||
Data.Add( TPWObj( ((char *)(void *)adr)+1, ++CurId ) );
|
||||
}
|
||||
|
||||
void TPWrittenObjects::RegisterVB( const TStreamableBase *adr )
|
||||
{
|
||||
Data.Add( TPWObj( adr, ++CurId ) );
|
||||
}
|
||||
|
||||
P_id_type TPWrittenObjects::FindObject( TStreamableBase *d )
|
||||
{
|
||||
unsigned res = Data.Find( TPWObj(((char *)(void *)d)+1,0) );
|
||||
if( res == UINT_MAX )
|
||||
return 0;
|
||||
else
|
||||
return Data[res].Ident;
|
||||
}
|
||||
|
||||
P_id_type TPWrittenObjects::FindVB( TStreamableBase *d )
|
||||
{
|
||||
unsigned res = Data.Find( TPWObj(d,0) );
|
||||
if( res == UINT_MAX )
|
||||
return 0;
|
||||
else
|
||||
return Data[res].Ident;
|
||||
}
|
||||
|
||||
pstream::~pstream()
|
||||
{
|
||||
}
|
||||
|
||||
void pstream::initTypes()
|
||||
{
|
||||
if( types == 0 )
|
||||
types = new TStreamableTypes;
|
||||
}
|
||||
|
||||
void pstream::releaseTypes()
|
||||
{
|
||||
delete types;
|
||||
types = 0;
|
||||
}
|
||||
|
||||
streampos ipstream::tellg()
|
||||
{
|
||||
streampos res;
|
||||
if( !good() )
|
||||
res = streampos(EOF);
|
||||
else
|
||||
{
|
||||
res = bp->seekoff( 0, ios::cur, ios::in );
|
||||
if( res == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ipstream& ipstream::seekg( streampos pos )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
objs.RemoveAll();
|
||||
if( bp->seekoff( pos, ios::beg, ios::in ) == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ipstream& ipstream::seekg( streamoff off, ios::seek_dir dir )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
objs.RemoveAll();
|
||||
if( bp->seekoff( off, dir, ios::in ) == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8 ipstream::readByte()
|
||||
{
|
||||
int res;
|
||||
if( !good() )
|
||||
res = uint8(0);
|
||||
else
|
||||
{
|
||||
res = bp->sbumpc();
|
||||
if( res == EOF )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return uint8(res);
|
||||
}
|
||||
|
||||
void ipstream::readBytes( void *data, size_t sz )
|
||||
{
|
||||
PRECONDITION( data != 0 );
|
||||
if( good() && sz > 0 )
|
||||
{
|
||||
if( bp->sgetn( (char *)data, sz ) != sz )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
}
|
||||
|
||||
void ipstream::freadBytes( void _BIDSFARDATA *data, size_t sz )
|
||||
{
|
||||
PRECONDITION( data != 0 );
|
||||
|
||||
if( good() && sz > 0 )
|
||||
{
|
||||
char *buf = new char[sz];
|
||||
|
||||
if( bp->sgetn( buf, sz ) != sz )
|
||||
clear( ios::failbit );
|
||||
else
|
||||
_fmemcpy( data, buf, sz);
|
||||
|
||||
delete [] buf;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ipstream::readWord()
|
||||
{
|
||||
if( getVersion() > 0 )
|
||||
return readWord32();
|
||||
else
|
||||
return readWord16();
|
||||
}
|
||||
|
||||
uint16 ipstream::readWord16()
|
||||
{
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint16 temp;
|
||||
if( bp->sgetn( (char *)&temp, sizeof( temp ) ) != sizeof( temp ) )
|
||||
clear( ios::failbit );
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ipstream::readWord32()
|
||||
{
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 temp;
|
||||
if( bp->sgetn( (char *)&temp, sizeof( temp ) ) != sizeof( temp ) )
|
||||
clear( ios::failbit );
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ipstream::readStringLength()
|
||||
{
|
||||
uint32 len;
|
||||
if( getVersion() > 0x0100 )
|
||||
{
|
||||
len = readWord32();
|
||||
}
|
||||
else
|
||||
{
|
||||
len = readByte();
|
||||
if( len == oldNullStringLen )
|
||||
len = nullStringLen;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
char *ipstream::readString()
|
||||
{
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 len = readStringLength();
|
||||
if( len == nullStringLen )
|
||||
return 0;
|
||||
|
||||
char *buf = new char[len+1];
|
||||
if( buf == 0 )
|
||||
return 0;
|
||||
readBytes( buf, len );
|
||||
buf[len] = EOS;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
char *ipstream::readString( char *buf, unsigned maxLen )
|
||||
{
|
||||
PRECONDITION( buf != 0 );
|
||||
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 len = readStringLength();
|
||||
if( len == nullStringLen || len > maxLen-1 )
|
||||
return 0;
|
||||
readBytes( buf, len );
|
||||
buf[len] = EOS;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
char _BIDSFARDATA *ipstream::freadString()
|
||||
{
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 len = readStringLength();
|
||||
if( len == nullStringLen )
|
||||
return 0;
|
||||
|
||||
char _BIDSFARDATA *buf = new _BIDSFARDATA char[len+1];
|
||||
freadBytes(buf, len);
|
||||
buf[len] = EOS;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
char _BIDSFARDATA *ipstream::freadString( char _BIDSFARDATA *buf, unsigned maxLen )
|
||||
{
|
||||
PRECONDITION(buf != 0 );
|
||||
|
||||
if( !good() )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint32 len = readStringLength();
|
||||
if( len == nullStringLen || len > maxLen-1 )
|
||||
return 0;
|
||||
|
||||
freadBytes( buf, len);
|
||||
buf[len] = EOS;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
void ipstream::readVersion()
|
||||
{
|
||||
if( !good() )
|
||||
version = 0;
|
||||
else
|
||||
{
|
||||
int res = bp->sgetc();
|
||||
if( res == EOF )
|
||||
{
|
||||
clear( ios::eofbit );
|
||||
version = 0;
|
||||
return;
|
||||
}
|
||||
if( res != versionIndicator )
|
||||
version = 0;
|
||||
else
|
||||
{
|
||||
bp->sbumpc();
|
||||
version = readWord32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TStreamableBase _FAR *ipstream::readObject( TStreamableBase _FAR *&mem,
|
||||
ModuleId mid )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
const ObjectBuilder *pc = readPrefix( mid );
|
||||
if( pc == 0 )
|
||||
mem = 0;
|
||||
else
|
||||
{
|
||||
readData( pc, mem );
|
||||
readSuffix();
|
||||
}
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
const ObjectBuilder *ipstream::readPrefix( ModuleId mid )
|
||||
{
|
||||
char ch = readByte();
|
||||
if( ch != '[' )
|
||||
{
|
||||
clear( ios::failbit );
|
||||
return 0;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
name[0] = EOS;
|
||||
readString( name, sizeof name );
|
||||
if( name[0] == EOS )
|
||||
{
|
||||
clear( ios::failbit );
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACEX(Objstrm,0,"Reading " << name);
|
||||
const ObjectBuilder *res = types->Lookup( mid, name );
|
||||
WARNX(Objstrm,res==0,0,"Unrecognized class identifier: " << name);
|
||||
if( res == 0 )
|
||||
{
|
||||
clear( ios::failbit );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ipstream::readData( const ObjectBuilder *c, TStreamableBase _FAR *&mem )
|
||||
{
|
||||
TStreamer *strmr = c->Builder(mem);
|
||||
mem = strmr->GetObject();
|
||||
|
||||
// register the address
|
||||
registerObject( mem );
|
||||
|
||||
uint32 classVer = 0;
|
||||
if( getVersion() > 0 )
|
||||
classVer = readWord32();
|
||||
|
||||
strmr->Read( *this, classVer );
|
||||
delete strmr;
|
||||
}
|
||||
|
||||
void ipstream::readSuffix()
|
||||
{
|
||||
if( !good() )
|
||||
return;
|
||||
char ch = readByte();
|
||||
if( ch != ']' )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
|
||||
TStreamableBase _FAR *ipstream::readObjectPointer( TStreamableBase _FAR *&mem,
|
||||
ModuleId mid )
|
||||
{
|
||||
if( !good() )
|
||||
return 0;
|
||||
|
||||
char ch = readByte();
|
||||
switch( ch )
|
||||
{
|
||||
case pstream::ptNull:
|
||||
mem = 0;
|
||||
break;
|
||||
case pstream::ptIndexed:
|
||||
{
|
||||
P_id_type index = P_id_type(readWord());
|
||||
mem = find( index );
|
||||
CHECK( mem != 0 );
|
||||
break;
|
||||
}
|
||||
case pstream::ptObject:
|
||||
{
|
||||
const ObjectBuilder *pc = readPrefix( mid );
|
||||
readData( pc, mem );
|
||||
readSuffix();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
clear( ios::failbit );
|
||||
break;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
opstream::opstream()
|
||||
{
|
||||
objs = new TPWrittenObjects;
|
||||
if( bp != 0 )
|
||||
writeVersion();
|
||||
}
|
||||
|
||||
opstream::opstream( streambuf * sb )
|
||||
{
|
||||
objs = new TPWrittenObjects;
|
||||
pstream::init( sb );
|
||||
writeVersion();
|
||||
}
|
||||
|
||||
streampos opstream::tellp()
|
||||
{
|
||||
streampos res;
|
||||
if( !good() )
|
||||
res = streampos(EOF);
|
||||
else
|
||||
{
|
||||
res = bp->seekoff( 0, ios::cur, ios::out );
|
||||
if( res == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
opstream& opstream::seekp( streampos pos )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
objs->RemoveAll();
|
||||
if( bp->seekoff( pos, ios::beg, ios::out ) == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
opstream& opstream::seekp( streamoff pos, ios::seek_dir dir )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
objs->RemoveAll();
|
||||
if( bp->seekoff( pos, dir, ios::out ) == streampos(EOF) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void opstream::writeVersion()
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
writeByte( versionIndicator );
|
||||
writeWord32( streamVersion );
|
||||
}
|
||||
}
|
||||
|
||||
opstream& opstream::flush()
|
||||
{
|
||||
if( bp->sync() == EOF )
|
||||
clear( ios::badbit );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void opstream::writeByte( uint8 ch )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
if( bp->sputc( ch ) == EOF )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writeBytes( const void *data, size_t sz )
|
||||
{
|
||||
PRECONDITION( data != 0 );
|
||||
|
||||
if( good() && sz > 0 )
|
||||
{
|
||||
if( bp->sputn( (char *)data, sz ) != sz )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writeWord16( uint16 word16 )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
if( bp->sputn( (char *)&word16, sizeof(word16) ) != sizeof(word16) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writeWord32( uint32 word32 )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
if( bp->sputn( (char *)&word32, sizeof(word32) ) != sizeof(word32) )
|
||||
clear( ios::failbit );
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::fwriteBytes( const void _BIDSFARDATA *data, size_t sz )
|
||||
{
|
||||
PRECONDITION( data != 0 );
|
||||
|
||||
if( good() && sz > 0 )
|
||||
{
|
||||
char *buf = new char[sz];
|
||||
|
||||
_fmemcpy( buf, data, sz );
|
||||
if( bp->sputn( (char *)buf, sz ) != sz )
|
||||
clear( ios::failbit );
|
||||
|
||||
delete buf;
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writeString( const char *str )
|
||||
{
|
||||
if( !good() )
|
||||
return;
|
||||
|
||||
if( str == 0 )
|
||||
{
|
||||
writeWord32( nullStringLen );
|
||||
return;
|
||||
}
|
||||
size_t len = strlen( str );
|
||||
writeWord32( len );
|
||||
writeBytes( str, len );
|
||||
}
|
||||
|
||||
void opstream::fwriteString( const char _BIDSFARDATA * str )
|
||||
{
|
||||
if( !good() )
|
||||
return;
|
||||
|
||||
if( str == 0 )
|
||||
{
|
||||
writeWord32( nullStringLen );
|
||||
return;
|
||||
}
|
||||
size_t len = _fstrlen( str );
|
||||
writeWord32( len );
|
||||
fwriteBytes(str, len);
|
||||
}
|
||||
|
||||
#pragma warn -par
|
||||
void opstream::writeObject( const TStreamableBase _FAR *mem, int isPtr, ModuleId mid )
|
||||
{
|
||||
WARNX(Objstrm,
|
||||
!isPtr && findObject( CONST_CAST(TStreamableBase *,mem) ),
|
||||
0,
|
||||
"Pointer written before object: " \
|
||||
<< _TYPENAME(mem) << '(' << (void _FAR *)mem << ')' );
|
||||
if( good() )
|
||||
{
|
||||
writePrefix( mem );
|
||||
writeData( mem, mid );
|
||||
writeSuffix( mem );
|
||||
}
|
||||
}
|
||||
#pragma warn +par
|
||||
|
||||
void opstream::writeObjectPointer( const TStreamableBase *t, ModuleId mid )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
P_id_type index;
|
||||
if( t == 0 )
|
||||
writeByte( pstream::ptNull );
|
||||
else if( (index = findObject( CONST_CAST(TStreamableBase *,t) )) != 0 )
|
||||
{
|
||||
writeByte( pstream::ptIndexed );
|
||||
writeWord( index );
|
||||
}
|
||||
else
|
||||
{
|
||||
writeByte( pstream::ptObject );
|
||||
writeObject( t, 1, mid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writePrefix( const TStreamableBase *t )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
writeByte( '[' );
|
||||
writeString( _TYPENAME(t) );
|
||||
}
|
||||
}
|
||||
|
||||
void opstream::writeData( const TStreamableBase *t, ModuleId mid )
|
||||
{
|
||||
if( good() )
|
||||
{
|
||||
registerObject( CONST_CAST(TStreamableBase *,t) );
|
||||
const ObjectBuilder *res = types->Lookup( mid, _TYPENAME(t) );
|
||||
CHECKX(res,_TYPENAME(t));
|
||||
TStreamer *strmr = res->Builder(CONST_CAST(TStreamableBase *,t));
|
||||
writeWord32( strmr->ClassVersion() );
|
||||
strmr->Write( *this );
|
||||
delete strmr;
|
||||
}
|
||||
}
|
||||
|
||||
void fpbase::open( const char *b, int m, int prot )
|
||||
{
|
||||
if( buf.is_open() )
|
||||
clear(ios::failbit); // fail - already open
|
||||
else if( buf.open(b, m, prot) )
|
||||
clear(ios::goodbit); // successful open
|
||||
else
|
||||
clear(ios::badbit); // open failed
|
||||
}
|
||||
|
||||
void fpbase::attach( int f )
|
||||
{
|
||||
if( buf.is_open() )
|
||||
clear(ios::failbit);
|
||||
else if( buf.attach(f) )
|
||||
clear(ios::goodbit);
|
||||
else
|
||||
clear(ios::badbit);
|
||||
}
|
||||
|
||||
void fpbase::close()
|
||||
{
|
||||
if( buf.close() )
|
||||
clear(ios::goodbit);
|
||||
else
|
||||
clear(ios::failbit);
|
||||
}
|
||||
|
||||
void fpbase::setbuf(char* b, int len)
|
||||
{
|
||||
if( buf.setbuf(b, len) )
|
||||
clear(ios::goodbit);
|
||||
else
|
||||
clear(ios::failbit);
|
||||
}
|
||||
|
||||
//
|
||||
// These operators are not friends of string, so
|
||||
// they must use only the public interface.
|
||||
//
|
||||
opstream _BIDSFAR& _BIDSENTRY _BIDSFUNC operator << ( opstream _BIDSFAR& os,
|
||||
const string _BIDSFAR& str )
|
||||
{
|
||||
os.writeString( str.c_str() );
|
||||
return os;
|
||||
}
|
||||
|
||||
ipstream _BIDSFAR& _BIDSENTRY _BIDSFUNC operator >> ( ipstream _BIDSFAR& is,
|
||||
string _BIDSFAR& str )
|
||||
{
|
||||
if( is.good() )
|
||||
{
|
||||
uint32 len = is.readStringLength();
|
||||
if( len == nullStringLen )
|
||||
str = "";
|
||||
else
|
||||
{
|
||||
char *temp = new char[len+1];
|
||||
is.readBytes( temp, len );
|
||||
temp[len] = EOS;
|
||||
str = temp;
|
||||
delete [] temp;
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* ABSTARRY.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __MEM_H )
|
||||
#include <mem.h>
|
||||
#endif // __MEM_H
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __ABSTARRY_H )
|
||||
#include "classlib\obsolete\abstarry.h"
|
||||
#endif // __ABSTARRY_H
|
||||
|
||||
AbstractArray::AbstractArray( int anUpper, int aLower, sizeType aDelta )
|
||||
{
|
||||
PRECONDITION( anUpper >= aLower );
|
||||
lastElementIndex = aLower - 1;
|
||||
lowerbound = aLower;
|
||||
upperbound = anUpper;
|
||||
delta = aDelta;
|
||||
|
||||
theArray = new Object *[ arraySize() ];
|
||||
if( theArray == 0 )
|
||||
ClassLib_error(__ENOMEM);
|
||||
|
||||
for( int i = 0; i < arraySize(); i++ )
|
||||
{
|
||||
theArray[ i ] = ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractArray::~AbstractArray()
|
||||
{
|
||||
PRECONDITION( theArray != 0 );
|
||||
if( ownsElements() )
|
||||
for( int i = 0; i < arraySize(); i++ )
|
||||
if( theArray[ i ] != ZERO )
|
||||
delete theArray[ i ];
|
||||
delete [] theArray;
|
||||
}
|
||||
|
||||
void AbstractArray::detach( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
detach( find( toDetach ), dt );
|
||||
}
|
||||
|
||||
void AbstractArray::detach( int atIndex, DeleteType dt )
|
||||
{
|
||||
PRECONDITION( atIndex >= lowerbound &&
|
||||
atIndex <= upperbound && theArray != 0
|
||||
);
|
||||
|
||||
if( ptrAt(atIndex) != ZERO )
|
||||
{
|
||||
if( delObj(dt) )
|
||||
delete ptrAt(atIndex);
|
||||
itemsInContainer--;
|
||||
}
|
||||
removeEntry(atIndex);
|
||||
if( atIndex <= lastElementIndex )
|
||||
lastElementIndex--;
|
||||
CHECK( itemsInContainer != UINT_MAX );
|
||||
}
|
||||
|
||||
void AbstractArray::flush( DeleteType dt )
|
||||
{
|
||||
if( delObj(dt) )
|
||||
for( unsigned i = 0; i <= zeroBase(upperbound); i++ )
|
||||
if( theArray[i] != ZERO )
|
||||
delete theArray[i];
|
||||
|
||||
for( unsigned i = 0; i <= zeroBase(upperbound); i++ )
|
||||
theArray[i] = ZERO;
|
||||
|
||||
itemsInContainer = 0;
|
||||
lastElementIndex = lowerbound-1;
|
||||
}
|
||||
|
||||
inline unsigned nextDelta( unsigned sz, unsigned delta )
|
||||
{
|
||||
return (sz%delta) ? ((sz+delta)/delta)*delta : sz;
|
||||
}
|
||||
|
||||
void AbstractArray::reallocate( sizeType newSize )
|
||||
{
|
||||
PRECONDITION( newSize > arraySize() );
|
||||
if( delta == 0 )
|
||||
ClassLib_error(__EEXPANDFS);
|
||||
|
||||
sizeType adjustedSize = arraySize() +
|
||||
nextDelta( newSize - arraySize(), delta );
|
||||
Object **newArray = new Object *[ adjustedSize ];
|
||||
if( newArray == 0 )
|
||||
ClassLib_error(__ENOMEM);
|
||||
|
||||
memcpy( newArray, theArray, arraySize() * sizeof( theArray[0] ) );
|
||||
|
||||
for( int i = arraySize(); i < adjustedSize; i++ )
|
||||
newArray[i] = ZERO;
|
||||
|
||||
delete [] theArray;
|
||||
theArray = newArray;
|
||||
upperbound = adjustedSize + lowerbound - 1;
|
||||
}
|
||||
|
||||
void AbstractArray::setData( int loc, Object *data )
|
||||
{
|
||||
PRECONDITION( loc >= lowerbound && loc <= upperbound );
|
||||
theArray[ zeroBase(loc) ] = data;
|
||||
}
|
||||
|
||||
void AbstractArray::insertEntry( int loc )
|
||||
{
|
||||
PRECONDITION( loc >= lowerbound && loc <= upperbound );
|
||||
memmove( theArray + zeroBase(loc) + 1,
|
||||
theArray + zeroBase(loc),
|
||||
(upperbound - loc)*sizeof( theArray[0] )
|
||||
);
|
||||
}
|
||||
|
||||
void AbstractArray::removeEntry( int loc )
|
||||
{
|
||||
if( loc >= lastElementIndex )
|
||||
theArray[zeroBase(loc)] = ZERO;
|
||||
else
|
||||
squeezeEntry( zeroBase(loc) );
|
||||
}
|
||||
|
||||
void AbstractArray::squeezeEntry( int squeezePoint )
|
||||
{
|
||||
PRECONDITION( squeezePoint >= 0 &&
|
||||
squeezePoint <= zeroBase(lastElementIndex)
|
||||
);
|
||||
|
||||
memmove( theArray + squeezePoint,
|
||||
theArray + squeezePoint + 1,
|
||||
(zeroBase(lastElementIndex)-squeezePoint)*sizeof( theArray[0] )
|
||||
);
|
||||
theArray[zeroBase(lastElementIndex)] = ZERO;
|
||||
}
|
||||
|
||||
int AbstractArray::find( const Object& o )
|
||||
{
|
||||
if( o == NOOBJECT )
|
||||
return INT_MIN;
|
||||
|
||||
for( int index = 0; index < arraySize(); index++ )
|
||||
if( *(theArray[index]) == o )
|
||||
return boundBase(index);
|
||||
return INT_MIN;
|
||||
}
|
||||
|
||||
inline int isZero( const Object *o )
|
||||
{
|
||||
return o == &NOOBJECT;
|
||||
}
|
||||
|
||||
int AbstractArray::isEqual( const Object& testObject ) const
|
||||
{
|
||||
PRECONDITION( isA() == testObject.isA() );
|
||||
AbstractArray& test = (AbstractArray&)testObject;
|
||||
if( lowerbound != test.lowerbound || upperbound != test.upperbound )
|
||||
return 0;
|
||||
|
||||
for( int i = 0; i < arraySize(); i++ )
|
||||
{
|
||||
if( isZero(theArray[i]) != isZero(test.theArray[i]) )
|
||||
return 0;
|
||||
if( *(theArray[i]) != *(test.theArray[i]) )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ContainerIterator& AbstractArray::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new ArrayIterator( *this ) );
|
||||
}
|
||||
|
||||
void AbstractArray::printContentsOn( ostream& outputStream ) const
|
||||
{
|
||||
ContainerIterator& printIterator = initIterator();
|
||||
printHeader( outputStream );
|
||||
while( printIterator != 0 )
|
||||
{
|
||||
Object& arrayObject = printIterator++;
|
||||
if( arrayObject != NOOBJECT )
|
||||
{
|
||||
arrayObject.printOn( outputStream );
|
||||
if( printIterator != 0 )
|
||||
printSeparator( outputStream );
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
printTrailer( outputStream );
|
||||
delete &printIterator;
|
||||
}
|
||||
|
||||
ArrayIterator::ArrayIterator( const AbstractArray& toIterate ) :
|
||||
beingIterated( toIterate ),
|
||||
currentIndex( toIterate.lowerbound )
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
ArrayIterator::~ArrayIterator()
|
||||
{
|
||||
}
|
||||
|
||||
ArrayIterator::operator int()
|
||||
{
|
||||
return currentIndex <= beingIterated.upperbound;
|
||||
}
|
||||
|
||||
Object& ArrayIterator::current()
|
||||
{
|
||||
if ( currentIndex <= beingIterated.upperbound )
|
||||
return beingIterated.objectAt( currentIndex );
|
||||
else
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
void ArrayIterator::scan()
|
||||
{
|
||||
if( currentIndex > beingIterated.upperbound )
|
||||
return;
|
||||
|
||||
while( ++currentIndex <= beingIterated.upperbound &&
|
||||
beingIterated.objectAt( currentIndex ) == NOOBJECT )
|
||||
; // empty body
|
||||
}
|
||||
|
||||
void ArrayIterator::restart()
|
||||
{
|
||||
currentIndex = beingIterated.lowerbound;
|
||||
if( beingIterated.objectAt( currentIndex ) == NOOBJECT )
|
||||
scan();
|
||||
}
|
||||
|
||||
Object& ArrayIterator::operator ++ ( int )
|
||||
{
|
||||
Object& res = (currentIndex <= beingIterated.upperbound) ?
|
||||
beingIterated.objectAt( currentIndex ) : NOOBJECT;
|
||||
|
||||
scan();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Object& ArrayIterator::operator ++ ()
|
||||
{
|
||||
scan();
|
||||
return (currentIndex <= beingIterated.upperbound) ?
|
||||
beingIterated.objectAt( currentIndex ) : NOOBJECT;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* ARRAY.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __ARRAY_H )
|
||||
#include "classlib\obsolete\array.h"
|
||||
#endif // __ARRAY_H
|
||||
|
||||
void Array::add( Object& toAdd )
|
||||
{
|
||||
lastElementIndex++;
|
||||
while( lastElementIndex <= upperbound &&
|
||||
ptrAt( lastElementIndex ) != ZERO
|
||||
)
|
||||
lastElementIndex++;
|
||||
|
||||
if( lastElementIndex > upperbound )
|
||||
reallocate( lastElementIndex - lowerbound + 1 );
|
||||
|
||||
setData( lastElementIndex, &toAdd );
|
||||
itemsInContainer++;
|
||||
CHECK( itemsInContainer > 0 );
|
||||
}
|
||||
|
||||
void Array::addAt( Object& toAdd, int atIndex )
|
||||
{
|
||||
PRECONDITION( atIndex >= lowerbound );
|
||||
if( atIndex > upperbound )
|
||||
reallocate( atIndex - lowerbound + 1 );
|
||||
|
||||
if( ptrAt( atIndex ) != ZERO )
|
||||
{
|
||||
if( ownsElements() )
|
||||
delete ptrAt( atIndex );
|
||||
itemsInContainer--;
|
||||
}
|
||||
|
||||
setData( atIndex, &toAdd );
|
||||
itemsInContainer++;
|
||||
CHECK( itemsInContainer > 0 );
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* ASSOC.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __ASSOC_H )
|
||||
#include "classlib\obsolete\assoc.h"
|
||||
#endif // __ASSOC_H
|
||||
|
||||
Association::~Association()
|
||||
{
|
||||
if( !ownsElements() )
|
||||
return;
|
||||
if( &aKey != ZERO )
|
||||
delete &aKey;
|
||||
if( &aValue != ZERO )
|
||||
delete &aValue;
|
||||
}
|
||||
|
||||
void Association::printOn( ostream& outputStream ) const
|
||||
{
|
||||
outputStream << " " << nameOf() << " { ";
|
||||
aKey.printOn( outputStream );
|
||||
outputStream << ", ";
|
||||
aValue.printOn( outputStream );
|
||||
outputStream << " }\n";
|
||||
}
|
||||
|
||||
int Association::isEqual( const Object& toObject ) const
|
||||
{
|
||||
return aKey == ( (Association&)toObject ).key();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BABSTARY.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( TEMPLATES )
|
||||
#define TEMPLATES
|
||||
#endif
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __MEM_H )
|
||||
#include <mem.h>
|
||||
#endif // __MEM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __ABSTARRY_H )
|
||||
#include "classlib\obsolete\abstarry.h"
|
||||
#endif // __ABSTARRY_H
|
||||
|
||||
inline int isZero( const Object& o )
|
||||
{
|
||||
return o == NOOBJECT;
|
||||
}
|
||||
|
||||
int AbstractArray::isEqual( const Object& obj ) const
|
||||
{
|
||||
PRECONDITION( isA() == obj.isA() );
|
||||
AbstractArray& test = (AbstractArray&)obj;
|
||||
if( lowerBound() != test.lowerBound() ||
|
||||
upperBound() != test.upperBound()
|
||||
)
|
||||
return 0;
|
||||
|
||||
ContainerIterator& iter1 = initIterator();
|
||||
ContainerIterator& iter2 = test.initIterator();
|
||||
while( iter1 && iter2 )
|
||||
if( iter1.current() != iter2.current() )
|
||||
{
|
||||
delete &iter1;
|
||||
delete &iter2;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter1++;
|
||||
iter2++;
|
||||
}
|
||||
|
||||
delete &iter1;
|
||||
delete &iter2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void AbstractArray::printContentsOn( ostream& outputStream ) const
|
||||
{
|
||||
ContainerIterator& printIterator = initIterator();
|
||||
printHeader( outputStream );
|
||||
while( printIterator != 0 )
|
||||
{
|
||||
Object& arrayObject = printIterator++;
|
||||
if( arrayObject != NOOBJECT )
|
||||
{
|
||||
arrayObject.printOn( outputStream );
|
||||
if( printIterator != 0 )
|
||||
printSeparator( outputStream );
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
printTrailer( outputStream );
|
||||
delete &printIterator;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BDICT.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( TEMPLATES )
|
||||
#define TEMPLATES
|
||||
#endif
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __ASSOC_H )
|
||||
#include "classlib\obsolete\assoc.h"
|
||||
#endif // __ASSOC_H
|
||||
|
||||
#if !defined( __DICT_H )
|
||||
#include "classlib\obsolete\dict.h"
|
||||
#endif // __DICT_H
|
||||
|
||||
#if !defined( __CLSTYPES_H )
|
||||
#include "classlib\obsolete\clstypes.h"
|
||||
#endif // __CLSTYPES_H
|
||||
|
||||
void Dictionary::add( Object& objectToAdd )
|
||||
{
|
||||
if( !objectToAdd.isAssociation() )
|
||||
ClassLib_error( __ENOTASSOC );
|
||||
else
|
||||
Set::add( objectToAdd );
|
||||
}
|
||||
|
||||
Association& Dictionary::lookup( const Object& toLookUp ) const
|
||||
{
|
||||
Association toFind( (Object&)toLookUp, NOOBJECT );
|
||||
toFind.ownsElements(0);
|
||||
|
||||
Association& found = (Association&)findMember( toFind );
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BSORTARY.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( TEMPLATES )
|
||||
#define TEMPLATES
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
#if !defined( __SORTABLE_H )
|
||||
#include "classlib\obsolete\sortable.h"
|
||||
#endif // __SORTABLE_H
|
||||
|
||||
#if !defined( __ARRAYS_H )
|
||||
#include "classlib\arrays.h"
|
||||
#endif // __ARRAYS_H
|
||||
|
||||
void BI_ISObjectVector::add( Object _FAR *o )
|
||||
{
|
||||
if( count_ >= lim )
|
||||
resize( count_+1 );
|
||||
unsigned loc = count_++;
|
||||
while( loc > 0 && *(Sortable _FAR *)o < *(Sortable _FAR *)(void _FAR *)(data[loc-1]) )
|
||||
{
|
||||
data[loc] = data[loc-1];
|
||||
loc--;
|
||||
}
|
||||
data[loc] = o;
|
||||
}
|
||||
|
||||
unsigned BI_ISObjectVector::find( void _FAR * obj ) const
|
||||
{
|
||||
unsigned lower = 0;
|
||||
unsigned upper = count_-1;
|
||||
if( count_ != 0 )
|
||||
{
|
||||
while( lower < upper && upper != UINT_MAX )
|
||||
{
|
||||
unsigned middle = (lower+upper)/2;
|
||||
if( *(const Sortable _FAR *)(void _FAR *)(data[middle]) ==
|
||||
*(const Sortable _FAR *)obj
|
||||
)
|
||||
return middle;
|
||||
if( *(const Sortable _FAR *)(const void _FAR *)(data[middle]) <
|
||||
*(const Sortable _FAR *)obj
|
||||
)
|
||||
lower = middle+1;
|
||||
else
|
||||
upper = middle-1;
|
||||
}
|
||||
}
|
||||
if( lower == upper &&
|
||||
*(const Sortable _FAR *)(const void _FAR *)(data[lower]) == *(const Sortable _FAR *)obj
|
||||
)
|
||||
return lower;
|
||||
else
|
||||
return UINT_MAX;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,496 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BTREE.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __BTREE_H )
|
||||
#include "classlib\obsolete\btree.h"
|
||||
#endif // __BTREE_H
|
||||
|
||||
/*
|
||||
|
||||
Implementation notes:
|
||||
|
||||
This implements B-trees with several refinements. Most of them can be found
|
||||
in Knuth Vol 3, but some were developed to adapt to restrictions imposed
|
||||
by C++. First, a restatement of Knuth's properties that a B-tree must
|
||||
satisfy, assuming we make the enhancement he suggests in the paragraph
|
||||
at the bottom of page 476. Instead of storing null pointers to non-existent
|
||||
nodes (which Knuth calls the leaves) we utilize the space to store keys.
|
||||
Therefore, what Knuth calls level (l-1) is the bottom of our tree, and
|
||||
we call the nodes at this level LeafNodes. Other nodes are called InnerNodes.
|
||||
The other enhancement we have adopted is in the paragraph at the bottom of
|
||||
page 477: overflow control.
|
||||
|
||||
The following are modifications of Knuth's properties on page 478:
|
||||
|
||||
i) Every InnerNode has at most Order keys, and at most Order+1 sub-trees.
|
||||
ii) Every LeafNode has at most 2*(Order+1) keys.
|
||||
iii)An InnerNode with k keys has k+1 sub-trees.
|
||||
iv) Every InnerNode that is not the root has at least InnerLowWaterMark keys.
|
||||
v) Every LeafNode that is not the root has at least LeafLowWaterMark keys.
|
||||
vi) If the root is a LeafNode, it has at least one key.
|
||||
vii)If the root is an InnerNode, it has at least one key and two sub-trees.
|
||||
viii)All LeafNodes are the same distance from the root as all the other
|
||||
LeafNodes.
|
||||
ix) For InnerNode n with key n[i].key, then sub-tree n[i-1].tree contains
|
||||
all keys <= n[i].key, and sub-tree n[i].tree contains all keys >= n[i].key.
|
||||
x) Order is at least 3.
|
||||
|
||||
The values of InnerLowWaterMark and LeafLowWaterMark may actually be set
|
||||
by the user when the tree is initialized, but currently they are set
|
||||
automatically to:
|
||||
InnerLowWaterMark = ceiling(Order/2)
|
||||
LeafLowWaterMark = Order - 1
|
||||
|
||||
If the tree is only filled, then all the nodes will be at least 2/3 full.
|
||||
They will almost all be exactly 2/3 full if the elements are added to the
|
||||
tree in order (either increasing or decreasing). [Knuth says McCreight's
|
||||
experiments showed almost 100% memory utilization. I don't see how that
|
||||
can be given the algorithms that Knuth gives. McCreight must have used
|
||||
a different scheme for balancing. [ No, he used a different scheme for
|
||||
splitting: he did a two-way split instead of the three way split as we do
|
||||
here. Which means that McCreight does better on insertion of ordered data,
|
||||
but we should do better on insertion of random data.]]
|
||||
|
||||
It must also be noted that B-trees were designed for DISK access algorithms,
|
||||
not necessarily in-memory sorting, as we intend it to be used here. However,
|
||||
if the order is kept small (< 6?) any inefficiency is negligible for
|
||||
in-memory sorting. Knuth points out that balanced trees are actually
|
||||
preferable for memory sorting. I'm not sure that I believe this, but
|
||||
it's interesting. Also, deleting elements from balanced binary trees, being
|
||||
beyond the scope of Knuth's book (p. 465), is beyond my scope. B-trees
|
||||
are good enough.
|
||||
|
||||
|
||||
A B-tree is declared to be of a certain ORDER (4 by default). This number
|
||||
determines the number of keys contained in any interior node of the tree.
|
||||
Each interior node will contain ORDER keys, and therefore ORDER+1 pointers
|
||||
to sub-trees. The keys are numbered and indexed 1 to ORDER while the
|
||||
pointers are numbered and indexed 0 to ORDER. The 0th ptr points to the
|
||||
sub-tree of all elements that are less than key[1]. Ptr[1] points to the
|
||||
sub-tree that contains all the elements greater than key[1] and less than
|
||||
key[2]. etc. The array of pointers and keys is allocated as ORDER+1
|
||||
pairs of keys and nodes, meaning that one key field (key[0]) is not used
|
||||
and therefore wasted. Given that the number of interior nodes is
|
||||
small, that this waste allows fewer cases of special code, and that it
|
||||
is useful in certain of the methods, it was felt to be a worthwhile waste.
|
||||
|
||||
The size of the exterior nodes (leaf nodes) does not need to be related to
|
||||
the size of the interior nodes at all. Since leaf nodes contain only
|
||||
keys, they may be as large or small as we like independent of the size
|
||||
of the interior nodes. For no particular reason other than it seems like
|
||||
a good idea, we will allocate 2*(ORDER+1) keys in each leaf node, and they
|
||||
will be numbered and indexed from 0 to 2*ORDER+1. It does have the advantage
|
||||
of keeping the size of the leaf and interior arrays the same, so that if we
|
||||
find allocation and de-allocation of these arrays expensive, we can modify
|
||||
their allocation to use a garbage ring, or something.
|
||||
|
||||
Both of these numbers will be run-time constants associated with each tree
|
||||
(each tree at run-time can be of a different order). The variable `order'
|
||||
is the order of the tree, and the inclusive upper limit on the indices of
|
||||
the keys in the interior nodes. The variable `order2' is the inclusive
|
||||
upper limit on the indices of the leaf nodes, and is designed
|
||||
(1) to keep the sizes of the two kinds of nodes the same;
|
||||
(2) to keep the expressions involving the arrays of keys looking
|
||||
somewhat the same: lower limit upper limit
|
||||
for inner nodes: 1 order
|
||||
for leaf nodes: 0 order2
|
||||
Remember that index 0 of the inner nodes is special.
|
||||
|
||||
Currently, order2 = 2*(order+1).
|
||||
|
||||
picture: (also see Knuth Vol 3 pg 478)
|
||||
|
||||
+--+--+--+--+--+--...
|
||||
| | | | | |
|
||||
parent--->| | | |
|
||||
| | | |
|
||||
+*-+*-+*-+--+--+--...
|
||||
| | |
|
||||
+----+ | +-----+
|
||||
| +-----+ |
|
||||
V | V
|
||||
+----------+ | +----------+
|
||||
| | | | |
|
||||
this->| | | | |<--sib
|
||||
+----------+ | +----------+
|
||||
V
|
||||
data
|
||||
|
||||
It is conceptually VERY convenient to think of the data as being the
|
||||
very first element of the sib node. Any primitive that tells sib to
|
||||
perform some action on n nodes should include this `hidden' element.
|
||||
For InnerNodes, the hidden element has (physical) index 0 in the array,
|
||||
and in LeafNodes, the hidden element has (virtual) index -1 in the array.
|
||||
Therefore, there are two `size' primitives for nodes:
|
||||
Psize - the physical size: how many elements are contained in the
|
||||
array in the node.
|
||||
Vsize - the `virtual' size; if the node is pointed to by
|
||||
element 0 of the parent node, then Vsize == Psize;
|
||||
otherwise the element in the parent item that points to this
|
||||
node `belongs' to this node, and Vsize == Psize+1;
|
||||
|
||||
Parent nodes are always InnerNodes.
|
||||
|
||||
These are the primitive operations on Nodes:
|
||||
|
||||
append(elt) - adds an element to the end of the array of elements in a
|
||||
node. It must never be called where appending the element
|
||||
would fill the node.
|
||||
split() - divide a node in two, and create two new nodes.
|
||||
splitWith(sib) - create a third node between this node and the sib node,
|
||||
divvying up the elements of their arrays.
|
||||
pushLeft(n) - move n elements into the left sibling
|
||||
pushRight(n) - move n elements into the right sibling
|
||||
balanceWithRight() - even up the number of elements in the two nodes.
|
||||
balanceWithLeft() - ditto
|
||||
|
||||
|
||||
To allow this implementation of btrees to also be an implementation of
|
||||
sorted arrays/lists, the overhead is included to allow O(log n) access
|
||||
of elements by their rank (`give me the 5th largest element').
|
||||
Therefore, each Item keeps track of the number of keys in and below it
|
||||
in the tree (remember, each item's tree is all keys to the RIGHT of the
|
||||
item's own key).
|
||||
|
||||
[ [ < 0 1 2 3 > 4 < 5 6 7 > 8 < 9 10 11 12 > ] 13 [ < 14 15 16 > 17 < 18 19 20 > ] ]
|
||||
4 1 1 1 1 4 1 1 1 5 1 1 1 1 7 3 1 1 1 4 1 1 1
|
||||
*/
|
||||
|
||||
//====== Btree functions ========
|
||||
|
||||
void Btree::finishInit( int O )
|
||||
{
|
||||
if( O < 3 )
|
||||
ClassLib_error( __EORDER3 );
|
||||
ownsElements( 0 );
|
||||
root = 0;
|
||||
Order = O;
|
||||
Order2 = 2 * (O+1);
|
||||
Leaf_MaxIndex = Order2 - 1; // item[0..Order2-1]
|
||||
Inner_MaxIndex = Order; // item[1..Order]
|
||||
//
|
||||
// the low water marks trigger an exploration for balancing
|
||||
// or merging nodes.
|
||||
// When the size of a node falls below X, then it must be possible to
|
||||
// either balance this node with another node, or it must be possible
|
||||
// to merge this node with another node.
|
||||
// This can be guaranteed only if (this->size() < (maxSize()-1)/2).
|
||||
//
|
||||
//
|
||||
Leaf_LowWaterMark = ((Leaf_MaxIndex+1 // == maxSize()
|
||||
)-1) / 2 // satisfies the above
|
||||
- 1; // because we compare
|
||||
// lowwatermark with last
|
||||
|
||||
Inner_LowWaterMark = (Order-1) / 2;
|
||||
}
|
||||
|
||||
Btree::Btree(int O) : itemsInContainer(0)
|
||||
{
|
||||
finishInit(O);
|
||||
}
|
||||
|
||||
Btree::~Btree(void)
|
||||
{
|
||||
if( root != 0 )
|
||||
delete root;
|
||||
}
|
||||
|
||||
void Btree::flush( DeleteType dt )
|
||||
{
|
||||
int oldValue = ownsElements();
|
||||
ownsElements( delObj(dt) );
|
||||
if( root != 0 )
|
||||
delete root;
|
||||
itemsInContainer = 0;
|
||||
root = 0;
|
||||
ownsElements( oldValue );
|
||||
}
|
||||
|
||||
int Btree::hasMember( Object& o ) const
|
||||
{
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error( __ENOTSORT );
|
||||
if( root == 0 )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
Node* loc;
|
||||
int idx;
|
||||
return root->found(&(Sortable&)o, &loc, &idx) != NOOBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
long Btree::rank( const Object& o ) const
|
||||
{
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error( __ENOTSORT );
|
||||
if( root == 0 )
|
||||
return -1;
|
||||
else
|
||||
return root->findRank(&(Sortable&)o);
|
||||
}
|
||||
|
||||
Object& Btree::findMember( Object& o ) const
|
||||
{
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error(__ENOTSORT);
|
||||
if( root == 0 )
|
||||
return NOOBJECT;
|
||||
else
|
||||
{
|
||||
Node* loc;
|
||||
int idx;
|
||||
return root->found(&(Sortable&)o, &loc, &idx);
|
||||
}
|
||||
}
|
||||
|
||||
void Btree::printOn( ostream& out ) const
|
||||
{
|
||||
if( root == 0 )
|
||||
out << "<empty>" ;
|
||||
else
|
||||
root->printOn(out);
|
||||
}
|
||||
|
||||
extern "C" void __ErrorMessage( const char * );
|
||||
|
||||
int Btree::isEqual( const Object& obj ) const
|
||||
{
|
||||
if( obj.isA() == btreeClass )
|
||||
{
|
||||
__ErrorMessage( "Btree isEqual not implemented\n" );
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
|
||||
// two btrees are equal only if they have the same number of
|
||||
// elements, and they are all equal. The structure of the tree
|
||||
// itself doesn't enter into it.
|
||||
}
|
||||
|
||||
|
||||
long Btree::i_add( const Object& o )
|
||||
{
|
||||
long r;
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error( __ENOTSORT );
|
||||
if( root == 0 )
|
||||
{
|
||||
root = new LeafNode( 0, &(Sortable&)o, this );
|
||||
CHECK( root != 0 );
|
||||
incrNofKeys();
|
||||
r = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node* loc;
|
||||
int idx;
|
||||
if( root->found(&(Sortable&)o, &loc, &idx) != NOOBJECT )
|
||||
{
|
||||
// loc and idx are set to either where the object
|
||||
// was found, or where it should go in the Btree.
|
||||
// Nothing is here now, but later we might give the user
|
||||
// the ability to declare a B-tree as `unique elements only',
|
||||
// in which case we would handle an exception here.
|
||||
// cerr << "Multiple entry warning\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK( loc->isLeaf );
|
||||
}
|
||||
if( loc->isLeaf )
|
||||
{
|
||||
if( loc->parent == 0 )
|
||||
r = idx;
|
||||
else
|
||||
r = idx + loc->parent->findRank_bu( loc );
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerNode *iloc = (InnerNode*)loc;
|
||||
r = iloc->findRank_bu( iloc->getTree( idx ) );
|
||||
}
|
||||
loc->add( &(Sortable&)o, idx );
|
||||
}
|
||||
CHECK( r == rank( (Sortable&)o ) || (Sortable&)o == (*this)[r] );
|
||||
return r;
|
||||
}
|
||||
|
||||
void Btree::add( Object& o )
|
||||
{
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error( __ENOTSORT );
|
||||
if (root == 0)
|
||||
{
|
||||
root = new LeafNode( 0, &(Sortable&)o, this );
|
||||
CHECK( root != 0 );
|
||||
incrNofKeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
Node* loc;
|
||||
int idx;
|
||||
if( root->found(&(Sortable&)o, &loc, &idx) != NOOBJECT )
|
||||
{
|
||||
// loc and idx are set to either where the object
|
||||
// was found, or where it should go in the Btree.
|
||||
// Nothing is here now, but later we might give the user
|
||||
// the ability to declare a B-tree as `unique elements only',
|
||||
// in which case we would handle an exception here.
|
||||
}
|
||||
loc->add( &(Sortable&)o, idx );
|
||||
}
|
||||
}
|
||||
|
||||
void Btree::detach( Object& o, DeleteType dt )
|
||||
{
|
||||
if( !o.isSortable() )
|
||||
ClassLib_error(__ENOTSORT);
|
||||
if( root == 0 )
|
||||
return;
|
||||
|
||||
Node* loc;
|
||||
int idx;
|
||||
Object* obj = &(root->found( &(Sortable&)o, &loc, &idx ));
|
||||
if( *obj == NOOBJECT )
|
||||
return;
|
||||
loc->remove( idx );
|
||||
if( delObj(dt) )
|
||||
delete obj;
|
||||
}
|
||||
|
||||
void Btree::rootIsFull()
|
||||
{
|
||||
// the root of the tree is full; create an InnerNode that
|
||||
// points to it, and then inform the InnerNode that it is full.
|
||||
Node* oldroot = root;
|
||||
root = new InnerNode( 0, this, oldroot );
|
||||
CHECK( root != 0 );
|
||||
oldroot->split();
|
||||
}
|
||||
|
||||
void Btree::rootIsEmpty()
|
||||
{
|
||||
if( root->isLeaf )
|
||||
{
|
||||
LeafNode* lroot = (LeafNode*)root;
|
||||
CHECK( lroot->Psize() == 0 );
|
||||
delete lroot;
|
||||
root = 0;
|
||||
}
|
||||
else {
|
||||
InnerNode* iroot = (InnerNode*)root;
|
||||
CHECK(iroot->Psize() == 0);
|
||||
root = iroot->getTree(0);
|
||||
root->parent = 0;
|
||||
delete iroot;
|
||||
}
|
||||
}
|
||||
|
||||
Item::Item()
|
||||
{
|
||||
nofKeysInTree = 0;
|
||||
tree = 0;
|
||||
key = 0;
|
||||
}
|
||||
|
||||
Item::Item(Node* n, Sortable* o)
|
||||
{
|
||||
nofKeysInTree = n->nofKeys()+1;
|
||||
tree = n;
|
||||
key = o;
|
||||
}
|
||||
|
||||
Item::Item(Sortable* o, Node* n)
|
||||
{
|
||||
nofKeysInTree = n->nofKeys()+1;
|
||||
tree = n;
|
||||
key = o;
|
||||
}
|
||||
|
||||
Item::~Item()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//====== Node functions ======
|
||||
//
|
||||
|
||||
Node::Node(int isleaf, InnerNode* P, Btree* T)
|
||||
{
|
||||
// nofElts = 0;
|
||||
last = -1;
|
||||
isLeaf = isleaf;
|
||||
parent = P;
|
||||
if( P == 0 )
|
||||
{
|
||||
CHECK( T != 0 );
|
||||
tree = T;
|
||||
}
|
||||
else
|
||||
tree = P->tree;
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//===== BtreeIterator methods =====
|
||||
//
|
||||
|
||||
void BtreeIterator::restart()
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
Object& BtreeIterator::operator++()
|
||||
{
|
||||
return beingIterated[++index];
|
||||
}
|
||||
|
||||
Object& BtreeIterator::operator++( int )
|
||||
{
|
||||
return beingIterated[index++];
|
||||
}
|
||||
|
||||
Object& BtreeIterator::current()
|
||||
{
|
||||
return beingIterated[index];
|
||||
}
|
||||
|
||||
|
||||
ContainerIterator&
|
||||
Btree::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new BtreeIterator( *this ) );
|
||||
}
|
||||
|
||||
BtreeIterator::~BtreeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BtreeIterator::operator int()
|
||||
{
|
||||
return index < beingIterated.getItemsInContainer();
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BTREEINN.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __BTREE_H )
|
||||
#include "classlib\obsolete\btree.h"
|
||||
#endif // __BTREE_H
|
||||
|
||||
//====== InnerNode functions ======
|
||||
|
||||
InnerNode::InnerNode(InnerNode* P, Btree* T) : Node(0,P,T)
|
||||
{
|
||||
item = new Item[maxIndex()+1];
|
||||
if( item == 0 )
|
||||
ClassLib_error( __ENOMEMIA );
|
||||
}
|
||||
|
||||
InnerNode::InnerNode(InnerNode* Parent, Btree* Tree, Node* oldroot)
|
||||
: Node(0, Parent, Tree)
|
||||
{
|
||||
// called only by Btree to initialize the InnerNode that is
|
||||
// about to become the root.
|
||||
item = new Item[maxIndex()+1];
|
||||
if( item == 0 )
|
||||
ClassLib_error( __ENOMEMIA );
|
||||
append( 0, oldroot );
|
||||
}
|
||||
|
||||
InnerNode::~InnerNode()
|
||||
{
|
||||
if( last > 0 )
|
||||
delete item[0].tree;
|
||||
for( int i = 1; i <= last; i++ )
|
||||
{
|
||||
delete item[i].tree;
|
||||
if( tree->ownsElements() )
|
||||
delete item[i].key;
|
||||
}
|
||||
delete [] item;
|
||||
}
|
||||
|
||||
// for quick (human reader) lookup, functions are in alphabetical order
|
||||
|
||||
void InnerNode::add( Sortable *obj, int index )
|
||||
{
|
||||
// this is called only from Btree::add()
|
||||
PRECONDITION( index >= 1 );
|
||||
LeafNode* ln = getTree(index-1)->lastLeafNode();
|
||||
ln->add( obj, ln->last+1 );
|
||||
}
|
||||
|
||||
void InnerNode::addElt( Item& itm, int at )
|
||||
{
|
||||
PRECONDITION( 0 <= at && at <= last+1 );
|
||||
PRECONDITION( last < maxIndex() );
|
||||
for( int i = last+1; i > at ; i-- )
|
||||
getItem(i) = getItem(i-1);
|
||||
setItem( at, itm );
|
||||
last++;
|
||||
}
|
||||
|
||||
void InnerNode::addElt( int at, Sortable* k, Node* t)
|
||||
{
|
||||
Item newitem( k, t );
|
||||
addElt( newitem, at );
|
||||
}
|
||||
|
||||
void InnerNode::add( Item& itm, int at )
|
||||
{
|
||||
addElt( itm, at );
|
||||
if( isFull() )
|
||||
informParent();
|
||||
}
|
||||
|
||||
void InnerNode::add( int at, Sortable* k, Node* t)
|
||||
{
|
||||
Item newitem( k, t );
|
||||
add( newitem, at );
|
||||
}
|
||||
|
||||
void InnerNode::appendFrom( InnerNode* src, int start, int stop )
|
||||
{
|
||||
// this should never create a full node
|
||||
// that is, it is not used anywhere where THIS could possibly be
|
||||
// near full.
|
||||
if( start > stop )
|
||||
return;
|
||||
PRECONDITION( 0 <= start && start <= src->last );
|
||||
PRECONDITION( 0 <= stop && stop <= src->last );
|
||||
PRECONDITION( last + stop - start + 1 < maxIndex() ); // full-node check
|
||||
for( int i = start; i <= stop; i++ )
|
||||
setItem( ++last, src->getItem(i) );
|
||||
}
|
||||
|
||||
void InnerNode::append( Sortable* D, Node* N )
|
||||
{
|
||||
// never called from anywhere where it might fill up THIS
|
||||
PRECONDITION( last < maxIndex() );
|
||||
setItem( ++last, D, N );
|
||||
}
|
||||
|
||||
void InnerNode::append( Item& itm )
|
||||
{
|
||||
PRECONDITION( last < maxIndex() );
|
||||
setItem( ++last, itm );
|
||||
}
|
||||
|
||||
void InnerNode::balanceWithLeft( InnerNode* leftsib, int pidx )
|
||||
{
|
||||
// THIS has more than LEFTSIB; move some item from THIS to LEFTSIB.
|
||||
// PIDX is the index of the parent item that will change when keys
|
||||
// are moved.
|
||||
PRECONDITION( Vsize() >= leftsib->Psize() );
|
||||
PRECONDITION( parent->getTree(pidx) == this );
|
||||
int newThisSize = (Vsize() + leftsib->Psize())/2;
|
||||
int noFromThis = Psize() - newThisSize;
|
||||
pushLeft( noFromThis, leftsib, pidx );
|
||||
}
|
||||
|
||||
void InnerNode::balanceWithRight( InnerNode* rightsib, int pidx )
|
||||
{
|
||||
// THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB.
|
||||
// PIDX is the index of the parent item that will change when keys
|
||||
// are moved.
|
||||
PRECONDITION( Psize() >= rightsib->Vsize() );
|
||||
PRECONDITION( parent->getTree(pidx) == rightsib );
|
||||
int newThisSize = (Psize() + rightsib->Vsize())/2;
|
||||
int noFromThis = Psize() - newThisSize;
|
||||
pushRight( noFromThis, rightsib, pidx );
|
||||
|
||||
}
|
||||
|
||||
void InnerNode::balanceWith( InnerNode* rightsib, int pindx )
|
||||
{
|
||||
// PINDX is the index of the parent item whose key will change when
|
||||
// keys are shifted from one InnerNode to the other.
|
||||
if( Psize() < rightsib->Vsize() )
|
||||
rightsib->balanceWithLeft( this, pindx );
|
||||
else
|
||||
balanceWithRight( rightsib, pindx );
|
||||
}
|
||||
|
||||
void InnerNode::decrNofKeys( Node *that )
|
||||
{
|
||||
// THAT is a child of THIS that has just shrunk by 1
|
||||
int i = indexOf( that );
|
||||
item[i].nofKeysInTree--;
|
||||
if( parent != 0 )
|
||||
parent->decrNofKeys( this );
|
||||
else
|
||||
tree->decrNofKeys();
|
||||
}
|
||||
|
||||
long InnerNode::findRank( Sortable* what ) const
|
||||
{
|
||||
// recursively look for WHAT starting in the current node
|
||||
|
||||
if ( *what < *getKey(1) )
|
||||
return getTree(0)->findRank(what);
|
||||
long sum = getNofKeys(0);
|
||||
for( int i = 1; i < last; i++ )
|
||||
{
|
||||
if( *what == *getKey(i) )
|
||||
return sum;
|
||||
sum++;
|
||||
if( *what < *getKey(i+1) )
|
||||
return sum + getTree(i)->findRank(what);
|
||||
sum += getNofKeys(i);
|
||||
}
|
||||
if( *what == *getKey(last) )
|
||||
return sum;
|
||||
sum++;
|
||||
// *what > getKey(last), so recurse on last item.tree
|
||||
return sum + getTree(last)->findRank(what);
|
||||
}
|
||||
|
||||
long InnerNode::findRank_bu( const Node *that ) const
|
||||
{
|
||||
// findRank_bu is findRank in reverse.
|
||||
// whereas findRank looks for the object and computes the rank
|
||||
// along the way while walking DOWN the tree, findRank_bu already
|
||||
// knows where the object is and has to walk UP the tree from the
|
||||
// object to compute the rank.
|
||||
int L = indexOf( that );
|
||||
long sum = 0;
|
||||
for( int i = 0; i < L; i++ )
|
||||
sum += getNofKeys(i);
|
||||
return sum + L + (parent == 0 ? 0 : parent->findRank_bu( this ));
|
||||
}
|
||||
|
||||
LeafNode*InnerNode::firstLeafNode()
|
||||
{
|
||||
return getTree(0)->firstLeafNode();
|
||||
}
|
||||
|
||||
Object& InnerNode::found(Sortable* what, Node** which, int* where )
|
||||
{
|
||||
// recursively look for WHAT starting in the current node
|
||||
for( int i = 1 ; i <= last; i++ )
|
||||
{
|
||||
if( *getKey(i) == *what )
|
||||
{
|
||||
// then could go in either item[i].tree or item[i-1].tree
|
||||
// should go in one with the most room, but that's kinda
|
||||
// hard to calculate, so we'll stick it in item[i].tree
|
||||
*which = this;
|
||||
*where = i;
|
||||
return *getKey(i);
|
||||
}
|
||||
if( *getKey(i) > *what )
|
||||
return getTree(i-1)->found(what, which, where);
|
||||
}
|
||||
// *what > *(*this)[last].key, so recurse on last item.tree
|
||||
return getTree(last)->found( what, which, where );
|
||||
}
|
||||
|
||||
void InnerNode::incrNofKeys( Node *that )
|
||||
{
|
||||
// THAT is a child of THIS that has just grown by 1
|
||||
int i = indexOf( that );
|
||||
item[i].nofKeysInTree++;
|
||||
if( parent != 0 )
|
||||
parent->incrNofKeys( this );
|
||||
else
|
||||
tree->incrNofKeys();
|
||||
}
|
||||
|
||||
#pragma warn -rvl
|
||||
|
||||
int InnerNode::indexOf( const Node *that ) const
|
||||
{
|
||||
// returns a number in the range 0 to this->last
|
||||
// 0 is returned if THAT == tree[0]
|
||||
for( int i = 0; i <= last; i++ )
|
||||
if( getTree(i) == that )
|
||||
return i;
|
||||
CHECK( 0 );
|
||||
}
|
||||
|
||||
#pragma warn .rvl
|
||||
|
||||
void InnerNode::informParent()
|
||||
{
|
||||
if( parent == 0 )
|
||||
{
|
||||
// then this is the root of the tree and nees to be split
|
||||
// inform the btree.
|
||||
PRECONDITION( tree->root == this );
|
||||
tree->rootIsFull();
|
||||
}
|
||||
else
|
||||
parent->isFull( this );
|
||||
}
|
||||
|
||||
void InnerNode::isFull(Node *that)
|
||||
{
|
||||
// the child node THAT is full. We will either redistribute elements
|
||||
// or create a new node and then redistribute.
|
||||
// In an attempt to minimize the number of splits, we adopt the following
|
||||
// strategy:
|
||||
// * redistribute if possible
|
||||
// * if not possible, then split with a sibling
|
||||
if( that->isLeaf )
|
||||
{
|
||||
LeafNode *leaf = (LeafNode *)that;
|
||||
LeafNode *left, *right;
|
||||
// split LEAF only if both sibling nodes are full.
|
||||
int leafidx = indexOf(leaf);
|
||||
int hasRightSib = (leafidx < last)
|
||||
&& ((right=(LeafNode*)getTree(leafidx+1))
|
||||
!= 0);
|
||||
int hasLeftSib = (leafidx > 0)
|
||||
&& ((left=(LeafNode*)getTree(leafidx-1))
|
||||
!= 0);
|
||||
int rightSibFull = (hasRightSib && right->isAlmostFull());
|
||||
int leftSibFull = (hasLeftSib && left->isAlmostFull());
|
||||
if( rightSibFull )
|
||||
{
|
||||
if( leftSibFull )
|
||||
{
|
||||
// both full, so pick one to split with
|
||||
left->splitWith( leaf, leafidx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
// left sib not full, so balance with it
|
||||
leaf->balanceWithLeft( left, leafidx );
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no left sibling, so split with right
|
||||
leaf->splitWith( right, leafidx+1 );
|
||||
}
|
||||
}
|
||||
else if( hasRightSib )
|
||||
{
|
||||
// right sib not full, so balance with it
|
||||
leaf->balanceWithRight( right, leafidx+1 );
|
||||
}
|
||||
else if( leftSibFull )
|
||||
{
|
||||
// no right sib, and left sib is full, so split with it
|
||||
left->splitWith( leaf, leafidx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
// left sib not full so balance with it
|
||||
leaf->balanceWithLeft( left, leafidx );
|
||||
}
|
||||
else
|
||||
{
|
||||
// neither a left or right sib; should never happen
|
||||
CHECK(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
InnerNode *inner = (InnerNode *)that;
|
||||
// split INNER only if both sibling nodes are full.
|
||||
int inneridx = indexOf(inner);
|
||||
InnerNode *left, *right;
|
||||
int hasRightSib = (inneridx < last)
|
||||
&& ((right=(InnerNode*)getTree(inneridx+1))
|
||||
!= 0);
|
||||
int hasLeftSib = (inneridx > 0)
|
||||
&& ((left=(InnerNode*)getTree(inneridx-1))
|
||||
!= 0);
|
||||
int rightSibFull = (hasRightSib && right->isAlmostFull());
|
||||
int leftSibFull = (hasLeftSib && left->isAlmostFull());
|
||||
if( rightSibFull )
|
||||
{
|
||||
if( leftSibFull )
|
||||
{
|
||||
left->splitWith( inner, inneridx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
inner->balanceWithLeft( left, inneridx );
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no left sibling
|
||||
inner->splitWith(right, inneridx+1);
|
||||
}
|
||||
}
|
||||
else if( hasRightSib )
|
||||
{
|
||||
inner->balanceWithRight( right, inneridx+1 );
|
||||
}
|
||||
else if( leftSibFull )
|
||||
{
|
||||
left->splitWith( inner, inneridx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
inner->balanceWithLeft( left, inneridx );
|
||||
}
|
||||
else {
|
||||
CHECK(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InnerNode::isLow( Node *that )
|
||||
{
|
||||
// the child node THAT is <= half full. We will either redistribute
|
||||
// elements between children, or THAT will be merged with another child.
|
||||
// In an attempt to minimize the number of mergers, we adopt the following
|
||||
// strategy:
|
||||
// * redistribute if possible
|
||||
// * if not possible, then merge with a sibling
|
||||
if( that->isLeaf )
|
||||
{
|
||||
LeafNode *leaf = (LeafNode *)that;
|
||||
LeafNode *left, *right;
|
||||
// split LEAF only if both sibling nodes are full.
|
||||
int leafidx = indexOf(leaf);
|
||||
int hasRightSib = (leafidx < last)
|
||||
&& ((right=(LeafNode*)getTree(leafidx+1))
|
||||
!= 0);
|
||||
int hasLeftSib = (leafidx > 0)
|
||||
&& ((left=(LeafNode*)getTree(leafidx-1))
|
||||
!= 0);
|
||||
if( hasRightSib
|
||||
&& (leaf->Psize() + right->Vsize()) >= leaf->maxPsize())
|
||||
{
|
||||
// then cannot merge,
|
||||
// and balancing this and rightsib will leave them both
|
||||
// more than half full
|
||||
leaf->balanceWith( right, leafidx+1 );
|
||||
}
|
||||
else if( hasLeftSib
|
||||
&& (leaf->Vsize() + left->Psize()) >= leaf->maxPsize())
|
||||
{
|
||||
// ditto
|
||||
left->balanceWith( leaf, leafidx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
// then they should be merged
|
||||
left->mergeWithRight( leaf, leafidx );
|
||||
}
|
||||
else if( hasRightSib )
|
||||
{
|
||||
leaf->mergeWithRight( right, leafidx+1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(0); // should never happen
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerNode *inner = (InnerNode *)that;
|
||||
//
|
||||
int inneridx = indexOf(inner);
|
||||
InnerNode *left, *right;
|
||||
int hasRightSib = (inneridx < last)
|
||||
&& ((right=(InnerNode*)getTree(inneridx+1))
|
||||
!= 0);
|
||||
int hasLeftSib = (inneridx > 0)
|
||||
&& ((left=(InnerNode*)getTree(inneridx-1))
|
||||
!= 0);
|
||||
if( hasRightSib
|
||||
&& (inner->Psize() + right->Vsize()) >= inner->maxPsize())
|
||||
{
|
||||
// cannot merge
|
||||
inner->balanceWith( right, inneridx+1 );
|
||||
}
|
||||
else if( hasLeftSib
|
||||
&& (inner->Vsize() + left->Psize()) >= inner->maxPsize())
|
||||
{
|
||||
// cannot merge
|
||||
left->balanceWith( inner, inneridx );
|
||||
}
|
||||
else if( hasLeftSib )
|
||||
{
|
||||
left->mergeWithRight( inner, inneridx );
|
||||
}
|
||||
else if( hasRightSib )
|
||||
{
|
||||
inner->mergeWithRight( right, inneridx+1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeafNode*InnerNode::lastLeafNode()
|
||||
{
|
||||
return getTree(last)->lastLeafNode();
|
||||
}
|
||||
|
||||
void InnerNode::mergeWithRight( InnerNode* rightsib, int pidx )
|
||||
{
|
||||
PRECONDITION( Psize() + rightsib->Vsize() < maxIndex() );
|
||||
if( rightsib->Psize() > 0 )
|
||||
rightsib->pushLeft( rightsib->Psize(), this, pidx );
|
||||
rightsib->setKey( 0, parent->getKey( pidx ) );
|
||||
appendFrom( rightsib, 0, 0 );
|
||||
parent->incNofKeys( pidx-1, rightsib->getNofKeys(0)+1 );
|
||||
parent->removeItem( pidx );
|
||||
delete rightsib;
|
||||
}
|
||||
|
||||
long InnerNode::nofKeys() const
|
||||
{
|
||||
long sum = 0;
|
||||
for( int i = 0; i <= last; i++)
|
||||
sum += getNofKeys(i);
|
||||
return sum + Psize();
|
||||
}
|
||||
|
||||
Object& InnerNode::operator[]( long idx ) const
|
||||
{
|
||||
for( int j=0; j <= last; j++ )
|
||||
{
|
||||
long R;
|
||||
if( idx < (R = getNofKeys(j)) )
|
||||
return (*getTree(j))[idx];
|
||||
if( idx == R )
|
||||
{
|
||||
if( j == last )
|
||||
return NOOBJECT;
|
||||
else
|
||||
return *getKey(j+1);
|
||||
}
|
||||
idx -= R+1; // +1 because of the key in the node
|
||||
}
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
void InnerNode::printOn(ostream& out) const
|
||||
{
|
||||
out << " [ " << "/" << getNofKeys(0) << *getTree(0);
|
||||
for( int i = 1; i <= last; i++ )
|
||||
{
|
||||
if( i > 1 )
|
||||
CHECK( *getKey(i-1) <= *getKey(i) );
|
||||
out << *getKey(i) << "/" << getNofKeys(i) << *getTree(i);
|
||||
}
|
||||
out << " ] ";
|
||||
}
|
||||
|
||||
void InnerNode::pushLeft( int noFromThis, InnerNode* leftsib, int pidx )
|
||||
{
|
||||
// noFromThis==1 => moves the parent item into the leftsib,
|
||||
// and the first item in this's array into the parent item
|
||||
PRECONDITION( parent->getTree(pidx) == this );
|
||||
PRECONDITION( noFromThis > 0 && noFromThis <= Psize() );
|
||||
PRECONDITION( noFromThis + leftsib->Psize() < maxPsize() );
|
||||
setKey( 0, parent->getKey(pidx) ); // makes appendFrom's job easier
|
||||
leftsib->appendFrom( this, 0, noFromThis-1 );
|
||||
shiftLeft( noFromThis );
|
||||
parent->setKey( pidx, getKey(0) );
|
||||
parent->setNofKeys( pidx-1, leftsib->nofKeys() );
|
||||
parent->setNofKeys( pidx, nofKeys() );
|
||||
}
|
||||
|
||||
void InnerNode::pushRight(int noFromThis, InnerNode* rightsib, int pidx)
|
||||
{
|
||||
PRECONDITION( noFromThis > 0 && noFromThis <= Psize() );
|
||||
PRECONDITION( noFromThis + rightsib->Psize() < rightsib->maxPsize() );
|
||||
PRECONDITION( parent->getTree(pidx) == rightsib );
|
||||
//
|
||||
// The operation is three steps:
|
||||
// Step I. Make room for the incoming keys in RIGHTSIB.
|
||||
// Step II. Move the items from THIS into RIGHTSIB.
|
||||
// Step III.Update the length of THIS.
|
||||
//
|
||||
// Step I.: make space for noFromThis items
|
||||
//
|
||||
int start = last - noFromThis + 1;
|
||||
int tgt, src;
|
||||
tgt = rightsib->last + noFromThis;
|
||||
src = rightsib->last;
|
||||
rightsib->last = tgt;
|
||||
rightsib->setKey( 0, parent->getKey( pidx ) ); incNofKeys(0);
|
||||
while( src >= 0 )
|
||||
{
|
||||
// do this kind of assignment on InnerNode Items only when
|
||||
// the parent fields
|
||||
// of the moved items do not change, as they don't here.
|
||||
// Otherwise, use setItem so the parents are updated appropriately.
|
||||
rightsib->getItem(tgt--) = rightsib->getItem(src--);
|
||||
}
|
||||
|
||||
// Step II.Move the items from THIS into RIGHTSIB
|
||||
for( int i = last; i >= start; i-- )
|
||||
{
|
||||
// this is the kind of assignment to use when parents change
|
||||
rightsib->setItem(tgt--, getItem(i));
|
||||
}
|
||||
parent->setKey( pidx, rightsib->getKey(0) );
|
||||
decNofKeys(0);
|
||||
CHECK( tgt == -1 );
|
||||
|
||||
// Step III.
|
||||
last -= noFromThis;
|
||||
|
||||
// Step VI. update nofKeys
|
||||
parent->setNofKeys( pidx-1, nofKeys() );
|
||||
parent->setNofKeys( pidx, rightsib->nofKeys() );
|
||||
}
|
||||
|
||||
void InnerNode::remove( int index )
|
||||
{
|
||||
PRECONDITION( index >= 1 && index <= last );
|
||||
LeafNode* lf = getTree(index)->firstLeafNode();
|
||||
setKey( index, lf->item[0] );
|
||||
lf->removeItem(0);
|
||||
}
|
||||
|
||||
void InnerNode::removeItem( int index )
|
||||
{
|
||||
PRECONDITION( index >= 1 && index <= last );
|
||||
for( int to = index; to < last; to++ )
|
||||
item[to] = item[to+1];
|
||||
last--;
|
||||
if( isLow() )
|
||||
{
|
||||
if( parent == 0 )
|
||||
{
|
||||
// then this is the root; when only one child, make the child
|
||||
// the root
|
||||
if( Psize() == 0 )
|
||||
tree->rootIsEmpty();
|
||||
}
|
||||
else
|
||||
parent->isLow( this );
|
||||
}
|
||||
}
|
||||
|
||||
void InnerNode::shiftLeft( int cnt )
|
||||
{
|
||||
if( cnt <= 0 )
|
||||
return;
|
||||
for( int i = cnt; i <= last; i++ )
|
||||
getItem(i-cnt) = getItem(i);
|
||||
last -= cnt;
|
||||
}
|
||||
|
||||
void InnerNode::split()
|
||||
{
|
||||
// this function is called only when THIS is the only descendent
|
||||
// of the root node, and THIS needs to be split.
|
||||
// assumes that idx of THIS in Parent is 0.
|
||||
InnerNode* newnode = new InnerNode( parent );
|
||||
CHECK( newnode != 0 );
|
||||
parent->append( getKey(last), newnode );
|
||||
newnode->appendFrom( this, last, last );
|
||||
last--;
|
||||
parent->incNofKeys( 1, newnode->getNofKeys(0) );
|
||||
parent->decNofKeys( 0, newnode->getNofKeys(0) );
|
||||
balanceWithRight( newnode, 1 );
|
||||
}
|
||||
|
||||
void
|
||||
InnerNode::splitWith( InnerNode *rightsib, int keyidx )
|
||||
{
|
||||
// THIS and SIB are too full; create a NEWnODE, and balance
|
||||
// the number of keys between the three of them.
|
||||
//
|
||||
// picture: (also see Knuth Vol 3 pg 478)
|
||||
// keyidx keyidx+1
|
||||
// +--+--+--+--+--+--...
|
||||
// | | | | | |
|
||||
// parent--->| | | |
|
||||
// | | | |
|
||||
// +*-+*-+*-+--+--+--...
|
||||
// | | |
|
||||
// +----+ | +-----+
|
||||
// | +-----+ |
|
||||
// V | V
|
||||
// +----------+ | +----------+
|
||||
// | | | | |
|
||||
// this->| | | | |<--sib
|
||||
// +----------+ | +----------+
|
||||
// V
|
||||
// data
|
||||
//
|
||||
// keyidx is the index of where the sibling is, and where the
|
||||
// newly created node will be recorded (sibling will be moved to
|
||||
// keyidx+1)
|
||||
//
|
||||
PRECONDITION( keyidx > 0 && keyidx <= parent->last );
|
||||
// I would like to be able to prove that the following assertion
|
||||
// is ALWAYS true, but it is beyond my time limits. If this assertion
|
||||
// ever comes up False, then the code to make it so must be inserted
|
||||
// here.
|
||||
// assert(parent->getKey(keyidx) == rightsib->getKey(0));
|
||||
// During debugging, this came up False, so
|
||||
rightsib->setKey(0,parent->getKey(keyidx));
|
||||
int nofKeys = Psize() + rightsib->Vsize();
|
||||
int newSizeThis = nofKeys / 3;
|
||||
int newSizeNew = (nofKeys - newSizeThis) / 2;
|
||||
int newSizeSib = (nofKeys - newSizeThis - newSizeNew);
|
||||
int noFromThis = Psize() - newSizeThis;
|
||||
int noFromSib = rightsib->Vsize() - newSizeSib;
|
||||
// because of their smaller size, this InnerNode may not have to
|
||||
// give up any elements to the new node. I.e., noFromThis == 0.
|
||||
// This will not happen for LeafNodes.
|
||||
// We handle this by pulling an item from the rightsib.
|
||||
CHECK( noFromThis >= 0 );
|
||||
CHECK( noFromSib >= 1 );
|
||||
InnerNode* newNode = new InnerNode(parent);
|
||||
CHECK( newNode != 0 );
|
||||
if( noFromThis > 0 )
|
||||
{
|
||||
newNode->append( getItem(last) );
|
||||
parent->addElt( keyidx, getKey(last--), newNode );
|
||||
if( noFromThis > 2 )
|
||||
this->pushRight( noFromThis-1, newNode, keyidx );
|
||||
rightsib->pushLeft( noFromSib, newNode, keyidx+1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// pull an element from the rightsib
|
||||
newNode->append( rightsib->getItem(0) );
|
||||
parent->addElt( keyidx+1, rightsib->getKey(1), rightsib);
|
||||
rightsib->shiftLeft(1);
|
||||
parent->setTree( keyidx, newNode );
|
||||
rightsib->pushLeft( noFromSib-1, newNode, keyidx+1 );
|
||||
}
|
||||
parent->setNofKeys( keyidx-1, this->nofKeys() );
|
||||
parent->setNofKeys( keyidx, newNode->nofKeys() );
|
||||
parent->setNofKeys( keyidx+1, rightsib->nofKeys() );
|
||||
if( parent->isFull() )
|
||||
parent->informParent();
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BTREELFN.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __BTREE_H )
|
||||
#include "classlib\obsolete\btree.h"
|
||||
#endif // __BTREE_H
|
||||
|
||||
//====== LeafNode functions =======
|
||||
|
||||
LeafNode::LeafNode(InnerNode* P, Sortable* O, Btree* T): Node(1, P, T)
|
||||
{
|
||||
item = new Sortable *[maxIndex()+1];
|
||||
if( item == 0 )
|
||||
ClassLib_error( __ENOMEMLN );
|
||||
if( O != 0 )
|
||||
item[++last] = O;
|
||||
}
|
||||
|
||||
LeafNode::~LeafNode()
|
||||
{
|
||||
if( tree->ownsElements() )
|
||||
{
|
||||
for( int i = 0; i <= last; i++ )
|
||||
delete item[i];
|
||||
}
|
||||
delete [] item;
|
||||
}
|
||||
|
||||
void LeafNode::add(Sortable *obj, int index)
|
||||
{
|
||||
// add the object OBJ to the leaf node, inserting it at location INDEX
|
||||
// in the item array
|
||||
PRECONDITION( 0 <= index && index <= last+1 );
|
||||
PRECONDITION( last <= maxIndex() );
|
||||
for( int i = last+1; i > index ; i-- )
|
||||
item[i] = item[ i - 1 ];
|
||||
item[ index ] = obj;
|
||||
last++;
|
||||
|
||||
// check for overflow
|
||||
if( parent == 0 )
|
||||
tree->incrNofKeys( );
|
||||
else
|
||||
parent->incrNofKeys( this );
|
||||
|
||||
if( isFull() )
|
||||
{
|
||||
// it's full; tell parent node
|
||||
if( parent == 0 )
|
||||
{
|
||||
// this occurs when this leaf is the only node in the
|
||||
// btree, and this->tree->root == this
|
||||
CHECK( tree->root == this );
|
||||
// in which case we inform the btree, which can be
|
||||
// considered the parent of this node
|
||||
tree->rootIsFull();
|
||||
}
|
||||
else
|
||||
{
|
||||
// the parent is responsible for splitting/balancing subnodes
|
||||
parent->isFull( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LeafNode::appendFrom( LeafNode* src, int start, int stop )
|
||||
{
|
||||
// A convenience function, does not worry about the element in
|
||||
// the parent, simply moves elements from SRC[start] to SRC[stop]
|
||||
// into the current array.
|
||||
// This should never create a full node.
|
||||
// That is, it is not used anywhere where THIS could possibly be
|
||||
// near full.
|
||||
// Does NOT handle nofKeys.
|
||||
if( start > stop )
|
||||
return;
|
||||
PRECONDITION( 0 <= start && start <= src->last );
|
||||
PRECONDITION( 0 <= stop && stop <= src->last );
|
||||
PRECONDITION( last + stop - start + 1 < maxIndex() ); // full-node check
|
||||
for( int i = start; i <= stop; i++ )
|
||||
item[++last] = src->item[i];
|
||||
CHECK( last < maxIndex() );
|
||||
}
|
||||
|
||||
void LeafNode::append( Sortable* D )
|
||||
{
|
||||
// never called from anywhere where it might fill up THIS
|
||||
// does NOT handle nofKeys.
|
||||
item[++last] = D;
|
||||
CHECK( last < maxIndex() );
|
||||
}
|
||||
|
||||
|
||||
void LeafNode::balanceWithLeft( LeafNode* leftsib, int pidx )
|
||||
{
|
||||
// THIS has more than LEFTSIB; move some items from THIS to LEFTSIB.
|
||||
PRECONDITION( Vsize() >= leftsib->Psize() );
|
||||
int newThisSize = (Vsize() + leftsib->Psize())/2;
|
||||
int noFromThis = Psize() - newThisSize;
|
||||
pushLeft( noFromThis, leftsib, pidx );
|
||||
}
|
||||
|
||||
void LeafNode::balanceWithRight( LeafNode* rightsib, int pidx )
|
||||
{
|
||||
// THIS has more than RIGHTSIB; move some items from THIS to RIGHTSIB.
|
||||
PRECONDITION( Psize() >= rightsib->Vsize() );
|
||||
int newThisSize = (Psize() + rightsib->Vsize())/2;
|
||||
int noFromThis = Psize() - newThisSize;
|
||||
pushRight( noFromThis, rightsib, pidx );
|
||||
}
|
||||
|
||||
void LeafNode::balanceWith( LeafNode* rightsib, int pidx )
|
||||
{
|
||||
// PITEM is the parent item whose key will change when keys are shifted
|
||||
// from one LeafNode to the other.
|
||||
if( Psize() < rightsib->Vsize() )
|
||||
rightsib->balanceWithLeft( this, pidx );
|
||||
else
|
||||
balanceWithRight( rightsib, pidx );
|
||||
}
|
||||
|
||||
long LeafNode::findRank( Sortable* what ) const
|
||||
{
|
||||
// WHAT was not in any inner node; it is either here, or it's
|
||||
// not in the tree
|
||||
for( int i = 0; i <= last; i++ )
|
||||
{
|
||||
if( *item[i] == *what )
|
||||
return i;
|
||||
if( *item[i] >= *what )
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
LeafNode *LeafNode::firstLeafNode()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Object& LeafNode::found(Sortable* what, Node** which, int* where )
|
||||
{
|
||||
// WHAT was not in any inner node; it is either here, or it's
|
||||
// not in the tree
|
||||
for( int i = 0; i <= last; i++ )
|
||||
{
|
||||
if( *item[i] == *what )
|
||||
{
|
||||
*which = this;
|
||||
*where = i;
|
||||
return *item[i];
|
||||
}
|
||||
if( *item[i] >= *what )
|
||||
{
|
||||
*which = this;
|
||||
*where = i;
|
||||
return NOOBJECT;
|
||||
}
|
||||
}
|
||||
*which = this;
|
||||
*where = last+1;
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
#pragma warn -rvl
|
||||
|
||||
int LeafNode::indexOf( const Sortable *that ) const
|
||||
{
|
||||
// returns a number in the range 0 to maxIndex()
|
||||
for( int i = 0; i <= last; i++ )
|
||||
{
|
||||
if( item[i] == that )
|
||||
return i;
|
||||
}
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
#pragma warn .rvl
|
||||
|
||||
LeafNode *LeafNode::lastLeafNode()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void LeafNode::mergeWithRight( LeafNode* rightsib, int pidx )
|
||||
{
|
||||
PRECONDITION( Psize() + rightsib->Vsize() < maxPsize() );
|
||||
rightsib->pushLeft( rightsib->Psize(), this, pidx );
|
||||
append( parent->getKey( pidx ) );
|
||||
parent->setNofKeys( pidx-1, nofKeys() );
|
||||
// cout << "in mergeWithRight:\n" << *parent << "\n";
|
||||
parent->removeItem( pidx );
|
||||
delete rightsib;
|
||||
// cout << "in mergeWithRight:\n" << *parent << "\n";
|
||||
}
|
||||
|
||||
long LeafNode::nofKeys( int ) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
long LeafNode::nofKeys() const
|
||||
{
|
||||
return Psize();
|
||||
}
|
||||
|
||||
void LeafNode::printOn(ostream& out) const
|
||||
{
|
||||
out << " < ";
|
||||
for( int i = 0; i <= last; i++ )
|
||||
out << *item[i] << " " ;
|
||||
out << "> ";
|
||||
}
|
||||
|
||||
void LeafNode::pushLeft( int noFromThis, LeafNode* leftsib, int pidx )
|
||||
{
|
||||
// noFromThis==1 => moves the parent item into the leftsib,
|
||||
// and the first item in this's array into the parent item
|
||||
PRECONDITION( noFromThis > 0 && noFromThis <= Psize() );
|
||||
PRECONDITION( noFromThis + leftsib->Psize() < maxPsize() );
|
||||
PRECONDITION( parent->getTree(pidx) == this );
|
||||
leftsib->append( parent->getKey(pidx) );
|
||||
if( noFromThis > 1 )
|
||||
leftsib->appendFrom( this, 0, noFromThis-2 );
|
||||
parent->setKey( pidx, item[noFromThis-1] );
|
||||
shiftLeft( noFromThis );
|
||||
parent->setNofKeys( pidx-1, leftsib->nofKeys() );
|
||||
parent->setNofKeys( pidx, nofKeys() );
|
||||
}
|
||||
|
||||
void LeafNode::pushRight( int noFromThis, LeafNode* rightsib, int pidx )
|
||||
{
|
||||
// noFromThis==1 => moves the parent item into the
|
||||
// rightsib, and the last item in this's array into the parent
|
||||
// item
|
||||
PRECONDITION(noFromThis > 0 && noFromThis <= Psize());
|
||||
PRECONDITION(noFromThis + rightsib->Psize() < maxPsize());
|
||||
PRECONDITION(parent->getTree(pidx) == rightsib);
|
||||
// The operation is five steps:
|
||||
// Step I. Make room for the incoming keys in RIGHTSIB.
|
||||
// Step II. Move the key in the parent into RIGHTSIB.
|
||||
// Step III.Move the items from THIS into RIGHTSIB.
|
||||
// Step IV. Move the item from THIS into the parent.
|
||||
// Step V. Update the length of THIS.
|
||||
//
|
||||
// Step I.: make space for noFromThis items
|
||||
//
|
||||
int start = last - noFromThis + 1;
|
||||
int tgt, src;
|
||||
tgt = rightsib->last + noFromThis;
|
||||
src = rightsib->last;
|
||||
rightsib->last = tgt;
|
||||
while (src >= 0)
|
||||
rightsib->item[tgt--] = rightsib->item[src--];
|
||||
|
||||
// Step II. Move the key from the parent into place
|
||||
rightsib->item[ tgt-- ] = parent->getKey( pidx );
|
||||
|
||||
// Step III.Move the items from THIS into RIGHTSIB
|
||||
for( int i = last; i > start; i-- )
|
||||
rightsib->item[tgt--] = item[i];
|
||||
CHECK( tgt == -1 );
|
||||
|
||||
// Step IV.
|
||||
parent->setKey( pidx, item[ start ] );
|
||||
|
||||
// Step V.
|
||||
last -= noFromThis;
|
||||
|
||||
// Step VI. update nofKeys
|
||||
parent->setNofKeys( pidx-1, nofKeys() );
|
||||
parent->setNofKeys( pidx, rightsib->nofKeys() );
|
||||
}
|
||||
|
||||
void LeafNode::remove( int index )
|
||||
{
|
||||
PRECONDITION( index >= 0 && index <= last );
|
||||
for( int to = index; to < last; to++ )
|
||||
item[to] = item[to+1];
|
||||
last--;
|
||||
if( parent == 0 )
|
||||
tree->decrNofKeys();
|
||||
else
|
||||
parent->decrNofKeys( this );
|
||||
if( isLow() )
|
||||
{
|
||||
if( parent == 0 )
|
||||
{
|
||||
// then this is the root; when no keys left, inform the tree
|
||||
if( Psize() == 0 )
|
||||
tree->rootIsEmpty();
|
||||
}
|
||||
else
|
||||
parent->isLow( this );
|
||||
}
|
||||
}
|
||||
|
||||
void LeafNode::shiftLeft( int cnt )
|
||||
{
|
||||
if( cnt <= 0 )
|
||||
return;
|
||||
for( int i = cnt; i <= last; i++ )
|
||||
item[i-cnt] = item[i];
|
||||
last -= cnt;
|
||||
}
|
||||
|
||||
void LeafNode::split()
|
||||
{
|
||||
// this function is called only when THIS is the only descendent
|
||||
// of the root node, and THIS needs to be split.
|
||||
// assumes that idx of THIS in Parent is 0.
|
||||
LeafNode* newnode = new LeafNode( parent );
|
||||
CHECK( newnode != 0 );
|
||||
parent->append( item[last--], newnode );
|
||||
parent->setNofKeys( 0, parent->getTree(0)->nofKeys() );
|
||||
parent->setNofKeys( 1, parent->getTree(1)->nofKeys() );
|
||||
balanceWithRight( newnode, 1 );
|
||||
}
|
||||
|
||||
void LeafNode::splitWith( LeafNode *rightsib, int keyidx )
|
||||
{
|
||||
PRECONDITION(parent == rightsib->parent);
|
||||
PRECONDITION(keyidx > 0 && keyidx <= parent->last);
|
||||
int nofKeys = Psize() + rightsib->Vsize();
|
||||
int newSizeThis = nofKeys / 3;
|
||||
int newSizeNew = (nofKeys - newSizeThis) / 2;
|
||||
int newSizeSib = (nofKeys - newSizeThis - newSizeNew);
|
||||
int noFromThis = Psize() - newSizeThis;
|
||||
int noFromSib = rightsib->Vsize() - newSizeSib;
|
||||
CHECK(noFromThis >= 0);
|
||||
CHECK(noFromSib >= 1);
|
||||
LeafNode* newNode = new LeafNode(parent);
|
||||
CHECK( newNode != 0 );
|
||||
parent->addElt( keyidx, item[last--], newNode );
|
||||
parent->setNofKeys( keyidx, 0 );
|
||||
parent->decNofKeys( keyidx-1 );
|
||||
this->pushRight( noFromThis-1, newNode, keyidx );
|
||||
rightsib->pushLeft( noFromSib, newNode, keyidx+1 );
|
||||
if( parent->isFull() )
|
||||
parent->informParent();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* COLLECT.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __COLLECT_H )
|
||||
#include "classlib\obsolete\collect.h"
|
||||
#endif // __COLLECT_H
|
||||
|
||||
Object _FAR & Collection::findMember( Object _FAR & testObject ) const
|
||||
{
|
||||
ContainerIterator& containerIterator = initIterator();
|
||||
while( containerIterator != 0 )
|
||||
{
|
||||
Object& listObject = containerIterator++;
|
||||
if( listObject == testObject )
|
||||
{
|
||||
delete &containerIterator;
|
||||
return listObject;
|
||||
}
|
||||
}
|
||||
delete &containerIterator;
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* CONTAIN.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif // CHECKS_H
|
||||
|
||||
#if !defined( __CONTAIN_H )
|
||||
#include "classlib\obsolete\contain.h"
|
||||
#endif // __CONTAIN_H
|
||||
|
||||
void Container::forEach( iterFuncType actionPtr, void *paramListPtr )
|
||||
{
|
||||
PRECONDITION( actionPtr != 0 );
|
||||
ContainerIterator& containerIterator = initIterator();
|
||||
while( containerIterator != 0 )
|
||||
containerIterator++.forEach( actionPtr, paramListPtr );
|
||||
delete &containerIterator;
|
||||
}
|
||||
|
||||
Object& Container::firstThat( condFuncType testFuncPtr,
|
||||
void *paramListPtr
|
||||
) const
|
||||
{
|
||||
PRECONDITION( testFuncPtr != 0 );
|
||||
ContainerIterator &containerIterator = initIterator();
|
||||
while( containerIterator != 0 )
|
||||
{
|
||||
Object& testResult =
|
||||
containerIterator++.firstThat( testFuncPtr, paramListPtr );
|
||||
if ( testResult != NOOBJECT )
|
||||
{
|
||||
delete &containerIterator;
|
||||
return testResult;
|
||||
}
|
||||
}
|
||||
delete &containerIterator;
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
Object& Container::lastThat( condFuncType testFuncPtr,
|
||||
void *paramListPtr
|
||||
) const
|
||||
{
|
||||
PRECONDITION( testFuncPtr != 0 );
|
||||
ContainerIterator& containerIterator = initIterator();
|
||||
Object *lastMet = ZERO;
|
||||
while( containerIterator != 0 )
|
||||
{
|
||||
Object& testResult =
|
||||
containerIterator++.lastThat( testFuncPtr, paramListPtr );
|
||||
if( testResult != NOOBJECT )
|
||||
lastMet = &testResult;
|
||||
}
|
||||
delete &containerIterator;
|
||||
return *lastMet;
|
||||
}
|
||||
|
||||
int Container::isEqual( const Object& testContainer ) const
|
||||
{
|
||||
PRECONDITION( isA() == testContainer.isA() );
|
||||
|
||||
int res = 1;
|
||||
|
||||
ContainerIterator& thisIterator = initIterator();
|
||||
ContainerIterator& testContainerIterator =
|
||||
((Container &)(testContainer)).initIterator();
|
||||
while( thisIterator != 0 && testContainerIterator != 0 )
|
||||
{
|
||||
if( thisIterator++ != testContainerIterator++ )
|
||||
{
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( thisIterator != 0 || testContainerIterator != 0 )
|
||||
res = 0;
|
||||
|
||||
delete &testContainerIterator;
|
||||
delete &thisIterator;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Container::printOn( ostream& outputStream ) const
|
||||
{
|
||||
ContainerIterator& printIterator = initIterator();
|
||||
printHeader( outputStream );
|
||||
while( printIterator != 0 )
|
||||
{
|
||||
printIterator++.printOn( outputStream );
|
||||
if ( printIterator != 0 )
|
||||
printSeparator( outputStream );
|
||||
else
|
||||
break;
|
||||
}
|
||||
printTrailer( outputStream );
|
||||
delete &printIterator;
|
||||
}
|
||||
|
||||
static void getHashValue( Object& o, void *valPtr )
|
||||
{
|
||||
hashValueType *val = (hashValueType *)valPtr;
|
||||
*val += o.hashValue();
|
||||
}
|
||||
|
||||
#pragma warn -ncf
|
||||
|
||||
hashValueType Container::hashValue() const
|
||||
{
|
||||
hashValueType val = 0;
|
||||
forEach( getHashValue, &val );
|
||||
return val;
|
||||
}
|
||||
|
||||
#pragma warn .ncf
|
||||
|
||||
void Container::printHeader( ostream& outputStream ) const
|
||||
{
|
||||
outputStream << nameOf() << " {\n ";
|
||||
}
|
||||
|
||||
void Container::printSeparator( ostream& outputStream ) const
|
||||
{
|
||||
outputStream << ",\n ";
|
||||
}
|
||||
|
||||
void Container::printTrailer( ostream& outputStream ) const
|
||||
{
|
||||
outputStream << " }\n";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DBLLIST.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __RESOURCE_H )
|
||||
#include "classlib\resource.h"
|
||||
#endif // __RESOURCE_H
|
||||
|
||||
#if !defined( __DBLLIST_H )
|
||||
#include "classlib\obsolete\dbllist.h"
|
||||
#endif // __DBLLIST_H
|
||||
|
||||
unsigned DoubleListBlockInitializer::count = 0;
|
||||
|
||||
MemBlocks _FAR *DoubleList::ListElement::mgr = 0;
|
||||
|
||||
void DoubleList::flush( DeleteType dt )
|
||||
{
|
||||
ListElement *current = head->next;
|
||||
while( current != tail )
|
||||
{
|
||||
ListElement *temp = current;
|
||||
current = current->next;
|
||||
if( delObj(dt) )
|
||||
delete temp->data;
|
||||
delete temp;
|
||||
}
|
||||
head->next = tail;
|
||||
tail->prev = head;
|
||||
itemsInContainer = 0;
|
||||
}
|
||||
|
||||
void DoubleList::addAtHead( Object& toAdd )
|
||||
{
|
||||
ListElement *newElement =
|
||||
new ListElement( &toAdd, head, head->next );
|
||||
CHECK( newElement != 0 );
|
||||
|
||||
head->next->prev = newElement;
|
||||
head->next = newElement;
|
||||
|
||||
itemsInContainer++;
|
||||
}
|
||||
|
||||
void DoubleList::addAtTail( Object& toAdd )
|
||||
{
|
||||
ListElement *newElement =
|
||||
new ListElement( &toAdd, tail->prev, tail );
|
||||
CHECK( newElement != 0 );
|
||||
|
||||
tail->prev->next = newElement;
|
||||
tail->prev = newElement;
|
||||
|
||||
itemsInContainer++;
|
||||
}
|
||||
|
||||
void DoubleList::detach( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
detachFromHead( toDetach, dt );
|
||||
}
|
||||
|
||||
void DoubleList::detachFromHead( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
tail->data = &toDetach;
|
||||
ListElement *current = head->next;
|
||||
while( *(current->data) != toDetach )
|
||||
current = current->next;
|
||||
tail->data = 0;
|
||||
|
||||
if( current->data == 0 ) // not found
|
||||
return;
|
||||
|
||||
current->next->prev = current->prev;
|
||||
current->prev->next = current->next;
|
||||
|
||||
if( delObj(dt) )
|
||||
delete current->data;
|
||||
delete current;
|
||||
|
||||
itemsInContainer--;
|
||||
}
|
||||
|
||||
void DoubleList::detachFromTail( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
head->data = &toDetach;
|
||||
ListElement *current = tail->prev;
|
||||
while( *(current->data) != toDetach )
|
||||
current = current->prev;
|
||||
head->data = 0;
|
||||
|
||||
if( current->data == 0 ) // not found
|
||||
return;
|
||||
|
||||
current->next->prev = current->prev;
|
||||
current->prev->next = current->next;
|
||||
|
||||
if( delObj(dt) )
|
||||
delete current->data;
|
||||
delete current;
|
||||
|
||||
itemsInContainer--;
|
||||
}
|
||||
|
||||
ContainerIterator& DoubleList::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new DoubleListIterator( *this ) );
|
||||
}
|
||||
|
||||
ContainerIterator& DoubleList::initReverseIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new DoubleListIterator( *this, 0 ) );
|
||||
}
|
||||
|
||||
DoubleListIterator::operator int()
|
||||
{
|
||||
return currentElement != currentElement->next &&
|
||||
currentElement != currentElement->prev;
|
||||
}
|
||||
|
||||
Object& DoubleListIterator::current()
|
||||
{
|
||||
return *(currentElement->data);
|
||||
}
|
||||
|
||||
Object& DoubleListIterator::operator ++ ( int )
|
||||
{
|
||||
if( currentElement != currentElement->next )
|
||||
{
|
||||
currentElement = currentElement->next;
|
||||
return *(currentElement->prev->data);
|
||||
}
|
||||
else
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
Object& DoubleListIterator::operator ++ ()
|
||||
{
|
||||
currentElement = currentElement->next;
|
||||
|
||||
if( currentElement != currentElement->next )
|
||||
return *(currentElement->data);
|
||||
else
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
void DoubleListIterator::restart()
|
||||
{
|
||||
currentElement = startingElement;
|
||||
}
|
||||
|
||||
Object& DoubleListIterator::operator -- ( int )
|
||||
{
|
||||
if( currentElement != currentElement->prev )
|
||||
{
|
||||
currentElement = currentElement->prev;
|
||||
return *(currentElement->next->data);
|
||||
}
|
||||
else
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
Object& DoubleListIterator::operator -- ()
|
||||
{
|
||||
currentElement = currentElement->prev;
|
||||
|
||||
if( currentElement != currentElement->prev )
|
||||
return *(currentElement->data);
|
||||
else
|
||||
return NOOBJECT;
|
||||
}
|
||||
|
||||
DoubleListIterator::~DoubleListIterator()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DEQUE.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __DEQUE_H )
|
||||
#include "classlib\obsolete\deque.h"
|
||||
#endif // __DEQUE_H
|
||||
|
||||
Object& Deque::getLeft()
|
||||
{
|
||||
Object& temp = list.peekAtHead();
|
||||
if( temp != NOOBJECT )
|
||||
{
|
||||
list.detachFromHead( temp );
|
||||
itemsInContainer--;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
Object& Deque::getRight()
|
||||
{
|
||||
Object& temp = list.peekAtTail();
|
||||
if( temp != NOOBJECT )
|
||||
{
|
||||
list.detachFromTail( temp );
|
||||
itemsInContainer--;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
ContainerIterator& Deque::initIterator() const
|
||||
{
|
||||
return *((ContainerIterator *)new DoubleListIterator(list));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* DICT.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __ASSOC_H )
|
||||
#include "classlib\obsolete\assoc.h"
|
||||
#endif // __ASSOC_H
|
||||
|
||||
#if !defined( __DICT_H )
|
||||
#include "classlib\obsolete\dict.h"
|
||||
#endif // __DICT_H
|
||||
|
||||
#if !defined( __CLSTYPES_H )
|
||||
#include "classlib\obsolete\clstypes.h"
|
||||
#endif // __CLSTYPES_H
|
||||
|
||||
void Dictionary::add( Object _FAR & objectToAdd )
|
||||
{
|
||||
if( !objectToAdd.isAssociation() )
|
||||
ClassLib_error( __ENOTASSOC );
|
||||
else
|
||||
Set::add( objectToAdd );
|
||||
}
|
||||
|
||||
Association _FAR & Dictionary::lookup( const Object _FAR & toLookUp ) const
|
||||
{
|
||||
Association toFind( (Object&)toLookUp, NOOBJECT );
|
||||
toFind.ownsElements(0);
|
||||
|
||||
Association& found = (Association&)findMember( toFind );
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* HASHTBL.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __HASHTBL_H )
|
||||
#include "classlib\obsolete\hashtbl.h"
|
||||
#endif // __HASHTBL_H
|
||||
|
||||
HashTable::HashTable( sizeType aPrime ) :
|
||||
size( aPrime ),
|
||||
table( aPrime ),
|
||||
itemsInContainer(0)
|
||||
{
|
||||
}
|
||||
|
||||
void HashTable::add( Object& objectToAdd )
|
||||
{
|
||||
hashValueType index = getHashValue( objectToAdd );
|
||||
if( table[ index ] == 0 )
|
||||
table[index] = new List;
|
||||
((List *)table[ index ])->add( objectToAdd );
|
||||
itemsInContainer++;
|
||||
}
|
||||
|
||||
void HashTable::detach( Object& objectToDetach, DeleteType dt )
|
||||
{
|
||||
hashValueType index = getHashValue( objectToDetach );
|
||||
if( table[ index ] != 0 )
|
||||
{
|
||||
unsigned listSize = ((List *)table[ index ])->getItemsInContainer();
|
||||
((List *)table[ index ])->detach( objectToDetach, delItem(dt) );
|
||||
if( ((List *)table[ index ])->getItemsInContainer() != listSize )
|
||||
itemsInContainer--;
|
||||
}
|
||||
}
|
||||
|
||||
static void setOwner( Object& list, void *owns )
|
||||
{
|
||||
((List&)list).ownsElements( *(TShouldDelete::DeleteType *)owns );
|
||||
}
|
||||
|
||||
void HashTable::flush( DeleteType dt )
|
||||
{
|
||||
int shouldDel = delObj( dt );
|
||||
table.forEach( setOwner, &shouldDel );
|
||||
table.flush( 1 );
|
||||
itemsInContainer = 0;
|
||||
}
|
||||
|
||||
Object& HashTable::findMember( Object& testObject ) const
|
||||
{
|
||||
hashValueType index = getHashValue( testObject );
|
||||
if( index >= table.limit() || table[ index ] == 0 )
|
||||
{
|
||||
return NOOBJECT;
|
||||
}
|
||||
return ((List *)table[ index ])->findMember( testObject );
|
||||
}
|
||||
|
||||
ContainerIterator& HashTable::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new HashTableIterator( *this ) );
|
||||
}
|
||||
|
||||
HashTableIterator::HashTableIterator( const HashTable& toIterate ) :
|
||||
beingIterated( toIterate ),
|
||||
listIterator(0)
|
||||
{
|
||||
arrayIterator = new BI_IVectorIteratorImp<Object>( toIterate.table );
|
||||
restart();
|
||||
}
|
||||
|
||||
HashTableIterator::~HashTableIterator()
|
||||
{
|
||||
delete arrayIterator;
|
||||
delete listIterator;
|
||||
}
|
||||
|
||||
Object& HashTableIterator::operator ++ ( int )
|
||||
{
|
||||
Object& res = (listIterator == 0) ? NOOBJECT : listIterator->current();
|
||||
scan();
|
||||
return res;
|
||||
}
|
||||
|
||||
Object& HashTableIterator::operator ++ ()
|
||||
{
|
||||
scan();
|
||||
return (listIterator == 0) ? NOOBJECT : listIterator->current();
|
||||
}
|
||||
|
||||
HashTableIterator::operator int()
|
||||
{
|
||||
return int(*arrayIterator);
|
||||
}
|
||||
|
||||
Object& HashTableIterator::current()
|
||||
{
|
||||
return (listIterator == 0) ? NOOBJECT : listIterator->current();
|
||||
}
|
||||
|
||||
void HashTableIterator::restart()
|
||||
{
|
||||
delete listIterator;
|
||||
|
||||
arrayIterator->restart();
|
||||
while( *arrayIterator != 0 && arrayIterator->current() == 0 )
|
||||
(*arrayIterator)++;
|
||||
|
||||
if( *arrayIterator != 0 )
|
||||
{
|
||||
const Object *curList = arrayIterator->current();
|
||||
listIterator = &(((List *)curList)->initIterator());
|
||||
if( listIterator->current() == NOOBJECT )
|
||||
scan();
|
||||
}
|
||||
else
|
||||
listIterator = 0;
|
||||
}
|
||||
|
||||
void HashTableIterator::scan()
|
||||
{
|
||||
if( listIterator == 0 )
|
||||
return;
|
||||
|
||||
(*listIterator)++;
|
||||
while( listIterator != 0 && listIterator->current() == NOOBJECT )
|
||||
{
|
||||
delete listIterator;
|
||||
|
||||
(*arrayIterator)++;
|
||||
while( *arrayIterator != 0 && arrayIterator->current() == 0 )
|
||||
(*arrayIterator)++;
|
||||
|
||||
if( *arrayIterator == 0 || arrayIterator->current() == 0 )
|
||||
{
|
||||
listIterator = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const Object *cur = arrayIterator->current();
|
||||
listIterator = &(((Container *)cur)->initIterator());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* LDATE.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif // __STRSTREA_H
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif // __STDIO_H
|
||||
|
||||
#if !defined( __LDATE_H )
|
||||
#include "classlib\obsolete\ldate.h"
|
||||
#endif // __LDATE_H
|
||||
|
||||
const BufSize = 20;
|
||||
|
||||
static char *MonthNames[] =
|
||||
{
|
||||
"",
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
};
|
||||
|
||||
int BaseDate::isEqual( const Object& testDate ) const
|
||||
{
|
||||
return MM == ((BaseDate&)testDate).MM &&
|
||||
DD == ((BaseDate&)testDate).DD &&
|
||||
YY == ((BaseDate&)testDate).YY;
|
||||
}
|
||||
|
||||
int BaseDate::isLessThan( const Object& testDate ) const
|
||||
{
|
||||
if( YY != ((BaseDate&)testDate).YY )
|
||||
return YY < ((BaseDate&)testDate).YY;
|
||||
if( MM != ((BaseDate&)testDate).MM )
|
||||
return MM < ((BaseDate&)testDate).MM;
|
||||
return DD < ((BaseDate&)testDate).DD;
|
||||
}
|
||||
|
||||
hashValueType BaseDate::hashValue() const
|
||||
{
|
||||
return hashValueType( YY + MM + DD );
|
||||
}
|
||||
|
||||
void Date::printOn( ostream& outputStream ) const
|
||||
{
|
||||
char temp[BufSize];
|
||||
ostrstream os( temp, BufSize );
|
||||
os << MonthNames[ Month() ] << " "
|
||||
<< Day() << ", " << Year() << ends;
|
||||
outputStream << temp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* LIST.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __RESOURCE_H )
|
||||
#include "classlib\resource.h"
|
||||
#endif // __RESOURCE_H
|
||||
|
||||
#if !defined( __LIST_H )
|
||||
#include "classlib\obsolete\list.h"
|
||||
#endif // __LIST_H
|
||||
|
||||
unsigned ListBlockInitializer::count = 0;
|
||||
|
||||
MemBlocks *List::ListElement::mgr = 0;
|
||||
|
||||
void List::add( Object& toAdd )
|
||||
{
|
||||
ListElement *newElement = new ListElement( &toAdd, head->next );
|
||||
CHECK( newElement != 0 );
|
||||
head->next = newElement;
|
||||
itemsInContainer++;
|
||||
}
|
||||
|
||||
List::ListElement *List::findPred( const Object& o )
|
||||
{
|
||||
tail->data = (Object *)&o;
|
||||
ListElement *cursor = head;
|
||||
while( o != *(cursor->next->data) )
|
||||
cursor = cursor->next;
|
||||
tail->data = 0;
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void List::detach( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
ListElement *pred = findPred( toDetach );
|
||||
ListElement *item = pred->next;
|
||||
if( delObj(dt) && pred->next != tail )
|
||||
delete item->data;
|
||||
pred->next = pred->next->next;
|
||||
if( item != tail )
|
||||
{
|
||||
itemsInContainer--;
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
void List::flush( DeleteType dt )
|
||||
{
|
||||
ListElement *current = head->next;
|
||||
while( current != tail )
|
||||
{
|
||||
ListElement *temp = current;
|
||||
current = current->next;
|
||||
if( delObj(dt) )
|
||||
delete temp->data;
|
||||
delete temp;
|
||||
}
|
||||
head->next = tail;
|
||||
itemsInContainer = 0;
|
||||
}
|
||||
|
||||
ContainerIterator& List::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new ListIterator( *this ) );
|
||||
}
|
||||
|
||||
ListIterator::~ListIterator()
|
||||
{
|
||||
}
|
||||
|
||||
ListIterator::operator int()
|
||||
{
|
||||
return currentElement->next != currentElement;
|
||||
}
|
||||
|
||||
Object& ListIterator::current()
|
||||
{
|
||||
return currentElement->data == 0 ? NOOBJECT : *(currentElement->data);
|
||||
}
|
||||
|
||||
Object& ListIterator::operator ++ ( int )
|
||||
{
|
||||
Object *data = currentElement->data;
|
||||
currentElement = currentElement->next;
|
||||
return data == 0 ? NOOBJECT : *data;
|
||||
}
|
||||
|
||||
Object& ListIterator::operator ++ ()
|
||||
{
|
||||
currentElement = currentElement->next;
|
||||
return currentElement->data == 0 ? NOOBJECT : *(currentElement->data);
|
||||
}
|
||||
|
||||
void ListIterator::restart()
|
||||
{
|
||||
currentElement = startingElement;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* LTIME.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __IOMANIP_H )
|
||||
#include <iomanip.h>
|
||||
#endif // __IOMANIP_H
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif // __STRSTREA_H
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif // __STDIO_H
|
||||
|
||||
#if !defined( __LTIME_H )
|
||||
#include "classlib\obsolete\ltime.h"
|
||||
#endif // __LTIME_H
|
||||
|
||||
const BufSize = 20;
|
||||
|
||||
int BaseTime::isEqual( const Object _FAR & testTime ) const
|
||||
{
|
||||
return HH == ((BaseTime&)testTime).HH &&
|
||||
MM == ((BaseTime&)testTime).MM &&
|
||||
SS == ((BaseTime&)testTime).SS &&
|
||||
HD == ((BaseTime&)testTime).HD;
|
||||
}
|
||||
|
||||
int BaseTime::isLessThan( const Object& testTime ) const
|
||||
{
|
||||
if( HH != ((BaseTime&)testTime).HH )
|
||||
return HH < ((BaseTime&)testTime).HH;
|
||||
if( MM != ((BaseTime&)testTime).MM )
|
||||
return MM < ((BaseTime&)testTime).MM;
|
||||
if( SS != ((BaseTime&)testTime).SS )
|
||||
return SS < ((BaseTime&)testTime).SS;
|
||||
if( HD != ((BaseTime&)testTime).HD )
|
||||
return HD < ((BaseTime&)testTime).HD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hashValueType BaseTime::hashValue() const
|
||||
{
|
||||
return hashValueType( HH + MM + SS + HD );
|
||||
}
|
||||
|
||||
void Time::printOn( ostream& outputStream ) const
|
||||
{
|
||||
char temp[BufSize];
|
||||
ostrstream os( temp, BufSize );
|
||||
os << ((hour()%12 == 0) ? 12 : hour()%12) << ":"
|
||||
<< setfill( '0' )
|
||||
<< setw( 2 ) << minute() << ":"
|
||||
<< setw( 2 ) << second() << "."
|
||||
<< setw( 2 ) << hundredths() << " "
|
||||
<< ((hour() > 11) ? "p" : "a") << "m" << ends;
|
||||
outputStream << temp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* OBJECT.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif // __STRSTREA_H
|
||||
|
||||
#if !defined( __MALLOC_H )
|
||||
#include <malloc.h>
|
||||
#endif // __MALLOC_H
|
||||
|
||||
#if !defined( __CLSDEFS_H )
|
||||
#include "classlib\obsolete\clsdefs.h"
|
||||
#endif // __CLSDEFS_H
|
||||
|
||||
#if !defined( __OBJECT_H )
|
||||
#include "classlib\obsolete\object.h"
|
||||
#endif // __OBJECT_H
|
||||
|
||||
Error theErrorObject;
|
||||
|
||||
Object *Object::ZERO = &theErrorObject;
|
||||
|
||||
// Error reporting
|
||||
|
||||
static char *errstring[__ElastError] =
|
||||
{
|
||||
"firstError: [[ Error in error reporting???? ]]",
|
||||
"EDELERROR: Attemping to delete the ERROR object",
|
||||
"EXPANDFS: Attempting to expand a fixed size array.",
|
||||
"EXPANDLB: Attempt to expand lower bound of array.",
|
||||
"NOMEM: Out of Memory",
|
||||
"NOTSORT: Object must be sortable.",
|
||||
"NOTASSOC: Object must be association type.",
|
||||
"ORDER3: B-trees must be at least of order 3.",
|
||||
"NOMEMIA: No room for the item array for an InnerNode",
|
||||
"NOMEMLN: No room for item array for a LeafNode.",
|
||||
"PRBADCLASS: PersistRegister called with bad class id.",
|
||||
"PRINCONS: PersistRegister called with inconsistent values.",
|
||||
"BNZERODIV: Attempt to divide by zero.",
|
||||
"BNILLLOG: Attempt to take log of zero or negative number.",
|
||||
"BNNOMEM: No memory for a bignum.",
|
||||
"RANDOM2SMALL: Bignum RNG must be bigger than 32 bits (> 2 words).",
|
||||
"BNTEMPSTKOVFL: Too many markTempRing invocations,",
|
||||
"BNTEMPSTKUNFL: Too many releaseTempRing invocations,",
|
||||
"BN2MANYTEMPS: Ran out of temporaries on the Temp ring.",
|
||||
"BN2BIG2PRINT: Bignum has too many digits in current output base.",
|
||||
"BNNOMEM4PRINT: No memory for temporaries for printing.",
|
||||
"BNRESULT2BIG: An operation would have resulted in too large of a number.",
|
||||
"RNG2BIG: Sorry. RNGs are limited to 32767 `digits' in size.",
|
||||
"BNSQRTILLEGAL: Trying to take sqrt of negative bignum.",
|
||||
};
|
||||
|
||||
extern "C" void __ErrorMessage( const char _FAR * );
|
||||
|
||||
void _FARFUNC ClassLib_error( ClassLib_errors errnum, char _FAR *addstr )
|
||||
{
|
||||
ostrstream os;
|
||||
os << endl << "Fatal error from class library:" << endl;
|
||||
os << "__E" << errstring[errnum] << endl;
|
||||
if( addstr != 0 )
|
||||
os << addstr << endl;
|
||||
os << ends;
|
||||
|
||||
char *buf = os.str();
|
||||
__ErrorMessage( buf );
|
||||
delete [] buf;
|
||||
|
||||
exit( errnum );
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* SORTARRY.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif // __STDLIB_H
|
||||
|
||||
#if !defined( __IOSTREAM_H )
|
||||
#include <iostream.h>
|
||||
#endif // __IOSTREAM_H
|
||||
|
||||
#if !defined( __SORTARRY_H )
|
||||
#include "classlib\obsolete\sortarry.h"
|
||||
#endif // __SORTARRY_H
|
||||
|
||||
void SortedArray::add( Object& toAdd )
|
||||
{
|
||||
if( toAdd.isSortable() )
|
||||
{
|
||||
if( lastElementIndex == upperbound )
|
||||
{
|
||||
reallocate( arraySize() + 1 );
|
||||
}
|
||||
int insertionPoint = lowerbound;
|
||||
while( insertionPoint <= lastElementIndex &&
|
||||
(Sortable&)objectAt( insertionPoint ) < (Sortable&)toAdd
|
||||
)
|
||||
insertionPoint++;
|
||||
|
||||
insertEntry( insertionPoint );
|
||||
setData( insertionPoint, &toAdd );
|
||||
itemsInContainer++;
|
||||
lastElementIndex++;
|
||||
}
|
||||
else
|
||||
ClassLib_error( __ENOTSORT );
|
||||
}
|
||||
|
||||
void SortedArray::detach( int loc, DeleteType dt )
|
||||
{
|
||||
if( loc != INT_MIN )
|
||||
{
|
||||
if( delObj(dt) )
|
||||
delete ptrAt( loc );
|
||||
removeEntry( loc );
|
||||
itemsInContainer--;
|
||||
if( loc <= lastElementIndex )
|
||||
lastElementIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
void SortedArray::detach( Object& toDetach, DeleteType dt )
|
||||
{
|
||||
int detachPoint = find( toDetach );
|
||||
detach( detachPoint, dt );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* STACK.CPP */
|
||||
/* */
|
||||
/* Copyright Borland International 1991, 1993 */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STACK_H )
|
||||
#include "classlib\obsolete\stack.h"
|
||||
#endif // __STACK_H
|
||||
|
||||
void Stack::push( Object& toPush )
|
||||
{
|
||||
list.add( toPush );
|
||||
itemsInContainer++;
|
||||
}
|
||||
|
||||
Object& Stack::pop()
|
||||
{
|
||||
Object& temp = list.peekHead();
|
||||
list.detach( temp );
|
||||
if( temp != NOOBJECT )
|
||||
itemsInContainer--;
|
||||
return temp;
|
||||
}
|
||||
|
||||
ContainerIterator& Stack::initIterator() const
|
||||
{
|
||||
return *( (ContainerIterator *)new ListIterator( list ) );
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// no longer used, beginning in classlib version 4.0
|
||||
@@ -0,0 +1,18 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* OS2MAIN.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1991, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/* Provides the initialization function for the DLL version */
|
||||
/* of the class libraries */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/locale.h>
|
||||
|
||||
TRegFormatHeap TRegItem::Heap = {0, 0, 0};
|
||||
@@ -0,0 +1,45 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#include <osl/locale.h>
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// Construct a reglink pointing to a reglist, and add to end of list
|
||||
//
|
||||
TRegLink::TRegLink(TRegList& regList, TRegLink*& head)
|
||||
:
|
||||
RegList(®List),
|
||||
Next(0)
|
||||
{
|
||||
AddLink(head, *this);
|
||||
}
|
||||
|
||||
//
|
||||
// Add a new link to the end of the link list
|
||||
//
|
||||
void TRegLink::AddLink(TRegLink*& head, TRegLink& newLink)
|
||||
{
|
||||
TRegLink** link = &head;
|
||||
while (*link) // put new link at end of list
|
||||
link = &(*link)->Next;
|
||||
*link = &newLink;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove a link from the link list. Return true if link found & removed
|
||||
//
|
||||
bool TRegLink::RemoveLink(TRegLink*& head, TRegLink& remLink)
|
||||
{
|
||||
for (TRegLink** link = &head; *link; link = &(*link)->Next) {
|
||||
if (*link == &remLink) {
|
||||
*link = (*link)->Next; // remove from list
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* THREAD.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __PROCESS_H )
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __STDLIB_H )
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DEFS_H )
|
||||
#include <classlib/defs.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_THREAD_H )
|
||||
#include <classlib/thread.h>
|
||||
#endif
|
||||
|
||||
DIAG_DEFINE_GROUP(Threads,1,0);
|
||||
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to close thread handle.
|
||||
//
|
||||
|
||||
inline void InternalCloseHandle( TThread::THandle Handle )
|
||||
{
|
||||
::CloseHandle(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to suspend thread.
|
||||
//
|
||||
|
||||
inline DWORD InternalSuspendThread( TThread::THandle Handle )
|
||||
{
|
||||
return ::SuspendThread(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to suspend thread.
|
||||
//
|
||||
|
||||
inline DWORD InternalResumeThread( TThread::THandle Handle )
|
||||
{
|
||||
return ::ResumeThread(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to wait for thread termination.
|
||||
//
|
||||
|
||||
inline unsigned long InternalWaitForThread( TThread::THandle Handle,
|
||||
unsigned long timeout )
|
||||
{
|
||||
return ::WaitForSingleObject( Handle, timeout );
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to get thread priority.
|
||||
//
|
||||
|
||||
inline int InternalGetThreadPriority( TThread::THandle Handle )
|
||||
{
|
||||
return ::GetThreadPriority( Handle );
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
// Use OS call to set thread priority.
|
||||
//
|
||||
|
||||
inline int InternalSetThreadPriority( TThread::THandle Handle, int pri )
|
||||
{
|
||||
return ::SetThreadPriority( Handle, pri );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( BI_PLAT_OS2 )
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// OS/2
|
||||
//
|
||||
// Don't need to close the handle.
|
||||
//
|
||||
inline void InternalCloseHandle( TThread::THandle )
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// OS/2
|
||||
//
|
||||
// Use OS call to suspend thread.
|
||||
//
|
||||
|
||||
inline ULONG InternalSuspendThread( TThread::THandle Handle )
|
||||
{
|
||||
return ::DosSuspendThread(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// OS/2
|
||||
//
|
||||
// Use OS call to suspend thread.
|
||||
//
|
||||
|
||||
inline ULONG InternalResumeThread( TThread::THandle Handle )
|
||||
{
|
||||
return ::DosResumeThread(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// OS/2
|
||||
//
|
||||
// Use OS call to wait for thread termination.
|
||||
//
|
||||
|
||||
inline ULONG InternalWaitForThread( TThread::THandle &Handle,
|
||||
unsigned long timeout )
|
||||
{
|
||||
return ::DosWaitThread( &Handle, timeout );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread constructors
|
||||
//
|
||||
|
||||
TThread::TThread() :
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
ThreadId(0),
|
||||
#elif defined( BI_PLAT_OS2 )
|
||||
Priority(0),
|
||||
#endif
|
||||
Handle(0),
|
||||
Stat(Created),
|
||||
TerminationRequested(0)
|
||||
{
|
||||
}
|
||||
|
||||
TThread::TThread( const TThread& ) :
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
ThreadId(0),
|
||||
#elif defined( BI_PLAT_OS2 )
|
||||
Priority(0),
|
||||
#endif
|
||||
Handle(0),
|
||||
Stat(Created),
|
||||
TerminationRequested(0)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread assignment operator
|
||||
//
|
||||
// Used when assigning derived objects. Attempting to
|
||||
// assign from a running object is an error, since the
|
||||
// data fields in the running object can be changing
|
||||
// asynchronously.
|
||||
//
|
||||
|
||||
const TThread& TThread::operator = ( const TThread& thread )
|
||||
{
|
||||
switch( GetStatus() )
|
||||
{
|
||||
case Created:
|
||||
case Suspended:
|
||||
case Finished:
|
||||
{
|
||||
if( this != &thread )
|
||||
{
|
||||
Handle = 0;
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
ThreadId = 0;
|
||||
#elif defined( BI_PLAT_OS2 )
|
||||
Priority = 0;
|
||||
#endif
|
||||
Stat = Created;
|
||||
TerminationRequested = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
default:
|
||||
throw ThreadError(ThreadError::AssignError);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread destructor
|
||||
//
|
||||
// If the thread hasn't finished, destroying its control
|
||||
// object is an error.
|
||||
//
|
||||
|
||||
TThread::~TThread()
|
||||
{
|
||||
if( GetStatus() != Finished )
|
||||
throw ThreadError(ThreadError::DestroyBeforeExit);
|
||||
InternalCloseHandle(Handle);
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::Start()
|
||||
//
|
||||
// Starts the thread executing. The actual call depends on the
|
||||
// operating system. After the system call we check status.
|
||||
//
|
||||
|
||||
TThread::THandle TThread::Start()
|
||||
{
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
#if defined( __MT__ )
|
||||
Handle = (HANDLE)::_beginthreadNT( &TThread::Execute, 4096, this, 0, 0, &ThreadId );
|
||||
#else
|
||||
Handle = ::CreateThread( 0, 0, &TThread::Execute, this, 0, &ThreadId );
|
||||
#endif
|
||||
#else
|
||||
#if defined( __MT__ )
|
||||
Handle = ::_beginthread( &TThread::Execute, 4096, this );
|
||||
#else
|
||||
APIRET res =
|
||||
::DosCreateThread( &Handle,
|
||||
(void (__syscall*)(unsigned long))&TThread::Execute,
|
||||
REINTERPRET_CAST(unsigned long,this),
|
||||
FALSE,
|
||||
4000 );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if( Handle != 0 )
|
||||
{
|
||||
TRACEX( Threads, 1, "Thread started [id:" << Handle << ']' );
|
||||
Stat = Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACEX(Threads, 2, "Thread failed to start" );
|
||||
Stat = Invalid;
|
||||
throw ThreadError(ThreadError::CreationFailure);
|
||||
}
|
||||
|
||||
return Handle;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::Suspend()
|
||||
//
|
||||
// It's an error to try to suspend a thread that
|
||||
// hasn't been started or that has already terminated.
|
||||
//
|
||||
|
||||
unsigned long TThread::Suspend()
|
||||
{
|
||||
switch( GetStatus() )
|
||||
{
|
||||
case Created:
|
||||
TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
|
||||
throw ThreadError(ThreadError::SuspendBeforeRun);
|
||||
case Finished:
|
||||
TRACEX( Threads, 2, "Illegal thread suspension [id:" << Handle << ']' );
|
||||
throw ThreadError(ThreadError::SuspendAfterExit);
|
||||
default:
|
||||
TRACEX( Threads, 0, "Thread suspended [id:" << Handle << ']' );
|
||||
Stat = Suspended;
|
||||
return InternalSuspendThread(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::Resume()
|
||||
//
|
||||
// It's an error to try to resume a thread that hasn't
|
||||
// been suspended.
|
||||
//
|
||||
|
||||
unsigned long TThread::Resume()
|
||||
{
|
||||
switch( GetStatus() )
|
||||
{
|
||||
case Created:
|
||||
TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
|
||||
throw ThreadError(ThreadError::ResumeBeforeRun);
|
||||
case Running:
|
||||
TRACEX( Threads, 2, "Illegal thread resumption [id:" << Handle << ']' );
|
||||
throw ThreadError(ThreadError::ResumeDuringRun);
|
||||
case Finished:
|
||||
throw ThreadError(ThreadError::ResumeAfterExit);
|
||||
default:
|
||||
TRACEX( Threads, 0, "Thread resumed [id:" << Handle << ']' );
|
||||
unsigned long res = InternalResumeThread(Handle);
|
||||
if( res == 0 )
|
||||
Stat = Running;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::Terminate()
|
||||
//
|
||||
// Mark the thread for termination.
|
||||
//
|
||||
|
||||
void TThread::Terminate()
|
||||
{
|
||||
TRACEX( Threads, 1, "Thread termination requested [handle:" << Handle << ']' );
|
||||
TerminationRequested = 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::WaitForExit()
|
||||
//
|
||||
// Block until the thread terminates.
|
||||
//
|
||||
// IMPORTANT: the meaning of the 'timeout' parameter is
|
||||
// different for NT and OS/2. Under NT it specifies how long
|
||||
// to wait for termination. Under OS/2 it specifies whether
|
||||
// to wait or to return immediately if the thread hasn't
|
||||
// terminated.
|
||||
//
|
||||
|
||||
unsigned long TThread::WaitForExit( unsigned long timeout )
|
||||
{
|
||||
TRACEX( Threads, 1, "Waiting for thread exit [id:" << Handle << ']' );
|
||||
if( Stat == Running )
|
||||
return ::InternalWaitForThread( Handle, timeout );
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::TerminateAndWait()
|
||||
//
|
||||
// See note for WaitForExit().
|
||||
//
|
||||
|
||||
unsigned long TThread::TerminateAndWait( unsigned long timeout )
|
||||
{
|
||||
Terminate();
|
||||
return WaitForExit( timeout );
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::SetPriority()
|
||||
//
|
||||
// Set the thread's priority.
|
||||
//
|
||||
|
||||
int TThread::SetPriority( int pri )
|
||||
{
|
||||
TRACEX( Threads, 1, "Thread priority changed to " << pri << " [id:" << Handle << ']' );
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
return ::SetThreadPriority(Handle,pri);
|
||||
#else
|
||||
|
||||
APIRET res = DosSetPriority( PRTYS_THREAD,
|
||||
PRTYC_NOCHANGE,
|
||||
pri-Priority,
|
||||
Handle );
|
||||
if( res != 0 )
|
||||
Priority = pri;
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::Execute()
|
||||
//
|
||||
// Run the thread.
|
||||
//
|
||||
|
||||
#if defined( __MT__ )
|
||||
void _USERENTRY TThread::Execute( void *thread )
|
||||
{
|
||||
STATIC_CAST(TThread*,thread)->Run();
|
||||
}
|
||||
#elif defined( BI_PLAT_WIN32 )
|
||||
unsigned long _stdcall TThread::Execute( void *thread )
|
||||
{
|
||||
return STATIC_CAST(TThread*,thread)->Run();
|
||||
}
|
||||
#else
|
||||
void __stdcall TThread::Execute( unsigned long thread )
|
||||
{
|
||||
REINTERPRET_CAST(TThread*,thread)->Run();
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::CheckStatus()
|
||||
//
|
||||
// Call only when Stat claims that the thread is Running.
|
||||
//
|
||||
|
||||
#if defined( BI_PLAT_WIN32 )
|
||||
TThread::Status TThread::CheckStatus() const
|
||||
{
|
||||
DWORD ExitCode;
|
||||
::GetExitCodeThread( Handle, &ExitCode );
|
||||
if( ExitCode == STILL_ACTIVE )
|
||||
return Running;
|
||||
else
|
||||
return Finished;
|
||||
}
|
||||
#elif defined( BI_PLAT_OS2 )
|
||||
TThread::Status TThread::CheckStatus() const
|
||||
{
|
||||
if( ::DosWaitThread( CONST_CAST(THandle *,&Handle), DCWW_NOWAIT ) == ERROR_THREAD_NOT_TERMINATED )
|
||||
return Running;
|
||||
else
|
||||
return Finished;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::ThreadError constructor
|
||||
//
|
||||
|
||||
TThread::ThreadError::ThreadError(ErrorType type) :
|
||||
xmsg(MakeString(type)),
|
||||
Type(type)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//
|
||||
// TThread::ThreadError::MakeString()
|
||||
//
|
||||
// Translates an error code into a string.
|
||||
//
|
||||
|
||||
string TThread::ThreadError::MakeString(ErrorType type)
|
||||
{
|
||||
static char *Names[] =
|
||||
{
|
||||
"Suspend() before Run()",
|
||||
"Resume() before Run()",
|
||||
"Resume() during Run()",
|
||||
"Suspend() after Exit()",
|
||||
"Resume() after Exit()",
|
||||
"creation failure",
|
||||
"destroyed before Exit()",
|
||||
"illegal assignment"
|
||||
};
|
||||
string Msg;
|
||||
Msg.reserve(40);
|
||||
Msg = "Error[thread]: ";
|
||||
Msg += Names[type];
|
||||
return Msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* TIME.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __TIME_H )
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CHECKS_H )
|
||||
#include <checks.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_TIME_H )
|
||||
#include <classlib/time.h>
|
||||
#endif
|
||||
|
||||
enum TimeZone { CarolineIslands=-11, MarianaIslands, Japan,
|
||||
China, minusSeven, minusSix,
|
||||
Pakistan, CaspianSea, Turkey,
|
||||
Finland, Europe, Greenwich,
|
||||
Azores, two, Greenland,
|
||||
Atlantic, USEastern, USCentral,
|
||||
USMountain, USPacific, Alaska,
|
||||
Hawaii, Bearing};
|
||||
|
||||
static const unsigned long SECONDS_IN_DAY = 86400L;
|
||||
static const unsigned long SECONDS_IN_HOUR = 3600L;
|
||||
static const unsigned SECONDS_IN_MIN = 60;
|
||||
|
||||
// Be sure that you have set your environment variable TZ.
|
||||
// For example, for Pacific coast time, set TZ=PDT8PST.
|
||||
// For other time zones, see your manuals.
|
||||
|
||||
struct TInitTime
|
||||
{
|
||||
TInitTime()
|
||||
{ tzset(); }
|
||||
};
|
||||
|
||||
static TInitTime cludgeTime; // To force the call to tzset()
|
||||
|
||||
|
||||
const TDate TTime::RefDate( (DayTy)0, (YearTy)0 );
|
||||
const TDate TTime::MaxDate( (DayTy)49709L, (YearTy)0 ); // ((2**32)-1)/SECONDS_IN_DAY -1
|
||||
static const int SUNDAY = 7;
|
||||
|
||||
int TTime::AssertDate( const TDate _BIDSFAR & date )
|
||||
{
|
||||
return date.Between(RefDate,MaxDate);
|
||||
}
|
||||
|
||||
/******************* private member functions ***********************/
|
||||
|
||||
|
||||
// Adjust for local time zone and Daylight Savings Time.
|
||||
ClockTy TTime::LocalSecs() const
|
||||
{
|
||||
TTime local_time( Sec - timezone );
|
||||
if (local_time.IsDST())
|
||||
local_time.Sec += SECONDS_IN_HOUR;
|
||||
return local_time.Sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds the time from a local time, adjusting to GMT. Does *not* adjust for DST.
|
||||
*/
|
||||
TTime TTime::BuildLocal( const TDate _BIDSFAR & date, HourTy h )
|
||||
{
|
||||
return TTime( SECONDS_IN_DAY * (date-RefDate) +
|
||||
SECONDS_IN_HOUR * h +
|
||||
timezone);
|
||||
}
|
||||
|
||||
/*************** public static member functions *******************/
|
||||
|
||||
/*
|
||||
* Return the time at which DST starts for the given year.
|
||||
* Note that the time returned is the time at which DST starts locally,
|
||||
* but it is returned in GMT.
|
||||
*/
|
||||
TTime TTime::BeginDST( unsigned year )
|
||||
{
|
||||
if( year > 1986 )
|
||||
{
|
||||
TDate endMarch(31, 3, year);
|
||||
return BuildLocal( endMarch.Previous(SUNDAY)+7, 2 );
|
||||
}
|
||||
|
||||
// Ah, remember those energy conscious years...???
|
||||
if( year==1974 )
|
||||
return BuildLocal( TDate(6,1,1974), 2 );
|
||||
if( year==1975 )
|
||||
return BuildLocal( TDate(23,2,1975), 2 );
|
||||
|
||||
TDate endApril( 30, 4, year );
|
||||
return BuildLocal( endApril.Previous(SUNDAY), 2 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the time at which DST ends for the given year.
|
||||
* Note that the time returned is the time at which DST ends locally,
|
||||
* but it is returned in GMT.
|
||||
*/
|
||||
TTime TTime::EndDST( unsigned year )
|
||||
{
|
||||
TDate endOctober( 31, 10, year );
|
||||
return BuildLocal( endOctober.Previous(SUNDAY), 1 );
|
||||
}
|
||||
|
||||
|
||||
/************************* constructor *********************************/
|
||||
|
||||
// Construct TTime with current time (seconds since Jan 1, 1901).
|
||||
TTime::TTime()
|
||||
{
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
struct tm _FAR *t = localtime(<ime);
|
||||
|
||||
// Construct the date. The time struct returns int, so casts are used.
|
||||
|
||||
TDate today( (DayTy)t->tm_mday,
|
||||
(MonthTy)(t->tm_mon + 1),
|
||||
(YearTy)t->tm_year );
|
||||
|
||||
*this = TTime( today,
|
||||
(HourTy)t->tm_hour,
|
||||
(MinuteTy)t->tm_min,
|
||||
(SecondTy)t->tm_sec );
|
||||
}
|
||||
|
||||
// Specified time and today's date:
|
||||
TTime::TTime( HourTy h, MinuteTy m, SecondTy s )
|
||||
{
|
||||
Sec = TTime( TDate(),h,m,s ).Sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a Time for the specified (local) Date, hour, minute, and second.
|
||||
* Note: this algorithm will fail if DST correction is something other
|
||||
* than an hour.
|
||||
* It is complicated by the DST boundary problem:
|
||||
* 1) Times in the phantom zone between 2AM and 3AM when DST is invoked are invalid.
|
||||
* 2) Times in the hour after 1AM when DST ends, are redundant.
|
||||
* Checking for these situations necessitates a lot of jumping back
|
||||
* and forth by an hour to check for the boundary.
|
||||
*/
|
||||
TTime::TTime( const TDate _BIDSFAR & date, HourTy h, MinuteTy m, SecondTy s )
|
||||
{
|
||||
if( date.IsValid() )
|
||||
{
|
||||
Sec = SECONDS_IN_DAY * (date-RefDate) +
|
||||
SECONDS_IN_HOUR * (h-1L) + /* Note the adjustment by one hour */
|
||||
SECONDS_IN_MIN * m + s;
|
||||
if( Sec )
|
||||
Sec += timezone; // Adjust to GMT.
|
||||
|
||||
if( IsDST() )
|
||||
{
|
||||
Sec += SECONDS_IN_HOUR;
|
||||
if( IsDST() )
|
||||
Sec -= SECONDS_IN_HOUR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sec += SECONDS_IN_HOUR;
|
||||
if( IsDST() )
|
||||
Sec = 0; // Invalid "phantom" time.
|
||||
}
|
||||
}
|
||||
else
|
||||
Sec = 0; // Invalid date
|
||||
}
|
||||
|
||||
/*************** conversion from TTime to TDate *******************/
|
||||
|
||||
// Type conversion to date.
|
||||
TDate::TDate( const TTime _BIDSFAR & t )
|
||||
{
|
||||
Julnum = t.IsValid() ? jul1901 + (JulTy)(t.LocalSecs()/SECONDS_IN_DAY) : 0;
|
||||
}
|
||||
|
||||
/********************* public member functions **********************/
|
||||
|
||||
int TTime::CompareTo( const TTime _BIDSFAR &t ) const
|
||||
{
|
||||
ClockTy diff = Sec - t.Sec;
|
||||
return diff==0 ? 0 : diff>0 ? 1 : -1;
|
||||
}
|
||||
|
||||
// Hash function:
|
||||
unsigned TTime::Hash() const
|
||||
{
|
||||
return (unsigned)Sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hour in local time:
|
||||
*/
|
||||
HourTy TTime::Hour() const
|
||||
{
|
||||
return HourTy((LocalSecs() % SECONDS_IN_DAY) / SECONDS_IN_HOUR);
|
||||
}
|
||||
|
||||
/*
|
||||
* The hour in GMT:
|
||||
*/
|
||||
HourTy TTime::HourGMT() const
|
||||
{
|
||||
return HourTy((Sec % SECONDS_IN_DAY) / SECONDS_IN_HOUR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if DST is active for this time:
|
||||
*/
|
||||
int TTime::IsDST() const
|
||||
{
|
||||
if( !daylight )
|
||||
return 0;
|
||||
|
||||
DayTy daycount = (unsigned)(Sec/SECONDS_IN_DAY);
|
||||
YearTy year = TDate( (DayTy)daycount, (YearTy)0 ).Year();
|
||||
|
||||
// Check to see if the time falls between the starting & stopping DST times.
|
||||
return *this >= BeginDST( year ) && *this < EndDST( year );
|
||||
}
|
||||
|
||||
TTime TTime::Max( const TTime _BIDSFAR & t ) const
|
||||
{
|
||||
if( *this > t )
|
||||
return *this;
|
||||
else
|
||||
return t;
|
||||
}
|
||||
|
||||
TTime TTime::Min( const TTime _BIDSFAR & t ) const
|
||||
{
|
||||
if( *this < t )
|
||||
return *this;
|
||||
else
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* minute, in local time
|
||||
*/
|
||||
MinuteTy TTime::Minute() const
|
||||
{
|
||||
return MinuteTy(((LocalSecs()%SECONDS_IN_DAY)%SECONDS_IN_HOUR)/SECONDS_IN_MIN);
|
||||
}
|
||||
|
||||
/*
|
||||
* minute: GMT
|
||||
*/
|
||||
MinuteTy TTime::MinuteGMT() const
|
||||
{
|
||||
return MinuteTy(((Sec%SECONDS_IN_DAY)%SECONDS_IN_HOUR)/SECONDS_IN_MIN);
|
||||
}
|
||||
|
||||
// second;local time or GMT
|
||||
SecondTy TTime::Second() const
|
||||
{
|
||||
return SecondTy(((Sec%SECONDS_IN_DAY)%SECONDS_IN_HOUR)%SECONDS_IN_MIN);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* TIMEIO.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STDIO_H )
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __IOMANIP_H )
|
||||
#include <iomanip.h>
|
||||
#endif
|
||||
|
||||
#if !defined( __CSTRING_H )
|
||||
#include <cstring.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_TIME_H )
|
||||
#include <classlib/time.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_FILE_H )
|
||||
#include <classlib/file.h>
|
||||
#endif
|
||||
|
||||
// Static variable intialization:
|
||||
int TTime::PrintDateFlag = 1;
|
||||
|
||||
string TTime::AsString() const
|
||||
{
|
||||
char buf[80];
|
||||
ostrstream strtemp(buf, sizeof(buf));
|
||||
strtemp << (*this) << ends;
|
||||
string temp(buf);
|
||||
return temp;
|
||||
}
|
||||
|
||||
ostream _BIDSFAR & _BIDSFUNC operator << ( ostream _BIDSFAR & s, const TTime _BIDSFAR & t )
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
// We use an ostrstream to format into buf so that
|
||||
// we don't affect the ostream's width setting.
|
||||
ostrstream out( buf, sizeof(buf) );
|
||||
|
||||
// First print the date if requested:
|
||||
if(TTime::PrintDateFlag)
|
||||
out << TDate(t) << " ";
|
||||
|
||||
unsigned hh = t.Hour();
|
||||
out << (hh <= 12 ? hh : hh-12) << ':'
|
||||
<< setfill('0') << setw(2) << t.Minute() << ':'
|
||||
<< setw(2) << t.Second() << ' ' << setfill(' ');
|
||||
out << ( hh<12 ? "am" : "pm") << ends;
|
||||
|
||||
// now we write out the formatted buffer, and the ostream's
|
||||
// width setting will control the actual width of the field.
|
||||
s << buf;
|
||||
return s;
|
||||
}
|
||||
|
||||
int TTime::PrintDate( int f )
|
||||
{
|
||||
int temp = PrintDateFlag;
|
||||
PrintDateFlag = f;
|
||||
return temp;
|
||||
}
|
||||
|
||||
ostream _BIDSFAR & _BIDSFUNC operator << ( ostream _BIDSFAR & os, const TFileStatus _BIDSFAR & status )
|
||||
{
|
||||
os << "File Status: " << status.fullName << '\n';
|
||||
os << " created: " << status.createTime << '\n';
|
||||
os << " modified: " << status.modifyTime << '\n';
|
||||
os << " accessed: " << status.accessTime << '\n';
|
||||
os << " size: " << status.size << '\n';
|
||||
os << " attributes: " << (int)status.attribute << '\n';
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* TIMEP.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __STRSTREA_H )
|
||||
#include <strstrea.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_TIME_H )
|
||||
#include <classlib/time.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_OBJSTRM_H )
|
||||
#include <classlib/objstrm.h>
|
||||
#endif
|
||||
|
||||
opstream _BIDSFAR & _BIDSFUNC operator << ( opstream _BIDSFAR & os,
|
||||
const TTime _BIDSFAR & d )
|
||||
{
|
||||
return os << d.Sec;
|
||||
}
|
||||
|
||||
ipstream _BIDSFAR & _BIDSFUNC operator >> ( ipstream _BIDSFAR & is,
|
||||
TTime _BIDSFAR & d )
|
||||
{
|
||||
return is >> d.Sec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* TIMER.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1991, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( __DOS_H )
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#define BUILDBIDSTIMER
|
||||
|
||||
#if !defined( CLASSLIB_TIMER_H )
|
||||
#include <classlib/timer.h>
|
||||
#endif
|
||||
|
||||
const unsigned long far * const dosTime =
|
||||
(const unsigned long far * const)MK_FP( 0x40, 0x6C );
|
||||
|
||||
unsigned TTimer::Adjust = Calibrate();
|
||||
|
||||
TTimer::TTimer() : Time_(0), Running(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TTimer::Start()
|
||||
{
|
||||
if( !Running )
|
||||
{
|
||||
outportb( 0x43, 0x34 );
|
||||
asm jmp __1;
|
||||
__1:
|
||||
outportb( 0x40, 0 );
|
||||
asm jmp __2;
|
||||
__2:
|
||||
outportb( 0x40, 0 );
|
||||
StartTime.DosCount = *dosTime;
|
||||
StartTime.TimerCount = 0;
|
||||
Running = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void TTimer::Stop()
|
||||
{
|
||||
outportb( 0x43, 0 );
|
||||
unsigned char temp = inportb( 0x40 );
|
||||
|
||||
TIME stopTime;
|
||||
stopTime.TimerCount = (inportb( 0x40 ) << 8) + temp;
|
||||
stopTime.DosCount = *dosTime;
|
||||
|
||||
TIME elapsedTime;
|
||||
elapsedTime.DosCount = stopTime.DosCount - StartTime.DosCount;
|
||||
elapsedTime.TimerCount = -( stopTime.TimerCount - Adjust );
|
||||
|
||||
const double fudge = 83810.0/100000.0;
|
||||
Time_ += ((elapsedTime.DosCount << 16) + elapsedTime.TimerCount)*fudge;
|
||||
|
||||
Running = 0;
|
||||
|
||||
}
|
||||
|
||||
void TTimer::Reset()
|
||||
{
|
||||
Time_ = 0;
|
||||
if( Running )
|
||||
Start();
|
||||
}
|
||||
|
||||
unsigned TTimer::Calibrate()
|
||||
{
|
||||
Adjust = 0;
|
||||
unsigned long sum = 0;
|
||||
TTimer w;
|
||||
for( int i = 0; i < 100; i++ )
|
||||
{
|
||||
w.Start();
|
||||
w.Stop();
|
||||
sum += w.Time();
|
||||
w.Reset();
|
||||
}
|
||||
return (unsigned)((sum+5)/100);
|
||||
}
|
||||
|
||||
#if defined( TEST_TIMER )
|
||||
#include <iostream.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main( void )
|
||||
{
|
||||
delay( 0 );
|
||||
cout << "Resolution: " << Timer::Resolution() << endl;
|
||||
TTimer w;
|
||||
for( unsigned del = 0; del < 10; del++ )
|
||||
{
|
||||
unsigned d1 = del*100;
|
||||
w.Start();
|
||||
delay( d1 );
|
||||
w.Stop();
|
||||
printf( "%4u ms., actual time = %6f seconds.\n", d1, w.Time() );
|
||||
w.Reset();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* TMPLINST.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1991, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/* Provides instantiations of the various Object containers, */
|
||||
/* for use in the class library DLLs. */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#pragma option -Jgd
|
||||
|
||||
#if !defined( __HASHTBL_H )
|
||||
#include <classlib\obsolete\hashtbl.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_OBJSTRM_H )
|
||||
#include <classlib/objstrm.h>
|
||||
#endif
|
||||
|
||||
// needed for HashTable
|
||||
typedef TIVectorImp<Object> dummy1;
|
||||
|
||||
// needed for Object Streaming
|
||||
typedef TSVectorImp<TPWrittenObjects::TPWObj> dummy2;
|
||||
typedef TCVectorImp<const void *> dummy3;
|
||||
typedef TISVectorImp<TStreamableClass> dummy4;
|
||||
|
||||
#if !defined( CLASSLIB_VECTIMP_H )
|
||||
#include <classlib/vectimp.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_STACKS_H )
|
||||
#include <classlib/stacks.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_QUEUES_H )
|
||||
#include <classlib/queues.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_LISTIMP_H )
|
||||
#include <classlib/listimp.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DLISTIMP_H )
|
||||
#include <classlib/dlistimp.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_DEQUES_H )
|
||||
#include <classlib/deques.h>
|
||||
#endif
|
||||
|
||||
#if !defined( CLASSLIB_SETS_H )
|
||||
#include <classlib/sets.h>
|
||||
#endif
|
||||
|
||||
typedef TSDoubleListImp<void _FAR *> dummy6;
|
||||
typedef TDoubleListIteratorImp<void _FAR *> dummy7;
|
||||
|
||||
typedef TIDequeAsVector<Object> dummy8;
|
||||
typedef TIDequeAsVectorIterator<Object> dummy9;
|
||||
|
||||
typedef TIDequeAsDoubleList<Object> dummy10;
|
||||
typedef TIDequeAsDoubleListIterator<Object> dummy11;
|
||||
|
||||
typedef TSListImp<void _FAR *> dummy12;
|
||||
typedef TListIteratorImp<void _FAR *> dummy13;
|
||||
|
||||
typedef TIQueueAsVector<Object> dummy14;
|
||||
typedef TIQueueAsVectorIterator<Object> dummy15;
|
||||
|
||||
typedef TIQueueAsDoubleList<Object> dummy16;
|
||||
typedef TIQueueAsDoubleListIterator<Object> dummy17;
|
||||
|
||||
typedef TIStackAsVector<Object> dummy18;
|
||||
typedef TIStackAsVectorIterator<Object> dummy19;
|
||||
|
||||
typedef TIStackAsList<Object> dummy20;
|
||||
typedef TIStackAsListIterator<Object> dummy21;
|
||||
|
||||
typedef TVectorImp<void _FAR *> dummy22;
|
||||
typedef TCVectorImp<void _FAR *> dummy23;
|
||||
typedef TSVectorImp<void _FAR *> dummy24;
|
||||
typedef TMVectorIteratorImp<void _FAR *,TStandardAllocator> dummy25;
|
||||
|
||||
typedef TISetAsVector<Object> dummy26;
|
||||
typedef TISetAsVectorIterator<Object> dummy27;
|
||||
|
||||
typedef TICVectorImp<Object> dummy28;
|
||||
@@ -0,0 +1,468 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
||||
//
|
||||
// TUString implementation (others functions are inline)
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#if !defined(_Windows)
|
||||
# define _Windows // pretend we are in windows to get the headers we need
|
||||
#endif
|
||||
#if !defined(INC_OLE2)
|
||||
# define INC_OLE2 // Make sure we get Ole2 headers
|
||||
#endif
|
||||
#include <osl/ustring.h>
|
||||
#include <osl/inlines.h>
|
||||
#include <string.h>
|
||||
|
||||
TUString TUString::Null; // null TAutoStrings reference this object
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
//
|
||||
// Take a wide char string & return an ANSI string in a new'd char[] buffer
|
||||
//
|
||||
char* TUString::ConvertWtoA(const wchar_t* src, size_t len)
|
||||
{
|
||||
size_t size = WideCharToMultiByte(CP_ACP, 0, src, len, 0, 0, 0, 0);
|
||||
char* dst = new char[size + (len != -1)]; // room for null if fixed size
|
||||
size = WideCharToMultiByte(CP_ACP, 0, src, len, dst, size, 0, 0);
|
||||
if (len != -1)
|
||||
dst[size] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
//
|
||||
// Take an ANSI char string & return a wide string in a new'd wchar_t[] buffer
|
||||
//
|
||||
wchar_t* TUString::ConvertAtoW(const char* src, size_t len)
|
||||
{
|
||||
size_t size = MultiByteToWideChar(CP_ACP, 0, src, len, 0, 0);
|
||||
wchar_t* dst = new wchar_t[size + (len != -1)];
|
||||
size = MultiByteToWideChar(CP_ACP, 0, src, len, dst, size);
|
||||
if (len != -1)
|
||||
dst[size] = 0;
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Change UString to isCopy regardless of current type
|
||||
//
|
||||
char* TUString::ChangeToCopy()
|
||||
{
|
||||
char* dst = 0;
|
||||
const char far* src;
|
||||
int len;
|
||||
switch (Kind) {
|
||||
case isNull:
|
||||
return 0;
|
||||
case isConst:
|
||||
src = Const;
|
||||
len = strlen(Const);
|
||||
break;
|
||||
case isCopy:
|
||||
return Copy;
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
case isWConst:
|
||||
dst = ConvertWtoA(WConst);
|
||||
break;
|
||||
case isWCopy:
|
||||
dst = ConvertWtoA(WCopy);
|
||||
delete [] WCopy;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BI_OLECHAR_WIDE)
|
||||
case isBstr:
|
||||
case isExtBstr:
|
||||
dst = ConvertWtoA(Bstr, ::SysStringLen(Bstr));
|
||||
break;
|
||||
#else
|
||||
case isBstr:
|
||||
case isExtBstr:
|
||||
src = Bstr;
|
||||
len = ::SysStringLen(Bstr);
|
||||
break;
|
||||
#endif
|
||||
case isString:
|
||||
src = ((string*)&String)->c_str();
|
||||
len = ((string*)&String)->length();
|
||||
}
|
||||
if (!dst) {
|
||||
dst = new char[len+1];
|
||||
memcpy(dst, src, len+1);
|
||||
}
|
||||
if (Kind == isBstr)
|
||||
::SysFreeString(Bstr);
|
||||
Kind = isCopy;
|
||||
Copy = dst;
|
||||
return Copy;
|
||||
}
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
//
|
||||
// Change UString to isWCopy regardless of current type
|
||||
//
|
||||
wchar_t* TUString::ChangeToWCopy()
|
||||
{
|
||||
wchar_t* dst = 0;
|
||||
const wchar_t* src;
|
||||
int len;
|
||||
switch (Kind) {
|
||||
case isNull:
|
||||
return 0;
|
||||
case isConst:
|
||||
dst = ConvertAtoW(Const);
|
||||
break;
|
||||
case isCopy:
|
||||
dst = ConvertAtoW(Copy);
|
||||
delete [] Copy;
|
||||
break;
|
||||
case isWConst:
|
||||
src = WConst;
|
||||
len = strlen(WConst);
|
||||
break;
|
||||
case isWCopy:
|
||||
return WCopy;
|
||||
#if defined(BI_OLECHAR_WIDE)
|
||||
case isBstr:
|
||||
case isExtBstr:
|
||||
src = Bstr;
|
||||
len = ::SysStringLen(Bstr);
|
||||
if (Kind == isBstr)
|
||||
::SysFreeString(Bstr);
|
||||
break;
|
||||
#else // This case probably never happens
|
||||
case isBstr:
|
||||
case isExtBstr:
|
||||
dst = ConvertAtoW(Bstr, ::SysStringLen(Bstr));
|
||||
if (Kind == isBstr)
|
||||
::SysFreeString(Bstr);
|
||||
break;
|
||||
#endif
|
||||
case isString:
|
||||
dst = ConvertAtoW(((string*)&String)->c_str(), ((string*)&String)->length());
|
||||
}
|
||||
if (!dst) {
|
||||
dst = new wchar_t[len+1];
|
||||
memcpy(dst, src, (len+1) * sizeof(wchar_t));
|
||||
}
|
||||
Kind = isWCopy;
|
||||
WCopy = dst;
|
||||
return WCopy;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// inline ctors used by Create functions
|
||||
|
||||
inline TUString::TUString(const char far& str)
|
||||
:
|
||||
Kind(isConst), Const(&str), RefCnt(1), Lang(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline TUString::TUString(char& str)
|
||||
:
|
||||
Kind(isCopy), RefCnt(1), Lang(0)
|
||||
{
|
||||
Copy = new char[strlen(&str)+1];
|
||||
strcpy(Copy, &str);
|
||||
}
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
inline TUString::TUString(const wchar_t& str)
|
||||
:
|
||||
Kind(isWConst), WConst(&str), RefCnt(1), Lang(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline TUString::TUString(wchar_t& str)
|
||||
:
|
||||
Kind(isWCopy), RefCnt(1), Lang(0)
|
||||
{
|
||||
WCopy = new wchar_t[strlen(&str)+1];
|
||||
strcpy(WCopy, &str);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline TUString::TUString(BSTR str, bool loan, TLangId lang)
|
||||
:
|
||||
Kind(loan ? isExtBstr : isBstr), Bstr(str), RefCnt(loan ? 2 : 1), Lang(lang)
|
||||
{
|
||||
}
|
||||
|
||||
inline void* operator new(size_t, TStringRef** p) {return p;}
|
||||
|
||||
inline TUString::TUString(const string& str)
|
||||
:
|
||||
Kind(isString), RefCnt(1), Lang(0)
|
||||
{
|
||||
new(&String) string(str);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
TUString* TUString::Create(const char far* str)
|
||||
{
|
||||
return str && *str ? new TUString(*str) : &++Null;
|
||||
}
|
||||
|
||||
TUString* TUString::Create(char* str)
|
||||
{
|
||||
return str && *str ? new TUString(*str) : &++Null;
|
||||
}
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
TUString* TUString::Create(const wchar_t* str)
|
||||
{
|
||||
return str && *str ? new TUString(*str) : &++Null;
|
||||
}
|
||||
|
||||
TUString* TUString::Create(wchar_t* str)
|
||||
{
|
||||
return str && *str ? new TUString(*str) : &++Null;
|
||||
}
|
||||
#endif
|
||||
|
||||
TUString* TUString::Create(BSTR str, bool loan, TLangId lang)
|
||||
{
|
||||
if (str && ::SysStringLen(str))
|
||||
return new TUString(str, loan, lang);
|
||||
if (!loan)
|
||||
::SysFreeString(str);
|
||||
return &++Null;
|
||||
}
|
||||
|
||||
TUString* TUString::Create(const string& str)
|
||||
{
|
||||
return str.length() ? new TUString(str) : &++Null;
|
||||
}
|
||||
|
||||
TUString* TUString::Assign(const TUString& s)
|
||||
{
|
||||
if (RefCnt == 1 && Kind != isNull && Kind != isExtBstr)
|
||||
Free();
|
||||
else
|
||||
--*this;
|
||||
|
||||
CONST_CAST(TUString&,s).RefCnt++;
|
||||
return &CONST_CAST(TUString&,s);
|
||||
}
|
||||
|
||||
TUString* TUString::Assign(const string& s)
|
||||
{
|
||||
if (s.length() && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isString;
|
||||
new(&String) string(s);
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(s);
|
||||
}
|
||||
}
|
||||
|
||||
TUString* TUString::Assign(const char far* s)
|
||||
{
|
||||
if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isConst;
|
||||
Const = s;
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(s);
|
||||
}
|
||||
}
|
||||
|
||||
TUString* TUString::Assign(char* s)
|
||||
{
|
||||
if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isCopy;
|
||||
Copy = new char[strlen(s)+1];
|
||||
strcpy(Copy, s);
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(s);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
TUString* TUString::Assign(const wchar_t* s)
|
||||
{
|
||||
if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isWConst;
|
||||
WConst = s;
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(s);
|
||||
}
|
||||
}
|
||||
|
||||
TUString* TUString::Assign(wchar_t* s)
|
||||
{
|
||||
if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isWCopy;
|
||||
WCopy = new wchar_t[strlen(s)+1];
|
||||
strcpy(WCopy, s);
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(s);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TUString* TUString::Assign(BSTR str, TLangId lang)
|
||||
{
|
||||
if (RefCnt==1 && Kind != isNull && Kind != isExtBstr) {
|
||||
Free();
|
||||
Kind = isBstr;
|
||||
Bstr = str;
|
||||
Lang = lang;
|
||||
if (Bstr && ::SysStringLen(Bstr))
|
||||
return this;
|
||||
delete this;
|
||||
return &++Null;
|
||||
}
|
||||
else {
|
||||
--*this;
|
||||
return Create(str, false, lang);
|
||||
}
|
||||
}
|
||||
|
||||
TUString::operator const char far*() const
|
||||
{
|
||||
switch (Kind) {
|
||||
case isNull: return 0;
|
||||
case isConst: return Const;
|
||||
case isCopy: return Copy;
|
||||
case isString: return ((string*)&String)->c_str();
|
||||
#if defined(BI_OLECHAR_WIDE)
|
||||
case isBstr:
|
||||
case isExtBstr: return CONST_CAST(TUString*,this)->ChangeToCopy();
|
||||
#else
|
||||
case isBstr:
|
||||
case isExtBstr: return Bstr;
|
||||
#endif
|
||||
case isWConst:
|
||||
case isWCopy: return CONST_CAST(TUString*,this)->ChangeToCopy();
|
||||
}
|
||||
return 0; // suppress warning
|
||||
}
|
||||
|
||||
TUString::operator char*()
|
||||
{
|
||||
return ChangeToCopy();
|
||||
}
|
||||
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
TUString::operator const wchar_t*() const
|
||||
{
|
||||
switch (Kind) {
|
||||
case isNull: return 0;
|
||||
case isWConst: return WConst;
|
||||
case isWCopy: return WCopy;
|
||||
#if defined(BI_OLECHAR_WIDE)
|
||||
case isBstr:
|
||||
case isExtBstr: return Bstr;
|
||||
#else
|
||||
case isBstr:
|
||||
case isExtBstr: return CONST_CAST(TUString*,this)->ChangeToWCopy();
|
||||
#endif
|
||||
case isConst:
|
||||
case isCopy:
|
||||
case isString: return CONST_CAST(TUString*,this)->ChangeToWCopy();
|
||||
}
|
||||
return 0; // suppress warning
|
||||
}
|
||||
|
||||
TUString::operator wchar_t*()
|
||||
{
|
||||
return ChangeToWCopy();
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
int TUString::Length() const
|
||||
{
|
||||
switch (Kind) {
|
||||
case isNull: return 0;
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
case isWConst: return strlen(WConst);
|
||||
case isWCopy: return strlen(WCopy);
|
||||
#endif
|
||||
case isBstr:
|
||||
case isExtBstr: return ::SysStringLen(Bstr);
|
||||
case isConst: return strlen(Const);
|
||||
case isCopy: return strlen(Copy);
|
||||
case isString: return ((string*)&String)->length();
|
||||
}
|
||||
return 0; // suppress warning
|
||||
}
|
||||
|
||||
//
|
||||
// Revokes BSTR ownership from this UString
|
||||
//
|
||||
void TUString::RevokeBstr(BSTR s)
|
||||
{
|
||||
if (Kind != isExtBstr || Bstr != s)
|
||||
return;
|
||||
if (RefCnt == 1) {
|
||||
Kind = isNull;
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
Kind = isCopy;
|
||||
#if defined(BI_OLECHAR_WIDE)
|
||||
WCopy = new wchar_t[strlen(s)+1];
|
||||
strcpy(WCopy, s);
|
||||
#else
|
||||
Copy = new char[strlen(s)+1];
|
||||
strcpy(Copy, s);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Passes BSTR ownership to this UString
|
||||
//
|
||||
void TUString::ReleaseBstr(BSTR s)
|
||||
{
|
||||
if (Kind == isExtBstr && Bstr == s) {
|
||||
Kind = isBstr;
|
||||
--*this;
|
||||
}
|
||||
else // has been overwritten with converted type
|
||||
::SysFreeString(Bstr);
|
||||
}
|
||||
|
||||
//
|
||||
// Free any resources held by this UString. Union & Kind left in random state;
|
||||
// must be reinitialized before use.
|
||||
//
|
||||
void TUString::Free()
|
||||
{
|
||||
switch (Kind) {
|
||||
case isCopy: delete [] Copy; break;
|
||||
#if defined(BI_HAS_WCHAR)
|
||||
case isWCopy: delete [] WCopy; break;
|
||||
#endif
|
||||
case isBstr: ::SysFreeString(Bstr); break;
|
||||
case isString: ((string*)&String)->string::~string();
|
||||
}
|
||||
Lang = 0;
|
||||
//Kind = isNull; // for safety, not really needed
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* VERSION.CPP */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined( CLASSLIB_VERSION_H )
|
||||
#include <classlib/version.h>
|
||||
#endif
|
||||
|
||||
#define ID "CLASSLIB"
|
||||
|
||||
struct TVersionHeader
|
||||
{
|
||||
char Signature[6];
|
||||
unsigned long InternalVersionNumber;
|
||||
char ComponentIDstring[sizeof (ID)];
|
||||
} VersionHeader =
|
||||
|
||||
{
|
||||
{'$', '*', '$', '*', '$', '*'},
|
||||
{InternalVersion},
|
||||
ID
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* VERSION.RC */
|
||||
/* */
|
||||
/* Copyright (c) 1993, 1994 Borland International */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#include <ver.h>
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE
|
||||
FILEFLAGS VS_FF_PRERELEASE | VS_FF_SPECIALBUILD
|
||||
#ifndef WIN32
|
||||
FILEOS VOS_DOS_WINDOWS16
|
||||
#else
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
#endif
|
||||
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VS_USER_DEFINED
|
||||
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Borland International\0"
|
||||
VALUE "FileDescription", "BIDS Class Library\0"
|
||||
VALUE "FileVersion", "1.00\0"
|
||||
VALUE "InternalName", "BIDS Class Library\0"
|
||||
VALUE "LegalCopyright", "Copyright Borland International 1993\0"
|
||||
VALUE "ProductName", "Borland C++ 4.0\0"
|
||||
VALUE "ProductVersion", "4.2"
|
||||
VALUE "SpecialBuild", "05 Nov 1994 09:43:34 "
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN /* Language | Translation */
|
||||
VALUE "Translation", 0x409, 1252 /* U.S. English, Windows Multilingual */
|
||||
END
|
||||
END
|
||||
|
||||
Reference in New Issue
Block a user