First public contribution.
1 /************************************************************************
3 * file.cpp - definitions of testsuite file I/O helpers
5 * $Id: file.cpp 290020 2005-09-18 23:58:30Z sebor $
7 ************************************************************************
9 * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave
10 * Software division. Licensed under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance with the
12 * License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0. Unless required by
14 * applicable law or agreed to in writing, software distributed under
15 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
16 * CONDITIONS OF ANY KIND, either express or implied. See the License
17 * for the specific language governing permissions and limitations under
20 **************************************************************************/
22 // expand _TEST_EXPORT macros
23 #define _RWSTD_TEST_SRC
28 // on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
29 # define _XOPEN_SOURCE 500 /* Single Unix conformance */
30 // bring __int32_t into scope (otherwise <wctype.h> fails to compile)
31 # include <sys/types.h>
37 #if (!defined (_WIN32) && !defined (_WIN64)) || defined (__SYMBIAN32__)
38 # include <langinfo.h> // for CODESET
44 #include <assert.h> // for assert
45 #include <errno.h> // for errno
46 #include <locale.h> // for LC_XXX macros
47 #include <stdio.h> // for sprintf, ...
48 #include <stdlib.h> // for free, malloc, realloc
49 #include <string.h> // for strcat, strcpy, strlen, ...
51 #include <wchar.h> // for wcslen, ...
55 # define PATH_MAX 1024
59 # define P_tmpdir "/tmp/"
62 #ifndef _RWSTD_NO_PURE_C_HEADERS
64 IMPORT_C int mkstemp (char*);
66 #endif // _RWSTD_NO_PURE_C_HEADERS
68 // write `str' using symbolic names from the Portable Character Set (PCS)
69 // or using the <U00XX> notations for narrow characters outside that set
70 // if (0 == str), writes out the CHARMAP section of the locale definition
71 // file for the Portable Character Set (in POSIX-compliant format)
72 _TEST_EXPORT void pcs_write (void *fpv, const char *str)
74 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, fpv);
76 // ASCII (ISO-646) character map definition
77 static const char* charmap[] = {
78 "<NUL>", "<SOH>", "<STX>", "<ETX>", "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
85 "<SO>", "<SI>", "<DLE>", "<DC1>", "<DC2>", "<DC3>", "<DC4>", "<NAK>",
86 "<SYN>","<ETB>", "<CAN>", "<EM>", "<SUB>", "<ESC>", "<IS4>", "<IS3>",
89 /* ! */ "<exclamation-mark>",
90 /* " */ "<quotation-mark>",
91 /* # */ "<number-sign>",
92 /* $ */ "<dollar-sign>",
93 /* % */ "<percent-sign>",
94 /* & */ "<ampersand>",
95 /* ' */ "<apostrophe>",
96 /* ( */ "<left-parenthesis>",
97 /* ) */ "<right-parenthesis>",
99 /* + */ "<plus-sign>",
115 /* ; */ "<semicolon>",
116 /* < */ "<less-than-sign>",
117 /* = */ "<equals-sign>",
118 /* > */ "<greater-than-sign>",
119 /* ? */ "<question-mark>",
120 /* @ */ "<commercial-at>",
121 "<A>", "<B>", "<C>", "<D>", "<E>", "<F>", "<G>", "<H>", "<I>", "<J>",
122 "<K>", "<L>", "<M>", "<N>", "<O>", "<P>", "<Q>", "<R>", "<S>", "<T>",
123 "<U>", "<V>", "<W>", "<X>", "<Y>", "<Z>",
124 /* [ */ "<left-square-bracket>",
125 /* \ */ "<backslash>",
126 /* ] */ "<right-square-bracket>",
127 /* ^ */ "<circumflex>",
128 /* _ */ "<underscore>",
129 /* ` */ "<grave-accent>",
130 "<a>", "<b>", "<c>", "<d>", "<e>", "<f>", "<g>", "<h>", "<i>", "<j>",
131 "<k>", "<l>", "<m>", "<n>", "<o>", "<p>", "<q>", "<r>", "<s>", "<t>",
132 "<u>", "<v>", "<w>", "<x>", "<y>", "<z>",
133 /* { */ "<left-brace>",
134 /* | */ "<vertical-line>",
135 /* } */ "<right-brace>",
141 // write out `str' using the charmap above
142 for (; *str; ++str) {
143 const unsigned char uc = _RWSTD_STATIC_CAST (unsigned char, *str);
145 if (uc < sizeof charmap / sizeof *charmap)
146 fprintf (fp, "%s", charmap [uc]);
148 fprintf (fp, "<U%04X>", uc);
153 #if !defined (_WIN32) && !defined (_WIN64)
154 const char* const codeset = nl_langinfo (CODESET);
156 // FIXME: determine the current code page
157 const char* const codeset = "UTF-8";
158 #endif // _WIN{32,64}
160 fprintf (fp, "<code_set_name> \"%s\"\n", codeset);
161 fprintf (fp, "<mb_cur_max> 1\n");
162 fprintf (fp, "<mb_cur_min> 1\n");
164 fprintf (fp, "CHARMAP\n");
166 // write out the charmap above
167 for (unsigned i = 0; i != sizeof charmap / sizeof *charmap; ++i) {
168 fprintf (fp, "%s \\x%02x\n", charmap [i], i);
171 // write out duplicate symbolic names to prevent warnings
172 fprintf (fp, "<alert> \\x%02x\n", '\a');
173 fprintf (fp, "<hyphen-minus> \\x%02x\n", '-');
174 fprintf (fp, "<full-stop> \\x%02x\n", '.');
175 fprintf (fp, "<solidus> \\x%02x\n", '/');
176 fprintf (fp, "<reverse-solidus> \\x%02x\n", '\\');
177 fprintf (fp, "<circumflex-accent> \\x%02x\n", '^');
178 fprintf (fp, "<underline> \\x%02x\n", '_');
179 fprintf (fp, "<low-line> \\x%02x\n", '_');
180 fprintf (fp, "<left-curly-bracket> \\x%02x\n", '{');
181 fprintf (fp, "<right-curly-bracket> \\x%02x\n", '}');
183 fprintf (fp, "END CHARMAP\n");
189 const char* rw_tmpnam (char *buf)
191 #ifndef _RWSTD_NO_MKSTEMP
192 # define TMP_TEMPLATE "tmpfile-XXXXXX"
195 static char fname_buf [sizeof (P_tmpdir) + sizeof (TMP_TEMPLATE)];
202 // copy the template to the buffer; make sure there is exactly
203 // one path separator character between P_tmpdir and the file
204 // name template (it doesn't really matter how many there are
205 // as long as it's at least one, but one looks better than two
206 // in diagnostic messages)
207 size_t len = sizeof (P_tmpdir) - 1;
209 memcpy (buf, P_tmpdir, len);
210 if (_RWSTD_PATH_SEP != buf [len - 1])
211 buf [len++] = _RWSTD_PATH_SEP;
213 memcpy (buf + len, TMP_TEMPLATE, sizeof TMP_TEMPLATE);
216 // prevent annoying glibc warnings (issued by the linker):
217 // the use of `tmpnam' is dangerous, better use `mkstemp'
219 const int fd = mkstemp (buf);
222 fprintf (stderr, "%s:%d: mkstemp(\"%s\") failed: %s\n",
223 __FILE__, __LINE__, buf, strerror (errno));
229 const char* const fname = buf;
232 #else // if defined (_RWSTD_NO_MKSTEMP)
234 # if defined (_WIN32) || defined (_WIN64)
236 // create a temporary file name
237 char* fname = tempnam (P_tmpdir, ".rwtest-tmp");
241 static char tmpbuf [256];
246 _RWSTD_ASSERT (strlen (fname) < sizeof (tmpbuf));
248 // copy the generated temporary file name to the provided buffer
251 // free the storage allocated by tempnam()
256 fprintf (stderr, "%s:%d: tempnam(\"%s\", \"%s\") failed: %s\n",
258 P_tmpdir, ".rwtest-tmp", strerror (errno));
262 # if defined (__hpux) && defined (_RWSTD_REENTRANT)
264 // on HP-UX, in reentrant mode, tmpnam(0) fails by design
267 static char tmpbuf [L_tmpnam];
272 # endif // __hpux && _REENTRANT
274 const char* const fname = tmpnam (buf);
277 fprintf (stderr, "%s:%d: tmpnam(\"%s\") failed: %s\n",
278 __FILE__, __LINE__, buf, strerror (errno));
280 # endif // _WIN{32,64}
281 #endif // _RWSTD_NO_MKSTEMP
288 size_t rw_fsize (const char *fname)
295 #pragma diag_suppress 63
297 if (-1 == stat (fname, &sb))
298 return _RWSTD_SIZE_MAX;
302 #elif defined (_WIN32) || defined (_WIN64)
304 // note: both method of obtaining the size of a file
305 // just written by a process may fail (i.e., the size
312 if (-1 == _stat (fname, &sb))
313 return _RWSTD_SIZE_MAX;
319 // #include <windows.h> for CreateFile() and GetFileSize()
324 0, // lpSecurityAttributes,
325 OPEN_EXISTING, // dwCreationDisposition,
326 FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes,
329 if (INVALID_HANDLE_VALUE == hfile)
330 return _RWSTD_SIZE_MAX;
332 const size_t size = GetFileSize (hfile, 0);
340 #else // if !defined (_WIN{32,64})
344 if (stat (fname, &sb) == -1)
345 return _RWSTD_SIZE_MAX;
349 #endif // _WIN{32,64}
355 void* rw_fread (const char *fname,
356 size_t *size /* = 0 */,
357 const char *mode /* = "r" */)
359 // buffer and size supplied by the user
360 static char* usrbuf = 0;
361 static size_t usrsize = 0;
363 // when called with 0 file name and non-0 size, set the static
364 // local buffer for the functions to use in subsequent calls
365 // with non-0 `fname' instead of dynamically allocating a new
367 if (!fname && size) {
369 char* const oldbuf = usrbuf;
371 usrbuf = _RWSTD_CONST_CAST (char*, mode);
372 usrsize = usrbuf ? *size : 0;
377 static char buffer [1024];
378 static char* buf = usrbuf ? usrbuf : buffer;
379 static size_t bufsize = usrbuf ? usrsize : sizeof buffer;
381 // open the file in the specified mode
382 FILE* const fp = fopen (fname, mode);
387 for (char *bufend = buf; ; ) {
388 // compute the total number of bytes read from the file so far
389 // and the number of bytes that are still available in the buffer
390 const size_t bytes_read = size_t (bufend - buf);
391 const size_t bytes_avail = bufsize - bytes_read;
393 // try to read the contents of the file into the buffer
394 const size_t nbytes = fread (bufend, 1, bytes_avail, fp);
399 // store the number of bytes read
406 if (nbytes == bytes_avail) {
408 // do not grow user-specified buffer
412 const size_t newsize = (bufsize + 1) * 2;
414 // increase the size of the buffer and continue reading
415 char *tmp = new char [newsize];
416 memcpy (tmp, buf, bufsize);
418 // deallocate buffer only if it's been
419 // previously dynamically allocated
424 bufend = tmp + bytes_read;
438 size_t rw_fwrite (const char *fname,
440 size_t size /* = -1 */,
441 const char *mode /* = "w" */)
446 fp = fopen (fname, mode);
455 if (size_t (-1) == size)
456 size = strlen (_RWSTD_STATIC_CAST (const char*, buf));
458 // fwrite() returns the number of elements successfully written
459 // set it up so that the number of elements == the number of bytes
460 const size_t nbytes = fwrite (buf, 1 /* byte */, size, fp);