os/ossrv/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/file.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /************************************************************************
     2  *
     3  * file.cpp - definitions of testsuite file I/O helpers
     4  *
     5  * $Id: file.cpp 290020 2005-09-18 23:58:30Z sebor $
     6  *
     7  ************************************************************************
     8  *
     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
    18  * the License.
    19  * 
    20  **************************************************************************/
    21 
    22 // expand _TEST_EXPORT macros
    23 #define _RWSTD_TEST_SRC
    24 #include <testdefs.h>
    25 #include <file.h>
    26 
    27 #if defined __linux__
    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>
    32 #endif   // __linux__
    33 
    34 #include <fcntl.h>
    35 #include <sys/stat.h>
    36 
    37 #if (!defined  (_WIN32) && !defined (_WIN64)) || defined (__SYMBIAN32__)
    38 #  include <langinfo.h>   // for CODESET
    39 #  include <unistd.h>
    40 #else
    41 #  include <io.h>
    42 #endif
    43 
    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, ...
    50 #include <ctype.h>
    51 #include <wchar.h>    // for wcslen, ...
    52 
    53 
    54 #ifndef PATH_MAX
    55 #  define PATH_MAX   1024
    56 #endif
    57 
    58 #ifndef P_tmpdir
    59 #  define P_tmpdir "/tmp/"
    60 #endif
    61 
    62 #ifndef _RWSTD_NO_PURE_C_HEADERS
    63 
    64 IMPORT_C int mkstemp (char*);
    65 
    66 #endif   // _RWSTD_NO_PURE_C_HEADERS
    67 
    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)
    73 {
    74     FILE* const fp = _RWSTD_STATIC_CAST (FILE*, fpv);
    75 
    76     // ASCII (ISO-646) character map definition
    77     static const char* charmap[] = {
    78         "<NUL>", "<SOH>", "<STX>", "<ETX>", "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
    79         "<backspace>",
    80         "<tab>",
    81         "<newline>",
    82         "<vertical-tab>",
    83         "<form-feed>",
    84         "<carriage-return>",
    85         "<SO>", "<SI>", "<DLE>", "<DC1>", "<DC2>", "<DC3>", "<DC4>", "<NAK>",
    86         "<SYN>","<ETB>", "<CAN>", "<EM>", "<SUB>", "<ESC>", "<IS4>", "<IS3>",
    87         "<IS2>", "<IS1>",
    88         "<space>",
    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>",
    98         /* * */ "<asterisk>",
    99         /* + */ "<plus-sign>",
   100         /* , */ "<comma>",
   101         /* - */ "<hyphen>",
   102         /* . */ "<period>",
   103         /* / */ "<slash>",
   104         /* 0 */ "<zero>",
   105         /* 1 */ "<one>",
   106         /* 2 */ "<two>",
   107         /* 3 */ "<three>",
   108         /* 4 */ "<four>",
   109         /* 5 */ "<five>",
   110         /* 6 */ "<six>",
   111         /* 7 */ "<seven>",
   112         /* 8 */ "<eight>",
   113         /* 9 */ "<nine>",
   114         /* : */ "<colon>",
   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>",
   136         /* ~ */ "<tilde>",
   137         "<DEL>"
   138     };
   139 
   140     if (str) {
   141         // write out `str' using the charmap above
   142         for (; *str; ++str) {
   143             const unsigned char uc = _RWSTD_STATIC_CAST (unsigned char, *str);
   144 
   145             if (uc < sizeof charmap / sizeof *charmap)
   146                 fprintf (fp, "%s", charmap [uc]);
   147             else
   148                 fprintf (fp, "<U%04X>", uc);
   149         }
   150     }
   151     else {
   152 
   153 #if !defined (_WIN32) && !defined (_WIN64)
   154         const char* const codeset = nl_langinfo (CODESET);
   155 #else
   156         // FIXME: determine the current code page
   157         const char* const codeset = "UTF-8";
   158 #endif   // _WIN{32,64}
   159 
   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");
   163 
   164         fprintf (fp, "CHARMAP\n");
   165 
   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);
   169         }
   170 
   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", '}');
   182 
   183         fprintf (fp, "END CHARMAP\n");
   184     }
   185 }
   186 
   187 
   188 _TEST_EXPORT
   189 const char* rw_tmpnam (char *buf)
   190 {
   191 #ifndef _RWSTD_NO_MKSTEMP
   192 #  define TMP_TEMPLATE      "tmpfile-XXXXXX"
   193 
   194     if (!buf) {
   195         static char fname_buf [sizeof (P_tmpdir) + sizeof (TMP_TEMPLATE)];
   196 
   197         buf = fname_buf;
   198         *buf = '\0';
   199     }
   200 
   201     if ('\0' == *buf) {
   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;
   208 
   209         memcpy (buf, P_tmpdir, len);
   210         if (_RWSTD_PATH_SEP != buf [len - 1])
   211             buf [len++] = _RWSTD_PATH_SEP;
   212 
   213         memcpy (buf + len, TMP_TEMPLATE, sizeof TMP_TEMPLATE);
   214     }
   215 
   216     // prevent annoying glibc warnings (issued by the linker):
   217     // the use of `tmpnam' is dangerous, better use `mkstemp'
   218 
   219     const int fd = mkstemp (buf);
   220 
   221     if (-1 == fd) {
   222         fprintf (stderr, "%s:%d: mkstemp(\"%s\") failed: %s\n",
   223                  __FILE__, __LINE__, buf, strerror (errno));
   224         return 0;
   225     }
   226 
   227     close (fd);
   228 
   229     const char* const fname = buf;
   230 
   231 #  undef TMP_TEMPLATE
   232 #else   // if defined (_RWSTD_NO_MKSTEMP)
   233 
   234 #  if defined (_WIN32) || defined (_WIN64)
   235 
   236     // create a temporary file name
   237     char* fname = tempnam (P_tmpdir, ".rwtest-tmp");
   238 
   239     if (fname) {
   240 
   241         static char tmpbuf [256];
   242 
   243         if (0 == buf)
   244             buf = tmpbuf;
   245 
   246         _RWSTD_ASSERT (strlen (fname) < sizeof (tmpbuf));
   247 
   248         // copy the generated temporary file name to the provided buffer
   249         strcpy (buf, fname);
   250 
   251         // free the storage allocated by tempnam()
   252         free (fname);
   253         fname = buf;
   254     }
   255     else {
   256         fprintf (stderr, "%s:%d: tempnam(\"%s\", \"%s\") failed: %s\n",
   257                  __FILE__, __LINE__,
   258                  P_tmpdir, ".rwtest-tmp", strerror (errno));
   259     }
   260 
   261 #  else
   262 #    if defined (__hpux) && defined (_RWSTD_REENTRANT)
   263 
   264     // on HP-UX, in reentrant mode, tmpnam(0) fails by design
   265 
   266     if (!buf) {
   267         static char tmpbuf [L_tmpnam];
   268         buf = tmpbuf;
   269         *buf = '\0';
   270     }
   271 
   272 #    endif   // __hpux && _REENTRANT
   273 
   274     const char* const fname = tmpnam (buf);
   275 
   276     if (!fname)
   277         fprintf (stderr, "%s:%d: tmpnam(\"%s\") failed: %s\n",
   278                  __FILE__, __LINE__, buf, strerror (errno));
   279 
   280 #  endif   // _WIN{32,64}
   281 #endif   // _RWSTD_NO_MKSTEMP
   282 
   283     return fname;
   284 }
   285 
   286 
   287 _TEST_EXPORT
   288 size_t rw_fsize (const char *fname)
   289 {
   290 #ifdef __SYMBIAN32__
   291 
   292     struct stat sb;
   293     
   294     #ifdef __ARMCC__
   295     #pragma diag_suppress 63
   296     #endif
   297     if (-1 == stat (fname, &sb))
   298         return _RWSTD_SIZE_MAX;
   299        
   300 
   301     return sb.st_size;
   302 #elif defined (_WIN32) || defined (_WIN64)
   303 
   304     // note: both method of obtaining the size of a file
   305     // just written by a process may fail (i.e., the size
   306     // will be 0)
   307 
   308 #  if 1
   309 
   310     struct _stat sb;
   311 
   312     if (-1 == _stat (fname, &sb))
   313         return _RWSTD_SIZE_MAX;
   314 
   315     return sb.st_size;
   316 
   317 #  else
   318 
   319     // #include <windows.h> for CreateFile() and GetFileSize()
   320     const HANDLE hfile =
   321         CreateFile (fname,
   322                     GENERIC_READ,
   323                     0,                     // dwShareMode,
   324                     0,                     // lpSecurityAttributes,
   325                     OPEN_EXISTING,         // dwCreationDisposition,
   326                     FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes,
   327                     0);                    // hTemplateFile
   328 
   329     if (INVALID_HANDLE_VALUE == hfile)
   330         return _RWSTD_SIZE_MAX;
   331 
   332     const size_t size = GetFileSize (hfile, 0);
   333 
   334     CloseHandle (hfile);
   335 
   336     return size;
   337 
   338 #  endif   // 0/1
   339 
   340 #else   // if !defined (_WIN{32,64})
   341 
   342     struct stat sb;
   343 
   344     if (stat (fname, &sb) == -1)
   345         return _RWSTD_SIZE_MAX;
   346 
   347     return sb.st_size;
   348 
   349 #endif   // _WIN{32,64}
   350 
   351 }
   352 
   353 
   354 _TEST_EXPORT
   355 void* rw_fread (const char *fname,
   356                 size_t     *size   /* = 0 */,
   357                 const char *mode   /* = "r" */)
   358 {
   359     // buffer and size supplied by the user
   360     static char*  usrbuf = 0;
   361     static size_t usrsize = 0;
   362 
   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
   366     // buffer
   367     if (!fname && size) {
   368 
   369         char* const oldbuf = usrbuf;
   370 
   371         usrbuf  = _RWSTD_CONST_CAST (char*, mode);
   372         usrsize = usrbuf ? *size : 0;
   373 
   374         return oldbuf;
   375     }
   376 
   377     static char   buffer [1024];
   378     static char*  buf     = usrbuf ? usrbuf : buffer;
   379     static size_t bufsize = usrbuf ? usrsize : sizeof buffer;
   380 
   381     // open the file in the specified mode
   382     FILE* const fp = fopen (fname, mode);
   383 
   384     if (!fp)
   385         return 0;
   386 
   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;
   392 
   393         // try to read the contents of the file into the buffer
   394         const size_t nbytes = fread (bufend, 1, bytes_avail, fp);
   395 
   396         if (0 == nbytes) {
   397             *bufend = '\0';
   398 
   399             // store the number of bytes read
   400             if (size)
   401                 *size = bytes_read;
   402 
   403             break;
   404         }
   405 
   406         if (nbytes == bytes_avail) {
   407 
   408             // do not grow user-specified buffer
   409             if (buf == usrbuf)
   410                 break;
   411 
   412             const size_t newsize = (bufsize + 1) * 2;
   413 
   414             // increase the size of the buffer and continue reading
   415             char *tmp = new char [newsize];
   416             memcpy (tmp, buf, bufsize);
   417 
   418             // deallocate buffer only if it's been
   419             // previously dynamically allocated
   420             if (buf != buffer)
   421                 delete[] buf;
   422 
   423             bufsize = newsize;
   424             bufend  = tmp + bytes_read;
   425             buf     = tmp;
   426         }
   427 
   428         bufend += nbytes;
   429     }
   430 
   431     fclose (fp);
   432 
   433     return buf;
   434 }
   435 
   436 
   437 _TEST_EXPORT
   438 size_t rw_fwrite (const char *fname,
   439                   const void *buf,
   440                   size_t      size /* = -1 */,
   441                   const char *mode /* = "w" */)
   442 {
   443     FILE *fp = 0;
   444 
   445     if (buf)
   446         fp = fopen (fname, mode);
   447     else {
   448         remove (fname);
   449         return 0;
   450     }
   451 
   452     if (!fp)
   453         return size_t (-1);
   454 
   455     if (size_t (-1) == size)
   456         size = strlen (_RWSTD_STATIC_CAST (const char*, buf));
   457 
   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);
   461 
   462     fclose (fp);
   463 
   464     return nbytes;
   465 }