home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics 16,000
/
graphics-16000.iso
/
msdos
/
plotting
/
pcgplots
/
basicio.cpp
next >
Wrap
C/C++ Source or Header
|
1992-04-24
|
28KB
|
1,163 lines
// C++ .cc file for gplot, gdoc, gtex basic I/O -*-c++-*-
// copyright Phil Andrews, Pittsburgh Supercomputing Center, 1992
// all rights reserved
#ifdef macintosh
# include <errors.h>
#endif
#if __MSDOS__
#include <windows.h>
#include <io.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <values.h>
#include "basicio.h"
#ifndef _toupper
#define _toupper(c) ((c) -'a'+'A')
#endif
////
// error call
////
extern void myError(const char *inMsg, const char *inMsg2=NULL,
int severity=1);
#ifdef macintosh
#pragma segment CIO1
#endif
////
// basic file
////
basicFile::basicFile()
{
filePtr = NULL;
#if __MSDOS__
hGlobalBuffer = NULL;
bufferSize = 65000; // first try, may have to expand
hGlobalBuffer = GlobalAlloc(GMEM_FIXED,65000);
if (hGlobalBuffer)
buffer = (HugePt)GlobalLock(hGlobalBuffer);
else buffer = NULL;
#else
bufferSize = 1024; // first try, may have to expand
buffer = new unsigned char[bufferSize]; // initial allocation of memory
#endif
tempBufferSize = 0; // not needed yet
tempBufferIndex = 0;
tempBuffer = NULL;
}
////
// destructor
////
basicFile::~basicFile()
{
if (filePtr) fclose(filePtr);
#if __MSDOS__
if (hGlobalBuffer)
{
GlobalUnlock(hGlobalBuffer);
GlobalFree(hGlobalBuffer);
buffer = NULL;
}
#endif
if (buffer) delete buffer;
}
////
// need more memory, double the buffer size
////
int basicFile::doubleBuffer(long bIndex)
{
#if __MSDOS__
bufferSize += bufferSize;
HANDLE hGlobalMemoryNew =
GlobalReAlloc(hGlobalBuffer, bufferSize, GMEM_MOVEABLE);
if (!hGlobalMemoryNew)
{
myError("couldn't double buffer size\n", "aborting", 0);
return 0;
}
hGlobalBuffer = hGlobalMemoryNew;
buffer = GlobalLock(hGlobalBuffer);
return 1;
#else
unsigned char * oldBuffer;
oldBuffer = buffer;
buffer = new unsigned char[bufferSize = 2 * bufferSize]; // double memory
if (!buffer) {
myError("couldn't double buffer size\n", "aborting", 0);
return 0;
}
for (long i=0; i<bIndex; ++i)
buffer[i] = oldBuffer[i]; // copy old data
delete oldBuffer;
return 1;
#endif
}
////
// output a string
////
int basicOutput::outS(const char *inStr)
{
if (!inStr) return 1;
for (int myLen = 0; inStr[myLen]; ++myLen);
return outS(inStr, myLen);
}
////
// general input
////
int memInput::getBytes(unsigned int noBytes, unsigned char *inPtr)
{
for (int i=0; (i<noBytes) && (i<mySize); ++i) inPtr[i] = myMem[myIndex++];
return i;
}
////
// basic file input
////
// constructor when may need to open the file
////
#ifdef macintosh
basicInput::basicInput(const char *, short ref_num)
{
filePtr = NULL;
frefHand = ref_num;
FailOSErr(SetFPos(frefNum, fsFromStart, 0)); // get to beginning
aIndex = bIndex = 0;
myLastPos = 0;
}
#elif __MSDOS__
basicInput::basicInput(const char *, short handle)
{
filePtr = NULL;
frefHand = handle;
lseek( frefHand, 0L,SEEK_SET); // get to beginning
aIndex = bIndex = 0;
myLastPos = 0;
}
#else
basicInput::basicInput(const char *inName, short )
{
filePtr = fopen((char *) inName, "r");
aIndex = bIndex = 0;
myLastPos = 0;
}
#endif
////
// constructor for already opened file
////
////
// constructor for already opened file
////
#ifdef macintosh
basicInput::basicInput(FILE * , short ref_num, int offset)
{
filePtr = NULL;
frefHand = ref_num;
FailOSErr(SetFPos(frefNum, fsFromStart, offset)); // get to right spot
aIndex = bIndex = 0;
}
#elif __MSDOS__
basicInput::basicInput(FILE *, short handle, int offset )
{
filePtr = NULL ;
frefHand = handle;
lseek( frefHand, (long)offset, SEEK_SET); // get to beginning
aIndex = bIndex = 0;
}
#else
basicInput::basicInput(FILE *inPtr, short , int offset)
{
filePtr = inPtr;
goTo(offset);
aIndex = bIndex = 0;
}
#endif
////
// read in some bytes to an arbitrary location
////
#if __MSDOS__
int basicInput::getBytes(unsigned int noBytes, HugePt location)
#else
int basicInput::getBytes(unsigned int noBytes, unsigned char *location)
#endif
{
if (tempBuffer) { // read out of tempBuffer
for (int i=0; (i<noBytes) && (tempBufferIndex < tempBufferSize); ++i) {
location[i] = tempBuffer[tempBufferIndex++];
}
return i;
} else { // really get from file
#ifdef macintosh
long bW = noBytes;
int ret = FSRead(frefNum, &bW, (Ptr) location);
if (noBytes == bW) return 1;
else if (ret == eofErr) myError("premature end of file");
return 0;
#elif __MSDOS__
if (location == NULL) { myError("Memory Allocation Problem"); return 0; }
unsigned char * FarPtr;
FarPtr = location;
int ret = read(frefHand, FarPtr, noBytes);
if ( noBytes == ret)
return 1;
else if (ret >= 0) myError("premature end of file");
return 0;
#else
if (fread((char *) location, 1, noBytes, filePtr) == noBytes) return 1;
else if (feof(filePtr)) myError("premature end of file");
else if (ferror(filePtr)) myError("error on read");
return 0;
#endif
}
}
////
// basic output
////
char tmpDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
char *basicFile::digits = tmpDigits;
////
// constructor
////
#ifdef macintosh
basicOutput::basicOutput(const char * , short ref_num)
{
filePtr = NULL;
frefHand = ref_num;
FailOSErr(SetFPos(frefNum, fsFromStart, 0)); // get to beginning
lineSize = 80;
lineIndex = 0;
lastSep = 0;
}
#elif __MSDOS__
basicOutput::basicOutput(const char * ,short handle)
{
filePtr = NULL;
frefHand = handle;
lseek( frefHand, 0L,SEEK_SET); // get to beginning
lineSize = 80;
lineIndex = 0;
lastSep = 0;
}
#else
basicOutput::basicOutput(const char *inName, short )
{
filePtr = fopen((char *) inName, "w");
lineSize = 80;
lineIndex = 0;
lastSep = 0;
}
#endif
int basicOutput::outSep() // output one separator (if necessary)
{
if (!lineIndex) return 1; // at beginning of line
if (lineIndex >= lineSize) return flushLine(); // at end of line
lastSep = lineIndex;
buffer[lineIndex++] = ' ';
return 1;
}
int basicOutput::outS(const char *inStr, int inLen) // output a bare string
{
int i;
// too big for what's left in line ?
if (((inLen + lineIndex) > lineSize) && ((inLen + lastSep) <= lineSize))
flushLine(1);
////
// too big for line since last separator ?
if ((inLen + lineIndex) > lineSize) {
flushLine();
}
// still too big for whole line ? Try to break at spaces
if (inLen > lineSize) {
int lastSpace = 0, lastStart = 0;
for (i=0; i<inLen; ++i) {
if (isspace(inStr[i])) lastSpace = i; // mark last space
if (((i-lastStart) >= lineSize) && (lastSpace > lastStart)) {
for (; lastStart < lastSpace; ++lastStart)
buffer[lineIndex++] = inStr[lastStart];
flushLine();
lastSpace = 0;
}
}
// any left ?
if (lastStart < inLen) {
putBytes((unsigned char *) inStr + lastStart, inLen - lastStart);
flushLine();
}
return 1;
}
// will fit on one line
for (i=0; i<inLen; ++i) buffer[lineIndex++] = inStr[i];
return 1;
}
int basicOutput::flushLine(int breakLine)
{
int ret;
if (breakLine && lastSep) { // make some room, if possible
buffer[lastSep] = '\n';
++lastSep; // skip over separator
ret = putBytes(lastSep);
for (int i=0; i<(lineIndex - lastSep ); ++i) buffer[i] = buffer[i+lastSep];
lineIndex = i;
lastSep = 0;
} else { // no room, or want to really flush
if (lastSep == (lineIndex - 1)) --lineIndex; // last char is a separator
if (lineIndex) { // started a line
buffer[lineIndex++] = '\n';
ret = putBytes(lineIndex);
} else ret = 1;
lineIndex = 0;
lastSep = 0;
}
return ret;
}
////
// only routine to do actual output
////
#if __MSDOS__
int basicOutput::putBytes(HugePt location, int noBytes)
#else
int basicOutput::putBytes(unsigned char *location, int noBytes)
#endif
{
#ifdef macintosh
long bW = noBytes;
int ret = FSWrite(frefNum, &bW,(Ptr)location);
if (noBytes == bW) return 1;
else myError("error on write");
return 0;
#elif __MSDOS__
if (location == NULL) { myError("Memory Allocation Problem"); return 0; }
int ret = write(frefHand, location, noBytes);
if (noBytes == ret) return 1;
else myError("error on write");
return 0;
#else
if (fwrite((char *) location, 1, noBytes, filePtr) == noBytes) return 1;
else if (ferror(filePtr)) myError("error on write");
return 0;
#endif
}
////
// put a real number in text format
////
int basicOutput::textRealOut(float inFloat)
{
const int noDecimals = 6;
int intPart, ret;
float rest;
intPart = (int) inFloat; // assume truncation toward zero
rest = (inFloat < 0) ? intPart - inFloat : inFloat - intPart;
ret = outSep() && textIntOut(intPart, 1) && outC('.');
for (int i = 0; (i<noDecimals) && rest; ++i) {
rest *= 10;
intPart = (int) rest;
ret = ret && textIntOut(intPart, 1);
rest -= intPart;
}
return ret;
}
int basicOutput::textIntOut(int i, int noSep) // output an integer
{
const int maxPwrs = 10; // maximum number size
char intBuffer[maxPwrs + 2];
char *cptr = intBuffer + maxPwrs + 1;
int isNeg = 0, j;
*cptr = 0; // end of string
if (i < 0) { // negative
if (!(i << 1)) { // special case for most negative no., assume 2's comp
*--cptr = digits[8];
i /= 10;
}
isNeg = 1;
i = -i;
} else if (!i) *--cptr = digits[0];
while (i && ((cptr + isNeg) > intBuffer)) {
j = i % 10;
*--cptr = digits[j];
i /= 10;
}
if (i) myError("too large int to output");
if (isNeg) *--cptr = '-';
#ifdef macintosh
int ret = ( noSep ? 1 : outSep() );
if (ret) outS(cptr, intBuffer + maxPwrs + 1 - cptr);
return ret;
#else
return (noSep ? 1 : outSep()) && outS(cptr, intBuffer + maxPwrs + 1 - cptr);
#endif
}
////
// make a hex dump
////
int basicOutput::textHexDump(const unsigned char *inPtr, int size)
{
int ret = 1;
for (int i=0; (i<size) && ret; ++i) ret = textHexOut(inPtr[i]);
return ret;
}
////
// output one hex character
////
int basicOutput::textHexOut(unsigned char inC)
{
static char hexChar[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
return outC(hexChar[15 & (inC >> 4)]) && outC(hexChar[15 & inC]);
}
////
// File I/O
////
////
// the basic text object, merely do something reasonable for these
////
textObject::textObject()
{
myVpos = 0;
maxCurrentFontNameSize = 127;
myCurrentFontName = new char[maxCurrentFontNameSize + 1];
myCurrentFontName[0] = 0;
myCurrentFontNameSize = 0;
leftMarginPtr = new posPtr(0);
rightMarginPtr = new posPtr(0);
hposPtr = new posPtr(0);
vposPtr = new posPtr(0);
myHpos = leftMargin();
}
////
// destructor
////
textObject::~textObject()
{
posPtr *oldPtr;
// delete the stacks of pointers
while (oldPtr = leftMarginPtr) {
leftMarginPtr = leftMarginPtr->next();
delete oldPtr;
}
while (oldPtr = rightMarginPtr) {
rightMarginPtr = rightMarginPtr->next();
delete oldPtr;
}
while (oldPtr = hposPtr) {
hposPtr = hposPtr->next();
delete oldPtr;
}
while (oldPtr = vposPtr) {
vposPtr = vposPtr->next();
delete oldPtr;
}
}
////
// handle pointers
////
void textObject::pushLeftMargin()
{
leftMarginPtr = new posPtr(hpos(), leftMarginPtr);
}
int textObject::popLeftMargin()
{
if (leftMarginPtr->next()) {
posPtr *oldPtr = leftMarginPtr;
leftMarginPtr = leftMarginPtr->next();
delete oldPtr;
return 1;
} else {
return 0;
}
}
void textObject::pushHpos()
{
hposPtr = new posPtr(myHpos, hposPtr);
}
int textObject::popHpos()
{
if (hposPtr) {
myHpos = hposPtr->value();
if (hposPtr->next()) {
posPtr *oldPtr = hposPtr;
hposPtr = hposPtr->next();
delete oldPtr;
return 1;
} else return 0;
} else return 0;
}
void textObject::pushRightMargin()
{
rightMarginPtr = new posPtr(hpos(), rightMarginPtr);
}
int textObject::popRightMargin()
{
if (rightMarginPtr->next()) {
posPtr *oldPtr = rightMarginPtr;
rightMarginPtr = rightMarginPtr->next();
delete oldPtr;
return 1;
} else return 0;
}
void textObject::pushVpos()
{
vposPtr = new posPtr(myVpos, vposPtr);
}
int textObject::popVpos()
{
if (vposPtr) {
myVpos = vposPtr->value();
if (vposPtr->next()) {
posPtr *oldPtr = vposPtr;
vposPtr = vposPtr->next();
delete oldPtr;
return 1;
} else return 0;
} else return 0;
}
////
// put out a space
////
textObject *textObject::outSpace()
{
int spaceWidth = stringWidth(" ", 1);
if ((hpos() + spaceWidth) >= pageWidth()) newLine();
else myHpos += spaceWidth;
return this;
}
////
// output a new line
////
textObject *textObject::newLine(int noLines)
{
myHpos = leftMargin();
myVpos += noLines * lineHeight();
return this;
}
////
// output at least one blank line
////
textObject *textObject::blankLine()
{
if (hpos() != leftMargin()) newLine(2);
else newLine();
return this;
}
////
// ensure we're at the begining of a new line
////
textObject *textObject::endLine()
{
if (hpos() != leftMargin()) newLine();
return this;
}
////
// break up a string of tokens into left justified set
////
textObject *textObject::breakLeft(tokenHolder *inHolder)
{
outputToken *myToken = inHolder->start(), *oldToken, *bestBreak;
// store our present horizontal position
pushHpos();
// go thru all of the tokens
while (myToken) {
myHpos = leftMargin(); // start new line
bestBreak = myToken; // initialize possible break
// take care of leading deletable tokens
while (myToken && (myToken->deletable() || !myToken->width(this))) {
if (myToken->deletable()) {
oldToken = myToken;
myToken = myToken->next();
delete oldToken;
} else myToken = myToken->next();
}
if (!myToken) break; // done
// now into real stuff, get one line's worth
while (myToken && (myHpos <= pageWidth()) && !myToken->newLine()) {
if (myToken->breakPenalty(this) < 1) { // good place to break
bestBreak = myToken; // latest one
}
myHpos += myToken->width(this);
myToken = myToken->next();
}
// reached end of line
if (myHpos > pageWidth()) { // need to insert a new line
myToken = new outputNL(bestBreak); // insert a break
}
if (myToken) myToken = myToken->next(); // first of new line
} // ran out of tokens
// restore our original horizontal position
popHpos();
return this;
}
////
// break up a string of tokens into a centered set
////
textObject *textObject::breakCenter(tokenHolder *inHolder)
{
outputToken *myToken, *nextToken, *bestBreak, *startToken;
int width, bestWidth;
myToken = inHolder->start();
while (myToken) {
while (myToken && (myToken->deletable() || !myToken->width(this))) {
nextToken = myToken->next();
// delete leading spaces, skip zero width elements
if (myToken->deletable()) delete myToken;
myToken = nextToken;
}
if (!myToken) break; // done
width = 0; // start new line
startToken = myToken; // kern before startToken
bestBreak = myToken; // break at bestBreak
bestWidth = myToken->width(this);
while (myToken && (width <= pageWidth())) { // do one line
if (!myToken->breakPenalty(this)) { // can break here
bestBreak = myToken; // latest one
bestWidth = (myToken->deletable()) ? width
: width + myToken->width(this);
}
width += myToken->width(this);
myToken = myToken->next();
} // end of line
if (width > pageWidth()) { // need to break the line
myToken = new outputNL(bestBreak); // insert a break
myToken = myToken->next(); // first of new line
} else bestWidth = width; // last line
new outputKern((pageWidth() - bestWidth) / 2, startToken);
}
return this;
}
////
// break up a string of tokens into a right justified set
////
textObject *textObject::breakRight(tokenHolder *inHolder)
{
return breakLeft(inHolder); // for now
}
////
// break up a string of tokens into a left and right justified set
////
textObject *textObject::breakBoth(tokenHolder *inHolder)
{
return breakLeft(inHolder); // for now
}
////
// no justification
////
textObject *textObject::breakNone(tokenHolder*)
{
return this;
}
////
// the basic output object
////
outputObject *outputObject::outString(const char*, int, int, int)
{
return this; // nothing by default
}
outputObject* outputObject::outString(const char *buffer)
{
return outString(buffer, strlen(buffer));
}
////
// output a character
////
outputObject* outputObject::outChar(char c)
{
return outString(&c, 1);
}
////
// the basic file output
////
fileOutput::fileOutput(const char *file_name, int inSize)
{
if (!(fout = fopen(file_name, "w"))) {
myError("couldn't open for output", file_name);
}
bufferSize = inSize;
lineBuffer = new char[bufferSize];
for (int i=0; i<bufferSize; ++i) lineBuffer[i] = ' ';
bufferIndex = 0;
}
////
// destructor
////
fileOutput::~fileOutput()
{
if (bufferIndex) flushBuffer();
delete lineBuffer;
if (fout) fclose(fout);
}
////
// output a string
////
outputObject *fileOutput::outString(const char *buffer, int size,
int useInWidth, int inWidth)
{
long i;
if (bufferIndex < 0) bufferIndex = 0; // safety
// will it fit on next line, but not this ?
if ((size<=bufferSize) && (size > (bufferSize - bufferIndex))) {
flushBuffer();
}
// too big for a whole line ? do as well as we can
while (size > bufferSize) {
// find space closest to end of line, if it exists
for (i=bufferSize; (i>0) && !isspace(buffer[i-1]); --i);
if (i) { // found a space
if (i) outString(buffer, (int) (i-1), useInWidth, inWidth);
buffer += i;
size -= (int) i;
} else {
outString(buffer, (int) bufferSize, useInWidth, inWidth);
buffer += bufferSize;
size -= (int) bufferSize;
}
flushBuffer();
}
// will fit OK
for (i = 0; (i < size) && ((bufferIndex + i) < bufferSize)
&& (buffer[i] != '\n'); ++i) {
lineBuffer[bufferIndex + i] = buffer[i];
}
bufferIndex += (useInWidth) ? inWidth : size;
return this;
}
////
// flush the output buffer and (possibly) add blank lines
////
outputObject *fileOutput::flushBuffer(int noLines)
{
if (fout) {
if (bufferIndex > 0) {
if (bufferIndex > bufferSize) bufferIndex = bufferSize;
fwrite(lineBuffer, 1, (unsigned int) bufferIndex, fout);
}
for (int i=0; i<noLines; ++i) fputc('\n', fout);
}
bufferIndex = 0;
for (int i=0; i<bufferSize; ++i) lineBuffer[i] = ' ';
return this;
}
////
// add a possible space
////
outputObject *fileOutput::addSpace()
{
if (bufferIndex <= 0) return this; // EOL counts
if (bufferIndex >= (bufferSize - 1)) flushBuffer(); // at end anyway
else if (lineBuffer[bufferIndex-1] == ' ') return this; // already a space
else ++bufferIndex; // already filled with blanks
return this;
}
////
// basic string output
////
////
// output a string
////
outputObject *stringOutput::outString(const char *inBuffer, int inSize,
int useInWidth, int inWidth)
{
if (inSize < 1) return this; // nothing to do
int i;
// how much more room do we need ?
int spaceNeeded = (useInWidth && (inWidth > inSize)) ? inWidth + 1
: inSize + 1;
////
// do we have enough room ?
if (spaceNeeded > (mySize - lastPos)) { // must make more room
char *newContents = new char[mySize *= 2];
for (i=0; i<lastPos; ++i) newContents[i] = myContents[i];
delete myContents;
myContents = newContents;
}
////
// copy over the input
for (i=0; i<inSize; ++i) myContents[lastPos++] = inBuffer[i];
if (useInWidth && (inWidth > inSize))
for (i=0; i<(inWidth - inSize); ++i) myContents[lastPos++] = ' ';
// terminate
myContents[lastPos] = 0;
return this;
}
////
// output to an array
////
textObject *outputArray::newLine(int noLines)
{
for (int i=0; i<noLines; ++i) outString("\n", 1);
return this;
}
////
// draw a string
////
textObject *outputFile::drawString(const char *inStr, int size,
int useInWidth, int inWidth)
{
int useSize = (size >= 0) ? size : strlen(inStr);
outString(inStr, useSize, useInWidth, inWidth);
return this;
}
////
// output new line(s)
////
textObject *outputFile::newLine(int no_lines)
{
flushBuffer(no_lines);
return this;
}
////
// new line output token
////
// constructor to replace token
////
outputNL::outputNL(outputToken *inToken, int inBefore) : outputToken()
{
myNoLines = 1;
if (!inToken) return; // no links to make
myOwner = inToken->owner();
// if inToken is deletable, the outputNL takes its place;
if (inToken->deletable()) {
myPrev = inToken->prev();
myNext = inToken->next();
inToken->unlink(); // so as not to screw up pointers when deleting
delete inToken;
} else {
if (inBefore) { // insert before
myNext = inToken;
myPrev = inToken->prev();
} else { // insert afterwards
myNext = inToken->next();
myPrev = inToken;
}
}
// relink next and previous
if (myPrev) myPrev->setNext(this);
if (myNext) myNext->setPrev(this);
}
////
// simple constructor
////
outputNL::outputNL(int inNoLines) : outputToken()
{
myNoLines = inNoLines;
}
////
// output token
////
// contructor (compiler problems if inlined ?)
////
outputToken::outputToken()
{
myNext = NULL;
myPrev = NULL;
myWidth = 0;
myOwner = NULL;
}
////
// destructor
////
outputToken::~outputToken()
{
if (myOwner) {
if (this == myOwner->start()) { // realign start
myOwner->newStart(next());
}
if (this == myOwner->end()) { // realign end
myOwner->newEnd(prev());
}
}
if (myPrev) myPrev->setNext(next()); // relink
if (myNext) myNext->setPrev(prev());
}
////
// the String token
////
// string constructor
// if inSize will fit in the ptr/array union, use that
// use default outputToken constructor (compiler problems ?)
////
outputString::outputString(const char *inPtr, int inSize,
outputToken *inToken)
{
myPrev = inToken;
if (((size = inSize) <= 0) || !inPtr) { // nothing to do
size = 0;
return;
}
// else a legitimate string
int i;
if (size > sizeof(char*)) {
if (!(myUnion.bptr = new char[size])) {
fprintf(stderr, "couldn't make %d bytes for outputString\n", size);
size = 0;
return;
} else for (i=0; i<size; ++i) myUnion.bptr[i] = inPtr[i];
} else for (i=0; i<size; ++i) myUnion.barray[i] = inPtr[i];
}
////
// character constructor
////
outputString::outputString(const char inChar, outputToken *inToken)
: outputToken()
{
size = 1;
myUnion.barray[0] = inChar; // save space
myPrev = inToken;
}
////
// destructor
////
outputString::~outputString()
{
if (size > sizeof(char*)) delete myUnion.bptr;
}
////
// draw it
////
void outputString::draw(textObject *inText)
{
inText->drawString(bptr(), size, 1, width(inText));
}
////
// width
////
int outputString::width(textObject *inText)
{
return (myWidth) ? myWidth : myWidth = inText->stringWidth(bptr(), size);
}
////
// single character class
////
void outputChar::draw(textObject *inText)
{
inText->drawString(&schar, 1, 1, width(inText));
}
int outputChar::width(textObject *inText)
{
return (myWidth) ? myWidth : myWidth = inText->stringWidth(&schar, 1);
}
////
// space class
////
void outputSpace::draw(textObject *inText)
{
inText->outSpace();
}
////
// width
////
int outputSpace::width(textObject *inText)
{
return (myWidth) ? myWidth : myWidth = inText->stringWidth(" ", 1);
}
////
// token holders
////
// constructor
////
tokenHolder::tokenHolder() : outputToken()
{
contents = lastToken = NULL;
myLinesBefore = myLinesAfter = 0;
}
////
// destructor
////
tokenHolder::~tokenHolder()
{
outputToken *myToken;
while (myToken = contents) {
contents = contents->next();
delete myToken;
}
}
////
// add space (AT&T can't inline this)
tokenHolder *tokenHolder::addSpace(int i)
{
static char myBuffer[20];
sprintf(myBuffer, "%d", i); // for now
return addSpace(myBuffer);
}
////
// add space (AT&T can't inline this)
tokenHolder *tokenHolder::addSpace(float x)
{
static char myBuffer[20];
sprintf(myBuffer, "%f", x); // for now
return addSpace(myBuffer);
}
////
// how many new lines do we hold ?
////
int tokenHolder::noLines()
{
int myNoLines = 0;
for (outputToken *myToken = start(); myToken; myToken = myToken->next()) {
myNoLines += myToken->noLines();
}
return myNoLines;
}
////
// draw it
////
void tokenHolder::draw(textObject *inText)
{
if (!inText) return;
inText->newLine(linesBefore());
int myHeight = inText->pageHeight();
for (outputToken *myToken = contents; myToken && ((!myHeight) ||
(inText->vpos() < myHeight)); myToken = myToken->next()) {
myToken->draw(inText);
}
inText->newLine(linesAfter());
}
////
// width
////
int tokenHolder::width(textObject *inText)
{
int myWidth = 0;
for (outputToken *myToken = contents; myToken; myToken = myToken->next())
myWidth += myToken->width(inText);
return myWidth;
}
////
// add one output token
////
tokenHolder *tokenHolder::addToken(outputToken *inToken, int addBreak)
{
if (!inToken) return this;
if (!contents || !lastToken) contents = lastToken = inToken;
else lastToken->setNext(inToken);
inToken->setPrev(lastToken);
lastToken = inToken;
inToken->setOwner(this);
inToken->setNext(NULL);
if (addBreak) addToken(new optionalBreak());
return this;
}
////
// short cut for adding an outputString
////
tokenHolder *tokenHolder::addToken(const char *inString, int addBreak)
{
for (int myLen = 0; inString[myLen]; ++myLen);
if (!myLen) return this;
// AT&T compiler seems to produce bad code if next 2 lines are combined
outputToken *myToken = new outputString(inString, myLen);
addToken(myToken, addBreak);
return this;
}
////
// short cut for adding an outputChar
////
tokenHolder *tokenHolder::addToken(char inChar, int addBreak)
{
addToken(new outputChar(inChar), addBreak);
return this;
}
////
// reset the first output token
////
void tokenHolder::newStart(outputToken *inToken)
{
if (inToken) {
inToken->setOwner(this);
inToken->setPrev(NULL);
}
contents = inToken;
if (!lastToken) lastToken = contents;
}
////
// reset the last output token
////
void tokenHolder::newEnd(outputToken *inToken)
{
if (inToken) {
inToken->setOwner(this);
inToken->setNext(NULL);
}
lastToken = inToken;
}
////
// how many tokens do we have
////
int tokenHolder::noTokens()
{
int i = 0;
for (outputToken *myToken = contents; myToken; myToken = myToken->next())
i += myToken->noTokens();
return i;
}
////
// make a kern
////
textObject *textObject::kern(int inKern)
{
if (inKern < 0) {
if ((hpos() + inKern) <= 0) myHpos = leftMargin();
else myHpos -= inKern;
} else {
if ((hpos() + inKern) >= pageWidth()) newLine();
else myHpos += inKern;
}
return this;
}
////
// the output file object
////
// make a kern
////
textObject *outputFile::kern(int inKern)
{
if (inKern > 0) {
bufferIndex += inKern;
} else {
bufferIndex = (bufferIndex >= inKern) ? bufferIndex - inKern : 0;
}
return this;
}
////
// output kern token
////
outputKern::outputKern(int inKern, outputToken *inToken) : outputToken()
{
myKern = inKern;
if (!inToken) {
myError("no inToken for outputKern!\n");
return; // no links to make
}
myOwner = inToken->owner();
if (!myOwner) {
myError("no owner for outputKern!\n");
return;
}
// the kern is inserted before the inToken
myNext = inToken;
myPrev = inToken->prev();
myNext->setPrev(this);
if (myPrev) {
myPrev->setNext(this);
if (inToken == myOwner->start())
myError("corrupted start in outputKern! (inToken == start)\n");
} else {
if (inToken != myOwner->start())
myError("corrupted start in outputKern! (inToken != start)\n");
myOwner->newStart(this);
if (this != myOwner->start()) myError("not equal to start!\n");
}
}
void outputKern::draw(textObject *inText)
{
inText->kern(myKern);
}