stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/file.cpp
changeset 0 e4d67989cc36
child 22 ddc455616bd6
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 extern "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     if (-1 == stat (fname, &sb))
       
   295         return _RWSTD_SIZE_MAX;
       
   296 
       
   297     return sb.st_size;
       
   298 #elif defined (_WIN32) || defined (_WIN64)
       
   299 
       
   300     // note: both method of obtaining the size of a file
       
   301     // just written by a process may fail (i.e., the size
       
   302     // will be 0)
       
   303 
       
   304 #  if 1
       
   305 
       
   306     struct _stat sb;
       
   307 
       
   308     if (-1 == _stat (fname, &sb))
       
   309         return _RWSTD_SIZE_MAX;
       
   310 
       
   311     return sb.st_size;
       
   312 
       
   313 #  else
       
   314 
       
   315     // #include <windows.h> for CreateFile() and GetFileSize()
       
   316     const HANDLE hfile =
       
   317         CreateFile (fname,
       
   318                     GENERIC_READ,
       
   319                     0,                     // dwShareMode,
       
   320                     0,                     // lpSecurityAttributes,
       
   321                     OPEN_EXISTING,         // dwCreationDisposition,
       
   322                     FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes,
       
   323                     0);                    // hTemplateFile
       
   324 
       
   325     if (INVALID_HANDLE_VALUE == hfile)
       
   326         return _RWSTD_SIZE_MAX;
       
   327 
       
   328     const size_t size = GetFileSize (hfile, 0);
       
   329 
       
   330     CloseHandle (hfile);
       
   331 
       
   332     return size;
       
   333 
       
   334 #  endif   // 0/1
       
   335 
       
   336 #else   // if !defined (_WIN{32,64})
       
   337 
       
   338     struct stat sb;
       
   339 
       
   340     if (stat (fname, &sb) == -1)
       
   341         return _RWSTD_SIZE_MAX;
       
   342 
       
   343     return sb.st_size;
       
   344 
       
   345 #endif   // _WIN{32,64}
       
   346 
       
   347 }
       
   348 
       
   349 
       
   350 _TEST_EXPORT
       
   351 void* rw_fread (const char *fname,
       
   352                 size_t     *size   /* = 0 */,
       
   353                 const char *mode   /* = "r" */)
       
   354 {
       
   355     // buffer and size supplied by the user
       
   356     static char*  usrbuf = 0;
       
   357     static size_t usrsize = 0;
       
   358 
       
   359     // when called with 0 file name and non-0 size, set the static
       
   360     // local buffer for the functions to use in subsequent calls
       
   361     // with non-0 `fname' instead of dynamically allocating a new
       
   362     // buffer
       
   363     if (!fname && size) {
       
   364 
       
   365         char* const oldbuf = usrbuf;
       
   366 
       
   367         usrbuf  = _RWSTD_CONST_CAST (char*, mode);
       
   368         usrsize = usrbuf ? *size : 0;
       
   369 
       
   370         return oldbuf;
       
   371     }
       
   372 
       
   373     static char   buffer [1024];
       
   374     static char*  buf     = usrbuf ? usrbuf : buffer;
       
   375     static size_t bufsize = usrbuf ? usrsize : sizeof buffer;
       
   376 
       
   377     // open the file in the specified mode
       
   378     FILE* const fp = fopen (fname, mode);
       
   379 
       
   380     if (!fp)
       
   381         return 0;
       
   382 
       
   383     for (char *bufend = buf; ; ) {
       
   384         // compute the total number of bytes read from the file so far
       
   385         // and the number of bytes that are still available in the buffer
       
   386         const size_t bytes_read  = size_t (bufend - buf);
       
   387         const size_t bytes_avail = bufsize - bytes_read;
       
   388 
       
   389         // try to read the contents of the file into the buffer
       
   390         const size_t nbytes = fread (bufend, 1, bytes_avail, fp);
       
   391 
       
   392         if (0 == nbytes) {
       
   393             *bufend = '\0';
       
   394 
       
   395             // store the number of bytes read
       
   396             if (size)
       
   397                 *size = bytes_read;
       
   398 
       
   399             break;
       
   400         }
       
   401 
       
   402         if (nbytes == bytes_avail) {
       
   403 
       
   404             // do not grow user-specified buffer
       
   405             if (buf == usrbuf)
       
   406                 break;
       
   407 
       
   408             const size_t newsize = (bufsize + 1) * 2;
       
   409 
       
   410             // increase the size of the buffer and continue reading
       
   411             char *tmp = new char [newsize];
       
   412             memcpy (tmp, buf, bufsize);
       
   413 
       
   414             // deallocate buffer only if it's been
       
   415             // previously dynamically allocated
       
   416             if (buf != buffer)
       
   417                 delete[] buf;
       
   418 
       
   419             bufsize = newsize;
       
   420             bufend  = tmp + bytes_read;
       
   421             buf     = tmp;
       
   422         }
       
   423 
       
   424         bufend += nbytes;
       
   425     }
       
   426 
       
   427     fclose (fp);
       
   428 
       
   429     return buf;
       
   430 }
       
   431 
       
   432 
       
   433 _TEST_EXPORT
       
   434 size_t rw_fwrite (const char *fname,
       
   435                   const void *buf,
       
   436                   size_t      size /* = -1 */,
       
   437                   const char *mode /* = "w" */)
       
   438 {
       
   439     FILE *fp = 0;
       
   440 
       
   441     if (buf)
       
   442         fp = fopen (fname, mode);
       
   443     else {
       
   444         remove (fname);
       
   445         return 0;
       
   446     }
       
   447 
       
   448     if (!fp)
       
   449         return size_t (-1);
       
   450 
       
   451     if (size_t (-1) == size)
       
   452         size = strlen (_RWSTD_STATIC_CAST (const char*, buf));
       
   453 
       
   454     // fwrite() returns the number of elements successfully written
       
   455     // set it up so that the number of elements == the number of bytes
       
   456     const size_t nbytes = fwrite (buf, 1 /* byte */, size, fp);
       
   457 
       
   458     fclose (fp);
       
   459 
       
   460     return nbytes;
       
   461 }