1 /****************************************************************************
2 * textstreambuffer.cpp
3 *
4 * This module contains the basic C++ text stream buffer.
5 *
6 * from Persistence of Vision(tm) Ray Tracer version 3.6.
7 * Copyright 1991-2003 Persistence of Vision Team
8 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
9 *---------------------------------------------------------------------------
10 * NOTICE: This source code file is provided so that users may experiment
11 * with enhancements to POV-Ray and to port the software to platforms other
12 * than those supported by the POV-Ray developers. There are strict rules
13 * regarding how you are permitted to use this file. These rules are contained
14 * in the distribution and derivative versions licenses which should have been
15 * provided with this file.
16 *
17 * These licences may be found online, linked from the end-user license
18 * agreement that is located at http://www.povray.org/povlegal.html
19 *---------------------------------------------------------------------------
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
23 *---------------------------------------------------------------------------
24 *
25 *===========================================================================
26 * This file is part of MegaPOV, a modified and unofficial version of POV-Ray
27 * For more information on MegaPOV visit our website:
28 * http://megapov.inetart.net/
29 *===========================================================================
30 *
31 * $RCSfile: textstreambuffer.cpp,v $
32 * $Revision: 1.8 $
33 * $Author: chris $
34 *
35 *****************************************************************************/
36
37 #include <algorithm>
38
39 #include "configbase.h"
40
41 #include "textstreambuffer.h"
42
43 #include "povms.h"
44 #include "pov_err.h"
45
46 BEGIN_POV_BASE_NAMESPACE
47
TextStreamBuffer(size_t buffersize,unsigned int wrapwidth)48 TextStreamBuffer::TextStreamBuffer(size_t buffersize, unsigned int wrapwidth)
49 {
50 boffset = 0;
51 bsize = buffersize;
52 wrap = wrapwidth;
53 curline = 0;
54 if(POVMSUtil_TempAlloc((void **)&buffer, bsize) != kNoErr)
55 throw int(kOutOfMemoryErr);
56 }
57
~TextStreamBuffer()58 TextStreamBuffer::~TextStreamBuffer()
59 {
60 boffset = 0;
61 bsize = 0;
62 wrap = 0;
63 curline = 0;
64 if(buffer != NULL)
65 (void)POVMSUtil_TempFree((void *)buffer);
66 buffer = NULL;
67 }
68
printf(const char * format,...)69 void TextStreamBuffer::printf(const char *format, ...)
70 {
71 va_list marker;
72
73 va_start(marker, format);
74 vsnprintf(&buffer[boffset], bsize - boffset - 1, format, marker);
75 va_end(marker);
76
77 // direct output
78 directflush(&buffer[boffset], strlen(&buffer[boffset]));
79
80 boffset = strlen(buffer);
81
82 // line buffered output
83 lineflush();
84 }
85
print(const char * str)86 void TextStreamBuffer::print(const char *str)
87 {
88 printf("%s", str);
89 }
90
puts(const char * str)91 void TextStreamBuffer::puts(const char *str)
92 {
93 printf("%s\n", str);
94 }
95
putc(int chr)96 void TextStreamBuffer::putc(int chr)
97 {
98 printf("%c", chr);
99 }
100
printfile(const char * filename,unsigned long offset,int lines)101 void TextStreamBuffer::printfile(const char *filename, unsigned long offset, int lines)
102 {
103 FILE *file = fopen(filename, "r");
104
105 if(file != NULL)
106 {
107 fseek(file, offset, SEEK_SET);
108 printfile(file, lines);
109 fclose(file);
110 }
111 }
112
printfile(FILE * file,int lines)113 void TextStreamBuffer::printfile(FILE *file, int lines)
114 {
115 if(file != NULL)
116 {
117 bool stopposset = (lines < 0); // only if walking backwards stop at current position
118 long stoppos = long(ftell(file));
119 int chr = 0;
120
121 if(lines < 0)
122 {
123 int lineoffset = lines;
124
125 // NOTE: This will walk back one line too far! However, it only walks
126 // back to the end of that line. Thus, the next step will walk forward
127 // again to the beginning of the right line, which is the desired
128 // position. Do not change this behavior without testing! [trf]
129 for(long pos = long(ftell(file)) - 1; (lineoffset < 1) && (pos >= 0); pos--)
130 {
131 // WARNING: Expensive way to walk backward through a file, but will only
132 // be used when problems are encountered anyway, and then it most likely
133 // does not matter if the output of the message takes a tiny bit longer!
134 fseek(file, pos, SEEK_SET);
135
136 chr = fgetc(file);
137
138 if((chr == 10) || (chr == 13))
139 {
140 chr = fgetc(file);
141 if(!((chr == 10) || (chr == 13)))
142 ungetc(chr, file);
143 lineoffset++;
144 }
145 else if(chr == EOF)
146 break;
147 }
148
149 // beginning of file was previously reached
150 if(lineoffset < 1)
151 fseek(file, 0, SEEK_SET);
152
153 while(lineoffset > 0)
154 {
155 chr = fgetc(file);
156
157 if((chr == 10) || (chr == 13))
158 {
159 chr = fgetc(file);
160 if(!((chr == 10) || (chr == 13)))
161 ungetc(chr, file);
162 lineoffset--;
163 }
164 else if(chr == EOF)
165 break;
166 }
167
168 // make number of lines to output positive for next step
169 lines = -lines;
170 }
171
172 while(lines > 0)
173 {
174 chr = fgetc(file);
175
176 if((stopposset == true) && (stoppos == (long(ftell(file)) - 1))) // only if walking backwards stop at initial position
177 break;
178
179 // count newlines in file and replace newlines with system specific newline charcater
180 if((chr == 10) || (chr == 13))
181 {
182 chr = fgetc(file);
183 if(!((chr == 10) || (chr == 13)))
184 ungetc(chr, file);
185 else
186 {
187 if((stopposset == true) && (stoppos == (long(ftell(file)) - 1))) // only if walking backwards stop at initial position
188 break;
189 }
190 printf("\n");
191 lines--;
192 }
193 else if(chr == EOF)
194 break;
195 else
196 printf("%c", chr);
197 }
198 }
199 }
200
flush()201 void TextStreamBuffer::flush()
202 {
203 if(curline > 0)
204 directoutput("\n", 1);
205 curline = 0;
206
207 lineflush();
208 if(boffset > 0)
209 lineoutput(buffer, boffset);
210 boffset = 0;
211 }
212
lineoutput(const char * str,unsigned int chars)213 void TextStreamBuffer::lineoutput(const char *str, unsigned int chars)
214 {
215 // by default output to stdout
216 fwrite(str, sizeof(char), chars, stdout);
217 fprintf(stdout, "\n");
218 fflush(stdout);
219 }
220
directoutput(const char *,unsigned int)221 void TextStreamBuffer::directoutput(const char *, unsigned int)
222 {
223 // does nothing by default
224 }
225
rawoutput(const char *,unsigned int)226 void TextStreamBuffer::rawoutput(const char *, unsigned int)
227 {
228 // does nothing by default
229 }
230
lineflush()231 void TextStreamBuffer::lineflush()
232 {
233 unsigned int lasti = 0;
234 unsigned int ii = 0;
235 unsigned int i = 0;
236
237 // output all complete lines in the buffer
238 while(i < boffset)
239 {
240 if((buffer[i] == '\n') || (buffer[i] == '\r'))
241 {
242 lineoutput(&buffer[lasti], i - lasti);
243 lasti = i + 1;
244 }
245 else if(i - lasti >= wrap)
246 {
247 // track back to last space up to 1/4 in the line to wrap
248 for(ii = 0; ii < min((wrap / 4), i); ii++)
249 {
250 if(isspace(buffer[i - ii]))
251 break;
252 }
253
254 // if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
255 if(ii == min((wrap / 4), i))
256 ii = 0;
257 i -= ii;
258
259 lineoutput(&buffer[lasti], i - lasti);
260 lasti = i;
261 continue;
262 }
263 i++;
264 }
265
266 // remove all completely output lines
267 memmove(buffer, &buffer[lasti], bsize - lasti);
268 boffset = boffset - lasti;
269 }
270
directflush(const char * str,unsigned int chars)271 void TextStreamBuffer::directflush(const char *str, unsigned int chars)
272 {
273 unsigned int ii = 0;
274 unsigned int i = 0;
275
276 rawoutput(str, chars);
277
278 for(i = 0; i < chars; i++)
279 {
280 if((str[i] == '\n') || (str[i] == '\r'))
281 {
282 i++;
283 directoutput(str, i);
284 str += i;
285 chars -= i;
286 i = 0;
287 curline = 0;
288 }
289 else if(curline + i >= wrap)
290 {
291 // track back to last space up to 1/4 in the line to wrap
292 for(ii = 0; ii < min((wrap / 4), i); ii++)
293 {
294 if(isspace(str[i - ii]))
295 break;
296 }
297
298 // if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
299 if(ii == min((wrap / 4), i))
300 ii = 0;
301 i -= ii;
302
303 directoutput(str, i);
304 directoutput("\n", 1);
305
306 str += i;
307 chars -= i;
308 i = 0;
309 curline = 0;
310 }
311 }
312
313 if(chars > 0)
314 {
315 directoutput(str, chars);
316 curline += chars;
317 }
318 }
319
320 END_POV_BASE_NAMESPACE
321