1 #include "sys.h"
2 #include <libcwd/debug.h>
3 #include <unistd.h>
4 #include <sys/poll.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <iostream>
8 #ifdef LIBCWD_USE_STRSTREAM
9 #include <strstream>
10 #else
11 #include <sstream>
12 #endif
13 #include <time.h>
14
15 struct timespec const one_ms = { 0, 1000000 };
16
slowdown(void)17 static void slowdown(void)
18 {
19 struct timespec rem = one_ms;
20 while (nanosleep(&rem, &rem) == -1) ;
21 }
22
23 using namespace std;
24
25 #ifdef REAL_CERR
26 #define DEBUG_CERR
27 #define USE_REAL_CERR
28 #endif
29 #ifdef WITHOUT_CERR
30 #define DEBUG_CERR
31 #define cerr_cf 0
32 #endif
33 #ifdef WITH_CERR
34 #define DEBUG_CERR
35 #endif
36
37 namespace libcwd {
38 namespace channels {
39 namespace dc {
40 channel_ct foo("FOO");
41 channel_ct bar("BAR");
42 channel_ct run("RUN");
43 }
44 }
45 }
46
47 #ifndef REAL_CERR
48 #ifdef LIBCWD_USE_STRSTREAM
49 // No idea why, but it doesn't work when strstream is dynamic.
50 static char ssbuf[1024];
51 static strstream ss(ssbuf, sizeof(ssbuf));
52 #else
53 static stringstream ss;
54 #endif
55 static streambuf* old_buf;
56 #endif
57
58 #if __GNUC__ == 2 && __GNUC_MINOR__ < 97
59 #define ios_base ios // Kludge.
60 #endif
61
grab_cerr(void)62 void grab_cerr(void)
63 {
64 #ifndef REAL_CERR
65 old_buf = cerr.rdbuf();
66 cerr.rdbuf(ss.rdbuf());
67 #endif
68 }
69
release_cerr(void)70 void release_cerr(void)
71 {
72 #ifndef REAL_CERR
73 cerr.rdbuf(old_buf);
74 #endif
75 }
76
flush_cout(void)77 void flush_cout(void)
78 {
79 std::cout << flush;
80 slowdown();
81 }
82
flush_cerr(void)83 void flush_cerr(void)
84 {
85 #ifdef REAL_CERR
86 cerr << flush;
87 #else
88 size_t curlen = ss.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out) - ss.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in);
89 std::string buf;
90 buf.append(ss.str(), 0, curlen);
91 #ifdef DEBUG_CERR
92 cout << buf;
93 #else
94 bool color = false;
95 char const* p = buf.data();
96 for (size_t i = 0; i < curlen; ++i)
97 {
98 if (!color)
99 {
100 cout << "\e[31m";
101 color = true;
102 }
103 cout.put(*p);
104 if (*p++ == '\n')
105 {
106 cout << "\e[0m";
107 color = false;
108 }
109 }
110 #endif
111 cout << flush;
112 slowdown();
113 ss.rdbuf()->pubseekoff(0, std::ios_base::beg, std::ios_base::in|std::ios_base::out);
114 #endif
115 }
116
nested_foo(bool with_error,bool to_cerr)117 char const* nested_foo(bool with_error, bool to_cerr)
118 {
119 if (with_error)
120 {
121 if (to_cerr)
122 {
123 flush_cout();
124 errno = 0;
125 Dout( dc::foo|cerr_cf|error_cf, "CERR: Inside `nested_foo()'" );
126 flush_cerr();
127 }
128 else
129 {
130 errno = 0;
131 Dout( dc::foo|error_cf, "Inside `nested_foo()'" );
132 }
133 }
134 else
135 {
136 if (to_cerr)
137 {
138 flush_cout();
139 Dout( dc::foo|cerr_cf, "CERR: Inside `nested_foo()'" );
140 flush_cerr();
141 }
142 else
143 Dout( dc::foo, "Inside `nested_foo()'" );
144 }
145 return "Foo";
146 }
147
nested_bar(bool bar_with_error,bool bar_to_cerr,bool foo_with_error,bool foo_to_cerr)148 char const* nested_bar(bool bar_with_error, bool bar_to_cerr, bool foo_with_error, bool foo_to_cerr)
149 {
150 if (bar_with_error)
151 {
152 if (bar_to_cerr)
153 {
154 flush_cout();
155 errno = EINVAL;
156 Dout( dc::bar|cerr_cf|error_cf, "CERR: Entering `nested_bar()'" );
157 flush_cerr();
158 flush_cout();
159 errno = EINVAL;
160 Dout( dc::bar|cerr_cf|error_cf, "CERR: `nested_foo(" << foo_with_error << ", " << foo_to_cerr << ")' returns the string \"" << nested_foo(foo_with_error, foo_to_cerr) << "\" when I call it." );
161 flush_cerr();
162 flush_cout();
163 errno = EINVAL;
164 Dout( dc::bar|cerr_cf|error_cf, "CERR: Leaving `nested_bar()'" );
165 flush_cerr();
166 }
167 else
168 {
169 errno = EINVAL;
170 Dout( dc::bar|error_cf, "Entering `nested_bar()'" );
171 errno = EINVAL;
172 Dout( dc::bar|error_cf, "`nested_foo(" << foo_with_error << ", " << foo_to_cerr << ")' returns the string \"" << nested_foo(foo_with_error, foo_to_cerr) << "\" when I call it." );
173 errno = EINVAL;
174 Dout( dc::bar|error_cf, "Leaving `nested_bar()'" );
175 }
176 }
177 else
178 {
179 if (bar_to_cerr)
180 {
181 flush_cout();
182 Dout( dc::bar|cerr_cf, "CERR: Entering `nested_bar()'" );
183 flush_cerr();
184 flush_cout();
185 Dout( dc::bar|cerr_cf, "CERR: `nested_foo(" << foo_with_error << ", " << foo_to_cerr << ")' returns the string \"" << nested_foo(foo_with_error, foo_to_cerr) << "\" when I call it." );
186 flush_cerr();
187 flush_cout();
188 Dout( dc::bar|cerr_cf, "CERR: Leaving `nested_bar()'" );
189 flush_cerr();
190 }
191 else
192 {
193 Dout( dc::bar, "Entering `nested_bar()'" );
194 Dout( dc::bar, "`nested_foo(" << foo_with_error << ", " << foo_to_cerr << ")' returns the string \"" << nested_foo(foo_with_error, foo_to_cerr) << "\" when I call it." );
195 Dout( dc::bar, "Leaving `nested_bar()'" );
196 }
197 }
198 return "Bar";
199 }
200
continued_func(unsigned int what)201 char const* continued_func(unsigned int what)
202 {
203 if (--what == 0)
204 return "BOTTOM";
205 Dout( dc::run|continued_cf, "1" );
206 // The order of evaluation of x() and y() in f(x(), y()) is undetermined,
207 // therefore we call the recursive functions outside the << << <<, forcing
208 // a fixed order.
209 Dout( dc::foo, ""; char const* str3 = nested_foo(what & 2, what & 1); char const* str2 = continued_func(what); char const* str1 = nested_foo(what & 1, what & 2); (*LIBCWD_DO_TSD_MEMBER(::libcwd::libcw_do, current_bufferstream)) << str1 << what << str2 << what << str3 );
210 Dout( dc::continued, "2" );
211 Dout( dc::foo, ""; char const* str3 = nested_foo(what & 2, what & 1); char const* str2 = continued_func(what); char const* str1 = nested_foo(what & 1, what & 2); (*LIBCWD_DO_TSD_MEMBER(::libcwd::libcw_do, current_bufferstream)) << str1 << what << str2 << what << str3 );
212 Dout( dc::finish, "3" );
213 return ":";
214 }
215
216 MAIN_FUNCTION
217 { PREFIX_CODE
218 #if !CWDEBUG_LOCATION
219 DoutFatal(dc::fatal, "Expected Failure.");
220 #endif
221
222 Debug( check_configuration() );
223
224 grab_cerr();
225
226 // Select channels
227 ForAllDebugChannels( if (debugChannel.is_on()) debugChannel.off(); );
228 Debug( dc::notice.on() );
229 Debug( dc::system.on() );
230 Debug( dc::foo.on() );
231 Debug( dc::bar.on() );
232 Debug( dc::run.on() );
233 #ifndef THREADTEST
234 // Write debug output to cout
235 Debug( libcw_do.set_ostream(&cout) );
236 #endif
237 // Turn debug object on
238 Debug( libcw_do.on() );
239
240 // Print channels
241 Debug( list_channels_on(libcw_do) );
242
243 //===================================================================================
244 // Unnested tests
245
246 cout << "===========================================================================\n";
247 cout << " Unnested tests\n\n";
248
249 // Simple, one line debug output
250 cout << "---------------------------------------------------------------------------\n";
251 Dout( dc::notice, "This is a single line" );
252
253 // The same, but splitting it by using `nonewline_cf' and `noprefix_cf'
254 cout << "---------------------------------------------------------------------------\n";
255 Dout( dc::notice|nonewline_cf, "This is " );
256 Dout( dc::notice|noprefix_cf, "a single line" );
257
258 // The same, but writing an error message behind it
259 cout << "---------------------------------------------------------------------------\n";
260 errno = 0;
261 Dout( dc::notice|error_cf, "This is a single line with an error message behind it" );
262
263 // Test writing forced to cerr
264 cout << "---------------------------------------------------------------------------\n";
265 flush_cout();
266 errno = 0;
267 Dout( dc::notice|error_cf|cerr_cf, "CERR: This is a single line with an error message behind it written to cerr" );
268 flush_cerr();
269
270 //===================================================================================
271 // Simple nests
272
273 cout << "===========================================================================\n";
274 cout << " Simple nests\n\n";
275
276 // Single depth
277 for(int i = 0; i < 4; ++i)
278 {
279 bool a = (i & 2), b = (i & 1);
280 cout << "---------------------------------------------------------------------------\n";
281 Dout( dc::notice, "`nested_foo(" << a << ", " << b << ")' returns the string \"" << nested_foo(a, b) << "\" when I call it." );
282 }
283
284 // Double depth
285 for(int i = 0; i < 16; ++i)
286 {
287 bool a = (i & 8), b = (i & 4), c = (i & 2), d = (i & 1);
288 cout << "---------------------------------------------------------------------------\n";
289 Dout( dc::notice, "`nested_bar(" << a << ", " << b << ", " << c << ", " << d << ")' returns the string \"" << nested_bar(a, b, c, d) << "\" when I call it." );
290 }
291
292 //===================================================================================
293 // Continued tests, single depth
294
295 cout << "===========================================================================\n";
296 cout << " Continued tests, single depth\n\n";
297
298 cout << "---------------------------------------------------------------------------\n";
299 Dout( dc::run|continued_cf, "Hello " );
300 Dout( dc::finish, "World" );
301
302 cout << "---------------------------------------------------------------------------\n";
303 Dout( dc::run|continued_cf, "Libcwd " );
304 Dout( dc::continued, "is an awesome " );
305 Dout( dc::finish, "library!" );
306
307 cout << "---------------------------------------------------------------------------\n";
308 Dout( dc::run|continued_cf, "Libcwd " );
309 Dout( dc::foo, "Single interruption before." );
310 Dout( dc::continued, "is an awesome " );
311 Dout( dc::finish, "library!" );
312
313 cout << "---------------------------------------------------------------------------\n";
314 Dout( dc::run|continued_cf, "Libcwd " );
315 Dout( dc::continued, "is an awesome " );
316 Dout( dc::foo, "Single interruption after." );
317 Dout( dc::finish, "library!" );
318
319 cout << "---------------------------------------------------------------------------\n";
320 Dout( dc::run|continued_cf, "Libcwd " );
321 Dout( dc::foo, "Single interruption before and" );
322 Dout( dc::continued, "is an awesome " );
323 Dout( dc::foo, "a single interruption after." );
324 Dout( dc::finish, "library!" );
325
326 cout << "---------------------------------------------------------------------------\n";
327 Dout( dc::run|continued_cf, "Libcwd " );
328 Dout( dc::foo, "Double interruption before," );
329 Dout( dc::foo, "double means two lines." );
330 Dout( dc::continued, "is an awesome " );
331 Dout( dc::finish, "library!" );
332
333 cout << "---------------------------------------------------------------------------\n";
334 Dout( dc::run|continued_cf, "Libcwd " );
335 Dout( dc::continued, "is an awesome " );
336 Dout( dc::foo, "Double interruption after," );
337 Dout( dc::foo, "double means two lines." );
338 Dout( dc::finish, "library!" );
339
340 cout << "---------------------------------------------------------------------------\n";
341 Dout( dc::run|continued_cf, "Libcwd " );
342 Dout( dc::foo, "Double interruption before and" );
343 Dout( dc::foo, "(double means two lines)" );
344 Dout( dc::continued, "is an awesome " );
345 Dout( dc::foo, "a double interruption after" );
346 Dout( dc::foo, "(double means two lines)" );
347 Dout( dc::finish, "library!" );
348
349 for(int i = 0; i < 4; ++i)
350 for(int j = 0; j < 4; ++j)
351 {
352 bool a, b;
353 cout << "---------------------------------------------------------------------------\n";
354 Dout( dc::run|continued_cf, "Libcwd " );
355 a = (i & 2);
356 b = (i & 1);
357 Dout( dc::notice, "`nested_foo(" << a << ", " << b << ")' returns the string \"" << nested_foo(a, b) << "\" when I call it." );
358 Dout( dc::continued, "is an awesome " );
359 a = (j & 2);
360 b = (j & 1);
361 Dout( dc::notice, "`nested_foo(" << a << ", " << b << ")' returns the string \"" << nested_foo(a, b) << "\" when I call it." );
362 Dout( dc::finish, "library!" );
363 }
364
365 for(int i = 0; i < 16; ++i)
366 {
367 bool a = (i & 8), b = (i & 4), c = (i & 2), d = (i & 1);
368 cout << "---------------------------------------------------------------------------\n";
369 Dout( dc::run|continued_cf, "Libcwd " );
370 Dout( dc::notice, "`nested_bar(" << a << ", " << b << ", " << c << ", " << d << ")' returns the string \"" << nested_bar(a, b, c, d) << "\" when I call it." );
371 Dout( dc::continued, "is an awesome " );
372 Dout( dc::finish, "library!" );
373 }
374
375 for(int i = 0; i < 16; ++i)
376 {
377 bool a = (i & 8), b = (i & 4), c = (i & 2), d = (i & 1);
378 cout << "---------------------------------------------------------------------------\n";
379 Dout( dc::run|continued_cf, "Libcwd " );
380 Dout( dc::continued, "is an awesome " );
381 Dout( dc::notice, "`nested_bar(" << a << ", " << b << ", " << c << ", " << d << ")' returns the string \"" << nested_bar(a, b, c, d) << "\" when I call it." );
382 Dout( dc::finish, "library!" );
383 }
384
385 //===================================================================================
386 // Continued tests, depth 2.
387
388 cout << "===========================================================================\n";
389 cout << " Continued tests, deep\n\n";
390
391 Dout( dc::notice, continued_func(5) );
392
393 release_cerr();
394
395 EXIT(0);
396 }
397