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 * $File: //depot/povray/3.6-release/source/base/textstreambuffer.cpp $
25 * $Revision: #2 $
26 * $Change: 2939 $
27 * $DateTime: 2004/07/04 13:43:26 $
28 * $Author: root $
29 * $Log$
30 *****************************************************************************/
31
32 #include <algorithm>
33
34 #include "configbase.h"
35
36 #include "textstreambuffer.h"
37
38 #include "povms.h"
39 #include "pov_err.h"
40
41 BEGIN_POV_BASE_NAMESPACE
42
TextStreamBuffer(size_t buffersize,unsigned int wrapwidth)43 TextStreamBuffer::TextStreamBuffer(size_t buffersize, unsigned int wrapwidth)
44 {
45 boffset = 0;
46 bsize = buffersize;
47 wrap = wrapwidth;
48 curline = 0;
49 if(POVMSUtil_TempAlloc((void **)&buffer, bsize) != kNoErr)
50 throw int(kOutOfMemoryErr);
51 }
52
~TextStreamBuffer()53 TextStreamBuffer::~TextStreamBuffer()
54 {
55 boffset = 0;
56 bsize = 0;
57 wrap = 0;
58 curline = 0;
59 if(buffer != NULL)
60 (void)POVMSUtil_TempFree((void *)buffer);
61 buffer = NULL;
62 }
63
printf(const char * format,...)64 void TextStreamBuffer::printf(const char *format, ...)
65 {
66 va_list marker;
67
68 va_start(marker, format);
69 vsnprintf(&buffer[boffset], bsize - boffset - 1, format, marker);
70 va_end(marker);
71
72 // direct output
73 directflush(&buffer[boffset], strlen(&buffer[boffset]));
74
75 boffset = strlen(buffer);
76
77 // line buffered output
78 lineflush();
79 }
80
print(const char * str)81 void TextStreamBuffer::print(const char *str)
82 {
83 printf("%s", str);
84 }
85
puts(const char * str)86 void TextStreamBuffer::puts(const char *str)
87 {
88 printf("%s\n", str);
89 }
90
putc(int chr)91 void TextStreamBuffer::putc(int chr)
92 {
93 printf("%c", chr);
94 }
95
printfile(const char * filename,unsigned long offset,int lines)96 void TextStreamBuffer::printfile(const char *filename, unsigned long offset, int lines)
97 {
98 FILE *file = fopen(filename, "r");
99
100 if(file != NULL)
101 {
102 fseek(file, offset, SEEK_SET);
103 printfile(file, lines);
104 fclose(file);
105 }
106 }
107
printfile(FILE * file,int lines)108 void TextStreamBuffer::printfile(FILE *file, int lines)
109 {
110 if(file != NULL)
111 {
112 bool stopposset = (lines < 0); // only if walking backwards stop at current position
113 long stoppos = long(ftell(file));
114 int chr = 0;
115
116 if(lines < 0)
117 {
118 int lineoffset = lines;
119
120 // NOTE: This will walk back one line too far! However, it only walks
121 // back to the end of that line. Thus, the next step will walk forward
122 // again to the beginning of the right line, which is the desired
123 // position. Do not change this behavior without testing! [trf]
124 for(long pos = long(ftell(file)) - 1; (lineoffset < 1) && (pos >= 0); pos--)
125 {
126 // WARNING: Expensive way to walk backward through a file, but will only
127 // be used when problems are encountered anyway, and then it most likely
128 // does not matter if the output of the message takes a tiny bit longer!
129 fseek(file, pos, SEEK_SET);
130
131 chr = fgetc(file);
132
133 if((chr == 10) || (chr == 13))
134 {
135 chr = fgetc(file);
136 if(!((chr == 10) || (chr == 13)))
137 ungetc(chr, file);
138 lineoffset++;
139 }
140 else if(chr == EOF)
141 break;
142 }
143
144 // beginning of file was previously reached
145 if(lineoffset < 1)
146 fseek(file, 0, SEEK_SET);
147
148 while(lineoffset > 0)
149 {
150 chr = fgetc(file);
151
152 if((chr == 10) || (chr == 13))
153 {
154 chr = fgetc(file);
155 if(!((chr == 10) || (chr == 13)))
156 ungetc(chr, file);
157 lineoffset--;
158 }
159 else if(chr == EOF)
160 break;
161 }
162
163 // make number of lines to output positive for next step
164 lines = -lines;
165 }
166
167 while(lines > 0)
168 {
169 chr = fgetc(file);
170
171 if((stopposset == true) && (stoppos == (long(ftell(file)) - 1))) // only if walking backwards stop at initial position
172 break;
173
174 // count newlines in file and replace newlines with system specific newline charcater
175 if((chr == 10) || (chr == 13))
176 {
177 chr = fgetc(file);
178 if(!((chr == 10) || (chr == 13)))
179 ungetc(chr, file);
180 else
181 {
182 if((stopposset == true) && (stoppos == (long(ftell(file)) - 1))) // only if walking backwards stop at initial position
183 break;
184 }
185 printf("\n");
186 lines--;
187 }
188 else if(chr == EOF)
189 break;
190 else
191 printf("%c", chr);
192 }
193 }
194 }
195
flush()196 void TextStreamBuffer::flush()
197 {
198 if(curline > 0)
199 directoutput("\n", 1);
200 curline = 0;
201
202 lineflush();
203 if(boffset > 0)
204 lineoutput(buffer, boffset);
205 boffset = 0;
206 }
207
lineoutput(const char * str,unsigned int chars)208 void TextStreamBuffer::lineoutput(const char *str, unsigned int chars)
209 {
210 // by default output to stdout
211 fwrite(str, sizeof(char), chars, stdout);
212 fprintf(stdout, "\n");
213 fflush(stdout);
214 }
215
directoutput(const char *,unsigned int)216 void TextStreamBuffer::directoutput(const char *, unsigned int)
217 {
218 // does nothing by default
219 }
220
rawoutput(const char *,unsigned int)221 void TextStreamBuffer::rawoutput(const char *, unsigned int)
222 {
223 // does nothing by default
224 }
225
lineflush()226 void TextStreamBuffer::lineflush()
227 {
228 unsigned int lasti = 0;
229 unsigned int ii = 0;
230 unsigned int i = 0;
231
232 // output all complete lines in the buffer
233 while(i < boffset)
234 {
235 if((buffer[i] == '\n') || (buffer[i] == '\r'))
236 {
237 lineoutput(&buffer[lasti], i - lasti);
238 lasti = i + 1;
239 }
240 else if(i - lasti >= wrap)
241 {
242 // track back to last space up to 1/4 in the line to wrap
243 for(ii = 0; ii < min((wrap / 4), i); ii++)
244 {
245 if(isspace(buffer[i - ii]))
246 break;
247 }
248
249 // if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
250 if(ii == min((wrap / 4), i))
251 ii = 0;
252 i -= ii;
253
254 lineoutput(&buffer[lasti], i - lasti);
255 lasti = i;
256 continue;
257 }
258 i++;
259 }
260
261 // remove all completely output lines
262 memmove(buffer, &buffer[lasti], bsize - lasti);
263 boffset = boffset - lasti;
264 }
265
directflush(const char * str,unsigned int chars)266 void TextStreamBuffer::directflush(const char *str, unsigned int chars)
267 {
268 unsigned int ii = 0;
269 unsigned int i = 0;
270
271 rawoutput(str, chars);
272
273 for(i = 0; i < chars; i++)
274 {
275 if((str[i] == '\n') || (str[i] == '\r'))
276 {
277 i++;
278 directoutput(str, i);
279 str += i;
280 chars -= i;
281 i = 0;
282 curline = 0;
283 }
284 else if(curline + i >= wrap)
285 {
286 // track back to last space up to 1/4 in the line to wrap
287 for(ii = 0; ii < min((wrap / 4), i); ii++)
288 {
289 if(isspace(str[i - ii]))
290 break;
291 }
292
293 // if no space was found in the last 1/4 of the line to wrap, split it at the end anyway
294 if(ii == min((wrap / 4), i))
295 ii = 0;
296 i -= ii;
297
298 directoutput(str, i);
299 directoutput("\n", 1);
300
301 str += i;
302 chars -= i;
303 i = 0;
304 curline = 0;
305 }
306 }
307
308 if(chars > 0)
309 {
310 directoutput(str, chars);
311 curline += chars;
312 }
313 }
314
315 END_POV_BASE_NAMESPACE
316