Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
file.cpp
Go to the documentation of this file.
1
29// expand _TEST_EXPORT macros
30#define _RWSTD_TEST_SRC
31
32#include <rw_file.h>
33
34#ifdef _RWSTD_OS_LINUX
35# ifdef _RWSTD_NO_PURE_C_HEADERS
36 // on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
37 // (avoid this hackery when using pure "C' headers (i.e., with the EDG
38 // eccp demo)
39# define _XOPEN_SOURCE 500 /* Single Unix conformance */
40 // bring __int32_t into scope (otherwise <wctype.h> fails to compile)
41# include <sys/types.h>
42# endif
43#endif // Linux
44
45#include <fcntl.h>
46#include <sys/stat.h>
47
48#ifndef _WIN32
49# include <langinfo.h> // for CODESET
50# include <unistd.h> // for close(), open()
51#else
52# include <io.h> // for _commit()
53# ifdef _MSC_VER
54# include <crtdbg.h> // for _CrtSetReportMode()
55# endif
56#endif
57
58#include <assert.h> // for assert
59#include <errno.h> // for errno
60#include <locale.h> // for LC_XXX macros
61#include <stdio.h> // for sprintf, ...
62#include <stdlib.h> // for free, malloc, realloc
63#include <string.h> // for strcat, strcpy, strlen, ...
64#include <ctype.h>
65#include <wchar.h> // for wcslen, ...
66
67
68#ifndef PATH_MAX
69# define PATH_MAX 1024
70#endif
71
72#ifndef P_tmpdir
73 // P_tmpdir is an XSI (X/Open System Interfaces) extension
74 // to POSIX which need not be provided by otherwise conforming
75 // implementations
76# define P_tmpdir "/tmp/"
77#endif
78
79#ifndef _RWSTD_NO_PURE_C_HEADERS
80
81extern "C" int mkstemp (char*);
82
83#endif // _RWSTD_NO_PURE_C_HEADERS
84
85// write `str' using symbolic names from the Portable Character Set (PCS)
86// or using the <U00XX> notations for narrow characters outside that set
87// if (0 == str), writes out the CHARMAP section of the locale definition
88// file for the Portable Character Set (in POSIX-compliant format)
89_TEST_EXPORT void pcs_write (void *fpv, const char *str)
90{
91 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, fpv);
92
93 // ASCII (ISO-646) character map definition
94 static const char* charmap[] = {
95 "<NUL>", "<SOH>", "<STX>", "<ETX>", "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
96 "<backspace>",
97 "<tab>",
98 "<newline>",
99 "<vertical-tab>",
100 "<form-feed>",
101 "<carriage-return>",
102 "<SO>", "<SI>", "<DLE>", "<DC1>", "<DC2>", "<DC3>", "<DC4>", "<NAK>",
103 "<SYN>","<ETB>", "<CAN>", "<EM>", "<SUB>", "<ESC>", "<IS4>", "<IS3>",
104 "<IS2>", "<IS1>",
105 "<space>",
106 /* ! */ "<exclamation-mark>",
107 /* " */ "<quotation-mark>",
108 /* # */ "<number-sign>",
109 /* $ */ "<dollar-sign>",
110 /* % */ "<percent-sign>",
111 /* & */ "<ampersand>",
112 /* ' */ "<apostrophe>",
113 /* ( */ "<left-parenthesis>",
114 /* ) */ "<right-parenthesis>",
115 /* * */ "<asterisk>",
116 /* + */ "<plus-sign>",
117 /* , */ "<comma>",
118 /* - */ "<hyphen>",
119 /* . */ "<period>",
120 /* / */ "<slash>",
121 /* 0 */ "<zero>",
122 /* 1 */ "<one>",
123 /* 2 */ "<two>",
124 /* 3 */ "<three>",
125 /* 4 */ "<four>",
126 /* 5 */ "<five>",
127 /* 6 */ "<six>",
128 /* 7 */ "<seven>",
129 /* 8 */ "<eight>",
130 /* 9 */ "<nine>",
131 /* : */ "<colon>",
132 /* ; */ "<semicolon>",
133 /* < */ "<less-than-sign>",
134 /* = */ "<equals-sign>",
135 /* > */ "<greater-than-sign>",
136 /* ? */ "<question-mark>",
137 /* @ */ "<commercial-at>",
138 "<A>", "<B>", "<C>", "<D>", "<E>", "<F>", "<G>", "<H>", "<I>", "<J>",
139 "<K>", "<L>", "<M>", "<N>", "<O>", "<P>", "<Q>", "<R>", "<S>", "<T>",
140 "<U>", "<V>", "<W>", "<X>", "<Y>", "<Z>",
141 /* [ */ "<left-square-bracket>",
142 /* \ */ "<backslash>",
143 /* ] */ "<right-square-bracket>",
144 /* ^ */ "<circumflex>",
145 /* _ */ "<underscore>",
146 /* ` */ "<grave-accent>",
147 "<a>", "<b>", "<c>", "<d>", "<e>", "<f>", "<g>", "<h>", "<i>", "<j>",
148 "<k>", "<l>", "<m>", "<n>", "<o>", "<p>", "<q>", "<r>", "<s>", "<t>",
149 "<u>", "<v>", "<w>", "<x>", "<y>", "<z>",
150 /* { */ "<left-brace>",
151 /* | */ "<vertical-line>",
152 /* } */ "<right-brace>",
153 /* ~ */ "<tilde>",
154 "<DEL>"
155 };
156
157 if (str) {
158 // write out `str' using the charmap above
159 for (; *str; ++str) {
160 const unsigned char uc = _RWSTD_STATIC_CAST (unsigned char, *str);
161
162 if (uc < sizeof charmap / sizeof *charmap)
163 fprintf (fp, "%s", charmap [uc]);
164 else
165 fprintf (fp, "<U%04X>", uc);
166 }
167 }
168 else {
169
170#ifndef _WIN32
171 const char* const codeset = nl_langinfo (CODESET);
172#else
173 // FIXME: determine the current code page
174 const char* const codeset = "UTF-8";
175#endif // _WIN32
176
177 fprintf (fp, "<code_set_name> \"%s\"\n", codeset);
178 fprintf (fp, "<mb_cur_max> 1\n");
179 fprintf (fp, "<mb_cur_min> 1\n");
180
181 fprintf (fp, "CHARMAP\n");
182
183 // write out the charmap above
184 for (unsigned i = 0; i != sizeof charmap / sizeof *charmap; ++i) {
185 fprintf (fp, "%s \\x%02x\n", charmap [i], i);
186 }
187
188 // write out duplicate symbolic names to prevent warnings
189 fprintf (fp, "<alert> \\x%02x\n", '\a');
190 fprintf (fp, "<hyphen-minus> \\x%02x\n", '-');
191 fprintf (fp, "<full-stop> \\x%02x\n", '.');
192 fprintf (fp, "<solidus> \\x%02x\n", '/');
193 fprintf (fp, "<reverse-solidus> \\x%02x\n", '\\');
194 fprintf (fp, "<circumflex-accent> \\x%02x\n", '^');
195 fprintf (fp, "<underline> \\x%02x\n", '_');
196 fprintf (fp, "<low-line> \\x%02x\n", '_');
197 fprintf (fp, "<left-curly-bracket> \\x%02x\n", '{');
198 fprintf (fp, "<right-curly-bracket> \\x%02x\n", '}');
199
200 fprintf (fp, "END CHARMAP\n");
201 }
202}
203
204
206const char* rw_tmpnam (char *buf)
207{
208#ifndef _RWSTD_NO_MKSTEMP
209# define TMP_TEMPLATE "tmpfile-XXXXXX"
210
211 if (!buf) {
212 static char fname_buf [sizeof (P_tmpdir) + sizeof (TMP_TEMPLATE)];
213
214 buf = fname_buf;
215 *buf = '\0';
216 }
217
218 if ('\0' == *buf) {
219 // copy the template to the buffer; make sure there is exactly
220 // one path separator character between P_tmpdir and the file
221 // name template (it doesn't really matter how many there are
222 // as long as it's at least one, but one looks better than two
223 // in diagnostic messages)
224 size_t len = sizeof (P_tmpdir) - 1;
225
226 memcpy (buf, P_tmpdir, len);
227 if (_RWSTD_PATH_SEP != buf [len - 1])
228 buf [len++] = _RWSTD_PATH_SEP;
229
230 memcpy (buf + len, TMP_TEMPLATE, sizeof TMP_TEMPLATE);
231 }
232
233 // prevent annoying glibc warnings (issued by the linker):
234 // the use of `tmpnam' is dangerous, better use `mkstemp'
235
236 const int fd = mkstemp (buf);
237
238 if (-1 == fd) {
239 fprintf (stderr, "%s:%d: mkstemp(\"%s\") failed: %s\n",
240 __FILE__, __LINE__, buf, strerror (errno));
241 return 0;
242 }
243
244 close (fd);
245
246 const char* const fname = buf;
247
248# undef TMP_TEMPLATE
249#else // if defined (_RWSTD_NO_MKSTEMP)
250
251# ifdef _WIN32
252
253 // create a temporary file name
254 char* fname = tempnam (P_tmpdir, ".rwtest-tmp");
255
256 if (fname) {
257
258 static char tmpbuf [256];
259
260 if (0 == buf)
261 buf = tmpbuf;
262
263 _RWSTD_ASSERT (strlen (fname) < sizeof (tmpbuf));
264
265 // copy the generated temporary file name to the provided buffer
266 strcpy (buf, fname);
267
268 // free the storage allocated by tempnam()
269 free (fname);
270 fname = buf;
271 }
272 else {
273 fprintf (stderr, "%s:%d: tempnam(\"%s\", \"%s\") failed: %s\n",
274 __FILE__, __LINE__,
275 P_tmpdir, ".rwtest-tmp", strerror (errno));
276 }
277
278# else
279# if defined (__hpux) && defined (_RWSTD_REENTRANT)
280
281 // on HP-UX, in reentrant mode, tmpnam(0) fails by design
282
283 if (!buf) {
284 static char tmpbuf [L_tmpnam];
285 buf = tmpbuf;
286 *buf = '\0';
287 }
288
289# endif // __hpux && _REENTRANT
290
291 const char* const fname = tmpnam (buf);
292
293 if (!fname)
294 fprintf (stderr, "%s:%d: tmpnam(\"%s\") failed: %s\n",
295 __FILE__, __LINE__, buf, strerror (errno));
296
297# endif // _WIN32
298#endif // _RWSTD_NO_MKSTEMP
299
300 return fname;
301}
302
303
305size_t rw_fsize (const char *fname)
306{
307#ifdef _WIN32
308
309 // note: both method of obtaining the size of a file
310 // just written by a process may fail (i.e., the size
311 // will be 0)
312
313# if 1
314
315 struct _stat sb;
316
317 if (-1 == _stat (fname, &sb))
318 return _RWSTD_SIZE_MAX;
319
320 return sb.st_size;
321
322# else
323
324 // #include <windows.h> for CreateFile() and GetFileSize()
325 const HANDLE hfile =
326 CreateFile (fname,
327 GENERIC_READ,
328 0, // dwShareMode,
329 0, // lpSecurityAttributes,
330 OPEN_EXISTING, // dwCreationDisposition,
331 FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes,
332 0); // hTemplateFile
333
334 if (INVALID_HANDLE_VALUE == hfile)
335 return _RWSTD_SIZE_MAX;
336
337 const size_t size = GetFileSize (hfile, 0);
338
339 CloseHandle (hfile);
340
341 return size;
342
343# endif // 0/1
344
345#else // ifndef _WIN32
346
347 struct stat sb;
348
349 if (stat (fname, &sb) == -1)
350 return _RWSTD_SIZE_MAX;
351
352 return sb.st_size;
353
354#endif // _WIN32
355
356}
357
358
360void* rw_fread (const char *fname,
361 size_t *size /* = 0 */,
362 const char *mode /* = "r" */)
363{
364 // buffer and size supplied by the user
365 static char* usrbuf = 0;
366 static size_t usrsize = 0;
367
368 // when called with 0 file name and non-0 size, set the static
369 // local buffer for the functions to use in subsequent calls
370 // with non-0 `fname' instead of dynamically allocating a new
371 // buffer
372 if (!fname && size) {
373
374 char* const oldbuf = usrbuf;
375
376 usrbuf = _RWSTD_CONST_CAST (char*, mode);
377 usrsize = usrbuf ? *size : 0;
378
379 return oldbuf;
380 }
381
382 static char buffer [1024];
383 static char* buf = usrbuf ? usrbuf : buffer;
384 static size_t bufsize = usrbuf ? usrsize : sizeof buffer;
385
386 // open the file in the specified mode
387 FILE* const fp = fopen (fname, mode);
388
389 if (!fp)
390 return 0;
391
392 for (char *bufend = buf; ; ) {
393 // compute the total number of bytes read from the file so far
394 // and the number of bytes that are still available in the buffer
395 const size_t bytes_read = size_t (bufend - buf);
396 const size_t bytes_avail = bufsize - bytes_read;
397
398 // try to read the contents of the file into the buffer
399 const size_t nbytes = fread (bufend, 1, bytes_avail, fp);
400
401 if (0 == nbytes) {
402 *bufend = '\0';
403
404 // store the number of bytes read
405 if (size)
406 *size = bytes_read;
407
408 break;
409 }
410
411 if (nbytes == bytes_avail) {
412
413 // do not grow user-specified buffer
414 if (buf == usrbuf)
415 break;
416
417 const size_t newsize = (bufsize + 1) * 2;
418
419 // increase the size of the buffer and continue reading
420 char *tmp = new char [newsize];
421 memcpy (tmp, buf, bufsize);
422
423 // deallocate buffer only if it's been
424 // previously dynamically allocated
425 if (buf != buffer)
426 delete[] buf;
427
428 bufsize = newsize;
429 bufend = tmp + bytes_read;
430 buf = tmp;
431 }
432
433 bufend += nbytes;
434 }
435
436 fclose (fp);
437
438 return buf;
439}
440
441
443size_t rw_fwrite (const char *fname,
444 const void *buf,
445 size_t size /* = -1 */,
446 const char *mode /* = "w" */)
447{
448 FILE *fp = 0;
449
450 if (buf)
451 fp = fopen (fname, mode);
452 else {
453 remove (fname);
454 return 0;
455 }
456
457 if (!fp)
458 return size_t (-1);
459
460 if (size_t (-1) == size)
461 size = strlen (_RWSTD_STATIC_CAST (const char*, buf));
462
463 // fwrite() returns the number of elements successfully written
464 // set it up so that the number of elements == the number of bytes
465 const size_t nbytes = fwrite (buf, 1 /* byte */, size, fp);
466
467 fclose (fp);
468
469 return nbytes;
470}
471
472
473
475// get the file descriptor that will be returned by the next call
476// to creat() or open() (used to detect file descriptor leaks)
477_TEST_EXPORT int
479{
480 if (count) {
481
482 *count = 0;
483
484#ifdef _WIN32
485
486# ifdef _MSC_VER
487 // save the report mode and disable "Invalid file descriptor"
488 // CRT assertions from _commit()
489 const int prev_mode = _CrtSetReportMode (_CRT_ASSERT, 0);
490# endif
491
492 for (int i = 0; i != 256; ++i) {
493
494 const int ret = _commit (i);
495
496 if (-1 != ret || EBADF != errno)
497 ++*count;
498 }
499
500# ifdef _MSC_VER
501 // restore the previous mode
502 if (-1 != prev_mode)
503 _CrtSetReportMode (_CRT_ASSERT, prev_mode);
504# endif
505
506#else // if not Windoze
507
508 for (int i = 0; i != 256; ++i) {
509 if (-1 != fcntl (i, F_GETFD))
510 ++*count;
511 }
512
513#endif // _WIN32
514
515 }
516
517 const int fd = open (DEV_NULL, O_RDONLY);
518
519 close (fd);
520
521 return fd;
522}
void count(T, T, const U &,...)
#define i
Definition 17.names.cpp:126
#define sb
Definition 17.names.cpp:542
#define buf
Definition 17.names.cpp:452
#define buffer
Definition 17.names.cpp:453
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
#define mode
Definition 17.names.cpp:497
#define open(f, m)
#define close(f)
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define FILE
#define stderr
#define L_tmpnam
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
const char * str
Definition exec.cpp:170
#define DEV_NULL
Definition rw_file.h:40
#define _TEST_EXPORT
Definition rw_testdefs.h:55
#define P_tmpdir
Definition file.cpp:76
_TEST_EXPORT const char * rw_tmpnam(char *buf)
Definition file.cpp:206
_TEST_EXPORT int rw_nextfd(int *count)
Definition file.cpp:478
int mkstemp(char *)
_TEST_EXPORT size_t rw_fwrite(const char *fname, const void *buf, size_t size, const char *mode)
Definition file.cpp:443
#define TMP_TEMPLATE
_TEST_EXPORT size_t rw_fsize(const char *fname)
Definition file.cpp:305
_TEST_EXPORT void pcs_write(void *fpv, const char *str)
Definition file.cpp:89
_TEST_EXPORT void * rw_fread(const char *fname, size_t *size, const char *mode)
Definition file.cpp:360