@@ -364,6 +364,27 @@ php_sprintf_getnumber(char **buffer, size_t *len)
364
364
}
365
365
/* }}} */
366
366
367
+ #define ARG_NUM_NEXT -1
368
+ #define ARG_NUM_INVALID -2
369
+
370
+ int php_sprintf_get_argnum (char * * format , size_t * format_len ) {
371
+ char * temppos = * format ;
372
+ while (isdigit ((int ) * temppos )) temppos ++ ;
373
+ if (* temppos != '$' ) {
374
+ return ARG_NUM_NEXT ;
375
+ }
376
+
377
+ int argnum = php_sprintf_getnumber (format , format_len );
378
+ if (argnum <= 0 ) {
379
+ zend_value_error ("Argument number must be greater than zero" );
380
+ return ARG_NUM_INVALID ;
381
+ }
382
+
383
+ (* format )++ ; /* skip the '$' */
384
+ (* format_len )-- ;
385
+ return argnum - 1 ;
386
+ }
387
+
367
388
/* php_formatted_print() {{{
368
389
* New sprintf implementation for PHP.
369
390
*
@@ -438,23 +459,12 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
438
459
* format , format - Z_STRVAL_P (z_format )));
439
460
if (isalpha ((int )* format )) {
440
461
width = precision = 0 ;
441
- argnum = currarg ++ ;
462
+ argnum = ARG_NUM_NEXT ;
442
463
} else {
443
464
/* first look for argnum */
444
- temppos = format ;
445
- while (isdigit ((int )* temppos )) temppos ++ ;
446
- if (* temppos == '$' ) {
447
- argnum = php_sprintf_getnumber (& format , & format_len );
448
-
449
- if (argnum <= 0 ) {
450
- zend_value_error ("Argument number must be greater than zero" );
451
- goto fail ;
452
- }
453
- argnum -- ;
454
- format ++ ; /* skip the '$' */
455
- format_len -- ;
456
- } else {
457
- argnum = currarg ++ ;
465
+ argnum = php_sprintf_get_argnum (& format , & format_len );
466
+ if (argnum == ARG_NUM_INVALID ) {
467
+ goto fail ;
458
468
}
459
469
460
470
/* after argnum comes modifiers */
@@ -489,7 +499,34 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
489
499
490
500
491
501
/* after modifiers comes width */
492
- if (isdigit ((int )* format )) {
502
+ if (* format == '*' ) {
503
+ format ++ ;
504
+ format_len -- ;
505
+
506
+ int width_argnum = php_sprintf_get_argnum (& format , & format_len );
507
+ if (width_argnum == ARG_NUM_INVALID ) {
508
+ goto fail ;
509
+ }
510
+ if (width_argnum == ARG_NUM_NEXT ) {
511
+ width_argnum = currarg ++ ;
512
+ }
513
+ if (width_argnum >= argc ) {
514
+ max_missing_argnum = MAX (max_missing_argnum , width_argnum );
515
+ continue ;
516
+ }
517
+ tmp = & args [width_argnum ];
518
+ ZVAL_DEREF (tmp );
519
+ if (Z_TYPE_P (tmp ) != IS_LONG ) {
520
+ zend_value_error ("Width must be an integer" );
521
+ goto fail ;
522
+ }
523
+ if (Z_LVAL_P (tmp ) < 0 || Z_LVAL_P (tmp ) > INT_MAX ) {
524
+ zend_value_error ("Width must be greater than zero and less than %d" , INT_MAX );
525
+ goto fail ;
526
+ }
527
+ width = Z_LVAL_P (tmp );
528
+ adjusting |= ADJ_WIDTH ;
529
+ } else if (isdigit ((int )* format )) {
493
530
PRINTF_DEBUG (("sprintf: getting width\n" ));
494
531
if ((width = php_sprintf_getnumber (& format , & format_len )) < 0 ) {
495
532
zend_value_error ("Width must be greater than zero and less than %d" , INT_MAX );
@@ -506,7 +543,35 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
506
543
format ++ ;
507
544
format_len -- ;
508
545
PRINTF_DEBUG (("sprintf: getting precision\n" ));
509
- if (isdigit ((int )* format )) {
546
+ if (* format == '*' ) {
547
+ format ++ ;
548
+ format_len -- ;
549
+
550
+ int prec_argnum = php_sprintf_get_argnum (& format , & format_len );
551
+ if (prec_argnum == ARG_NUM_INVALID ) {
552
+ goto fail ;
553
+ }
554
+ if (prec_argnum == ARG_NUM_NEXT ) {
555
+ prec_argnum = currarg ++ ;
556
+ }
557
+ if (prec_argnum >= argc ) {
558
+ max_missing_argnum = MAX (max_missing_argnum , prec_argnum );
559
+ continue ;
560
+ }
561
+ tmp = & args [prec_argnum ];
562
+ ZVAL_DEREF (tmp );
563
+ if (Z_TYPE_P (tmp ) != IS_LONG ) {
564
+ zend_value_error ("Precision must be an integer" );
565
+ goto fail ;
566
+ }
567
+ if (Z_LVAL_P (tmp ) < -1 || Z_LVAL_P (tmp ) > INT_MAX ) {
568
+ zend_value_error ("Precision must be between -1 and %d" , INT_MAX );
569
+ goto fail ;
570
+ }
571
+ precision = Z_LVAL_P (tmp );
572
+ adjusting |= ADJ_PRECISION ;
573
+ expprec = 1 ;
574
+ } else if (isdigit ((int )* format )) {
510
575
if ((precision = php_sprintf_getnumber (& format , & format_len )) < 0 ) {
511
576
zend_value_error ("Precision must be greater than zero and less than %d" , INT_MAX );
512
577
goto fail ;
@@ -528,11 +593,19 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
528
593
}
529
594
PRINTF_DEBUG (("sprintf: format character='%c'\n" , * format ));
530
595
596
+ if (argnum == ARG_NUM_NEXT ) {
597
+ argnum = currarg ++ ;
598
+ }
531
599
if (argnum >= argc ) {
532
600
max_missing_argnum = MAX (max_missing_argnum , argnum );
533
601
continue ;
534
602
}
535
603
604
+ if (expprec && precision == -1 && * format != 'g' && * format != 'G' ) {
605
+ zend_value_error ("Precision -1 is only supported for %%g and %%G" );
606
+ goto fail ;
607
+ }
608
+
536
609
/* now we expect to find a type specifier */
537
610
tmp = & args [argnum ];
538
611
switch (* format ) {
0 commit comments