Exemple #1
0
        /// <summary>
        /// Sets user-level session storage functions
        /// </summary>
        public static bool session_set_save_handler(
            Context ctx,
            IPhpCallable open, IPhpCallable close,
            IPhpCallable read, IPhpCallable write,
            IPhpCallable destroy, IPhpCallable gc,
            IPhpCallable create_sid       = null,
            IPhpCallable validate_sid     = null,
            IPhpCallable update_timestamp = null)
        {
            if (!ctx.IsWebApplication ||
                !PhpVariable.IsValidBoundCallback(ctx, open) ||
                !PhpVariable.IsValidBoundCallback(ctx, close) ||
                !PhpVariable.IsValidBoundCallback(ctx, read) ||
                !PhpVariable.IsValidBoundCallback(ctx, write) ||
                !PhpVariable.IsValidBoundCallback(ctx, destroy) ||
                !PhpVariable.IsValidBoundCallback(ctx, gc))
            {
                return(false);
            }

            session_set_save_handler(
                ctx,
                sessionhandler: new CustomSessionHandler(ctx,
                                                         open, close, read, write, destroy, gc,
                                                         create_sid: create_sid, validate_sid: validate_sid, update_timestamp: update_timestamp),
                register_shutdown: false);
            return(true);
        }
Exemple #2
0
        /// <summary>
        /// Increases the level of buffering, enables output buffering if disabled and assignes the filtering callback
        /// to the new level of buffering.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="filter">The filtering callback. Ignores invalid callbacks.</param>
        /// <param name="chunkSize">Not supported.</param>
        /// <param name="erase">Not supported.</param>
        /// <returns>Whether the filter is valid callback.</returns>
        public static bool ob_start(Context ctx, IPhpCallable filter = null, int chunkSize = 0, bool erase = true)
        {
            if (chunkSize != 0)
            {
                //PhpException.ArgumentValueNotSupported("chunkSize", "!= 0");
                throw new NotSupportedException("chunkSize != 0");
            }
            if (!erase)
            {
                //PhpException.ArgumentValueNotSupported("erase", erase);
                throw new NotSupportedException("erase == false");
            }

            ctx.BufferedOutput.IncreaseLevel();

            bool result = true;

            // skips filter setting if filter is not specified or valid:
            if (filter != null) //  && (result = filter.Bind())) // TODO: PhpCallback.Bind -> Delegate, done by caller
            {
                ctx.BufferedOutput.SetFilter(filter);
            }

            ctx.IsOutputBuffered = true;

            return(result);
        }
Exemple #3
0
        public static PhpValue preg_replace_callback(Context ctx, PhpValue pattern, IPhpCallable callback, PhpValue subject, long limit, ref long count)
        {
            count = 0;

            // PHP's behaviour for undocumented limit range
            if (limit < -1)
            {
                limit = 0;
            }

            //
            var pattern_array = pattern.AsArray();

            if (pattern_array == null)
            {
                // string pattern
                return(PregReplaceInternal(ctx, pattern.ToStringOrThrow(ctx), null, callback, subject, (int)limit, ref count));
            }
            else
            {
                // array pattern
            }

            throw new NotImplementedException();
        }
Exemple #4
0
        /// <summary>
        /// Sets user defined handler to handle exceptions.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="newHandler">The user callback called to handle an exceptions.</param>
        /// <returns>
        /// The PHP representation of previous user handler, <B>null</B> if there is no user one, or
        /// <B>false</B> if <paramref name="newHandler"/> is invalid or empty.
        /// </returns>
        /// <remarks>
        /// Stores old user handlers on the stack so that it is possible to
        /// go back to arbitrary previous user handler.
        /// </remarks>
        public static PhpValue set_exception_handler(Context ctx, IPhpCallable newHandler)
        {
            if (newHandler == null)
            {
                return(PhpValue.Null);
            }
            if (newHandler is PhpCallback && !((PhpCallback)newHandler).IsValid)
            {
                return(PhpValue.Null);
            }

            var errctx = GetErrorContext(ctx);

            //PhpCallback old_handler = Configuration.Local.ErrorControl.UserExceptionHandler;

            //// previous handler was defined by user => store it into the stack:
            //if (old_handler != null)
            //{
            //    if (OldUserExceptionHandlers == null)
            //    {
            //        OldUserExceptionHandlers = new Stack(5);
            //        RequestContext.RequestEnd += new Action(ClearOldUserHandlers);
            //    }
            //    OldUserExceptionHandlers.Push(old_handler);
            //}

            //// sets the current handler:
            //Configuration.Local.ErrorControl.UserExceptionHandler = newHandler;

            //// returns the previous handler:
            //return (old_handler != null) ? old_handler.ToPhpRepresentation() : null;
            return(PhpValue.Null);
        }
Exemple #5
0
        /// <summary>
        /// Sets user defined handler to handle errors.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="newHandler">The user callback called to handle an error.</param>
        /// <param name="errorTypes">Error types to be handled by the handler.</param>
        /// <returns>
        /// The PHP representation of previous user handler, <B>null</B> if there is no user one, or
        /// <B>false</B> if <paramref name="newHandler"/> is invalid or empty.
        /// </returns>
        /// <remarks>
        /// Stores old user handlers on the stack so that it is possible to
        /// go back to arbitrary previous user handler.
        /// </remarks>
        public static PhpValue set_error_handler(Context ctx, IPhpCallable newHandler, PhpErrorSets errorTypes = PhpErrorSets.Handleable)
        {
            if (newHandler == null)
            {
                return(PhpValue.Null);
            }
            if (newHandler is PhpCallback && !((PhpCallback)newHandler).IsValid)
            {
                return(PhpValue.Null);
            }

            var errctx = GetErrorContext(ctx);

            //var old_handler = ctx.UserErrorHandler;
            //var old_handlers = errctx.OldUserErrorHandlers;

            //// previous handler was defined by user => store it into the stack:
            //if (old_handler != null)
            //{
            //    if (old_handlers == null)
            //    {
            //        old_handlers = new Stack(5);
            //        RequestContext.RequestEnd += new Action(ClearOldUserHandlers);
            //    }
            //    old_handlers.Push(new ErrorHandlerRecord(old_handler, old_errors));
            //}

            //// sets the current handler:
            //Configuration.Local.ErrorControl.UserHandler = newHandler;
            //Configuration.Local.ErrorControl.UserHandlerErrors = (PhpError)errorTypes;

            //// returns the previous handler:
            //return (old_handler != null) ? old_handler.ToPhpRepresentation() : null;
            return(PhpValue.Null);
        }
Exemple #6
0
        /// <summary>
        /// Registers autoload function.
        /// </summary>
        public static bool spl_autoload_register(Context ctx, IPhpCallable autoloadFunction, bool throwError = true, bool prepend = false)
        {
            if (autoloadFunction == null)
            {
                //PhpException.ArgumentNull("autoloadFunction");
                //return false;
                throw new ArgumentNullException(nameof(autoloadFunction));
            }

            if (autoloadFunction is PhpCallback && !((PhpCallback)autoloadFunction).IsValid)
            {
                return(false);
            }

            var autoload = ctx.EnsureSplAutoload();

            if (autoload.FindAutoload(autoloadFunction) != null)
            {
                return(false);
            }

            if (prepend)
            {
                autoload.Autoloaders.AddFirst(autoloadFunction);
            }
            else
            {
                autoload.Autoloaders.AddLast(autoloadFunction);
            }

            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Sets user defined handler to handle errors.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="newHandler">The user callback called to handle an error.</param>
        /// <param name="errorTypes">Error types to be handled by the handler.</param>
        /// <returns>
        /// The PHP representation of previous user handler, <B>null</B> if there is no user one, or
        /// <B>false</B> if <paramref name="newHandler"/> is invalid or empty.
        /// </returns>
        /// <remarks>
        /// Stores old user handlers on the stack so that it is possible to
        /// go back to arbitrary previous user handler.
        /// </remarks>
        public static PhpValue set_error_handler(Context ctx, IPhpCallable newHandler, PhpErrorSets errorTypes = PhpErrorSets.Handleable)
        {
            if (newHandler == null)
            {
                return(PhpValue.Null);
            }
            if (newHandler is PhpCallback && !((PhpCallback)newHandler).IsValid)
            {
                return(PhpValue.Null);
            }

            var config = ctx.Configuration.Core;

            var oldhandler = config.UserErrorHandler;
            var oldtypes   = config.UserErrorTypes;

            if (oldhandler != null)
            {
                GetErrorContext(ctx).StoreErrorHandler(new ErrorHandlerRecord(oldhandler, oldtypes));
            }

            config.UserErrorHandler = newHandler;
            config.UserErrorTypes   = (PhpError)errorTypes;

            // returns the previous handler:
            return((oldhandler != null)
                ? oldhandler.ToPhpValue()
                : PhpValue.Null);
        }
Exemple #8
0
        /// <summary>
        /// Sets user defined handler to handle exceptions.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="newHandler">The user callback called to handle an exceptions.</param>
        /// <returns>
        /// The PHP representation of previous user handler, <B>null</B> if there is no user one, or
        /// <B>false</B> if <paramref name="newHandler"/> is invalid or empty.
        /// </returns>
        /// <remarks>
        /// Stores old user handlers on the stack so that it is possible to
        /// go back to arbitrary previous user handler.
        /// </remarks>
        public static PhpValue set_exception_handler(Context ctx, IPhpCallable newHandler)
        {
            if (newHandler == null)
            {
                return(PhpValue.Null);
            }
            if (newHandler is PhpCallback callback && !callback.IsValid)
            {
                return(PhpValue.Null);
            }

            var config = ctx.Configuration.Core;

            var old_handler = config.UserExceptionHandler;

            config.UserExceptionHandler = newHandler;

            // previous handler was defined by user => store it into the stack:
            if (old_handler != null)
            {
                GetErrorContext(ctx).StoreExceptionHandler(new ErrorHandlerRecord(old_handler, (PhpError)PhpErrorSets.All));

                // returns the previous handler:
                return(old_handler.ToPhpValue());
            }
            else
            {
                return(PhpValue.Null);
            }
        }
Exemple #9
0
        /// <summary>
        /// Determines if given callable is valid and referes toi an existing function.
        /// </summary>
        public static bool IsValidBoundCallback(Context ctx, IPhpCallable callable)
        {
            var tmp = callable as PhpCallback;

            return((tmp != null)
                ? tmp.IsValidBound(ctx)
                : callable != null);
        }
Exemple #10
0
        /// <summary>
        /// Adds PHP handler to the event.
        /// </summary>
        public void addEventElapsed(Context ctx, IPhpCallable handler)
        {
            void HandlerDelegate(object sender, ElapsedEventArgs args)
            {
                handler.Invoke(ctx, PhpValue.FromClr(sender), PhpValue.FromClass(args));
            }

            timer.Elapsed += new System.Timers.ElapsedEventHandler(HandlerDelegate);
        }
Exemple #11
0
        /// <summary>
        /// Assignes the filtering callback to the specified level of buffering.
        /// </summary>
        /// <param name="filter">The filter. Null reference means no filter.</param>
        /// <param name="levelIndex">The level of buffering which the filter to associate with.</param>
        /// <remarks>Data are filtered when flushed.</remarks>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="levelIndex"/> is out of range.</exception>
        public void SetFilter(IPhpCallable filter, int levelIndex)
        {
            if (levelIndex < 0 || levelIndex >= _levels.Count)
            {
                throw new ArgumentOutOfRangeException("levelIndex");
            }

            _levels[levelIndex].filter = filter;
        }
Exemple #12
0
        /// <summary>
        /// Registers callback which will be called when script processing is complete but before the request
        /// has been complete.
        /// Function has no return value.
        /// </summary>
        /// <param name="ctx">Runtime context. Cannot be <c>null</c>.</param>
        /// <param name="function">The function which is called after main code of the script is finishes execution.</param>
        /// <param name="arguments">Parameters for the <paramref name="function"/>.</param>
        /// <remarks>
        /// Although, there is explicitly written in the PHP manual that it is not possible
        /// to send an output to a browser via echo or another output handling functions you can actually do so.
        /// </remarks>
        public static void register_shutdown_function(Context ctx, IPhpCallable function, params PhpValue[] arguments)
        {
            if (function == null)
            {
                PhpException.ArgumentNull(nameof(function));
                return;
            }

            ctx.RegisterShutdownCallback((_ctx) => function.Invoke(_ctx, arguments));
        }
Exemple #13
0
        /// <summary>
        /// Creates a new instance of a comparer using <see cref="PhpCallback"/> for comparisons.
        /// </summary>
        /// <param name="ctx">Current context. Cannot be <c>null</c>.</param>
        /// <param name="compare">User callback which provides comparing functionality.</param>
        /// <remarks>
        /// <para>
        /// Callback should have the signature <c>object(object,object)</c> and should already be bound.
        /// </para>
        /// <para>
        /// The result of calback's invocation is converted to a double by <see cref="PhpValue.ToDouble"/>
        /// and than the sign is taken as a result of the comparison.</para>
        /// </remarks>
        /// <exception cref="ArgumentNullException"><paramref name="compare"/> is a <B>null</B> reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="compare"/> callback is not bound.</exception>
        public PhpUserComparer(Context ctx, IPhpCallable compare)
        {
            if (compare == null)
            {
                throw new ArgumentNullException(nameof(compare));
            }

            _compare = compare;
            _ctx     = ctx;
        }
Exemple #14
0
    /// <summary>
    /// Create and return a new anonymous function from given callable using the current scope.
    /// This method checks if the callable is callable in the current scope and throws a TypeError if it is not.
    /// </summary>
    public static Closure fromCallable(Context ctx, IPhpCallable callable)
    {
        if (callable is Closure closure)
        {
            return(closure);
        }

        if (callable != null && PhpVariable.IsValidBoundCallback(ctx, callable))
        {
            return(new Closure(ctx, callable, null, default, null, PhpArray.Empty, PhpArray.Empty));
Exemple #15
0
        /// <summary>
        /// Gets or sets option.
        /// </summary>
        public static IPhpCallable GetSet(ref IPhpCallable option, IPhpCallable defaultValue, PhpValue newValue, IniAction action)
        {
            var oldValue = option;

            if (action == IniAction.Set)
            {
                option = newValue.AsCallable(default(RuntimeTypeHandle));
            }

            return(oldValue);
        }
        /// <summary>
        /// Calls a function or a method defined by callback with given arguments.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
        /// <param name="args">The arguments.</param>
        /// <returns>The return value.</returns>
        public static PhpValue call_user_func(Context ctx, IPhpCallable function, params PhpValue[] args)
        {
            if (function == null)
            {
                PhpException.ArgumentNull("function");
                return(PhpValue.Null);
            }

            Debug.Assert(args != null);

            // invoke the callback:
            return(function.Invoke(ctx, args));
        }
Exemple #17
0
        /// <summary>
        /// Registers a function that will be called when PHP starts sending output.
        /// </summary>
        public static bool header_register_callback(Context ctx, IPhpCallable callback)
        {
            var webctx = ctx.HttpPhpContext;

            if (webctx == null || callback == null)
            {
                return(false);
            }

            webctx.HeadersSending += () => { callback.Invoke(ctx); };

            return(true);
        }
Exemple #18
0
        /// <summary>
        /// Gets some information about a specified level.
        /// </summary>
        /// <param name="levelIndex">Level index starting from 1.</param>
        /// <param name="filter">Filtering callback (if any).</param>
        /// <param name="size">Data size.</param>
        /// <param name="name">Optionally the level name.</param>
        public void GetLevelInfo(int levelIndex, out IPhpCallable filter, out int size, out string name)
        {
            if (levelIndex < 1 || levelIndex > Level)
            {
                throw new ArgumentOutOfRangeException("levelIndex");
            }

            var element = _levels[levelIndex - 1];

            filter = element.filter;
            size   = element.size;
            name   = GetLevelName(element);
        }
Exemple #19
0
        /// <summary>
		/// Calls a function or a method defined by callback with given arguments.
		/// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
		/// <param name="args">The arguments.</param>
		/// <returns>The return value.</returns>
		public static PhpValue call_user_func(Context ctx, IPhpCallable function, params PhpValue[] args)
        {
            if (function == null)
            {
                //PhpException.ArgumentNull("function");
                //return null;
                throw new ArgumentNullException();  // NOTE: should not be reached, runtime converts NULL to InvalidCallback instance
            }

            Debug.Assert(args != null);

            // invoke the callback:
            return function.Invoke(ctx, args);
        }
Exemple #20
0
    /// <summary>
    /// Create and return a new anonymous function from given callable using the current scope.
    /// This method checks if the callable is callable in the current scope and throws a TypeError if it is not.
    /// </summary>
    public static Closure fromCallable(Context ctx, IPhpCallable callable)
    {
        if (callable == null)
        {
            throw new ArgumentNullException(nameof(callable));
        }

        if (callable is Closure)
        {
            return((Closure)callable);
        }

        //
        return(new Closure(ctx, callable, null, default, null, PhpArray.Empty, PhpArray.Empty));
Exemple #21
0
        /// <summary>
        /// Calls a function or a method defined by callback with given arguments.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
        /// <param name="args">The arguments.</param>
        /// <returns>The return value.</returns>
        public static PhpValue call_user_func(Context ctx, IPhpCallable function, params PhpValue[] args)
        {
            if (function == null)
            {
                //PhpException.ArgumentNull("function");
                //return null;
                throw new ArgumentNullException();  // NOTE: should not be reached, runtime converts NULL to InvalidCallback instance
            }

            Debug.Assert(args != null);

            // invoke the callback:
            return function.Invoke(ctx, args);
        }
Exemple #22
0
        /// <summary>
        /// Unregisteres the autoload function.
        /// </summary>
        public static bool spl_autoload_unregister(Context ctx, IPhpCallable autoloadFunction)
        {
            var functionNode = FindAutoloadFunction(ctx, autoloadFunction);

            if (functionNode != null)
            {
                functionNode.List.Remove(functionNode);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #23
0
        /// <summary>
        /// Find level index by the filter callback.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int FindLevelByFilter(IPhpCallable filter)
        {
            if (_levels != null && filter != null)
            {
                for (int i = 0; i < Level; i++)
                {
                    if (_levels[i].filter == filter)
                    {
                        return(i);
                    }
                }
            }

            return(-1);
        }
Exemple #24
0
    /// <summary>
    /// Constructs the closure.
    /// </summary>
    internal Closure(Context /*!*/ ctx, IPhpCallable /*!*/ routine, object @this, RuntimeTypeHandle scope, PhpArray /*!*/ parameter, PhpArray /*!*/ @static)
    {
        Debug.Assert(ctx != null);
        Debug.Assert(routine != null);
        Debug.Assert(parameter != null);
        Debug.Assert(@static != null);

        _callable = routine;
        _ctx      = ctx;
        _this     = @this;
        _scope    = scope;

        this.parameter = parameter;
        this.@static   = @static;
    }
Exemple #25
0
            /// <summary>
            /// Finds node within <see cref="_autoloaders"/> matches given callback.
            /// </summary>
            public LinkedListNode <IPhpCallable> FindAutoload(IPhpCallable autoloadFunction)
            {
                if (autoloadFunction != null)
                {
                    for (var node = _autoloaders.First; node != null; node = node.Next)
                    {
                        if (object.ReferenceEquals(node.Value, autoloadFunction) ||
                            node.Value.Equals(autoloadFunction))
                        {
                            return(node);
                        }
                    }
                }

                return(null);
            }
Exemple #26
0
        /// <summary>
        /// Calls a function or a method defined by callback with arguments stored in an array.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
        /// <param name="args">Arguments. Can be null.</param>
        /// <returns>The returned value.</returns>
        public static PhpValue call_user_func_array(Context ctx, IPhpCallable function, PhpArray args)
        {
            PhpValue[] args_array;

            if (args != null && args.Count != 0)
            {
                args_array = new PhpValue[args.Count];
                args.CopyValuesTo(args_array, 0);
            }
            else
            {
                args_array = Core.Utilities.ArrayUtils.EmptyValues;
            }

            return call_user_func(ctx, function, args_array);
        }
Exemple #27
0
        /// <summary>
        /// Calls a function or a method defined by callback with arguments stored in an array.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
        /// <param name="args">Arguments. Can be null.</param>
        /// <returns>The returned value.</returns>
        public static PhpValue call_user_func_array(Context ctx, IPhpCallable function, PhpArray args)
        {
            PhpValue[] args_array;

            if (args != null && args.Count != 0)
            {
                args_array = new PhpValue[args.Count];
                args.CopyValuesTo(args_array, 0);
            }
            else
            {
                args_array = Core.Utilities.ArrayUtils.EmptyValues;
            }

            return(call_user_func(ctx, function, args_array));
        }
Exemple #28
0
        /// <summary>
        /// Calls a function or a method defined by callback with given arguments.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="function">Target callback.</param>
        /// <param name="args">The arguments.</param>
        /// <returns>The return value.</returns>
        public static PhpValue call_user_func(Context ctx, IPhpCallable function, params PhpValue[] args)
        {
            if (function == null)
            {
                PhpException.ArgumentNull("function");
                return(PhpValue.Null);
            }
            else if (!PhpVariable.IsValidBoundCallback(ctx, function))
            {
                PhpException.InvalidArgument(nameof(function));
                return(PhpValue.Null);
            }

            Debug.Assert(args != null);

            // invoke the callback:
            return(function.Invoke(ctx, args));
        }
Exemple #29
0
            public CustomSessionHandler(
                Context ctx,
                IPhpCallable open, IPhpCallable close,
                IPhpCallable read, IPhpCallable write,
                IPhpCallable destroy, IPhpCallable gc,
                IPhpCallable create_sid       = null,
                IPhpCallable validate_sid     = null,
                IPhpCallable update_timestamp = null)
            {
                _ctx = ctx;

                _open    = open;
                _close   = close;
                _read    = read;
                _write   = write;
                _destroy = destroy;
                _gc      = gc;

                _create_sid       = create_sid;
                _validate_sid     = validate_sid;
                _update_timestamp = update_timestamp;
            }
        /// <summary>
        /// Calls a function for every element in an iterator.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="iterator">The class to iterate over.</param>
        /// <param name="function">The callback function to call on every element.
        /// Note: The function must return <c>TRUE</c> in order to continue iterating over the iterator.</param>
        /// <param name="args">Arguments to pass to the callback function.</param>
        /// <returns>The iteration count.</returns>
        public static int iterator_apply(Context ctx, Iterator iterator, IPhpCallable function, PhpArray args = null)
        {
            if (iterator == null)
            {
                throw new ArgumentNullException(nameof(iterator));
            }

            if (function == null)
            {
                PhpException.ArgumentNull(nameof(function));
                return(-1);
            }

            // construct callback arguments
            var args_array = args != null
                ? args.GetValues()
                : Array.Empty <PhpValue>();

            //
            int n = 0;

            iterator.rewind();

            while (iterator.valid())
            {
                if (function.Invoke(ctx, args_array).ToBoolean() == false)
                {
                    break;
                }

                //
                n++;
                iterator.next();
            }

            //
            return(n);
        }
Exemple #31
0
        public static TFunc Get(IPhpCallable callable, Context ctx)
        {
            if (callable == null)
            {
                throw new ArgumentNullException(nameof(callable));
            }

            //
            if (typeof(TFunc) == typeof(Action))
            {
                return((TFunc)(object)new Action(() => callable.Invoke(ctx)));
            }
            if (typeof(TFunc) == typeof(Func <bool>))
            {
                return((TFunc)(object)new Func <bool>(() => (bool)callable.Invoke(ctx)));
            }
            if (typeof(TFunc) == typeof(Func <long, long>))
            {
                return((TFunc)(object)new Func <long, long>((p1) => (long)callable.Invoke(ctx, p1)));
            }

            //
            throw new NotImplementedException($"Creating delegate of type '{typeof(TFunc)}'."); // TODO: construct the delegate dynamically
        }
Exemple #32
0
        public static TFunc Get(IPhpCallable callable, Context ctx)
        {
            if (callable == null)
            {
                throw new ArgumentNullException(nameof(callable));
            }

            //
            if (typeof(TFunc) == typeof(Action))
            {
                return((TFunc)(object)new Action(() => callable.Invoke(ctx)));
            }
            if (typeof(TFunc) == typeof(Func <bool>))
            {
                return((TFunc)(object)new Func <bool>(() => (bool)callable.Invoke(ctx)));
            }
            if (typeof(TFunc) == typeof(Func <long, long>))
            {
                return((TFunc)(object)new Func <long, long>((p1) => (long)callable.Invoke(ctx, p1)));
            }

            //
            return(Dynamic.BinderHelpers.CreateDelegate <TFunc>(callable, ctx));
        }
Exemple #33
0
        /// <summary>
        /// Sorts an array using user comparison callback for comparing values.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array to be sorted.</param>
        /// <param name="compare">The user callback to be used for comparison of values.</param>
        /// <remarks>Resets <paramref name="array"/>'s intrinsic enumerator.</remarks>
        /// <returns>True on success, False on failure.</returns>
        public static bool usort(Context ctx /*, caller*/, [In, Out] PhpArray array, IPhpCallable compare)
        {
            if (array == null)
            {
                //PhpException.ReferenceNull("array");
                //return false;
                throw new ArgumentNullException();
            }
            if (!PhpVariable.IsValidCallback(compare)) return false;

            // sorts array using callback for comparisons:
            array.Sort(new ValueComparer(new PhpUserComparer(ctx, compare), false));

            array.ReindexAll();
            array.RestartIntrinsicEnumerator();

            return true;
        }
Exemple #34
0
        /// <summary>
        /// Sorts an array using user comparison callback for comparing keys.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array to be sorted.</param>
        /// <param name="compare">The user callback to be used for comparison of values.</param>
        /// <remarks>Resets <paramref name="array"/>'s intrinsic enumerator.</remarks>
        /// <returns>True on success, False on failure.</returns>
        public static bool uksort(Context ctx /*, caller*/, [In, Out] PhpArray array, IPhpCallable compare)
        {
            if (array == null)
            {
                //PhpException.ReferenceNull("array");
                //return false;
                throw new ArgumentNullException();
            }
            if (!PhpVariable.IsValidCallback(compare)) return false;

            array.Sort(new KeyComparer(new PhpUserComparer(ctx, compare), false));

            return true;
        }
Exemple #35
0
        /// <summary>
        /// Applies a callback function on specified tuples one by one storing its results to an array.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="map">
        /// A callback to be called on tuples. The number of arguments should be the same as
        /// the number of arrays specified by <pramref name="arrays"/>.
        /// Arguments passed by reference modifies elements of <pramref name="arrays"/>.
        /// A <B>null</B> means default callback which makes integer indexed arrays from the tuples is used. 
        /// </param>
        /// <param name="arrays">Arrays where to load tuples from. </param>
        /// <returns>An array of return values of the callback
        /// keyed by keys of the <paramref name="arrays"/> if it
        /// is a single array or by integer keys starting from 0.</returns>
        /// <remarks>
        /// <para>
        /// In the <I>i</I>-th call the <I>j</I>-th parameter of the callback will be 
        /// the <I>i</I>-th value of the <I>j</I>-the array or a <B>null</B> if that array 
        /// has less then <I>i</I> entries.
        /// </para>
        /// <para>
        /// If the callback assigns a value to a parameter passed by reference in the <I>i</I>-the call 
        /// and the respective array contains at least <I>i</I> elements the assigned value is propagated 
        /// to the array.
        /// </para>
        /// </remarks>
        public static PhpArray array_map(Context ctx /*, caller*/, IPhpCallable map, [In, Out] params PhpArray[] arrays)
        {
            //if (!PhpArgument.CheckCallback(map, caller, "map", 0, true)) return null;
            if (arrays == null || arrays.Length == 0)
            {
                //PhpException.InvalidArgument("arrays", LibResources.GetString("arg:null_or_emtpy"));
                //return null;
                throw new ArgumentException();
            }

            // if callback has not been specified uses the default one:
            if (map == null)
            {
                map = _mapIdentity;
            }

            int count = arrays.Length;
            bool preserve_keys = count == 1;
            var args = new PhpValue[count];
            var iterators = new OrderedDictionary.FastEnumerator[count];
            PhpArray result;

            // initializes iterators and args array, computes length of the longest array:
            int max_count = 0;
            for (int i = 0; i < arrays.Length; i++)
            {
                var array = arrays[i];

                if (array == null)
                {
                    //PhpException.Throw(PhpError.Warning, LibResources.GetString("argument_not_array", i + 2));// +2 (first arg is callback) 
                    //return null;
                    throw new ArgumentException();
                }

                args[i] = PhpValue.CreateAlias();
                iterators[i] = array.GetFastEnumerator();
                if (array.Count > max_count) max_count = array.Count;
            }

            // keys are preserved in a case of a single array and re-indexed otherwise:
            if (preserve_keys)
                result = new PhpArray(arrays[0].IntegerCount, arrays[0].StringCount);
            else
                result = new PhpArray(max_count, 0);

            for (;;)
            {
                bool hasvalid = false;

                // fills args[] with items from arrays:
                for (int i = 0; i < arrays.Length; i++)
                {
                    if (iterators[i].IsValid)
                    {
                        hasvalid = true;

                        // note: deep copy is not necessary since a function copies its arguments if needed:
                        args[i].Alias.Value = iterators[i].CurrentValue.GetValue();
                        // TODO: throws if the current Value is PhpReference
                    }
                    else
                    {
                        args[i].Alias.Value = PhpValue.Null;
                    }
                }

                if (!hasvalid) break;

                // invokes callback:
                var return_value = map.Invoke(ctx, args);

                // return value is not deeply copied:
                if (preserve_keys)
                    result.Add(iterators[0].CurrentKey, return_value);
                else
                    result.Add(return_value);

                // loads new values (callback may modify some by ref arguments):
                for (int i = 0; i < arrays.Length; i++)
                {
                    if (iterators[i].IsValid)
                    {
                        var item = iterators[i].CurrentValue;
                        if (item.IsAlias)
                        {
                            item.Alias.Value = args[i].Alias.Value;
                        }
                        else
                        {
                            iterators[i].CurrentValue = args[i].Alias.Value;
                        }

                        //
                        iterators[i].MoveNext();
                    }
                }
            }

            return result;
        }
Exemple #36
0
        /// <summary>
        /// Visits an entry of array which <see cref="array_walk(Context, PhpHashtable, IPhpCallable, PhpValue)"/> or <see cref="array_walk_recursive(Context, PhpHashtable, IPhpCallable, PhpValue)"/> is walking through.
        /// </summary>
        private static void VisitEntryOnWalk(Context ctx,
            KeyValuePair<IntStringKey, PhpValue> entry,
            IDictionary<IntStringKey, PhpValue> array,
            IPhpCallable callback, PhpValue[] args)
        {
            Debug.Assert(args[0].IsAlias);

            // fills arguments for the callback:
            args[0].Alias.Value = entry.Value.GetValue();
            args[1] = PhpValue.Create(entry.Key);

            // invoke callback:
            callback.Invoke(ctx, args);

            // loads a new value from a reference:
            if (entry.Value.IsAlias)
            {
                entry.Value.Alias.Value = args[0].Alias.Value;
            }
            else
            {
                array[entry.Key] = args[0].Alias.Value;
            }
        }
Exemple #37
0
        public static PhpValue array_reduce(Context ctx, [In, Out] PhpArray array, IPhpCallable function, PhpValue initialValue)
        {
            if (array == null)
            {
                //PhpException.ReferenceNull("array");
                //return PhpValue.Null;
                throw new ArgumentNullException(nameof(array));
            }

            //if (!PhpArgument.CheckCallback(function, caller, "function", 0, false)) return null;

            if (array.Count == 0)
            {
                return initialValue;
            }

            PhpValue[] args = new PhpValue[] { initialValue.DeepCopy(), PhpValue.Null };

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                var item = iterator.CurrentValue;

                args[1] = item.IsAlias ? item : PhpValue.Create(item.EnsureAlias());
                args[0] = function.Invoke(ctx, args);

                // updates an item if it wasn't alias
                if (!item.IsAlias)
                {
                    iterator.CurrentValue = args[1].Alias.Value;
                }
            }

            // dereferences the last returned value:
            return args[0].GetValue();
        }
Exemple #38
0
 /// <summary>
 /// Applies a user function or method on each element of a specified array or dictionary.
 /// </summary>
 /// <returns><B>true</B>.</returns>
 /// <remarks>See <see cref="Walk(PHP.Core.Reflection.DTypeDesc,PhpHashtable,PhpCallback,object)"/> for details.</remarks>
 /// <exception cref="PhpException"><paramref name="function"/> or <paramref name="array"/> are <B>null</B> references.</exception>
 public static bool array_walk(Context ctx, [In, Out] PhpHashtable array, IPhpCallable function)
 {
     return array_walk(ctx, array, function, PhpValue.Null);
 }
Exemple #39
0
        /// <summary>
        /// Applies a user function or method on each element (value) of a specified dictionary.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array (or generic dictionary) to walk through.</param>
        /// <param name="callback">
        /// The callback called for each element of <paramref name="array"/>.
        /// The callback is assumed to have two or three parameters:
        /// <list type="number">
        ///   <item>
        ///     <term>
        ///       A value of dictionary entry. Can be specified with &amp; modifier which propagates any changes
        ///       make to the argument back to the entry. The dictionary can be changed in this way.
        ///     </term>
        ///   </item>
        ///   <item>A key of dictionary entry.</item>
        ///   <item>
        ///     Value of <paramref name="data"/> parameter if it is not a <B>null</B> reference.
        ///     Otherwise, the callback is assumed to have two parameters only.
        ///   </item>
        /// </list>
        /// </param>
        /// <param name="data">An additional parameter passed to <paramref name="callback"/> as its third parameter.</param>
        /// <returns><B>true</B>.</returns>
        /// <exception cref="PhpException"><paramref name="callback"/> or <paramref name="array"/> are <B>null</B> references.</exception>
        public static bool array_walk(Context ctx /*, caller*/, [In, Out] PhpHashtable array, IPhpCallable callback, PhpValue data)
        {
            PhpValue[] args = PrepareWalk(array, callback, data);
            if (args == null) return false;

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                VisitEntryOnWalk(ctx, iterator.Current, array, callback, args);
            }

            return true;
        }
Exemple #40
0
        /// <summary>
        /// Applies a user function or method on each element (value) of a specified dictionary recursively.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array to walk through.</param>
        /// <param name="callback">The callback called for each element of <paramref name="array"/>.</param>
        /// <param name="data">An additional parameter passed to <paramref name="callback"/> as its third parameter.</param>
        /// <exception cref="PhpException"><paramref name="callback"/> or <paramref name="array"/> are <B>null</B> references.</exception>
        /// <remarks><seealso cref="Walk"/>.</remarks>
        public static bool array_walk_recursive(Context ctx /*, caller*/, [In, Out] PhpHashtable array, IPhpCallable callback, PhpValue data)
        {
            var args = PrepareWalk(array, callback, data);
            if (args == null)
            {
                return false;
            }

            using (var iterator = array.GetRecursiveEnumerator(true, false))
            {
                while (iterator.MoveNext())
                {
                    var current = iterator.Current;

                    // visits the item unless it is an array or a reference to an array:
                    if (!current.Value.GetValue().IsArray)
                    {
                        VisitEntryOnWalk(ctx, iterator.Current, iterator.CurrentTable, callback, args);
                    }
                }
            }
            return true;
        }
Exemple #41
0
 public static PhpValue array_reduce(Context ctx, [In, Out] PhpArray array, IPhpCallable function)
 {
     return array_reduce(ctx, array, function, PhpValue.Null);
 }
Exemple #42
0
        /// <summary>
        /// Filters an array using a specified callback.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="array">The array to be filtered.</param>
        /// <param name="callback">
        /// The callback called on each value in the <paramref name="array"/>. 
        /// If the callback returns value convertible to <B>true</B> the value is copied to the resulting array.
        /// Otherwise, it is ignored.
        /// </param>
        /// <returns>An array of unfiltered items.</returns>
        //[return: PhpDeepCopy]
        public static PhpArray array_filter(Context ctx /*, caller*/, PhpArray array, IPhpCallable callback)
        {
            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException(nameof(array));
            }

            if (callback == null)
            {
                //PhpException.ArgumentNull("callback");
                //return null;
                throw new ArgumentNullException(nameof(callback));
            }

            var result = new PhpArray();
            var args = new PhpValue[1];

            var iterator = array.GetFastEnumerator();
            while (iterator.MoveNext())
            {
                var entry = iterator.Current;

                // no deep copying needed because it is done so in callback:
                args[0] = entry.Value;

                // adds entry to the resulting array if callback returns true:
                if (callback.Invoke(ctx, args).ToBoolean())
                {
                    result.Add(entry);
                }
            }

            // values should be inplace deeply copied:
            //result.InplaceCopyOnReturn = true;
            return result;
        }
Exemple #43
0
 public static PhpCallback Create(IPhpCallable callable) => Create(callable.Invoke);
Exemple #44
0
        // TODO: specific parameters instead of 'params PhpValue[] arraysAndComparer'

        /// <summary>
        /// There have to be at least 1 value in <paramref name="vars"/>.
        /// The last is converted to callback, the rest to arrays.
        /// </summary>
        private static bool SplitArraysAndComparers(int comparerCount, PhpArray array, PhpValue[] vars, out PhpArray[] arrays, out IPhpCallable cmp1, out IPhpCallable cmp2)
        {
            arrays = null;
            cmp1 = cmp2 = null;

            if (vars == null || vars.Length == 0)
            {
                // TODO: PhpException.InvalidArgumentCount(null, null);
                return false;
            }

            // the first callback:
            cmp1 = vars[vars.Length - comparerCount].AsCallable();
            if (PhpVariable.IsValidCallback(cmp1)) return false;

            // the second callback:
            if (comparerCount > 1)
            {
                cmp2 = vars[vars.Length - 1].AsCallable();
                if (!PhpVariable.IsValidCallback(cmp2)) return false;
            }

            // remaining arguments should be arrays:
            arrays = new PhpArray[vars.Length - comparerCount + 1];
            arrays[0] = array;
            for (int i = 0; i < vars.Length - comparerCount; i++)
            {
                var var = vars[i];
                if ((arrays[i + 1] = vars[i].AsArray()) == null)
                {
                    // TODO: PhpException.Throw(PhpError.Warning, LibResources.GetString("argument_not_array", i + 3));
                    return false;
                }
            }

            //
            return true;
        }
Exemple #45
0
        /// <summary>
        /// Prepares a walk for <see cref="array_walk(Context, PhpHashtable, IPhpCallable, PhpValue)"/> and <see cref="array_walk_recursive(Context, PhpHashtable, IPhpCallable, PhpValue)"/> methods.
        /// </summary>
        /// <exception cref="PhpException"><paramref name="callback"/> or <paramref name="array"/> are <B>null</B> references.</exception>
        private static PhpValue[] PrepareWalk(IDictionary array, IPhpCallable callback, PhpValue data)
        {
            if (callback == null)
            {
                //PhpException.ArgumentNull("callback");
                // return null;
                throw new ArgumentNullException(nameof(callback));
            }

            if (array == null)
            {
                //PhpException.ArgumentNull("array");
                //return null;
                throw new ArgumentNullException(nameof(array));
            }

            // prepares an array of callback's arguments (no deep copying needed because it is done so in callback):
            return (data != null)
                ? new PhpValue[] { PhpValue.CreateAlias(), PhpValue.Null, data }
                : new PhpValue[] { PhpValue.CreateAlias(), PhpValue.Null };
        }
Exemple #46
0
 /// <summary>
 /// Applies a user function or method on each element of a specified array recursively.
 /// </summary>
 /// <returns><B>true</B>.</returns>
 /// <remarks>See <see cref="Walk(PHP.Core.Reflection.DTypeDesc,PhpHashtable,PhpCallback,object)"/> for details.</remarks>
 /// <exception cref="PhpException"><paramref name="callback"/> or <paramref name="array"/> are <B>null</B> references.</exception>
 public static bool array_walk_recursive(Context ctx, [In, Out] PhpHashtable array, IPhpCallable callback)
 {
     return array_walk_recursive(ctx, array, callback, PhpValue.Null);
 }