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