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