From 91601deb844848dc02959679fd41e1441a76aff4 Mon Sep 17 00:00:00 2001 From: Aaron Seigo Date: Sun, 14 Dec 2014 12:30:27 +0100 Subject: the all-in-one-file version of unqlite --- common/unqlite/jx9_vfs.c | 8222 ---------------------------------------------- 1 file changed, 8222 deletions(-) delete mode 100644 common/unqlite/jx9_vfs.c (limited to 'common/unqlite/jx9_vfs.c') diff --git a/common/unqlite/jx9_vfs.c b/common/unqlite/jx9_vfs.c deleted file mode 100644 index d6aee2e..0000000 --- a/common/unqlite/jx9_vfs.c +++ /dev/null @@ -1,8222 +0,0 @@ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * 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://jx9.symisc.net/ - */ - /* $SymiscID: vfs.c v2.1 Ubuntu 2012-12-13 00:013 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* - * This file implement a virtual file systems (VFS) for the JX9 engine. - */ -/* - * Given a string containing the path of a file or directory, this function - * return the parent directory's path. - */ -JX9_PRIVATE const char * jx9ExtractDirName(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 JX9_DISABLE_BUILTIN_FUNC directive is defined. - */ -#ifndef JX9_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 jx9Vfs_chdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xChdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_chroot(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChroot == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xChroot(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_getcwd(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int rc; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGetcwd == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - rc = pVfs->xGetcwd(pCtx); - if( rc != JX9_OK ){ - /* Error, return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * bool rmdir(string $directory) - * Removes directory. - * Parameters - * $directory - * The path to the directory - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_rmdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRmdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xRmdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_is_dir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIsdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIsdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool mkdir(string $pathname[, int $mode = 0777]) - * 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(). - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_mkdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iRecursive = 0; - const char *zPath; - jx9_vfs *pVfs; - int iMode, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xMkdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); -#ifdef __WINNT__ - iMode = 0; -#else - /* Assume UNIX */ - iMode = 0777; -#endif - if( nArg > 1 ){ - iMode = jx9_value_to_int(apArg[1]); - if( nArg > 2 ){ - iRecursive = jx9_value_to_bool(apArg[2]); - } - } - /* Perform the requested operation */ - rc = pVfs->xMkdir(zPath, iMode, iRecursive); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_rename(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zOld, *zNew; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRename == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - zOld = jx9_value_to_string(apArg[0], 0); - zNew = jx9_value_to_string(apArg[1], 0); - rc = pVfs->xRename(zOld, zNew); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_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 jx9Vfs_realpath(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRealpath == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set an empty string untnil the underlying OS interface change that */ - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - zPath = jx9_value_to_string(apArg[0], 0); - rc = pVfs->xRealpath(zPath, pCtx); - if( rc != JX9_OK ){ - jx9_result_bool(pCtx, 0); - } - return JX9_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 jx9Vfs_sleep(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int rc, nSleep; - if( nArg < 1 || !jx9_value_is_int(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSleep == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Amount to sleep */ - nSleep = jx9_value_to_int(apArg[0]); - if( nSleep < 0 ){ - /* Invalid value, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation (Microseconds) */ - rc = pVfs->xSleep((unsigned int)(nSleep * SX_USEC_PER_SEC)); - if( rc != JX9_OK ){ - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return zero */ - jx9_result_int(pCtx, 0); - } - return JX9_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 jx9Vfs_usleep(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nSleep; - if( nArg < 1 || !jx9_value_is_int(apArg[0]) ){ - /* Missing/Invalid argument, return immediately */ - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSleep == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - return JX9_OK; - } - /* Amount to sleep */ - nSleep = jx9_value_to_int(apArg[0]); - if( nSleep < 0 ){ - /* Invalid value, return immediately */ - return JX9_OK; - } - /* Perform the requested operation (Microseconds) */ - pVfs->xSleep((unsigned int)nSleep); - return JX9_OK; -} -/* - * bool unlink (string $filename) - * Delete a file. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_unlink(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUnlink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xUnlink(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_chmod(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int iMode; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChmod == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the mode */ - iMode = jx9_value_to_int(apArg[1]); - /* Perform the requested operation */ - rc = pVfs->xChmod(zPath, iMode); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_chown(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zUser; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChown == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the user */ - zUser = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xChown(zPath, zUser); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_chgrp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zGroup; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChgrp == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the user */ - zGroup = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xChgrp(zPath, zGroup); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_disk_free_space(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFreeSpace == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xFreeSpace(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_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 jx9Vfs_disk_total_space(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTotalSpace == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xTotalSpace(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_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 jx9Vfs_file_exists(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileExists == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xFileExists(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_file_size(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileSize == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xFileSize(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_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 jx9Vfs_file_atime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileAtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileAtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_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 jx9Vfs_file_mtime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileMtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileMtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_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 jx9Vfs_file_ctime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileCtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileCtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_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 jx9Vfs_is_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIsfile == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIsfile(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_is_link(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIslink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIslink(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_is_readable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xReadable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xReadable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_is_writable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xWritable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xWritable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_is_executable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xExecutable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xExecutable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Vfs_filetype(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFiletype == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Set the empty string as the default return value */ - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - pVfs->xFiletype(zPath, pCtx); - return JX9_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 jx9Vfs_stat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xStat == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xStat(zPath, pArray, pValue); - if( rc != JX9_OK ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the associative array */ - jx9_result_value(pCtx, pArray); - } - /* Don't worry about freeing memory here, everything will be released - * automatically as soon we return from this function. */ - return JX9_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 jx9Vfs_lstat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xlStat == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xlStat(zPath, pArray, pValue); - if( rc != JX9_OK ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the associative array */ - jx9_result_value(pCtx, pArray); - } - /* Don't worry about freeing memory here, everything will be released - * automatically as soon we return from this function. */ - return JX9_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 jx9Vfs_getenv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zEnv; - jx9_vfs *pVfs; - int iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGetenv == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the environment variable */ - zEnv = jx9_value_to_string(apArg[0], &iLen); - /* Set a boolean FALSE as the default return value */ - jx9_result_bool(pCtx, 0); - if( iLen < 1 ){ - /* Empty string */ - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xGetenv(zEnv, pCtx); - return JX9_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 jx9Vfs_putenv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zName, *zValue; - char *zSettings, *zEnd; - jx9_vfs *pVfs; - int iLen, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the setting variable */ - zSettings = (char *)jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_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 */ - jx9_result_bool(pCtx, 0); - if( zSettings < zEnd ){ - zSettings[0] = '='; - } - return JX9_OK; - } - jx9_vm_config(pCtx->pVm, JX9_VM_CONFIG_ENV_ATTR, zName, zValue, (int)(zEnd-zValue)); - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSetenv == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - zSettings[0] = '='; - return JX9_OK; - } - /* Perform the requested operation */ - rc = pVfs->xSetenv(zName, zValue); - jx9_result_bool(pCtx, rc == JX9_OK ); - zSettings[0] = '='; - return JX9_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 jx9Vfs_touch(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nTime, nAccess; - const char *zFile; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTouch == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nTime = nAccess = -1; - zFile = jx9_value_to_string(apArg[0], 0); - if( nArg > 1 ){ - nTime = jx9_value_to_int64(apArg[1]); - if( nArg > 2 ){ - nAccess = jx9_value_to_int64(apArg[1]); - }else{ - nAccess = nTime; - } - } - rc = pVfs->xTouch(zFile, nTime, nAccess); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * Path processing functions that do not need access to the VFS layer - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.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 jx9Builtin_dirname(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zDir; - int iLen, iDirlen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Reuturn "." */ - jx9_result_string(pCtx, ".", sizeof(char)); - return JX9_OK; - } - /* Perform the requested operation */ - zDir = jx9ExtractDirName(zPath, iLen, &iDirlen); - /* Return directory name */ - jx9_result_string(pCtx, zDir, iDirlen); - return JX9_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 jx9Builtin_basename(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zBase, *zEnd; - int c, d, iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - c = d = '/'; -#ifdef __WINNT__ - d = '\\'; -#endif - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_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 && jx9_value_is_string(apArg[1]) ){ - const char *zSuffix; - int nSuffix; - /* Strip suffix */ - zSuffix = jx9_value_to_string(apArg[1], &nSuffix); - if( nSuffix > 0 && nSuffix < iLen && SyMemcmp(&zEnd[-nSuffix], zSuffix, nSuffix) == 0 ){ - zEnd -= nSuffix; - } - } - /* Store the basename */ - jx9_result_string(pCtx, zBase, (int)(zEnd-zBase)); - return JX9_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 jx9Builtin_pathinfo(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - path_info sInfo; - SyString *pComp; - int iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract path info */ - ExtractPathInfo(zPath, iLen, &sInfo); - if( nArg > 1 && jx9_value_is_int(apArg[1]) ){ - /* Return path component */ - int nComp = jx9_value_to_int(apArg[1]); - switch(nComp){ - case 1: /* PATHINFO_DIRNAME */ - pComp = &sInfo.sDir; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 2: /*PATHINFO_BASENAME*/ - pComp = &sInfo.sBasename; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 3: /*PATHINFO_EXTENSION*/ - pComp = &sInfo.sExtension; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 4: /*PATHINFO_FILENAME*/ - pComp = &sInfo.sFilename; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - default: - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - break; - } - }else{ - /* Return an associative array */ - jx9_value *pArray, *pValue; - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - /* Out of mem, return NULL */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* dirname */ - pComp = &sInfo.sDir; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "dirname", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* basername */ - pComp = &sInfo.sBasename; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "basename", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* extension */ - pComp = &sInfo.sExtension; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "extension", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* filename */ - pComp = &sInfo.sFilename; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "filename", pValue); /* Will make it's own copy */ - } - /* Return the created array */ - jx9_result_value(pCtx, pArray); - /* Don't worry about freeing memory, everything will be released - * automatically as soon we return from this foreign function. - */ - } - return JX9_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 = jx9Utf8Read(zPattern, 0, &zPattern))!=0 ){ - if( !prevEscape && c==matchAll ){ - while( (c= jx9Utf8Read(zPattern, 0, &zPattern)) == matchAll - || c == matchOne ){ - if( c==matchOne && jx9Utf8Read(zString, 0, &zString)==0 ){ - return 0; - } - } - if( c==0 ){ - return 1; - }else if( c==esc ){ - c = jx9Utf8Read(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 = jx9Utf8Read(zString, 0, &zString))!=0 ){ - if( noCase ){ - GlogUpperToLower(c2); - GlogUpperToLower(c); - while( c2 != 0 && c2 != c ){ - c2 = jx9Utf8Read(zString, 0, &zString); - GlogUpperToLower(c2); - } - }else{ - while( c2 != 0 && c2 != c ){ - c2 = jx9Utf8Read(zString, 0, &zString); - } - } - if( c2==0 ) return 0; - if( patternCompare(zPattern, zString, esc, noCase) ) return 1; - } - return 0; - }else if( !prevEscape && c==matchOne ){ - if( jx9Utf8Read(zString, 0, &zString)==0 ){ - return 0; - } - }else if( c==matchSet ){ - int prior_c = 0; - if( esc == 0 ) return 0; - seen = 0; - invert = 0; - c = jx9Utf8Read(zString, 0, &zString); - if( c==0 ) return 0; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - if( c2=='^' ){ - invert = 1; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - if( c2==']' ){ - if( c==']' ) seen = 1; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - while( c2 && c2!=']' ){ - if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - if( c>=prior_c && c<=c2 ) seen = 1; - prior_c = 0; - }else{ - if( c==c2 ){ - seen = 1; - } - prior_c = c2; - } - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - if( c2==0 || (seen ^ invert)==0 ){ - return 0; - } - }else if( esc==c && !prevEscape ){ - prevEscape = 1; - }else{ - c2 = jx9Utf8Read(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 jx9Builtin_fnmatch(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zPattern; - int iEsc = '\\'; - int noCase = 0; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the pattern and the string */ - zPattern = jx9_value_to_string(apArg[0], 0); - zString = jx9_value_to_string(apArg[1], 0); - /* Extract the flags if avaialble */ - if( nArg > 2 && jx9_value_is_int(apArg[2]) ){ - rc = jx9_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 */ - jx9_result_bool(pCtx, rc); - return JX9_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. - */ -static int jx9Builtin_strglob(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zPattern; - int iEsc = '\\'; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the pattern and the string */ - zPattern = jx9_value_to_string(apArg[0], 0); - zString = jx9_value_to_string(apArg[1], 0); - /* Go globbing */ - rc = Glob((const unsigned char *)zPattern, (const unsigned char *)zString, iEsc, 0); - /* Globbing result */ - jx9_result_bool(pCtx, rc); - return JX9_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 jx9Vfs_link(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zTarget, *zLink; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xLink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the given arguments */ - zTarget = jx9_value_to_string(apArg[0], 0); - zLink = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xLink(zTarget, zLink, 0/*Not a symbolic link */); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_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 jx9Vfs_symlink(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zTarget, *zLink; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xLink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the given arguments */ - zTarget = jx9_value_to_string(apArg[0], 0); - zLink = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xLink(zTarget, zLink, 1/*A symbolic link */); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_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 jx9Vfs_umask(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iOld, iNew; - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUmask == 0 ){ - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - iNew = 0; - if( nArg > 0 ){ - iNew = jx9_value_to_int(apArg[0]); - } - /* Perform the requested operation */ - iOld = pVfs->xUmask(iNew); - /* Old mask */ - jx9_result_int(pCtx, iOld); - return JX9_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 jx9Vfs_sys_get_temp_dir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - /* Set the empty string as the default return value */ - jx9_result_string(pCtx, "", 0); - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTempDir == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return "" */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xTempDir(pCtx); - return JX9_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 jx9Vfs_get_current_user(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUsername == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - /* Set a dummy username */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xUsername(pCtx); - return JX9_OK; -} -/* - * int64 getmypid() - * Gets process ID. - * Parameters - * None - * Return - * Returns the process ID. - */ -static int jx9Vfs_getmypid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nProcessId; - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xProcessId == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nProcessId = (jx9_int64)pVfs->xProcessId(); - /* Set the result */ - jx9_result_int64(pCtx, nProcessId); - return JX9_OK; -} -/* - * int getmyuid() - * Get user ID. - * Parameters - * None - * Return - * Returns the user ID. - */ -static int jx9Vfs_getmyuid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nUid; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUid == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nUid = pVfs->xUid(); - /* Set the result */ - jx9_result_int(pCtx, nUid); - return JX9_OK; -} -/* - * int getmygid() - * Get group ID. - * Parameters - * None - * Return - * Returns the group ID. - */ -static int jx9Vfs_getmygid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nGid; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGid == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nGid = pVfs->xGid(); - /* Set the result */ - jx9_result_int(pCtx, nGid); - return JX9_OK; -} -#ifdef __WINNT__ -#include -#elif defined(__UNIXES__) -#include -#endif -/* - * string 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 jx9Vfs_uname(jx9_context *pCtx, int nArg, jx9_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 && jx9_value_is_string(apArg[0]) ){ - /* Extract the desired mode */ - zMode = jx9_value_to_string(apArg[0], 0); - } -#if defined(__WINNT__) - sVer.dwOSVersionInfoSize = sizeof(sVer); - if( TRUE != GetVersionExW(&sVer)){ - jx9_result_string(pCtx, zName, -1); - return JX9_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 8"; break; - default: break; - } - } - } - switch(zMode[0]){ - case 's': - /* Operating system name */ - jx9_result_string(pCtx, zName, -1/* Compute length automatically*/); - break; - case 'n': - /* Host name */ - jx9_result_string(pCtx, "localhost", (int)sizeof("localhost")-1); - break; - case 'r': - case 'v': - /* Version information. */ - jx9_result_string_format(pCtx, "%u.%u build %u", - sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber - ); - break; - case 'm': - /* Machine name */ - jx9_result_string(pCtx, "x86", (int)sizeof("x86")-1); - break; - default: - jx9_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 ){ - jx9_result_string(pCtx, "Unix", (int)sizeof("Unix")-1); - return JX9_OK; - } - switch(zMode[0]){ - case 's': - /* Operating system name */ - jx9_result_string(pCtx, sName.sysname, -1/* Compute length automatically*/); - break; - case 'n': - /* Host name */ - jx9_result_string(pCtx, sName.nodename, -1/* Compute length automatically*/); - break; - case 'r': - /* Release information */ - jx9_result_string(pCtx, sName.release, -1/* Compute length automatically*/); - break; - case 'v': - /* Version information. */ - jx9_result_string(pCtx, sName.version, -1/* Compute length automatically*/); - break; - case 'm': - /* Machine name */ - jx9_result_string(pCtx, sName.machine, -1/* Compute length automatically*/); - break; - default: - jx9_result_string_format(pCtx, - "%s %s %s %s %s", - sName.sysname, - sName.release, - sName.version, - sName.nodename, - sName.machine - ); - break; - } -#else - jx9_result_string(pCtx, "Host Operating System/localhost", (int)sizeof("Host Operating System/localhost")-1); -#endif - return JX9_OK; -} -/* - * Section: - * IO stream implementation. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -typedef struct io_private io_private; -struct io_private -{ - const jx9_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 jx9Builtin_ftruncate(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xTrunc == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xTrunc(pDev->pHandle, jx9_value_to_int64(apArg[1])); - if( rc == JX9_OK ){ - /* Discard buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Builtin_fseek(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 iOfft; - int whence; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSeek == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract the offset */ - iOfft = jx9_value_to_int64(apArg[1]); - whence = 0;/* SEEK_SET */ - if( nArg > 2 && jx9_value_is_int(apArg[2]) ){ - whence = jx9_value_to_int(apArg[2]); - } - /* Perform the requested operation */ - rc = pStream->xSeek(pDev->pHandle, iOfft, whence); - if( rc == JX9_OK ){ - /* Ignore buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_int(pCtx, rc == JX9_OK ? 0 : - 1); - return JX9_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 jx9Builtin_ftell(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 iOfft; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xTell == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - iOfft = pStream->xTell(pDev->pHandle); - /* IO result */ - jx9_result_int64(pCtx, iOfft); - return JX9_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 jx9Builtin_rewind(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSeek == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xSeek(pDev->pHandle, 0, 0/*SEEK_SET*/); - if( rc == JX9_OK ){ - /* Ignore buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Builtin_fflush(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSync == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xSync(pDev->pHandle); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Builtin_feof(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - rc = SXERR_EOF; - /* Perform the requested operation */ - if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ - /* Data is available */ - rc = JX9_OK; - }else{ - char zBuf[4096]; - jx9_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 = JX9_OK; - } - } - /* EOF or not */ - jx9_result_bool(pCtx, rc == SXERR_EOF); - return JX9_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 jx9_int64 StreamRead(io_private *pDev, void *pBuf, jx9_int64 nLen) -{ - const jx9_io_stream *pStream = pDev->pStream; - char *zBuf = (char *)pBuf; - jx9_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, jx9_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 JX9 specification */ - *pLen = (jx9_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 jx9_int64 StreamReadLine(io_private *pDev, const char **pzData, jx9_int64 nMaxLen) -{ - const jx9_io_stream *pStream = pDev->pStream; - char zBuf[8192]; - jx9_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 JX9 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 JX9 IO streams looks like JX9 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. - */ -JX9_PRIVATE void * jx9StreamOpenHandle(jx9_vm *pVm, const jx9_io_stream *pStream, const char *zFile, - int iFlags, int use_include, jx9_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 == JX9_OK ){ - if( bPushInclude ){ - /* Mark as included */ - jx9VmPushFilePath(pVm, (const char *)SyBlobData(&sWorker), SyBlobLength(&sWorker), FALSE, pNew); - } - break; - } - /* Reset the working buffer */ - SyBlobReset(&sWorker); - /* Check the next path */ - } - SyBlobRelease(&sWorker); - } - if( rc == JX9_OK ){ - if( bPushInclude ){ - /* Mark as included */ - jx9VmPushFilePath(pVm, sFile.zString, sFile.nByte, FALSE, pNew); - } - } - }else{ - /* Open the URI direcly */ - rc = pStream->xOpen(zFile, iFlags, pResource, &pHandle); - } - if( rc != JX9_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. - */ -JX9_PRIVATE sxi32 jx9StreamReadWholeFile(void *pHandle, const jx9_io_stream *pStream, SyBlob *pOut) -{ - jx9_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..]. - */ -JX9_PRIVATE void jx9StreamCloseHandle(const jx9_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 jx9Builtin_fgetc(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int c, n; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - n = (int)StreamRead(pDev, (void *)&c, sizeof(char)); - /* IO result */ - if( n < 1 ){ - /* EOF or error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the string holding the character */ - jx9_result_string(pCtx, (const char *)&c, sizeof(char)); - } - return JX9_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 jx9Builtin_fgets(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the freshly extracted line */ - jx9_result_string(pCtx, zLine, (int)n); - } - return JX9_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 jx9Builtin_fread(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 nRead; - void *pBuf; - int nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = 4096; - if( nArg > 1 ){ - nLen = jx9_value_to_int(apArg[1]); - if( nLen < 1 ){ - /* Invalid length, set a default length */ - nLen = 4096; - } - } - /* Allocate enough buffer */ - pBuf = jx9_context_alloc_chunk(pCtx, (unsigned int)nLen, FALSE, FALSE); - if( pBuf == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nRead = StreamRead(pDev, pBuf, (jx9_int64)nLen); - if( nRead < 1 ){ - /* Nothing read, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Make a copy of the data just read */ - jx9_result_string(pCtx, (const char *)pBuf, (int)nRead); - } - /* Release the buffer */ - jx9_context_free_chunk(pCtx, pBuf); - return JX9_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 jx9Builtin_fgetcsv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - jx9_value *pArray; - int delim = ','; /* Delimiter */ - int encl = '"' ; /* Enclosure */ - int escape = '\\'; /* Escape character */ - if( nArg > 2 ){ - const char *zPtr; - int i; - if( jx9_value_is_string(apArg[2]) ){ - /* Extract the delimiter */ - zPtr = jx9_value_to_string(apArg[2], &i); - if( i > 0 ){ - delim = zPtr[0]; - } - } - if( nArg > 3 ){ - if( jx9_value_is_string(apArg[3]) ){ - /* Extract the enclosure */ - zPtr = jx9_value_to_string(apArg[3], &i); - if( i > 0 ){ - encl = zPtr[0]; - } - } - if( nArg > 4 ){ - if( jx9_value_is_string(apArg[4]) ){ - /* Extract the escape character */ - zPtr = jx9_value_to_string(apArg[4], &i); - if( i > 0 ){ - escape = zPtr[0]; - } - } - } - } - } - /* Create our array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - } - /* Parse the raw input */ - jx9ProcessCsv(zLine, (int)n, delim, encl, escape, jx9CsvConsumer, pArray); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - } - return JX9_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 JX9 code stripped. If an error occurs, returns FALSE. - */ -static int jx9Builtin_fgetss(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - const char *zTaglist = 0; - int nTaglen = 0; - if( nArg > 2 && jx9_value_is_string(apArg[2]) ){ - /* Allowed tag */ - zTaglist = jx9_value_to_string(apArg[2], &nTaglen); - } - /* Process data just read */ - jx9StripTagsFromString(pCtx, zLine, (int)n, zTaglist, nTaglen); - } - return JX9_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 jx9Builtin_readdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xReadDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - jx9_result_bool(pCtx, 0); - /* Perform the requested operation */ - rc = pStream->xReadDir(pDev->pHandle, pCtx); - if( rc != JX9_OK ){ - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_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 jx9Builtin_rewinddir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xRewindDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xRewindDir(pDev->pHandle); - return JX9_OK; - } -/* Forward declaration */ -static void InitIOPrivate(jx9_vm *pVm, const jx9_io_stream *pStream, io_private *pOut); -static void ReleaseIOPrivate(jx9_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 jx9Builtin_closedir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xCloseDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xCloseDir(pDev->pHandle); - /* Release the private stucture */ - ReleaseIOPrivate(pCtx, pDev); - jx9MemObjRelease(apArg[0]); - return JX9_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 jx9Builtin_opendir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zPath; - io_private *pDev; - int iLen, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a directory path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - /* Try to extract a stream */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zPath, iLen); - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "No stream device is associated with the given path(%s)", zPath); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( pStream->xOpenDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pStream->zName - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_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 != JX9_OK ){ - /* IO error, return FALSE */ - ReleaseIOPrivate(pCtx, pDev); - jx9_result_bool(pCtx, 0); - }else{ - /* Return the handle as a resource */ - jx9_result_resource(pCtx, pDev); - } - return JX9_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 jx9Builtin_readfile(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int use_include = FALSE; - const jx9_io_stream *pStream; - jx9_int64 n, nRead; - const char *zFile; - char zBuf[8192]; - void *pHandle; - int rc, nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - use_include = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, - use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_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 = jx9_context_output(pCtx, zBuf, (int)n); - if( rc == JX9_ABORT ){ - break; - } - /* Increment counter */ - nRead += n; - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Total number of bytes readen */ - jx9_result_int64(pCtx, nRead); - return JX9_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 jx9Builtin_file_get_contents(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - jx9_int64 n, nRead, nMaxlen; - int use_include = FALSE; - const char *zFile; - char zBuf[8192]; - void *pHandle; - int nLen; - - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nMaxlen = -1; - if( nArg > 1 ){ - use_include = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 3 ){ - /* Extract the offset */ - n = jx9_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 = jx9_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 */ - jx9_result_string(pCtx, zBuf, (int)n); - /* Increment read counter */ - nRead += n; - if( nMaxlen > 0 && nRead >= nMaxlen ){ - /* Read limit reached */ - break; - } - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Check if we have read something */ - if( jx9_context_result_buf_length(pCtx) < 1 ){ - /* Nothing read, return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_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 jx9Builtin_file_put_contents(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int use_include = FALSE; - const jx9_io_stream *pStream; - const char *zFile; - const char *zData; - int iOpenFlags; - void *pHandle; - int iFlags; - int nLen; - - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Data to write */ - zData = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Nothing to write, return immediately */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-write mode */ - iOpenFlags = JX9_IO_OPEN_CREATE|JX9_IO_OPEN_RDWR|JX9_IO_OPEN_TRUNC; - /* Extract the flags */ - iFlags = 0; - if( nArg > 2 ){ - iFlags = jx9_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 &= ~JX9_IO_OPEN_TRUNC; - /* Append mode */ - iOpenFlags |= JX9_IO_OPEN_APPEND; - } - } - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, iOpenFlags, use_include, - nArg > 3 ? apArg[3] : 0, FALSE, FALSE); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( pStream->xWrite ){ - jx9_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 */ - jx9_result_bool(pCtx, 0); - }else{ - /* Total number of bytes written */ - jx9_result_int64(pCtx, n); - } - }else{ - /* Read-only stream */ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, - "Read-only stream(%s): Cannot perform write operation", - pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - } - /* Close the handle */ - jx9StreamCloseHandle(pStream, pHandle); - return JX9_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 jx9Builtin_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFile, *zPtr, *zEnd, *zBuf; - jx9_value *pArray, *pLine; - const jx9_io_stream *pStream; - int use_include = 0; - io_private *pDev; - jx9_int64 n; - int iFlags; - int nLen; - - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Initialize the structure */ - InitIOPrivate(pCtx->pVm, pStream, pDev); - iFlags = 0; - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - } - if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/ ){ - use_include = TRUE; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pLine = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pLine == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-only mode */ - pDev->pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pDev->pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - /* Don't worry about freeing memory, everything will be released automatically - * as soon we return from this function. - */ - return JX9_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 */ - jx9_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; - } - } - jx9_value_string(pLine, zBuf, (int)(zEnd-zBuf)); - /* Insert line */ - jx9_array_add_elem(pArray, 0/* Automatic index assign*/, pLine); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pDev->pHandle); - /* Release the io_private instance */ - ReleaseIOPrivate(pCtx, pDev); - /* Return the created array */ - jx9_result_value(pCtx, pArray); - return JX9_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 jx9Builtin_copy(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pSin, *pSout; - const char *zFile; - char zBuf[8192]; - void *pIn, *pOut; - jx9_int64 n; - int nLen; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1])){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a source and a destination path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the source name */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pSin = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pSin == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the source file in a read-only mode */ - pIn = jx9StreamOpenHandle(pCtx->pVm, pSin, zFile, JX9_IO_OPEN_RDONLY, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pIn == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening source: '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the destination name */ - zFile = jx9_value_to_string(apArg[1], &nLen); - /* Point to the target IO stream device */ - pSout = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pSout == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_OK; - } - if( pSout->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pSin->zName - ); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_OK; - } - /* Try to open the destination file in a read-write mode */ - pOut = jx9StreamOpenHandle(pCtx->pVm, pSout, zFile, - JX9_IO_OPEN_CREATE|JX9_IO_OPEN_TRUNC|JX9_IO_OPEN_RDWR, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pOut == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening destination: '%s'", zFile); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_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 */ - jx9StreamCloseHandle(pSin, pIn); - jx9StreamCloseHandle(pSout, pOut); - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_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 jx9Builtin_fstat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xStat == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xStat(pDev->pHandle, pArray, pValue); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - /* Don't worry about freeing memory here, everything will be - * released automatically as soon we return from this function. - */ - return JX9_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 jx9Builtin_fwrite(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zString; - io_private *pDev; - int nLen, n; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xWrite == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the data to write */ - zString = jx9_value_to_string(apArg[1], &nLen); - if( nArg > 2 ){ - /* Maximum data length to write */ - n = jx9_value_to_int(apArg[2]); - if( n >= 0 && n < nLen ){ - nLen = n; - } - } - if( nLen < 1 ){ - /* Nothing to write */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - n = (int)pStream->xWrite(pDev->pHandle, (const void *)zString, nLen); - if( n < 0 ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* #Bytes written */ - jx9_result_int(pCtx, n); - } - return JX9_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 jx9Builtin_flock(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int nLock; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xLock == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Requested lock operation */ - nLock = jx9_value_to_int(apArg[1]); - /* Lock operation */ - rc = pStream->xLock(pDev->pHandle, nLock); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_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 jx9Builtin_fpassthru(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 n, nRead; - char zBuf[8192]; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_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 = jx9_context_output(pCtx, zBuf, (int)nRead /* FIXME: 64-bit issues */); - if( rc == JX9_ABORT ){ - /* Consumer callback request an operation abort */ - break; - } - } - /* Total number of bytes readen */ - jx9_result_int64(pCtx, nRead); - return JX9_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(jx9_value *pKey, jx9_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 = jx9_value_to_string(pValue, &nLen); - if( nLen < 1 ){ - /* Nothing to write */ - return JX9_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, (jx9_int64)nLen) < 1 ){ - SXUNUSED(pKey); /* cc warning */ - return JX9_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 JX9_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 jx9Builtin_fputcsv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - struct csv_data sCsv; - io_private *pDev; - char *zEol; - int eolen; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_json_array(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Missing/Invalid arguments"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xWrite == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_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 = jx9_value_to_string(apArg[2], &n); - if( n > 0 ){ - sCsv.delimiter = z[0]; - } - if( nArg > 3 ){ - z = jx9_value_to_string(apArg[3], &n); - if( n > 0 ){ - sCsv.enclosure = z[0]; - } - } - } - /* Iterate throw array entries and write csv data */ - jx9_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 JX9_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 */ - jx9_int64 nCount; /* Total number of bytes written */ -}; -/* - * Callback [i.e: Formatted input consumer] for the fprintf function. - */ -static int fprintfConsumer(jx9_context *pCtx, const char *zInput, int nLen, void *pUserData) -{ - fprintf_data *pFdata = (fprintf_data *)pUserData; - jx9_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 JX9_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 jx9Builtin_fprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - fprintf_data sFdata; - const char *zFormat; - io_private *pDev; - int nLen; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return zero */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Invalid arguments"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Empty string, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Prepare our private data */ - sFdata.nCount = 0; - sFdata.pIO = pDev; - /* Format the string */ - jx9InputFormat(fprintfConsumer, pCtx, zFormat, nLen, nArg - 1, &apArg[1], (void *)&sFdata, FALSE); - /* Return total number of bytes written */ - jx9_result_int64(pCtx, sFdata.nCount); - return JX9_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 jx9Builtin_vfprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - fprintf_data sFdata; - const char *zFormat; - jx9_hashmap *pMap; - io_private *pDev; - SySet sArg; - int n, nLen; - if( nArg < 3 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_string(apArg[1]) || !jx9_value_is_json_array(apArg[2]) ){ - /* Missing/Invalid arguments, return zero */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Invalid arguments"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Empty string, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to hashmap */ - pMap = (jx9_hashmap *)apArg[2]->x.pOther; - /* Extract arguments from the hashmap */ - n = jx9HashmapValuesToSet(pMap, &sArg); - /* Prepare our private data */ - sFdata.nCount = 0; - sFdata.pIO = pDev; - /* Format the string */ - jx9InputFormat(fprintfConsumer, pCtx, zFormat, nLen, n, (jx9_value **)SySetBasePtr(&sArg), (void *)&sFdata, TRUE); - /* Return total number of bytes written*/ - jx9_result_int64(pCtx, sFdata.nCount); - SySetRelease(&sArg); - return JX9_OK; -} -/* - * Convert open modes (string passed to the fopen() function) [i.e: 'r', 'w+', 'a', ...] into JX9 flags. - * According to the JX9 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(jx9_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 JX9_IO_OPEN_RDONLY; - } - c = zMode[0]; - if( c == 'r' || c == 'R' ){ - /* Read-only access */ - iFlag = JX9_IO_OPEN_RDONLY; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'w' || c == 'W' ){ - /* Read+Write access */ - iFlag = JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'w' || c == 'W' ){ - /* Overwrite mode. - * If the file does not exists, try to create it - */ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_TRUNC|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'r' || c == 'R' ){ - /* Read+Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_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 = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_APPEND|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_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 = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_EXCL; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'r' || c == 'R' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'c' || c == 'C' ){ - /* Overwrite mode.Create the file if it does not exists.*/ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else{ - /* Invalid mode. Assume a read only open */ - jx9_context_throw_error(pCtx, JX9_CTX_NOTICE, "Invalid open mode, JX9 is assuming a Read-Only open"); - iFlag = JX9_IO_OPEN_RDONLY; - } - while( zMode < zEnd ){ - c = zMode[0]; - if( c == 'b' || c == 'B' ){ - iFlag &= ~JX9_IO_OPEN_TEXT; - iFlag |= JX9_IO_OPEN_BINARY; - }else if( c == 't' || c == 'T' ){ - iFlag &= ~JX9_IO_OPEN_BINARY; - iFlag |= JX9_IO_OPEN_TEXT; - } - zMode++; - } - return iFlag; -} -/* - * Initialize the IO private structure. - */ -static void InitIOPrivate(jx9_vm *pVm, const jx9_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(jx9_context *pCtx, io_private *pDev) -{ - SyBlobRelease(&pDev->sBuffer); - pDev->iMagic = 0x2126; /* Invalid magic number so we can detetct misuse */ - /* Release the whole structure */ - jx9_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_jx9_stream(const jx9_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 JX9 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 jx9Builtin_fopen(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zUri, *zMode; - jx9_value *pResource; - io_private *pDev; - int iLen, imLen; - int iOpenFlags; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path or URL"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the URI and the desired access mode */ - zUri = jx9_value_to_string(apArg[0], &iLen); - if( nArg > 1 ){ - zMode = jx9_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 = jx9VmGetStreamDevice(pCtx->pVm, &zUri, iLen); - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "No stream device is associated with the given URI(%s)", zUri); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pResource = 0; - if( nArg > 3 ){ - pResource = apArg[3]; - }else if( is_jx9_stream(pStream) ){ - /* TICKET 1433-80: The jx9:// stream need a jx9_value to access the underlying - * virtual machine. - */ - pResource = apArg[0]; - } - /* Initialize the structure */ - InitIOPrivate(pCtx->pVm, pStream, pDev); - /* Convert open mode to JX9 flags */ - iOpenFlags = StrModeToFlags(pCtx, zMode, imLen); - /* Try to get a handle */ - pDev->pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zUri, iOpenFlags, - nArg > 2 ? jx9_value_to_bool(apArg[2]) : FALSE, pResource, FALSE, 0); - if( pDev->pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zUri); - jx9_result_bool(pCtx, 0); - jx9_context_free_chunk(pCtx, pDev); - return JX9_OK; - } - /* All done, return the io_private instance as a resource */ - jx9_result_resource(pCtx, pDev); - return JX9_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 jx9Builtin_fclose(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_vm *pVm; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_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 */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_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 */ - jx9StreamCloseHandle(pStream, pDev->pHandle); - /* Release the IO private structure */ - ReleaseIOPrivate(pCtx, pDev); - /* Invalidate the resource handle */ - jx9_value_release(apArg[0]); - } - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -#if !defined(JX9_DISABLE_HASH_FUNC) -/* - * MD5/SHA1 digest consumer. - */ -static int vfsHashConsumer(const void *pData, unsigned int nLen, void *pUserData) -{ - /* Append hex chunk verbatim */ - jx9_result_string((jx9_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 jx9Builtin_md5_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - unsigned char zDigest[16]; - int raw_output = FALSE; - const char *zFile; - MD5Context sCtx; - char zBuf[8192]; - void *pHandle; - jx9_int64 n; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_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 */ - jx9StreamCloseHandle(pStream, pHandle); - /* Extract the digest */ - MD5Final(zDigest, &sCtx); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx); - } - return JX9_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 jx9Builtin_sha1_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - unsigned char zDigest[20]; - int raw_output = FALSE; - const char *zFile; - SHA1Context sCtx; - char zBuf[8192]; - void *pHandle; - jx9_int64 n; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_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 */ - jx9StreamCloseHandle(pStream, pHandle); - /* Extract the digest */ - SHA1Final(&sCtx, zDigest); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx); - } - return JX9_OK; -} -#endif /* JX9_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 jx9Builtin_parse_ini_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zFile; - SyBlob sContents; - void *pHandle; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - SyBlobInit(&sContents, &pCtx->pVm->sAllocator); - /* Read the whole file */ - jx9StreamReadWholeFile(pHandle, pStream, &sContents); - if( SyBlobLength(&sContents) < 1 ){ - /* Empty buffer, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Process the raw INI buffer */ - jx9ParseIniString(pCtx, (const char *)SyBlobData(&sContents), SyBlobLength(&sContents), - nArg > 1 ? jx9_value_to_bool(apArg[1]) : 0); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Release the working buffer */ - SyBlobRelease(&sContents); - return JX9_OK; -} -/* - * Section: - * ZIP archive processing. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.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 */ - jx9_int64 nSize; /* Map size */ - const jx9_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 jx9Builtin_zip_open(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - SyArchive *pArchive; - zip_raw_data *pRaw; - const char *zFile; - SyBlob *pContents; - void *pHandle; - int nLen; - sxi32 rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create an in-memory archive */ - pArchive = (SyArchive *)jx9_context_alloc_chunk(pCtx, sizeof(SyArchive)+sizeof(zip_raw_data), TRUE, FALSE); - if( pArchive == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_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 jx9_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 = jx9ExportBuiltinVfs(); - if( pVfs && pVfs->xMmap ){ - rc = pVfs->xMmap(zFile, &pRaw->raw.mmap.pMap, &pRaw->raw.mmap.nSize); - if( rc == JX9_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 */ - jx9_context_free_chunk(pCtx, pArchive); - /* Something goes wrong with this ZIP archive, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_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 = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pContents = &pRaw->raw.sBlob; - SyBlobInit(pContents, &pCtx->pVm->sAllocator); - /* Read the whole file */ - jx9StreamReadWholeFile(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 */ - jx9StreamCloseHandle(pStream, pHandle); - if( rc != SXRET_OK ){ - /* Release the working buffer */ - SyBlobRelease(pContents); - /* Release the allocated chunk */ - jx9_context_free_chunk(pCtx, pArchive); - /* Something goes wrong with this ZIP archive, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } -success: - /* Reset the loop cursor */ - SyArchiveResetLoopCursor(pArchive); - /* Return the in-memory archive as a resource handle */ - jx9_result_resource(pCtx, pArchive); - return JX9_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 jx9Builtin_zip_close(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchive *pArchive; - zip_raw_data *pRaw; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - return JX9_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 jx9_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 */ - jx9_context_free_chunk(pCtx, pArchive); - return JX9_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 jx9Builtin_zip_read(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pNext = 0; /* cc warning */ - SyArchive *pArchive; - sxi32 rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the next entry */ - rc = SyArchiveGetNextEntry(pArchive, &pNext); - if( rc != SXRET_OK ){ - /* No more entries in the central directory, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return as a resource handle */ - jx9_result_resource(pCtx, pNext); - /* Point to the ZIP raw data */ - pNext->pUserData = (void *)&pArchive[1]; - } - return JX9_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 jx9Builtin_zip_entry_open(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - SyArchive *pArchive; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_resource(apArg[1]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[1]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* All done. Actually this function is a no-op, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_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 jx9Builtin_zip_entry_close(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Reset the read cursor */ - pEntry->nReadCount = 0; - /*All done. Actually this function is a no-op, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_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 jx9Builtin_zip_entry_name(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - SyString *pName; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry name */ - pName = &pEntry->sFileName; - jx9_result_string(pCtx, pName->zString, (int)pName->nByte); - return JX9_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 jx9Builtin_zip_entry_filesize(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry size */ - jx9_result_int64(pCtx, (jx9_int64)pEntry->nByte); - return JX9_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 jx9Builtin_zip_entry_compressedsize(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry compressed size */ - jx9_result_int64(pCtx, (jx9_int64)pEntry->nByteCompr); - return JX9_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 jx9Builtin_zip_entry_read(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - zip_raw_data *pRaw; - const char *zData; - int iLength; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zData = 0; - if( pEntry->nReadCount >= pEntry->nByteCompr ){ - /* No more data to read, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set a default read length */ - iLength = 1024; - if( nArg > 1 ){ - iLength = jx9_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 */ - jx9_result_string(pCtx, zData, iLength); - return JX9_OK; -} -/* - * bool zip_entry_reset_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. - */ -static int jx9Builtin_zip_entry_reset_cursor(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Reset the cursor */ - pEntry->nReadCount = 0; - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_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 jx9Builtin_zip_entry_compressionmethod(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - switch(pEntry->nComprMeth){ - case 0: - /* No compression;entry is stored */ - jx9_result_string(pCtx, "stored", (int)sizeof("stored")-1); - break; - case 8: - /* Entry is deflated (Default compression algorithm) */ - jx9_result_string(pCtx, "deflate", (int)sizeof("deflate")-1); - break; - /* Exotic compression algorithms */ - case 1: - jx9_result_string(pCtx, "shrunk", (int)sizeof("shrunk")-1); - break; - case 2: - case 3: - case 4: - case 5: - /* Entry is reduced */ - jx9_result_string(pCtx, "reduced", (int)sizeof("reduced")-1); - break; - case 6: - /* Entry is imploded */ - jx9_result_string(pCtx, "implode", (int)sizeof("implode")-1); - break; - default: - jx9_result_string(pCtx, "unknown", (int)sizeof("unknown")-1); - break; - } - return JX9_OK; -} -#endif /* #ifndef JX9_DISABLE_BUILTIN_FUNC*/ -/* NULL VFS [i.e: a no-op VFS]*/ -static const jx9_vfs null_vfs = { - "null_vfs", - JX9_VFS_VERSION, - 0, /* int (*xChdir)(const char *) */ - 0, /* int (*xChroot)(const char *); */ - 0, /* int (*xGetcwd)(jx9_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 *, jx9_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, /* jx9_int64 (*xFreeSpace)(const char *) */ - 0, /* jx9_int64 (*xTotalSpace)(const char *) */ - 0, /* jx9_int64 (*xFileSize)(const char *) */ - 0, /* jx9_int64 (*xFileAtime)(const char *) */ - 0, /* jx9_int64 (*xFileMtime)(const char *) */ - 0, /* jx9_int64 (*xFileCtime)(const char *) */ - 0, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - 0, /* int (*xlStat)(const char *, jx9_value *, jx9_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 *, jx9_context *) */ - 0, /* int (*xGetenv)(const char *, jx9_context *) */ - 0, /* int (*xSetenv)(const char *, const char *) */ - 0, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - 0, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - 0, /* void (*xUnmap)(void *, jx9_int64); */ - 0, /* int (*xLink)(const char *, const char *, int) */ - 0, /* int (*xUmask)(int) */ - 0, /* void (*xTempDir)(jx9_context *) */ - 0, /* unsigned int (*xProcessId)(void) */ - 0, /* int (*xUid)(void) */ - 0, /* int (*xGid)(void) */ - 0, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO -#ifdef __WINNT__ -/* - * Windows VFS implementation for the JX9 engine. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* What follows here is code that is specific to windows systems. */ -#include -/* -** 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 *jx9utf8ToUnicode(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 *jx9convertUtf8Filename(const char *zFilename){ - void *zConverted; - zConverted = jx9utf8ToUnicode(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 *jx9unicodeToUtf8(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 = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = SetCurrentDirectoryW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xGetcwd)(jx9_context *) */ -static int WinVfs_getcwd(jx9_context *pCtx) -{ - WCHAR zDir[2048]; - char *zConverted; - DWORD rc; - /* Get the current directory */ - rc = GetCurrentDirectoryW(sizeof(zDir), zDir); - if( rc < 1 ){ - return -1; - } - zConverted = jx9unicodeToUtf8(zDir); - if( zConverted == 0 ){ - return -1; - } - jx9_result_string(pCtx, zConverted, -1/*Compute length automatically*/); /* Will make it's own copy */ - HeapFree(GetProcessHeap(), 0, zConverted); - return JX9_OK; -} -/* int (*xMkdir)(const char *, int, int) */ -static int WinVfs_mkdir(const char *zPath, int mode, int recursive) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - mode= 0; /* MSVC warning */ - recursive = 0; - rc = CreateDirectoryW((LPCWSTR)pConverted, 0); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xRmdir)(const char *) */ -static int WinVfs_rmdir(const char *zPath) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = RemoveDirectoryW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xIsdir)(const char *) */ -static int WinVfs_isdir(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(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) ? JX9_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 = jx9convertUtf8Filename(zOld); - if( pOld == 0 ){ - return -1; - } - pNew = jx9convertUtf8Filename(zNew); - if( pNew ){ - rc = MoveFileW((LPCWSTR)pOld, (LPCWSTR)pNew); - } - HeapFree(GetProcessHeap(), 0, pOld); - if( pNew ){ - HeapFree(GetProcessHeap(), 0, pNew); - } - return rc ? JX9_OK : - 1; -} -/* int (*xRealpath)(const char *, jx9_context *) */ -static int WinVfs_Realpath(const char *zPath, jx9_context *pCtx) -{ - WCHAR zTemp[2048]; - void *pPath; - char *zReal; - DWORD n; - pPath = jx9convertUtf8Filename(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 = jx9unicodeToUtf8(zTemp); - if( zReal == 0 ){ - return -1; - } - jx9_result_string(pCtx, zReal, -1); /* Will make it's own copy */ - HeapFree(GetProcessHeap(), 0, zReal); - return JX9_OK; -} -/* int (*xSleep)(unsigned int) */ -static int WinVfs_Sleep(unsigned int uSec) -{ - Sleep(uSec/1000/*uSec per Millisec */); - return JX9_OK; -} -/* int (*xUnlink)(const char *) */ -static int WinVfs_unlink(const char *zPath) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = DeleteFileW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : - 1; -} -/* jx9_int64 (*xFreeSpace)(const char *) */ -static jx9_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 = jx9convertUtf8Filename(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 (jx9_int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect; -#endif -} -/* jx9_int64 (*xTotalSpace)(const char *) */ -static jx9_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 = jx9convertUtf8Filename(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 (jx9_int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect; -#endif -} -/* int (*xFileExists)(const char *) */ -static int WinVfs_FileExists(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - return JX9_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; -} -/* jx9_int64 (*xFileSize)(const char *) */ -static jx9_int64 WinVfs_FileSize(const char *zPath) -{ - DWORD dwLow, dwHigh; - void * pConverted; - jx9_int64 nSize; - HANDLE pHandle; - - pConverted = jx9convertUtf8Filename(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 jx9_int64 convertWindowsTimeToUnixTime(LPFILETIME pTime) -{ - jx9_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(jx9_int64 nUnixtime, LPFILETIME pOut) -{ - jx9_int64 result = EPOCH_DIFFERENCE; - result += nUnixtime; - result *= 10000000LL; - pOut->dwHighDateTime = (DWORD)(nUnixtime>>32); - pOut->dwLowDateTime = (DWORD)nUnixtime; -} -/* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ -static int WinVfs_Touch(const char *zPath, jx9_int64 touch_time, jx9_int64 access_time) -{ - FILETIME sTouch, sAccess; - void *pConverted; - void *pHandle; - BOOL rc = 0; - pConverted = jx9convertUtf8Filename(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 ? JX9_OK : -1; -} -/* jx9_int64 (*xFileAtime)(const char *) */ -static jx9_int64 WinVfs_FileAtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 atime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(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; -} -/* jx9_int64 (*xFileMtime)(const char *) */ -static jx9_int64 WinVfs_FileMtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 mtime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(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; -} -/* jx9_int64 (*xFileCtime)(const char *) */ -static jx9_int64 WinVfs_FileCtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 ctime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(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 *, jx9_value *, jx9_value *) */ -/* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ -static int WinVfs_Stat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void *pConverted; - HANDLE pHandle; - BOOL rc; - pConverted = jx9convertUtf8Filename(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 */ - jx9_value_int64(pWorker, (jx9_int64)sInfo.dwVolumeSerialNumber); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)sInfo.nNumberOfLinks); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* int (*xIsfile)(const char *) */ -static int WinVfs_isfile(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(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)) ? JX9_OK : -1; -} -/* int (*xIslink)(const char *) */ -static int WinVfs_islink(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(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) ? JX9_OK : -1; -} -/* int (*xWritable)(const char *) */ -static int WinVfs_iswritable(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(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 JX9_OK; -} -/* int (*xExecutable)(const char *) */ -static int WinVfs_isexecutable(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(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 JX9_OK; -} -/* int (*xFiletype)(const char *, jx9_context *) */ -static int WinVfs_Filetype(const char *zPath, jx9_context *pCtx) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - if(dwAttr & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE) ){ - jx9_result_string(pCtx, "file", sizeof("file")-1); - }else if(dwAttr & FILE_ATTRIBUTE_DIRECTORY){ - jx9_result_string(pCtx, "dir", sizeof("dir")-1); - }else if(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT){ - jx9_result_string(pCtx, "link", sizeof("link")-1); - }else if(dwAttr & (FILE_ATTRIBUTE_DEVICE)){ - jx9_result_string(pCtx, "block", sizeof("block")-1); - }else{ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - } - return JX9_OK; -} -/* int (*xGetenv)(const char *, jx9_context *) */ -static int WinVfs_Getenv(const char *zVar, jx9_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; - } - jx9_result_string(pCtx, zValue, (int)n); - return JX9_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 ? JX9_OK : -1; -} -/* int (*xMmap)(const char *, void **, jx9_int64 *) */ -static int WinVfs_Mmap(const char *zPath, void **ppMap, jx9_int64 *pSize) -{ - DWORD dwSizeLow, dwSizeHigh; - HANDLE pHandle, pMapHandle; - void *pConverted, *pView; - - pConverted = jx9convertUtf8Filename(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 = ((jx9_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 ? JX9_OK : -1; -} -/* void (*xUnmap)(void *, jx9_int64) */ -static void WinVfs_Unmap(void *pView, jx9_int64 nSize) -{ - nSize = 0; /* Compiler warning */ - UnmapViewOfFile(pView); -} -/* void (*xTempDir)(jx9_context *) */ -static void WinVfs_TempDir(jx9_context *pCtx) -{ - CHAR zTemp[1024]; - DWORD n; - n = GetTempPathA(sizeof(zTemp), zTemp); - if( n < 1 ){ - /* Assume the default windows temp directory */ - jx9_result_string(pCtx, "C:\\Windows\\Temp", -1/*Compute length automatically*/); - }else{ - jx9_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; -} - -/* Export the windows vfs */ -static const jx9_vfs sWinVfs = { - "Windows_vfs", - JX9_VFS_VERSION, - WinVfs_chdir, /* int (*xChdir)(const char *) */ - 0, /* int (*xChroot)(const char *); */ - WinVfs_getcwd, /* int (*xGetcwd)(jx9_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 *, jx9_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, /* jx9_int64 (*xFreeSpace)(const char *) */ - WinVfs_DiskTotalSpace, /* jx9_int64 (*xTotalSpace)(const char *) */ - WinVfs_FileSize, /* jx9_int64 (*xFileSize)(const char *) */ - WinVfs_FileAtime, /* jx9_int64 (*xFileAtime)(const char *) */ - WinVfs_FileMtime, /* jx9_int64 (*xFileMtime)(const char *) */ - WinVfs_FileCtime, /* jx9_int64 (*xFileCtime)(const char *) */ - WinVfs_Stat, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - WinVfs_Stat, /* int (*xlStat)(const char *, jx9_value *, jx9_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 *, jx9_context *) */ - WinVfs_Getenv, /* int (*xGetenv)(const char *, jx9_context *) */ - WinVfs_Setenv, /* int (*xSetenv)(const char *, const char *) */ - WinVfs_Touch, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - WinVfs_Mmap, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - WinVfs_Unmap, /* void (*xUnmap)(void *, jx9_int64); */ - 0, /* int (*xLink)(const char *, const char *, int) */ - 0, /* int (*xUmask)(int) */ - WinVfs_TempDir, /* void (*xTempDir)(jx9_context *) */ - WinVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ - 0, /* int (*xUid)(void) */ - 0, /* int (*xGid)(void) */ - 0, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -/* Windows file IO */ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int WinFile_Open(const char *zPath, int iOpenMode, jx9_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 = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Set the desired flags according to the open mode */ - if( iOpenMode & JX9_IO_OPEN_CREATE ){ - /* Open existing file, or create if it doesn't exist */ - dwCreate = OPEN_ALWAYS; - if( iOpenMode & JX9_IO_OPEN_TRUNC ){ - /* If the specified file exists and is writable, the function overwrites the file */ - dwCreate = CREATE_ALWAYS; - } - }else if( iOpenMode & JX9_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 & JX9_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 & JX9_IO_OPEN_RDWR ){ - /* Read+Write access */ - dwAccess |= GENERIC_WRITE; - }else if( iOpenMode & JX9_IO_OPEN_WRONLY ){ - /* Write only access */ - dwAccess = GENERIC_WRITE; - } - if( iOpenMode & JX9_IO_OPEN_APPEND ){ - /* Append mode */ - dwAccess = FILE_APPEND_DATA; - } - if( iOpenMode & JX9_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 JX9_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 *, jx9_value *, void **) */ -static int WinDir_Open(const char *zPath, jx9_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 = jx9convertUtf8Filename(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 JX9_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 *, jx9_context *) */ -static int WinDir_Read(void *pUserData, jx9_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 = jx9unicodeToUtf8(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 */ - jx9_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 JX9_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; - } -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64); */ -static jx9_int64 WinFile_Read(void *pOS, void *pBuffer, jx9_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 (jx9_int64)nRd; -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64); */ -static jx9_int64 WinFile_Write(void *pOS, const void *pBuffer, jx9_int64 nWrite) -{ - const char *zData = (const char *)pBuffer; - HANDLE pHandle = (HANDLE)pOS; - jx9_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 *, jx9_int64, int) */ -static int WinFile_Seek(void *pUserData, jx9_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 JX9_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 ? JX9_OK : -1 /* Lock error */; -} -/* jx9_int64 (*xTell)(void *) */ -static jx9_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 (jx9_int64)dwNew; -} -/* int (*xTrunc)(void *, jx9_int64) */ -static int WinFile_Trunc(void *pUserData, jx9_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 ? JX9_OK : -1; -} -/* int (*xSync)(void *); */ -static int WinFile_Sync(void *pUserData) -{ - HANDLE pHandle = (HANDLE)pUserData; - BOOL rc; - rc = FlushFileBuffers(pHandle); - return rc ? JX9_OK : - 1; -} -/* int (*xStat)(void *, jx9_value *, jx9_value *) */ -static int WinFile_Stat(void *pUserData, jx9_value *pArray, jx9_value *pWorker) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - HANDLE pHandle = (HANDLE)pUserData; - BOOL rc; - rc = GetFileInformationByHandle(pHandle, &sInfo); - if( !rc ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)sInfo.dwVolumeSerialNumber); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)sInfo.nNumberOfLinks); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* Export the file:// stream */ -static const jx9_io_stream sWinFileStream = { - "file", /* Stream name */ - JX9_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 JX9 engine. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* int (*xchdir)(const char *) */ -static int UnixVfs_chdir(const char *zPath) -{ - int rc; - rc = chdir(zPath); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xGetcwd)(jx9_context *) */ -static int UnixVfs_getcwd(jx9_context *pCtx) -{ - char zBuf[4096]; - char *zDir; - /* Get the current directory */ - zDir = getcwd(zBuf, sizeof(zBuf)); - if( zDir == 0 ){ - return -1; - } - jx9_result_string(pCtx, zDir, -1/*Compute length automatically*/); - return JX9_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 ? JX9_OK : -1; -} -/* int (*xRmdir)(const char *) */ -static int UnixVfs_rmdir(const char *zPath) -{ - int rc; - rc = rmdir(zPath); - return rc == 0 ? JX9_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 ? JX9_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 ? JX9_OK : -1; -} -/* int (*xRealpath)(const char *, jx9_context *) */ -static int UnixVfs_Realpath(const char *zPath, jx9_context *pCtx) -{ -#ifndef JX9_UNIX_OLD_LIBC - char *zReal; - zReal = realpath(zPath, 0); - if( zReal == 0 ){ - return -1; - } - jx9_result_string(pCtx, zReal, -1/*Compute length automatically*/); - /* Release the allocated buffer */ - free(zReal); - return JX9_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 JX9_OK; -} -/* int (*xUnlink)(const char *) */ -static int UnixVfs_unlink(const char *zPath) -{ - int rc; - rc = unlink(zPath); - return rc == 0 ? JX9_OK : -1 ; -} -/* int (*xFileExists)(const char *) */ -static int UnixVfs_FileExists(const char *zPath) -{ - int rc; - rc = access(zPath, F_OK); - return rc == 0 ? JX9_OK : -1; -} -/* jx9_int64 (*xFileSize)(const char *) */ -static jx9_int64 UnixVfs_FileSize(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_size; -} -/* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ -static int UnixVfs_Touch(const char *zPath, jx9_int64 touch_time, jx9_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 JX9_OK; -} -/* jx9_int64 (*xFileAtime)(const char *) */ -static jx9_int64 UnixVfs_FileAtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_atime; -} -/* jx9_int64 (*xFileMtime)(const char *) */ -static jx9_int64 UnixVfs_FileMtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_mtime; -} -/* jx9_int64 (*xFileCtime)(const char *) */ -static jx9_int64 UnixVfs_FileCtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_ctime; -} -/* int (*xStat)(const char *, jx9_value *, jx9_value *) */ -static int UnixVfs_Stat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ -static int UnixVfs_lStat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = lstat(zPath, &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_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 ? JX9_OK : - 1; -} -/* int (*xChown)(const char *, const char *) */ -static int UnixVfs_Chown(const char *zPath, const char *zUser) -{ -#ifndef JX9_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 ? JX9_OK : -1; -#else - SXUNUSED(zPath); - SXUNUSED(zUser); - return -1; -#endif /* JX9_UNIX_STATIC_BUILD */ -} -/* int (*xChgrp)(const char *, const char *) */ -static int UnixVfs_Chgrp(const char *zPath, const char *zGroup) -{ -#ifndef JX9_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 ? JX9_OK : -1; -#else - SXUNUSED(zPath); - SXUNUSED(zGroup); - return -1; -#endif /* JX9_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 ? JX9_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 ? JX9_OK : -1 ; -} -/* int (*xReadable)(const char *) */ -static int UnixVfs_isreadable(const char *zPath) -{ - int rc; - rc = access(zPath, R_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xWritable)(const char *) */ -static int UnixVfs_iswritable(const char *zPath) -{ - int rc; - rc = access(zPath, W_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xExecutable)(const char *) */ -static int UnixVfs_isexecutable(const char *zPath) -{ - int rc; - rc = access(zPath, X_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xFiletype)(const char *, jx9_context *) */ -static int UnixVfs_Filetype(const char *zPath, jx9_context *pCtx) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - if(S_ISREG(st.st_mode) ){ - jx9_result_string(pCtx, "file", sizeof("file")-1); - }else if(S_ISDIR(st.st_mode)){ - jx9_result_string(pCtx, "dir", sizeof("dir")-1); - }else if(S_ISLNK(st.st_mode)){ - jx9_result_string(pCtx, "link", sizeof("link")-1); - }else if(S_ISBLK(st.st_mode)){ - jx9_result_string(pCtx, "block", sizeof("block")-1); - }else if(S_ISSOCK(st.st_mode)){ - jx9_result_string(pCtx, "socket", sizeof("socket")-1); - }else if(S_ISFIFO(st.st_mode)){ - jx9_result_string(pCtx, "fifo", sizeof("fifo")-1); - }else{ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - } - return JX9_OK; -} -/* int (*xGetenv)(const char *, jx9_context *) */ -static int UnixVfs_Getenv(const char *zVar, jx9_context *pCtx) -{ - char *zEnv; - zEnv = getenv(zVar); - if( zEnv == 0 ){ - return -1; - } - jx9_result_string(pCtx, zEnv, -1/*Compute length automatically*/); - return JX9_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 ? JX9_OK : -1; -} -/* int (*xMmap)(const char *, void **, jx9_int64 *) */ -static int UnixVfs_Mmap(const char *zPath, void **ppMap, jx9_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 = JX9_OK; - if( pMap == MAP_FAILED ){ - rc = -1; - }else{ - /* Point to the memory view */ - *ppMap = pMap; - *pSize = (jx9_int64)st.st_size; - } - close(fd); - return rc; -} -/* void (*xUnmap)(void *, jx9_int64) */ -static void UnixVfs_Unmap(void *pView, jx9_int64 nSize) -{ - munmap(pView, (size_t)nSize); -} -/* void (*xTempDir)(jx9_context *) */ -static void UnixVfs_TempDir(jx9_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) ){ - jx9_result_string(pCtx, zDir, -1); - return; - } - for(i=0; ipw_name, -1); -#else - jx9_result_string(pCtx, "Unknown", -1); -#endif /* JX9_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 ? JX9_OK : -1; -} -/* int (*xChroot)(const char *) */ -static int UnixVfs_chroot(const char *zRootDir) -{ - int rc; - rc = chroot(zRootDir); - return rc == 0 ? JX9_OK : -1; -} -/* Export the UNIX vfs */ -static const jx9_vfs sUnixVfs = { - "Unix_vfs", - JX9_VFS_VERSION, - UnixVfs_chdir, /* int (*xChdir)(const char *) */ - UnixVfs_chroot, /* int (*xChroot)(const char *); */ - UnixVfs_getcwd, /* int (*xGetcwd)(jx9_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 *, jx9_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, /* jx9_int64 (*xFreeSpace)(const char *) */ - 0, /* jx9_int64 (*xTotalSpace)(const char *) */ - UnixVfs_FileSize, /* jx9_int64 (*xFileSize)(const char *) */ - UnixVfs_FileAtime, /* jx9_int64 (*xFileAtime)(const char *) */ - UnixVfs_FileMtime, /* jx9_int64 (*xFileMtime)(const char *) */ - UnixVfs_FileCtime, /* jx9_int64 (*xFileCtime)(const char *) */ - UnixVfs_Stat, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - UnixVfs_lStat, /* int (*xlStat)(const char *, jx9_value *, jx9_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 *, jx9_context *) */ - UnixVfs_Getenv, /* int (*xGetenv)(const char *, jx9_context *) */ - UnixVfs_Setenv, /* int (*xSetenv)(const char *, const char *) */ - UnixVfs_Touch, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - UnixVfs_Mmap, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - UnixVfs_Unmap, /* void (*xUnmap)(void *, jx9_int64); */ - UnixVfs_link, /* int (*xLink)(const char *, const char *, int) */ - UnixVfs_Umask, /* int (*xUmask)(int) */ - UnixVfs_TempDir, /* void (*xTempDir)(jx9_context *) */ - UnixVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ - UnixVfs_uid, /* int (*xUid)(void) */ - UnixVfs_gid, /* int (*xGid)(void) */ - UnixVfs_Username, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -/* UNIX File IO */ -#define JX9_UNIX_OPEN_MODE 0640 /* Default open mode */ -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int UnixFile_Open(const char *zPath, int iOpenMode, jx9_value *pResource, void **ppHandle) -{ - int iOpen = O_RDONLY; - int fd; - /* Set the desired flags according to the open mode */ - if( iOpenMode & JX9_IO_OPEN_CREATE ){ - /* Open existing file, or create if it doesn't exist */ - iOpen = O_CREAT; - if( iOpenMode & JX9_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 & JX9_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 & JX9_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 & JX9_IO_OPEN_RDWR ){ - /* Read+Write access */ - iOpen &= ~O_RDONLY; - iOpen |= O_RDWR; - }else if( iOpenMode & JX9_IO_OPEN_WRONLY ){ - /* Write only access */ - iOpen &= ~O_RDONLY; - iOpen |= O_WRONLY; - } - if( iOpenMode & JX9_IO_OPEN_APPEND ){ - /* Append mode */ - iOpen |= O_APPEND; - } -#ifdef O_TEMP - if( iOpenMode & JX9_IO_OPEN_TEMP ){ - /* File is temporary */ - iOpen |= O_TEMP; - } -#endif - /* Open the file now */ - fd = open(zPath, iOpen, JX9_UNIX_OPEN_MODE); - if( fd < 0 ){ - /* IO error */ - return -1; - } - /* Save the handle */ - *ppHandle = SX_INT_TO_PTR(fd); - return JX9_OK; -} -/* int (*xOpenDir)(const char *, jx9_value *, void **) */ -static int UnixDir_Open(const char *zPath, jx9_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 JX9_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 *, jx9_context *) */ -static int UnixDir_Read(void *pUserData, jx9_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 */ - jx9_result_string(pCtx, zName, (int)n); - return JX9_OK; -} -/* void (*xRewindDir)(void *) */ -static void UnixDir_Rewind(void *pUserData) -{ - rewinddir((DIR *)pUserData); -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64); */ -static jx9_int64 UnixFile_Read(void *pUserData, void *pBuffer, jx9_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 (jx9_int64)nRd; -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64); */ -static jx9_int64 UnixFile_Write(void *pUserData, const void *pBuffer, jx9_int64 nWrite) -{ - const char *zData = (const char *)pBuffer; - int fd = SX_PTR_TO_INT(pUserData); - jx9_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 *, jx9_int64, int) */ -static int UnixFile_Seek(void *pUserData, jx9_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 JX9_OK; -} -/* int (*xLock)(void *, int) */ -static int UnixFile_Lock(void *pUserData, int lock_type) -{ - int fd = SX_PTR_TO_INT(pUserData); - int rc = JX9_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 ? JX9_OK : -1; -} -/* jx9_int64 (*xTell)(void *) */ -static jx9_int64 UnixFile_Tell(void *pUserData) -{ - off_t iNew; - iNew = lseek(SX_PTR_TO_INT(pUserData), 0, SEEK_CUR); - return (jx9_int64)iNew; -} -/* int (*xTrunc)(void *, jx9_int64) */ -static int UnixFile_Trunc(void *pUserData, jx9_int64 nOfft) -{ - int rc; - rc = ftruncate(SX_PTR_TO_INT(pUserData), (off_t)nOfft); - if( rc != 0 ){ - return -1; - } - return JX9_OK; -} -/* int (*xSync)(void *); */ -static int UnixFile_Sync(void *pUserData) -{ - int rc; - rc = fsync(SX_PTR_TO_INT(pUserData)); - return rc == 0 ? JX9_OK : - 1; -} -/* int (*xStat)(void *, jx9_value *, jx9_value *) */ -static int UnixFile_Stat(void *pUserData, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = fstat(SX_PTR_TO_INT(pUserData), &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* Export the file:// stream */ -static const jx9_io_stream sUnixFileStream = { - "file", /* Stream name */ - JX9_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 /* JX9_DISABLE_DISK_IO */ -#endif /* JX9_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 JX9_DISABLE_DISK_IO/JX9_DISABLE_BUILTIN_FUNC - * directives defined then this function return the null_vfs instead. - */ -JX9_PRIVATE const jx9_vfs * jx9ExportBuiltinVfs(void) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifdef JX9_DISABLE_DISK_IO - return &null_vfs; -#else -#ifdef __WINNT__ - return &sWinVfs; -#elif defined(__UNIXES__) - return &sUnixVfs; -#else - return &null_vfs; -#endif /* __WINNT__/__UNIXES__ */ -#endif /*JX9_DISABLE_DISK_IO*/ -#else - return &null_vfs; -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_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 -/* - * jx9:// Accessing various I/O streams - * According to the JX9 langage reference manual - * JX9 provides a number of miscellaneous I/O streams that allow access to JX9's own input - * and output streams, the standard input, output and error file descriptors. - * jx9://stdin, jx9://stdout and jx9://stderr: - * Allow direct access to the corresponding input or output stream of the JX9 process. - * The stream references a duplicate file descriptor, so if you open jx9://stdin and later - * close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. - * jx9://stdin is read-only, whereas jx9://stdout and jx9://stderr are write-only. - * jx9://output - * jx9://output is a write-only stream that allows you to write to the output buffer - * mechanism in the same way as print and print. - */ -typedef struct jx9_stream_data jx9_stream_data; -/* Supported IO streams */ -#define JX9_IO_STREAM_STDIN 1 /* jx9://stdin */ -#define JX9_IO_STREAM_STDOUT 2 /* jx9://stdout */ -#define JX9_IO_STREAM_STDERR 3 /* jx9://stderr */ -#define JX9_IO_STREAM_OUTPUT 4 /* jx9://output */ - /* The following structure is the private data associated with the jx9:// stream */ -struct jx9_stream_data -{ - jx9_vm *pVm; /* VM that own this instance */ - int iType; /* Stream type */ - union{ - void *pHandle; /* Stream handle */ - jx9_output_consumer sConsumer; /* VM output consumer */ - }x; -}; -/* - * Allocate a new instance of the jx9_stream_data structure. - */ -static jx9_stream_data * JX9StreamDataInit(jx9_vm *pVm, int iType) -{ - jx9_stream_data *pData; - if( pVm == 0 ){ - return 0; - } - /* Allocate a new instance */ - pData = (jx9_stream_data *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(jx9_stream_data)); - if( pData == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pData, sizeof(jx9_stream_data)); - /* Initialize fields */ - pData->iType = iType; - if( iType == JX9_IO_STREAM_OUTPUT ){ - /* Point to the default VM consumer routine. */ - pData->x.sConsumer = pVm->sVmConsumer; - }else{ -#ifdef __WINNT__ - DWORD nChannel; - switch(iType){ - case JX9_IO_STREAM_STDOUT: nChannel = STD_OUTPUT_HANDLE; break; - case JX9_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 JX9_IO_STREAM_STDOUT: ifd = STDOUT_FILENO; break; - case JX9_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 jx9:// IO streams routines - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int JX9StreamData_Open(const char *zName, int iMode, jx9_value *pResource, void ** ppHandle) -{ - jx9_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 = JX9_IO_STREAM_STDIN; - }else if( SyStrnicmp(sStream.zString, "output", sizeof("output")-1) == 0 ){ - iMode = JX9_IO_STREAM_OUTPUT; - }else if( SyStrnicmp(sStream.zString, "stdout", sizeof("stdout")-1) == 0 ){ - iMode = JX9_IO_STREAM_STDOUT; - }else if( SyStrnicmp(sStream.zString, "stderr", sizeof("stderr")-1) == 0 ){ - iMode = JX9_IO_STREAM_STDERR; - }else{ - /* unknown stream name */ - return -1; - } - /* Create our handle */ - pData = JX9StreamDataInit(pResource?pResource->pVm:0, iMode); - if( pData == 0 ){ - return -1; - } - /* Make the handle public */ - *ppHandle = (void *)pData; - return JX9_OK; -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64) */ -static jx9_int64 JX9StreamData_Read(void *pHandle, void *pBuffer, jx9_int64 nDatatoRead) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - if( pData == 0 ){ - return -1; - } - if( pData->iType != JX9_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 (jx9_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 (jx9_int64)nRd; - } -#else - return -1; -#endif -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64) */ -static jx9_int64 JX9StreamData_Write(void *pHandle, const void *pBuf, jx9_int64 nWrite) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - if( pData == 0 ){ - return -1; - } - if( pData->iType == JX9_IO_STREAM_STDIN ){ - /* Forbidden */ - return -1; - }else if( pData->iType == JX9_IO_STREAM_OUTPUT ){ - jx9_output_consumer *pCons = &pData->x.sConsumer; - int rc; - /* Call the vm output consumer */ - rc = pCons->xConsumer(pBuf, (unsigned int)nWrite, pCons->pUserData); - if( rc == JX9_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 (jx9_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 (jx9_int64)nWr; - } -#else - return -1; -#endif -} -/* void (*xClose)(void *) */ -static void JX9StreamData_Close(void *pHandle) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - jx9_vm *pVm; - if( pData == 0 ){ - return; - } - pVm = pData->pVm; - /* Free the instance */ - SyMemBackendFree(&pVm->sAllocator, pData); -} -/* Export the jx9:// stream */ -static const jx9_io_stream sjx9Stream = { - "jx9", - JX9_IO_STREAM_VERSION, - JX9StreamData_Open, /* xOpen */ - 0, /* xOpenDir */ - JX9StreamData_Close, /* xClose */ - 0, /* xCloseDir */ - JX9StreamData_Read, /* xRead */ - 0, /* xReadDir */ - JX9StreamData_Write, /* xWrite */ - 0, /* xSeek */ - 0, /* xLock */ - 0, /* xRewindDir */ - 0, /* xTell */ - 0, /* xTrunc */ - 0, /* xSeek */ - 0 /* xStat */ -}; -#endif /* JX9_DISABLE_DISK_IO */ -/* - * Return TRUE if we are dealing with the jx9:// stream. - * FALSE otherwise. - */ -static int is_jx9_stream(const jx9_io_stream *pStream) -{ -#ifndef JX9_DISABLE_DISK_IO - return pStream == &sjx9Stream; -#else - SXUNUSED(pStream); /* cc warning */ - return 0; -#endif /* JX9_DISABLE_DISK_IO */ -} - -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Export the IO routines defined above and the built-in IO streams - * [i.e: file://, jx9://]. - * Note: - * If the engine is compiled with the JX9_DISABLE_BUILTIN_FUNC directive - * defined then this function is a no-op. - */ -JX9_PRIVATE sxi32 jx9RegisterIORoutine(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC - /* VFS functions */ - static const jx9_builtin_func aVfsFunc[] = { - {"chdir", jx9Vfs_chdir }, - {"chroot", jx9Vfs_chroot }, - {"getcwd", jx9Vfs_getcwd }, - {"rmdir", jx9Vfs_rmdir }, - {"is_dir", jx9Vfs_is_dir }, - {"mkdir", jx9Vfs_mkdir }, - {"rename", jx9Vfs_rename }, - {"realpath", jx9Vfs_realpath}, - {"sleep", jx9Vfs_sleep }, - {"usleep", jx9Vfs_usleep }, - {"unlink", jx9Vfs_unlink }, - {"delete", jx9Vfs_unlink }, - {"chmod", jx9Vfs_chmod }, - {"chown", jx9Vfs_chown }, - {"chgrp", jx9Vfs_chgrp }, - {"disk_free_space", jx9Vfs_disk_free_space }, - {"disk_total_space", jx9Vfs_disk_total_space}, - {"file_exists", jx9Vfs_file_exists }, - {"filesize", jx9Vfs_file_size }, - {"fileatime", jx9Vfs_file_atime }, - {"filemtime", jx9Vfs_file_mtime }, - {"filectime", jx9Vfs_file_ctime }, - {"is_file", jx9Vfs_is_file }, - {"is_link", jx9Vfs_is_link }, - {"is_readable", jx9Vfs_is_readable }, - {"is_writable", jx9Vfs_is_writable }, - {"is_executable", jx9Vfs_is_executable}, - {"filetype", jx9Vfs_filetype }, - {"stat", jx9Vfs_stat }, - {"lstat", jx9Vfs_lstat }, - {"getenv", jx9Vfs_getenv }, - {"setenv", jx9Vfs_putenv }, - {"putenv", jx9Vfs_putenv }, - {"touch", jx9Vfs_touch }, - {"link", jx9Vfs_link }, - {"symlink", jx9Vfs_symlink }, - {"umask", jx9Vfs_umask }, - {"sys_get_temp_dir", jx9Vfs_sys_get_temp_dir }, - {"get_current_user", jx9Vfs_get_current_user }, - {"getpid", jx9Vfs_getmypid }, - {"getuid", jx9Vfs_getmyuid }, - {"getgid", jx9Vfs_getmygid }, - {"uname", jx9Vfs_uname}, - /* Path processing */ - {"dirname", jx9Builtin_dirname }, - {"basename", jx9Builtin_basename }, - {"pathinfo", jx9Builtin_pathinfo }, - {"strglob", jx9Builtin_strglob }, - {"fnmatch", jx9Builtin_fnmatch }, - /* ZIP processing */ - {"zip_open", jx9Builtin_zip_open }, - {"zip_close", jx9Builtin_zip_close}, - {"zip_read", jx9Builtin_zip_read }, - {"zip_entry_open", jx9Builtin_zip_entry_open }, - {"zip_entry_close", jx9Builtin_zip_entry_close}, - {"zip_entry_name", jx9Builtin_zip_entry_name }, - {"zip_entry_filesize", jx9Builtin_zip_entry_filesize }, - {"zip_entry_compressedsize", jx9Builtin_zip_entry_compressedsize }, - {"zip_entry_read", jx9Builtin_zip_entry_read }, - {"zip_entry_reset_cursor", jx9Builtin_zip_entry_reset_cursor}, - {"zip_entry_compressionmethod", jx9Builtin_zip_entry_compressionmethod} - }; - /* IO stream functions */ - static const jx9_builtin_func aIOFunc[] = { - {"ftruncate", jx9Builtin_ftruncate }, - {"fseek", jx9Builtin_fseek }, - {"ftell", jx9Builtin_ftell }, - {"rewind", jx9Builtin_rewind }, - {"fflush", jx9Builtin_fflush }, - {"feof", jx9Builtin_feof }, - {"fgetc", jx9Builtin_fgetc }, - {"fgets", jx9Builtin_fgets }, - {"fread", jx9Builtin_fread }, - {"fgetcsv", jx9Builtin_fgetcsv}, - {"fgetss", jx9Builtin_fgetss }, - {"readdir", jx9Builtin_readdir}, - {"rewinddir", jx9Builtin_rewinddir }, - {"closedir", jx9Builtin_closedir}, - {"opendir", jx9Builtin_opendir }, - {"readfile", jx9Builtin_readfile}, - {"file_get_contents", jx9Builtin_file_get_contents}, - {"file_put_contents", jx9Builtin_file_put_contents}, - {"file", jx9Builtin_file }, - {"copy", jx9Builtin_copy }, - {"fstat", jx9Builtin_fstat }, - {"fwrite", jx9Builtin_fwrite }, - {"fputs", jx9Builtin_fwrite }, - {"flock", jx9Builtin_flock }, - {"fclose", jx9Builtin_fclose }, - {"fopen", jx9Builtin_fopen }, - {"fpassthru", jx9Builtin_fpassthru }, - {"fputcsv", jx9Builtin_fputcsv }, - {"fprintf", jx9Builtin_fprintf }, -#if !defined(JX9_DISABLE_HASH_FUNC) - {"md5_file", jx9Builtin_md5_file}, - {"sha1_file", jx9Builtin_sha1_file}, -#endif /* JX9_DISABLE_HASH_FUNC */ - {"parse_ini_file", jx9Builtin_parse_ini_file}, - {"vfprintf", jx9Builtin_vfprintf} - }; - const jx9_io_stream *pFileStream = 0; - sxu32 n = 0; - /* Register the functions defined above */ - for( n = 0 ; n < SX_ARRAYSIZE(aVfsFunc) ; ++n ){ - jx9_create_function(&(*pVm), aVfsFunc[n].zName, aVfsFunc[n].xFunc, (void *)pVm->pEngine->pVfs); - } - for( n = 0 ; n < SX_ARRAYSIZE(aIOFunc) ; ++n ){ - jx9_create_function(&(*pVm), aIOFunc[n].zName, aIOFunc[n].xFunc, pVm); - } -#ifndef JX9_DISABLE_DISK_IO - /* Register the file stream if available */ -#ifdef __WINNT__ - pFileStream = &sWinFileStream; -#elif defined(__UNIXES__) - pFileStream = &sUnixFileStream; -#endif - /* Install the jx9:// stream */ - jx9_vm_config(pVm, JX9_VM_CONFIG_IO_STREAM, &sjx9Stream); -#endif /* JX9_DISABLE_DISK_IO */ - if( pFileStream ){ - /* Install the file:// stream */ - jx9_vm_config(pVm, JX9_VM_CONFIG_IO_STREAM, pFileStream); - } -#else - SXUNUSED(pVm); /* cc warning */ -#endif /* JX9_DISABLE_BUILTIN_FUNC */ - return SXRET_OK; -} -/* - * Export the STDIN handle. - */ -JX9_PRIVATE void * jx9ExportStdin(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_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, &sjx9Stream, pIn); - /* Initialize the handle */ - pIn->pHandle = JX9StreamDataInit(pVm, JX9_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. - */ -JX9_PRIVATE void * jx9ExportStdout(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_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, &sjx9Stream, pOut); - /* Initialize the handle */ - pOut->pHandle = JX9StreamDataInit(pVm, JX9_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. - */ -JX9_PRIVATE void * jx9ExportStderr(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_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, &sjx9Stream, pErr); - /* Initialize the handle */ - pErr->pHandle = JX9StreamDataInit(pVm, JX9_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 -} -- cgit v1.2.3