Category : Files from Magazines
Archive   : CUJ9208.ZIP
Filename : 1008022A

 
Output of file : 1008022A contained in archive : CUJ9208.ZIP
///////////////////////////////////////////////////////
// Listing 2 - QC.CPP: Quadcode support routines
// by Kenneth Van Camp
///////////////////////////////////////////////////////
#include
#include
#include
#include
#ifdef __TURBOC__
#include
#else
#include
#endif
#include "qc.h"

// The following macro returns the number of bytes reqd
// to store a quadcode, given the number of quits:
#define QC_NBYTES(q) (((q) - 1) / 4 + 1)

// These are shifts & masks to extract a single quit
static int QCshifts[4] = { 6, 4, 2, 0 };
static int QCmasks[4] = { 3<<6, 3<<4, 3<<2, 3 };
// This is the inverse mask:
static int QCimasks[4] =
{ 0xff^(3<<6), 0xff^(3<<4), 0xff^(3<<2), 0xff^3 };
// And these are masks for each bit in a normal byte:
static int bitmasks[8] =
{ 1, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7 };

#ifndef STAT_QC
void QuadCode::FreeMem (void)
// Free dynamic memory.
{
if (nquits > 0 && qca)
delete qca;
qca = NULL;
nquits = 0;
} // QuadCode::FreeMem
#endif // STAT_QC

QuadCode::QuadCode (COORD i, COORD j, int nq)
// QuadCode constructor from (I,J) coordinates of the
// upper-left corner of the qc.
// i is the vertical row# of quadcode (0 at top)
// j is the horizontal column# of quadcode
// nq is the # of quits in quadcode
{
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);

// We traverse both the (i,j) coordinates and the qc
// from the msb to the lsb and msq to msq. Note the
// following assumes MAXQUITS is a multiple of 8.
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + (MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + (MAXQUITS - nq) / 8;
#else
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1 -
(MAXQUITS - nq) / 8;
#endif

int bit = 7 - (MAXQUITS - nq) % 8;
int nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif

memset (qca, '\0', nbytes);
BYTE *p = qca;
nquits = nq;

int pos = 0; // position within qc (0,1,2,3)
for ( ; nq > 0; nq--)
{
if (*ip & bitmasks[bit])
*p |= 1 << (QCshifts[pos] + 1);
if (*jp & bitmasks[bit])
*p |= 1 << QCshifts[pos];
// Advance to next quit
if (++pos > 3)
{
pos = 0;
p++;
}
// Back up to next bit
if (--bit < 0)
{
bit = 7;
#ifdef MSB_FIRST
ip++; jp++;
#else
ip--; jp--;
#endif
} // if --bit

} // for nq

} // QuadCode::QuadCode

void QuadCode::Init (const char *chqc)
// QuadCode initializer from string.
// chqc is the quadcode in a null-terminated
// character representation - i.e., "123"
{
int nq = strlen (chqc);
#ifndef STAT_QC
qca = NULL;
#endif
nquits = 0;
assert (nq > 0 && nq <= MAXQUITS);
size_t nbytes = QC_NBYTES (nq);
#ifndef STAT_QC
qca = new BYTE [nbytes];
assert (qca != NULL);
#endif
memset (qca, '\0', nbytes);

// Store quadcode in binary form, from msq to lsq.
int i;
int pos; // pos within byte of this quit (0,1,2,3)
BYTE *p; // ptr to current byte in qc
for (i = 0, pos = 0, p = qca; i < nq; i++)
{
int val = chqc[i] - '0';
assert (val >= 0 && val <= 3);
*p |= val << QCshifts[pos];
if (++pos > 3)
{
pos = 0;
p++;
}
} // for i

nquits = nq;
} // QuadCode::Init

int QuadCode::GetQuit (int quit)
// Return single quit from quadcode.
// quit is the pos# of the quit to extract (zero-based).
// Pos 0 is the high-order quit ('1' in "123").
{
assert (quit <= nquits && quit >= 0);

int byte = quit / 4;
int pos = quit % 4;
return ( (*(qca + byte) & QCmasks[pos]) >>
QCshifts[pos]);
} // QuadCode::GetQuit

void QuadCode::SetQuit (int quit, int val)
// Set value of a single quit.
// quit is the pos# of the quit to extract (zero-based).
// val is the value of the quit (0, 1, 2 or 3).
{
assert (quit <= nquits && quit >= 0 && val >= 0 &&
val < 4);

BYTE *p = qca + quit / 4;
int pos = quit % 4;
// Clear out the old value
*p &= (255 - QCmasks[pos]);
// Put in the new value
*p |= val << QCshifts[pos];
} // QuadCode::SetQuit

void QuadCode::ToIJ (COORD &i, COORD &j, int &nq)
// Convert quadcode value to (I,J).
// The offsets returned are the coords of the
// upper-left corner of the quadcode.
// i is the row#
// j is the col#
// nq is the #quits
{
i = j = nq = 0;
if (nquits < 1)
return;
assert (nquits <= MAXQUITS);
nq = nquits;

// Go from lsq to msq. Following loop is based on the
// conversion algorithm by Gargantini:
#ifdef MSB_FIRST
BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1;
BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1;
#else
BYTE *ip = (BYTE *)&i;
BYTE *jp = (BYTE *)&j;
#endif
int quit, // current quit# in qc
bit = 0; // current bit# in byte of (i,j)

for (quit = nquits-1; quit >= 0; quit--)
{
int val = GetQuit (quit);
// Bit pos 0 gives J val, bit pos 1 gives I val.
int ival = val >> 1;
int jval = val & 1;
*ip |= (ival << bit);
*jp |= (jval << bit);
// Advance to next bit
if (bit == 7)
{
bit = 0;
#ifdef MSB_FIRST
ip--; jp--;
#else
ip++; jp++;
#endif
}
else
bit++;
} // for quit

} // QuadCode::ToIJ

int QuadCode::Compare (QuadCode &qc)
// Compare one quadcode to another.
// Return 0 if the two quadcodes are equal; -1 if the
// current quadcode is less than qc; or +1 if the
// current quadcode is greater than qc.
// qc is the quadcode to compare to
{
// Check for zero-length quadcodes
if (nquits == 0)
{
if (qc.nquits == 0)
return 0;
else
return -1;
}
else if (qc.nquits == 0)
return 1;

BYTE *p1 = qca;
BYTE *p2 = qc.qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;

// Compare each byte of the two quadcodes.
for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
if (*p1 != *p2)
{
if (*p1 < *p2)
return -1;
else
return 1;
}

if (nquits == qc.nquits)
// quadcodes same
return 0;
else if (nquits < qc.nquits)
// this quadcode contains qc
return -1;
else
// qc contains this quadcode
return 1;
} // QuadCode::Compare

int QuadCode::Sibling (const QuadCode *qc)
// Compare one quadcode to another.
// Return TRUE if they are siblings, FALSE if not.
// qc is the quadcode to compare to
{
// Must be the same length, can't be empty.
if (qc == NULL || nquits != qc->nquits || nquits==0)
return (FALSE);

BYTE *p1 = qca;
BYTE *p2 = qc->qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;

// Compare each byte of the two quadcodes.
// If any differ except the last, then not siblings.
for ( ; p1 < end1; p1++, p2++)
if (*p1 != *p2)
return (FALSE);

if (*p1 == *p2)
// Quadcodes are same
return (FALSE);

// Make sure final byte matches in all but last quit.
int pos = (nquits-1) % 4;
return
((*p1 & QCimasks[pos]) == (*p2 & QCimasks[pos]));

} // QuadCode::Sibling

int QuadCode::Contains (QuadCode &qc)
// Compare one quadcode to another.
// Return TRUE if the current quadcode contains qc
// (i.e., is equal to it or is a parent of it), or
// FALSE otherwise.
// qc is the quadcode to compare to
{
if (nquits > qc.nquits)
return (FALSE);
if (nquits == 0)
return (TRUE);

BYTE *p1 = qca;
BYTE *p2 = qc.qca;
BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;

// Compare each byte of the two quadcodes.
for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
if (*p1 != *p2)
{
// Found a byte that differs. This quadcode
// contains qc iff: (1) We are at the last byte
// of this quadcode; and (2) All quits in this
// quadcode before the last one match the
// corresponding quits in qc.
if (p1 != end1)
return (FALSE);
int lastpos = (nquits - 1) % 4;
int pos;
for (pos = lastpos; pos >= 0; pos--)
if ((*p1 & QCmasks[pos]) !=
(*p2 & QCmasks[pos]))
return (FALSE);
// They match up to nquits.
return (TRUE);
}

// All bytes match - either qc's are same or this is
// the parent.
return (TRUE);
} // QuadCode::Contains

void QuadCode::MakeParent (void)
// Make quadcode into its parent.
{
// Clear the bits that saved the last quit. Don't
// bother to reclaim storage if size is reduced.
nquits--;
int byte = nquits / 4;
int pos = nquits % 4;
*(qca + byte) &= QCimasks[pos];
} // QuadCode::MakeParent

QuadCode &QuadCode::operator= (QuadCode &qc)
// Assign one quadcode the same value as another.
// The target quadcode is assumed to be initialized.
// qc is the quadcode to copy
{
#ifdef STAT_QC
memcpy (qca, qc.qca, NBYTE_QC);
#else
FreeMem();

size_t nbytes = QC_NBYTES (qc.nquits);
qca = new BYTE [nbytes];
assert (qca != NULL);
memcpy (qca, qc.qca, nbytes);
#endif // STAT_QC

nquits = qc.nquits;
return (*this);
} // QuadCode::operator=

ostream &operator<< (ostream &stream, QuadCode &qc)
// Overload "Put to" operator for output to stream.
// stream is the stream to print to
// qc is the quadcode to print
{
int quit;

for (quit = 0; quit < qc.nquits; quit++)
stream << (char)(qc.GetQuit (quit) + '0');
return (stream);
} // operator<<

istream &operator>> (istream &stream, QuadCode &qc)
// Overload "Get From" operator for input from stream.
// stream is the stream to get from
// qc is the quadcode to store the result in
{
char tmp[80];

qc.FreeMem();
stream >> tmp;
qc.Init (tmp);
return (stream);
} // operator>>


  3 Responses to “Category : Files from Magazines
Archive   : CUJ9208.ZIP
Filename : 1008022A

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/