Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
file.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30
31// both macros must be defined before #including <rw/_defs.h>
32#ifndef _RWSTD_NO_PURE_C_HEADERS
33# define _RWSTD_NO_PURE_C_HEADERS
34#endif // _RWSTD_NO_PURE_C_HEADERS
35
36#ifndef _RWSTD_NO_DEPRECATED_C_HEADERS
37# define _RWSTD_NO_DEPRECATED_C_HEADERS
38#endif // _RWSTD_NO_DEPRECATED_C_HEADERS
39
40#include <errno.h> // for ERANGE, errno
41#include <stdio.h> // for P_tmpdir, std{err,in,out}, tmpnam()
42#include <stdlib.h> // for mkstemp(), strtoul()
43#include <ctype.h> // for isalpha(), isspace(), toupper()
44
45
46#if defined (_WIN32) && !defined (__CYGWIN__)
47# include <fcntl.h>
48# include <io.h>
49#else
50# include <unistd.h>
51# include <fcntl.h>
52#endif // _WIN32
53
54#ifdef _WIN32
55# define _BINARY _O_BINARY
56#else
57# define _BINARY 0
58#endif
59
60
61#include <rw/_file.h>
62#include <rw/_defs.h>
63
64
65#ifdef _RWSTD_MSVC
66 // shut up the braindead warning C4146: unary minus operator
67 // applied to unsigned type, result still unsigned
68# pragma warning (disable: 4146)
69#endif // _RWSTD_MSVC
70
71
72#if defined (_RWSTD_NO_MKSTEMP) && !defined (_RWSTD_NO_MKSTEMP_IN_LIBC) \
73 || !defined (_RWSTD_NO_PURE_C_HEADERS)
74
75extern "C" {
76
77#undef mkstemp
78#define mkstemp _RWSTD_LIBC_SYM (mkstemp)
79
80_RWSTD_DLLIMPORT int mkstemp (char*);
81
82} // extern "C"
83
84# undef _RWSTD_NO_MKSTEMP
85
86#endif // _RWSTD_NO_MKSTEMP[_IN_LIBC] || !_NO_PURE_C_HEADERS
87
88
89#if defined (_RWSTD_NO_FILENO) && !defined (_RWSTD_NO_FILENO_IN_LIBC) \
90 || !defined (_RWSTD_NO_PURE_C_HEADERS)
91
92// declare fileno in case it's not declared (for strict ANSI conformance)
93extern "C" {
94
96
97# undef _RWSTD_NO_FILENO
98
99} // extern "C"
100
101#endif // _NO_FILENO && !_NO_FILENO_IN_LIBC || !_NO_PURE_C_HEADERS
102
103
105
106
107#if __SUNPRO_CC == 0x530 && defined (__SunOS_5_6)
108 // working around a SunPro 5.3 bug on SunOS 5.6 (PR #26283)
109# define _RWSTD_FILENO(f) (f)->_file
110#else
111# define _RWSTD_FILENO(f) fileno (f)
112#endif
113
114
115static const int __rw_io_modes [] = {
116 /* 0 */ -1,
117 /* 1 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_WRONLY,
118 /* 2 */ -1,
119 /* 3 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_WRONLY | _BINARY,
120 /* 4 */ _RWSTD_O_RDONLY,
121 /* 5 */ _RWSTD_O_RDONLY | _RWSTD_O_APPEND,
122 /* 6 */ _RWSTD_O_RDONLY | _BINARY,
123 /* 7 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_RDONLY | _BINARY,
124 /* 8 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_WRONLY,
125 /* 9 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_WRONLY,
126 /* 10 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_WRONLY | _BINARY,
127 /* 11 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_WRONLY | _BINARY,
128 /* 12 */ _RWSTD_O_RDWR,
129 /* 13 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_RDWR,
130 /* 14 */ _RWSTD_O_RDWR | _BINARY,
131 /* 15 */ _RWSTD_O_CREAT | _RWSTD_O_APPEND | _RWSTD_O_RDWR | _BINARY,
132 /* 16 */ _RWSTD_O_TRUNC,
133 /* 17 */ _RWSTD_O_TRUNC | _RWSTD_O_APPEND,
134 /* 18 */ _RWSTD_O_TRUNC | _BINARY,
135 /* 19 */ _RWSTD_O_TRUNC | _RWSTD_O_APPEND | _BINARY,
136 /* 20 */ _RWSTD_O_TRUNC | _RWSTD_O_RDONLY,
137 /* 21 */ _RWSTD_O_TRUNC | _RWSTD_O_APPEND | _RWSTD_O_RDONLY,
138 /* 22 */ _RWSTD_O_TRUNC | _RWSTD_O_RDONLY | _BINARY,
139 /* 23 */ _RWSTD_O_TRUNC | _RWSTD_O_APPEND | _RWSTD_O_RDONLY | _BINARY,
140 /* 24 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_WRONLY,
141 /* 25 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_APPEND
142 | _RWSTD_O_WRONLY,
143 /* 26 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_WRONLY | _BINARY,
144 /* 27 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_APPEND
145 | _RWSTD_O_WRONLY | _BINARY,
146 /* 28 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_RDWR,
147 /* 29 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_APPEND | _RWSTD_O_RDWR,
148 /* 30 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_RDWR | _BINARY,
149 /* 31 */ _RWSTD_O_CREAT | _RWSTD_O_TRUNC | _RWSTD_O_APPEND | _RWSTD_O_RDWR
150 | _BINARY
151};
152
153
154static const char __rw_stdio_modes [][4] = {
155 /* 0 */ "", // error
156 /* 1 */ "a", // app
157 /* 2 */ "", // binary
158 /* 3 */ "ab", // binary|app
159 /* 4 */ "r", // in
160 /* 5 */ "a", // in|app
161 /* 6 */ "rb", // in|binary
162 /* 7 */ "ab", // in|binary|app
163 /* 8 */ "w", // out
164 /* 9 */ "a", // out|app
165 /* 10 */ "wb", // out|binary
166 /* 11 */ "ab", // out|binary|app
167 /* 12 */ "r+", // out|in
168 /* 13 */ "a+", // out|in|app
169 /* 14 */ "r+b", // out|in|binary
170 /* 15 */ "a+b", // out|in|binary|app
171 /* 16 */ "w", // trunc
172 /* 17 */ "w", // trunc|app
173 /* 18 */ "wb", // trunc|binary
174 /* 19 */ "wb", // trunc|binary|app
175 /* 20 */ "", // trunc|in
176 /* 21 */ "", // trunc|in|app
177 /* 22 */ "", // trunc|in|binary
178 /* 23 */ "", // trunc|in|binary|app
179 /* 24 */ "w", // trunc|out
180 /* 25 */ "w", // trunc|out|app
181 /* 26 */ "wb", // trunc|out|binary
182 /* 27 */ "wb", // trunc|out|binary|app
183 /* 28 */ "w+", // trunc|out|in
184 /* 29 */ "w+", // trunc|out|in|app
185 /* 30 */ "w+b", // trunc|out|in|binary
186 /* 31 */ "w+b" // trunc|out|in|binary|app
187#ifdef _RWSTD_METADATA_EXTENSIONS
188 /* 32 */ "w+b+f", // trunc|out|in|binary|app|fork
189 /* 33 */ "w+f", // trunc|out|in|fork
190 /* 34 */ "r+f", // out|in|fork
191 /* 35 */ "r+b+f", // out|in|fork
192 /* 36 */ "f", // fork
193 /* 37 */ "" // trunc|in|binary|app|fork
194#endif // _RWSTD_METADATA_EXTENSIONS
195};
196
197
198static const int
199__rw_openmode_mask =
202
203
204// converts iostream open mode to POSIX file access mode
205static inline int
206__rw_io_mode (int openmode)
207{
208 // mask out irrelevant bits
209 const _RWSTD_SIZE_T inx = openmode & __rw_openmode_mask;
210
211 if (sizeof __rw_io_modes / sizeof *__rw_io_modes <= inx)
212 return -1;
213
214 int fdmode = __rw_io_modes [inx];
215
216 // nocreate: open fails if the file does not exist
217 if (openmode & _RWSTD_IOS_NOCREATE)
218 fdmode &= ~_RWSTD_O_CREAT;
219
220 // noreplace: open for writing fails if the file exists
221 if ( (openmode & (_RWSTD_IOS_OUT | _RWSTD_IOS_NOREPLACE))
223 fdmode |= _RWSTD_O_EXCL;
224
225 return fdmode;
226}
227
228
229// converts iostream open mode to C stdio file open mode
230// or the empty string on error (never returns null)
231static inline const char*
232__rw_stdio_mode (int openmode)
233{
234 // mask out irrelevant bits
235 const _RWSTD_SIZE_T inx = openmode & __rw_openmode_mask;
236
237 if (sizeof __rw_stdio_modes / sizeof *__rw_stdio_modes <= inx)
238 return ""; // error -- bad mode
239
240 if (openmode & (_RWSTD_IOS_NOCREATE | _RWSTD_IOS_NOREPLACE))
241 return ""; // error -- not implemented
242
243 const char* const stdio_mode = __rw_stdio_modes [inx];
244
245 // verify postcondition: function never returns null
246 _RWSTD_ASSERT (0 != stdio_mode);
247
248 return stdio_mode;
249}
250
251
252static int
253__rw_mkstemp (int modebits, long prot)
254{
255 int fd;
256
257#ifndef _RWSTD_NO_MKSTEMP
258
259 // mkstemp() opens a temporary file for reading and writing
260 _RWSTD_UNUSED (modebits);
261 _RWSTD_UNUSED (prot);
262
263# ifndef P_tmpdir // #defined in <stdio.h> by POSIX
264# define P_tmpdir "/tmp"
265# endif // P_tmpdir
266
267 char fnamebuf[] = P_tmpdir "/.rwtmpXXXXXX";
268
269 fd = mkstemp (fnamebuf);
270
271 if (fd >= 0)
272 unlink (fnamebuf);
273
274#else // if defined (_RWSTD_NO_MKSTEMP)
275
276 modebits |= _RWSTD_O_EXCL | _RWSTD_O_CREAT;
277
278#ifdef _WIN32
279
280 // tempnam(const char *dir, const char *prefix) will generate
281 // a unique file name for a directory chosen by the following rules:
282 //
283 // * If the TMP environment variable is defined and set to a valid
284 // directory name, unique file names will be generated for the
285 // directory specified by TMP.
286 // * If the TMP environment variable is not defined or if it is set
287 // to the name of a directory that does not exist, tempnam will
288 // use the dir parameter as the path for which it will generate
289 // unique names.
290 // * If the TMP environment variable is not defined or if it is set
291 // to the name of a directory that does not exist, and if dir is
292 // either NULL or set to the name of a directory that does not
293 // exist, tempnam will use the current working directory to
294 // generate unique names. Currently, if both TMP and dir specify
295 // names of directories that do not exist, the tempnam function
296 // call will fail.
297 //
298 // The name returned by tempnam will be a concatenation of prefix
299 // and a sequential number, which will combine to create a unique
300 // file name for the specified directory. tempnam generates file
301 // names that have no extension. tempnam uses malloc to allocate
302 // space for the filename; the program is responsible for freeing
303 // this space when it is no longer needed.
304 char* const fname = tempnam (P_tmpdir, ".rwtmp");
305
306 if (!fname)
307 return -1;
308
309 // create a temporary file that will be deleted when
310 // the last file descriptor that refers to it is closed
311 fd = open (fname, modebits | _O_TEMPORARY, prot);
312
313 // deallocate storage allocated by tempnam()
314 free (fname);
315
316# else // ifndef _WIN32
317
318 char tmpbuf [L_tmpnam];
319
320 const char* const fname = tmpnam (tmpbuf);
321
322 if (!fname)
323 return -1;
324
325 fd = open (fname, modebits, prot);
326
327 // unlink the file, forcing the OS to delete it when
328 // the last file descriptor that refers to it is closed
329 if (fd >= 0)
330 unlink (fname);
331
332# endif // _WIN32
333#endif // _RWSTD_NO_MKSTEMP
334
335 return fd;
336}
337
338
339_RWSTD_EXPORT void*
340__rw_fopen (const char *fname, int openmode, long prot)
341{
342 if (openmode & _RWSTD_IOS_STDIO) {
343
344 // convert the iostream open mode to the C stdio file open mode
345 const char* const fmode = __rw_stdio_mode (openmode);
346
347 _RWSTD_ASSERT (0 != fmode);
348
349 // fmode is the empty string on failure
350 if ('\0' == *fmode)
351 return 0;
352
353 FILE *file;
354
355 if (fname) {
356 // open the named file using C stdio
357 file = fopen (fname, fmode);
358 }
359 else {
360 // FIXME: check openmode to make sure it's valid for "w+"
361
362 // extension: create a temporary file for update ("w+")
363 // that will be automatically deleted when all references
364 // to the file are closed
365 file = tmpfile ();
366 }
367
368 if (0 == file)
369 return 0;
370
371 return _RWSTD_STATIC_CAST (void*, file);
372 }
373
374 // convert the iostream open mode to the POSIX file access mode
375 const int fdmode = __rw_io_mode (openmode);
376
377 if (fdmode < 0)
378 return 0;
379
380 int fd;
381
382 if (fname) {
383 // open the named file
384 fd = open (fname, fdmode, prot);
385 }
386 else {
387 // extension: create a temporary file that will be deleted
388 // when the last file descriptor that refers to it is closed
389 fd = __rw_mkstemp (fdmode, prot);
390 }
391
392 if (fd < 0)
393 return 0;
394
395 return _RWSTD_REINTERPRET_CAST (void*, fd + 1);
396}
397
398
399_RWSTD_EXPORT void*
400__rw_fdopen (int fd)
401{
402 if (fd < 0)
403 return 0;
404
405 return _RWSTD_REINTERPRET_CAST (void*, fd + 1);
406}
407
408
410__rw_fclose (void *file, int flags)
411{
412 if (flags & _RWSTD_IOS_STDIO) {
413 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
414
415 return fclose (fp);
416 }
417
418 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
419
420 return close (fd);
421}
422
423
425__rw_fileno (void *file, int flags)
426{
428 return _RWSTD_FILENO (_RWSTD_STATIC_CAST (FILE*, file));
429
430 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
431
432 return fd;
433}
434
435
437__rw_fdmode (int fd)
438{
439// FIXME -- need to have equivalent of fcntl() on win32.
440#ifdef _WIN32
441
442 return fd == _RWSTD_STDIN_FILENO
444 : fd == _RWSTD_STDOUT_FILENO || fd == _RWSTD_STDERR_FILENO
446
447#else // ifndef _WIN32
448
449 const int m = fcntl (fd, _RWSTD_F_GETFL);
450
451 if (-1 == m)
453
454 int mode = m & _RWSTD_O_APPEND ? _RWSTD_IOS_APP : 0;
455
456 switch (m & _RWSTD_O_ACCMODE) {
457 case _RWSTD_O_RDONLY: mode |= _RWSTD_IOS_IN; break;
458 case _RWSTD_O_WRONLY: mode |= _RWSTD_IOS_OUT; break;
459 case _RWSTD_O_RDWR: mode |= _RWSTD_IOS_IN | _RWSTD_IOS_OUT; break;
460 }
461
462 return mode;
463
464#endif
465}
466
467
469__rw_fmode (void *file, int flags)
470{
471 if (flags & _RWSTD_IOS_STDIO) {
472 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
473
474 return __rw_fdmode (_RWSTD_FILENO (fp));
475 }
476
477 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
478
479 return __rw_fdmode (fd);
480}
481
482
483#if defined (_RWSTD_MSVC) && defined (_WIN64)
484// disable MSVC warning: conversion from '__int64' to 'long', possible loss of data
485#pragma warning (disable: 4244)
486#endif
487
488_RWSTD_EXPORT long
489__rw_fseek (void *file, int flags, _RWSTD_PTRDIFF_T offset, int origin)
490{
491 if (flags & _RWSTD_IOS_STDIO) {
492 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
493
494 const int pos = fseek (fp, long (offset), origin);
495 if (pos < 0)
496 return long (pos);
497
498 return ftell (fp);
499 }
500
501 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
502
503 return lseek (fd, offset, origin);
504}
505
506
507_RWSTD_EXPORT _RWSTD_SIZE_T
508__rw_fread (void *file, int flags, void *buf, _RWSTD_SIZE_T size)
509{
510 if (flags & _RWSTD_IOS_STDIO) {
511 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
512
513 return fread (buf, 1, size, fp);
514 }
515
516 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
517
518 return read (fd, buf, size);
519}
520
521
522_RWSTD_EXPORT _RWSTD_PTRDIFF_T
523__rw_fwrite (void *file, int flags, const void *buf, _RWSTD_SIZE_T size)
524{
525 if (flags & _RWSTD_IOS_STDIO) {
526 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
527
528 return _RWSTD_STATIC_CAST (_RWSTD_PTRDIFF_T, fwrite (buf, 1, size, fp));
529 }
530
531 const int fd = int (_RWSTD_STATIC_CAST (char*, file) - 1 - (char*)0);
532
533 return write (fd, buf, size);
534}
535
536#if defined (_RWSTD_MSVC) && defined (_WIN64)
537// restore MSVC warning: conversion from '__int64' to 'long', possible loss of data
538#pragma warning (default: 4244)
539#endif
540
541
542_RWSTD_EXPORT extern const void* __rw_std_streams[];
543
544
546__rw_fflush (void *file, int flags)
547{
548 if ( file == __rw_std_streams [1] /* cout */
549 || file == __rw_std_streams [5] /* wcout */)
550 return fflush (stdout);
551
552 if ( file == __rw_std_streams [2] /* cerr */
553 || file == __rw_std_streams [3] /* clog */
554 || file == __rw_std_streams [6] /* wcerr */
555 || file == __rw_std_streams [7] /* wclog */)
556 return fflush (stderr);
557
558 if (file) {
559 if (flags & _RWSTD_IOS_STDIO) {
560
561 // `file' is a C file objec, flush it
562 FILE* const fp = _RWSTD_STATIC_CAST (FILE*, file);
563
564 return fflush (fp);
565 }
566
567 // `file' is a file descriptor, no need to flush it
568 }
569 else {
570
571 // convenience call to flush both C files
572 return fflush (stdout) + fflush (stderr);
573 }
574
575 return 0;
576}
577
578
579#ifdef _RWSTD_EDG_ECCP
580
581 // undefine macros that expand to __rw_stderr et al
582 // before initializing the globals to their values
583# undef stderr
584# undef stdin
585# undef stdout
586
587extern "C" {
588
589# ifdef _RWSTD_OS_LINUX
590
591// Linux glibc defines stdin, stdout, and stderr as global objects
592// of type _IO_FILE but we fake the type using FILEs (it doesn't
593// matter since the type isn't mangled into object names)
594extern FILE *stdin;
595extern FILE *stdout;
596extern FILE *stderr;
597
598# elif defined (_RWSTD_OS_SUNOS)
599
600// define a type that's as big as SunOS __FILE
601typedef struct _RW_Sun_FILE {
602
603# if 8 == _RWSTD_LONG_SIZE
604
605 int fill [4]; // 16 bytes
606
607# else // if (ILP32)
608
609 long fill [16]; // 128 bytes
610
611# endif // LP64/ILP32
612
613} __FILE;
614
615
616// Solaris file array
617extern struct __FILE __iob [FOPEN_MAX];
618
619# define stderr (FILE*)(__iob + 0)
620# define stdin (FILE*)(__iob + 1)
621# define stdout (FILE*)(__iob + 2)
622
623# elif defined (_RWSTD_OS_WINDOWS)
624# error "need stderr, stdin, and stdout"
625# else
626# error "need stderr, stdin, and stdout"
627# endif
628
629} // extern "C"
630
631#endif // vanilla EDG eccp
632
633FILE* __rw_stderr = stderr;
634FILE* __rw_stdin = stdin;
635FILE* __rw_stdout = stdout;
636
637} // namespace __rw
#define m
Definition 17.names.cpp:129
#define buf
Definition 17.names.cpp:452
#define offset
Definition 17.names.cpp:508
#define inx
Definition 17.names.cpp:484
#define mode
Definition 17.names.cpp:497
#define pos
Definition 17.names.cpp:518
#define open(f, m)
#define close(f)
#define flags
#define _RWSTD_DLLIMPORT
Definition _config.h:391
#define stdout
#define FILE
#define stderr
#define FOPEN_MAX
#define stdin
#define L_tmpnam
#define _RWSTD_EXPORT
Definition _defs.h:485
#define _RWSTD_IOS_NOREPLACE
Definition _defs.h:822
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_IOS_STDIO
Definition _defs.h:823
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _LIBC_THROWS()
Definition _defs.h:1152
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_IOS_ATE
Definition _defs.h:820
#define _RWSTD_IOS_NOCREATE
Definition _defs.h:821
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_INVALID_OPENMODE
Definition _defs.h:753
#define _RWSTD_IOS_OUT
Definition _defs.h:818
#define _RWSTD_IOS_IN
Definition _defs.h:817
#define _RWSTD_IOS_APP
Definition _defs.h:815
_RWSTD_DLLIMPORT int() fileno(FILE *) _LIBC_THROWS()
#define P_tmpdir
#define _RWSTD_FILENO(f)
#define _BINARY
Definition file.cpp:57
int mkstemp(char *)