Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
27.ios.members.static.cpp
Go to the documentation of this file.
1
29// exercise that the default setting of ios_base::sync_with_stdio()
30// produces the expected output, i.e., that the ouptut of the standard
31// iostream objects, std::cout, std::cerr, etc., is properly interleaved
32// with the output produced by interleaving calls to stdio printf()
33// also exercises the ability of buffered standard iostream objects
34// (i.e., cout, wcout, clog, and wclog) to flush output on program exit
35
36#include <cerrno> // for errno
37#include <cstdio> // for fprintf, L_tmpnam
38#include <cstdlib> // for STD{ERR,OUT}_FILENO
39#include <cstring> // for strerror
40#include <iostream>
41
42// rwtest headers
43#include <rw_driver.h>
44#include <rw_file.h>
45
46#ifndef _WIN32
47
48# include <fcntl.h>
49# include <unistd.h>
50# include <sys/types.h>
51# include <sys/wait.h>
52
53# define DEV_TTY "/dev/tty"
54
55#else // ifdef _WIN32
56
57# include <fcntl.h>
58# include <io.h>
59
60# ifndef STDIN_FILENO
61# define STDIN_FILENO 0
62# define STDOUT_FILENO 1
63# define STDERR_FILENO 2
64# endif // STDIN_FILENO
65
66# define DEV_TTY "CON:"
67
68#endif // _WIN32
69
70
71// use buffers larger than L_tmpnam with rw_tmpnam()
72char stderr_fname [256]; // name of file to which stderr is redirected
73char stdout_fname [256]; // name of file to which stderr is redirected
74char stdio_fname [256]; // same as above but for both stderr and stdout
75
76
78template <class charT>
79/*static*/ void
80test_file (const char* fname, const char* expect)
81{
82 std::FILE* fp = std::fopen (fname, "r");
83
84 if (!fp) {
85 rw_assert (false, __FILE__, __LINE__,
86 "fopen (\"%s\", \"r\") failed: %s",
87 fname, std::strerror (errno));
88
89 return;
90 }
91
92 enum { bufsiz = 256 };
93 char buf [bufsiz] = { 0 };
94 std::fgets (buf, bufsiz, fp);
95
96 rw_assert (!std::strcmp (expect, buf), __FILE__, __LINE__,
97 "expected output: \"%s\", got: \"%s\"", expect, buf);
98
99 std::fclose (fp);
100}
101
102
104static void
105do_test ()
106{
107 static const char stdout_expect[] = {
108 "[STDOUT_FILENO]"
109 "[cout,1][stdout,1][cout,2][stdout,2]"
110
111#ifndef _RWSTD_NO_WCHAR_T
112 "[wcout,1][stdout,3][wcout,2][stdout,4]"
113#endif // _RWSTD_NO_WCHAR_T
114 };
115
116 static const char stderr_expect[] = {
117 "[STDERR_FILENO]"
118 "[cerr,1][stderr,1][cerr,2][stderr,2]"
119 "[clog,1][stderr,3][clog,2][stderr,4]"
120
121#ifndef _RWSTD_NO_WCHAR_T
122 "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
123 "[wclog,1][stderr,7][wclog,2][stderr,8]"
124#endif // _RWSTD_NO_WCHAR_T
125 };
126
127 static const char stdio_expect[] = {
128 "[STDOUT_FILENO][STDERR_FILENO]"
129 "[cout,1][stdout,1][cout,2]" // no [stdout,2] here
130 "[cerr,1][stderr,1][cerr,2][stderr,2]"
131 "[clog,1][stderr,3][clog,2][stderr,4]"
132 "[stdout,2]" // but [stdout,2] flushed here
133
134#ifndef _RWSTD_NO_WCHAR_T
135 "[wcout,1][stdout,3][wcout,2]" // no [stdout,2] here
136 "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
137 "[wclog,1][stderr,7][wclog,2][stderr,8]"
138 "[stdout,4]" // but [stdout,2] flushed here
139#endif // _RWSTD_NO_WCHAR_T
140 };
141
142 rw_info (0, __FILE__, __LINE__,
143 "ios_base::sync_with_stdio (true)");
144
145 // call not necessary, stdio synchronized by default
146 // std::ios_base::sync_with_stdio (true);
147
148 rw_info (0, __FILE__, __LINE__,
149 "interleaved std::cout and stdout output");
150 test_file<char> (stdout_fname, stdout_expect);
151
152 rw_info (0, __FILE__, __LINE__,
153 "interleaved std::cerr and stderr output");
154 test_file<char> (stderr_fname, stderr_expect);
155
156 rw_info (0, __FILE__, __LINE__,
157 "interleaved std::cout/cerr and stdout/stderr output");
158 test_file<char> (stdio_fname, stdio_expect);
159}
160
161
163static int
164redirect_to_file (const char* fname, int fd)
165{
166 static int fd_tty = open (DEV_TTY, O_WRONLY);
167
168 if (fd_tty < 0) {
169 std::fprintf (stderr,
170 "open (\"" DEV_TTY "\", O_WRONLY) failed: %s\n",
171 std::strerror (errno));
172
173 fd_tty = STDERR_FILENO;
174 }
175
176 char buf [1024];
177 int n;
178
179 // create a new file and redirect `fd' to it
180 const int fd_tmp =
181 open (fname, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666);
182
183 if (fd_tmp < 0) {
184 n = std::sprintf (buf,
185 "open (\"%s\", O_WRONLY | O_CREAT | O_TRUNC, "
186 "0666) failed: %s\n",
187 fname, std::strerror (errno));
188 write (fd_tty, buf, n);
189 return -1; // bail out after a critical error
190 }
191
192 const int fd2 = dup2 (fd_tmp, fd);
193
194 if (0 > fd2) {
195 n = std::sprintf (buf,
196 "dup2 (%d, %d) failed: %s\n",
197 fd2, fd, std::strerror (errno));
198 write (fd_tty, buf, n);
199 return -2; // bail out after a critical error
200 }
201
202 if (fd2 != fd) {
203 n = std::sprintf (buf,
204 "dup2 (%d, %d) != %d; got %d\n",
205 fd_tmp, fd, fd, fd2);
206 // should never happen
207 write (fd_tty, buf, n);
208 }
209
210 if (close (fd_tmp)) {
211 n = std::sprintf (buf,
212 "close (%d) failed: %s\n",
213 fd_tmp, std::strerror (errno));
214 write (fd_tty, buf, n);
215 // proceed after a benign error
216 }
217
218 return fd2;
219}
220
221
222static int
223exec_stdout_setup ()
224{
225 // create a new file and redirect stdout to it
226 const int fd_stdout = redirect_to_file (stdout_fname, STDOUT_FILENO);
227
228 if (fd_stdout != STDOUT_FILENO)
229 return fd_stdout;
230
231 // expected output (w/o newlines):
232 // "[STDOUT_FILENO]"
233 // "[cout,1][stdout,1]"
234 // "[cout,2][stdout,2]"
235 // "[wcout,1][stdout,3]"
236 // "[wcout,2][stdout,4]"
237
238 write (STDOUT_FILENO, "[STDOUT_FILENO]", 15);
239 std::cout << "[cout,1]";
240 std::printf ("[stdout,1]");
241 std::cout << "[cout,2]"; // flushes the printf() above
242 std::printf ("[stdout,2]");
243
244#ifndef _RWSTD_WCHAR_T
245
246 std::wcout << "[wcout,1]"; // flushes the printf() above
247 std::printf ("[stdout,3]");
248 std::wcout << "[wcout,2]"; // flushes the printf() above
249 std::printf ("[stdout,4]"); // flushed during termination
250
251#endif // _RWSTD_WCHAR_T
252
253 return 0;
254}
255
256
257static int
258exec_stderr_setup ()
259{
260 // create a new file and redirect stderr to it
261 const int fd_stderr = redirect_to_file (stderr_fname, STDERR_FILENO);
262
263 if (fd_stderr != STDERR_FILENO)
264 return fd_stderr;
265
266 // expected output (w/o newlines):
267 // "[STDERR_FILENO]"
268 // "[cerr,1][stderr,1][cerr,2][stderr,2]"
269 // "[clog,1][stderr,3][clog,2][stderr,4]"
270 // "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
271 // "[wclog,1][stderr,7][wclog,2][stderr,8]"
272
273 write (STDERR_FILENO, "[STDERR_FILENO]", 15);
274 std::cerr << "[cerr,1]";
275 std::fprintf (stderr, "[stderr,1]");
276 std::cerr << "[cerr,2]";
277 std::fprintf (stderr, "[stderr,2]");
278 std::clog << "[clog,1]";
279 std::fprintf (stderr, "[stderr,3]");
280 std::clog << "[clog,2]";
281 std::fprintf (stderr, "[stderr,4]");
282
283#ifndef _RWSTD_WCHAR_T
284
285 std::wcerr << "[wcerr,1]";
286 std::fprintf (stderr, "[stderr,5]");
287 std::wcerr << "[wcerr,2]";
288 std::fprintf (stderr, "[stderr,6]");
289 std::wclog << "[wclog,1]";
290 std::fprintf (stderr, "[stderr,7]");
291 std::wclog << "[wclog,2]";
292 std::fprintf (stderr, "[stderr,8]");
293
294#endif // _RWSTD_WCHAR_T
295
296 return 0;
297}
298
299
300static int
301exec_stdio_setup ()
302{
303 // create a new file and redirect both stdout and stderr to it
304 const int fd_stdout = redirect_to_file (stdio_fname, STDOUT_FILENO);
305 const int fd_stderr = redirect_to_file (stdio_fname, STDERR_FILENO);
306
307 if (fd_stdout != STDOUT_FILENO)
308 return fd_stdout;
309
310 if (fd_stderr != STDERR_FILENO)
311 return fd_stderr;
312
313 // expected output (w/o newlines):
314 // "[STDOUT_FILENO][STDERR_FILENO]"
315 // "[cout,1][stdout,1][cout,2]"
316 // "[cerr,1][stderr,1][cerr,2][stderr,2]"
317 // "[clog,1][stderr,3][clog,2][stderr,4]"
318 // "[stdout,2]"
319 // "[wcout,1][stdout,3][wcout,2]"
320 // "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
321 // "[wclog,1][stderr,7][wclog,2][stderr,8]"
322 // "[stdout,4]"
323
324 write (STDOUT_FILENO, "[STDOUT_FILENO]", 15);
325 write (STDERR_FILENO, "[STDERR_FILENO]", 15);
326
327 std::cout << "[cout,1]";
328 std::printf ("[stdout,1]");
329 std::cout << "[cout,2]";
330 std::printf ("[stdout,2]"); // flushed after STDERR output below
331
332 std::cerr << "[cerr,1]";
333 std::fprintf (stderr, "[stderr,1]");
334 std::cerr << "[cerr,2]";
335 std::fprintf (stderr, "[stderr,2]");
336 std::clog << "[clog,1]";
337 std::fprintf (stderr, "[stderr,3]");
338 std::clog << "[clog,2]";
339 std::fprintf (stderr, "[stderr,4]");
340
341#ifndef _RWSTD_NO_WCHAR_T
342
343 std::wcout << "[wcout,1]";
344 std::printf ("[stdout,3]");
345 std::wcout << "[wcout,2]";
346 std::printf ("[stdout,4]"); // flushed after STDERR output below
347
348 std::wcerr << "[wcerr,1]";
349 std::fprintf (stderr, "[stderr,5]");
350 std::wcerr << "[wcerr,2]";
351 std::fprintf (stderr, "[stderr,6]");
352 std::wclog << "[wclog,1]";
353 std::fprintf (stderr, "[stderr,7]");
354 std::wclog << "[wclog,2]";
355 std::fprintf (stderr, "[stderr,8]");
356
357#endif // _RWSTD_NO_WCHAR_T
358
359 return 0;
360}
361
362
365{
366 int dummy;
367
369 if (*stdout_fname)
370 std::remove (stdout_fname);
371 if (*stderr_fname)
372 std::remove (stderr_fname);
373 if (*stdio_fname)
374 std::remove (stdio_fname);
375 }
376};
377
378
379static int
380run_test (int /* unused */, char* /* unused */ [])
381{
382 const cleanup remove_tmp_files = { 0 };
383
384 // prevent unused warnings
385 (void)&remove_tmp_files;
386
387 if (!rw_tmpnam (stdout_fname)) {
388 std::fprintf (stderr,
389 "rw_tmpnam (%p) failed: %s\n",
390 stdout_fname, std::strerror (errno));
391 return 1;
392 }
393
394 if (!rw_tmpnam (stderr_fname)) {
395 std::fprintf (stderr,
396 "rw_tmpnam (%p) failed: %s\n",
397 stderr_fname, std::strerror (errno));
398 return 1;
399 }
400
401 if (!rw_tmpnam (stdio_fname)) {
402 std::fprintf (stderr,
403 "rw_tmpnam (%p) failed: %s\n",
404 stdio_fname, std::strerror (errno));
405 return 1;
406 }
407
408#ifndef _WIN32
409
410 // create three child process and have each redirect
411 // its stdout, stderr, and both, respectively, to
412 // a file
413 // after all the children exit, the parent will check
414 // the contents of the file to determine whether all
415 // streams have been properly flushed and synchronized
416
417 for (int i = 0; i != 3; ++i) {
418 const pid_t child_pid = fork ();
419
420 if (child_pid < 0) { // fork error
421
422 std::fprintf (stderr, "fork() failed: %s\n",
423 std::strerror (errno));
424
425 return 1;
426 }
427 else if (child_pid > 0) { // parent
428 wait (0);
429 }
430 else { // child
431
432 int ret = 1;
433
434 switch (i) {
435 case 0: ret = exec_stderr_setup (); break;
436 case 1: ret = exec_stdout_setup (); break;
437 case 2: ret = exec_stdio_setup (); break;
438 }
439
440 // prevent child process from cleaning up files
442 return ret;
443 }
444 }
445
446#endif // _WIN32
447
448 do_test ();
449
450 return 0;
451}
452
453
454/* extern */ int
455main (int argc, char* argv [])
456{
457 return rw_test (argc, argv, __FILE__,
458 "lib.ios.members.static",
459 "27.4.2.4 ios_base static members",
460 run_test, "", 0);
461}
462
#define i
Definition 17.names.cpp:126
#define buf
Definition 17.names.cpp:452
#define n
Definition 17.names.cpp:130
#define open(f, m)
#define close(f)
void do_test(int line, const char *src, std::size_t resoff, ForwardIterator dummy_iter, const T *, const char *predname)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
char stdout_fname[256]
char stdio_fname[256]
char stderr_fname[256]
#define DEV_TTY
void test_file(const char *fname, const char *expect)
#define main
#define STDOUT_FILENO
#define STDERR_FILENO
#define stderr
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT const char * rw_tmpnam(char *)
Definition file.cpp:206