Files
harbour-core/contrib/hbmemio/memio.c
Przemysław Czerpak fbe077d628 2017-09-26 14:54 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* contrib/hbmemio/memio.c
    ! fixed FO_TRUNC attribute in MEM: file IO - thanks to Miroslav Georgiev
      for information about the problem

  * include/hbgtinfo.ch
  * src/rtl/gtwvt/gtwvt.h
  * src/rtl/gtwvt/gtwvt.c
    + added new hb_gtInfo() action HB_GTI_SYSMENUADD
      It allows to add new items to window system menu which
      selected add defined by user key code into keyboard queue, i.e.
         hb_gtInfo( HB_GTI_SYSMENUADD, HB_K_MENU, "Settings" )
    * In WinCE builds use DeleteMenu() + AppendMenu() instead of
      missing ModifyMenu()
    ! pacified warning in non UNICODE builds
2017-09-26 14:54:59 +02:00

1188 lines
30 KiB
C

/*
* Memory file system
* I/O driver for Memory file system
*
* Copyright 2009 Mindaugas Kavaliauskas <dbtopas at dbtopas.lt>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/* this has to be declared before hbapifs.h is included */
#define _HB_FILE_IMPLEMENTATION_
#include "hbapi.h"
#include "hbapifs.h"
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbthread.h"
#include "hbvm.h"
#include "hbinit.h"
#include "directry.ch"
/* -- Memory file system --- */
/* change this define for public hb_memfs*() API */
#ifdef HB_MEMFS_PUBLIC_API
#define HB_MEMFS_EXPORT
#else
#define HB_MEMFS_EXPORT static
#endif
#define HB_MEMFS_INITSIZE 16
/* File access flags */
#define FOX_READ 1
#define FOX_WRITE 2
#define FOX_READWRITE 3
/* File sharing flags */
#define FOX_DENYNONE 0
#define FOX_DENYREAD 16
#define FOX_DENYWRITE 32
#define FOX_EXCLUSIVE 48
#define FOX_DENYFLAGS 48
typedef struct _HB_MEMFS_INODE
{
HB_FOFFSET llSize;
HB_FOFFSET llAlloc;
char * pData;
char * szName;
unsigned int uiCount;
unsigned int uiCountRead, uiCountWrite;
HB_USHORT uiDeny;
} HB_MEMFS_INODE, * PHB_MEMFS_INODE;
typedef struct _HB_MEMFS_FILE
{
PHB_MEMFS_INODE pInode;
HB_FOFFSET llPos;
HB_USHORT uiFlags;
} HB_MEMFS_FILE, * PHB_MEMFS_FILE;
typedef struct _HB_MEMFS_FS
{
HB_ULONG ulInodeCount;
HB_ULONG ulInodeAlloc;
PHB_MEMFS_INODE * pInodes;
HB_ULONG ulFileAlloc;
HB_ULONG ulFileLast;
PHB_MEMFS_FILE * pFiles;
} HB_MEMFS_FS, * PHB_MEMFS_FS;
typedef struct _HB_MEMFS_DIRENTRY
{
char * szName;
HB_FOFFSET llSize;
} HB_MEMFS_DIRENTRY, * PHB_MEMFS_DIRENTRY;
static HB_MEMFS_FS s_fs;
static HB_ERRCODE s_error;
static HB_CRITICAL_NEW( s_mtx );
#define HB_MEMFSMT_LOCK() hb_threadEnterCriticalSection( &s_mtx )
#define HB_MEMFSMT_UNLOCK() hb_threadLeaveCriticalSection( &s_mtx )
static void memfsInodeFree( PHB_MEMFS_INODE pInode );
static void memfsExit( void * cargo )
{
HB_ULONG ul;
HB_SYMBOL_UNUSED( cargo );
for( ul = 0; ul < s_fs.ulFileAlloc; ul++ )
{
if( s_fs.pFiles[ ul ] )
hb_xfree( s_fs.pFiles[ ul ] );
}
hb_xfree( s_fs.pFiles );
for( ul = 0; ul < s_fs.ulInodeCount; ul++ )
{
memfsInodeFree( s_fs.pInodes[ ul ] );
}
hb_xfree( s_fs.pInodes );
}
static void memfsInit( void )
{
#if 0
HB_CRITICAL_INIT( s_mtx );
#endif
s_error = 0;
s_fs.ulInodeCount = 0;
s_fs.ulInodeAlloc = HB_MEMFS_INITSIZE;
s_fs.pInodes = ( PHB_MEMFS_INODE * ) hb_xgrab( sizeof( PHB_MEMFS_INODE ) * s_fs.ulInodeAlloc );
s_fs.ulFileAlloc = HB_MEMFS_INITSIZE;
s_fs.pFiles = ( PHB_MEMFS_FILE * ) hb_xgrab( sizeof( PHB_MEMFS_FILE ) * s_fs.ulFileAlloc );
memset( s_fs.pFiles, 0, sizeof( PHB_MEMFS_FILE ) * s_fs.ulFileAlloc );
s_fs.ulFileLast = 0;
hb_vmAtQuit( memfsExit, NULL );
}
/* Note: returns 1 based index! */
static HB_ULONG memfsInodeFind( const char * szName, HB_ULONG * pulPos )
{
HB_ULONG ulLeft, ulRight;
ulLeft = 0;
ulRight = s_fs.ulInodeCount;
while( ulLeft < ulRight )
{
HB_ULONG ulMiddle;
int i;
ulMiddle = ( ulLeft + ulRight ) >> 1;
i = strcmp( szName, s_fs.pInodes[ ulMiddle ]->szName );
if( i == 0 )
return ulMiddle + 1;
else if( i < 0 )
ulRight = ulMiddle;
else
ulLeft = ulMiddle + 1;
}
if( pulPos )
*pulPos = ulLeft;
return 0;
}
static PHB_MEMFS_INODE memfsInodeAlloc( const char * szName )
{
PHB_MEMFS_INODE pInode = ( PHB_MEMFS_INODE ) hb_xgrab( sizeof( HB_MEMFS_INODE ) );
HB_ULONG ulInode = 0;
pInode->llSize = 0;
pInode->llAlloc = HB_MEMFS_INITSIZE;
pInode->pData = ( char * ) hb_xgrab( ( HB_ULONG ) pInode->llAlloc );
memset( pInode->pData, 0, ( HB_SIZE ) pInode->llAlloc );
pInode->szName = hb_strdup( szName );
pInode->uiCount = 1;
pInode->uiCountRead = pInode->uiCountWrite = 0;
pInode->uiDeny = 0;
/* Insert into inode array. Inode should not exist!!! */
if( s_fs.ulInodeCount >= s_fs.ulInodeAlloc )
{
s_fs.ulInodeAlloc += s_fs.ulInodeAlloc >> 1;
s_fs.pInodes = ( PHB_MEMFS_INODE * ) hb_xrealloc( s_fs.pInodes, s_fs.ulInodeAlloc * sizeof( PHB_MEMFS_INODE ) );
}
if( memfsInodeFind( szName, &ulInode ) )
{
hb_errInternal( 9999, "memfsInodeAlloc: Inode already exists", NULL, NULL );
return NULL;
}
if( ulInode < s_fs.ulInodeCount )
{
memmove( s_fs.pInodes + ulInode + 1, s_fs.pInodes + ulInode, ( s_fs.ulInodeCount - ulInode ) * sizeof( PHB_MEMFS_INODE ) );
}
s_fs.pInodes[ ulInode ] = pInode;
s_fs.ulInodeCount++;
return pInode;
}
static void memfsInodeFree( PHB_MEMFS_INODE pInode )
{
hb_xfree( pInode->pData );
hb_xfree( pInode->szName );
hb_xfree( pInode );
}
static PHB_MEMFS_FILE memfsFileAlloc( PHB_MEMFS_INODE pInode )
{
PHB_MEMFS_FILE pFile = ( PHB_MEMFS_FILE ) hb_xgrab( sizeof( HB_MEMFS_FILE ) );
pFile->pInode = pInode;
pFile->llPos = 0;
pInode->uiCount++;
return pFile;
}
static PHB_MEMFS_FILE memfsHandleToFile( HB_FHANDLE hFile )
{
if( hFile == FS_ERROR || ( HB_ULONG ) hFile == 0 || ( HB_ULONG ) hFile > s_fs.ulFileAlloc || s_fs.pFiles[ ( HB_ULONG ) hFile - 1 ] == NULL )
{
#if 0
hb_errInternal( 9999, "memfsHandleToFile: Invalid file handle", NULL, NULL );
#endif
return NULL;
}
else
return s_fs.pFiles[ ( HB_ULONG ) hFile - 1 ];
}
static HB_FHANDLE memfsHandleAlloc( PHB_MEMFS_FILE pFile )
{
HB_ULONG ul;
/* This allocation will help to avoid reallocation of just released file handle. */
for( ul = s_fs.ulFileLast; ul < s_fs.ulFileAlloc; ul++ )
{
if( ! s_fs.pFiles[ ul ] )
{
s_fs.pFiles[ ul ] = pFile;
s_fs.ulFileLast = ul + 1;
return ( HB_FHANDLE ) ( ul + 1 );
}
}
for( ul = 0; ul < s_fs.ulFileLast; ul++ )
{
if( ! s_fs.pFiles[ ul ] )
{
s_fs.pFiles[ ul ] = pFile;
s_fs.ulFileLast = ul + 1;
return ( HB_FHANDLE ) ( ul + 1 );
}
}
s_fs.pFiles = ( PHB_MEMFS_FILE * ) hb_xrealloc( s_fs.pFiles, ( s_fs.ulFileAlloc << 1 ) * sizeof( PHB_MEMFS_FILE ) );
memset( s_fs.pFiles + s_fs.ulFileAlloc, 0, s_fs.ulFileAlloc * sizeof( PHB_MEMFS_FILE ) );
ul = s_fs.ulFileAlloc;
s_fs.ulFileAlloc <<= 1;
s_fs.pFiles[ ul ] = pFile;
s_fs.ulFileLast = ul + 1;
return ( HB_FHANDLE ) ( ul + 1 );
}
/* --- Public Memory FS functions --- */
HB_MEMFS_EXPORT HB_ERRCODE hb_memfsError( void )
{
return s_error;
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsFileExists( const char * szName )
{
HB_BOOL bRet;
HB_MEMFSMT_LOCK();
bRet = memfsInodeFind( szName, NULL ) != 0;
HB_MEMFSMT_UNLOCK();
return bRet;
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsDelete( const char * szName )
{
PHB_MEMFS_INODE pInode;
HB_ULONG ulFile;
HB_MEMFSMT_LOCK();
if( ( ulFile = memfsInodeFind( szName, NULL ) ) == 0 )
{
HB_MEMFSMT_UNLOCK();
return HB_FALSE;
}
pInode = s_fs.pInodes[ ulFile - 1 ];
if( ulFile < s_fs.ulInodeCount )
memmove( s_fs.pInodes + ulFile - 1, s_fs.pInodes + ulFile, ( s_fs.ulInodeCount - ulFile ) * sizeof( PHB_MEMFS_INODE ) );
s_fs.ulInodeCount--;
if( --pInode->uiCount == 0 )
memfsInodeFree( pInode );
HB_MEMFSMT_UNLOCK();
return HB_TRUE;
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsRename( const char * szName, const char * szNewName )
{
HB_ULONG ulInode;
HB_MEMFSMT_LOCK();
if( ( ulInode = memfsInodeFind( szName, NULL ) ) == 0 )
{
HB_MEMFSMT_UNLOCK();
/* File not found */
return HB_FALSE;
}
if( memfsInodeFind( szNewName, NULL ) )
{
HB_MEMFSMT_UNLOCK();
/* File already exists */
return HB_FALSE;
}
hb_xfree( s_fs.pInodes[ ulInode - 1 ]->szName );
s_fs.pInodes[ ulInode - 1 ]->szName = hb_strdup( szNewName );
HB_MEMFSMT_UNLOCK();
return HB_TRUE;
}
HB_MEMFS_EXPORT PHB_ITEM hb_memfsDirectory( const char * pszDirSpec, const char * pszAttr )
{
PHB_MEMFS_DIRENTRY pDirEn = NULL;
char * pszFree = NULL;
PHB_ITEM pDirArray;
HB_SIZE nLen;
HB_ULONG ulCount, ul;
HB_SYMBOL_UNUSED( pszAttr );
if( pszDirSpec && *pszDirSpec )
{
nLen = strlen( pszDirSpec ) - 1;
if( pszDirSpec[ nLen ] == HB_OS_PATH_DELIM_CHR )
{
if( nLen == 0 )
pszDirSpec = HB_OS_ALLFILE_MASK;
else
pszDirSpec = pszFree = hb_xstrcpy( NULL, pszDirSpec, HB_OS_ALLFILE_MASK, NULL );
}
}
else
pszDirSpec = HB_OS_ALLFILE_MASK;
HB_MEMFSMT_LOCK();
ulCount = s_fs.ulInodeCount;
nLen = 0;
if( ulCount )
{
pDirEn = ( PHB_MEMFS_DIRENTRY ) hb_xgrab( ulCount * sizeof( HB_MEMFS_DIRENTRY ) );
for( ul = 0; ul < ulCount; ul++ )
{
if( hb_strMatchFile( s_fs.pInodes[ ul ]->szName, pszDirSpec ) )
{
pDirEn[ nLen ].szName = hb_strdup( s_fs.pInodes[ ul ]->szName );
pDirEn[ nLen ].llSize = s_fs.pInodes[ ul ]->llSize;
nLen++;
}
}
}
HB_MEMFSMT_UNLOCK();
pDirArray = hb_itemArrayNew( nLen );
for( ul = 0; ( HB_SIZE ) ul < nLen; ul++ )
{
PHB_ITEM pSubarray = hb_arrayGetItemPtr( pDirArray, ul + 1 );
hb_arrayNew ( pSubarray, F_LEN );
hb_arraySetCPtr( pSubarray, F_NAME, pDirEn[ ul ].szName );
hb_arraySetNInt( pSubarray, F_SIZE, pDirEn[ ul ].llSize );
hb_arraySetDL ( pSubarray, F_DATE, 0 );
hb_arraySetC ( pSubarray, F_TIME, "00:00:00" );
hb_arraySetC ( pSubarray, F_ATTR, "" );
}
if( pDirEn )
hb_xfree( pDirEn );
if( pszFree )
hb_xfree( pszFree );
return pDirArray;
}
HB_MEMFS_EXPORT HB_FHANDLE hb_memfsOpen( const char * szName, HB_USHORT uiFlags )
{
PHB_MEMFS_FILE pFile = NULL;
HB_FHANDLE hFile;
HB_ULONG ulInode;
HB_ERRCODE uiError = 0;
/*
Recalculate flags. Bit should indicate feature: 1=read, 2=write, 16=denyread, 32=denywrite.
So, 3=readwrite, 48=exclusive.
Compatibility mode == DenyNone.
*/
uiFlags = ( uiFlags & ( FO_CREAT | FO_TRUNC | FO_EXCL ) ) |
( uiFlags & FO_READWRITE ? FOX_READWRITE : ( uiFlags & FO_WRITE ? FOX_WRITE : FOX_READ ) ) |
( ( uiFlags & 0xf0 ) == FO_EXCLUSIVE ? FOX_EXCLUSIVE :
( ( uiFlags & 0xf0 ) == FO_DENYWRITE ? FOX_DENYWRITE :
( ( uiFlags & 0xf0 ) == FO_DENYREAD ? FOX_DENYREAD : FOX_DENYNONE ) ) );
HB_MEMFSMT_LOCK();
ulInode = memfsInodeFind( szName, NULL );
if( uiFlags & FO_CREAT )
{
if( uiFlags & FO_EXCL )
{
/* create new */
if( ulInode )
uiError = 80;
}
else if( uiFlags & FO_TRUNC )
{
/* create always */
if( ulInode && s_fs.pInodes[ ulInode - 1 ]->uiDeny & FOX_DENYWRITE )
uiError = 32;
}
else
{
/* open always */
/* Do nothing */
}
}
else if( uiFlags & FO_TRUNC )
{
/* truncate existing */
if( ulInode )
{
if( s_fs.pInodes[ ulInode - 1 ]->uiDeny & FOX_DENYWRITE )
uiError = 32;
}
else
uiError = 2;
}
else
{
/* open existing */
if( ! ulInode )
uiError = 2;
}
if( ! uiError )
{
if( ulInode )
{
if( ( uiFlags & FOX_READ && s_fs.pInodes[ ulInode - 1 ]->uiDeny & FOX_DENYREAD ) ||
( uiFlags & FOX_WRITE && s_fs.pInodes[ ulInode - 1 ]->uiDeny & FOX_DENYWRITE ) ||
s_fs.pInodes[ ulInode - 1 ]->uiDeny & uiFlags )
uiError = 32;
else
pFile = memfsFileAlloc( s_fs.pInodes[ ulInode - 1 ] );
}
else
pFile = memfsFileAlloc( memfsInodeAlloc( szName ) );
}
s_error = uiError;
if( pFile )
{
if( uiFlags & FO_TRUNC )
{
pFile->pInode->llSize = 0;
if( pFile->pInode->llAlloc != HB_MEMFS_INITSIZE )
{
pFile->pInode->llAlloc = HB_MEMFS_INITSIZE;
hb_xfree( pFile->pInode->pData );
pFile->pInode->pData = ( char * ) hb_xgrab( ( HB_ULONG ) pFile->pInode->llAlloc );
}
memset( pFile->pInode->pData, 0, ( HB_SIZE ) pFile->pInode->llAlloc );
}
pFile->pInode->uiDeny |= uiFlags & FOX_DENYFLAGS;
if( uiFlags & FOX_READ )
pFile->pInode->uiCountRead++;
if( uiFlags & FOX_WRITE )
pFile->pInode->uiCountWrite++;
pFile->uiFlags = uiFlags;
hFile = memfsHandleAlloc( pFile );
}
else
hFile = FS_ERROR;
HB_MEMFSMT_UNLOCK();
return hFile;
}
HB_MEMFS_EXPORT void hb_memfsClose( HB_FHANDLE hFile )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
HB_MEMFSMT_LOCK();
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
{
HB_MEMFSMT_UNLOCK();
return; /* invalid handle */
}
s_fs.pFiles[ hFile - 1 ] = NULL;
pInode = pFile->pInode;
if( --pInode->uiCount == 0 )
{
memfsInodeFree( pInode );
}
else
{
if( pFile->uiFlags & FOX_READ )
pInode->uiCountRead--;
if( pFile->uiFlags & FOX_WRITE )
pInode->uiCountWrite--;
pInode->uiDeny ^= pFile->uiFlags & FOX_DENYFLAGS;
}
HB_MEMFSMT_UNLOCK();
hb_xfree( pFile );
}
HB_MEMFS_EXPORT HB_SIZE hb_memfsReadAt( HB_FHANDLE hFile, void * pBuff, HB_SIZE nCount, HB_FOFFSET llOffset )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
HB_SIZE nRead;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return 0; /* invalid handle */
pInode = pFile->pInode;
if( ( pFile->uiFlags & FOX_READ ) == 0 )
return 0; /* access denied */
if( llOffset < 0 || pInode->llSize <= llOffset )
return 0;
HB_MEMFSMT_LOCK();
if( pInode->llSize >= llOffset + ( HB_FOFFSET ) nCount )
nRead = nCount;
else
nRead = ( HB_SIZE ) ( pInode->llSize - llOffset );
memcpy( pBuff, pInode->pData + ( HB_SIZE ) llOffset, nRead );
HB_MEMFSMT_UNLOCK();
pFile->llPos = llOffset + ( HB_FOFFSET ) nCount;
return nRead;
}
HB_MEMFS_EXPORT HB_SIZE hb_memfsWriteAt( HB_FHANDLE hFile, const void * pBuff, HB_SIZE nCount, HB_FOFFSET llOffset )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return 0; /* invalid handle */
pInode = pFile->pInode;
if( ( pFile->uiFlags & FOX_WRITE ) == 0 )
return 0; /* access denied */
if( llOffset < 0 )
return 0;
HB_MEMFSMT_LOCK();
/* Reallocate if neccesary */
if( pInode->llAlloc < llOffset + ( HB_FOFFSET ) nCount )
{
HB_FOFFSET llNewAlloc = pInode->llAlloc + ( pInode->llAlloc >> 1 );
if( llNewAlloc < llOffset + ( HB_FOFFSET ) nCount )
llNewAlloc = llOffset + ( HB_FOFFSET ) nCount;
pInode->pData = ( char * ) hb_xrealloc( pInode->pData, ( HB_SIZE ) llNewAlloc );
memset( pInode->pData + ( HB_SIZE ) pInode->llAlloc, 0, ( HB_SIZE ) ( llNewAlloc - pInode->llAlloc ) );
pInode->llAlloc = llNewAlloc;
}
memcpy( pInode->pData + ( HB_SIZE ) llOffset, pBuff, nCount );
if( pInode->llSize < llOffset + ( HB_FOFFSET ) nCount )
pInode->llSize = llOffset + ( HB_FOFFSET ) nCount;
HB_MEMFSMT_UNLOCK();
pFile->llPos = llOffset + ( HB_FOFFSET ) nCount;
return nCount;
}
HB_MEMFS_EXPORT HB_SIZE hb_memfsRead( HB_FHANDLE hFile, void * pBuff, HB_SIZE nCount )
{
PHB_MEMFS_FILE pFile;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return 0; /* invalid handle */
return hb_memfsReadAt( hFile, pBuff, nCount, pFile->llPos );
}
HB_MEMFS_EXPORT HB_SIZE hb_memfsWrite( HB_FHANDLE hFile, const void * pBuff, HB_SIZE nCount )
{
PHB_MEMFS_FILE pFile;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return 0; /* invalid handle */
return hb_memfsWriteAt( hFile, pBuff, nCount, pFile->llPos );
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsTruncAt( HB_FHANDLE hFile, HB_FOFFSET llOffset )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return HB_FALSE; /* invalid handle */
pInode = pFile->pInode;
if( ( pFile->uiFlags & FOX_WRITE ) == 0 )
return HB_FALSE; /* access denied */
if( llOffset < 0 )
return HB_FALSE;
HB_MEMFSMT_LOCK();
/* Reallocate if neccesary */
if( pInode->llAlloc < llOffset )
{
HB_FOFFSET llNewAlloc = pInode->llAlloc + ( pInode->llAlloc >> 1 );
if( llNewAlloc < llOffset )
llNewAlloc = llOffset;
pInode->pData = ( char * ) hb_xrealloc( pInode->pData, ( HB_SIZE ) llNewAlloc );
memset( pInode->pData + ( HB_SIZE ) pInode->llAlloc, 0, ( HB_SIZE ) ( llNewAlloc - pInode->llAlloc ) );
pInode->llAlloc = llNewAlloc;
}
else if( ( pInode->llAlloc >> 2 ) > ( llOffset > HB_MEMFS_INITSIZE ? llOffset : HB_MEMFS_INITSIZE ) )
{
pInode->llAlloc = ( llOffset > HB_MEMFS_INITSIZE ? llOffset : HB_MEMFS_INITSIZE );
pInode->pData = ( char * ) hb_xrealloc( pInode->pData, ( HB_SIZE ) pInode->llAlloc );
}
memset( pInode->pData + ( HB_SIZE ) llOffset, 0, ( HB_SIZE ) ( pInode->llAlloc - llOffset ) );
pInode->llSize = llOffset;
HB_MEMFSMT_UNLOCK();
return HB_TRUE;
}
HB_MEMFS_EXPORT HB_FOFFSET hb_memfsSeek( HB_FHANDLE hFile, HB_FOFFSET llOffset, HB_USHORT uiFlags )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
HB_FOFFSET llPos;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return 0; /* invalid handle */
pInode = pFile->pInode;
HB_MEMFSMT_LOCK();
if( uiFlags & FS_END )
llPos = pInode->llSize + llOffset;
else if( uiFlags & FS_RELATIVE )
llPos = pFile->llPos + llOffset;
else
llPos = llOffset;
if( llPos < 0 )
llPos = 0;
if( llPos > pInode->llSize )
llPos = pInode->llSize;
HB_MEMFSMT_UNLOCK();
pFile->llPos = llPos;
return llPos;
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsEof( HB_FHANDLE hFile )
{
PHB_MEMFS_FILE pFile;
PHB_MEMFS_INODE pInode;
HB_BOOL fEof;
if( ( pFile = memfsHandleToFile( hFile ) ) == NULL )
return HB_FALSE; /* invalid handle */
pInode = pFile->pInode;
HB_MEMFSMT_LOCK();
fEof = pFile->llPos >= pInode->llSize;
HB_MEMFSMT_UNLOCK();
return fEof;
}
HB_MEMFS_EXPORT void hb_memfsFlush( HB_FHANDLE hFile, HB_BOOL fDirty )
{
HB_SYMBOL_UNUSED( hFile );
HB_SYMBOL_UNUSED( fDirty );
}
HB_MEMFS_EXPORT void hb_memfsCommit( HB_FHANDLE hFile )
{
HB_SYMBOL_UNUSED( hFile );
}
HB_MEMFS_EXPORT HB_BOOL hb_memfsLock( HB_FHANDLE hFile, HB_FOFFSET ulStart, HB_FOFFSET nLength, int iMode )
{
HB_SYMBOL_UNUSED( hFile );
HB_SYMBOL_UNUSED( ulStart );
HB_SYMBOL_UNUSED( nLength );
HB_SYMBOL_UNUSED( iMode );
return HB_TRUE;
}
HB_MEMFS_EXPORT int hb_memfsLockTest( HB_FHANDLE hFile, HB_FOFFSET ulStart, HB_FOFFSET nLength, int iMode )
{
HB_SYMBOL_UNUSED( hFile );
HB_SYMBOL_UNUSED( ulStart );
HB_SYMBOL_UNUSED( nLength );
HB_SYMBOL_UNUSED( iMode );
return 0;
}
/* --- I/O Driver for Memory file system --- */
#define FILE_PREFIX "MEM:"
#define FILE_PREFIX_LEN strlen( FILE_PREFIX )
typedef struct _HB_FILE
{
const HB_FILE_FUNCS * pFuncs;
HB_FHANDLE hFile;
}
HB_FILE;
static PHB_FILE s_fileNew( HB_FHANDLE hFile );
static HB_BOOL s_fileAccept( PHB_FILE_FUNCS pFuncs, const char * pszFileName )
{
HB_SYMBOL_UNUSED( pFuncs );
return hb_strnicmp( pszFileName, FILE_PREFIX, FILE_PREFIX_LEN ) == 0;
}
static HB_BOOL s_fileExists( PHB_FILE_FUNCS pFuncs, const char * pszFileName, char * pRetPath )
{
HB_SYMBOL_UNUSED( pFuncs );
if( hb_memfsFileExists( pszFileName + FILE_PREFIX_LEN ) )
{
/* Warning: return buffer could be the same memory place as filename parameter! */
if( pRetPath && pRetPath != pszFileName )
hb_strncpy( pRetPath, pszFileName, HB_PATH_MAX - 1 );
return HB_TRUE;
}
return HB_FALSE;
}
static HB_BOOL s_fileDelete( PHB_FILE_FUNCS pFuncs, const char * pszFileName )
{
HB_SYMBOL_UNUSED( pFuncs );
return hb_memfsDelete( pszFileName + FILE_PREFIX_LEN );
}
static HB_BOOL s_fileRename( PHB_FILE_FUNCS pFuncs, const char * szName, const char * szNewName )
{
szName += FILE_PREFIX_LEN;
if( s_fileAccept( pFuncs, szNewName ) )
{
szNewName += FILE_PREFIX_LEN;
return hb_memfsRename( szName, szNewName );
}
return HB_FALSE;
}
static HB_BOOL s_fileCopy( PHB_FILE_FUNCS pFuncs, const char * pszSrcFile, const char * pszDstFile )
{
HB_SYMBOL_UNUSED( pFuncs );
/* TODO: optimize it when both points to MEMIO files */
return hb_fsCopy( pszSrcFile, pszDstFile );
}
static HB_BOOL s_fileDirExists( PHB_FILE_FUNCS pFuncs, const char * pszDirName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszDirName );
return HB_FALSE;
}
static HB_BOOL s_fileDirMake( PHB_FILE_FUNCS pFuncs, const char * pszDirName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszDirName );
return HB_FALSE;
}
static HB_BOOL s_fileDirRemove( PHB_FILE_FUNCS pFuncs, const char * pszDirName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszDirName );
return HB_FALSE;
}
static double s_fileDirSpace( PHB_FILE_FUNCS pFuncs, const char * pszDirName, HB_USHORT uiType )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszDirName );
HB_SYMBOL_UNUSED( uiType );
/* TODO: return allocated memory and free memory */
return 0.0;
}
static PHB_ITEM s_fileDirectory( PHB_FILE_FUNCS pFuncs, const char * pszDirSpec, const char * pszAttr )
{
HB_SYMBOL_UNUSED( pFuncs );
return hb_memfsDirectory( pszDirSpec + FILE_PREFIX_LEN, pszAttr );
}
static HB_BOOL s_fileTimeGet( PHB_FILE_FUNCS pFuncs, const char * pszFileName, long * plJulian, long * plMillisec )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszFileName );
HB_SYMBOL_UNUSED( plJulian );
HB_SYMBOL_UNUSED( plMillisec );
return HB_FALSE;
}
static HB_BOOL s_fileTimeSet( PHB_FILE_FUNCS pFuncs, const char * pszFileName, long lJulian, long lMillisec )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszFileName );
HB_SYMBOL_UNUSED( lJulian );
HB_SYMBOL_UNUSED( lMillisec );
return HB_FALSE;
}
static HB_BOOL s_fileAttrGet( PHB_FILE_FUNCS pFuncs, const char * pszFileName, HB_FATTR * pulAttr )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszFileName );
HB_SYMBOL_UNUSED( pulAttr );
return HB_FALSE;
}
static HB_BOOL s_fileAttrSet( PHB_FILE_FUNCS pFuncs, const char * pszFileName, HB_FATTR ulAttr )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszFileName );
HB_SYMBOL_UNUSED( ulAttr );
return HB_FALSE;
}
static HB_BOOL s_fileLink( PHB_FILE_FUNCS pFuncs, const char * pszExisting, const char * pszNewName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszExisting );
HB_SYMBOL_UNUSED( pszNewName );
return HB_FALSE;
}
static HB_BOOL s_fileLinkSym( PHB_FILE_FUNCS pFuncs, const char * pszTarget, const char * pszNewName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszTarget );
HB_SYMBOL_UNUSED( pszNewName );
return HB_FALSE;
}
static char * s_fileLinkRead( PHB_FILE_FUNCS pFuncs, const char * pszFileName )
{
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pszFileName );
return NULL;
}
static PHB_FILE s_fileOpen( PHB_FILE_FUNCS pFuncs, const char * szName,
const char * szDefExt, HB_FATTR nExFlags,
const char * pPaths, PHB_ITEM pError )
{
HB_FHANDLE hFile;
char szNameNew[ HB_PATH_MAX ];
HB_USHORT uiFlags;
HB_SYMBOL_UNUSED( pFuncs );
HB_SYMBOL_UNUSED( pPaths );
HB_SYMBOL_UNUSED( pError );
hb_strncpy( szNameNew, szName + FILE_PREFIX_LEN, HB_PATH_MAX - 1 );
if( szDefExt )
{
HB_SIZE nLen = strlen( szNameNew );
do
{
if( nLen == 0 || strchr( HB_OS_PATH_DELIM_CHR_LIST, szNameNew[ nLen - 1 ] ) )
{
hb_strncat( szNameNew, szDefExt, HB_PATH_MAX - 1 );
break;
}
}
while( szNameNew[ --nLen ] != '.' );
}
uiFlags = nExFlags & 0xff;
if( nExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) )
{
uiFlags |= FO_CREAT;
if( nExFlags & FXO_UNIQUE )
uiFlags |= FO_EXCL;
else if( nExFlags & FXO_TRUNCATE )
uiFlags |= FO_TRUNC;
}
hFile = hb_memfsOpen( szNameNew, uiFlags );
if( hFile != FS_ERROR )
return s_fileNew( hFile );
else
{
if( pError )
{
hb_errPutFileName( pError, szName );
hb_errPutOsCode( pError, hb_memfsError() );
hb_errPutGenCode( pError, ( HB_ERRCODE ) ( ( nExFlags & FXO_TRUNCATE ) ? EG_CREATE : EG_OPEN ) );
}
return NULL;
}
}
static void s_fileClose( PHB_FILE pFile )
{
hb_memfsClose( pFile->hFile );
hb_xfree( pFile );
}
static HB_BOOL s_fileLock( PHB_FILE pFile, HB_FOFFSET ulStart,
HB_FOFFSET nLen, int iType )
{
return hb_memfsLock( pFile->hFile, ulStart, nLen, iType );
}
static int s_fileLockTest( PHB_FILE pFile, HB_FOFFSET ulStart,
HB_FOFFSET nLen, int iType )
{
return hb_memfsLockTest( pFile->hFile, ulStart, nLen, iType );
}
static HB_SIZE s_fileRead( PHB_FILE pFile, void * buffer,
HB_SIZE nSize, HB_MAXINT nTimeout )
{
HB_SYMBOL_UNUSED( nTimeout );
return hb_memfsRead( pFile->hFile, buffer, nSize );
}
static HB_SIZE s_fileWrite( PHB_FILE pFile, const void * buffer,
HB_SIZE nSize, HB_MAXINT nTimeout )
{
HB_SYMBOL_UNUSED( nTimeout );
return hb_memfsWrite( pFile->hFile, buffer, nSize );
}
static HB_SIZE s_fileReadAt( PHB_FILE pFile, void * buffer,
HB_SIZE nSize, HB_FOFFSET llOffset )
{
return hb_memfsReadAt( pFile->hFile, buffer, nSize, llOffset );
}
static HB_SIZE s_fileWriteAt( PHB_FILE pFile, const void * buffer,
HB_SIZE nSize, HB_FOFFSET llOffset )
{
return hb_memfsWriteAt( pFile->hFile, buffer, nSize, llOffset );
}
static HB_BOOL s_fileTruncAt( PHB_FILE pFile, HB_FOFFSET llOffset )
{
return hb_memfsTruncAt( pFile->hFile, llOffset );
}
static HB_FOFFSET s_fileSeek( PHB_FILE pFile, HB_FOFFSET nOffset,
HB_USHORT uiFlags )
{
return hb_memfsSeek( pFile->hFile, nOffset, uiFlags );
}
static HB_FOFFSET s_fileSize( PHB_FILE pFile )
{
return hb_memfsSeek( pFile->hFile, 0, FS_END );
}
static HB_BOOL s_fileEof( PHB_FILE pFile )
{
return hb_memfsEof( pFile->hFile );
}
static void s_fileFlush( PHB_FILE pFile, HB_BOOL fDirty )
{
hb_memfsFlush( pFile->hFile, fDirty );
}
static void s_fileCommit( PHB_FILE pFile )
{
hb_memfsCommit( pFile->hFile );
}
static HB_BOOL s_fileConfigure( PHB_FILE pFile, int iIndex, PHB_ITEM pValue )
{
HB_SYMBOL_UNUSED( pFile );
switch( iIndex )
{
case HB_VF_IONAME:
hb_itemPutC( pValue, FILE_PREFIX );
return HB_TRUE;
}
return HB_FALSE;
}
static HB_FHANDLE s_fileHandle( PHB_FILE pFile )
{
return pFile ? pFile->hFile : FS_ERROR;
}
static const HB_FILE_FUNCS s_fileFuncs =
{
s_fileAccept,
s_fileExists,
s_fileDelete,
s_fileRename,
s_fileCopy,
s_fileDirExists,
s_fileDirMake,
s_fileDirRemove,
s_fileDirSpace,
s_fileDirectory,
s_fileTimeGet,
s_fileTimeSet,
s_fileAttrGet,
s_fileAttrSet,
s_fileLink,
s_fileLinkSym,
s_fileLinkRead,
s_fileOpen,
s_fileClose,
s_fileLock,
s_fileLockTest,
s_fileRead,
s_fileWrite,
s_fileReadAt,
s_fileWriteAt,
s_fileTruncAt,
s_fileSeek,
s_fileSize,
s_fileEof,
s_fileFlush,
s_fileCommit,
s_fileConfigure,
s_fileHandle
};
static PHB_FILE s_fileNew( HB_FHANDLE hFile )
{
PHB_FILE pFile = ( PHB_FILE ) hb_xgrab( sizeof( HB_FILE ) );
pFile->pFuncs = &s_fileFuncs;
pFile->hFile = hFile;
return pFile;
}
HB_FUNC( HB_MEMIO ) { ; }
HB_CALL_ON_STARTUP_BEGIN( _hb_file_memio_init_ )
memfsInit();
hb_fileRegisterFull( &s_fileFuncs );
HB_CALL_ON_STARTUP_END( _hb_file_memio_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup _hb_file_memio_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_file_memio_init_ )
#include "hbiniseg.h"
#endif