/******************************************************************************* * 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 . * --------------------------------------------------------------------------- * 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 #include // 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; } } }