@@ -2667,6 +2667,60 @@ PHP_FUNCTION(array_fill_keys)
2667
2667
zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
2668
2668
} while (0)
2669
2669
2670
+ static uint8_t php_range_process_input (const zval * input , uint32_t arg_num , zend_long /* restrict */ * lval , double /* restrict */ * dval )
2671
+ {
2672
+ switch (Z_TYPE_P (input )) {
2673
+ case IS_LONG :
2674
+ * lval = Z_LVAL_P (input );
2675
+ * dval = (double ) Z_LVAL_P (input );
2676
+ return IS_LONG ;
2677
+ case IS_DOUBLE :
2678
+ * dval = Z_DVAL_P (input );
2679
+ check_dval_value :
2680
+ if (zend_isinf (* dval )) {
2681
+ zend_argument_value_error (arg_num , "must be a finite number, INF provided" );
2682
+ return 0 ;
2683
+ }
2684
+ if (zend_isnan (* dval )) {
2685
+ zend_argument_value_error (arg_num , "must be a finite number, NAN provided" );
2686
+ return 0 ;
2687
+ }
2688
+ return IS_DOUBLE ;
2689
+ case IS_STRING : {
2690
+ if (Z_STRLEN_P (input ) == 0 ) {
2691
+ const char * arg_name = get_active_function_arg_name (arg_num );
2692
+ php_error_docref (NULL , E_WARNING , "Argument #%d ($%s) must not be empty, casted to 0" , arg_num , arg_name );
2693
+ if (UNEXPECTED (EG (exception ))) {
2694
+ return 0 ;
2695
+ }
2696
+ * lval = 0 ;
2697
+ * dval = 0.0 ;
2698
+ return IS_LONG ;
2699
+ }
2700
+ uint8_t type = is_numeric_str_function (Z_STR_P (input ), lval , dval );
2701
+ if (type == IS_DOUBLE ) {
2702
+ goto check_dval_value ;
2703
+ }
2704
+ if (type == IS_LONG ) {
2705
+ * dval = (double ) * lval ;
2706
+ return IS_LONG ;
2707
+ }
2708
+ if (Z_STRLEN_P (input ) != 1 ) {
2709
+ const char * arg_name = get_active_function_arg_name (arg_num );
2710
+ php_error_docref (NULL , E_WARNING , "Argument #%d ($%s) must be a single byte, subsequent bytes are ignored" , arg_num , arg_name );
2711
+ if (UNEXPECTED (EG (exception ))) {
2712
+ return 0 ;
2713
+ }
2714
+ }
2715
+ /* Set fall back values to 0 in case the other argument is not a string */
2716
+ * lval = 0 ;
2717
+ * dval = 0.0 ;
2718
+ return IS_STRING ;
2719
+ }
2720
+ EMPTY_SWITCH_DEFAULT_CASE ();
2721
+ }
2722
+ }
2723
+
2670
2724
/* {{{ Create an array containing the range of integers or characters from low to high (inclusive) */
2671
2725
PHP_FUNCTION (range )
2672
2726
{
@@ -2717,22 +2771,54 @@ PHP_FUNCTION(range)
2717
2771
}
2718
2772
}
2719
2773
2720
- /* If the range is given as strings, generate an array of characters. */
2721
- if (Z_TYPE_P (user_start ) == IS_STRING && Z_TYPE_P (user_end ) == IS_STRING && Z_STRLEN_P (user_start ) >= 1 && Z_STRLEN_P (user_end ) >= 1 ) {
2722
- int type1 , type2 ;
2723
- unsigned char low , high ;
2774
+ uint8_t start_type ;
2775
+ double start_double ;
2776
+ zend_long start_long ;
2777
+ uint8_t end_type ;
2778
+ double end_double ;
2779
+ zend_long end_long ;
2724
2780
2725
- type1 = is_numeric_string (Z_STRVAL_P (user_start ), Z_STRLEN_P (user_start ), NULL , NULL , 0 );
2726
- type2 = is_numeric_string (Z_STRVAL_P (user_end ), Z_STRLEN_P (user_end ), NULL , NULL , 0 );
2781
+ start_type = php_range_process_input (user_start , 1 , & start_long , & start_double );
2782
+ if (start_type == 0 ) {
2783
+ RETURN_THROWS ();
2784
+ }
2785
+ end_type = php_range_process_input (user_end , 2 , & end_long , & end_double );
2786
+ if (end_type == 0 ) {
2787
+ RETURN_THROWS ();
2788
+ }
2789
+
2790
+ /* If the range is given as strings, generate an array of characters. */
2791
+ if (start_type == IS_STRING || end_type == IS_STRING ) {
2792
+ if (UNEXPECTED (start_type != end_type )) {
2793
+ if (start_type != IS_STRING ) {
2794
+ php_error_docref (NULL , E_WARNING , "Argument #1 ($start) must be a string if argument #2 ($end)"
2795
+ " is a string, argument #2 ($end) converted to 0" );
2796
+ end_type = IS_LONG ;
2797
+ } else {
2798
+ php_error_docref (NULL , E_WARNING , "Argument #2 ($end) must be a string if argument #1 ($start)"
2799
+ " is a string, argument #1 ($start) converted to 0" );
2800
+ start_type = IS_LONG ;
2801
+ }
2802
+ if (UNEXPECTED (EG (exception ))) {
2803
+ RETURN_THROWS ();
2804
+ }
2805
+ goto handle_numeric_inputs ;
2806
+ }
2727
2807
2728
- if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double ) {
2729
- goto double_str ;
2730
- } else if (type1 == IS_LONG || type2 == IS_LONG ) {
2731
- goto long_str ;
2808
+ if (is_step_double ) {
2809
+ php_error_docref (NULL , E_WARNING , "Argument #3 ($step) must be of type int when generating an array"
2810
+ " of characters, inputs converted to 0" );
2811
+ if (UNEXPECTED (EG (exception ))) {
2812
+ RETURN_THROWS ();
2813
+ }
2814
+ end_type = IS_LONG ;
2815
+ start_type = IS_LONG ;
2816
+ goto handle_numeric_inputs ;
2732
2817
}
2733
2818
2734
- low = (unsigned char )Z_STRVAL_P (user_start )[0 ];
2735
- high = (unsigned char )Z_STRVAL_P (user_end )[0 ];
2819
+ /* Generate array of characters */
2820
+ unsigned char low = (unsigned char )Z_STRVAL_P (user_start )[0 ];
2821
+ unsigned char high = (unsigned char )Z_STRVAL_P (user_end )[0 ];
2736
2822
2737
2823
if (low > high ) { /* Negative Steps */
2738
2824
if (low - high < step ) {
@@ -2772,93 +2858,84 @@ PHP_FUNCTION(range)
2772
2858
ZVAL_CHAR (& tmp , low );
2773
2859
zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & tmp );
2774
2860
}
2775
- } else if (Z_TYPE_P (user_start ) == IS_DOUBLE || Z_TYPE_P (user_end ) == IS_DOUBLE || is_step_double ) {
2776
- double low , high , element ;
2777
- uint32_t i , size ;
2778
- double_str :
2779
- low = zval_get_double (user_start );
2780
- high = zval_get_double (user_end );
2861
+ return ;
2862
+ }
2781
2863
2782
- if ( zend_isinf ( high ) || zend_isinf ( low )) {
2783
- zend_value_error ( "Invalid range supplied: start=%0.0f end=%0.0f" , low , high );
2784
- RETURN_THROWS () ;
2785
- }
2864
+ handle_numeric_inputs :
2865
+ if ( start_type == IS_DOUBLE || end_type == IS_DOUBLE || is_step_double ) {
2866
+ double element ;
2867
+ uint32_t i , size ;
2786
2868
2787
- if (low > high ) { /* Negative steps */
2788
- if (low - high < step_double ) {
2869
+ if (start_double > end_double ) { /* Negative steps */
2870
+ if (start_double - end_double < step_double ) {
2789
2871
err = 1 ;
2790
2872
goto err ;
2791
2873
}
2792
2874
2793
- RANGE_CHECK_DOUBLE_INIT_ARRAY (low , high , step_double );
2875
+ RANGE_CHECK_DOUBLE_INIT_ARRAY (start_double , end_double , step_double );
2794
2876
2795
2877
ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
2796
- for (i = 0 , element = low ; i < size && element >= high ; ++ i , element = low - (i * step_double )) {
2878
+ for (i = 0 , element = start_double ; i < size && element >= end_double ; ++ i , element = start_double - (i * step_double )) {
2797
2879
ZEND_HASH_FILL_SET_DOUBLE (element );
2798
2880
ZEND_HASH_FILL_NEXT ();
2799
2881
}
2800
2882
} ZEND_HASH_FILL_END ();
2801
- } else if (high > low ) { /* Positive steps */
2802
- if (high - low < step_double ) {
2883
+ } else if (end_double > start_double ) { /* Positive steps */
2884
+ if (end_double - start_double < step_double ) {
2803
2885
err = 1 ;
2804
2886
goto err ;
2805
2887
}
2806
2888
2807
- RANGE_CHECK_DOUBLE_INIT_ARRAY (high , low , step_double );
2889
+ RANGE_CHECK_DOUBLE_INIT_ARRAY (end_double , start_double , step_double );
2808
2890
2809
2891
ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
2810
- for (i = 0 , element = low ; i < size && element <= high ; ++ i , element = low + (i * step_double )) {
2892
+ for (i = 0 , element = start_double ; i < size && element <= end_double ; ++ i , element = start_double + (i * step_double )) {
2811
2893
ZEND_HASH_FILL_SET_DOUBLE (element );
2812
2894
ZEND_HASH_FILL_NEXT ();
2813
2895
}
2814
2896
} ZEND_HASH_FILL_END ();
2815
2897
} else {
2816
2898
array_init (return_value );
2817
- ZVAL_DOUBLE (& tmp , low );
2899
+ ZVAL_DOUBLE (& tmp , start_double );
2818
2900
zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & tmp );
2819
2901
}
2820
2902
} else {
2821
- zend_long low , high ;
2903
+ ZEND_ASSERT ( start_type == IS_LONG && end_type == IS_LONG && ! is_step_double ) ;
2822
2904
/* unsigned_step is a zend_ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
2823
- zend_ulong unsigned_step ;
2905
+ zend_ulong unsigned_step = ( zend_ulong ) step ;
2824
2906
uint32_t i , size ;
2825
- long_str :
2826
- low = zval_get_long (user_start );
2827
- high = zval_get_long (user_end );
2828
-
2829
- unsigned_step = (zend_ulong )step ;
2830
2907
2831
- if (low > high ) { /* Negative steps */
2832
- if ((zend_ulong )low - high < unsigned_step ) {
2908
+ if (start_long > end_long ) { /* Negative steps */
2909
+ if ((zend_ulong )start_long - end_long < unsigned_step ) {
2833
2910
err = 1 ;
2834
2911
goto err ;
2835
2912
}
2836
2913
2837
- RANGE_CHECK_LONG_INIT_ARRAY (low , high , unsigned_step );
2914
+ RANGE_CHECK_LONG_INIT_ARRAY (start_long , end_long , unsigned_step );
2838
2915
2839
2916
ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
2840
2917
for (i = 0 ; i < size ; ++ i ) {
2841
- ZEND_HASH_FILL_SET_LONG (low - (i * unsigned_step ));
2918
+ ZEND_HASH_FILL_SET_LONG (start_long - (i * unsigned_step ));
2842
2919
ZEND_HASH_FILL_NEXT ();
2843
2920
}
2844
2921
} ZEND_HASH_FILL_END ();
2845
- } else if (high > low ) { /* Positive steps */
2846
- if ((zend_ulong )high - low < unsigned_step ) {
2922
+ } else if (end_long > start_long ) { /* Positive steps */
2923
+ if ((zend_ulong )end_long - start_long < unsigned_step ) {
2847
2924
err = 1 ;
2848
2925
goto err ;
2849
2926
}
2850
2927
2851
- RANGE_CHECK_LONG_INIT_ARRAY (high , low , unsigned_step );
2928
+ RANGE_CHECK_LONG_INIT_ARRAY (end_long , start_long , unsigned_step );
2852
2929
2853
2930
ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
2854
2931
for (i = 0 ; i < size ; ++ i ) {
2855
- ZEND_HASH_FILL_SET_LONG (low + (i * unsigned_step ));
2932
+ ZEND_HASH_FILL_SET_LONG (start_long + (i * unsigned_step ));
2856
2933
ZEND_HASH_FILL_NEXT ();
2857
2934
}
2858
2935
} ZEND_HASH_FILL_END ();
2859
2936
} else {
2860
2937
array_init (return_value );
2861
- ZVAL_LONG (& tmp , low );
2938
+ ZVAL_LONG (& tmp , start_long );
2862
2939
zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & tmp );
2863
2940
}
2864
2941
}
0 commit comments