@@ -102,10 +102,13 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath)
102
102
}
103
103
/* }}} */
104
104
105
+ static void bc_num_register_class (void );
106
+
105
107
/* {{{ PHP_MINIT_FUNCTION */
106
108
PHP_MINIT_FUNCTION (bcmath )
107
109
{
108
110
REGISTER_INI_ENTRIES ();
111
+ bc_num_register_class ();
109
112
110
113
return SUCCESS ;
111
114
}
@@ -763,5 +766,271 @@ PHP_FUNCTION(bcscale)
763
766
}
764
767
/* }}} */
765
768
769
+ static zend_class_entry * bc_num_ce ;
770
+ static zend_object_handlers bc_num_obj_handlers ;
771
+ #define IS_BC_NUM (zval ) (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), bc_num_ce))
772
+
773
+ static inline bc_num_obj * bc_num_obj_from_obj (zend_object * obj ) {
774
+ return (bc_num_obj * )((char * )(obj ) - XtOffsetOf (bc_num_obj , std ));
775
+ }
776
+
777
+ static inline bc_num_obj * bc_num_obj_from_zval (zval * zv ) {
778
+ return bc_num_obj_from_obj (Z_OBJ_P (zv ));
779
+ }
780
+
781
+ /* {{{ bc_num_ce->create_object */
782
+ static zend_object * bc_num_create_obj (zend_class_entry * ce )
783
+ {
784
+ bc_num_obj * intern ;
785
+
786
+ intern = zend_object_alloc (sizeof (bc_num_obj ), ce );
787
+ zend_object_std_init (& intern -> std , ce );
788
+ object_properties_init (& intern -> std , ce );
789
+ rebuild_object_properties (& intern -> std );
790
+
791
+ return & intern -> std ;
792
+ }
793
+ /* }}} */
794
+
795
+ /* {{{ bc_num_obj_handlers.free_obj */
796
+ static void bc_num_free_obj (zend_object * object )
797
+ {
798
+ bc_num_obj * intern = bc_num_obj_from_obj (object );
799
+ if (intern -> bc_num ) {
800
+ bc_free_num (& intern -> bc_num );
801
+ }
802
+ efree (intern -> bc_num );
803
+ zend_object_std_dtor (& intern -> std );
804
+ }
805
+ /* }}} */
806
+
807
+ /* {{{ bc_num_obj_handlers.clone_obj */
808
+ static zend_object * bc_num_clone_obj (zend_object * object )
809
+ {
810
+ bc_num_obj * old_obj = bc_num_obj_from_obj (object );
811
+ bc_num_obj * new_obj = bc_num_obj_from_obj (bc_num_create_obj (old_obj -> std .ce ));
812
+
813
+ zend_objects_clone_members (& new_obj -> std , & old_obj -> std );
814
+ new_obj -> bc_num = bc_copy_num (old_obj -> bc_num );
815
+
816
+ return & new_obj -> std ;
817
+ }
818
+ /* }}} */
819
+
820
+ static zend_result convert_zval_to_bc_num (zval * zv , bc_num * num )
821
+ {
822
+ switch (Z_TYPE_P (zv )) {
823
+ case IS_LONG :
824
+ case IS_STRING :
825
+ convert_to_string (zv );
826
+ bc_init_num (& num1 );
827
+ if (!bc_str2num (num , Z_STRVAL_P (zv ), 0 )) {
828
+ return FAILURE ;
829
+ }
830
+ break ;
831
+ case IS_OBJECT :
832
+ if (instanceof_function (Z_OBJCE_P (zv ), bc_num_ce )) {
833
+ bc_free_num (num );
834
+ * num = bc_num_obj_from_zval (zv )-> bc_num ;
835
+ } else {
836
+ zend_argument_type_error (0 , "must be of type int, string, or BcNum, %s given" , zend_zval_value_name (zv ));
837
+ return FAILURE ;
838
+ }
839
+ break ;
840
+ }
841
+
842
+ return SUCCESS ;
843
+ }
844
+
845
+ static zend_result bc_num_calculation (zval * result , zval * op1 , zval * op2 , bc_num_calculation_type type , bool is_operator )
846
+ {
847
+ bc_num num1 , num2 ;
848
+
849
+ if (convert_zval_to_bc_num (op1 , & num1 ) == FAILURE || convert_zval_to_bc_num (op2 , & num2 ) == FAILURE ) {
850
+ return FAILURE ;
851
+ }
852
+
853
+ bc_num_obj * result_obj = bc_num_obj_from_obj (bc_num_create_obj (bc_num_ce ));
854
+ bc_init_num (& result_obj -> bc_num );
855
+
856
+ size_t scale = MAX (num1 -> n_scale , num2 -> n_scale );
857
+
858
+ switch (type ) {
859
+ case BC_NUM_ADD :
860
+ bc_add (num1 , num2 , & result_obj -> bc_num , scale );
861
+ break ;
862
+ case BC_NUM_SUB :
863
+ bc_sub (num1 , num2 , & result_obj -> bc_num , scale );
864
+ break ;
865
+ case BC_NUM_MUL :
866
+ bc_multiply (num1 , num2 , & result_obj -> bc_num , scale );
867
+ break ;
868
+ case BC_NUM_DIV :
869
+ bc_divide (num1 , num2 , & result_obj -> bc_num , scale );
870
+ break ;
871
+ case BC_NUM_MOD :
872
+ bc_modulo (num1 , num2 , & result_obj -> bc_num , scale );
873
+ break ;
874
+ case BC_NUM_POW :
875
+ {
876
+ long exponent = bc_num2long (num2 );
877
+ if (exponent == 0 && (num2 -> n_len > 1 || num2 -> n_value [0 ] != 0 )) {
878
+ zend_argument_value_error (is_operator ? 0 : 1 , "exponent is too large" );
879
+ return FAILURE ;
880
+ }
881
+ bc_raise (num1 , bc_num2long (num2 ), & result_obj -> bc_num , scale );
882
+ }
883
+ break ;
884
+ EMPTY_SWITCH_DEFAULT_CASE ()
885
+ }
886
+
887
+ result_obj -> bc_num -> n_scale = scale ;
888
+ ZVAL_OBJ (result , & result_obj -> std );
889
+ return SUCCESS ;
890
+ }
891
+
892
+ /* {{{ bc_num_obj_handlers.do_operation */
893
+ static int bc_num_do_operation (uint8_t opcode , zval * result , zval * op1 , zval * op2 )
894
+ {
895
+ zend_result ret ;
896
+
897
+ switch (opcode ) {
898
+ case ZEND_ADD :
899
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_ADD , true);
900
+ break ;
901
+ case ZEND_SUB :
902
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_SUB , true);
903
+ break ;
904
+ case ZEND_MUL :
905
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_MUL , true);
906
+ break ;
907
+ case ZEND_POW :
908
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_POW , true);
909
+ break ;
910
+ case ZEND_DIV :
911
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_DIV , true);
912
+ break ;
913
+ case ZEND_MOD :
914
+ ret = bc_num_calculation (result , op1 , op2 , BC_NUM_MOD , true);
915
+ break ;
916
+ default :
917
+ return FAILURE ;
918
+ }
919
+
920
+ return ret ;
921
+ }
922
+ /* }}} */
923
+
924
+ /* {{{ bc_num_obj_handlers.compare */
925
+ static int bc_num_compare (zval * z1 , zval * z2 )
926
+ {
927
+ bc_num_obj * obj1 ;
928
+ bc_num_obj * obj2 ;
929
+
930
+ ZEND_COMPARE_OBJECTS_FALLBACK (z1 , z2 );
931
+
932
+ obj1 = bc_num_obj_from_zval (z1 );
933
+ obj2 = bc_num_obj_from_zval (z2 );
934
+
935
+ return bc_compare (obj1 -> bc_num , obj2 -> bc_num );
936
+ }
937
+ /* }}} */
938
+
939
+ /* {{{ bc_num_obj_handlers.get_properties_for */
940
+ static HashTable * bc_num_get_properties_for (zend_object * object , zend_prop_purpose purpose )
941
+ {
942
+ HashTable * props ;
943
+ bc_num_obj * bc_num_obj ;
944
+
945
+ switch (purpose ) {
946
+ case ZEND_PROP_PURPOSE_DEBUG :
947
+ case ZEND_PROP_PURPOSE_SERIALIZE :
948
+ case ZEND_PROP_PURPOSE_VAR_EXPORT :
949
+ case ZEND_PROP_PURPOSE_JSON :
950
+ case ZEND_PROP_PURPOSE_ARRAY_CAST :
951
+ break ;
952
+ default :
953
+ return zend_std_get_properties_for (object , purpose );
954
+ }
955
+
956
+ zval zv ;
957
+ bc_num_obj = bc_num_obj_from_obj (object );
958
+ props = zend_array_dup (zend_std_get_properties (object ));
959
+
960
+ ZVAL_STR (& zv , bc_num2str (bc_num_obj -> bc_num ));
961
+ zend_hash_str_update (props , "num" , sizeof ("num" )- 1 , & zv );
962
+ ZVAL_LONG (& zv , bc_num_obj -> bc_num -> n_scale );
963
+ zend_hash_str_update (props , "scale" , sizeof ("scale" )- 1 , & zv );
964
+
965
+ return props ;
966
+ }
967
+ /* }}} */
968
+
969
+ /* {{{ bc_num_obj_handlers.get_gc */
970
+ static HashTable * bc_num_get_gc (zend_object * object , zval * * table , int * n )
971
+ {
972
+ * table = NULL ;
973
+ * n = 0 ;
974
+ return zend_std_get_properties (object );
975
+ }
976
+ /* }}} */
977
+
978
+ static void bc_num_register_class (void )
979
+ {
980
+ bc_num_ce = register_class_BcNum ();
981
+ bc_num_ce -> create_object = bc_num_create_obj ;
982
+ bc_num_ce -> default_object_handlers = & bc_num_obj_handlers ;
983
+
984
+ memcpy (& bc_num_obj_handlers , & std_object_handlers , sizeof (zend_object_handlers ));
985
+ bc_num_obj_handlers .offset = XtOffsetOf (bc_num_obj , std );
986
+ bc_num_obj_handlers .free_obj = bc_num_free_obj ;
987
+ bc_num_obj_handlers .clone_obj = bc_num_clone_obj ;
988
+ bc_num_obj_handlers .do_operation = bc_num_do_operation ;
989
+ bc_num_obj_handlers .compare = bc_num_compare ;
990
+ bc_num_obj_handlers .get_properties_for = bc_num_get_properties_for ;
991
+ bc_num_obj_handlers .get_gc = bc_num_get_gc ;
992
+ }
993
+
994
+ /* {{{ Creates new BcNum */
995
+ PHP_METHOD (BcNum , __construct )
996
+ {
997
+ zend_string * num_str ;
998
+ zend_long scale_param ;
999
+ bool scale_param_is_null = 1 ;
1000
+ int scale ;
1001
+
1002
+ ZEND_PARSE_PARAMETERS_START (1 , 2 )
1003
+ Z_PARAM_STR (num_str )
1004
+ Z_PARAM_OPTIONAL
1005
+ Z_PARAM_LONG_OR_NULL (scale_param , scale_param_is_null )
1006
+ ZEND_PARSE_PARAMETERS_END ();
1007
+
1008
+ if (scale_param_is_null ) {
1009
+ scale = BCG (bc_precision );
1010
+ } else if (scale_param < 0 || scale_param > INT_MAX ) {
1011
+ zend_argument_value_error (2 , "must be between 0 and %d" , INT_MAX );
1012
+ RETURN_THROWS ();
1013
+ } else {
1014
+ scale = (int ) scale_param ;
1015
+ }
1016
+
1017
+ bc_num_obj * obj = bc_num_obj_from_zval (ZEND_THIS );
1018
+ bc_init_num (& obj -> bc_num );
1019
+
1020
+ if (php_str2num (& obj -> bc_num , ZSTR_VAL (num_str )) == FAILURE ) {
1021
+ zend_argument_value_error (1 , "is not well-formed" );
1022
+ bc_free_num (& obj -> bc_num );
1023
+ RETURN_THROWS ();
1024
+ }
1025
+
1026
+ if (obj -> bc_num -> n_scale < scale ) {
1027
+ char * nptr = (char * ) (obj -> bc_num -> n_value + obj -> bc_num -> n_len + obj -> bc_num -> n_scale );
1028
+ for (int count = scale - obj -> bc_num -> n_scale ; count > 0 ; count -- ) {
1029
+ * nptr ++ = 0 ;
1030
+ }
1031
+ }
1032
+ obj -> bc_num -> n_scale = scale ;
1033
+ }
1034
+ /* }}} */
766
1035
767
1036
#endif
0 commit comments