sl@0: /************************************************************************ sl@0: * sl@0: * file.cpp - definitions of testsuite file I/O helpers sl@0: * sl@0: * $Id: file.cpp 290020 2005-09-18 23:58:30Z sebor $ sl@0: * sl@0: ************************************************************************ sl@0: * sl@0: * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave sl@0: * Software division. Licensed under the Apache License, Version 2.0 (the sl@0: * "License"); you may not use this file except in compliance with the sl@0: * License. You may obtain a copy of the License at sl@0: * http://www.apache.org/licenses/LICENSE-2.0. Unless required by sl@0: * applicable law or agreed to in writing, software distributed under sl@0: * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR sl@0: * CONDITIONS OF ANY KIND, either express or implied. See the License sl@0: * for the specific language governing permissions and limitations under sl@0: * the License. sl@0: * sl@0: **************************************************************************/ sl@0: sl@0: // expand _TEST_EXPORT macros sl@0: #define _RWSTD_TEST_SRC sl@0: #include sl@0: #include sl@0: sl@0: #if defined __linux__ sl@0: // on Linux define _XOPEN_SOURCE to get CODESET defined in sl@0: # define _XOPEN_SOURCE 500 /* Single Unix conformance */ sl@0: // bring __int32_t into scope (otherwise fails to compile) sl@0: # include sl@0: #endif // __linux__ sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #if (!defined (_WIN32) && !defined (_WIN64)) || defined (__SYMBIAN32__) sl@0: # include // for CODESET sl@0: # include sl@0: #else sl@0: # include sl@0: #endif sl@0: sl@0: #include // for assert sl@0: #include // for errno sl@0: #include // for LC_XXX macros sl@0: #include // for sprintf, ... sl@0: #include // for free, malloc, realloc sl@0: #include // for strcat, strcpy, strlen, ... sl@0: #include sl@0: #include // for wcslen, ... sl@0: sl@0: sl@0: #ifndef PATH_MAX sl@0: # define PATH_MAX 1024 sl@0: #endif sl@0: sl@0: #ifndef P_tmpdir sl@0: # define P_tmpdir "/tmp/" sl@0: #endif sl@0: sl@0: #ifndef _RWSTD_NO_PURE_C_HEADERS sl@0: sl@0: IMPORT_C int mkstemp (char*); sl@0: sl@0: #endif // _RWSTD_NO_PURE_C_HEADERS sl@0: sl@0: // write `str' using symbolic names from the Portable Character Set (PCS) sl@0: // or using the notations for narrow characters outside that set sl@0: // if (0 == str), writes out the CHARMAP section of the locale definition sl@0: // file for the Portable Character Set (in POSIX-compliant format) sl@0: _TEST_EXPORT void pcs_write (void *fpv, const char *str) sl@0: { sl@0: FILE* const fp = _RWSTD_STATIC_CAST (FILE*, fpv); sl@0: sl@0: // ASCII (ISO-646) character map definition sl@0: static const char* charmap[] = { sl@0: "", "", "", "", "", "", "", "", sl@0: "", sl@0: "", sl@0: "", sl@0: "", sl@0: "", sl@0: "", sl@0: "", "", "", "", "", "", "", "", sl@0: "","", "", "", "", "", "", "", sl@0: "", "", sl@0: "", sl@0: /* ! */ "", sl@0: /* " */ "", sl@0: /* # */ "", sl@0: /* $ */ "", sl@0: /* % */ "", sl@0: /* & */ "", sl@0: /* ' */ "", sl@0: /* ( */ "", sl@0: /* ) */ "", sl@0: /* * */ "", sl@0: /* + */ "", sl@0: /* , */ "", sl@0: /* - */ "", sl@0: /* . */ "", sl@0: /* / */ "", sl@0: /* 0 */ "", sl@0: /* 1 */ "", sl@0: /* 2 */ "", sl@0: /* 3 */ "", sl@0: /* 4 */ "", sl@0: /* 5 */ "", sl@0: /* 6 */ "", sl@0: /* 7 */ "", sl@0: /* 8 */ "", sl@0: /* 9 */ "", sl@0: /* : */ "", sl@0: /* ; */ "", sl@0: /* < */ "", sl@0: /* = */ "", sl@0: /* > */ "", sl@0: /* ? */ "", sl@0: /* @ */ "", sl@0: "", "", "", "", "", "", "", "", "", "", sl@0: "", "", "", "", "", "

", "", "", "", "", sl@0: "", "", "", "", "", "", sl@0: /* { */ "", sl@0: /* | */ "", sl@0: /* } */ "", sl@0: /* ~ */ "", sl@0: "" sl@0: }; sl@0: sl@0: if (str) { sl@0: // write out `str' using the charmap above sl@0: for (; *str; ++str) { sl@0: const unsigned char uc = _RWSTD_STATIC_CAST (unsigned char, *str); sl@0: sl@0: if (uc < sizeof charmap / sizeof *charmap) sl@0: fprintf (fp, "%s", charmap [uc]); sl@0: else sl@0: fprintf (fp, "", uc); sl@0: } sl@0: } sl@0: else { sl@0: sl@0: #if !defined (_WIN32) && !defined (_WIN64) sl@0: const char* const codeset = nl_langinfo (CODESET); sl@0: #else sl@0: // FIXME: determine the current code page sl@0: const char* const codeset = "UTF-8"; sl@0: #endif // _WIN{32,64} sl@0: sl@0: fprintf (fp, " \"%s\"\n", codeset); sl@0: fprintf (fp, " 1\n"); sl@0: fprintf (fp, " 1\n"); sl@0: sl@0: fprintf (fp, "CHARMAP\n"); sl@0: sl@0: // write out the charmap above sl@0: for (unsigned i = 0; i != sizeof charmap / sizeof *charmap; ++i) { sl@0: fprintf (fp, "%s \\x%02x\n", charmap [i], i); sl@0: } sl@0: sl@0: // write out duplicate symbolic names to prevent warnings sl@0: fprintf (fp, " \\x%02x\n", '\a'); sl@0: fprintf (fp, " \\x%02x\n", '-'); sl@0: fprintf (fp, " \\x%02x\n", '.'); sl@0: fprintf (fp, " \\x%02x\n", '/'); sl@0: fprintf (fp, " \\x%02x\n", '\\'); sl@0: fprintf (fp, " \\x%02x\n", '^'); sl@0: fprintf (fp, " \\x%02x\n", '_'); sl@0: fprintf (fp, " \\x%02x\n", '_'); sl@0: fprintf (fp, " \\x%02x\n", '{'); sl@0: fprintf (fp, " \\x%02x\n", '}'); sl@0: sl@0: fprintf (fp, "END CHARMAP\n"); sl@0: } sl@0: } sl@0: sl@0: sl@0: _TEST_EXPORT sl@0: const char* rw_tmpnam (char *buf) sl@0: { sl@0: #ifndef _RWSTD_NO_MKSTEMP sl@0: # define TMP_TEMPLATE "tmpfile-XXXXXX" sl@0: sl@0: if (!buf) { sl@0: static char fname_buf [sizeof (P_tmpdir) + sizeof (TMP_TEMPLATE)]; sl@0: sl@0: buf = fname_buf; sl@0: *buf = '\0'; sl@0: } sl@0: sl@0: if ('\0' == *buf) { sl@0: // copy the template to the buffer; make sure there is exactly sl@0: // one path separator character between P_tmpdir and the file sl@0: // name template (it doesn't really matter how many there are sl@0: // as long as it's at least one, but one looks better than two sl@0: // in diagnostic messages) sl@0: size_t len = sizeof (P_tmpdir) - 1; sl@0: sl@0: memcpy (buf, P_tmpdir, len); sl@0: if (_RWSTD_PATH_SEP != buf [len - 1]) sl@0: buf [len++] = _RWSTD_PATH_SEP; sl@0: sl@0: memcpy (buf + len, TMP_TEMPLATE, sizeof TMP_TEMPLATE); sl@0: } sl@0: sl@0: // prevent annoying glibc warnings (issued by the linker): sl@0: // the use of `tmpnam' is dangerous, better use `mkstemp' sl@0: sl@0: const int fd = mkstemp (buf); sl@0: sl@0: if (-1 == fd) { sl@0: fprintf (stderr, "%s:%d: mkstemp(\"%s\") failed: %s\n", sl@0: __FILE__, __LINE__, buf, strerror (errno)); sl@0: return 0; sl@0: } sl@0: sl@0: close (fd); sl@0: sl@0: const char* const fname = buf; sl@0: sl@0: # undef TMP_TEMPLATE sl@0: #else // if defined (_RWSTD_NO_MKSTEMP) sl@0: sl@0: # if defined (_WIN32) || defined (_WIN64) sl@0: sl@0: // create a temporary file name sl@0: char* fname = tempnam (P_tmpdir, ".rwtest-tmp"); sl@0: sl@0: if (fname) { sl@0: sl@0: static char tmpbuf [256]; sl@0: sl@0: if (0 == buf) sl@0: buf = tmpbuf; sl@0: sl@0: _RWSTD_ASSERT (strlen (fname) < sizeof (tmpbuf)); sl@0: sl@0: // copy the generated temporary file name to the provided buffer sl@0: strcpy (buf, fname); sl@0: sl@0: // free the storage allocated by tempnam() sl@0: free (fname); sl@0: fname = buf; sl@0: } sl@0: else { sl@0: fprintf (stderr, "%s:%d: tempnam(\"%s\", \"%s\") failed: %s\n", sl@0: __FILE__, __LINE__, sl@0: P_tmpdir, ".rwtest-tmp", strerror (errno)); sl@0: } sl@0: sl@0: # else sl@0: # if defined (__hpux) && defined (_RWSTD_REENTRANT) sl@0: sl@0: // on HP-UX, in reentrant mode, tmpnam(0) fails by design sl@0: sl@0: if (!buf) { sl@0: static char tmpbuf [L_tmpnam]; sl@0: buf = tmpbuf; sl@0: *buf = '\0'; sl@0: } sl@0: sl@0: # endif // __hpux && _REENTRANT sl@0: sl@0: const char* const fname = tmpnam (buf); sl@0: sl@0: if (!fname) sl@0: fprintf (stderr, "%s:%d: tmpnam(\"%s\") failed: %s\n", sl@0: __FILE__, __LINE__, buf, strerror (errno)); sl@0: sl@0: # endif // _WIN{32,64} sl@0: #endif // _RWSTD_NO_MKSTEMP sl@0: sl@0: return fname; sl@0: } sl@0: sl@0: sl@0: _TEST_EXPORT sl@0: size_t rw_fsize (const char *fname) sl@0: { sl@0: #ifdef __SYMBIAN32__ sl@0: sl@0: struct stat sb; sl@0: sl@0: #ifdef __ARMCC__ sl@0: #pragma diag_suppress 63 sl@0: #endif sl@0: if (-1 == stat (fname, &sb)) sl@0: return _RWSTD_SIZE_MAX; sl@0: sl@0: sl@0: return sb.st_size; sl@0: #elif defined (_WIN32) || defined (_WIN64) sl@0: sl@0: // note: both method of obtaining the size of a file sl@0: // just written by a process may fail (i.e., the size sl@0: // will be 0) sl@0: sl@0: # if 1 sl@0: sl@0: struct _stat sb; sl@0: sl@0: if (-1 == _stat (fname, &sb)) sl@0: return _RWSTD_SIZE_MAX; sl@0: sl@0: return sb.st_size; sl@0: sl@0: # else sl@0: sl@0: // #include for CreateFile() and GetFileSize() sl@0: const HANDLE hfile = sl@0: CreateFile (fname, sl@0: GENERIC_READ, sl@0: 0, // dwShareMode, sl@0: 0, // lpSecurityAttributes, sl@0: OPEN_EXISTING, // dwCreationDisposition, sl@0: FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes, sl@0: 0); // hTemplateFile sl@0: sl@0: if (INVALID_HANDLE_VALUE == hfile) sl@0: return _RWSTD_SIZE_MAX; sl@0: sl@0: const size_t size = GetFileSize (hfile, 0); sl@0: sl@0: CloseHandle (hfile); sl@0: sl@0: return size; sl@0: sl@0: # endif // 0/1 sl@0: sl@0: #else // if !defined (_WIN{32,64}) sl@0: sl@0: struct stat sb; sl@0: sl@0: if (stat (fname, &sb) == -1) sl@0: return _RWSTD_SIZE_MAX; sl@0: sl@0: return sb.st_size; sl@0: sl@0: #endif // _WIN{32,64} sl@0: sl@0: } sl@0: sl@0: sl@0: _TEST_EXPORT sl@0: void* rw_fread (const char *fname, sl@0: size_t *size /* = 0 */, sl@0: const char *mode /* = "r" */) sl@0: { sl@0: // buffer and size supplied by the user sl@0: static char* usrbuf = 0; sl@0: static size_t usrsize = 0; sl@0: sl@0: // when called with 0 file name and non-0 size, set the static sl@0: // local buffer for the functions to use in subsequent calls sl@0: // with non-0 `fname' instead of dynamically allocating a new sl@0: // buffer sl@0: if (!fname && size) { sl@0: sl@0: char* const oldbuf = usrbuf; sl@0: sl@0: usrbuf = _RWSTD_CONST_CAST (char*, mode); sl@0: usrsize = usrbuf ? *size : 0; sl@0: sl@0: return oldbuf; sl@0: } sl@0: sl@0: static char buffer [1024]; sl@0: static char* buf = usrbuf ? usrbuf : buffer; sl@0: static size_t bufsize = usrbuf ? usrsize : sizeof buffer; sl@0: sl@0: // open the file in the specified mode sl@0: FILE* const fp = fopen (fname, mode); sl@0: sl@0: if (!fp) sl@0: return 0; sl@0: sl@0: for (char *bufend = buf; ; ) { sl@0: // compute the total number of bytes read from the file so far sl@0: // and the number of bytes that are still available in the buffer sl@0: const size_t bytes_read = size_t (bufend - buf); sl@0: const size_t bytes_avail = bufsize - bytes_read; sl@0: sl@0: // try to read the contents of the file into the buffer sl@0: const size_t nbytes = fread (bufend, 1, bytes_avail, fp); sl@0: sl@0: if (0 == nbytes) { sl@0: *bufend = '\0'; sl@0: sl@0: // store the number of bytes read sl@0: if (size) sl@0: *size = bytes_read; sl@0: sl@0: break; sl@0: } sl@0: sl@0: if (nbytes == bytes_avail) { sl@0: sl@0: // do not grow user-specified buffer sl@0: if (buf == usrbuf) sl@0: break; sl@0: sl@0: const size_t newsize = (bufsize + 1) * 2; sl@0: sl@0: // increase the size of the buffer and continue reading sl@0: char *tmp = new char [newsize]; sl@0: memcpy (tmp, buf, bufsize); sl@0: sl@0: // deallocate buffer only if it's been sl@0: // previously dynamically allocated sl@0: if (buf != buffer) sl@0: delete[] buf; sl@0: sl@0: bufsize = newsize; sl@0: bufend = tmp + bytes_read; sl@0: buf = tmp; sl@0: } sl@0: sl@0: bufend += nbytes; sl@0: } sl@0: sl@0: fclose (fp); sl@0: sl@0: return buf; sl@0: } sl@0: sl@0: sl@0: _TEST_EXPORT sl@0: size_t rw_fwrite (const char *fname, sl@0: const void *buf, sl@0: size_t size /* = -1 */, sl@0: const char *mode /* = "w" */) sl@0: { sl@0: FILE *fp = 0; sl@0: sl@0: if (buf) sl@0: fp = fopen (fname, mode); sl@0: else { sl@0: remove (fname); sl@0: return 0; sl@0: } sl@0: sl@0: if (!fp) sl@0: return size_t (-1); sl@0: sl@0: if (size_t (-1) == size) sl@0: size = strlen (_RWSTD_STATIC_CAST (const char*, buf)); sl@0: sl@0: // fwrite() returns the number of elements successfully written sl@0: // set it up so that the number of elements == the number of bytes sl@0: const size_t nbytes = fwrite (buf, 1 /* byte */, size, fp); sl@0: sl@0: fclose (fp); sl@0: sl@0: return nbytes; sl@0: }

", "", "", "", "", sl@0: "", "", "", "", "", "", sl@0: /* [ */ "", sl@0: /* \ */ "", sl@0: /* ] */ "", sl@0: /* ^ */ "", sl@0: /* _ */ "", sl@0: /* ` */ "", sl@0: "", "", "", "", "", "", "", "", "", "", sl@0: "", "", "", "", "", "