diff --git a/csrc/stdio/pf_fileio_stdio.c b/csrc/stdio/pf_fileio_stdio.c index 960df63..f3adec9 100644 --- a/csrc/stdio/pf_fileio_stdio.c +++ b/csrc/stdio/pf_fileio_stdio.c @@ -1,5 +1,6 @@ /*************************************************************** -** File access routines based on ANSI C (no Unix stuff). +** File access routines based on ANSI C +** (no more Unix stuff than strictly necessary). ** ** This file is part of pForth ** @@ -25,32 +26,33 @@ typedef int bool_t; -/* Copy SIZE bytes from File FROM to File TO. Return non-FALSE on error. */ -static bool_t CopyFile( FileStream *From, FileStream *To, long Size) -{ - bool_t Error = TRUE; - size_t Diff = Size; - size_t BufSize = 512; - char *Buffer = pfAllocMem( BufSize ); - if( Buffer != 0 ) - { - while( Diff > 0 ) - { - size_t N = MIN( Diff, BufSize ); - if( fread( Buffer, 1, N, From ) < N ) goto cleanup; - if( fwrite( Buffer, 1, N, To ) < N ) goto cleanup; - Diff -= N; - } - Error = FALSE; +static bool_t TruncateFile( FileStream *File, long Newsize ); /* Shrink the file FILE to NEWSIZE. Return non-FALSE on error. */ -cleanup: - pfFreeMem( Buffer ); - } - return Error; +#if defined( __CYGWIN__) || defined( __FreeBSD__) || defined(__NetBSD__) || defined(__minix__) /* __unix__ */ +/* Cygwin, FreeBSD, NetBSD and (Manjaro)Linux all define "__unix__", + which might also be defined on incompatible platforms as well (so we do not use it). + Linux is excluded from the if statement in order to test the portable code on build. + This uses Unix specific APIs to work around problems with the portable implementation. +*/ + +#include /* fileno() */ +#include /* ftruncate */ + +static bool_t TruncateFile( FileStream *File, long Newsize ) +{ + bool_t Error = TRUE; + int fd; + if( -1 != ( fd = fileno(File) ) ) + { + if( 0 == ftruncate(fd, Newsize) ) + Error = FALSE; + } + return Error; } -/* Shrink the file FILE to NEWSIZE. Return non-FALSE on error. - * +#else /* __unix__ */ + +/* * There's no direct way to do this in ANSI C. The closest thing we * have is freopen(3), which truncates a file to zero length if we use * "w+b" as mode argument. So we do this: @@ -64,39 +66,34 @@ static bool_t CopyFile( FileStream *From, FileStream *To, long Size) * * We call freopen with NULL as path argument, because we don't know * the actual file-name. It seems that the trick with path=NULL is - * not part of C89 but it's in C99. It does not work on NetBSD though. - */ - -#if defined(__NetBSD__) || defined(_NETBSD_SOURCE) -/* Tested on NetBSD 10.1. - "F_GETPATH" is not defined on Linux (Kernel 6.6.63), FreeBSD (13.2) or MSYS-Cygwin - (MSYS_NT-10.0-22631), so we restrict this function to NetBSD. - It might also work on "Mac OS X" but that needs to be verified. + * not part of C89 but it's in C99. + * It does not work on NetBSD and Cygwin though. */ -#include - -/* note: we do not malloc this, so we need not to free it after use! */ -static char getFilePathFromStreamData[PATH_MAX]; - -static char* getFilePathFromStream( FileStream* File) +/* Copy SIZE bytes from File FROM to File TO. Return non-FALSE on error. */ +static bool_t CopyFile( FileStream *From, FileStream *To, long Size) { - char* result = NULL; - int fd; - if( (fd=fileno(File)) != -1 ) + bool_t Error = TRUE; + size_t Diff = Size; + size_t BufSize = 512; + char *Buffer = pfAllocMem( BufSize ); + if( Buffer != 0 ) { - if( fcntl(fd, F_GETPATH, getFilePathFromStreamData) != -1 ) + while( Diff > 0 ) { - result = getFilePathFromStreamData; + size_t N = MIN( Diff, BufSize ); + if( fread( Buffer, 1, N, From ) < N ) goto cleanup; + if( fwrite( Buffer, 1, N, To ) < N ) goto cleanup; + Diff -= N; } + Error = FALSE; + +cleanup: + pfFreeMem( Buffer ); } - return result; + return Error; } -#else -static char* getFilePathFromStream( FileStream* File) { return NULL; } -#endif /* NetBSD */ - static bool_t TruncateFile( FileStream *File, long Newsize ) { bool_t Error = TRUE; @@ -107,7 +104,7 @@ static bool_t TruncateFile( FileStream *File, long Newsize ) { if( CopyFile( File, TmpFile, Newsize )) goto cleanup; if( fseek( TmpFile, 0, SEEK_SET ) != 0 ) goto cleanup; - if( freopen( getFilePathFromStream(File), "w+b", File ) == NULL ) goto cleanup; + if( freopen( NULL, "w+b", File ) == NULL ) goto cleanup; if( CopyFile( TmpFile, File, Newsize )) goto cleanup; Error = FALSE; @@ -118,6 +115,9 @@ static bool_t TruncateFile( FileStream *File, long Newsize ) return Error; } +#endif /* __unix__ */ + + /* Write DIFF 0 bytes to FILE. Return non-FALSE on error. */ static bool_t ExtendFile( FileStream *File, size_t Diff ) {