326 lines
7.5 KiB
C++
326 lines
7.5 KiB
C++
/*******************************************************************************
|
|
* textstreambuffer.cpp
|
|
*
|
|
* This module contains the basic C++ text stream buffer.
|
|
*
|
|
* ---------------------------------------------------------------------------
|
|
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
|
|
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
|
|
*
|
|
* POV-Ray is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* POV-Ray is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------------
|
|
* POV-Ray is based on the popular DKB raytracer version 2.12.
|
|
* DKBTrace was originally written by David K. Buck.
|
|
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
|
|
* ---------------------------------------------------------------------------
|
|
* $File: //depot/public/povray/3.x/source/base/textstreambuffer.cpp $
|
|
* $Revision: #1 $
|
|
* $Change: 6069 $
|
|
* $DateTime: 2013/11/06 11:59:40 $
|
|
* $Author: chrisc $
|
|
*******************************************************************************/
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
// configbase.h must always be the first POV file included within base *.cpp files
|
|
#include "configbase.h"
|
|
|
|
#include "textstreambuffer.h"
|
|
|
|
#include "povms.h"
|
|
#include "pov_err.h"
|
|
|
|
// this must be the last file included
|
|
#include "base/povdebug.h"
|
|
|
|
namespace pov_base
|
|
{
|
|
|
|
TextStreamBuffer::TextStreamBuffer(size_t buffersize, unsigned int wrapwidth)
|
|
{
|
|
boffset = 0;
|
|
bsize = buffersize;
|
|
wrap = wrapwidth;
|
|
curline = 0;
|
|
if(POVMSUtil_TempAlloc((void **)&buffer, bsize) != kNoErr)
|
|
throw POV_EXCEPTION_CODE(kOutOfMemoryErr);
|
|
}
|
|
|
|
TextStreamBuffer::~TextStreamBuffer()
|
|
{
|
|
boffset = 0;
|
|
bsize = 0;
|
|
wrap = 0;
|
|
curline = 0;
|
|
if(buffer != NULL)
|
|
(void)POVMSUtil_TempFree((void *)buffer);
|
|
buffer = NULL;
|
|
}
|
|
|
|
void TextStreamBuffer::printf(const char *format, ...)
|
|
{
|
|
va_list marker;
|
|
|
|
va_start(marker, format);
|
|
vsnprintf(&buffer[boffset], bsize - boffset - 1, format, marker);
|
|
va_end(marker);
|
|
|
|
// direct output
|
|
directflush(&buffer[boffset], strlen(&buffer[boffset]));
|
|
|
|
boffset = strlen(buffer);
|
|
|
|
// line buffered output
|
|
lineflush();
|
|
}
|
|
|
|
void TextStreamBuffer::print(const char *str)
|
|
{
|
|
printf("%s", str);
|
|
}
|
|
|
|
void TextStreamBuffer::puts(const char *str)
|
|
{
|
|
printf("%s\n", str);
|
|
}
|
|
|
|
void TextStreamBuffer::putc(int chr)
|
|
{
|
|
printf("%c", chr);
|
|
}
|
|
|
|
void TextStreamBuffer::printfile(const char *filename, POV_LONG offset, POV_LONG lines)
|
|
{
|
|
FILE *file = fopen(filename, "r");
|
|
|
|
if(file != NULL)
|
|
{
|
|
fseek(file, offset, SEEK_SET);
|
|
printfile(file, lines);
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
void TextStreamBuffer::printfile(FILE *file, POV_LONG lines)
|
|
{
|
|
if(file != NULL)
|
|
{
|
|
bool stopposset = (lines < 0); // only if walking backwards stop at current position
|
|
POV_LONG stoppos = (POV_LONG)(ftell(file));
|
|
int chr = 0;
|
|
|
|
if(lines < 0)
|
|
{
|
|
POV_LONG lineoffset = lines;
|
|
|
|
// NOTE: This will walk back one line too far! However, it only walks
|
|
// back to the end of that line. Thus, the next step will walk forward
|
|
// again to the beginning of the right line, which is the desired
|
|
// position. Do not change this behavior without testing! [trf]
|
|
for(POV_LONG pos = (POV_LONG)(ftell(file)) - 1; (lineoffset < 1) && (pos >= 0); pos--)
|
|
{
|
|
// WARNING: Expensive way to walk backward through a file, but will only
|
|
// be used when problems are encountered anyway, and then it most likely
|
|
// does not matter if the output of the message takes a tiny bit longer!
|
|
fseek(file, pos, SEEK_SET);
|
|
|
|
chr = fgetc(file);
|
|
|
|
if((chr == 10) || (chr == 13))
|
|
{
|
|
chr = fgetc(file);
|
|
if(!((chr == 10) || (chr == 13)))
|
|
ungetc(chr, file);
|
|
lineoffset++;
|
|
}
|
|
else if(chr == EOF)
|
|
break;
|
|
}
|
|
|
|
// beginning of file was previously reached
|
|
if(lineoffset < 1)
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
while(lineoffset > 0)
|
|
{
|
|
chr = fgetc(file);
|
|
|
|
if((chr == 10) || (chr == 13))
|
|
{
|
|
chr = fgetc(file);
|
|
if(!((chr == 10) || (chr == 13)))
|
|
ungetc(chr, file);
|
|
lineoffset--;
|
|
}
|
|
else if(chr == EOF)
|
|
break;
|
|
}
|
|
|
|
// make number of lines to output positive for next step
|
|
lines = -lines;
|
|
}
|
|
|
|
while(lines > 0)
|
|
{
|
|
chr = fgetc(file);
|
|
|
|
if((stopposset == true) && (stoppos == ((POV_LONG)(ftell(file)) - 1))) // only if walking backwards stop at initial position
|
|
break;
|
|
|
|
// count newlines in file and replace newlines with system specific newline charcater
|
|
if((chr == 10) || (chr == 13))
|
|
{
|
|
chr = fgetc(file);
|
|
if(!((chr == 10) || (chr == 13)))
|
|
ungetc(chr, file);
|
|
else
|
|
{
|
|
if((stopposset == true) && (stoppos == ((POV_LONG)(ftell(file)) - 1))) // only if walking backwards stop at initial position
|
|
break;
|
|
}
|
|
printf("\n");
|
|
lines--;
|
|
}
|
|
else if(chr == EOF)
|
|
break;
|
|
else
|
|
printf("%c", chr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextStreamBuffer::flush()
|
|
{
|
|
if(curline > 0)
|
|
directoutput("\n", 1);
|
|
curline = 0;
|
|
|
|
lineflush();
|
|
if(boffset > 0)
|
|
lineoutput(buffer, boffset);
|
|
boffset = 0;
|
|
}
|
|
|
|
void TextStreamBuffer::lineoutput(const char *str, unsigned int chars)
|
|
{
|
|
// by default output to stdout
|
|
fwrite(str, sizeof(char), chars, stdout);
|
|
fprintf(stdout, "\n");
|
|
fflush(stdout);
|
|
}
|
|
|
|
void TextStreamBuffer::directoutput(const char *, unsigned int)
|
|
{
|
|
// does nothing by default
|
|
}
|
|
|
|
void TextStreamBuffer::rawoutput(const char *, unsigned int)
|
|
{
|
|
// does nothing by default
|
|
}
|
|
|
|
void TextStreamBuffer::lineflush()
|
|
{
|
|
unsigned int lasti = 0;
|
|
unsigned int ii = 0;
|
|
unsigned int i = 0;
|
|
|
|
// output all complete lines in the buffer
|
|
while(i < boffset)
|
|
{
|
|
if((buffer[i] == '\n') || (buffer[i] == '\r'))
|
|
{
|
|
lineoutput(&buffer[lasti], i - lasti);
|
|
lasti = i + 1;
|
|
}
|
|
else if(i - lasti >= wrap)
|
|
{
|
|
// track back to last space up to 1/4 in the line to wrap
|
|
for(ii = 0; ii < min((wrap / 4), i); ii++)
|
|
{
|
|
if(isspace(buffer[i - ii]))
|
|
break;
|
|
}
|
|
|
|
// if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
|
|
if(ii == min((wrap / 4), i))
|
|
ii = 0;
|
|
i -= ii;
|
|
|
|
lineoutput(&buffer[lasti], i - lasti);
|
|
lasti = i;
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if(lasti > 0)
|
|
{
|
|
// remove all completely output lines
|
|
boffset -= lasti;
|
|
memmove(buffer, &buffer[lasti], boffset);
|
|
}
|
|
}
|
|
|
|
void TextStreamBuffer::directflush(const char *str, unsigned int chars)
|
|
{
|
|
unsigned int ii = 0;
|
|
unsigned int i = 0;
|
|
|
|
rawoutput(str, chars);
|
|
|
|
for(i = 0; i < chars; i++)
|
|
{
|
|
if((str[i] == '\n') || (str[i] == '\r'))
|
|
{
|
|
i++;
|
|
directoutput(str, i);
|
|
str += i;
|
|
chars -= i;
|
|
i = 0;
|
|
curline = 0;
|
|
}
|
|
else if(curline + i >= wrap)
|
|
{
|
|
// track back to last space up to 1/4 in the line to wrap
|
|
for(ii = 0; ii < min((wrap / 4), i); ii++)
|
|
{
|
|
if(isspace(str[i - ii]))
|
|
break;
|
|
}
|
|
|
|
// if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
|
|
if(ii == min((wrap / 4), i))
|
|
ii = 0;
|
|
i -= ii;
|
|
|
|
directoutput(str, i);
|
|
directoutput("\n", 1);
|
|
|
|
str += i;
|
|
chars -= i;
|
|
i = 0;
|
|
curline = 0;
|
|
}
|
|
}
|
|
|
|
if(chars > 0)
|
|
{
|
|
directoutput(str, chars);
|
|
curline += chars;
|
|
}
|
|
}
|
|
|
|
}
|