@@ -1130,16 +1130,134 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, const char *de
1130
1130
return res ;
1131
1131
}
1132
1132
1133
+ PHPAPI zend_string * _php_math_number_format_long (zend_long num , zend_long dec , const char * dec_point ,
1134
+ size_t dec_point_len , const char * thousand_sep , size_t thousand_sep_len )
1135
+ {
1136
+ static const zend_ulong powers [] = {
1137
+ 1 , 10 , 100 , 1000 , 10000 ,
1138
+ 100000 , 1000000 , 10000000 , 100000000 , 1000000000 ,
1139
+ #if SIZEOF_ZEND_LONG == 8
1140
+ 10000000000 , 100000000000 , 1000000000000 , 10000000000000 , 100000000000000 ,
1141
+ 1000000000000000 , 10000000000000000 , 100000000000000000 , 1000000000000000000 , 10000000000000000000ul
1142
+ #elif SIZEOF_ZEND_LONG > 8
1143
+ # error "Unknown SIZEOF_ZEND_LONG "
1144
+ #endif
1145
+ };
1146
+
1147
+ int is_negative = 0 ;
1148
+ zend_ulong tmpnum ;
1149
+ zend_ulong power ;
1150
+ zend_ulong power_half ;
1151
+ zend_ulong rest ;
1152
+
1153
+ zend_string * tmpbuf ;
1154
+ zend_string * res ;
1155
+ size_t reslen ;
1156
+ char * s , * t ; /* source, target */
1157
+ int count = 0 ;
1158
+ size_t topad ;
1159
+
1160
+ // unsigned absolute number and memorize negative sign
1161
+ if (num < 0 ) {
1162
+ is_negative = 1 ;
1163
+ tmpnum = ((zend_ulong )- (num + 1 )) + 1 ;
1164
+ } else {
1165
+ tmpnum = (zend_ulong )num ;
1166
+ }
1167
+
1168
+ // rounding the number
1169
+ if (dec < 0 ) {
1170
+ // Check rounding to more negative places than possible
1171
+ if (dec < - (sizeof (powers ) / sizeof (powers [0 ]) - 1 )) {
1172
+ tmpnum = 0 ;
1173
+ } else {
1174
+ power = powers [- dec ];
1175
+ power_half = power / 2 ;
1176
+ rest = tmpnum % power ;
1177
+ tmpnum = tmpnum / power ;
1178
+
1179
+ if (rest >= power_half ) {
1180
+ tmpnum = tmpnum * power + power ;
1181
+ } else {
1182
+ tmpnum = tmpnum * power ;
1183
+ }
1184
+ }
1185
+
1186
+ // prevent resulting in negative zero
1187
+ if (tmpnum == 0 ) {
1188
+ is_negative = 0 ;
1189
+ }
1190
+ }
1191
+
1192
+ tmpbuf = strpprintf (0 , ZEND_ULONG_FMT , tmpnum );
1193
+ reslen = ZSTR_LEN (tmpbuf );
1194
+
1195
+ /* allow for thousand separators */
1196
+ if (thousand_sep ) {
1197
+ reslen = zend_safe_addmult ((reslen - 1 )/3 , thousand_sep_len , reslen , "number formatting" );
1198
+ }
1199
+
1200
+ reslen += is_negative ;
1201
+
1202
+ if (dec > 0 ) {
1203
+ reslen += dec ;
1204
+
1205
+ if (dec_point ) {
1206
+ reslen = zend_safe_addmult (reslen , 1 , dec_point_len , "number formatting" );
1207
+ }
1208
+ }
1209
+
1210
+ res = zend_string_alloc (reslen , 0 );
1211
+
1212
+ s = ZSTR_VAL (tmpbuf ) + ZSTR_LEN (tmpbuf ) - 1 ;
1213
+ t = ZSTR_VAL (res ) + reslen ;
1214
+ * t -- = '\0' ;
1215
+
1216
+ /* copy the decimal places. */
1217
+ if (dec > 0 ) {
1218
+ topad = (size_t )dec ;
1219
+
1220
+ /* pad with '0's */
1221
+ while (topad -- ) {
1222
+ * t -- = '0' ;
1223
+ }
1224
+
1225
+ /* add decimal point */
1226
+ if (dec_point ) {
1227
+ t -= dec_point_len ;
1228
+ memcpy (t + 1 , dec_point , dec_point_len );
1229
+ }
1230
+ }
1231
+
1232
+ /* copy the numbers before the decimal point, adding thousand
1233
+ * separator every three digits */
1234
+ while (s >= ZSTR_VAL (tmpbuf )) {
1235
+ * t -- = * s -- ;
1236
+ if (thousand_sep && (++ count % 3 ) == 0 && s >= ZSTR_VAL (tmpbuf )) {
1237
+ t -= thousand_sep_len ;
1238
+ memcpy (t + 1 , thousand_sep , thousand_sep_len );
1239
+ }
1240
+ }
1241
+
1242
+ if (is_negative ) {
1243
+ * t -- = '-' ;
1244
+ }
1245
+
1246
+ ZSTR_LEN (res ) = reslen ;
1247
+ zend_string_release_ex (tmpbuf , 0 );
1248
+ return res ;
1249
+ }
1250
+
1133
1251
/* {{{ Formats a number with grouped thousands */
1134
1252
PHP_FUNCTION (number_format )
1135
1253
{
1136
- double num ;
1254
+ zval * num ;
1137
1255
zend_long dec = 0 ;
1138
1256
char * thousand_sep = NULL , * dec_point = NULL ;
1139
1257
size_t thousand_sep_len = 0 , dec_point_len = 0 ;
1140
1258
1141
1259
ZEND_PARSE_PARAMETERS_START (1 , 4 )
1142
- Z_PARAM_DOUBLE (num )
1260
+ Z_PARAM_NUMBER (num )
1143
1261
Z_PARAM_OPTIONAL
1144
1262
Z_PARAM_LONG (dec )
1145
1263
Z_PARAM_STRING_OR_NULL (dec_point , dec_point_len )
@@ -1155,7 +1273,17 @@ PHP_FUNCTION(number_format)
1155
1273
thousand_sep_len = 1 ;
1156
1274
}
1157
1275
1158
- RETURN_STR (_php_math_number_format_ex (num , (int )dec , dec_point , dec_point_len , thousand_sep , thousand_sep_len ));
1276
+ switch (Z_TYPE_P (num )) {
1277
+ case IS_LONG :
1278
+ RETURN_STR (_php_math_number_format_long (Z_LVAL_P (num ), dec , dec_point , dec_point_len , thousand_sep , thousand_sep_len ));
1279
+ break ;
1280
+
1281
+ case IS_DOUBLE :
1282
+ RETURN_STR (_php_math_number_format_ex (Z_DVAL_P (num ), (int )dec , dec_point , dec_point_len , thousand_sep , thousand_sep_len ));
1283
+ break ;
1284
+
1285
+ EMPTY_SWITCH_DEFAULT_CASE ()
1286
+ }
1159
1287
}
1160
1288
/* }}} */
1161
1289
0 commit comments