@@ -373,6 +373,27 @@ php_sprintf_getnumber(char **buffer, size_t *len)
373
373
}
374
374
/* }}} */
375
375
376
+ #define ARG_NUM_NEXT -1
377
+ #define ARG_NUM_INVALID -2
378
+
379
+ int php_sprintf_get_argnum (char * * format , size_t * format_len ) {
380
+ char * temppos = * format ;
381
+ while (isdigit ((int ) * temppos )) temppos ++ ;
382
+ if (* temppos != '$' ) {
383
+ return ARG_NUM_NEXT ;
384
+ }
385
+
386
+ int argnum = php_sprintf_getnumber (format , format_len );
387
+ if (argnum <= 0 ) {
388
+ zend_value_error ("Argument number must be greater than zero" );
389
+ return ARG_NUM_INVALID ;
390
+ }
391
+
392
+ (* format )++ ; /* skip the '$' */
393
+ (* format_len )-- ;
394
+ return argnum - 1 ;
395
+ }
396
+
376
397
/* php_formatted_print() {{{
377
398
* New sprintf implementation for PHP.
378
399
*
@@ -447,23 +468,12 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
447
468
* format , format - Z_STRVAL_P (z_format )));
448
469
if (isalpha ((int )* format )) {
449
470
width = precision = 0 ;
450
- argnum = currarg ++ ;
471
+ argnum = ARG_NUM_NEXT ;
451
472
} else {
452
473
/* first look for argnum */
453
- temppos = format ;
454
- while (isdigit ((int )* temppos )) temppos ++ ;
455
- if (* temppos == '$' ) {
456
- argnum = php_sprintf_getnumber (& format , & format_len );
457
-
458
- if (argnum <= 0 ) {
459
- zend_value_error ("Argument number must be greater than zero" );
460
- goto fail ;
461
- }
462
- argnum -- ;
463
- format ++ ; /* skip the '$' */
464
- format_len -- ;
465
- } else {
466
- argnum = currarg ++ ;
474
+ argnum = php_sprintf_get_argnum (& format , & format_len );
475
+ if (argnum == ARG_NUM_INVALID ) {
476
+ goto fail ;
467
477
}
468
478
469
479
/* after argnum comes modifiers */
@@ -498,7 +508,34 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
498
508
499
509
500
510
/* after modifiers comes width */
501
- if (isdigit ((int )* format )) {
511
+ if (* format == '*' ) {
512
+ format ++ ;
513
+ format_len -- ;
514
+
515
+ int width_argnum = php_sprintf_get_argnum (& format , & format_len );
516
+ if (width_argnum == ARG_NUM_INVALID ) {
517
+ goto fail ;
518
+ }
519
+ if (width_argnum == ARG_NUM_NEXT ) {
520
+ width_argnum = currarg ++ ;
521
+ }
522
+ if (width_argnum >= argc ) {
523
+ max_missing_argnum = MAX (max_missing_argnum , width_argnum );
524
+ continue ;
525
+ }
526
+ tmp = & args [width_argnum ];
527
+ ZVAL_DEREF (tmp );
528
+ if (Z_TYPE_P (tmp ) != IS_LONG ) {
529
+ zend_value_error ("Width must be an integer" );
530
+ goto fail ;
531
+ }
532
+ if (Z_LVAL_P (tmp ) < 0 || Z_LVAL_P (tmp ) > INT_MAX ) {
533
+ zend_value_error ("Width must be greater than zero and less than %d" , INT_MAX );
534
+ goto fail ;
535
+ }
536
+ width = Z_LVAL_P (tmp );
537
+ adjusting |= ADJ_WIDTH ;
538
+ } else if (isdigit ((int )* format )) {
502
539
PRINTF_DEBUG (("sprintf: getting width\n" ));
503
540
if ((width = php_sprintf_getnumber (& format , & format_len )) < 0 ) {
504
541
zend_value_error ("Width must be greater than zero and less than %d" , INT_MAX );
@@ -515,7 +552,35 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
515
552
format ++ ;
516
553
format_len -- ;
517
554
PRINTF_DEBUG (("sprintf: getting precision\n" ));
518
- if (isdigit ((int )* format )) {
555
+ if (* format == '*' ) {
556
+ format ++ ;
557
+ format_len -- ;
558
+
559
+ int prec_argnum = php_sprintf_get_argnum (& format , & format_len );
560
+ if (prec_argnum == ARG_NUM_INVALID ) {
561
+ goto fail ;
562
+ }
563
+ if (prec_argnum == ARG_NUM_NEXT ) {
564
+ prec_argnum = currarg ++ ;
565
+ }
566
+ if (prec_argnum >= argc ) {
567
+ max_missing_argnum = MAX (max_missing_argnum , prec_argnum );
568
+ continue ;
569
+ }
570
+ tmp = & args [prec_argnum ];
571
+ ZVAL_DEREF (tmp );
572
+ if (Z_TYPE_P (tmp ) != IS_LONG ) {
573
+ zend_value_error ("Precision must be an integer" );
574
+ goto fail ;
575
+ }
576
+ if (Z_LVAL_P (tmp ) < -1 || Z_LVAL_P (tmp ) > INT_MAX ) {
577
+ zend_value_error ("Precision must be between -1 and %d" , INT_MAX );
578
+ goto fail ;
579
+ }
580
+ precision = Z_LVAL_P (tmp );
581
+ adjusting |= ADJ_PRECISION ;
582
+ expprec = 1 ;
583
+ } else if (isdigit ((int )* format )) {
519
584
if ((precision = php_sprintf_getnumber (& format , & format_len )) < 0 ) {
520
585
zend_value_error ("Precision must be greater than zero and less than %d" , INT_MAX );
521
586
goto fail ;
@@ -537,11 +602,20 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
537
602
}
538
603
PRINTF_DEBUG (("sprintf: format character='%c'\n" , * format ));
539
604
605
+ if (argnum == ARG_NUM_NEXT ) {
606
+ argnum = currarg ++ ;
607
+ }
540
608
if (argnum >= argc ) {
541
609
max_missing_argnum = MAX (max_missing_argnum , argnum );
542
610
continue ;
543
611
}
544
612
613
+ if (expprec && precision == -1
614
+ && * format != 'g' && * format != 'G' && * format != 'h' && * format != 'H' ) {
615
+ zend_value_error ("Precision -1 is only supported for %%g, %%G, %%h and %%H" );
616
+ goto fail ;
617
+ }
618
+
545
619
/* now we expect to find a type specifier */
546
620
tmp = & args [argnum ];
547
621
switch (* format ) {
0 commit comments