2019-12-19 03:24:12 +00:00
# include "cwCommon.h"
# include "cwLog.h"
# include "cwCommonImpl.h"
# include "cwMem.h"
# include "cwFileSys.h"
# include "cwText.h"
# include "cwFile.h"
2020-03-24 12:51:51 +00:00
# ifdef OS_LINUX
2019-12-19 03:24:12 +00:00
# include <sys/stat.h>
# endif
namespace cw
{
2019-12-26 02:44:14 +00:00
namespace file
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
typedef struct file_str
{
FILE * fp ;
char * fnStr ;
2020-12-29 15:09:43 +00:00
rc_t lastRC ;
2019-12-26 02:44:14 +00:00
} this_t ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
this_t * _handleToPtr ( handle_t h )
{
return handleToPtr < handle_t , this_t > ( h ) ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
char * _fileToBuf ( handle_t h , unsigned nn , unsigned * bufByteCntPtr )
{
errno = 0 ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
unsigned n = byteCount ( h ) ;
char * buf = nullptr ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
// if the file size calculation is ok
if ( errno ! = 0 )
{
cwLogSysError ( kOpFailRC , errno , " Invalid file buffer length on '%s'. " , cwStringNullGuard ( name ( h ) ) ) ;
goto errLabel ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
// allocate the read target buffer
2019-12-28 02:51:28 +00:00
if ( ( buf = mem : : alloc < char > ( n + nn ) ) = = nullptr )
2019-12-26 02:44:14 +00:00
{
cwLogError ( kMemAllocFailRC , " Read buffer allocation failed. " ) ;
goto errLabel ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
// read the file
if ( read ( h , buf , n ) ! = kOkRC )
goto errLabel ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
// zero memory after the file data
memset ( buf + n , 0 , nn ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
if ( bufByteCntPtr ! = nullptr )
* bufByteCntPtr = n ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
return buf ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
errLabel :
if ( bufByteCntPtr ! = nullptr )
* bufByteCntPtr = 0 ;
2019-12-19 03:24:12 +00:00
2019-12-28 02:51:28 +00:00
mem : : release ( buf ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
return nullptr ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
char * _fileFnToBuf ( const char * fn , unsigned nn , unsigned * bufByteCntPtr )
{
handle_t h ;
char * buf = nullptr ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
if ( open ( h , fn , kReadFl | kBinaryFl ) ! = kOkRC )
goto errLabel ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
buf = _fileToBuf ( h , nn , bufByteCntPtr ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
errLabel :
close ( h ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
return buf ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
rc_t _fileGetLine ( this_t * p , char * buf , unsigned * bufByteCntPtr )
{
// fgets() reads up to n-1 bytes into buf[]
if ( fgets ( buf , * bufByteCntPtr , p - > fp ) = = nullptr )
{
// an read error or EOF condition occurred
* bufByteCntPtr = 0 ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
if ( ! feof ( p - > fp ) )
2020-12-29 15:09:43 +00:00
return p - > lastRC = cwLogSysError ( kReadFailRC , errno , " File read line failed " ) ;
p - > lastRC = kEofRC ;
return kEofRC ;
2019-12-26 02:44:14 +00:00
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
return kOkRC ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : open ( handle_t & hRef , const char * fn , unsigned flags )
2019-12-19 03:24:12 +00:00
{
2021-02-26 18:33:31 +00:00
this_t * p = nullptr ;
char * exp_fn = nullptr ;
rc_t rc = kOkRC ;
char mode [ ] = " /0/0/0 " ;
2019-12-26 02:44:14 +00:00
if ( ( rc = close ( hRef ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kReadFl ) )
2019-12-19 03:24:12 +00:00
mode [ 0 ] = ' r ' ;
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kWriteFl ) )
2019-12-19 03:24:12 +00:00
mode [ 0 ] = ' w ' ;
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kAppendFl ) )
2019-12-19 03:24:12 +00:00
mode [ 0 ] = ' a ' ;
else
2019-12-26 02:44:14 +00:00
cwLogError ( kInvalidArgRC , " File open flags must contain 'kReadFl','kWriteFl', or 'kAppendFl'. " ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kUpdateFl ) )
2019-12-19 03:24:12 +00:00
mode [ 1 ] = ' + ' ;
// handle requests to use stdin,stdout,stderr
FILE * sfp = nullptr ;
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kStdoutFl ) )
2019-12-19 03:24:12 +00:00
{
sfp = stdout ;
fn = " stdout " ;
}
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kStderrFl ) )
2019-12-19 03:24:12 +00:00
{
sfp = stderr ;
fn = " stderr " ;
}
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kStdinFl ) )
2019-12-19 03:24:12 +00:00
{
sfp = stdin ;
fn = " stdin " ;
}
2021-02-26 18:33:31 +00:00
// verify the filename is not empty
if ( fn = = nullptr | | strlen ( fn ) = = 0 )
2019-12-19 03:24:12 +00:00
return cwLogError ( kInvalidArgRC , " File object allocation failed due to empty file name. " ) ;
2021-02-26 18:33:31 +00:00
2019-12-26 02:44:14 +00:00
unsigned byteCnt = sizeof ( this_t ) + strlen ( fn ) + 1 ;
2019-12-19 03:24:12 +00:00
2021-02-26 18:33:31 +00:00
// create the file object
2019-12-28 02:51:28 +00:00
if ( ( p = mem : : allocZ < this_t > ( byteCnt ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
return cwLogError ( kOpFailRC , " File object allocation failed for file '%s'. " , cwStringNullGuard ( fn ) ) ;
2021-02-26 18:33:31 +00:00
// copy in the file name
2019-12-19 03:24:12 +00:00
p - > fnStr = ( char * ) ( p + 1 ) ;
strcpy ( p - > fnStr , fn ) ;
2021-02-26 18:33:31 +00:00
// if a special file was requestd
2019-12-19 03:24:12 +00:00
if ( sfp ! = nullptr )
p - > fp = sfp ;
2021-02-26 18:33:31 +00:00
else
2019-12-19 03:24:12 +00:00
{
2021-02-26 18:33:31 +00:00
exp_fn = filesys : : expandPath ( fn ) ;
errno = 0 ;
if ( ( p - > fp = fopen ( exp_fn , mode ) ) = = nullptr )
rc = p - > lastRC = cwLogSysError ( kOpenFailRC , errno , " File open failed on file:'%s'. " , cwStringNullGuard ( fn ) ) ;
mem : : release ( exp_fn ) ;
2019-12-19 03:24:12 +00:00
}
2021-02-26 18:33:31 +00:00
if ( rc ! = kOkRC )
mem : : release ( p ) ;
else
hRef . set ( p ) ;
return rc ;
2019-12-19 03:24:12 +00:00
}
2020-12-29 15:09:43 +00:00
cw : : rc_t cw : : file : : close ( handle_t & hRef )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
if ( isValid ( hRef ) = = false )
2019-12-19 03:24:12 +00:00
return kOkRC ;
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( hRef ) ;
2019-12-19 03:24:12 +00:00
errno = 0 ;
if ( p - > fp ! = nullptr )
if ( fclose ( p - > fp ) ! = 0 )
2020-12-29 15:09:43 +00:00
return p - > lastRC = cwLogSysError ( kCloseFailRC , errno , " File close failed on '%s'. " , cwStringNullGuard ( p - > fnStr ) ) ;
2019-12-19 03:24:12 +00:00
2019-12-28 02:51:28 +00:00
mem : : release ( p ) ;
2019-12-26 02:44:14 +00:00
hRef . clear ( ) ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
bool cw : : file : : isValid ( handle_t h )
2019-12-19 03:24:12 +00:00
{ return h . isValid ( ) ; }
2020-12-29 15:09:43 +00:00
cw : : rc_t cw : : file : : lastRC ( handle_t h )
2019-12-19 03:24:12 +00:00
{
2020-12-29 15:09:43 +00:00
this_t * p = _handleToPtr ( h ) ;
return p - > lastRC ;
}
cw : : rc_t cw : : file : : read ( handle_t h , void * buf , unsigned bufByteCnt , unsigned * actualByteCntRef )
{
rc_t rc = kOkRC ;
this_t * p = _handleToPtr ( h ) ;
unsigned actualByteCnt = 0 ;
2020-12-29 16:20:24 +00:00
if ( p - > lastRC ! = kOkRC )
return p - > lastRC ;
2019-12-19 03:24:12 +00:00
errno = 0 ;
2020-12-29 15:09:43 +00:00
if ( ( actualByteCnt = fread ( buf , 1 , bufByteCnt , p - > fp ) ) ! = bufByteCnt )
2020-12-15 20:29:36 +00:00
{
if ( feof ( p - > fp ) ! = 0 )
2020-12-29 15:09:43 +00:00
rc = p - > lastRC = kEofRC ;
else
rc = p - > lastRC = cwLogSysError ( kReadFailRC , errno , " File read failed on '%s'. " , cwStringNullGuard ( p - > fnStr ) ) ;
2020-12-15 20:29:36 +00:00
}
2019-12-19 03:24:12 +00:00
2020-12-29 15:09:43 +00:00
if ( actualByteCntRef ! = nullptr )
* actualByteCntRef = actualByteCnt ;
return rc ;
2019-12-19 03:24:12 +00:00
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : write ( handle_t h , const void * buf , unsigned bufByteCnt )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2020-12-29 16:20:24 +00:00
if ( p - > lastRC ! = kOkRC )
return p - > lastRC ;
2019-12-19 03:24:12 +00:00
2023-11-14 12:52:15 +00:00
if ( bufByteCnt )
{
errno = 0 ;
if ( fwrite ( buf , bufByteCnt , 1 , p - > fp ) ! = 1 )
return p - > lastRC = cwLogSysError ( kWriteFailRC , errno , " File write failed on '%s'. " , cwStringNullGuard ( p - > fnStr ) ) ;
}
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : seek ( handle_t h , enum seekFlags_t flags , int offsByteCnt )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
unsigned fileflags = 0 ;
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kBeginFl ) )
2019-12-19 03:24:12 +00:00
fileflags = SEEK_SET ;
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kCurFl ) )
2019-12-19 03:24:12 +00:00
fileflags = SEEK_CUR ;
else
2019-12-26 02:44:14 +00:00
if ( cwIsFlag ( flags , kEndFl ) )
2019-12-19 03:24:12 +00:00
fileflags = SEEK_END ;
else
return cwLogError ( kInvalidArgRC , " Invalid file seek flag on '%s'. " , cwStringNullGuard ( p - > fnStr ) ) ;
errno = 0 ;
if ( fseek ( p - > fp , offsByteCnt , fileflags ) ! = 0 )
return cwLogSysError ( kSeekFailRC , errno , " File seek failed on '%s' " , cwStringNullGuard ( p - > fnStr ) ) ;
2020-12-29 15:09:43 +00:00
// if the seek succeeded then override any previous error state
p - > lastRC = kOkRC ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : tell ( handle_t h , long * offsPtr )
2019-12-19 03:24:12 +00:00
{
cwAssert ( offsPtr ! = nullptr ) ;
* offsPtr = - 1 ;
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
errno = 0 ;
if ( ( * offsPtr = ftell ( p - > fp ) ) = = - 1 )
2020-12-29 15:09:43 +00:00
return p - > lastRC = cwLogSysError ( kOpFailRC , errno , " File tell failed on '%s'. " , cwStringNullGuard ( p - > fnStr ) ) ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
bool cw : : file : : eof ( handle_t h )
{ return feof ( _handleToPtr ( h ) - > fp ) ! = 0 ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
unsigned cw : : file : : byteCount ( handle_t h )
2019-12-19 03:24:12 +00:00
{
struct stat sr ;
int f ;
2020-12-29 15:09:43 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
const char errMsg [ ] = " File byte count request failed. " ;
errno = 0 ;
if ( ( f = fileno ( p - > fp ) ) = = - 1 )
{
2020-12-29 15:09:43 +00:00
p - > lastRC = cwLogSysError ( kInvalidOpRC , errno , " %s because fileno() failed on '%s'. " , errMsg , cwStringNullGuard ( p - > fnStr ) ) ;
2019-12-19 03:24:12 +00:00
return 0 ;
}
if ( fstat ( f , & sr ) = = - 1 )
{
2020-12-29 15:09:43 +00:00
p - > lastRC = cwLogSysError ( kInvalidOpRC , errno , " %s because fstat() failed on '%s'. " , errMsg , cwStringNullGuard ( p - > fnStr ) ) ;
2019-12-19 03:24:12 +00:00
return 0 ;
}
return sr . st_size ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : byteCountFn ( const char * fn , unsigned * fileByteCntPtr )
2019-12-19 03:24:12 +00:00
{
cwAssert ( fileByteCntPtr ! = nullptr ) ;
rc_t rc ;
2019-12-26 02:44:14 +00:00
handle_t h ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
if ( ( rc = open ( h , fn , kReadFl ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
if ( fileByteCntPtr ! = nullptr )
2019-12-26 02:44:14 +00:00
* fileByteCntPtr = byteCount ( h ) ;
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
close ( h ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : compare ( const char * fn0 , const char * fn1 , bool & isEqualRef )
2019-12-19 03:24:12 +00:00
{
rc_t rc = kOkRC ;
unsigned bufByteCnt = 2048 ;
2019-12-26 02:44:14 +00:00
handle_t h0 ;
handle_t h1 ;
this_t * p0 = nullptr ;
this_t * p1 = nullptr ;
2019-12-19 03:24:12 +00:00
char b0 [ bufByteCnt ] ;
char b1 [ bufByteCnt ] ;
isEqualRef = true ;
2019-12-26 02:44:14 +00:00
if ( ( rc = open ( h0 , fn0 , kReadFl ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
goto errLabel ;
2019-12-26 02:44:14 +00:00
if ( ( rc = open ( h1 , fn1 , kReadFl ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
goto errLabel ;
2019-12-26 02:44:14 +00:00
p0 = _handleToPtr ( h0 ) ;
p1 = _handleToPtr ( h1 ) ;
2019-12-19 03:24:12 +00:00
while ( 1 )
{
size_t n0 = fread ( b0 , 1 , bufByteCnt , p0 - > fp ) ;
size_t n1 = fread ( b1 , 1 , bufByteCnt , p1 - > fp ) ;
if ( n0 ! = n1 | | memcmp ( b0 , b1 , n0 ) ! = 0 )
{
isEqualRef = false ;
break ;
}
if ( n0 ! = bufByteCnt | | n1 ! = bufByteCnt )
break ;
}
errLabel :
2019-12-26 02:44:14 +00:00
close ( h0 ) ;
close ( h1 ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2019-12-26 02:44:14 +00:00
const char * cw : : file : : name ( handle_t h )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
return p - > fnStr ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : fnWrite ( const char * fn , const void * buf , unsigned bufByteCnt )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
handle_t h ;
2019-12-19 03:24:12 +00:00
rc_t rc ;
2019-12-26 02:44:14 +00:00
if ( ( rc = open ( h , fn , kWriteFl ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
goto errLabel ;
2019-12-26 02:44:14 +00:00
rc = write ( h , buf , bufByteCnt ) ;
2019-12-19 03:24:12 +00:00
errLabel :
2019-12-26 02:44:14 +00:00
close ( h ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : copy (
2019-12-19 03:24:12 +00:00
const char * srcDir ,
const char * srcFn ,
const char * srcExt ,
const char * dstDir ,
const char * dstFn ,
const char * dstExt )
{
rc_t rc = kOkRC ;
unsigned byteCnt = 0 ;
char * buf = nullptr ;
char * srcPathFn = nullptr ;
char * dstPathFn = nullptr ;
// form the source path fn
2019-12-28 02:51:28 +00:00
if ( ( srcPathFn = filesys : : makeFn ( srcDir , srcFn , srcExt , nullptr ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpFailRC , " The soure file name for dir:%s name:%s ext:%s could not be formed. " , cwStringNullGuard ( srcDir ) , cwStringNullGuard ( srcFn ) , cwStringNullGuard ( srcExt ) ) ;
goto errLabel ;
}
// form the dest path fn
2019-12-28 02:51:28 +00:00
if ( ( dstPathFn = filesys : : makeFn ( dstDir , dstFn , dstExt , nullptr ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpFailRC , " The destination file name for dir:%s name:%s ext:%s could not be formed. " , cwStringNullGuard ( dstDir ) , cwStringNullGuard ( dstFn ) , cwStringNullGuard ( dstExt ) ) ;
goto errLabel ;
}
// verify that the source exists
2019-12-28 02:51:28 +00:00
if ( filesys : : isFile ( srcPathFn ) = = false )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpenFailRC , " The source file '%s' does not exist. " , cwStringNullGuard ( srcPathFn ) ) ;
goto errLabel ;
}
// read the source file into a buffer
2019-12-26 02:44:14 +00:00
if ( ( buf = fnToBuf ( srcPathFn , & byteCnt ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
rc = cwLogError ( kReadFailRC , " Attempt to fill a buffer from '%s' failed. " , cwStringNullGuard ( srcPathFn ) ) ;
else
{
// write the file to the output file
2019-12-26 02:44:14 +00:00
if ( fnWrite ( dstPathFn , buf , byteCnt ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
rc = cwLogError ( kWriteFailRC , " An attempt to write a buffer to '%s' failed. " , cwStringNullGuard ( dstPathFn ) ) ;
}
errLabel :
// free the buffer
2019-12-28 02:51:28 +00:00
mem : : release ( buf ) ;
mem : : release ( srcPathFn ) ;
mem : : release ( dstPathFn ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2023-03-17 21:41:04 +00:00
cw : : rc_t cw : : file : : backup ( const char * dir , const char * name , const char * ext , const char * dst0_dir )
2019-12-19 03:24:12 +00:00
{
2023-03-17 21:41:04 +00:00
rc_t rc = kOkRC ;
char * newName = nullptr ;
char * newFn = nullptr ;
unsigned n = 0 ;
char * srcFn = nullptr ;
2019-12-28 02:51:28 +00:00
filesys : : pathPart_t * pp = nullptr ;
2023-03-17 21:41:04 +00:00
const char * dst_dir = nullptr ;
char * dst_base_dir = nullptr ;
2019-12-19 03:24:12 +00:00
2023-03-17 21:41:04 +00:00
// expand the destination path
if ( dst0_dir ! = nullptr )
{
if ( ( dst_base_dir = filesys : : expandPath ( dst0_dir ) ) = = nullptr )
{
rc = cwLogError ( kOpFailRC , " The backup dest directory '%s' could not be expanded. " ) ;
goto errLabel ;
}
dst_dir = dst_base_dir ;
}
// form the name of the backup file to backup
2019-12-28 02:51:28 +00:00
if ( ( srcFn = filesys : : makeFn ( dir , name , ext , nullptr ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpFailRC , " Backup source file name formation failed. " ) ;
goto errLabel ;
}
// if the src file does not exist then there is nothing to do
2019-12-28 02:51:28 +00:00
if ( filesys : : isFile ( srcFn ) = = false )
2019-12-19 03:24:12 +00:00
return rc ;
// break the source file name up into dir/fn/ext.
2019-12-28 02:51:28 +00:00
if ( ( pp = filesys : : pathParts ( srcFn ) ) = = nullptr | | pp - > fnStr = = nullptr )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpFailRC , " The file name '%s' could not be parsed into its parts. " , cwStringNullGuard ( srcFn ) ) ;
goto errLabel ;
}
2022-12-17 13:14:40 +00:00
if ( dst_dir = = nullptr )
dst_dir = pp - > dirStr ;
2019-12-19 03:24:12 +00:00
// iterate until a unique file name is found
for ( n = 0 ; 1 ; + + n )
{
2019-12-28 02:51:28 +00:00
mem : : release ( newFn ) ;
2019-12-19 03:24:12 +00:00
// generate a new file name
2019-12-28 02:51:28 +00:00
newName = mem : : printf ( newName , " %s_%i " , pp - > fnStr , n ) ;
2019-12-19 03:24:12 +00:00
// form the new file name into a complete path
2022-12-17 13:14:40 +00:00
if ( ( newFn = filesys : : makeFn ( dst_dir , newName , pp - > extStr , nullptr ) ) = = nullptr )
2019-12-19 03:24:12 +00:00
{
rc = cwLogError ( kOpFailRC , " A backup file name could not be formed for the file '%s'. " , cwStringNullGuard ( newName ) ) ;
goto errLabel ;
}
// if the new file name is not already in use ...
2019-12-28 02:51:28 +00:00
if ( filesys : : isFile ( newFn ) = = false )
2019-12-19 03:24:12 +00:00
{
// .. then duplicate the file
2019-12-26 02:44:14 +00:00
if ( ( rc = copy ( srcFn , nullptr , nullptr , newFn , nullptr , nullptr ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
rc = cwLogError ( rc , " The file '%s' could not be duplicated as '%s'. " , cwStringNullGuard ( srcFn ) , cwStringNullGuard ( newFn ) ) ;
break ;
}
}
errLabel :
2023-03-17 21:41:04 +00:00
mem : : release ( dst_base_dir ) ;
2019-12-28 02:51:28 +00:00
mem : : release ( srcFn ) ;
mem : : release ( newFn ) ;
mem : : release ( newName ) ;
mem : : release ( pp ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2023-03-17 21:41:04 +00:00
cw : : rc_t cw : : file : : backup ( const char * fname , const char * dst_dir )
{
rc_t rc = kOkRC ;
filesys : : pathPart_t * pp = nullptr ;
if ( ( pp = filesys : : pathParts ( fname ) ) = = nullptr )
{
rc = cwLogError ( kInvalidArgRC , " The parts (dir,name,ext) of the file name '%s' could not be parsed. " ) ;
goto errLabel ;
}
rc = backup ( pp - > dirStr , pp - > fnStr , pp - > extStr , dst_dir ) ;
errLabel :
mem : : release ( pp ) ;
return rc ;
}
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
char * cw : : file : : toBuf ( handle_t h , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{ return _fileToBuf ( h , 0 , bufByteCntPtr ) ; }
2019-12-26 02:44:14 +00:00
char * cw : : file : : fnToBuf ( const char * fn , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{ return _fileFnToBuf ( fn , 0 , bufByteCntPtr ) ; }
2019-12-26 02:44:14 +00:00
char * cw : : file : : toStr ( handle_t h , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{ return _fileToBuf ( h , 1 , bufByteCntPtr ) ; }
2019-12-26 02:44:14 +00:00
char * cw : : file : : fnToStr ( const char * fn , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{ return _fileFnToBuf ( fn , 1 , bufByteCntPtr ) ; }
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : lineCount ( handle_t h , unsigned * lineCntPtr )
2019-12-19 03:24:12 +00:00
{
rc_t rc = kOkRC ;
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
unsigned lineCnt = 0 ;
long offs ;
int c ;
cwAssert ( lineCntPtr ! = nullptr ) ;
* lineCntPtr = 0 ;
2019-12-26 02:44:14 +00:00
if ( ( rc = tell ( h , & offs ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
errno = 0 ;
while ( 1 )
{
c = fgetc ( p - > fp ) ;
if ( c = = EOF )
{
if ( errno )
2019-12-26 02:44:14 +00:00
rc = cwLogSysError ( kReadFailRC , errno , " File read char failed on 's'. " , cwStringNullGuard ( name ( h ) ) ) ;
2019-12-19 03:24:12 +00:00
else
+ + lineCnt ; // add one in case the last line isn't terminated with a '\n'.
break ;
}
// if an end-of-line was encountered
if ( c = = ' \n ' )
+ + lineCnt ;
}
2019-12-26 02:44:14 +00:00
if ( ( rc = seek ( h , kBeginFl , offs ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
* lineCntPtr = lineCnt ;
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : getLine ( handle_t h , char * buf , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{
cwAssert ( bufByteCntPtr ! = nullptr ) ;
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
unsigned tn = 128 ;
char t [ tn ] ;
unsigned on = * bufByteCntPtr ;
long offs ;
rc_t rc ;
// store the current file offset
2019-12-26 02:44:14 +00:00
if ( ( rc = tell ( h , & offs ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
// if no buffer was given then use t[]
if ( buf = = nullptr | | * bufByteCntPtr = = 0 )
{
* bufByteCntPtr = tn ;
buf = t ;
}
// fill the buffer from the current line
if ( ( rc = _fileGetLine ( p , buf , bufByteCntPtr ) ) ! = kOkRC )
return rc ;
// get length of the string in the buffer
// (this is one less than the count of bytes written to the buffer)
unsigned n = strlen ( buf ) ;
// if the provided buffer was large enough to read the entire string
if ( on > n + 1 )
{
//*bufByteCntPtr = n+1;
return kOkRC ;
}
//
// the provided buffer was not large enough
//
// m tracks the length of the string
unsigned m = n ;
while ( n + 1 = = * bufByteCntPtr )
{
// fill the buffer from the current line
if ( ( rc = _fileGetLine ( p , buf , bufByteCntPtr ) ) ! = kOkRC )
return rc ;
n = strlen ( buf ) ;
m + = n ;
}
// restore the original file offset
2019-12-26 02:44:14 +00:00
if ( ( rc = seek ( h , kBeginFl , offs ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
// add 1 for /0, 1 for /n and 1 to detect buf-too-short
* bufByteCntPtr = m + 3 ;
return kBufTooSmallRC ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : getLineAuto ( handle_t h , char * * bufPtrPtr , unsigned * bufByteCntPtr )
2019-12-19 03:24:12 +00:00
{
rc_t rc = kOkRC ;
bool fl = true ;
char * buf = * bufPtrPtr ;
* bufPtrPtr = nullptr ;
while ( fl )
{
fl = false ;
2019-12-26 02:44:14 +00:00
switch ( rc = getLine ( h , buf , bufByteCntPtr ) )
2019-12-19 03:24:12 +00:00
{
case kOkRC :
{
* bufPtrPtr = buf ;
}
break ;
case kBufTooSmallRC :
2019-12-28 02:51:28 +00:00
buf = mem : : resizeZ < char > ( buf , * bufByteCntPtr ) ;
2019-12-19 03:24:12 +00:00
fl = true ;
break ;
default :
2019-12-28 02:51:28 +00:00
mem : : release ( buf ) ;
2019-12-19 03:24:12 +00:00
break ;
}
}
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readChar ( handle_t h , char * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readUChar ( handle_t h , unsigned char * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readShort ( handle_t h , short * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readUShort ( handle_t h , unsigned short * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readLong ( handle_t h , long * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readULong ( handle_t h , unsigned long * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readInt ( handle_t h , int * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readUInt ( handle_t h , unsigned int * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readFloat ( handle_t h , float * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readDouble ( handle_t h , double * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readBool ( handle_t h , bool * buf , unsigned cnt )
{ return read ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeChar ( handle_t h , const char * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeUChar ( handle_t h , const unsigned char * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeShort ( handle_t h , const short * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeUShort ( handle_t h , const unsigned short * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeLong ( handle_t h , const long * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeULong ( handle_t h , const unsigned long * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeInt ( handle_t h , const int * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeUInt ( handle_t h , const unsigned int * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeFloat ( handle_t h , const float * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeDouble ( handle_t h , const double * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeBool ( handle_t h , const bool * buf , unsigned cnt )
{ return write ( h , buf , sizeof ( buf [ 0 ] ) * cnt ) ; }
2019-12-19 03:24:12 +00:00
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : writeStr ( handle_t h , const char * s )
2019-12-19 03:24:12 +00:00
{
rc_t rc ;
unsigned n = textLength ( s ) ;
2019-12-26 02:44:14 +00:00
if ( ( rc = writeUInt ( h , & n , 1 ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
if ( n > 0 )
2019-12-26 02:44:14 +00:00
rc = writeChar ( h , s , n ) ;
2019-12-19 03:24:12 +00:00
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : readStr ( handle_t h , char * * sRef , unsigned maxCharN )
2019-12-19 03:24:12 +00:00
{
unsigned n ;
rc_t rc ;
cwAssert ( sRef ! = nullptr ) ;
* sRef = nullptr ;
if ( maxCharN = = 0 )
maxCharN = 16384 ;
// read the string length
2019-12-26 02:44:14 +00:00
if ( ( rc = readUInt ( h , & n , 1 ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
// verify that string isn't too long
if ( n > maxCharN )
{
return cwLogError ( kInvalidArgRC , " The stored string is larger than the maximum allowable size of %i. " , maxCharN ) ;
}
// allocate a read buffer
2019-12-28 02:51:28 +00:00
char * s = mem : : allocZ < char > ( n + 1 ) ;
2019-12-19 03:24:12 +00:00
// fill the buffer from the file
2019-12-26 02:44:14 +00:00
if ( ( rc = readChar ( h , s , n ) ) ! = kOkRC )
2019-12-19 03:24:12 +00:00
return rc ;
s [ n ] = 0 ; // terminate the string
* sRef = s ;
return rc ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : print ( handle_t h , const char * text )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
errno = 0 ;
if ( fputs ( text , p - > fp ) < 0 )
2020-12-29 15:09:43 +00:00
return p - > lastRC = cwLogSysError ( kOpFailRC , errno , " File print failed on '%s'. " , cwStringNullGuard ( name ( h ) ) ) ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : vPrintf ( handle_t h , const char * fmt , va_list vl )
2019-12-19 03:24:12 +00:00
{
2019-12-26 02:44:14 +00:00
this_t * p = _handleToPtr ( h ) ;
2019-12-19 03:24:12 +00:00
if ( vfprintf ( p - > fp , fmt , vl ) < 0 )
2020-12-29 15:09:43 +00:00
return p - > lastRC = cwLogSysError ( kOpFailRC , errno , " File print failed on '%s'. " , cwStringNullGuard ( name ( h ) ) ) ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
2019-12-26 02:44:14 +00:00
cw : : rc_t cw : : file : : printf ( handle_t h , const char * fmt , . . . )
2019-12-19 03:24:12 +00:00
{
va_list vl ;
va_start ( vl , fmt ) ;
2019-12-26 02:44:14 +00:00
rc_t rc = vPrintf ( h , fmt , vl ) ;
2019-12-19 03:24:12 +00:00
va_end ( vl ) ;
return rc ;
}