Aer/vfs.c

8254 lines
243 KiB
C

/*
* Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
* Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
* Version 2.1.4
* For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
* please contact Symisc Systems via:
* legal@symisc.net
* licensing@symisc.net
* contact@symisc.net
* or visit:
* http://ph7.symisc.net/
*/
/* $SymiscID: vfs.c v2.1 Win7 2012-05-24 01:18 devel <chm@symisc.net> $ */
#include "ph7int.h"
/*
* This file implement a virtual file systems (VFS) for the PH7 engine.
*/
/*
* Given a string containing the path of a file or directory, this function
* return the parent directory's path.
*/
PH7_PRIVATE const char * PH7_ExtractDirName(const char *zPath,int nByte,int *pLen)
{
const char *zEnd = &zPath[nByte - 1];
int c,d;
c = d = '/';
#ifdef __WINNT__
d = '\\';
#endif
while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){
zEnd--;
}
*pLen = (int)(zEnd-zPath);
#ifdef __WINNT__
if( (*pLen) == (int)sizeof(char) && zPath[0] == '/' ){
/* Normalize path on windows */
return "\\";
}
#endif
if( zEnd == zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d) ){
/* No separator,return "." as the current directory */
*pLen = sizeof(char);
return ".";
}
if( (*pLen) == 0 ){
*pLen = sizeof(char);
#ifdef __WINNT__
return "\\";
#else
return "/";
#endif
}
return zPath;
}
/*
* Omit the vfs layer implementation from the built if the PH7_DISABLE_BUILTIN_FUNC directive is defined.
*/
#ifndef PH7_DISABLE_BUILTIN_FUNC
/*
* bool chdir(string $directory)
* Change the current directory.
* Parameters
* $directory
* The new current directory
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_chdir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xChdir == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xChdir(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool chroot(string $directory)
* Change the root directory.
* Parameters
* $directory
* The path to change the root directory to
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_chroot(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xChroot == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xChroot(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* string getcwd(void)
* Gets the current working directory.
* Parameters
* None
* Return
* Returns the current working directory on success, or FALSE on failure.
*/
static int PH7_vfs_getcwd(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
int rc;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xGetcwd == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
ph7_result_string(pCtx,"",0);
/* Perform the requested operation */
rc = pVfs->xGetcwd(pCtx);
if( rc != PH7_OK ){
/* Error,return FALSE */
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* bool rmdir(string $directory)
* Removes directory.
* Parameters
* $directory
* The path to the directory
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_rmdir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xRmdir == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xRmdir(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool is_dir(string $filename)
* Tells whether the given filename is a directory.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_dir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xIsdir == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xIsdir(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool mkdir(string $pathname[,int $mode = 0777 [,bool $recursive = false])
* Make a directory.
* Parameters
* $pathname
* The directory path.
* $mode
* The mode is 0777 by default, which means the widest possible access.
* Note:
* mode is ignored on Windows.
* Note that you probably want to specify the mode as an octal number, which means
* it should have a leading zero. The mode is also modified by the current umask
* which you can change using umask().
* $recursive
* Allows the creation of nested directories specified in the pathname.
* Defaults to FALSE. (Not used)
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_mkdir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int iRecursive = 0;
const char *zPath;
ph7_vfs *pVfs;
int iMode,rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xMkdir == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
#ifdef __WINNT__
iMode = 0;
#else
/* Assume UNIX */
iMode = 0777;
#endif
if( nArg > 1 ){
iMode = ph7_value_to_int(apArg[1]);
if( nArg > 2 ){
iRecursive = ph7_value_to_bool(apArg[2]);
}
}
/* Perform the requested operation */
rc = pVfs->xMkdir(zPath,iMode,iRecursive);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool rename(string $oldname,string $newname)
* Attempts to rename oldname to newname.
* Parameters
* $oldname
* Old name.
* $newname
* New name.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_rename(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zOld,*zNew;
ph7_vfs *pVfs;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xRename == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
zOld = ph7_value_to_string(apArg[0],0);
zNew = ph7_value_to_string(apArg[1],0);
rc = pVfs->xRename(zOld,zNew);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK );
return PH7_OK;
}
/*
* string realpath(string $path)
* Returns canonicalized absolute pathname.
* Parameters
* $path
* Target path.
* Return
* Canonicalized absolute pathname on success. or FALSE on failure.
*/
static int PH7_vfs_realpath(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xRealpath == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Set an empty string untnil the underlying OS interface change that */
ph7_result_string(pCtx,"",0);
/* Perform the requested operation */
zPath = ph7_value_to_string(apArg[0],0);
rc = pVfs->xRealpath(zPath,pCtx);
if( rc != PH7_OK ){
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int sleep(int $seconds)
* Delays the program execution for the given number of seconds.
* Parameters
* $seconds
* Halt time in seconds.
* Return
* Zero on success or FALSE on failure.
*/
static int PH7_vfs_sleep(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
int rc,nSleep;
if( nArg < 1 || !ph7_value_is_int(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xSleep == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Amount to sleep */
nSleep = ph7_value_to_int(apArg[0]);
if( nSleep < 0 ){
/* Invalid value,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation (Microseconds) */
rc = pVfs->xSleep((unsigned int)(nSleep * SX_USEC_PER_SEC));
if( rc != PH7_OK ){
/* Return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return zero */
ph7_result_int(pCtx,0);
}
return PH7_OK;
}
/*
* void usleep(int $micro_seconds)
* Delays program execution for the given number of micro seconds.
* Parameters
* $micro_seconds
* Halt time in micro seconds. A micro second is one millionth of a second.
* Return
* None.
*/
static int PH7_vfs_usleep(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
int nSleep;
if( nArg < 1 || !ph7_value_is_int(apArg[0]) ){
/* Missing/Invalid argument,return immediately */
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xSleep == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
return PH7_OK;
}
/* Amount to sleep */
nSleep = ph7_value_to_int(apArg[0]);
if( nSleep < 0 ){
/* Invalid value,return immediately */
return PH7_OK;
}
/* Perform the requested operation (Microseconds) */
pVfs->xSleep((unsigned int)nSleep);
return PH7_OK;
}
/*
* bool unlink (string $filename)
* Delete a file.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_unlink(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xUnlink == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xUnlink(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool chmod(string $filename,int $mode)
* Attempts to change the mode of the specified file to that given in mode.
* Parameters
* $filename
* Path to the file.
* $mode
* Mode (Must be an integer)
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_chmod(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int iMode;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xChmod == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Extract the mode */
iMode = ph7_value_to_int(apArg[1]);
/* Perform the requested operation */
rc = pVfs->xChmod(zPath,iMode);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool chown(string $filename,string $user)
* Attempts to change the owner of the file filename to user user.
* Parameters
* $filename
* Path to the file.
* $user
* Username.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_chown(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath,*zUser;
ph7_vfs *pVfs;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xChown == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Extract the user */
zUser = ph7_value_to_string(apArg[1],0);
/* Perform the requested operation */
rc = pVfs->xChown(zPath,zUser);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool chgrp(string $filename,string $group)
* Attempts to change the group of the file filename to group.
* Parameters
* $filename
* Path to the file.
* $group
* groupname.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_chgrp(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath,*zGroup;
ph7_vfs *pVfs;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xChgrp == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Extract the user */
zGroup = ph7_value_to_string(apArg[1],0);
/* Perform the requested operation */
rc = pVfs->xChgrp(zPath,zGroup);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* int64 disk_free_space(string $directory)
* Returns available space on filesystem or disk partition.
* Parameters
* $directory
* A directory of the filesystem or disk partition.
* Return
* Returns the number of available bytes as a 64-bit integer or FALSE on failure.
*/
static int PH7_vfs_disk_free_space(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iSize;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFreeSpace == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iSize = pVfs->xFreeSpace(zPath);
/* IO return value */
ph7_result_int64(pCtx,iSize);
return PH7_OK;
}
/*
* int64 disk_total_space(string $directory)
* Returns the total size of a filesystem or disk partition.
* Parameters
* $directory
* A directory of the filesystem or disk partition.
* Return
* Returns the number of available bytes as a 64-bit integer or FALSE on failure.
*/
static int PH7_vfs_disk_total_space(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iSize;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xTotalSpace == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iSize = pVfs->xTotalSpace(zPath);
/* IO return value */
ph7_result_int64(pCtx,iSize);
return PH7_OK;
}
/*
* bool file_exists(string $filename)
* Checks whether a file or directory exists.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_file_exists(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFileExists == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xFileExists(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* int64 file_size(string $filename)
* Gets the size for the given file.
* Parameters
* $filename
* Path to the file.
* Return
* File size on success or FALSE on failure.
*/
static int PH7_vfs_file_size(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iSize;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFileSize == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iSize = pVfs->xFileSize(zPath);
/* IO return value */
ph7_result_int64(pCtx,iSize);
return PH7_OK;
}
/*
* int64 fileatime(string $filename)
* Gets the last access time of the given file.
* Parameters
* $filename
* Path to the file.
* Return
* File atime on success or FALSE on failure.
*/
static int PH7_vfs_file_atime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iTime;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFileAtime == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iTime = pVfs->xFileAtime(zPath);
/* IO return value */
ph7_result_int64(pCtx,iTime);
return PH7_OK;
}
/*
* int64 filemtime(string $filename)
* Gets file modification time.
* Parameters
* $filename
* Path to the file.
* Return
* File mtime on success or FALSE on failure.
*/
static int PH7_vfs_file_mtime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iTime;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFileMtime == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iTime = pVfs->xFileMtime(zPath);
/* IO return value */
ph7_result_int64(pCtx,iTime);
return PH7_OK;
}
/*
* int64 filectime(string $filename)
* Gets inode change time of file.
* Parameters
* $filename
* Path to the file.
* Return
* File ctime on success or FALSE on failure.
*/
static int PH7_vfs_file_ctime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_int64 iTime;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFileCtime == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
iTime = pVfs->xFileCtime(zPath);
/* IO return value */
ph7_result_int64(pCtx,iTime);
return PH7_OK;
}
/*
* bool is_file(string $filename)
* Tells whether the filename is a regular file.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_file(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xIsfile == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xIsfile(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool is_link(string $filename)
* Tells whether the filename is a symbolic link.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_link(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xIslink == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xIslink(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool is_readable(string $filename)
* Tells whether a file exists and is readable.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_readable(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xReadable == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xReadable(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool is_writable(string $filename)
* Tells whether the filename is writable.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_writable(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xWritable == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xWritable(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool is_executable(string $filename)
* Tells whether the filename is executable.
* Parameters
* $filename
* Path to the file.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_is_executable(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xExecutable == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xExecutable(zPath);
/* IO return value */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* string filetype(string $filename)
* Gets file type.
* Parameters
* $filename
* Path to the file.
* Return
* The type of the file. Possible values are fifo, char, dir, block, link
* file, socket and unknown.
*/
static int PH7_vfs_filetype(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
ph7_vfs *pVfs;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return 'unknown' */
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xFiletype == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the desired directory */
zPath = ph7_value_to_string(apArg[0],0);
/* Set the empty string as the default return value */
ph7_result_string(pCtx,"",0);
/* Perform the requested operation */
pVfs->xFiletype(zPath,pCtx);
return PH7_OK;
}
/*
* array stat(string $filename)
* Gives information about a file.
* Parameters
* $filename
* Path to the file.
* Return
* An associative array on success holding the following entries on success
* 0 dev device number
* 1 ino inode number (zero on windows)
* 2 mode inode protection mode
* 3 nlink number of links
* 4 uid userid of owner (zero on windows)
* 5 gid groupid of owner (zero on windows)
* 6 rdev device type, if inode device
* 7 size size in bytes
* 8 atime time of last access (Unix timestamp)
* 9 mtime time of last modification (Unix timestamp)
* 10 ctime time of last inode change (Unix timestamp)
* 11 blksize blocksize of filesystem IO (zero on windows)
* 12 blocks number of 512-byte blocks allocated.
* Note:
* FALSE is returned on failure.
*/
static int PH7_vfs_stat(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_value *pArray,*pValue;
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xStat == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Create the array and the working value */
pArray = ph7_context_new_array(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pValue == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xStat(zPath,pArray,pValue);
if( rc != PH7_OK ){
/* IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return the associative array */
ph7_result_value(pCtx,pArray);
}
/* Don't worry about freeing memory here,everything will be released
* automatically as soon we return from this function. */
return PH7_OK;
}
/*
* array lstat(string $filename)
* Gives information about a file or symbolic link.
* Parameters
* $filename
* Path to the file.
* Return
* An associative array on success holding the following entries on success
* 0 dev device number
* 1 ino inode number (zero on windows)
* 2 mode inode protection mode
* 3 nlink number of links
* 4 uid userid of owner (zero on windows)
* 5 gid groupid of owner (zero on windows)
* 6 rdev device type, if inode device
* 7 size size in bytes
* 8 atime time of last access (Unix timestamp)
* 9 mtime time of last modification (Unix timestamp)
* 10 ctime time of last inode change (Unix timestamp)
* 11 blksize blocksize of filesystem IO (zero on windows)
* 12 blocks number of 512-byte blocks allocated.
* Note:
* FALSE is returned on failure.
*/
static int PH7_vfs_lstat(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_value *pArray,*pValue;
const char *zPath;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xlStat == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Create the array and the working value */
pArray = ph7_context_new_array(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pValue == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zPath = ph7_value_to_string(apArg[0],0);
/* Perform the requested operation */
rc = pVfs->xlStat(zPath,pArray,pValue);
if( rc != PH7_OK ){
/* IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return the associative array */
ph7_result_value(pCtx,pArray);
}
/* Don't worry about freeing memory here,everything will be released
* automatically as soon we return from this function. */
return PH7_OK;
}
/*
* string getenv(string $varname)
* Gets the value of an environment variable.
* Parameters
* $varname
* The variable name.
* Return
* Returns the value of the environment variable varname, or FALSE if the environment
* variable varname does not exist.
*/
static int PH7_vfs_getenv(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zEnv;
ph7_vfs *pVfs;
int iLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xGetenv == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the environment variable */
zEnv = ph7_value_to_string(apArg[0],&iLen);
/* Set a boolean FALSE as the default return value */
ph7_result_bool(pCtx,0);
if( iLen < 1 ){
/* Empty string */
return PH7_OK;
}
/* Perform the requested operation */
pVfs->xGetenv(zEnv,pCtx);
return PH7_OK;
}
/*
* bool putenv(string $settings)
* Set the value of an environment variable.
* Parameters
* $setting
* The setting, like "FOO=BAR"
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_putenv(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zName,*zValue;
char *zSettings,*zEnd;
ph7_vfs *pVfs;
int iLen,rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the setting variable */
zSettings = (char *)ph7_value_to_string(apArg[0],&iLen);
if( iLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Parse the setting */
zEnd = &zSettings[iLen];
zValue = 0;
zName = zSettings;
while( zSettings < zEnd ){
if( zSettings[0] == '=' ){
/* Null terminate the name */
zSettings[0] = 0;
zValue = &zSettings[1];
break;
}
zSettings++;
}
/* Install the environment variable in the $_Env array */
if( zValue == 0 || zName[0] == 0 || zValue >= zEnd || zName >= zValue ){
/* Invalid settings,retun FALSE */
ph7_result_bool(pCtx,0);
if( zSettings < zEnd ){
zSettings[0] = '=';
}
return PH7_OK;
}
ph7_vm_config(pCtx->pVm,PH7_VM_CONFIG_ENV_ATTR,zName,zValue,(int)(zEnd-zValue));
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xSetenv == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
zSettings[0] = '=';
return PH7_OK;
}
/* Perform the requested operation */
rc = pVfs->xSetenv(zName,zValue);
ph7_result_bool(pCtx,rc == PH7_OK );
zSettings[0] = '=';
return PH7_OK;
}
/*
* bool touch(string $filename[,int64 $time = time()[,int64 $atime]])
* Sets access and modification time of file.
* Note: On windows
* If the file does not exists,it will not be created.
* Parameters
* $filename
* The name of the file being touched.
* $time
* The touch time. If time is not supplied, the current system time is used.
* $atime
* If present, the access time of the given filename is set to the value of atime.
* Otherwise, it is set to the value passed to the time parameter. If neither are
* present, the current system time is used.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_touch(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_int64 nTime,nAccess;
const char *zFile;
ph7_vfs *pVfs;
int rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xTouch == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
nTime = nAccess = -1;
zFile = ph7_value_to_string(apArg[0],0);
if( nArg > 1 ){
nTime = ph7_value_to_int64(apArg[1]);
if( nArg > 2 ){
nAccess = ph7_value_to_int64(apArg[1]);
}else{
nAccess = nTime;
}
}
rc = pVfs->xTouch(zFile,nTime,nAccess);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* Path processing functions that do not need access to the VFS layer
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/*
* string dirname(string $path)
* Returns parent directory's path.
* Parameters
* $path
* Target path.
* On Windows, both slash (/) and backslash (\) are used as directory separator character.
* In other environments, it is the forward slash (/).
* Return
* The path of the parent directory. If there are no slashes in path, a dot ('.')
* is returned, indicating the current directory.
*/
static int PH7_builtin_dirname(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath,*zDir;
int iLen,iDirlen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Point to the target path */
zPath = ph7_value_to_string(apArg[0],&iLen);
if( iLen < 1 ){
/* Reuturn "." */
ph7_result_string(pCtx,".",sizeof(char));
return PH7_OK;
}
/* Perform the requested operation */
zDir = PH7_ExtractDirName(zPath,iLen,&iDirlen);
/* Return directory name */
ph7_result_string(pCtx,zDir,iDirlen);
return PH7_OK;
}
/*
* string basename(string $path[, string $suffix ])
* Returns trailing name component of path.
* Parameters
* $path
* Target path.
* On Windows, both slash (/) and backslash (\) are used as directory separator character.
* In other environments, it is the forward slash (/).
* $suffix
* If the name component ends in suffix this will also be cut off.
* Return
* The base name of the given path.
*/
static int PH7_builtin_basename(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath,*zBase,*zEnd;
int c,d,iLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
c = d = '/';
#ifdef __WINNT__
d = '\\';
#endif
/* Point to the target path */
zPath = ph7_value_to_string(apArg[0],&iLen);
if( iLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zPath[iLen - 1];
/* Ignore trailing '/' */
while( zEnd > zPath && ( (int)zEnd[0] == c || (int)zEnd[0] == d ) ){
zEnd--;
}
iLen = (int)(&zEnd[1]-zPath);
while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){
zEnd--;
}
zBase = (zEnd > zPath) ? &zEnd[1] : zPath;
zEnd = &zPath[iLen];
if( nArg > 1 && ph7_value_is_string(apArg[1]) ){
const char *zSuffix;
int nSuffix;
/* Strip suffix */
zSuffix = ph7_value_to_string(apArg[1],&nSuffix);
if( nSuffix > 0 && nSuffix < iLen && SyMemcmp(&zEnd[-nSuffix],zSuffix,nSuffix) == 0 ){
zEnd -= nSuffix;
}
}
/* Store the basename */
ph7_result_string(pCtx,zBase,(int)(zEnd-zBase));
return PH7_OK;
}
/*
* value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ])
* Returns information about a file path.
* Parameter
* $path
* The path to be parsed.
* $options
* If present, specifies a specific element to be returned; one of
* PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME.
* Return
* If the options parameter is not passed, an associative array containing the following
* elements is returned: dirname, basename, extension (if any), and filename.
* If options is present, returns a string containing the requested element.
*/
typedef struct path_info path_info;
struct path_info
{
SyString sDir; /* Directory [i.e: /var/www] */
SyString sBasename; /* Basename [i.e httpd.conf] */
SyString sExtension; /* File extension [i.e xml,pdf..] */
SyString sFilename; /* Filename */
};
/*
* Extract path fields.
*/
static sxi32 ExtractPathInfo(const char *zPath,int nByte,path_info *pOut)
{
const char *zPtr,*zEnd = &zPath[nByte - 1];
SyString *pCur;
int c,d;
c = d = '/';
#ifdef __WINNT__
d = '\\';
#endif
/* Zero the structure */
SyZero(pOut,sizeof(path_info));
/* Handle special case */
if( nByte == sizeof(char) && ( (int)zPath[0] == c || (int)zPath[0] == d ) ){
#ifdef __WINNT__
SyStringInitFromBuf(&pOut->sDir,"\\",sizeof(char));
#else
SyStringInitFromBuf(&pOut->sDir,"/",sizeof(char));
#endif
return SXRET_OK;
}
/* Extract the basename */
while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){
zEnd--;
}
zPtr = (zEnd > zPath) ? &zEnd[1] : zPath;
zEnd = &zPath[nByte];
/* dirname */
pCur = &pOut->sDir;
SyStringInitFromBuf(pCur,zPath,zPtr-zPath);
if( pCur->nByte > 1 ){
SyStringTrimTrailingChar(pCur,'/');
#ifdef __WINNT__
SyStringTrimTrailingChar(pCur,'\\');
#endif
}else if( (int)zPath[0] == c || (int)zPath[0] == d ){
#ifdef __WINNT__
SyStringInitFromBuf(&pOut->sDir,"\\",sizeof(char));
#else
SyStringInitFromBuf(&pOut->sDir,"/",sizeof(char));
#endif
}
/* basename/filename */
pCur = &pOut->sBasename;
SyStringInitFromBuf(pCur,zPtr,zEnd-zPtr);
SyStringTrimLeadingChar(pCur,'/');
#ifdef __WINNT__
SyStringTrimLeadingChar(pCur,'\\');
#endif
SyStringDupPtr(&pOut->sFilename,pCur);
if( pCur->nByte > 0 ){
/* extension */
zEnd--;
while( zEnd > pCur->zString /*basename*/ && zEnd[0] != '.' ){
zEnd--;
}
if( zEnd > pCur->zString ){
zEnd++; /* Jump leading dot */
SyStringInitFromBuf(&pOut->sExtension,zEnd,&zPath[nByte]-zEnd);
/* Fix filename */
pCur = &pOut->sFilename;
if( pCur->nByte > SyStringLength(&pOut->sExtension) ){
pCur->nByte -= 1 + SyStringLength(&pOut->sExtension);
}
}
}
return SXRET_OK;
}
/*
* value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ])
* See block comment above.
*/
static int PH7_builtin_pathinfo(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zPath;
path_info sInfo;
SyString *pComp;
int iLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Point to the target path */
zPath = ph7_value_to_string(apArg[0],&iLen);
if( iLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract path info */
ExtractPathInfo(zPath,iLen,&sInfo);
if( nArg > 1 && ph7_value_is_int(apArg[1]) ){
/* Return path component */
int nComp = ph7_value_to_int(apArg[1]);
switch(nComp){
case 1: /* PATHINFO_DIRNAME */
pComp = &sInfo.sDir;
if( pComp->nByte > 0 ){
ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte);
}else{
/* Expand the empty string */
ph7_result_string(pCtx,"",0);
}
break;
case 2: /*PATHINFO_BASENAME*/
pComp = &sInfo.sBasename;
if( pComp->nByte > 0 ){
ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte);
}else{
/* Expand the empty string */
ph7_result_string(pCtx,"",0);
}
break;
case 3: /*PATHINFO_EXTENSION*/
pComp = &sInfo.sExtension;
if( pComp->nByte > 0 ){
ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte);
}else{
/* Expand the empty string */
ph7_result_string(pCtx,"",0);
}
break;
case 4: /*PATHINFO_FILENAME*/
pComp = &sInfo.sFilename;
if( pComp->nByte > 0 ){
ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte);
}else{
/* Expand the empty string */
ph7_result_string(pCtx,"",0);
}
break;
default:
/* Expand the empty string */
ph7_result_string(pCtx,"",0);
break;
}
}else{
/* Return an associative array */
ph7_value *pArray,*pValue;
pArray = ph7_context_new_array(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pValue == 0 ){
/* Out of mem,return NULL */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* dirname */
pComp = &sInfo.sDir;
if( pComp->nByte > 0 ){
ph7_value_string(pValue,pComp->zString,(int)pComp->nByte);
/* Perform the insertion */
ph7_array_add_strkey_elem(pArray,"dirname",pValue); /* Will make it's own copy */
}
/* Reset the string cursor */
ph7_value_reset_string_cursor(pValue);
/* basername */
pComp = &sInfo.sBasename;
if( pComp->nByte > 0 ){
ph7_value_string(pValue,pComp->zString,(int)pComp->nByte);
/* Perform the insertion */
ph7_array_add_strkey_elem(pArray,"basename",pValue); /* Will make it's own copy */
}
/* Reset the string cursor */
ph7_value_reset_string_cursor(pValue);
/* extension */
pComp = &sInfo.sExtension;
if( pComp->nByte > 0 ){
ph7_value_string(pValue,pComp->zString,(int)pComp->nByte);
/* Perform the insertion */
ph7_array_add_strkey_elem(pArray,"extension",pValue); /* Will make it's own copy */
}
/* Reset the string cursor */
ph7_value_reset_string_cursor(pValue);
/* filename */
pComp = &sInfo.sFilename;
if( pComp->nByte > 0 ){
ph7_value_string(pValue,pComp->zString,(int)pComp->nByte);
/* Perform the insertion */
ph7_array_add_strkey_elem(pArray,"filename",pValue); /* Will make it's own copy */
}
/* Return the created array */
ph7_result_value(pCtx,pArray);
/* Don't worry about freeing memory, everything will be released
* automatically as soon we return from this foreign function.
*/
}
return PH7_OK;
}
/*
* Globbing implementation extracted from the sqlite3 source tree.
* Original author: D. Richard Hipp (http://www.sqlite.org)
* Status: Public Domain
*/
typedef unsigned char u8;
/* An array to map all upper-case characters into their corresponding
** lower-case character.
**
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
** handle case conversions for the UTF character set since the tables
** involved are nearly as big or bigger than SQLite itself.
*/
static const unsigned char sqlite3UpperToLower[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255
};
#define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
*/
#define SQLITE_SKIP_UTF8(zIn) { \
if( (*(zIn++))>=0xc0 ){ \
while( (*zIn & 0xc0)==0x80 ){ zIn++; } \
} \
}
/*
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression. Return true (1) if they
** are the same and false (0) if they are different.
**
** Globbing rules:
**
** '*' Matches any sequence of zero or more characters.
**
** '?' Matches exactly one character.
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
**
** With the [...] and [^...] matching, a ']' character can be included
** in the list by making it the first character after '[' or '^'. A
** range of characters can be specified using '-'. Example:
** "[a-z]" matches any single lower-case letter. To match a '-', make
** it the last character in the list.
**
** This routine is usually quick, but can be N**2 in the worst case.
**
** Hints: to match '*' or '?', put them in "[]". Like this:
**
** abc[*]xyz Matches "abc*xyz" only
*/
static int patternCompare(
const u8 *zPattern, /* The glob pattern */
const u8 *zString, /* The string to compare against the glob */
const int esc, /* The escape character */
int noCase
){
int c, c2;
int invert;
int seen;
u8 matchOne = '?';
u8 matchAll = '*';
u8 matchSet = '[';
int prevEscape = 0; /* True if the previous character was 'escape' */
if( !zPattern || !zString ) return 0;
while( (c = PH7_Utf8Read(zPattern,0,&zPattern))!=0 ){
if( !prevEscape && c==matchAll ){
while( (c=PH7_Utf8Read(zPattern,0,&zPattern)) == matchAll
|| c == matchOne ){
if( c==matchOne && PH7_Utf8Read(zString, 0, &zString)==0 ){
return 0;
}
}
if( c==0 ){
return 1;
}else if( c==esc ){
c = PH7_Utf8Read(zPattern, 0, &zPattern);
if( c==0 ){
return 0;
}
}else if( c==matchSet ){
if( (esc==0) || (matchSet<0x80) ) return 0;
while( *zString && patternCompare(&zPattern[-1],zString,esc,noCase)==0 ){
SQLITE_SKIP_UTF8(zString);
}
return *zString!=0;
}
while( (c2 = PH7_Utf8Read(zString,0,&zString))!=0 ){
if( noCase ){
GlogUpperToLower(c2);
GlogUpperToLower(c);
while( c2 != 0 && c2 != c ){
c2 = PH7_Utf8Read(zString, 0, &zString);
GlogUpperToLower(c2);
}
}else{
while( c2 != 0 && c2 != c ){
c2 = PH7_Utf8Read(zString, 0, &zString);
}
}
if( c2==0 ) return 0;
if( patternCompare(zPattern,zString,esc,noCase) ) return 1;
}
return 0;
}else if( !prevEscape && c==matchOne ){
if( PH7_Utf8Read(zString, 0, &zString)==0 ){
return 0;
}
}else if( c==matchSet ){
int prior_c = 0;
if( esc == 0 ) return 0;
seen = 0;
invert = 0;
c = PH7_Utf8Read(zString, 0, &zString);
if( c==0 ) return 0;
c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
if( c2=='^' ){
invert = 1;
c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
}
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
}
while( c2 && c2!=']' ){
if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
if( c==c2 ){
seen = 1;
}
prior_c = c2;
}
c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
return 0;
}
}else if( esc==c && !prevEscape ){
prevEscape = 1;
}else{
c2 = PH7_Utf8Read(zString, 0, &zString);
if( noCase ){
GlogUpperToLower(c);
GlogUpperToLower(c2);
}
if( c!=c2 ){
return 0;
}
prevEscape = 0;
}
}
return *zString==0;
}
/*
* Wrapper around patternCompare() defined above.
* See block comment above for more information.
*/
static int Glob(const unsigned char *zPattern,const unsigned char *zString,int iEsc,int CaseCompare)
{
int rc;
if( iEsc < 0 ){
iEsc = '\\';
}
rc = patternCompare(zPattern,zString,iEsc,CaseCompare);
return rc;
}
/*
* bool fnmatch(string $pattern,string $string[,int $flags = 0 ])
* Match filename against a pattern.
* Parameters
* $pattern
* The shell wildcard pattern.
* $string
* The tested string.
* $flags
* A list of possible flags:
* FNM_NOESCAPE Disable backslash escaping.
* FNM_PATHNAME Slash in string only matches slash in the given pattern.
* FNM_PERIOD Leading period in string must be exactly matched by period in the given pattern.
* FNM_CASEFOLD Caseless match.
* Return
* TRUE if there is a match, FALSE otherwise.
*/
static int PH7_builtin_fnmatch(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zPattern;
int iEsc = '\\';
int noCase = 0;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the pattern and the string */
zPattern = ph7_value_to_string(apArg[0],0);
zString = ph7_value_to_string(apArg[1],0);
/* Extract the flags if avaialble */
if( nArg > 2 && ph7_value_is_int(apArg[2]) ){
rc = ph7_value_to_int(apArg[2]);
if( rc & 0x01 /*FNM_NOESCAPE*/){
iEsc = 0;
}
if( rc & 0x08 /*FNM_CASEFOLD*/){
noCase = 1;
}
}
/* Go globbing */
rc = Glob((const unsigned char *)zPattern,(const unsigned char *)zString,iEsc,noCase);
/* Globbing result */
ph7_result_bool(pCtx,rc);
return PH7_OK;
}
/*
* bool strglob(string $pattern,string $string)
* Match string against a pattern.
* Parameters
* $pattern
* The shell wildcard pattern.
* $string
* The tested string.
* Return
* TRUE if there is a match, FALSE otherwise.
* Note that this a symisc eXtension.
*/
static int PH7_builtin_strglob(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zPattern;
int iEsc = '\\';
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the pattern and the string */
zPattern = ph7_value_to_string(apArg[0],0);
zString = ph7_value_to_string(apArg[1],0);
/* Go globbing */
rc = Glob((const unsigned char *)zPattern,(const unsigned char *)zString,iEsc,0);
/* Globbing result */
ph7_result_bool(pCtx,rc);
return PH7_OK;
}
/*
* bool link(string $target,string $link)
* Create a hard link.
* Parameters
* $target
* Target of the link.
* $link
* The link name.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_link(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zTarget,*zLink;
ph7_vfs *pVfs;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xLink == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the given arguments */
zTarget = ph7_value_to_string(apArg[0],0);
zLink = ph7_value_to_string(apArg[1],0);
/* Perform the requested operation */
rc = pVfs->xLink(zTarget,zLink,0/*Not a symbolic link */);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK );
return PH7_OK;
}
/*
* bool symlink(string $target,string $link)
* Creates a symbolic link.
* Parameters
* $target
* Target of the link.
* $link
* The link name.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_vfs_symlink(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zTarget,*zLink;
ph7_vfs *pVfs;
int rc;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xLink == 0 ){
/* IO routine not implemented,return NULL */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE",
ph7_function_name(pCtx)
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the given arguments */
zTarget = ph7_value_to_string(apArg[0],0);
zLink = ph7_value_to_string(apArg[1],0);
/* Perform the requested operation */
rc = pVfs->xLink(zTarget,zLink,1/*A symbolic link */);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK );
return PH7_OK;
}
/*
* int umask([ int $mask ])
* Changes the current umask.
* Parameters
* $mask
* The new umask.
* Return
* umask() without arguments simply returns the current umask.
* Otherwise the old umask is returned.
*/
static int PH7_vfs_umask(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int iOld,iNew;
ph7_vfs *pVfs;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xUmask == 0 ){
/* IO routine not implemented,return -1 */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
ph7_result_int(pCtx,0);
return PH7_OK;
}
iNew = 0;
if( nArg > 0 ){
iNew = ph7_value_to_int(apArg[0]);
}
/* Perform the requested operation */
iOld = pVfs->xUmask(iNew);
/* Old mask */
ph7_result_int(pCtx,iOld);
return PH7_OK;
}
/*
* string sys_get_temp_dir()
* Returns directory path used for temporary files.
* Parameters
* None
* Return
* Returns the path of the temporary directory.
*/
static int PH7_vfs_sys_get_temp_dir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
/* Set the empty string as the default return value */
ph7_result_string(pCtx,"",0);
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xTempDir == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented,return "" */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
return PH7_OK;
}
/* Perform the requested operation */
pVfs->xTempDir(pCtx);
return PH7_OK;
}
/*
* string get_current_user()
* Returns the name of the current working user.
* Parameters
* None
* Return
* Returns the name of the current working user.
*/
static int PH7_vfs_get_current_user(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xUsername == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
/* Set a dummy username */
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
return PH7_OK;
}
/* Perform the requested operation */
pVfs->xUsername(pCtx);
return PH7_OK;
}
/*
* int64 getmypid()
* Gets process ID.
* Parameters
* None
* Return
* Returns the process ID.
*/
static int PH7_vfs_getmypid(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_int64 nProcessId;
ph7_vfs *pVfs;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xProcessId == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented,return -1 */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Perform the requested operation */
nProcessId = (ph7_int64)pVfs->xProcessId();
/* Set the result */
ph7_result_int64(pCtx,nProcessId);
return PH7_OK;
}
/*
* int getmyuid()
* Get user ID.
* Parameters
* None
* Return
* Returns the user ID.
*/
static int PH7_vfs_getmyuid(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
int nUid;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xUid == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented,return -1 */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Perform the requested operation */
nUid = pVfs->xUid();
/* Set the result */
ph7_result_int(pCtx,nUid);
return PH7_OK;
}
/*
* int getmygid()
* Get group ID.
* Parameters
* None
* Return
* Returns the group ID.
*/
static int PH7_vfs_getmygid(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_vfs *pVfs;
int nGid;
/* Point to the underlying vfs */
pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
if( pVfs == 0 || pVfs->xGid == 0 ){
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* IO routine not implemented,return -1 */
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying VFS",
ph7_function_name(pCtx)
);
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Perform the requested operation */
nGid = pVfs->xGid();
/* Set the result */
ph7_result_int(pCtx,nGid);
return PH7_OK;
}
#ifdef __WINNT__
#include <Windows.h>
#elif defined(__UNIXES__)
#include <sys/utsname.h>
#endif
/*
* string php_uname([ string $mode = "a" ])
* Returns information about the host operating system.
* Parameters
* $mode
* mode is a single character that defines what information is returned:
* 'a': This is the default. Contains all modes in the sequence "s n r v m".
* 's': Operating system name. eg. FreeBSD.
* 'n': Host name. eg. localhost.example.com.
* 'r': Release name. eg. 5.1.2-RELEASE.
* 'v': Version information. Varies a lot between operating systems.
* 'm': Machine type. eg. i386.
* Return
* OS description as a string.
*/
static int PH7_vfs_ph7_uname(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
#if defined(__WINNT__)
const char *zName = "Microsoft Windows";
OSVERSIONINFOW sVer;
#elif defined(__UNIXES__)
struct utsname sName;
#endif
const char *zMode = "a";
if( nArg > 0 && ph7_value_is_string(apArg[0]) ){
/* Extract the desired mode */
zMode = ph7_value_to_string(apArg[0],0);
}
#if defined(__WINNT__)
sVer.dwOSVersionInfoSize = sizeof(sVer);
if( TRUE != GetVersionExW(&sVer)){
ph7_result_string(pCtx,zName,-1);
return PH7_OK;
}
if( sVer.dwPlatformId == VER_PLATFORM_WIN32_NT ){
if( sVer.dwMajorVersion <= 4 ){
zName = "Microsoft Windows NT";
}else if( sVer.dwMajorVersion == 5 ){
switch(sVer.dwMinorVersion){
case 0: zName = "Microsoft Windows 2000"; break;
case 1: zName = "Microsoft Windows XP"; break;
case 2: zName = "Microsoft Windows Server 2003"; break;
}
}else if( sVer.dwMajorVersion == 6){
switch(sVer.dwMinorVersion){
case 0: zName = "Microsoft Windows Vista"; break;
case 1: zName = "Microsoft Windows 7"; break;
case 2: zName = "Microsoft Windows Server 2008"; break;
case 3: zName = "Microsoft Windows 8"; break;
default: break;
}
}
}
switch(zMode[0]){
case 's':
/* Operating system name */
ph7_result_string(pCtx,zName,-1/* Compute length automatically*/);
break;
case 'n':
/* Host name */
ph7_result_string(pCtx,"localhost",(int)sizeof("localhost")-1);
break;
case 'r':
case 'v':
/* Version information. */
ph7_result_string_format(pCtx,"%u.%u build %u",
sVer.dwMajorVersion,sVer.dwMinorVersion,sVer.dwBuildNumber
);
break;
case 'm':
/* Machine name */
ph7_result_string(pCtx,"x86",(int)sizeof("x86")-1);
break;
default:
ph7_result_string_format(pCtx,"%s localhost %u.%u build %u x86",
zName,
sVer.dwMajorVersion,sVer.dwMinorVersion,sVer.dwBuildNumber
);
break;
}
#elif defined(__UNIXES__)
if( uname(&sName) != 0 ){
ph7_result_string(pCtx,"Unix",(int)sizeof("Unix")-1);
return PH7_OK;
}
switch(zMode[0]){
case 's':
/* Operating system name */
ph7_result_string(pCtx,sName.sysname,-1/* Compute length automatically*/);
break;
case 'n':
/* Host name */
ph7_result_string(pCtx,sName.nodename,-1/* Compute length automatically*/);
break;
case 'r':
/* Release information */
ph7_result_string(pCtx,sName.release,-1/* Compute length automatically*/);
break;
case 'v':
/* Version information. */
ph7_result_string(pCtx,sName.version,-1/* Compute length automatically*/);
break;
case 'm':
/* Machine name */
ph7_result_string(pCtx,sName.machine,-1/* Compute length automatically*/);
break;
default:
ph7_result_string_format(pCtx,
"%s %s %s %s %s",
sName.sysname,
sName.release,
sName.version,
sName.nodename,
sName.machine
);
break;
}
#else
ph7_result_string(pCtx,"Unknown Operating System",(int)sizeof("Unknown Operating System")-1);
#endif
return PH7_OK;
}
/*
* Section:
* IO stream implementation.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
typedef struct io_private io_private;
struct io_private
{
const ph7_io_stream *pStream; /* Underlying IO device */
void *pHandle; /* IO handle */
/* Unbuffered IO */
SyBlob sBuffer; /* Working buffer */
sxu32 nOfft; /* Current read offset */
sxu32 iMagic; /* Sanity check to avoid misuse */
};
#define IO_PRIVATE_MAGIC 0xFEAC14
/* Make sure we are dealing with a valid io_private instance */
#define IO_PRIVATE_INVALID(IO) ( IO == 0 || IO->iMagic != IO_PRIVATE_MAGIC )
/* Forward declaration */
static void ResetIOPrivate(io_private *pDev);
/*
* bool ftruncate(resource $handle,int64 $size)
* Truncates a file to a given length.
* Parameters
* $handle
* The file pointer.
* Note:
* The handle must be open for writing.
* $size
* The size to truncate to.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_builtin_ftruncate(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int rc;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xTrunc == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
rc = pStream->xTrunc(pDev->pHandle,ph7_value_to_int64(apArg[1]));
if( rc == PH7_OK ){
/* Discard buffered data */
ResetIOPrivate(pDev);
}
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* int fseek(resource $handle,int $offset[,int $whence = SEEK_SET ])
* Seeks on a file pointer.
* Parameters
* $handle
* A file system pointer resource that is typically created using fopen().
* $offset
* The offset.
* To move to a position before the end-of-file, you need to pass a negative
* value in offset and set whence to SEEK_END.
* whence
* whence values are:
* SEEK_SET - Set position equal to offset bytes.
* SEEK_CUR - Set position to current location plus offset.
* SEEK_END - Set position to end-of-file plus offset.
* Return
* 0 on success,-1 on failure
*/
static int PH7_builtin_fseek(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
ph7_int64 iOfft;
int whence;
int rc;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xSeek == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Extract the offset */
iOfft = ph7_value_to_int64(apArg[1]);
whence = 0;/* SEEK_SET */
if( nArg > 2 && ph7_value_is_int(apArg[2]) ){
whence = ph7_value_to_int(apArg[2]);
}
/* Perform the requested operation */
rc = pStream->xSeek(pDev->pHandle,iOfft,whence);
if( rc == PH7_OK ){
/* Ignore buffered data */
ResetIOPrivate(pDev);
}
/* IO result */
ph7_result_int(pCtx,rc == PH7_OK ? 0 : - 1);
return PH7_OK;
}
/*
* int64 ftell(resource $handle)
* Returns the current position of the file read/write pointer.
* Parameters
* $handle
* The file pointer.
* Return
* Returns the position of the file pointer referenced by handle
* as an integer; i.e., its offset into the file stream.
* FALSE is returned on failure.
*/
static int PH7_builtin_ftell(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
ph7_int64 iOfft;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xTell == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
iOfft = pStream->xTell(pDev->pHandle);
/* IO result */
ph7_result_int64(pCtx,iOfft);
return PH7_OK;
}
/*
* bool rewind(resource $handle)
* Rewind the position of a file pointer.
* Parameters
* $handle
* The file pointer.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_builtin_rewind(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xSeek == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
rc = pStream->xSeek(pDev->pHandle,0,0/*SEEK_SET*/);
if( rc == PH7_OK ){
/* Ignore buffered data */
ResetIOPrivate(pDev);
}
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool fflush(resource $handle)
* Flushes the output to a file.
* Parameters
* $handle
* The file pointer.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_builtin_fflush(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xSync == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
rc = pStream->xSync(pDev->pHandle);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* bool feof(resource $handle)
* Tests for end-of-file on a file pointer.
* Parameters
* $handle
* The file pointer.
* Return
* Returns TRUE if the file pointer is at EOF.FALSE otherwise
*/
static int PH7_builtin_feof(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,1);
return PH7_OK;
}
rc = SXERR_EOF;
/* Perform the requested operation */
if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){
/* Data is available */
rc = PH7_OK;
}else{
char zBuf[4096];
ph7_int64 n;
/* Perform a buffered read */
n = pStream->xRead(pDev->pHandle,zBuf,sizeof(zBuf));
if( n > 0 ){
/* Copy buffered data */
SyBlobAppend(&pDev->sBuffer,zBuf,(sxu32)n);
rc = PH7_OK;
}
}
/* EOF or not */
ph7_result_bool(pCtx,rc == SXERR_EOF);
return PH7_OK;
}
/*
* Read n bytes from the underlying IO stream device.
* Return total numbers of bytes readen on success. A number < 1 on failure
* [i.e: IO error ] or EOF.
*/
static ph7_int64 StreamRead(io_private *pDev,void *pBuf,ph7_int64 nLen)
{
const ph7_io_stream *pStream = pDev->pStream;
char *zBuf = (char *)pBuf;
ph7_int64 n,nRead;
n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
if( n > 0 ){
if( n > nLen ){
n = nLen;
}
/* Copy the buffered data */
SyMemcpy(SyBlobDataAt(&pDev->sBuffer,pDev->nOfft),pBuf,(sxu32)n);
/* Update the read offset */
pDev->nOfft += (sxu32)n;
if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){
/* Reset the working buffer so that we avoid excessive memory allocation */
SyBlobReset(&pDev->sBuffer);
pDev->nOfft = 0;
}
nLen -= n;
if( nLen < 1 ){
/* All done */
return n;
}
/* Advance the cursor */
zBuf += n;
}
/* Read without buffering */
nRead = pStream->xRead(pDev->pHandle,zBuf,nLen);
if( nRead > 0 ){
n += nRead;
}else if( n < 1 ){
/* EOF or IO error */
return nRead;
}
return n;
}
/*
* Extract a single line from the buffered input.
*/
static sxi32 GetLine(io_private *pDev,ph7_int64 *pLen,const char **pzLine)
{
const char *zIn,*zEnd,*zPtr;
zIn = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft);
zEnd = &zIn[SyBlobLength(&pDev->sBuffer)-pDev->nOfft];
zPtr = zIn;
while( zIn < zEnd ){
if( zIn[0] == '\n' ){
/* Line found */
zIn++; /* Include the line ending as requested by the PHP specification */
*pLen = (ph7_int64)(zIn-zPtr);
*pzLine = zPtr;
return SXRET_OK;
}
zIn++;
}
/* No line were found */
return SXERR_NOTFOUND;
}
/*
* Read a single line from the underlying IO stream device.
*/
static ph7_int64 StreamReadLine(io_private *pDev,const char **pzData,ph7_int64 nMaxLen)
{
const ph7_io_stream *pStream = pDev->pStream;
char zBuf[8192];
ph7_int64 n;
sxi32 rc;
n = 0;
if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){
/* Reset the working buffer so that we avoid excessive memory allocation */
SyBlobReset(&pDev->sBuffer);
pDev->nOfft = 0;
}
if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){
/* Check if there is a line */
rc = GetLine(pDev,&n,pzData);
if( rc == SXRET_OK ){
/* Got line,update the cursor */
pDev->nOfft += (sxu32)n;
return n;
}
}
/* Perform the read operation until a new line is extracted or length
* limit is reached.
*/
for(;;){
n = pStream->xRead(pDev->pHandle,zBuf,(nMaxLen > 0 && nMaxLen < sizeof(zBuf)) ? nMaxLen : sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error */
break;
}
/* Append the data just read */
SyBlobAppend(&pDev->sBuffer,zBuf,(sxu32)n);
/* Try to extract a line */
rc = GetLine(pDev,&n,pzData);
if( rc == SXRET_OK ){
/* Got one,return immediately */
pDev->nOfft += (sxu32)n;
return n;
}
if( nMaxLen > 0 && (SyBlobLength(&pDev->sBuffer) - pDev->nOfft >= nMaxLen) ){
/* Read limit reached,return the available data */
*pzData = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft);
n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
/* Reset the working buffer */
SyBlobReset(&pDev->sBuffer);
pDev->nOfft = 0;
return n;
}
}
if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){
/* Read limit reached,return the available data */
*pzData = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft);
n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
/* Reset the working buffer */
SyBlobReset(&pDev->sBuffer);
pDev->nOfft = 0;
}
return n;
}
/*
* Open an IO stream handle.
* Notes on stream:
* According to the PHP reference manual.
* In its simplest definition, a stream is a resource object which exhibits streamable behavior.
* That is, it can be read from or written to in a linear fashion, and may be able to fseek()
* to an arbitrary locations within the stream.
* A wrapper is additional code which tells the stream how to handle specific protocols/encodings.
* For example, the http wrapper knows how to translate a URL into an HTTP/1.0 request for a file
* on a remote server.
* A stream is referenced as: scheme://target
* scheme(string) - The name of the wrapper to be used. Examples include: file, http...
* If no wrapper is specified, the function default is used (typically file://).
* target - Depends on the wrapper used. For filesystem related streams this is typically a path
* and filename of the desired file. For network related streams this is typically a hostname, often
* with a path appended.
*
* Note that PH7 IO streams looks like PHP streams but their implementation differ greately.
* Please refer to the official documentation for a full discussion.
* This function return a handle on success. Otherwise null.
*/
PH7_PRIVATE void * PH7_StreamOpenHandle(ph7_vm *pVm,const ph7_io_stream *pStream,const char *zFile,
int iFlags,int use_include,ph7_value *pResource,int bPushInclude,int *pNew)
{
void *pHandle = 0; /* cc warning */
SyString sFile;
int rc;
if( pStream == 0 ){
/* No such stream device */
return 0;
}
SyStringInitFromBuf(&sFile,zFile,SyStrlen(zFile));
if( use_include ){
if( sFile.zString[0] == '/' ||
#ifdef __WINNT__
(sFile.nByte > 2 && sFile.zString[1] == ':' && (sFile.zString[2] == '\\' || sFile.zString[2] == '/') ) ||
#endif
(sFile.nByte > 1 && sFile.zString[0] == '.' && sFile.zString[1] == '/') ||
(sFile.nByte > 2 && sFile.zString[0] == '.' && sFile.zString[1] == '.' && sFile.zString[2] == '/') ){
/* Open the file directly */
rc = pStream->xOpen(zFile,iFlags,pResource,&pHandle);
}else{
SyString *pPath;
SyBlob sWorker;
#ifdef __WINNT__
static const int c = '\\';
#else
static const int c = '/';
#endif
/* Init the path builder working buffer */
SyBlobInit(&sWorker,&pVm->sAllocator);
/* Build a path from the set of include path */
SySetResetCursor(&pVm->aPaths);
rc = SXERR_IO;
while( SXRET_OK == SySetGetNextEntry(&pVm->aPaths,(void **)&pPath) ){
/* Build full path */
SyBlobFormat(&sWorker,"%z%c%z",pPath,c,&sFile);
/* Append null terminator */
if( SXRET_OK != SyBlobNullAppend(&sWorker) ){
continue;
}
/* Try to open the file */
rc = pStream->xOpen((const char *)SyBlobData(&sWorker),iFlags,pResource,&pHandle);
if( rc == PH7_OK ){
if( bPushInclude ){
/* Mark as included */
PH7_VmPushFilePath(pVm,(const char *)SyBlobData(&sWorker),SyBlobLength(&sWorker),FALSE,pNew);
}
break;
}
/* Reset the working buffer */
SyBlobReset(&sWorker);
/* Check the next path */
}
SyBlobRelease(&sWorker);
}
if( rc == PH7_OK ){
if( bPushInclude ){
/* Mark as included */
PH7_VmPushFilePath(pVm,sFile.zString,sFile.nByte,FALSE,pNew);
}
}
}else{
/* Open the URI direcly */
rc = pStream->xOpen(zFile,iFlags,pResource,&pHandle);
}
if( rc != PH7_OK ){
/* IO error */
return 0;
}
/* Return the file handle */
return pHandle;
}
/*
* Read the whole contents of an open IO stream handle [i.e local file/URL..]
* Store the read data in the given BLOB (last argument).
* The read operation is stopped when he hit the EOF or an IO error occurs.
*/
PH7_PRIVATE sxi32 PH7_StreamReadWholeFile(void *pHandle,const ph7_io_stream *pStream,SyBlob *pOut)
{
ph7_int64 nRead;
char zBuf[8192]; /* 8K */
int rc;
/* Perform the requested operation */
for(;;){
nRead = pStream->xRead(pHandle,zBuf,sizeof(zBuf));
if( nRead < 1 ){
/* EOF or IO error */
break;
}
/* Append contents */
rc = SyBlobAppend(pOut,zBuf,(sxu32)nRead);
if( rc != SXRET_OK ){
break;
}
}
return SyBlobLength(pOut) > 0 ? SXRET_OK : -1;
}
/*
* Close an open IO stream handle [i.e local file/URI..].
*/
PH7_PRIVATE void PH7_StreamCloseHandle(const ph7_io_stream *pStream,void *pHandle)
{
if( pStream->xClose ){
pStream->xClose(pHandle);
}
}
/*
* string fgetc(resource $handle)
* Gets a character from the given file pointer.
* Parameters
* $handle
* The file pointer.
* Return
* Returns a string containing a single character read from the file
* pointed to by handle. Returns FALSE on EOF.
* WARNING
* This operation is extremely slow.Avoid using it.
*/
static int PH7_builtin_fgetc(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int c,n;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
n = (int)StreamRead(pDev,(void *)&c,sizeof(char));
/* IO result */
if( n < 1 ){
/* EOF or error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return the string holding the character */
ph7_result_string(pCtx,(const char *)&c,sizeof(char));
}
return PH7_OK;
}
/*
* string fgets(resource $handle[,int64 $length ])
* Gets line from file pointer.
* Parameters
* $handle
* The file pointer.
* $length
* Reading ends when length - 1 bytes have been read, on a newline
* (which is included in the return value), or on EOF (whichever comes first).
* If no length is specified, it will keep reading from the stream until it reaches
* the end of the line.
* Return
* Returns a string of up to length - 1 bytes read from the file pointed to by handle.
* If there is no more data to read in the file pointer, then FALSE is returned.
* If an error occurs, FALSE is returned.
*/
static int PH7_builtin_fgets(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zLine;
io_private *pDev;
ph7_int64 n,nLen;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nLen = -1;
if( nArg > 1 ){
/* Maximum data to read */
nLen = ph7_value_to_int64(apArg[1]);
}
/* Perform the requested operation */
n = StreamReadLine(pDev,&zLine,nLen);
if( n < 1 ){
/* EOF or IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return the freshly extracted line */
ph7_result_string(pCtx,zLine,(int)n);
}
return PH7_OK;
}
/*
* string fread(resource $handle,int64 $length)
* Binary-safe file read.
* Parameters
* $handle
* The file pointer.
* $length
* Up to length number of bytes read.
* Return
* The data readen on success or FALSE on failure.
*/
static int PH7_builtin_fread(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
ph7_int64 nRead;
void *pBuf;
int nLen;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nLen = 4096;
if( nArg > 1 ){
nLen = ph7_value_to_int(apArg[1]);
if( nLen < 1 ){
/* Invalid length,set a default length */
nLen = 4096;
}
}
/* Allocate enough buffer */
pBuf = ph7_context_alloc_chunk(pCtx,(unsigned int)nLen,FALSE,FALSE);
if( pBuf == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
nRead = StreamRead(pDev,pBuf,(ph7_int64)nLen);
if( nRead < 1 ){
/* Nothing read,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Make a copy of the data just read */
ph7_result_string(pCtx,(const char *)pBuf,(int)nRead);
}
/* Release the buffer */
ph7_context_free_chunk(pCtx,pBuf);
return PH7_OK;
}
/*
* array fgetcsv(resource $handle [, int $length = 0
* [,string $delimiter = ','[,string $enclosure = '"'[,string $escape='\\']]]])
* Gets line from file pointer and parse for CSV fields.
* Parameters
* $handle
* The file pointer.
* $length
* Reading ends when length - 1 bytes have been read, on a newline
* (which is included in the return value), or on EOF (whichever comes first).
* If no length is specified, it will keep reading from the stream until it reaches
* the end of the line.
* $delimiter
* Set the field delimiter (one character only).
* $enclosure
* Set the field enclosure character (one character only).
* $escape
* Set the escape character (one character only). Defaults as a backslash (\)
* Return
* Returns a string of up to length - 1 bytes read from the file pointed to by handle.
* If there is no more data to read in the file pointer, then FALSE is returned.
* If an error occurs, FALSE is returned.
*/
static int PH7_builtin_fgetcsv(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zLine;
io_private *pDev;
ph7_int64 n,nLen;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nLen = -1;
if( nArg > 1 ){
/* Maximum data to read */
nLen = ph7_value_to_int64(apArg[1]);
}
/* Perform the requested operation */
n = StreamReadLine(pDev,&zLine,nLen);
if( n < 1 ){
/* EOF or IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
ph7_value *pArray;
int delim = ','; /* Delimiter */
int encl = '"' ; /* Enclosure */
int escape = '\\'; /* Escape character */
if( nArg > 2 ){
const char *zPtr;
int i;
if( ph7_value_is_string(apArg[2]) ){
/* Extract the delimiter */
zPtr = ph7_value_to_string(apArg[2],&i);
if( i > 0 ){
delim = zPtr[0];
}
}
if( nArg > 3 ){
if( ph7_value_is_string(apArg[3]) ){
/* Extract the enclosure */
zPtr = ph7_value_to_string(apArg[3],&i);
if( i > 0 ){
encl = zPtr[0];
}
}
if( nArg > 4 ){
if( ph7_value_is_string(apArg[4]) ){
/* Extract the escape character */
zPtr = ph7_value_to_string(apArg[4],&i);
if( i > 0 ){
escape = zPtr[0];
}
}
}
}
}
/* Create our array */
pArray = ph7_context_new_array(pCtx);
if( pArray == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_null(pCtx);
return PH7_OK;
}
/* Parse the raw input */
PH7_ProcessCsv(zLine,(int)n,delim,encl,escape,PH7_CsvConsumer,pArray);
/* Return the freshly created array */
ph7_result_value(pCtx,pArray);
}
return PH7_OK;
}
/*
* string fgetss(resource $handle [,int $length [,string $allowable_tags ]])
* Gets line from file pointer and strip HTML tags.
* Parameters
* $handle
* The file pointer.
* $length
* Reading ends when length - 1 bytes have been read, on a newline
* (which is included in the return value), or on EOF (whichever comes first).
* If no length is specified, it will keep reading from the stream until it reaches
* the end of the line.
* $allowable_tags
* You can use the optional second parameter to specify tags which should not be stripped.
* Return
* Returns a string of up to length - 1 bytes read from the file pointed to by
* handle, with all HTML and PHP code stripped. If an error occurs, returns FALSE.
*/
static int PH7_builtin_fgetss(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zLine;
io_private *pDev;
ph7_int64 n,nLen;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nLen = -1;
if( nArg > 1 ){
/* Maximum data to read */
nLen = ph7_value_to_int64(apArg[1]);
}
/* Perform the requested operation */
n = StreamReadLine(pDev,&zLine,nLen);
if( n < 1 ){
/* EOF or IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
const char *zTaglist = 0;
int nTaglen = 0;
if( nArg > 2 && ph7_value_is_string(apArg[2]) ){
/* Allowed tag */
zTaglist = ph7_value_to_string(apArg[2],&nTaglen);
}
/* Process data just read */
PH7_StripTagsFromString(pCtx,zLine,(int)n,zTaglist,nTaglen);
}
return PH7_OK;
}
/*
* string readdir(resource $dir_handle)
* Read entry from directory handle.
* Parameter
* $dir_handle
* The directory handle resource previously opened with opendir().
* Return
* Returns the filename on success or FALSE on failure.
*/
static int PH7_builtin_readdir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xReadDir == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
ph7_result_bool(pCtx,0);
/* Perform the requested operation */
rc = pStream->xReadDir(pDev->pHandle,pCtx);
if( rc != PH7_OK ){
/* Return FALSE */
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* void rewinddir(resource $dir_handle)
* Rewind directory handle.
* Parameter
* $dir_handle
* The directory handle resource previously opened with opendir().
* Return
* FALSE on failure.
*/
static int PH7_builtin_rewinddir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xRewindDir == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
pStream->xRewindDir(pDev->pHandle);
return PH7_OK;
}
/* Forward declaration */
static void InitIOPrivate(ph7_vm *pVm,const ph7_io_stream *pStream,io_private *pOut);
static void ReleaseIOPrivate(ph7_context *pCtx,io_private *pDev);
/*
* void closedir(resource $dir_handle)
* Close directory handle.
* Parameter
* $dir_handle
* The directory handle resource previously opened with opendir().
* Return
* FALSE on failure.
*/
static int PH7_builtin_closedir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xCloseDir == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
pStream->xCloseDir(pDev->pHandle);
/* Release the private stucture */
ReleaseIOPrivate(pCtx,pDev);
PH7_MemObjRelease(apArg[0]);
return PH7_OK;
}
/*
* resource opendir(string $path[,resource $context])
* Open directory handle.
* Parameters
* $path
* The directory path that is to be opened.
* $context
* A context stream resource.
* Return
* A directory handle resource on success,or FALSE on failure.
*/
static int PH7_builtin_opendir(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zPath;
io_private *pDev;
int iLen,rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a directory path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target path */
zPath = ph7_value_to_string(apArg[0],&iLen);
/* Try to extract a stream */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zPath,iLen);
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"No stream device is associated with the given path(%s)",zPath);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( pStream->xOpenDir == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device",
ph7_function_name(pCtx),pStream->zName
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Allocate a new IO private instance */
pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE);
if( pDev == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Initialize the structure */
InitIOPrivate(pCtx->pVm,pStream,pDev);
/* Open the target directory */
rc = pStream->xOpenDir(zPath,nArg > 1 ? apArg[1] : 0,&pDev->pHandle);
if( rc != PH7_OK ){
/* IO error,return FALSE */
ReleaseIOPrivate(pCtx,pDev);
ph7_result_bool(pCtx,0);
}else{
/* Return the handle as a resource */
ph7_result_resource(pCtx,pDev);
}
return PH7_OK;
}
/*
* int readfile(string $filename[,bool $use_include_path = false [,resource $context ]])
* Reads a file and writes it to the output buffer.
* Parameters
* $filename
* The filename being read.
* $use_include_path
* You can use the optional second parameter and set it to
* TRUE, if you want to search for the file in the include_path, too.
* $context
* A context stream resource.
* Return
* The number of bytes read from the file on success or FALSE on failure.
*/
static int PH7_builtin_readfile(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int use_include = FALSE;
const ph7_io_stream *pStream;
ph7_int64 n,nRead;
const char *zFile;
char zBuf[8192];
void *pHandle;
int rc,nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( nArg > 1 ){
use_include = ph7_value_to_bool(apArg[1]);
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,
use_include,nArg > 2 ? apArg[2] : 0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
nRead = 0;
for(;;){
n = pStream->xRead(pHandle,zBuf,sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error,break immediately */
break;
}
/* Output data */
rc = ph7_context_output(pCtx,zBuf,(int)n);
if( rc == PH7_ABORT ){
break;
}
/* Increment counter */
nRead += n;
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
/* Total number of bytes readen */
ph7_result_int64(pCtx,nRead);
return PH7_OK;
}
/*
* string file_get_contents(string $filename[,bool $use_include_path = false
* [, resource $context [, int $offset = -1 [, int $maxlen ]]]])
* Reads entire file into a string.
* Parameters
* $filename
* The filename being read.
* $use_include_path
* You can use the optional second parameter and set it to
* TRUE, if you want to search for the file in the include_path, too.
* $context
* A context stream resource.
* $offset
* The offset where the reading starts on the original stream.
* $maxlen
* Maximum length of data read. The default is to read until end of file
* is reached. Note that this parameter is applied to the stream processed by the filters.
* Return
* The function returns the read data or FALSE on failure.
*/
static int PH7_builtin_file_get_contents(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
ph7_int64 n,nRead,nMaxlen;
int use_include = FALSE;
const char *zFile;
char zBuf[8192];
void *pHandle;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nMaxlen = -1;
if( nArg > 1 ){
use_include = ph7_value_to_bool(apArg[1]);
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,use_include,nArg > 2 ? apArg[2] : 0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( nArg > 3 ){
/* Extract the offset */
n = ph7_value_to_int64(apArg[3]);
if( n > 0 ){
if( pStream->xSeek ){
/* Seek to the desired offset */
pStream->xSeek(pHandle,n,0/*SEEK_SET*/);
}
}
if( nArg > 4 ){
/* Maximum data to read */
nMaxlen = ph7_value_to_int64(apArg[4]);
}
}
/* Perform the requested operation */
nRead = 0;
for(;;){
n = pStream->xRead(pHandle,zBuf,
(nMaxlen > 0 && (nMaxlen < sizeof(zBuf))) ? nMaxlen : sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error,break immediately */
break;
}
/* Append data */
ph7_result_string(pCtx,zBuf,(int)n);
/* Increment read counter */
nRead += n;
if( nMaxlen > 0 && nRead >= nMaxlen ){
/* Read limit reached */
break;
}
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
/* Check if we have read something */
if( ph7_context_result_buf_length(pCtx) < 1 ){
/* Nothing read,return FALSE */
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int file_put_contents(string $filename,mixed $data[,int $flags = 0[,resource $context]])
* Write a string to a file.
* Parameters
* $filename
* Path to the file where to write the data.
* $data
* The data to write(Must be a string).
* $flags
* The value of flags can be any combination of the following
* flags, joined with the binary OR (|) operator.
* FILE_USE_INCLUDE_PATH Search for filename in the include directory. See include_path for more information.
* FILE_APPEND If file filename already exists, append the data to the file instead of overwriting it.
* LOCK_EX Acquire an exclusive lock on the file while proceeding to the writing.
* context
* A context stream resource.
* Return
* The function returns the number of bytes that were written to the file, or FALSE on failure.
*/
static int PH7_builtin_file_put_contents(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int use_include = FALSE;
const ph7_io_stream *pStream;
const char *zFile;
const char *zData;
int iOpenFlags;
void *pHandle;
int iFlags;
int nLen;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Data to write */
zData = ph7_value_to_string(apArg[1],&nLen);
if( nLen < 1 ){
/* Nothing to write,return immediately */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Try to open the file in read-write mode */
iOpenFlags = PH7_IO_OPEN_CREATE|PH7_IO_OPEN_RDWR|PH7_IO_OPEN_TRUNC;
/* Extract the flags */
iFlags = 0;
if( nArg > 2 ){
iFlags = ph7_value_to_int(apArg[2]);
if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/){
use_include = TRUE;
}
if( iFlags & 0x08 /* FILE_APPEND */){
/* If the file already exists, append the data to the file
* instead of overwriting it.
*/
iOpenFlags &= ~PH7_IO_OPEN_TRUNC;
/* Append mode */
iOpenFlags |= PH7_IO_OPEN_APPEND;
}
}
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,iOpenFlags,use_include,
nArg > 3 ? apArg[3] : 0,FALSE,FALSE);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( pStream->xWrite ){
ph7_int64 n;
if( (iFlags & 0x01/* LOCK_EX */) && pStream->xLock ){
/* Try to acquire an exclusive lock */
pStream->xLock(pHandle,1/* LOCK_EX */);
}
/* Perform the write operation */
n = pStream->xWrite(pHandle,(const void *)zData,nLen);
if( n < 1 ){
/* IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Total number of bytes written */
ph7_result_int64(pCtx,n);
}
}else{
/* Read-only stream */
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,
"Read-only stream(%s): Cannot perform write operation",
pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
}
/* Close the handle */
PH7_StreamCloseHandle(pStream,pHandle);
return PH7_OK;
}
/*
* array file(string $filename[,int $flags = 0[,resource $context]])
* Reads entire file into an array.
* Parameters
* $filename
* The filename being read.
* $flags
* The optional parameter flags can be one, or more, of the following constants:
* FILE_USE_INCLUDE_PATH
* Search for the file in the include_path.
* FILE_IGNORE_NEW_LINES
* Do not add newline at the end of each array element
* FILE_SKIP_EMPTY_LINES
* Skip empty lines
* $context
* A context stream resource.
* Return
* The function returns the read data or FALSE on failure.
*/
static int PH7_builtin_file(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFile,*zPtr,*zEnd,*zBuf;
ph7_value *pArray,*pLine;
const ph7_io_stream *pStream;
int use_include = 0;
io_private *pDev;
ph7_int64 n;
int iFlags;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Allocate a new IO private instance */
pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE);
if( pDev == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Initialize the structure */
InitIOPrivate(pCtx->pVm,pStream,pDev);
iFlags = 0;
if( nArg > 1 ){
iFlags = ph7_value_to_int(apArg[1]);
}
if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/ ){
use_include = TRUE;
}
/* Create the array and the working value */
pArray = ph7_context_new_array(pCtx);
pLine = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pLine == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Try to open the file in read-only mode */
pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,use_include,nArg > 2 ? apArg[2] : 0,FALSE,0);
if( pDev->pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
/* Don't worry about freeing memory, everything will be released automatically
* as soon we return from this function.
*/
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
/* Try to extract a line */
n = StreamReadLine(pDev,&zBuf,-1);
if( n < 1 ){
/* EOF or IO error */
break;
}
/* Reset the cursor */
ph7_value_reset_string_cursor(pLine);
/* Remove line ending if requested by the caller */
zPtr = zBuf;
zEnd = &zBuf[n];
if( iFlags & 0x02 /* FILE_IGNORE_NEW_LINES */ ){
/* Ignore trailig lines */
while( zPtr < zEnd && (zEnd[-1] == '\n'
#ifdef __WINNT__
|| zEnd[-1] == '\r'
#endif
)){
n--;
zEnd--;
}
}
if( iFlags & 0x04 /* FILE_SKIP_EMPTY_LINES */ ){
/* Ignore empty lines */
while( zPtr < zEnd && (unsigned char)zPtr[0] < 0xc0 && SyisSpace(zPtr[0]) ){
zPtr++;
}
if( zPtr >= zEnd ){
/* Empty line */
continue;
}
}
ph7_value_string(pLine,zBuf,(int)(zEnd-zBuf));
/* Insert line */
ph7_array_add_elem(pArray,0/* Automatic index assign*/,pLine);
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pDev->pHandle);
/* Release the io_private instance */
ReleaseIOPrivate(pCtx,pDev);
/* Return the created array */
ph7_result_value(pCtx,pArray);
return PH7_OK;
}
/*
* bool copy(string $source,string $dest[,resource $context ] )
* Makes a copy of the file source to dest.
* Parameters
* $source
* Path to the source file.
* $dest
* The destination path. If dest is a URL, the copy operation
* may fail if the wrapper does not support overwriting of existing files.
* $context
* A context stream resource.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_builtin_copy(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pSin,*pSout;
const char *zFile;
char zBuf[8192];
void *pIn,*pOut;
ph7_int64 n;
int nLen;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a source and a destination path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the source name */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pSin = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pSin == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Try to open the source file in a read-only mode */
pIn = PH7_StreamOpenHandle(pCtx->pVm,pSin,zFile,PH7_IO_OPEN_RDONLY,FALSE,nArg > 2 ? apArg[2] : 0,FALSE,0);
if( pIn == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening source: '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the destination name */
zFile = ph7_value_to_string(apArg[1],&nLen);
/* Point to the target IO stream device */
pSout = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pSout == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
PH7_StreamCloseHandle(pSin,pIn);
return PH7_OK;
}
if( pSout->xWrite == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pSin->zName
);
ph7_result_bool(pCtx,0);
PH7_StreamCloseHandle(pSin,pIn);
return PH7_OK;
}
/* Try to open the destination file in a read-write mode */
pOut = PH7_StreamOpenHandle(pCtx->pVm,pSout,zFile,
PH7_IO_OPEN_CREATE|PH7_IO_OPEN_TRUNC|PH7_IO_OPEN_RDWR,FALSE,nArg > 2 ? apArg[2] : 0,FALSE,0);
if( pOut == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening destination: '%s'",zFile);
ph7_result_bool(pCtx,0);
PH7_StreamCloseHandle(pSin,pIn);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
/* Read from source */
n = pSin->xRead(pIn,zBuf,sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error,break immediately */
break;
}
/* Write to dest */
n = pSout->xWrite(pOut,zBuf,n);
if( n < 1 ){
/* IO error,break immediately */
break;
}
}
/* Close the streams */
PH7_StreamCloseHandle(pSin,pIn);
PH7_StreamCloseHandle(pSout,pOut);
/* Return TRUE */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/*
* array fstat(resource $handle)
* Gets information about a file using an open file pointer.
* Parameters
* $handle
* The file pointer.
* Return
* Returns an array with the statistics of the file or FALSE on failure.
*/
static int PH7_builtin_fstat(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_value *pArray,*pValue;
const ph7_io_stream *pStream;
io_private *pDev;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/* Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xStat == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Create the array and the working value */
pArray = ph7_context_new_array(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pValue == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
pStream->xStat(pDev->pHandle,pArray,pValue);
/* Return the freshly created array */
ph7_result_value(pCtx,pArray);
/* Don't worry about freeing memory here,everything will be
* released automatically as soon we return from this function.
*/
return PH7_OK;
}
/*
* int fwrite(resource $handle,string $string[,int $length])
* Writes the contents of string to the file stream pointed to by handle.
* Parameters
* $handle
* The file pointer.
* $string
* The string that is to be written.
* $length
* If the length argument is given, writing will stop after length bytes have been written
* or the end of string is reached, whichever comes first.
* Return
* Returns the number of bytes written, or FALSE on error.
*/
static int PH7_builtin_fwrite(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zString;
io_private *pDev;
int nLen,n;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/* Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xWrite == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the data to write */
zString = ph7_value_to_string(apArg[1],&nLen);
if( nArg > 2 ){
/* Maximum data length to write */
n = ph7_value_to_int(apArg[2]);
if( n >= 0 && n < nLen ){
nLen = n;
}
}
if( nLen < 1 ){
/* Nothing to write */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
n = (int)pStream->xWrite(pDev->pHandle,(const void *)zString,nLen);
if( n < 0 ){
/* IO error,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* #Bytes written */
ph7_result_int(pCtx,n);
}
return PH7_OK;
}
/*
* bool flock(resource $handle,int $operation)
* Portable advisory file locking.
* Parameters
* $handle
* The file pointer.
* $operation
* operation is one of the following:
* LOCK_SH to acquire a shared lock (reader).
* LOCK_EX to acquire an exclusive lock (writer).
* LOCK_UN to release a lock (shared or exclusive).
* Return
* Returns TRUE on success or FALSE on failure.
*/
static int PH7_builtin_flock(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
int nLock;
int rc;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xLock == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Requested lock operation */
nLock = ph7_value_to_int(apArg[1]);
/* Lock operation */
rc = pStream->xLock(pDev->pHandle,nLock);
/* IO result */
ph7_result_bool(pCtx,rc == PH7_OK);
return PH7_OK;
}
/*
* int fpassthru(resource $handle)
* Output all remaining data on a file pointer.
* Parameters
* $handle
* The file pointer.
* Return
* Total number of characters read from handle and passed through
* to the output on success or FALSE on failure.
*/
static int PH7_builtin_fpassthru(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
ph7_int64 n,nRead;
char zBuf[8192];
int rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
nRead = 0;
for(;;){
n = StreamRead(pDev,zBuf,sizeof(zBuf));
if( n < 1 ){
/* Error or EOF */
break;
}
/* Increment the read counter */
nRead += n;
/* Output data */
rc = ph7_context_output(pCtx,zBuf,(int)nRead /* FIXME: 64-bit issues */);
if( rc == PH7_ABORT ){
/* Consumer callback request an operation abort */
break;
}
}
/* Total number of bytes readen */
ph7_result_int64(pCtx,nRead);
return PH7_OK;
}
/* CSV reader/writer private data */
struct csv_data
{
int delimiter; /* Delimiter. Default ',' */
int enclosure; /* Enclosure. Default '"'*/
io_private *pDev; /* Open stream handle */
int iCount; /* Counter */
};
/*
* The following callback is used by the fputcsv() function inorder to iterate
* throw array entries and output CSV data based on the current key and it's
* associated data.
*/
static int csv_write_callback(ph7_value *pKey,ph7_value *pValue,void *pUserData)
{
struct csv_data *pData = (struct csv_data *)pUserData;
const char *zData;
int nLen,c2;
sxu32 n;
/* Point to the raw data */
zData = ph7_value_to_string(pValue,&nLen);
if( nLen < 1 ){
/* Nothing to write */
return PH7_OK;
}
if( pData->iCount > 0 ){
/* Write the delimiter */
pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->delimiter,sizeof(char));
}
n = 1;
c2 = 0;
if( SyByteFind(zData,(sxu32)nLen,pData->delimiter,0) == SXRET_OK ||
SyByteFind(zData,(sxu32)nLen,pData->enclosure,&n) == SXRET_OK ){
c2 = 1;
if( n == 0 ){
c2 = 2;
}
/* Write the enclosure */
pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char));
if( c2 > 1 ){
pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char));
}
}
/* Write the data */
if( pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)zData,(ph7_int64)nLen) < 1 ){
SXUNUSED(pKey); /* cc warning */
return PH7_ABORT;
}
if( c2 > 0 ){
/* Write the enclosure */
pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char));
if( c2 > 1 ){
pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char));
}
}
pData->iCount++;
return PH7_OK;
}
/*
* int fputcsv(resource $handle,array $fields[,string $delimiter = ','[,string $enclosure = '"' ]])
* Format line as CSV and write to file pointer.
* Parameters
* $handle
* Open file handle.
* $fields
* An array of values.
* $delimiter
* The optional delimiter parameter sets the field delimiter (one character only).
* $enclosure
* The optional enclosure parameter sets the field enclosure (one character only).
*/
static int PH7_builtin_fputcsv(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
struct csv_data sCsv;
io_private *pDev;
const char *zEol;
int eolen;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Missing/Invalid arguments");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 || pStream->xWrite == 0){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Set default csv separator */
sCsv.delimiter = ',';
sCsv.enclosure = '"';
sCsv.pDev = pDev;
sCsv.iCount = 0;
if( nArg > 2 ){
/* User delimiter */
const char *z;
int n;
z = ph7_value_to_string(apArg[2],&n);
if( n > 0 ){
sCsv.delimiter = z[0];
}
if( nArg > 3 ){
z = ph7_value_to_string(apArg[3],&n);
if( n > 0 ){
sCsv.enclosure = z[0];
}
}
}
/* Iterate throw array entries and write csv data */
ph7_array_walk(apArg[1],csv_write_callback,&sCsv);
/* Write a line ending */
#ifdef __WINNT__
zEol = "\r\n";
eolen = (int)sizeof("\r\n")-1;
#else
/* Assume UNIX LF */
zEol = "\n";
eolen = (int)sizeof(char);
#endif
pDev->pStream->xWrite(pDev->pHandle,(const void *)zEol,eolen);
return PH7_OK;
}
/*
* fprintf,vfprintf private data.
* An instance of the following structure is passed to the formatted
* input consumer callback defined below.
*/
typedef struct fprintf_data fprintf_data;
struct fprintf_data
{
io_private *pIO; /* IO stream */
ph7_int64 nCount; /* Total number of bytes written */
};
/*
* Callback [i.e: Formatted input consumer] for the fprintf function.
*/
static int fprintfConsumer(ph7_context *pCtx,const char *zInput,int nLen,void *pUserData)
{
fprintf_data *pFdata = (fprintf_data *)pUserData;
ph7_int64 n;
/* Write the formatted data */
n = pFdata->pIO->pStream->xWrite(pFdata->pIO->pHandle,(const void *)zInput,nLen);
if( n < 1 ){
SXUNUSED(pCtx); /* cc warning */
/* IO error,abort immediately */
return SXERR_ABORT;
}
/* Increment counter */
pFdata->nCount += n;
return PH7_OK;
}
/*
* int fprintf(resource $handle,string $format[,mixed $args [, mixed $... ]])
* Write a formatted string to a stream.
* Parameters
* $handle
* The file pointer.
* $format
* String format (see sprintf()).
* Return
* The length of the written string.
*/
static int PH7_builtin_fprintf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
fprintf_data sFdata;
const char *zFormat;
io_private *pDev;
int nLen;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1]) ){
/* Missing/Invalid arguments,return zero */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Invalid arguments");
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device",
ph7_function_name(pCtx),pDev->pStream ? pDev->pStream->zName : "null_stream"
);
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[1],&nLen);
if( nLen < 1 ){
/* Empty string,return zero */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Prepare our private data */
sFdata.nCount = 0;
sFdata.pIO = pDev;
/* Format the string */
PH7_InputFormat(fprintfConsumer,pCtx,zFormat,nLen,nArg - 1,&apArg[1],(void *)&sFdata,FALSE);
/* Return total number of bytes written */
ph7_result_int64(pCtx,sFdata.nCount);
return PH7_OK;
}
/*
* int vfprintf(resource $handle,string $format,array $args)
* Write a formatted string to a stream.
* Parameters
* $handle
* The file pointer.
* $format
* String format (see sprintf()).
* $args
* User arguments.
* Return
* The length of the written string.
*/
static int PH7_builtin_vfprintf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
fprintf_data sFdata;
const char *zFormat;
ph7_hashmap *pMap;
io_private *pDev;
SySet sArg;
int n,nLen;
if( nArg < 3 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1]) || !ph7_value_is_array(apArg[2]) ){
/* Missing/Invalid arguments,return zero */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Invalid arguments");
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device",
ph7_function_name(pCtx),pDev->pStream ? pDev->pStream->zName : "null_stream"
);
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[1],&nLen);
if( nLen < 1 ){
/* Empty string,return zero */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Point to hashmap */
pMap = (ph7_hashmap *)apArg[2]->x.pOther;
/* Extract arguments from the hashmap */
n = PH7_HashmapValuesToSet(pMap,&sArg);
/* Prepare our private data */
sFdata.nCount = 0;
sFdata.pIO = pDev;
/* Format the string */
PH7_InputFormat(fprintfConsumer,pCtx,zFormat,nLen,n,(ph7_value **)SySetBasePtr(&sArg),(void *)&sFdata,TRUE);
/* Return total number of bytes written*/
ph7_result_int64(pCtx,sFdata.nCount);
SySetRelease(&sArg);
return PH7_OK;
}
/*
* Convert open modes (string passed to the fopen() function) [i.e: 'r','w+','a',...] into PH7 flags.
* According to the PHP reference manual:
* The mode parameter specifies the type of access you require to the stream. It may be any of the following
* 'r' Open for reading only; place the file pointer at the beginning of the file.
* 'r+' Open for reading and writing; place the file pointer at the beginning of the file.
* 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file
* to zero length. If the file does not exist, attempt to create it.
* 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate
* the file to zero length. If the file does not exist, attempt to create it.
* 'a' Open for writing only; place the file pointer at the end of the file. If the file does not
* exist, attempt to create it.
* 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does
* not exist, attempt to create it.
* 'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file
* already exists,
* the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file
* does not exist attempt to create it. This is equivalent to specifying O_EXCL|O_CREAT flags for
* the underlying open(2) system call.
* 'x+' Create and open for reading and writing; otherwise it has the same behavior as 'x'.
* 'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated
* (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer
* is positioned on the beginning of the file.
* This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file
* as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can
* be used after the lock is requested).
* 'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'.
*/
static int StrModeToFlags(ph7_context *pCtx,const char *zMode,int nLen)
{
const char *zEnd = &zMode[nLen];
int iFlag = 0;
int c;
if( nLen < 1 ){
/* Open in a read-only mode */
return PH7_IO_OPEN_RDONLY;
}
c = zMode[0];
if( c == 'r' || c == 'R' ){
/* Read-only access */
iFlag = PH7_IO_OPEN_RDONLY;
zMode++; /* Advance */
if( zMode < zEnd ){
c = zMode[0];
if( c == '+' || c == 'w' || c == 'W' ){
/* Read+Write access */
iFlag = PH7_IO_OPEN_RDWR;
}
}
}else if( c == 'w' || c == 'W' ){
/* Overwrite mode.
* If the file does not exists,try to create it
*/
iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_TRUNC|PH7_IO_OPEN_CREATE;
zMode++; /* Advance */
if( zMode < zEnd ){
c = zMode[0];
if( c == '+' || c == 'r' || c == 'R' ){
/* Read+Write access */
iFlag &= ~PH7_IO_OPEN_WRONLY;
iFlag |= PH7_IO_OPEN_RDWR;
}
}
}else if( c == 'a' || c == 'A' ){
/* Append mode (place the file pointer at the end of the file).
* Create the file if it does not exists.
*/
iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_APPEND|PH7_IO_OPEN_CREATE;
zMode++; /* Advance */
if( zMode < zEnd ){
c = zMode[0];
if( c == '+' ){
/* Read-Write access */
iFlag &= ~PH7_IO_OPEN_WRONLY;
iFlag |= PH7_IO_OPEN_RDWR;
}
}
}else if( c == 'x' || c == 'X' ){
/* Exclusive access.
* If the file already exists,return immediately with a failure code.
* Otherwise create a new file.
*/
iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_EXCL;
zMode++; /* Advance */
if( zMode < zEnd ){
c = zMode[0];
if( c == '+' || c == 'r' || c == 'R' ){
/* Read-Write access */
iFlag &= ~PH7_IO_OPEN_WRONLY;
iFlag |= PH7_IO_OPEN_RDWR;
}
}
}else if( c == 'c' || c == 'C' ){
/* Overwrite mode.Create the file if it does not exists.*/
iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_CREATE;
zMode++; /* Advance */
if( zMode < zEnd ){
c = zMode[0];
if( c == '+' ){
/* Read-Write access */
iFlag &= ~PH7_IO_OPEN_WRONLY;
iFlag |= PH7_IO_OPEN_RDWR;
}
}
}else{
/* Invalid mode. Assume a read only open */
ph7_context_throw_error(pCtx,PH7_CTX_NOTICE,"Invalid open mode,PH7 is assuming a Read-Only open");
iFlag = PH7_IO_OPEN_RDONLY;
}
while( zMode < zEnd ){
c = zMode[0];
if( c == 'b' || c == 'B' ){
iFlag &= ~PH7_IO_OPEN_TEXT;
iFlag |= PH7_IO_OPEN_BINARY;
}else if( c == 't' || c == 'T' ){
iFlag &= ~PH7_IO_OPEN_BINARY;
iFlag |= PH7_IO_OPEN_TEXT;
}
zMode++;
}
return iFlag;
}
/*
* Initialize the IO private structure.
*/
static void InitIOPrivate(ph7_vm *pVm,const ph7_io_stream *pStream,io_private *pOut)
{
pOut->pStream = pStream;
SyBlobInit(&pOut->sBuffer,&pVm->sAllocator);
pOut->nOfft = 0;
/* Set the magic number */
pOut->iMagic = IO_PRIVATE_MAGIC;
}
/*
* Release the IO private structure.
*/
static void ReleaseIOPrivate(ph7_context *pCtx,io_private *pDev)
{
SyBlobRelease(&pDev->sBuffer);
pDev->iMagic = 0x2126; /* Invalid magic number so we can detetct misuse */
/* Release the whole structure */
ph7_context_free_chunk(pCtx,pDev);
}
/*
* Reset the IO private structure.
*/
static void ResetIOPrivate(io_private *pDev)
{
SyBlobReset(&pDev->sBuffer);
pDev->nOfft = 0;
}
/* Forward declaration */
static int is_php_stream(const ph7_io_stream *pStream);
/*
* resource fopen(string $filename,string $mode [,bool $use_include_path = false[,resource $context ]])
* Open a file,a URL or any other IO stream.
* Parameters
* $filename
* If filename is of the form "scheme://...", it is assumed to be a URL and PHP will search
* for a protocol handler (also known as a wrapper) for that scheme. If no scheme is given
* then a regular file is assumed.
* $mode
* The mode parameter specifies the type of access you require to the stream
* See the block comment associated with the StrModeToFlags() for the supported
* modes.
* $use_include_path
* You can use the optional second parameter and set it to
* TRUE, if you want to search for the file in the include_path, too.
* $context
* A context stream resource.
* Return
* File handle on success or FALSE on failure.
*/
static int PH7_builtin_fopen(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zUri,*zMode;
ph7_value *pResource;
io_private *pDev;
int iLen,imLen;
int iOpenFlags;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path or URL");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the URI and the desired access mode */
zUri = ph7_value_to_string(apArg[0],&iLen);
if( nArg > 1 ){
zMode = ph7_value_to_string(apArg[1],&imLen);
}else{
/* Set a default read-only mode */
zMode = "r";
imLen = (int)sizeof(char);
}
/* Try to extract a stream */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zUri,iLen);
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"No stream device is associated with the given URI(%s)",zUri);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Allocate a new IO private instance */
pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE);
if( pDev == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
pResource = 0;
if( nArg > 3 ){
pResource = apArg[3];
}else if( is_php_stream(pStream) ){
/* TICKET 1433-80: The php:// stream need a ph7_value to access the underlying
* virtual machine.
*/
pResource = apArg[0];
}
/* Initialize the structure */
InitIOPrivate(pCtx->pVm,pStream,pDev);
/* Convert open mode to PH7 flags */
iOpenFlags = StrModeToFlags(pCtx,zMode,imLen);
/* Try to get a handle */
pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zUri,iOpenFlags,
nArg > 2 ? ph7_value_to_bool(apArg[2]) : FALSE,pResource,FALSE,0);
if( pDev->pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zUri);
ph7_result_bool(pCtx,0);
ph7_context_free_chunk(pCtx,pDev);
return PH7_OK;
}
/* All done,return the io_private instance as a resource */
ph7_result_resource(pCtx,pDev);
return PH7_OK;
}
/*
* bool fclose(resource $handle)
* Closes an open file pointer
* Parameters
* $handle
* The file pointer.
* Return
* TRUE on success or FALSE on failure.
*/
static int PH7_builtin_fclose(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
io_private *pDev;
ph7_vm *pVm;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract our private data */
pDev = (io_private *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid io_private instance */
if( IO_PRIVATE_INVALID(pDev) ){
/*Expecting an IO handle */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target IO stream device */
pStream = pDev->pStream;
if( pStream == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING,
"IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE",
ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the VM that own this context */
pVm = pCtx->pVm;
/* TICKET 1433-62: Keep the STDIN/STDOUT/STDERR handles open */
if( pDev != pVm->pStdin && pDev != pVm->pStdout && pDev != pVm->pStderr ){
/* Perform the requested operation */
PH7_StreamCloseHandle(pStream,pDev->pHandle);
/* Release the IO private structure */
ReleaseIOPrivate(pCtx,pDev);
/* Invalidate the resource handle */
ph7_value_release(apArg[0]);
}
/* Return TRUE */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
#if !defined(PH7_DISABLE_HASH_FUNC)
/*
* MD5/SHA1 digest consumer.
*/
static int vfsHashConsumer(const void *pData,unsigned int nLen,void *pUserData)
{
/* Append hex chunk verbatim */
ph7_result_string((ph7_context *)pUserData,(const char *)pData,(int)nLen);
return SXRET_OK;
}
/*
* string md5_file(string $uri[,bool $raw_output = false ])
* Calculates the md5 hash of a given file.
* Parameters
* $uri
* Target URI (file(/path/to/something) or URL(http://www.symisc.net/))
* $raw_output
* When TRUE, returns the digest in raw binary format with a length of 16.
* Return
* Return the MD5 digest on success or FALSE on failure.
*/
static int PH7_builtin_md5_file(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
unsigned char zDigest[16];
int raw_output = FALSE;
const char *zFile;
MD5Context sCtx;
char zBuf[8192];
void *pHandle;
ph7_int64 n;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( nArg > 1 ){
raw_output = ph7_value_to_bool(apArg[1]);
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Init the MD5 context */
MD5Init(&sCtx);
/* Perform the requested operation */
for(;;){
n = pStream->xRead(pHandle,zBuf,sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error,break immediately */
break;
}
MD5Update(&sCtx,(const unsigned char *)zBuf,(unsigned int)n);
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
/* Extract the digest */
MD5Final(zDigest,&sCtx);
if( raw_output ){
/* Output raw digest */
ph7_result_string(pCtx,(const char *)zDigest,sizeof(zDigest));
}else{
/* Perform a binary to hex conversion */
SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),vfsHashConsumer,pCtx);
}
return PH7_OK;
}
/*
* string sha1_file(string $uri[,bool $raw_output = false ])
* Calculates the SHA1 hash of a given file.
* Parameters
* $uri
* Target URI (file(/path/to/something) or URL(http://www.symisc.net/))
* $raw_output
* When TRUE, returns the digest in raw binary format with a length of 20.
* Return
* Return the SHA1 digest on success or FALSE on failure.
*/
static int PH7_builtin_sha1_file(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
unsigned char zDigest[20];
int raw_output = FALSE;
const char *zFile;
SHA1Context sCtx;
char zBuf[8192];
void *pHandle;
ph7_int64 n;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( nArg > 1 ){
raw_output = ph7_value_to_bool(apArg[1]);
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Init the SHA1 context */
SHA1Init(&sCtx);
/* Perform the requested operation */
for(;;){
n = pStream->xRead(pHandle,zBuf,sizeof(zBuf));
if( n < 1 ){
/* EOF or IO error,break immediately */
break;
}
SHA1Update(&sCtx,(const unsigned char *)zBuf,(unsigned int)n);
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
/* Extract the digest */
SHA1Final(&sCtx,zDigest);
if( raw_output ){
/* Output raw digest */
ph7_result_string(pCtx,(const char *)zDigest,sizeof(zDigest));
}else{
/* Perform a binary to hex conversion */
SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),vfsHashConsumer,pCtx);
}
return PH7_OK;
}
#endif /* PH7_DISABLE_HASH_FUNC */
/*
* array parse_ini_file(string $filename[, bool $process_sections = false [, int $scanner_mode = INI_SCANNER_NORMAL ]] )
* Parse a configuration file.
* Parameters
* $filename
* The filename of the ini file being parsed.
* $process_sections
* By setting the process_sections parameter to TRUE, you get a multidimensional array
* with the section names and settings included.
* The default for process_sections is FALSE.
* $scanner_mode
* Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW.
* If INI_SCANNER_RAW is supplied, then option values will not be parsed.
* Return
* The settings are returned as an associative array on success.
* Otherwise is returned.
*/
static int PH7_builtin_parse_ini_file(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
const char *zFile;
SyBlob sContents;
void *pHandle;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
SyBlobInit(&sContents,&pCtx->pVm->sAllocator);
/* Read the whole file */
PH7_StreamReadWholeFile(pHandle,pStream,&sContents);
if( SyBlobLength(&sContents) < 1 ){
/* Empty buffer,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Process the raw INI buffer */
PH7_ParseIniString(pCtx,(const char *)SyBlobData(&sContents),SyBlobLength(&sContents),
nArg > 1 ? ph7_value_to_bool(apArg[1]) : 0);
}
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
/* Release the working buffer */
SyBlobRelease(&sContents);
return PH7_OK;
}
/*
* Section:
* ZIP archive processing.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
typedef struct zip_raw_data zip_raw_data;
struct zip_raw_data
{
int iType; /* Where the raw data is stored */
union raw_data{
struct mmap_data{
void *pMap; /* Memory mapped data */
ph7_int64 nSize; /* Map size */
const ph7_vfs *pVfs; /* Underlying vfs */
}mmap;
SyBlob sBlob; /* Memory buffer */
}raw;
};
#define ZIP_RAW_DATA_MMAPED 1 /* Memory mapped ZIP raw data */
#define ZIP_RAW_DATA_MEMBUF 2 /* ZIP raw data stored in a dynamically
* allocated memory chunk.
*/
/*
* mixed zip_open(string $filename)
* Opens a new zip archive for reading.
* Parameters
* $filename
* The file name of the ZIP archive to open.
* Return
* A resource handle for later use with zip_read() and zip_close() or FALSE on failure.
*/
static int PH7_builtin_zip_open(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const ph7_io_stream *pStream;
SyArchive *pArchive;
zip_raw_data *pRaw;
const char *zFile;
SyBlob *pContents;
void *pHandle;
int nLen;
sxi32 rc;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the file path */
zFile = ph7_value_to_string(apArg[0],&nLen);
/* Point to the target IO stream device */
pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen);
if( pStream == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Create an in-memory archive */
pArchive = (SyArchive *)ph7_context_alloc_chunk(pCtx,sizeof(SyArchive)+sizeof(zip_raw_data),TRUE,FALSE);
if( pArchive == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"PH7 is running out of memory");
ph7_result_bool(pCtx,0);
return PH7_OK;
}
pRaw = (zip_raw_data *)&pArchive[1];
/* Initialize the archive */
SyArchiveInit(pArchive,&pCtx->pVm->sAllocator,0,0);
/* Extract the default stream */
if( pStream == pCtx->pVm->pDefStream /* file:// stream*/){
const ph7_vfs *pVfs;
/* Try to get a memory view of the whole file since ZIP files
* tends to be very big this days,this is a huge performance win.
*/
pVfs = PH7_ExportBuiltinVfs();
if( pVfs && pVfs->xMmap ){
rc = pVfs->xMmap(zFile,&pRaw->raw.mmap.pMap,&pRaw->raw.mmap.nSize);
if( rc == PH7_OK ){
/* Nice,Extract the whole archive */
rc = SyZipExtractFromBuf(pArchive,(const char *)pRaw->raw.mmap.pMap,(sxu32)pRaw->raw.mmap.nSize);
if( rc != SXRET_OK ){
if( pVfs->xUnmap ){
pVfs->xUnmap(pRaw->raw.mmap.pMap,pRaw->raw.mmap.nSize);
}
/* Release the allocated chunk */
ph7_context_free_chunk(pCtx,pArchive);
/* Something goes wrong with this ZIP archive,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Archive successfully opened */
pRaw->iType = ZIP_RAW_DATA_MMAPED;
pRaw->raw.mmap.pVfs = pVfs;
goto success;
}
}
/* FALL THROUGH */
}
/* Try to open the file in read-only mode */
pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0);
if( pHandle == 0 ){
ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
pContents = &pRaw->raw.sBlob;
SyBlobInit(pContents,&pCtx->pVm->sAllocator);
/* Read the whole file */
PH7_StreamReadWholeFile(pHandle,pStream,pContents);
/* Assume an invalid ZIP file */
rc = SXERR_INVALID;
if( SyBlobLength(pContents) > 0 ){
/* Extract archive entries */
rc = SyZipExtractFromBuf(pArchive,(const char *)SyBlobData(pContents),SyBlobLength(pContents));
}
pRaw->iType = ZIP_RAW_DATA_MEMBUF;
/* Close the stream */
PH7_StreamCloseHandle(pStream,pHandle);
if( rc != SXRET_OK ){
/* Release the working buffer */
SyBlobRelease(pContents);
/* Release the allocated chunk */
ph7_context_free_chunk(pCtx,pArchive);
/* Something goes wrong with this ZIP archive,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
success:
/* Reset the loop cursor */
SyArchiveResetLoopCursor(pArchive);
/* Return the in-memory archive as a resource handle */
ph7_result_resource(pCtx,pArchive);
return PH7_OK;
}
/*
* void zip_close(resource $zip)
* Close an in-memory ZIP archive.
* Parameters
* $zip
* A ZIP file previously opened with zip_open().
* Return
* null.
*/
static int PH7_builtin_zip_close(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchive *pArchive;
zip_raw_data *pRaw;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
return PH7_OK;
}
/* Point to the in-memory archive */
pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid ZIP archive */
if( SXARCH_INVALID(pArchive) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
return PH7_OK;
}
/* Release the archive */
SyArchiveRelease(pArchive);
pRaw = (zip_raw_data *)&pArchive[1];
if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){
SyBlobRelease(&pRaw->raw.sBlob);
}else{
const ph7_vfs *pVfs = pRaw->raw.mmap.pVfs;
if( pVfs->xUnmap ){
/* Unmap the memory view */
pVfs->xUnmap(pRaw->raw.mmap.pMap,pRaw->raw.mmap.nSize);
}
}
/* Release the memory chunk */
ph7_context_free_chunk(pCtx,pArchive);
return PH7_OK;
}
/*
* mixed zip_read(resource $zip)
* Reads the next entry from an in-memory ZIP archive.
* Parameters
* $zip
* A ZIP file previously opened with zip_open().
* Return
* A directory entry resource for later use with the zip_entry_... functions
* or FALSE if there are no more entries to read, or an error code if an error occurred.
*/
static int PH7_builtin_zip_read(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pNext = 0; /* cc warning */
SyArchive *pArchive;
sxi32 rc;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the in-memory archive */
pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid ZIP archive */
if( SXARCH_INVALID(pArchive) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the next entry */
rc = SyArchiveGetNextEntry(pArchive,&pNext);
if( rc != SXRET_OK ){
/* No more entries in the central directory,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return as a resource handle */
ph7_result_resource(pCtx,pNext);
/* Point to the ZIP raw data */
pNext->pUserData = (void *)&pArchive[1];
}
return PH7_OK;
}
/*
* bool zip_entry_open(resource $zip,resource $zip_entry[,string $mode ])
* Open a directory entry for reading
* Parameters
* $zip
* A ZIP file previously opened with zip_open().
* $zip_entry
* A directory entry returned by zip_read().
* $mode
* Not used
* Return
* A directory entry resource for later use with the zip_entry_... functions
* or FALSE if there are no more entries to read, or an error code if an error occurred.
*/
static int PH7_builtin_zip_entry_open(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
SyArchive *pArchive;
if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_resource(apArg[1]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the in-memory archive */
pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
/* Make sure we are dealing with a valid ZIP archive */
if( SXARCH_INVALID(pArchive) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[1]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* All done. Actually this function is a no-op,return TRUE */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/*
* bool zip_entry_close(resource $zip_entry)
* Close a directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* Returns TRUE on success or FALSE on failure.
*/
static int PH7_builtin_zip_entry_close(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Reset the read cursor */
pEntry->nReadCount = 0;
/*All done. Actually this function is a no-op,return TRUE */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/*
* string zip_entry_name(resource $zip_entry)
* Retrieve the name of a directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* The name of the directory entry.
*/
static int PH7_builtin_zip_entry_name(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
SyString *pName;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return entry name */
pName = &pEntry->sFileName;
ph7_result_string(pCtx,pName->zString,(int)pName->nByte);
return PH7_OK;
}
/*
* int64 zip_entry_filesize(resource $zip_entry)
* Retrieve the actual file size of a directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* The size of the directory entry.
*/
static int PH7_builtin_zip_entry_filesize(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return entry size */
ph7_result_int64(pCtx,(ph7_int64)pEntry->nByte);
return PH7_OK;
}
/*
* int64 zip_entry_compressedsize(resource $zip_entry)
* Retrieve the compressed size of a directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* The compressed size.
*/
static int PH7_builtin_zip_entry_compressedsize(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return entry compressed size */
ph7_result_int64(pCtx,(ph7_int64)pEntry->nByteCompr);
return PH7_OK;
}
/*
* string zip_entry_read(resource $zip_entry[,int $length])
* Reads from an open directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* $length
* The number of bytes to return. If not specified, this function
* will attempt to read 1024 bytes.
* Return
* Returns the data read, or FALSE if the end of the file is reached.
*/
static int PH7_builtin_zip_entry_read(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
zip_raw_data *pRaw;
const char *zData;
int iLength;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
zData = 0;
if( pEntry->nReadCount >= pEntry->nByteCompr ){
/* No more data to read,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Set a default read length */
iLength = 1024;
if( nArg > 1 ){
iLength = ph7_value_to_int(apArg[1]);
if( iLength < 1 ){
iLength = 1024;
}
}
if( (sxu32)iLength > pEntry->nByteCompr - pEntry->nReadCount ){
iLength = (int)(pEntry->nByteCompr - pEntry->nReadCount);
}
/* Return the entry contents */
pRaw = (zip_raw_data *)pEntry->pUserData;
if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){
zData = (const char *)SyBlobDataAt(&pRaw->raw.sBlob,(pEntry->nOfft+pEntry->nReadCount));
}else{
const char *zMap = (const char *)pRaw->raw.mmap.pMap;
/* Memory mmaped chunk */
zData = &zMap[pEntry->nOfft+pEntry->nReadCount];
}
/* Increment the read counter */
pEntry->nReadCount += iLength;
/* Return the raw data */
ph7_result_string(pCtx,zData,iLength);
return PH7_OK;
}
/*
* bool zip_entry_reset_read_cursor(resource $zip_entry)
* Reset the read cursor of an open directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* TRUE on success,FALSE on failure.
* Note that this is a symisc eXtension.
*/
static int PH7_builtin_zip_entry_reset_read_cursor(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Reset the cursor */
pEntry->nReadCount = 0;
/* Return TRUE */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
/*
* string zip_entry_compressionmethod(resource $zip_entry)
* Retrieve the compression method of a directory entry.
* Parameters
* $zip_entry
* A directory entry returned by zip_read().
* Return
* The compression method on success or FALSE on failure.
*/
static int PH7_builtin_zip_entry_compressionmethod(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyArchiveEntry *pEntry;
if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){
/* Missing/Invalid arguments */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Make sure we are dealing with a valid ZIP archive entry */
pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
if( SXARCH_ENTRY_INVALID(pEntry) ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry");
/* return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
switch(pEntry->nComprMeth){
case 0:
/* No compression;entry is stored */
ph7_result_string(pCtx,"stored",(int)sizeof("stored")-1);
break;
case 8:
/* Entry is deflated (Default compression algorithm) */
ph7_result_string(pCtx,"deflate",(int)sizeof("deflate")-1);
break;
/* Exotic compression algorithms */
case 1:
ph7_result_string(pCtx,"shrunk",(int)sizeof("shrunk")-1);
break;
case 2:
case 3:
case 4:
case 5:
/* Entry is reduced */
ph7_result_string(pCtx,"reduced",(int)sizeof("reduced")-1);
break;
case 6:
/* Entry is imploded */
ph7_result_string(pCtx,"implode",(int)sizeof("implode")-1);
break;
default:
ph7_result_string(pCtx,"unknown",(int)sizeof("unknown")-1);
break;
}
return PH7_OK;
}
#endif /* #ifndef PH7_DISABLE_BUILTIN_FUNC*/
/* NULL VFS [i.e: a no-op VFS]*/
static const ph7_vfs null_vfs = {
"null_vfs",
PH7_VFS_VERSION,
0, /* int (*xChdir)(const char *) */
0, /* int (*xChroot)(const char *); */
0, /* int (*xGetcwd)(ph7_context *) */
0, /* int (*xMkdir)(const char *,int,int) */
0, /* int (*xRmdir)(const char *) */
0, /* int (*xIsdir)(const char *) */
0, /* int (*xRename)(const char *,const char *) */
0, /*int (*xRealpath)(const char *,ph7_context *)*/
0, /* int (*xSleep)(unsigned int) */
0, /* int (*xUnlink)(const char *) */
0, /* int (*xFileExists)(const char *) */
0, /*int (*xChmod)(const char *,int)*/
0, /*int (*xChown)(const char *,const char *)*/
0, /*int (*xChgrp)(const char *,const char *)*/
0, /* ph7_int64 (*xFreeSpace)(const char *) */
0, /* ph7_int64 (*xTotalSpace)(const char *) */
0, /* ph7_int64 (*xFileSize)(const char *) */
0, /* ph7_int64 (*xFileAtime)(const char *) */
0, /* ph7_int64 (*xFileMtime)(const char *) */
0, /* ph7_int64 (*xFileCtime)(const char *) */
0, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
0, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
0, /* int (*xIsfile)(const char *) */
0, /* int (*xIslink)(const char *) */
0, /* int (*xReadable)(const char *) */
0, /* int (*xWritable)(const char *) */
0, /* int (*xExecutable)(const char *) */
0, /* int (*xFiletype)(const char *,ph7_context *) */
0, /* int (*xGetenv)(const char *,ph7_context *) */
0, /* int (*xSetenv)(const char *,const char *) */
0, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
0, /* int (*xMmap)(const char *,void **,ph7_int64 *) */
0, /* void (*xUnmap)(void *,ph7_int64); */
0, /* int (*xLink)(const char *,const char *,int) */
0, /* int (*xUmask)(int) */
0, /* void (*xTempDir)(ph7_context *) */
0, /* unsigned int (*xProcessId)(void) */
0, /* int (*xUid)(void) */
0, /* int (*xGid)(void) */
0, /* void (*xUsername)(ph7_context *) */
0 /* int (*xExec)(const char *,ph7_context *) */
};
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifndef PH7_DISABLE_DISK_IO
#ifdef __WINNT__
/*
* Windows VFS implementation for the PH7 engine.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/* What follows here is code that is specific to windows systems. */
#include <Windows.h>
/*
** Convert a UTF-8 string to microsoft unicode (UTF-16?).
**
** Space to hold the returned string is obtained from HeapAlloc().
** Taken from the sqlite3 source tree
** status: Public Domain
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar;
WCHAR *zWideFilename;
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0);
zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nChar*sizeof(zWideFilename[0]));
if( zWideFilename == 0 ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
if( nChar==0 ){
HeapFree(GetProcessHeap(),0,zWideFilename);
return 0;
}
return zWideFilename;
}
/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in.Space to hold the result
** is obtained from HeapAlloc() and must be freed by the calling
** function.
** Taken from the sqlite3 source tree
** status: Public Domain
*/
static void *convertUtf8Filename(const char *zFilename){
void *zConverted;
zConverted = utf8ToUnicode(zFilename);
return zConverted;
}
/*
** Convert microsoft unicode to UTF-8. Space to hold the returned string is
** obtained from HeapAlloc().
** Taken from the sqlite3 source tree
** status: Public Domain
*/
static char *unicodeToUtf8(const WCHAR *zWideFilename){
char *zFilename;
int nByte;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
zFilename = (char *)HeapAlloc(GetProcessHeap(),0,nByte);
if( zFilename == 0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,0, 0);
if( nByte == 0 ){
HeapFree(GetProcessHeap(),0,zFilename);
return 0;
}
return zFilename;
}
/* int (*xchdir)(const char *) */
static int WinVfs_chdir(const char *zPath)
{
void * pConverted;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
rc = SetCurrentDirectoryW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
return rc ? PH7_OK : -1;
}
/* int (*xGetcwd)(ph7_context *) */
static int WinVfs_getcwd(ph7_context *pCtx)
{
WCHAR zDir[2048];
char *zConverted;
DWORD rc;
/* Get the current directory */
rc = GetCurrentDirectoryW(sizeof(zDir),zDir);
if( rc < 1 ){
return -1;
}
zConverted = unicodeToUtf8(zDir);
if( zConverted == 0 ){
return -1;
}
ph7_result_string(pCtx,zConverted,-1/*Compute length automatically*/); /* Will make it's own copy */
HeapFree(GetProcessHeap(),0,zConverted);
return PH7_OK;
}
/* int (*xMkdir)(const char *,int,int) */
static int WinVfs_mkdir(const char *zPath,int mode,int recursive)
{
void * pConverted;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
mode= 0; /* MSVC warning */
recursive = 0;
rc = CreateDirectoryW((LPCWSTR)pConverted,0);
HeapFree(GetProcessHeap(),0,pConverted);
return rc ? PH7_OK : -1;
}
/* int (*xRmdir)(const char *) */
static int WinVfs_rmdir(const char *zPath)
{
void * pConverted;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
rc = RemoveDirectoryW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
return rc ? PH7_OK : -1;
}
/* int (*xIsdir)(const char *) */
static int WinVfs_isdir(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ? PH7_OK : -1;
}
/* int (*xRename)(const char *,const char *) */
static int WinVfs_Rename(const char *zOld,const char *zNew)
{
void *pOld,*pNew;
BOOL rc = 0;
pOld = convertUtf8Filename(zOld);
if( pOld == 0 ){
return -1;
}
pNew = convertUtf8Filename(zNew);
if( pNew ){
rc = MoveFileW((LPCWSTR)pOld,(LPCWSTR)pNew);
}
HeapFree(GetProcessHeap(),0,pOld);
if( pNew ){
HeapFree(GetProcessHeap(),0,pNew);
}
return rc ? PH7_OK : - 1;
}
/* int (*xRealpath)(const char *,ph7_context *) */
static int WinVfs_Realpath(const char *zPath,ph7_context *pCtx)
{
WCHAR zTemp[2048];
void *pPath;
char *zReal;
DWORD n;
pPath = convertUtf8Filename(zPath);
if( pPath == 0 ){
return -1;
}
n = GetFullPathNameW((LPCWSTR)pPath,0,0,0);
if( n > 0 ){
if( n >= sizeof(zTemp) ){
n = sizeof(zTemp) - 1;
}
GetFullPathNameW((LPCWSTR)pPath,n,zTemp,0);
}
HeapFree(GetProcessHeap(),0,pPath);
if( !n ){
return -1;
}
zReal = unicodeToUtf8(zTemp);
if( zReal == 0 ){
return -1;
}
ph7_result_string(pCtx,zReal,-1); /* Will make it's own copy */
HeapFree(GetProcessHeap(),0,zReal);
return PH7_OK;
}
/* int (*xSleep)(unsigned int) */
static int WinVfs_Sleep(unsigned int uSec)
{
Sleep(uSec/1000/*uSec per Millisec */);
return PH7_OK;
}
/* int (*xUnlink)(const char *) */
static int WinVfs_unlink(const char *zPath)
{
void * pConverted;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
rc = DeleteFileW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
return rc ? PH7_OK : - 1;
}
/* ph7_int64 (*xFreeSpace)(const char *) */
static ph7_int64 WinVfs_DiskFreeSpace(const char *zPath)
{
#ifdef _WIN32_WCE
/* GetDiskFreeSpace is not supported under WINCE */
SXUNUSED(zPath);
return 0;
#else
DWORD dwSectPerClust,dwBytesPerSect,dwFreeClusters,dwTotalClusters;
void * pConverted;
WCHAR *p;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return 0;
}
p = (WCHAR *)pConverted;
for(;*p;p++){
if( *p == '\\' || *p == '/'){
*p = '\0';
break;
}
}
rc = GetDiskFreeSpaceW((LPCWSTR)pConverted,&dwSectPerClust,&dwBytesPerSect,&dwFreeClusters,&dwTotalClusters);
if( !rc ){
return 0;
}
return (ph7_int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect;
#endif
}
/* ph7_int64 (*xTotalSpace)(const char *) */
static ph7_int64 WinVfs_DiskTotalSpace(const char *zPath)
{
#ifdef _WIN32_WCE
/* GetDiskFreeSpace is not supported under WINCE */
SXUNUSED(zPath);
return 0;
#else
DWORD dwSectPerClust,dwBytesPerSect,dwFreeClusters,dwTotalClusters;
void * pConverted;
WCHAR *p;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return 0;
}
p = (WCHAR *)pConverted;
for(;*p;p++){
if( *p == '\\' || *p == '/'){
*p = '\0';
break;
}
}
rc = GetDiskFreeSpaceW((LPCWSTR)pConverted,&dwSectPerClust,&dwBytesPerSect,&dwFreeClusters,&dwTotalClusters);
if( !rc ){
return 0;
}
return (ph7_int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect;
#endif
}
/* int (*xFileExists)(const char *) */
static int WinVfs_FileExists(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
return PH7_OK;
}
/* Open a file in a read-only mode */
static HANDLE OpenReadOnly(LPCWSTR pPath)
{
DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD dwAccess = GENERIC_READ;
DWORD dwCreate = OPEN_EXISTING;
HANDLE pHandle;
pHandle = CreateFileW(pPath,dwAccess,dwShare,0,dwCreate,dwType,0);
if( pHandle == INVALID_HANDLE_VALUE){
return 0;
}
return pHandle;
}
/* ph7_int64 (*xFileSize)(const char *) */
static ph7_int64 WinVfs_FileSize(const char *zPath)
{
DWORD dwLow,dwHigh;
void * pConverted;
ph7_int64 nSize;
HANDLE pHandle;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Open the file in read-only mode */
pHandle = OpenReadOnly((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( pHandle ){
dwLow = GetFileSize(pHandle,&dwHigh);
nSize = dwHigh;
nSize <<= 32;
nSize += dwLow;
CloseHandle(pHandle);
}else{
nSize = -1;
}
return nSize;
}
#define TICKS_PER_SECOND 10000000
#define EPOCH_DIFFERENCE 11644473600LL
/* Convert Windows timestamp to UNIX timestamp */
static ph7_int64 convertWindowsTimeToUnixTime(LPFILETIME pTime)
{
ph7_int64 input,temp;
input = pTime->dwHighDateTime;
input <<= 32;
input += pTime->dwLowDateTime;
temp = input / TICKS_PER_SECOND; /*convert from 100ns intervals to seconds*/
temp = temp - EPOCH_DIFFERENCE; /*subtract number of seconds between epochs*/
return temp;
}
/* Convert UNIX timestamp to Windows timestamp */
static void convertUnixTimeToWindowsTime(ph7_int64 nUnixtime,LPFILETIME pOut)
{
ph7_int64 result = EPOCH_DIFFERENCE;
result += nUnixtime;
result *= 10000000LL;
pOut->dwHighDateTime = (DWORD)(nUnixtime>>32);
pOut->dwLowDateTime = (DWORD)nUnixtime;
}
/* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
static int WinVfs_Touch(const char *zPath,ph7_int64 touch_time,ph7_int64 access_time)
{
FILETIME sTouch,sAccess;
void *pConverted;
void *pHandle;
BOOL rc = 0;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
pHandle = OpenReadOnly((LPCWSTR)pConverted);
if( pHandle ){
if( touch_time < 0 ){
GetSystemTimeAsFileTime(&sTouch);
}else{
convertUnixTimeToWindowsTime(touch_time,&sTouch);
}
if( access_time < 0 ){
/* Use the touch time */
sAccess = sTouch; /* Structure assignment */
}else{
convertUnixTimeToWindowsTime(access_time,&sAccess);
}
rc = SetFileTime(pHandle,&sTouch,&sAccess,0);
/* Close the handle */
CloseHandle(pHandle);
}
HeapFree(GetProcessHeap(),0,pConverted);
return rc ? PH7_OK : -1;
}
/* ph7_int64 (*xFileAtime)(const char *) */
static ph7_int64 WinVfs_FileAtime(const char *zPath)
{
BY_HANDLE_FILE_INFORMATION sInfo;
void * pConverted;
ph7_int64 atime;
HANDLE pHandle;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Open the file in read-only mode */
pHandle = OpenReadOnly((LPCWSTR)pConverted);
if( pHandle ){
BOOL rc;
rc = GetFileInformationByHandle(pHandle,&sInfo);
if( rc ){
atime = convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime);
}else{
atime = -1;
}
CloseHandle(pHandle);
}else{
atime = -1;
}
HeapFree(GetProcessHeap(),0,pConverted);
return atime;
}
/* ph7_int64 (*xFileMtime)(const char *) */
static ph7_int64 WinVfs_FileMtime(const char *zPath)
{
BY_HANDLE_FILE_INFORMATION sInfo;
void * pConverted;
ph7_int64 mtime;
HANDLE pHandle;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Open the file in read-only mode */
pHandle = OpenReadOnly((LPCWSTR)pConverted);
if( pHandle ){
BOOL rc;
rc = GetFileInformationByHandle(pHandle,&sInfo);
if( rc ){
mtime = convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime);
}else{
mtime = -1;
}
CloseHandle(pHandle);
}else{
mtime = -1;
}
HeapFree(GetProcessHeap(),0,pConverted);
return mtime;
}
/* ph7_int64 (*xFileCtime)(const char *) */
static ph7_int64 WinVfs_FileCtime(const char *zPath)
{
BY_HANDLE_FILE_INFORMATION sInfo;
void * pConverted;
ph7_int64 ctime;
HANDLE pHandle;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Open the file in read-only mode */
pHandle = OpenReadOnly((LPCWSTR)pConverted);
if( pHandle ){
BOOL rc;
rc = GetFileInformationByHandle(pHandle,&sInfo);
if( rc ){
ctime = convertWindowsTimeToUnixTime(&sInfo.ftCreationTime);
}else{
ctime = -1;
}
CloseHandle(pHandle);
}else{
ctime = -1;
}
HeapFree(GetProcessHeap(),0,pConverted);
return ctime;
}
/* int (*xStat)(const char *,ph7_value *,ph7_value *) */
/* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
static int WinVfs_Stat(const char *zPath,ph7_value *pArray,ph7_value *pWorker)
{
BY_HANDLE_FILE_INFORMATION sInfo;
void *pConverted;
HANDLE pHandle;
BOOL rc;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Open the file in read-only mode */
pHandle = OpenReadOnly((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( pHandle == 0 ){
return -1;
}
rc = GetFileInformationByHandle(pHandle,&sInfo);
CloseHandle(pHandle);
if( !rc ){
return -1;
}
/* dev */
ph7_value_int64(pWorker,(ph7_int64)sInfo.dwVolumeSerialNumber);
ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */
/* ino */
ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow));
ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */
/* mode */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"mode",pWorker);
/* nlink */
ph7_value_int(pWorker,(int)sInfo.nNumberOfLinks);
ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */
/* uid,gid,rdev */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"uid",pWorker);
ph7_array_add_strkey_elem(pArray,"gid",pWorker);
ph7_array_add_strkey_elem(pArray,"rdev",pWorker);
/* size */
ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow));
ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */
/* atime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime));
ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */
/* mtime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime));
ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */
/* ctime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftCreationTime));
ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */
/* blksize,blocks */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"blksize",pWorker);
ph7_array_add_strkey_elem(pArray,"blocks",pWorker);
return PH7_OK;
}
/* int (*xIsfile)(const char *) */
static int WinVfs_isfile(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
return (dwAttr & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE)) ? PH7_OK : -1;
}
/* int (*xIslink)(const char *) */
static int WinVfs_islink(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
return (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) ? PH7_OK : -1;
}
/* int (*xWritable)(const char *) */
static int WinVfs_iswritable(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
if( (dwAttr & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL)) == 0 ){
/* Not a regular file */
return -1;
}
if( dwAttr & FILE_ATTRIBUTE_READONLY ){
/* Read-only file */
return -1;
}
/* File is writable */
return PH7_OK;
}
/* int (*xExecutable)(const char *) */
static int WinVfs_isexecutable(const char *zPath)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
return -1;
}
if( (dwAttr & FILE_ATTRIBUTE_NORMAL) == 0 ){
/* Not a regular file */
return -1;
}
/* File is executable */
return PH7_OK;
}
/* int (*xFiletype)(const char *,ph7_context *) */
static int WinVfs_Filetype(const char *zPath,ph7_context *pCtx)
{
void * pConverted;
DWORD dwAttr;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
/* Expand 'unknown' */
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
return -1;
}
dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( dwAttr == INVALID_FILE_ATTRIBUTES ){
/* Expand 'unknown' */
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
return -1;
}
if(dwAttr & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE) ){
ph7_result_string(pCtx,"file",sizeof("file")-1);
}else if(dwAttr & FILE_ATTRIBUTE_DIRECTORY){
ph7_result_string(pCtx,"dir",sizeof("dir")-1);
}else if(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT){
ph7_result_string(pCtx,"link",sizeof("link")-1);
}else if(dwAttr & (FILE_ATTRIBUTE_DEVICE)){
ph7_result_string(pCtx,"block",sizeof("block")-1);
}else{
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
}
return PH7_OK;
}
/* int (*xGetenv)(const char *,ph7_context *) */
static int WinVfs_Getenv(const char *zVar,ph7_context *pCtx)
{
char zValue[1024];
DWORD n;
/*
* According to MSDN
* If lpBuffer is not large enough to hold the data, the return
* value is the buffer size, in characters, required to hold the
* string and its terminating null character and the contents
* of lpBuffer are undefined.
*/
n = sizeof(zValue);
SyMemcpy("Undefined",zValue,sizeof("Undefined")-1);
/* Extract the environment value */
n = GetEnvironmentVariableA(zVar,zValue,sizeof(zValue));
if( !n ){
/* No such variable*/
return -1;
}
ph7_result_string(pCtx,zValue,(int)n);
return PH7_OK;
}
/* int (*xSetenv)(const char *,const char *) */
static int WinVfs_Setenv(const char *zName,const char *zValue)
{
BOOL rc;
rc = SetEnvironmentVariableA(zName,zValue);
return rc ? PH7_OK : -1;
}
/* int (*xMmap)(const char *,void **,ph7_int64 *) */
static int WinVfs_Mmap(const char *zPath,void **ppMap,ph7_int64 *pSize)
{
DWORD dwSizeLow,dwSizeHigh;
HANDLE pHandle,pMapHandle;
void *pConverted,*pView;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
pHandle = OpenReadOnly((LPCWSTR)pConverted);
HeapFree(GetProcessHeap(),0,pConverted);
if( pHandle == 0 ){
return -1;
}
/* Get the file size */
dwSizeLow = GetFileSize(pHandle,&dwSizeHigh);
/* Create the mapping */
pMapHandle = CreateFileMappingW(pHandle,0,PAGE_READONLY,dwSizeHigh,dwSizeLow,0);
if( pMapHandle == 0 ){
CloseHandle(pHandle);
return -1;
}
*pSize = ((ph7_int64)dwSizeHigh << 32) | dwSizeLow;
/* Obtain the view */
pView = MapViewOfFile(pMapHandle,FILE_MAP_READ,0,0,(SIZE_T)(*pSize));
if( pView ){
/* Let the upper layer point to the view */
*ppMap = pView;
}
/* Close the handle
* According to MSDN it's OK the close the HANDLES.
*/
CloseHandle(pMapHandle);
CloseHandle(pHandle);
return pView ? PH7_OK : -1;
}
/* void (*xUnmap)(void *,ph7_int64) */
static void WinVfs_Unmap(void *pView,ph7_int64 nSize)
{
nSize = 0; /* Compiler warning */
UnmapViewOfFile(pView);
}
/* void (*xTempDir)(ph7_context *) */
static void WinVfs_TempDir(ph7_context *pCtx)
{
CHAR zTemp[1024];
DWORD n;
n = GetTempPathA(sizeof(zTemp),zTemp);
if( n < 1 ){
/* Assume the default windows temp directory */
ph7_result_string(pCtx,"C:\\Windows\\Temp",-1/*Compute length automatically*/);
}else{
ph7_result_string(pCtx,zTemp,(int)n);
}
}
/* unsigned int (*xProcessId)(void) */
static unsigned int WinVfs_ProcessId(void)
{
DWORD nID = 0;
#ifndef __MINGW32__
nID = GetProcessId(GetCurrentProcess());
#endif /* __MINGW32__ */
return (unsigned int)nID;
}
/* void (*xUsername)(ph7_context *) */
static void WinVfs_Username(ph7_context *pCtx)
{
WCHAR zUser[1024];
DWORD nByte;
BOOL rc;
nByte = sizeof(zUser);
rc = GetUserNameW(zUser,&nByte);
if( !rc ){
/* Set a dummy name */
ph7_result_string(pCtx,"Unknown",sizeof("Unknown")-1);
}else{
char *zName;
zName = unicodeToUtf8(zUser);
if( zName == 0 ){
ph7_result_string(pCtx,"Unknown",sizeof("Unknown")-1);
}else{
ph7_result_string(pCtx,zName,-1/*Compute length automatically*/); /* Will make it's own copy */
HeapFree(GetProcessHeap(),0,zName);
}
}
}
/* Export the windows vfs */
static const ph7_vfs sWinVfs = {
"Windows_vfs",
PH7_VFS_VERSION,
WinVfs_chdir, /* int (*xChdir)(const char *) */
0, /* int (*xChroot)(const char *); */
WinVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */
WinVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */
WinVfs_rmdir, /* int (*xRmdir)(const char *) */
WinVfs_isdir, /* int (*xIsdir)(const char *) */
WinVfs_Rename, /* int (*xRename)(const char *,const char *) */
WinVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/
WinVfs_Sleep, /* int (*xSleep)(unsigned int) */
WinVfs_unlink, /* int (*xUnlink)(const char *) */
WinVfs_FileExists, /* int (*xFileExists)(const char *) */
0, /*int (*xChmod)(const char *,int)*/
0, /*int (*xChown)(const char *,const char *)*/
0, /*int (*xChgrp)(const char *,const char *)*/
WinVfs_DiskFreeSpace,/* ph7_int64 (*xFreeSpace)(const char *) */
WinVfs_DiskTotalSpace,/* ph7_int64 (*xTotalSpace)(const char *) */
WinVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */
WinVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */
WinVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */
WinVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */
WinVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
WinVfs_Stat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
WinVfs_isfile, /* int (*xIsfile)(const char *) */
WinVfs_islink, /* int (*xIslink)(const char *) */
WinVfs_isfile, /* int (*xReadable)(const char *) */
WinVfs_iswritable, /* int (*xWritable)(const char *) */
WinVfs_isexecutable, /* int (*xExecutable)(const char *) */
WinVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */
WinVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */
WinVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */
WinVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
WinVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */
WinVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */
0, /* int (*xLink)(const char *,const char *,int) */
0, /* int (*xUmask)(int) */
WinVfs_TempDir, /* void (*xTempDir)(ph7_context *) */
WinVfs_ProcessId, /* unsigned int (*xProcessId)(void) */
0, /* int (*xUid)(void) */
0, /* int (*xGid)(void) */
WinVfs_Username, /* void (*xUsername)(ph7_context *) */
0 /* int (*xExec)(const char *,ph7_context *) */
};
/* Windows file IO */
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/* int (*xOpen)(const char *,int,ph7_value *,void **) */
static int WinFile_Open(const char *zPath,int iOpenMode,ph7_value *pResource,void **ppHandle)
{
DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
DWORD dwAccess = GENERIC_READ;
DWORD dwShare,dwCreate;
void *pConverted;
HANDLE pHandle;
pConverted = convertUtf8Filename(zPath);
if( pConverted == 0 ){
return -1;
}
/* Set the desired flags according to the open mode */
if( iOpenMode & PH7_IO_OPEN_CREATE ){
/* Open existing file, or create if it doesn't exist */
dwCreate = OPEN_ALWAYS;
if( iOpenMode & PH7_IO_OPEN_TRUNC ){
/* If the specified file exists and is writable, the function overwrites the file */
dwCreate = CREATE_ALWAYS;
}
}else if( iOpenMode & PH7_IO_OPEN_EXCL ){
/* Creates a new file, only if it does not already exist.
* If the file exists, it fails.
*/
dwCreate = CREATE_NEW;
}else if( iOpenMode & PH7_IO_OPEN_TRUNC ){
/* Opens a file and truncates it so that its size is zero bytes
* The file must exist.
*/
dwCreate = TRUNCATE_EXISTING;
}else{
/* Opens a file, only if it exists. */
dwCreate = OPEN_EXISTING;
}
if( iOpenMode & PH7_IO_OPEN_RDWR ){
/* Read+Write access */
dwAccess |= GENERIC_WRITE;
}else if( iOpenMode & PH7_IO_OPEN_WRONLY ){
/* Write only access */
dwAccess = GENERIC_WRITE;
}
if( iOpenMode & PH7_IO_OPEN_APPEND ){
/* Append mode */
dwAccess = FILE_APPEND_DATA;
}
if( iOpenMode & PH7_IO_OPEN_TEMP ){
/* File is temporary */
dwType = FILE_ATTRIBUTE_TEMPORARY;
}
dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
pHandle = CreateFileW((LPCWSTR)pConverted,dwAccess,dwShare,0,dwCreate,dwType,0);
HeapFree(GetProcessHeap(),0,pConverted);
if( pHandle == INVALID_HANDLE_VALUE){
SXUNUSED(pResource); /* MSVC warning */
return -1;
}
/* Make the handle accessible to the upper layer */
*ppHandle = (void *)pHandle;
return PH7_OK;
}
/* An instance of the following structure is used to record state information
* while iterating throw directory entries.
*/
typedef struct WinDir_Info WinDir_Info;
struct WinDir_Info
{
HANDLE pDirHandle;
void *pPath;
WIN32_FIND_DATAW sInfo;
int rc;
};
/* int (*xOpenDir)(const char *,ph7_value *,void **) */
static int WinDir_Open(const char *zPath,ph7_value *pResource,void **ppHandle)
{
WinDir_Info *pDirInfo;
void *pConverted;
char *zPrep;
sxu32 n;
/* Prepare the path */
n = SyStrlen(zPath);
zPrep = (char *)HeapAlloc(GetProcessHeap(),0,n+sizeof("\\*")+4);
if( zPrep == 0 ){
return -1;
}
SyMemcpy((const void *)zPath,zPrep,n);
zPrep[n] = '\\';
zPrep[n+1] = '*';
zPrep[n+2] = 0;
pConverted = convertUtf8Filename(zPrep);
HeapFree(GetProcessHeap(),0,zPrep);
if( pConverted == 0 ){
return -1;
}
/* Allocate a new instance */
pDirInfo = (WinDir_Info *)HeapAlloc(GetProcessHeap(),0,sizeof(WinDir_Info));
if( pDirInfo == 0 ){
pResource = 0; /* Compiler warning */
return -1;
}
pDirInfo->rc = SXRET_OK;
pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pConverted,&pDirInfo->sInfo);
if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){
/* Cannot open directory */
HeapFree(GetProcessHeap(),0,pConverted);
HeapFree(GetProcessHeap(),0,pDirInfo);
return -1;
}
/* Save the path */
pDirInfo->pPath = pConverted;
/* Save our structure */
*ppHandle = pDirInfo;
return PH7_OK;
}
/* void (*xCloseDir)(void *) */
static void WinDir_Close(void *pUserData)
{
WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
if( pDirInfo->pDirHandle != INVALID_HANDLE_VALUE ){
FindClose(pDirInfo->pDirHandle);
}
HeapFree(GetProcessHeap(),0,pDirInfo->pPath);
HeapFree(GetProcessHeap(),0,pDirInfo);
}
/* void (*xClose)(void *); */
static void WinFile_Close(void *pUserData)
{
HANDLE pHandle = (HANDLE)pUserData;
CloseHandle(pHandle);
}
/* int (*xReadDir)(void *,ph7_context *) */
static int WinDir_Read(void *pUserData,ph7_context *pCtx)
{
WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
LPWIN32_FIND_DATAW pData;
char *zName;
BOOL rc;
sxu32 n;
if( pDirInfo->rc != SXRET_OK ){
/* No more entry to process */
return -1;
}
pData = &pDirInfo->sInfo;
for(;;){
zName = unicodeToUtf8(pData->cFileName);
if( zName == 0 ){
/* Out of memory */
return -1;
}
n = SyStrlen(zName);
/* Ignore '.' && '..' */
if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){
break;
}
HeapFree(GetProcessHeap(),0,zName);
rc = FindNextFileW(pDirInfo->pDirHandle,&pDirInfo->sInfo);
if( !rc ){
return -1;
}
}
/* Return the current file name */
ph7_result_string(pCtx,zName,-1);
HeapFree(GetProcessHeap(),0,zName);
/* Point to the next entry */
rc = FindNextFileW(pDirInfo->pDirHandle,&pDirInfo->sInfo);
if( !rc ){
pDirInfo->rc = SXERR_EOF;
}
return PH7_OK;
}
/* void (*xRewindDir)(void *) */
static void WinDir_RewindDir(void *pUserData)
{
WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
FindClose(pDirInfo->pDirHandle);
pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pDirInfo->pPath,&pDirInfo->sInfo);
if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){
pDirInfo->rc = SXERR_EOF;
}else{
pDirInfo->rc = SXRET_OK;
}
}
/* ph7_int64 (*xRead)(void *,void *,ph7_int64); */
static ph7_int64 WinFile_Read(void *pOS,void *pBuffer,ph7_int64 nDatatoRead)
{
HANDLE pHandle = (HANDLE)pOS;
DWORD nRd;
BOOL rc;
rc = ReadFile(pHandle,pBuffer,(DWORD)nDatatoRead,&nRd,0);
if( !rc ){
/* EOF or IO error */
return -1;
}
return (ph7_int64)nRd;
}
/* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */
static ph7_int64 WinFile_Write(void *pOS,const void *pBuffer,ph7_int64 nWrite)
{
const char *zData = (const char *)pBuffer;
HANDLE pHandle = (HANDLE)pOS;
ph7_int64 nCount;
DWORD nWr;
BOOL rc;
nWr = 0;
nCount = 0;
for(;;){
if( nWrite < 1 ){
break;
}
rc = WriteFile(pHandle,zData,(DWORD)nWrite,&nWr,0);
if( !rc ){
/* IO error */
break;
}
nWrite -= nWr;
nCount += nWr;
zData += nWr;
}
if( nWrite > 0 ){
return -1;
}
return nCount;
}
/* int (*xSeek)(void *,ph7_int64,int) */
static int WinFile_Seek(void *pUserData,ph7_int64 iOfft,int whence)
{
HANDLE pHandle = (HANDLE)pUserData;
DWORD dwMove,dwNew;
LONG nHighOfft;
switch(whence){
case 1:/*SEEK_CUR*/
dwMove = FILE_CURRENT;
break;
case 2: /* SEEK_END */
dwMove = FILE_END;
break;
case 0: /* SEEK_SET */
default:
dwMove = FILE_BEGIN;
break;
}
nHighOfft = (LONG)(iOfft >> 32);
dwNew = SetFilePointer(pHandle,(LONG)iOfft,&nHighOfft,dwMove);
if( dwNew == INVALID_SET_FILE_POINTER ){
return -1;
}
return PH7_OK;
}
/* int (*xLock)(void *,int) */
static int WinFile_Lock(void *pUserData,int lock_type)
{
HANDLE pHandle = (HANDLE)pUserData;
static DWORD dwLo = 0,dwHi = 0; /* xx: MT-SAFE */
OVERLAPPED sDummy;
BOOL rc;
SyZero(&sDummy,sizeof(sDummy));
/* Get the file size */
if( lock_type < 1 ){
/* Unlock the file */
rc = UnlockFileEx(pHandle,0,dwLo,dwHi,&sDummy);
}else{
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; /* Shared non-blocking lock by default*/
/* Lock the file */
if( lock_type == 1 /* LOCK_EXCL */ ){
dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
}
dwLo = GetFileSize(pHandle,&dwHi);
rc = LockFileEx(pHandle,dwFlags,0,dwLo,dwHi,&sDummy);
}
return rc ? PH7_OK : -1 /* Lock error */;
}
/* ph7_int64 (*xTell)(void *) */
static ph7_int64 WinFile_Tell(void *pUserData)
{
HANDLE pHandle = (HANDLE)pUserData;
DWORD dwNew;
dwNew = SetFilePointer(pHandle,0,0,FILE_CURRENT/* SEEK_CUR */);
if( dwNew == INVALID_SET_FILE_POINTER ){
return -1;
}
return (ph7_int64)dwNew;
}
/* int (*xTrunc)(void *,ph7_int64) */
static int WinFile_Trunc(void *pUserData,ph7_int64 nOfft)
{
HANDLE pHandle = (HANDLE)pUserData;
LONG HighOfft;
DWORD dwNew;
BOOL rc;
HighOfft = (LONG)(nOfft >> 32);
dwNew = SetFilePointer(pHandle,(LONG)nOfft,&HighOfft,FILE_BEGIN);
if( dwNew == INVALID_SET_FILE_POINTER ){
return -1;
}
rc = SetEndOfFile(pHandle);
return rc ? PH7_OK : -1;
}
/* int (*xSync)(void *); */
static int WinFile_Sync(void *pUserData)
{
HANDLE pHandle = (HANDLE)pUserData;
BOOL rc;
rc = FlushFileBuffers(pHandle);
return rc ? PH7_OK : - 1;
}
/* int (*xStat)(void *,ph7_value *,ph7_value *) */
static int WinFile_Stat(void *pUserData,ph7_value *pArray,ph7_value *pWorker)
{
BY_HANDLE_FILE_INFORMATION sInfo;
HANDLE pHandle = (HANDLE)pUserData;
BOOL rc;
rc = GetFileInformationByHandle(pHandle,&sInfo);
if( !rc ){
return -1;
}
/* dev */
ph7_value_int64(pWorker,(ph7_int64)sInfo.dwVolumeSerialNumber);
ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */
/* ino */
ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow));
ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */
/* mode */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"mode",pWorker);
/* nlink */
ph7_value_int(pWorker,(int)sInfo.nNumberOfLinks);
ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */
/* uid,gid,rdev */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"uid",pWorker);
ph7_array_add_strkey_elem(pArray,"gid",pWorker);
ph7_array_add_strkey_elem(pArray,"rdev",pWorker);
/* size */
ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow));
ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */
/* atime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime));
ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */
/* mtime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime));
ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */
/* ctime */
ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftCreationTime));
ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */
/* blksize,blocks */
ph7_value_int(pWorker,0);
ph7_array_add_strkey_elem(pArray,"blksize",pWorker);
ph7_array_add_strkey_elem(pArray,"blocks",pWorker);
return PH7_OK;
}
/* Export the file:// stream */
static const ph7_io_stream sWinFileStream = {
"file", /* Stream name */
PH7_IO_STREAM_VERSION,
WinFile_Open, /* xOpen */
WinDir_Open, /* xOpenDir */
WinFile_Close, /* xClose */
WinDir_Close, /* xCloseDir */
WinFile_Read, /* xRead */
WinDir_Read, /* xReadDir */
WinFile_Write, /* xWrite */
WinFile_Seek, /* xSeek */
WinFile_Lock, /* xLock */
WinDir_RewindDir, /* xRewindDir */
WinFile_Tell, /* xTell */
WinFile_Trunc, /* xTrunc */
WinFile_Sync, /* xSeek */
WinFile_Stat /* xStat */
};
#elif defined(__UNIXES__)
/*
* UNIX VFS implementation for the PH7 engine.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
#include <sys/types.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
#include <utime.h>
#include <stdio.h>
#include <stdlib.h>
/* int (*xchdir)(const char *) */
static int UnixVfs_chdir(const char *zPath)
{
int rc;
rc = chdir(zPath);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xGetcwd)(ph7_context *) */
static int UnixVfs_getcwd(ph7_context *pCtx)
{
char zBuf[4096];
char *zDir;
/* Get the current directory */
zDir = getcwd(zBuf,sizeof(zBuf));
if( zDir == 0 ){
return -1;
}
ph7_result_string(pCtx,zDir,-1/*Compute length automatically*/);
return PH7_OK;
}
/* int (*xMkdir)(const char *,int,int) */
static int UnixVfs_mkdir(const char *zPath,int mode,int recursive)
{
int rc;
rc = mkdir(zPath,mode);
recursive = 0; /* cc warning */
return rc == 0 ? PH7_OK : -1;
}
/* int (*xRmdir)(const char *) */
static int UnixVfs_rmdir(const char *zPath)
{
int rc;
rc = rmdir(zPath);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xIsdir)(const char *) */
static int UnixVfs_isdir(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
rc = S_ISDIR(st.st_mode);
return rc ? PH7_OK : -1 ;
}
/* int (*xRename)(const char *,const char *) */
static int UnixVfs_Rename(const char *zOld,const char *zNew)
{
int rc;
rc = rename(zOld,zNew);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xRealpath)(const char *,ph7_context *) */
static int UnixVfs_Realpath(const char *zPath,ph7_context *pCtx)
{
#ifndef PH7_UNIX_OLD_LIBC
char *zReal;
zReal = realpath(zPath,0);
if( zReal == 0 ){
return -1;
}
ph7_result_string(pCtx,zReal,-1/*Compute length automatically*/);
/* Release the allocated buffer */
free(zReal);
return PH7_OK;
#else
zPath = 0; /* cc warning */
pCtx = 0;
return -1;
#endif
}
/* int (*xSleep)(unsigned int) */
static int UnixVfs_Sleep(unsigned int uSec)
{
usleep(uSec);
return PH7_OK;
}
/* int (*xUnlink)(const char *) */
static int UnixVfs_unlink(const char *zPath)
{
int rc;
rc = unlink(zPath);
return rc == 0 ? PH7_OK : -1 ;
}
/* int (*xFileExists)(const char *) */
static int UnixVfs_FileExists(const char *zPath)
{
int rc;
rc = access(zPath,F_OK);
return rc == 0 ? PH7_OK : -1;
}
/* ph7_int64 (*xFileSize)(const char *) */
static ph7_int64 UnixVfs_FileSize(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
return (ph7_int64)st.st_size;
}
/* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
static int UnixVfs_Touch(const char *zPath,ph7_int64 touch_time,ph7_int64 access_time)
{
struct utimbuf ut;
int rc;
ut.actime = (time_t)access_time;
ut.modtime = (time_t)touch_time;
rc = utime(zPath,&ut);
if( rc != 0 ){
return -1;
}
return PH7_OK;
}
/* ph7_int64 (*xFileAtime)(const char *) */
static ph7_int64 UnixVfs_FileAtime(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
return (ph7_int64)st.st_atime;
}
/* ph7_int64 (*xFileMtime)(const char *) */
static ph7_int64 UnixVfs_FileMtime(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
return (ph7_int64)st.st_mtime;
}
/* ph7_int64 (*xFileCtime)(const char *) */
static ph7_int64 UnixVfs_FileCtime(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
return (ph7_int64)st.st_ctime;
}
/* int (*xStat)(const char *,ph7_value *,ph7_value *) */
static int UnixVfs_Stat(const char *zPath,ph7_value *pArray,ph7_value *pWorker)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
/* dev */
ph7_value_int64(pWorker,(ph7_int64)st.st_dev);
ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */
/* ino */
ph7_value_int64(pWorker,(ph7_int64)st.st_ino);
ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */
/* mode */
ph7_value_int(pWorker,(int)st.st_mode);
ph7_array_add_strkey_elem(pArray,"mode",pWorker);
/* nlink */
ph7_value_int(pWorker,(int)st.st_nlink);
ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */
/* uid,gid,rdev */
ph7_value_int(pWorker,(int)st.st_uid);
ph7_array_add_strkey_elem(pArray,"uid",pWorker);
ph7_value_int(pWorker,(int)st.st_gid);
ph7_array_add_strkey_elem(pArray,"gid",pWorker);
ph7_value_int(pWorker,(int)st.st_rdev);
ph7_array_add_strkey_elem(pArray,"rdev",pWorker);
/* size */
ph7_value_int64(pWorker,(ph7_int64)st.st_size);
ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */
/* atime */
ph7_value_int64(pWorker,(ph7_int64)st.st_atime);
ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */
/* mtime */
ph7_value_int64(pWorker,(ph7_int64)st.st_mtime);
ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */
/* ctime */
ph7_value_int64(pWorker,(ph7_int64)st.st_ctime);
ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */
/* blksize,blocks */
ph7_value_int(pWorker,(int)st.st_blksize);
ph7_array_add_strkey_elem(pArray,"blksize",pWorker);
ph7_value_int(pWorker,(int)st.st_blocks);
ph7_array_add_strkey_elem(pArray,"blocks",pWorker);
return PH7_OK;
}
/* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
static int UnixVfs_lStat(const char *zPath,ph7_value *pArray,ph7_value *pWorker)
{
struct stat st;
int rc;
rc = lstat(zPath,&st);
if( rc != 0 ){
return -1;
}
/* dev */
ph7_value_int64(pWorker,(ph7_int64)st.st_dev);
ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */
/* ino */
ph7_value_int64(pWorker,(ph7_int64)st.st_ino);
ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */
/* mode */
ph7_value_int(pWorker,(int)st.st_mode);
ph7_array_add_strkey_elem(pArray,"mode",pWorker);
/* nlink */
ph7_value_int(pWorker,(int)st.st_nlink);
ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */
/* uid,gid,rdev */
ph7_value_int(pWorker,(int)st.st_uid);
ph7_array_add_strkey_elem(pArray,"uid",pWorker);
ph7_value_int(pWorker,(int)st.st_gid);
ph7_array_add_strkey_elem(pArray,"gid",pWorker);
ph7_value_int(pWorker,(int)st.st_rdev);
ph7_array_add_strkey_elem(pArray,"rdev",pWorker);
/* size */
ph7_value_int64(pWorker,(ph7_int64)st.st_size);
ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */
/* atime */
ph7_value_int64(pWorker,(ph7_int64)st.st_atime);
ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */
/* mtime */
ph7_value_int64(pWorker,(ph7_int64)st.st_mtime);
ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */
/* ctime */
ph7_value_int64(pWorker,(ph7_int64)st.st_ctime);
ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */
/* blksize,blocks */
ph7_value_int(pWorker,(int)st.st_blksize);
ph7_array_add_strkey_elem(pArray,"blksize",pWorker);
ph7_value_int(pWorker,(int)st.st_blocks);
ph7_array_add_strkey_elem(pArray,"blocks",pWorker);
return PH7_OK;
}
/* int (*xChmod)(const char *,int) */
static int UnixVfs_Chmod(const char *zPath,int mode)
{
int rc;
rc = chmod(zPath,(mode_t)mode);
return rc == 0 ? PH7_OK : - 1;
}
/* int (*xChown)(const char *,const char *) */
static int UnixVfs_Chown(const char *zPath,const char *zUser)
{
#ifndef PH7_UNIX_STATIC_BUILD
struct passwd *pwd;
uid_t uid;
int rc;
pwd = getpwnam(zUser); /* Try getting UID for username */
if (pwd == 0) {
return -1;
}
uid = pwd->pw_uid;
rc = chown(zPath,uid,-1);
return rc == 0 ? PH7_OK : -1;
#else
SXUNUSED(zPath);
SXUNUSED(zUser);
return -1;
#endif /* PH7_UNIX_STATIC_BUILD */
}
/* int (*xChgrp)(const char *,const char *) */
static int UnixVfs_Chgrp(const char *zPath,const char *zGroup)
{
#ifndef PH7_UNIX_STATIC_BUILD
struct group *group;
gid_t gid;
int rc;
group = getgrnam(zGroup);
if (group == 0) {
return -1;
}
gid = group->gr_gid;
rc = chown(zPath,-1,gid);
return rc == 0 ? PH7_OK : -1;
#else
SXUNUSED(zPath);
SXUNUSED(zGroup);
return -1;
#endif /* PH7_UNIX_STATIC_BUILD */
}
/* int (*xIsfile)(const char *) */
static int UnixVfs_isfile(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
rc = S_ISREG(st.st_mode);
return rc ? PH7_OK : -1 ;
}
/* int (*xIslink)(const char *) */
static int UnixVfs_islink(const char *zPath)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
return -1;
}
rc = S_ISLNK(st.st_mode);
return rc ? PH7_OK : -1 ;
}
/* int (*xReadable)(const char *) */
static int UnixVfs_isreadable(const char *zPath)
{
int rc;
rc = access(zPath,R_OK);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xWritable)(const char *) */
static int UnixVfs_iswritable(const char *zPath)
{
int rc;
rc = access(zPath,W_OK);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xExecutable)(const char *) */
static int UnixVfs_isexecutable(const char *zPath)
{
int rc;
rc = access(zPath,X_OK);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xFiletype)(const char *,ph7_context *) */
static int UnixVfs_Filetype(const char *zPath,ph7_context *pCtx)
{
struct stat st;
int rc;
rc = stat(zPath,&st);
if( rc != 0 ){
/* Expand 'unknown' */
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
return -1;
}
if(S_ISREG(st.st_mode) ){
ph7_result_string(pCtx,"file",sizeof("file")-1);
}else if(S_ISDIR(st.st_mode)){
ph7_result_string(pCtx,"dir",sizeof("dir")-1);
}else if(S_ISLNK(st.st_mode)){
ph7_result_string(pCtx,"link",sizeof("link")-1);
}else if(S_ISBLK(st.st_mode)){
ph7_result_string(pCtx,"block",sizeof("block")-1);
}else if(S_ISSOCK(st.st_mode)){
ph7_result_string(pCtx,"socket",sizeof("socket")-1);
}else if(S_ISFIFO(st.st_mode)){
ph7_result_string(pCtx,"fifo",sizeof("fifo")-1);
}else{
ph7_result_string(pCtx,"unknown",sizeof("unknown")-1);
}
return PH7_OK;
}
/* int (*xGetenv)(const char *,ph7_context *) */
static int UnixVfs_Getenv(const char *zVar,ph7_context *pCtx)
{
char *zEnv;
zEnv = getenv(zVar);
if( zEnv == 0 ){
return -1;
}
ph7_result_string(pCtx,zEnv,-1/*Compute length automatically*/);
return PH7_OK;
}
/* int (*xSetenv)(const char *,const char *) */
static int UnixVfs_Setenv(const char *zName,const char *zValue)
{
int rc;
rc = setenv(zName,zValue,1);
return rc == 0 ? PH7_OK : -1;
}
/* int (*xMmap)(const char *,void **,ph7_int64 *) */
static int UnixVfs_Mmap(const char *zPath,void **ppMap,ph7_int64 *pSize)
{
struct stat st;
void *pMap;
int fd;
int rc;
/* Open the file in a read-only mode */
fd = open(zPath,O_RDONLY);
if( fd < 0 ){
return -1;
}
/* stat the handle */
fstat(fd,&st);
/* Obtain a memory view of the whole file */
pMap = mmap(0,st.st_size,PROT_READ,MAP_PRIVATE|MAP_FILE,fd,0);
rc = PH7_OK;
if( pMap == MAP_FAILED ){
rc = -1;
}else{
/* Point to the memory view */
*ppMap = pMap;
*pSize = (ph7_int64)st.st_size;
}
close(fd);
return rc;
}
/* void (*xUnmap)(void *,ph7_int64) */
static void UnixVfs_Unmap(void *pView,ph7_int64 nSize)
{
munmap(pView,(size_t)nSize);
}
/* void (*xTempDir)(ph7_context *) */
static void UnixVfs_TempDir(ph7_context *pCtx)
{
static const char *azDirs[] = {
"/var/tmp",
"/usr/tmp",
"/usr/local/tmp"
};
unsigned int i;
struct stat buf;
const char *zDir;
zDir = getenv("TMPDIR");
if( zDir && zDir[0] != 0 && !access(zDir,07) ){
ph7_result_string(pCtx,zDir,-1);
return;
}
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
zDir=azDirs[i];
if( zDir==0 ) continue;
if( stat(zDir, &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
if( access(zDir, 07) ) continue;
/* Got one */
ph7_result_string(pCtx,zDir,-1);
return;
}
/* Default temp dir */
ph7_result_string(pCtx,"/tmp",(int)sizeof("/tmp")-1);
}
/* unsigned int (*xProcessId)(void) */
static unsigned int UnixVfs_ProcessId(void)
{
return (unsigned int)getpid();
}
/* int (*xUid)(void) */
static int UnixVfs_uid(void)
{
return (int)getuid();
}
/* int (*xGid)(void) */
static int UnixVfs_gid(void)
{
return (int)getgid();
}
/* int (*xUmask)(int) */
static int UnixVfs_Umask(int new_mask)
{
int old_mask;
old_mask = umask(new_mask);
return old_mask;
}
/* void (*xUsername)(ph7_context *) */
static void UnixVfs_Username(ph7_context *pCtx)
{
#ifndef PH7_UNIX_STATIC_BUILD
struct passwd *pwd;
uid_t uid;
uid = getuid();
pwd = getpwuid(uid); /* Try getting UID for username */
if (pwd == 0) {
return;
}
/* Return the username */
ph7_result_string(pCtx,pwd->pw_name,-1);
#else
ph7_result_string(pCtx,"Unknown",-1);
#endif /* PH7_UNIX_STATIC_BUILD */
return;
}
/* int (*xLink)(const char *,const char *,int) */
static int UnixVfs_link(const char *zSrc,const char *zTarget,int is_sym)
{
int rc;
if( is_sym ){
/* Symbolic link */
rc = symlink(zSrc,zTarget);
}else{
/* Hard link */
rc = link(zSrc,zTarget);
}
return rc == 0 ? PH7_OK : -1;
}
/* int (*xChroot)(const char *) */
static int UnixVfs_chroot(const char *zRootDir)
{
int rc;
rc = chroot(zRootDir);
return rc == 0 ? PH7_OK : -1;
}
/* Export the UNIX vfs */
static const ph7_vfs sUnixVfs = {
"Unix_vfs",
PH7_VFS_VERSION,
UnixVfs_chdir, /* int (*xChdir)(const char *) */
UnixVfs_chroot, /* int (*xChroot)(const char *); */
UnixVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */
UnixVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */
UnixVfs_rmdir, /* int (*xRmdir)(const char *) */
UnixVfs_isdir, /* int (*xIsdir)(const char *) */
UnixVfs_Rename, /* int (*xRename)(const char *,const char *) */
UnixVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/
UnixVfs_Sleep, /* int (*xSleep)(unsigned int) */
UnixVfs_unlink, /* int (*xUnlink)(const char *) */
UnixVfs_FileExists, /* int (*xFileExists)(const char *) */
UnixVfs_Chmod, /*int (*xChmod)(const char *,int)*/
UnixVfs_Chown, /*int (*xChown)(const char *,const char *)*/
UnixVfs_Chgrp, /*int (*xChgrp)(const char *,const char *)*/
0, /* ph7_int64 (*xFreeSpace)(const char *) */
0, /* ph7_int64 (*xTotalSpace)(const char *) */
UnixVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */
UnixVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */
UnixVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */
UnixVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */
UnixVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
UnixVfs_lStat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
UnixVfs_isfile, /* int (*xIsfile)(const char *) */
UnixVfs_islink, /* int (*xIslink)(const char *) */
UnixVfs_isreadable, /* int (*xReadable)(const char *) */
UnixVfs_iswritable, /* int (*xWritable)(const char *) */
UnixVfs_isexecutable,/* int (*xExecutable)(const char *) */
UnixVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */
UnixVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */
UnixVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */
UnixVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
UnixVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */
UnixVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */
UnixVfs_link, /* int (*xLink)(const char *,const char *,int) */
UnixVfs_Umask, /* int (*xUmask)(int) */
UnixVfs_TempDir, /* void (*xTempDir)(ph7_context *) */
UnixVfs_ProcessId, /* unsigned int (*xProcessId)(void) */
UnixVfs_uid, /* int (*xUid)(void) */
UnixVfs_gid, /* int (*xGid)(void) */
UnixVfs_Username, /* void (*xUsername)(ph7_context *) */
0 /* int (*xExec)(const char *,ph7_context *) */
};
/* UNIX File IO */
#define PH7_UNIX_OPEN_MODE 0640 /* Default open mode */
/* int (*xOpen)(const char *,int,ph7_value *,void **) */
static int UnixFile_Open(const char *zPath,int iOpenMode,ph7_value *pResource,void **ppHandle)
{
int iOpen = O_RDONLY;
int fd;
/* Set the desired flags according to the open mode */
if( iOpenMode & PH7_IO_OPEN_CREATE ){
/* Open existing file, or create if it doesn't exist */
iOpen = O_CREAT;
if( iOpenMode & PH7_IO_OPEN_TRUNC ){
/* If the specified file exists and is writable, the function overwrites the file */
iOpen |= O_TRUNC;
SXUNUSED(pResource); /* cc warning */
}
}else if( iOpenMode & PH7_IO_OPEN_EXCL ){
/* Creates a new file, only if it does not already exist.
* If the file exists, it fails.
*/
iOpen = O_CREAT|O_EXCL;
}else if( iOpenMode & PH7_IO_OPEN_TRUNC ){
/* Opens a file and truncates it so that its size is zero bytes
* The file must exist.
*/
iOpen = O_RDWR|O_TRUNC;
}
if( iOpenMode & PH7_IO_OPEN_RDWR ){
/* Read+Write access */
iOpen &= ~O_RDONLY;
iOpen |= O_RDWR;
}else if( iOpenMode & PH7_IO_OPEN_WRONLY ){
/* Write only access */
iOpen &= ~O_RDONLY;
iOpen |= O_WRONLY;
}
if( iOpenMode & PH7_IO_OPEN_APPEND ){
/* Append mode */
iOpen |= O_APPEND;
}
#ifdef O_TEMP
if( iOpenMode & PH7_IO_OPEN_TEMP ){
/* File is temporary */
iOpen |= O_TEMP;
}
#endif
/* Open the file now */
fd = open(zPath,iOpen,PH7_UNIX_OPEN_MODE);
if( fd < 0 ){
/* IO error */
return -1;
}
/* Save the handle */
*ppHandle = SX_INT_TO_PTR(fd);
return PH7_OK;
}
/* int (*xOpenDir)(const char *,ph7_value *,void **) */
static int UnixDir_Open(const char *zPath,ph7_value *pResource,void **ppHandle)
{
DIR *pDir;
/* Open the target directory */
pDir = opendir(zPath);
if( pDir == 0 ){
pResource = 0; /* Compiler warning */
return -1;
}
/* Save our structure */
*ppHandle = pDir;
return PH7_OK;
}
/* void (*xCloseDir)(void *) */
static void UnixDir_Close(void *pUserData)
{
closedir((DIR *)pUserData);
}
/* void (*xClose)(void *); */
static void UnixFile_Close(void *pUserData)
{
close(SX_PTR_TO_INT(pUserData));
}
/* int (*xReadDir)(void *,ph7_context *) */
static int UnixDir_Read(void *pUserData,ph7_context *pCtx)
{
DIR *pDir = (DIR *)pUserData;
struct dirent *pEntry;
char *zName = 0; /* cc warning */
sxu32 n = 0;
for(;;){
pEntry = readdir(pDir);
if( pEntry == 0 ){
/* No more entries to process */
return -1;
}
zName = pEntry->d_name;
n = SyStrlen(zName);
/* Ignore '.' && '..' */
if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){
break;
}
/* Next entry */
}
/* Return the current file name */
ph7_result_string(pCtx,zName,(int)n);
return PH7_OK;
}
/* void (*xRewindDir)(void *) */
static void UnixDir_Rewind(void *pUserData)
{
rewinddir((DIR *)pUserData);
}
/* ph7_int64 (*xRead)(void *,void *,ph7_int64); */
static ph7_int64 UnixFile_Read(void *pUserData,void *pBuffer,ph7_int64 nDatatoRead)
{
ssize_t nRd;
nRd = read(SX_PTR_TO_INT(pUserData),pBuffer,(size_t)nDatatoRead);
if( nRd < 1 ){
/* EOF or IO error */
return -1;
}
return (ph7_int64)nRd;
}
/* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */
static ph7_int64 UnixFile_Write(void *pUserData,const void *pBuffer,ph7_int64 nWrite)
{
const char *zData = (const char *)pBuffer;
int fd = SX_PTR_TO_INT(pUserData);
ph7_int64 nCount;
ssize_t nWr;
nCount = 0;
for(;;){
if( nWrite < 1 ){
break;
}
nWr = write(fd,zData,(size_t)nWrite);
if( nWr < 1 ){
/* IO error */
break;
}
nWrite -= nWr;
nCount += nWr;
zData += nWr;
}
if( nWrite > 0 ){
return -1;
}
return nCount;
}
/* int (*xSeek)(void *,ph7_int64,int) */
static int UnixFile_Seek(void *pUserData,ph7_int64 iOfft,int whence)
{
off_t iNew;
switch(whence){
case 1:/*SEEK_CUR*/
whence = SEEK_CUR;
break;
case 2: /* SEEK_END */
whence = SEEK_END;
break;
case 0: /* SEEK_SET */
default:
whence = SEEK_SET;
break;
}
iNew = lseek(SX_PTR_TO_INT(pUserData),(off_t)iOfft,whence);
if( iNew < 0 ){
return -1;
}
return PH7_OK;
}
/* int (*xLock)(void *,int) */
static int UnixFile_Lock(void *pUserData,int lock_type)
{
int fd = SX_PTR_TO_INT(pUserData);
int rc = PH7_OK; /* cc warning */
if( lock_type < 0 ){
/* Unlock the file */
rc = flock(fd,LOCK_UN);
}else{
if( lock_type == 1 ){
/* Exculsive lock */
rc = flock(fd,LOCK_EX);
}else{
/* Shared lock */
rc = flock(fd,LOCK_SH);
}
}
return !rc ? PH7_OK : -1;
}
/* ph7_int64 (*xTell)(void *) */
static ph7_int64 UnixFile_Tell(void *pUserData)
{
off_t iNew;
iNew = lseek(SX_PTR_TO_INT(pUserData),0,SEEK_CUR);
return (ph7_int64)iNew;
}
/* int (*xTrunc)(void *,ph7_int64) */
static int UnixFile_Trunc(void *pUserData,ph7_int64 nOfft)
{
int rc;
rc = ftruncate(SX_PTR_TO_INT(pUserData),(off_t)nOfft);
if( rc != 0 ){
return -1;
}
return PH7_OK;
}
/* int (*xSync)(void *); */
static int UnixFile_Sync(void *pUserData)
{
int rc;
rc = fsync(SX_PTR_TO_INT(pUserData));
return rc == 0 ? PH7_OK : - 1;
}
/* int (*xStat)(void *,ph7_value *,ph7_value *) */
static int UnixFile_Stat(void *pUserData,ph7_value *pArray,ph7_value *pWorker)
{
struct stat st;
int rc;
rc = fstat(SX_PTR_TO_INT(pUserData),&st);
if( rc != 0 ){
return -1;
}
/* dev */
ph7_value_int64(pWorker,(ph7_int64)st.st_dev);
ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */
/* ino */
ph7_value_int64(pWorker,(ph7_int64)st.st_ino);
ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */
/* mode */
ph7_value_int(pWorker,(int)st.st_mode);
ph7_array_add_strkey_elem(pArray,"mode",pWorker);
/* nlink */
ph7_value_int(pWorker,(int)st.st_nlink);
ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */
/* uid,gid,rdev */
ph7_value_int(pWorker,(int)st.st_uid);
ph7_array_add_strkey_elem(pArray,"uid",pWorker);
ph7_value_int(pWorker,(int)st.st_gid);
ph7_array_add_strkey_elem(pArray,"gid",pWorker);
ph7_value_int(pWorker,(int)st.st_rdev);
ph7_array_add_strkey_elem(pArray,"rdev",pWorker);
/* size */
ph7_value_int64(pWorker,(ph7_int64)st.st_size);
ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */
/* atime */
ph7_value_int64(pWorker,(ph7_int64)st.st_atime);
ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */
/* mtime */
ph7_value_int64(pWorker,(ph7_int64)st.st_mtime);
ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */
/* ctime */
ph7_value_int64(pWorker,(ph7_int64)st.st_ctime);
ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */
/* blksize,blocks */
ph7_value_int(pWorker,(int)st.st_blksize);
ph7_array_add_strkey_elem(pArray,"blksize",pWorker);
ph7_value_int(pWorker,(int)st.st_blocks);
ph7_array_add_strkey_elem(pArray,"blocks",pWorker);
return PH7_OK;
}
/* Export the file:// stream */
static const ph7_io_stream sUnixFileStream = {
"file", /* Stream name */
PH7_IO_STREAM_VERSION,
UnixFile_Open, /* xOpen */
UnixDir_Open, /* xOpenDir */
UnixFile_Close, /* xClose */
UnixDir_Close, /* xCloseDir */
UnixFile_Read, /* xRead */
UnixDir_Read, /* xReadDir */
UnixFile_Write, /* xWrite */
UnixFile_Seek, /* xSeek */
UnixFile_Lock, /* xLock */
UnixDir_Rewind, /* xRewindDir */
UnixFile_Tell, /* xTell */
UnixFile_Trunc, /* xTrunc */
UnixFile_Sync, /* xSeek */
UnixFile_Stat /* xStat */
};
#endif /* __WINNT__/__UNIXES__ */
#endif /* PH7_DISABLE_DISK_IO */
#endif /* PH7_DISABLE_BUILTIN_FUNC */
/*
* Export the builtin vfs.
* Return a pointer to the builtin vfs if available.
* Otherwise return the null_vfs [i.e: a no-op vfs] instead.
* Note:
* The built-in vfs is always available for Windows/UNIX systems.
* Note:
* If the engine is compiled with the PH7_DISABLE_DISK_IO/PH7_DISABLE_BUILTIN_FUNC
* directives defined then this function return the null_vfs instead.
*/
PH7_PRIVATE const ph7_vfs * PH7_ExportBuiltinVfs(void)
{
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifdef PH7_DISABLE_DISK_IO
return &null_vfs;
#else
#ifdef __WINNT__
return &sWinVfs;
#elif defined(__UNIXES__)
return &sUnixVfs;
#else
return &null_vfs;
#endif /* __WINNT__/__UNIXES__ */
#endif /*PH7_DISABLE_DISK_IO*/
#else
return &null_vfs;
#endif /* PH7_DISABLE_BUILTIN_FUNC */
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifndef PH7_DISABLE_DISK_IO
/*
* The following defines are mostly used by the UNIX built and have
* no particular meaning on windows.
*/
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
/*
* php:// Accessing various I/O streams
* According to the PHP langage reference manual
* PHP provides a number of miscellaneous I/O streams that allow access to PHP's own input
* and output streams, the standard input, output and error file descriptors.
* php://stdin, php://stdout and php://stderr:
* Allow direct access to the corresponding input or output stream of the PHP process.
* The stream references a duplicate file descriptor, so if you open php://stdin and later
* close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected.
* php://stdin is read-only, whereas php://stdout and php://stderr are write-only.
* php://output
* php://output is a write-only stream that allows you to write to the output buffer
* mechanism in the same way as print and echo.
*/
typedef struct ph7_stream_data ph7_stream_data;
/* Supported IO streams */
#define PH7_IO_STREAM_STDIN 1 /* php://stdin */
#define PH7_IO_STREAM_STDOUT 2 /* php://stdout */
#define PH7_IO_STREAM_STDERR 3 /* php://stderr */
#define PH7_IO_STREAM_OUTPUT 4 /* php://output */
/* The following structure is the private data associated with the php:// stream */
struct ph7_stream_data
{
ph7_vm *pVm; /* VM that own this instance */
int iType; /* Stream type */
union{
void *pHandle; /* Stream handle */
ph7_output_consumer sConsumer; /* VM output consumer */
}x;
};
/*
* Allocate a new instance of the ph7_stream_data structure.
*/
static ph7_stream_data * PHPStreamDataInit(ph7_vm *pVm,int iType)
{
ph7_stream_data *pData;
if( pVm == 0 ){
return 0;
}
/* Allocate a new instance */
pData = (ph7_stream_data *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(ph7_stream_data));
if( pData == 0 ){
return 0;
}
/* Zero the structure */
SyZero(pData,sizeof(ph7_stream_data));
/* Initialize fields */
pData->iType = iType;
if( iType == PH7_IO_STREAM_OUTPUT ){
/* Point to the default VM consumer routine. */
pData->x.sConsumer = pVm->sVmConsumer;
}else{
#ifdef __WINNT__
DWORD nChannel;
switch(iType){
case PH7_IO_STREAM_STDOUT: nChannel = STD_OUTPUT_HANDLE; break;
case PH7_IO_STREAM_STDERR: nChannel = STD_ERROR_HANDLE; break;
default:
nChannel = STD_INPUT_HANDLE;
break;
}
pData->x.pHandle = GetStdHandle(nChannel);
#else
/* Assume an UNIX system */
int ifd = STDIN_FILENO;
switch(iType){
case PH7_IO_STREAM_STDOUT: ifd = STDOUT_FILENO; break;
case PH7_IO_STREAM_STDERR: ifd = STDERR_FILENO; break;
default:
break;
}
pData->x.pHandle = SX_INT_TO_PTR(ifd);
#endif
}
pData->pVm = pVm;
return pData;
}
/*
* Implementation of the php:// IO streams routines
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/* int (*xOpen)(const char *,int,ph7_value *,void **) */
static int PHPStreamData_Open(const char *zName,int iMode,ph7_value *pResource,void ** ppHandle)
{
ph7_stream_data *pData;
SyString sStream;
SyStringInitFromBuf(&sStream,zName,SyStrlen(zName));
/* Trim leading and trailing white spaces */
SyStringFullTrim(&sStream);
/* Stream to open */
if( SyStrnicmp(sStream.zString,"stdin",sizeof("stdin")-1) == 0 ){
iMode = PH7_IO_STREAM_STDIN;
}else if( SyStrnicmp(sStream.zString,"output",sizeof("output")-1) == 0 ){
iMode = PH7_IO_STREAM_OUTPUT;
}else if( SyStrnicmp(sStream.zString,"stdout",sizeof("stdout")-1) == 0 ){
iMode = PH7_IO_STREAM_STDOUT;
}else if( SyStrnicmp(sStream.zString,"stderr",sizeof("stderr")-1) == 0 ){
iMode = PH7_IO_STREAM_STDERR;
}else{
/* unknown stream name */
return -1;
}
/* Create our handle */
pData = PHPStreamDataInit(pResource?pResource->pVm:0,iMode);
if( pData == 0 ){
return -1;
}
/* Make the handle public */
*ppHandle = (void *)pData;
return PH7_OK;
}
/* ph7_int64 (*xRead)(void *,void *,ph7_int64) */
static ph7_int64 PHPStreamData_Read(void *pHandle,void *pBuffer,ph7_int64 nDatatoRead)
{
ph7_stream_data *pData = (ph7_stream_data *)pHandle;
if( pData == 0 ){
return -1;
}
if( pData->iType != PH7_IO_STREAM_STDIN ){
/* Forbidden */
return -1;
}
#ifdef __WINNT__
{
DWORD nRd;
BOOL rc;
rc = ReadFile(pData->x.pHandle,pBuffer,(DWORD)nDatatoRead,&nRd,0);
if( !rc ){
/* IO error */
return -1;
}
return (ph7_int64)nRd;
}
#elif defined(__UNIXES__)
{
ssize_t nRd;
int fd;
fd = SX_PTR_TO_INT(pData->x.pHandle);
nRd = read(fd,pBuffer,(size_t)nDatatoRead);
if( nRd < 1 ){
return -1;
}
return (ph7_int64)nRd;
}
#else
return -1;
#endif
}
/* ph7_int64 (*xWrite)(void *,const void *,ph7_int64) */
static ph7_int64 PHPStreamData_Write(void *pHandle,const void *pBuf,ph7_int64 nWrite)
{
ph7_stream_data *pData = (ph7_stream_data *)pHandle;
if( pData == 0 ){
return -1;
}
if( pData->iType == PH7_IO_STREAM_STDIN ){
/* Forbidden */
return -1;
}else if( pData->iType == PH7_IO_STREAM_OUTPUT ){
ph7_output_consumer *pCons = &pData->x.sConsumer;
int rc;
/* Call the vm output consumer */
rc = pCons->xConsumer(pBuf,(unsigned int)nWrite,pCons->pUserData);
if( rc == PH7_ABORT ){
return -1;
}
return nWrite;
}
#ifdef __WINNT__
{
DWORD nWr;
BOOL rc;
rc = WriteFile(pData->x.pHandle,pBuf,(DWORD)nWrite,&nWr,0);
if( !rc ){
/* IO error */
return -1;
}
return (ph7_int64)nWr;
}
#elif defined(__UNIXES__)
{
ssize_t nWr;
int fd;
fd = SX_PTR_TO_INT(pData->x.pHandle);
nWr = write(fd,pBuf,(size_t)nWrite);
if( nWr < 1 ){
return -1;
}
return (ph7_int64)nWr;
}
#else
return -1;
#endif
}
/* void (*xClose)(void *) */
static void PHPStreamData_Close(void *pHandle)
{
ph7_stream_data *pData = (ph7_stream_data *)pHandle;
ph7_vm *pVm;
if( pData == 0 ){
return;
}
pVm = pData->pVm;
/* Free the instance */
SyMemBackendFree(&pVm->sAllocator,pData);
}
/* Export the php:// stream */
static const ph7_io_stream sPHP_Stream = {
"php",
PH7_IO_STREAM_VERSION,
PHPStreamData_Open, /* xOpen */
0, /* xOpenDir */
PHPStreamData_Close, /* xClose */
0, /* xCloseDir */
PHPStreamData_Read, /* xRead */
0, /* xReadDir */
PHPStreamData_Write, /* xWrite */
0, /* xSeek */
0, /* xLock */
0, /* xRewindDir */
0, /* xTell */
0, /* xTrunc */
0, /* xSeek */
0 /* xStat */
};
#endif /* PH7_DISABLE_DISK_IO */
/*
* Return TRUE if we are dealing with the php:// stream.
* FALSE otherwise.
*/
static int is_php_stream(const ph7_io_stream *pStream)
{
#ifndef PH7_DISABLE_DISK_IO
return pStream == &sPHP_Stream;
#else
SXUNUSED(pStream); /* cc warning */
return 0;
#endif /* PH7_DISABLE_DISK_IO */
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
/*
* Export the IO routines defined above and the built-in IO streams
* [i.e: file://,php://].
* Note:
* If the engine is compiled with the PH7_DISABLE_BUILTIN_FUNC directive
* defined then this function is a no-op.
*/
PH7_PRIVATE sxi32 PH7_RegisterIORoutine(ph7_vm *pVm)
{
#ifndef PH7_DISABLE_BUILTIN_FUNC
/* VFS functions */
static const ph7_builtin_func aVfsFunc[] = {
{"chdir", PH7_vfs_chdir },
{"chroot", PH7_vfs_chroot },
{"getcwd", PH7_vfs_getcwd },
{"rmdir", PH7_vfs_rmdir },
{"is_dir", PH7_vfs_is_dir },
{"mkdir", PH7_vfs_mkdir },
{"rename", PH7_vfs_rename },
{"realpath",PH7_vfs_realpath},
{"sleep", PH7_vfs_sleep },
{"usleep", PH7_vfs_usleep },
{"unlink", PH7_vfs_unlink },
{"delete", PH7_vfs_unlink },
{"chmod", PH7_vfs_chmod },
{"chown", PH7_vfs_chown },
{"chgrp", PH7_vfs_chgrp },
{"disk_free_space",PH7_vfs_disk_free_space },
{"diskfreespace", PH7_vfs_disk_free_space },
{"disk_total_space",PH7_vfs_disk_total_space},
{"file_exists", PH7_vfs_file_exists },
{"filesize", PH7_vfs_file_size },
{"fileatime", PH7_vfs_file_atime },
{"filemtime", PH7_vfs_file_mtime },
{"filectime", PH7_vfs_file_ctime },
{"is_file", PH7_vfs_is_file },
{"is_link", PH7_vfs_is_link },
{"is_readable", PH7_vfs_is_readable },
{"is_writable", PH7_vfs_is_writable },
{"is_executable",PH7_vfs_is_executable},
{"filetype", PH7_vfs_filetype },
{"stat", PH7_vfs_stat },
{"lstat", PH7_vfs_lstat },
{"getenv", PH7_vfs_getenv },
{"setenv", PH7_vfs_putenv },
{"putenv", PH7_vfs_putenv },
{"touch", PH7_vfs_touch },
{"link", PH7_vfs_link },
{"symlink", PH7_vfs_symlink },
{"umask", PH7_vfs_umask },
{"sys_get_temp_dir", PH7_vfs_sys_get_temp_dir },
{"get_current_user", PH7_vfs_get_current_user },
{"getmypid", PH7_vfs_getmypid },
{"getpid", PH7_vfs_getmypid },
{"getmyuid", PH7_vfs_getmyuid },
{"getuid", PH7_vfs_getmyuid },
{"getmygid", PH7_vfs_getmygid },
{"getgid", PH7_vfs_getmygid },
{"ph7_uname", PH7_vfs_ph7_uname},
{"php_uname", PH7_vfs_ph7_uname},
/* Path processing */
{"dirname", PH7_builtin_dirname },
{"basename", PH7_builtin_basename },
{"pathinfo", PH7_builtin_pathinfo },
{"strglob", PH7_builtin_strglob },
{"fnmatch", PH7_builtin_fnmatch },
/* ZIP processing */
{"zip_open", PH7_builtin_zip_open },
{"zip_close", PH7_builtin_zip_close},
{"zip_read", PH7_builtin_zip_read },
{"zip_entry_open", PH7_builtin_zip_entry_open },
{"zip_entry_close",PH7_builtin_zip_entry_close},
{"zip_entry_name", PH7_builtin_zip_entry_name },
{"zip_entry_filesize", PH7_builtin_zip_entry_filesize },
{"zip_entry_compressedsize",PH7_builtin_zip_entry_compressedsize },
{"zip_entry_read", PH7_builtin_zip_entry_read },
{"zip_entry_reset_read_cursor",PH7_builtin_zip_entry_reset_read_cursor},
{"zip_entry_compressionmethod",PH7_builtin_zip_entry_compressionmethod}
};
/* IO stream functions */
static const ph7_builtin_func aIOFunc[] = {
{"ftruncate", PH7_builtin_ftruncate },
{"fseek", PH7_builtin_fseek },
{"ftell", PH7_builtin_ftell },
{"rewind", PH7_builtin_rewind },
{"fflush", PH7_builtin_fflush },
{"feof", PH7_builtin_feof },
{"fgetc", PH7_builtin_fgetc },
{"fgets", PH7_builtin_fgets },
{"fread", PH7_builtin_fread },
{"fgetcsv", PH7_builtin_fgetcsv},
{"fgetss", PH7_builtin_fgetss },
{"readdir", PH7_builtin_readdir},
{"rewinddir", PH7_builtin_rewinddir },
{"closedir", PH7_builtin_closedir},
{"opendir", PH7_builtin_opendir },
{"readfile", PH7_builtin_readfile},
{"file_get_contents", PH7_builtin_file_get_contents},
{"file_put_contents", PH7_builtin_file_put_contents},
{"file", PH7_builtin_file },
{"copy", PH7_builtin_copy },
{"fstat", PH7_builtin_fstat },
{"fwrite", PH7_builtin_fwrite },
{"fputs", PH7_builtin_fwrite },
{"flock", PH7_builtin_flock },
{"fclose", PH7_builtin_fclose },
{"fopen", PH7_builtin_fopen },
{"fpassthru", PH7_builtin_fpassthru },
{"fputcsv", PH7_builtin_fputcsv },
{"fprintf", PH7_builtin_fprintf },
#if !defined(PH7_DISABLE_HASH_FUNC)
{"md5_file", PH7_builtin_md5_file},
{"sha1_file", PH7_builtin_sha1_file},
#endif /* PH7_DISABLE_HASH_FUNC */
{"parse_ini_file", PH7_builtin_parse_ini_file},
{"vfprintf", PH7_builtin_vfprintf}
};
const ph7_io_stream *pFileStream = 0;
sxu32 n = 0;
/* Register the functions defined above */
for( n = 0 ; n < SX_ARRAYSIZE(aVfsFunc) ; ++n ){
ph7_create_function(&(*pVm),aVfsFunc[n].zName,aVfsFunc[n].xFunc,(void *)pVm->pEngine->pVfs);
}
for( n = 0 ; n < SX_ARRAYSIZE(aIOFunc) ; ++n ){
ph7_create_function(&(*pVm),aIOFunc[n].zName,aIOFunc[n].xFunc,pVm);
}
#ifndef PH7_DISABLE_DISK_IO
/* Register the file stream if available */
#ifdef __WINNT__
pFileStream = &sWinFileStream;
#elif defined(__UNIXES__)
pFileStream = &sUnixFileStream;
#endif
/* Install the php:// stream */
ph7_vm_config(pVm,PH7_VM_CONFIG_IO_STREAM,&sPHP_Stream);
#endif /* PH7_DISABLE_DISK_IO */
if( pFileStream ){
/* Install the file:// stream */
ph7_vm_config(pVm,PH7_VM_CONFIG_IO_STREAM,pFileStream);
}
#else
SXUNUSED(pVm); /* cc warning */
#endif /* PH7_DISABLE_BUILTIN_FUNC */
return SXRET_OK;
}
/*
* Export the STDIN handle.
*/
PH7_PRIVATE void * PH7_ExportStdin(ph7_vm *pVm)
{
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifndef PH7_DISABLE_DISK_IO
if( pVm->pStdin == 0 ){
io_private *pIn;
/* Allocate an IO private instance */
pIn = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private));
if( pIn == 0 ){
return 0;
}
InitIOPrivate(pVm,&sPHP_Stream,pIn);
/* Initialize the handle */
pIn->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDIN);
/* Install the STDIN stream */
pVm->pStdin = pIn;
return pIn;
}else{
/* NULL or STDIN */
return pVm->pStdin;
}
#else
return 0;
#endif
#else
SXUNUSED(pVm); /* cc warning */
return 0;
#endif
}
/*
* Export the STDOUT handle.
*/
PH7_PRIVATE void * PH7_ExportStdout(ph7_vm *pVm)
{
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifndef PH7_DISABLE_DISK_IO
if( pVm->pStdout == 0 ){
io_private *pOut;
/* Allocate an IO private instance */
pOut = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private));
if( pOut == 0 ){
return 0;
}
InitIOPrivate(pVm,&sPHP_Stream,pOut);
/* Initialize the handle */
pOut->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDOUT);
/* Install the STDOUT stream */
pVm->pStdout = pOut;
return pOut;
}else{
/* NULL or STDOUT */
return pVm->pStdout;
}
#else
return 0;
#endif
#else
SXUNUSED(pVm); /* cc warning */
return 0;
#endif
}
/*
* Export the STDERR handle.
*/
PH7_PRIVATE void * PH7_ExportStderr(ph7_vm *pVm)
{
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifndef PH7_DISABLE_DISK_IO
if( pVm->pStderr == 0 ){
io_private *pErr;
/* Allocate an IO private instance */
pErr = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private));
if( pErr == 0 ){
return 0;
}
InitIOPrivate(pVm,&sPHP_Stream,pErr);
/* Initialize the handle */
pErr->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDERR);
/* Install the STDERR stream */
pVm->pStderr = pErr;
return pErr;
}else{
/* NULL or STDERR */
return pVm->pStderr;
}
#else
return 0;
#endif
#else
SXUNUSED(pVm); /* cc warning */
return 0;
#endif
}