home *** CD-ROM | disk | FTP | other *** search
- // 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);
- }
-