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