@@ -555,6 +555,49 @@ inline int parseIntAndAdvance(const char*& c)
555555 return i;
556556}
557557
558+ // Parse width or precision `n` from format string pointer `c`, and advance it
559+ // to the next character. If an indirection is requested with `*`, the argument
560+ // is read from `formatters[argIndex]` and `argIndex` is incremented (or read
561+ // from `formatters[n]` in positional mode). Returns true if one or more
562+ // characters were read.
563+ inline bool parseWidthOrPrecision (int & n, const char *& c, bool positionalMode,
564+ const detail::FormatArg* formatters,
565+ int & argIndex, int numFormatters)
566+ {
567+ if (*c >= ' 0' && *c <= ' 9' )
568+ {
569+ n = parseIntAndAdvance (c);
570+ }
571+ else if (*c == ' *' )
572+ {
573+ ++c;
574+ n = 0 ;
575+ if (positionalMode)
576+ {
577+ int pos = parseIntAndAdvance (c) - 1 ;
578+ if (*c != ' $' )
579+ TINYFORMAT_ERROR (" tinyformat: Non-positional argument used after a positional one" );
580+ if (pos >= 0 && pos < numFormatters)
581+ n = formatters[pos].toInt ();
582+ else
583+ TINYFORMAT_ERROR (" tinyformat: Positional argument out of range" );
584+ ++c;
585+ }
586+ else
587+ {
588+ if (argIndex < numFormatters)
589+ n = formatters[argIndex++].toInt ();
590+ else
591+ TINYFORMAT_ERROR (" tinyformat: Not enough arguments to read variable width or precision" );
592+ }
593+ }
594+ else
595+ {
596+ return false ;
597+ }
598+ return true ;
599+ }
600+
558601// Print literal part of format string and return next format spec
559602// position.
560603//
@@ -649,15 +692,12 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode
649692 const char tmpc = *c;
650693 int value = parseIntAndAdvance (c);
651694 if (*c == ' $' )
652- { // value is an argument index
695+ {
696+ // value is an argument index
653697 if (value > 0 && value <= numFormatters)
654- {
655698 argIndex = value - 1 ;
656- }
657699 else
658- {
659700 TINYFORMAT_ERROR (" tinyformat: Positional argument out of range" );
660- }
661701 ++c;
662702 positionalMode = true ;
663703 }
@@ -727,33 +767,11 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode
727767 break ;
728768 }
729769 // Parse width
730- if (*c >= ' 0' && *c <= ' 9' )
731- {
732- widthSet = true ;
733- out.width (parseIntAndAdvance (c));
734- }
735- else if (*c == ' *' )
770+ int width = 0 ;
771+ widthSet = parseWidthOrPrecision (width, c, positionalMode,
772+ formatters, argIndex, numFormatters);
773+ if (widthSet)
736774 {
737- widthSet = true ;
738- int width = 0 ;
739- if (positionalMode)
740- {
741- ++c;
742- int pos = parseIntAndAdvance (c) - 1 ;
743- if (*c != ' $' )
744- TINYFORMAT_ERROR (" tinyformat: Non-positional argument used after a positional one" );
745- if (pos >= 0 && pos < numFormatters)
746- width = formatters[pos].toInt ();
747- else
748- TINYFORMAT_ERROR (" tinyformat: Positional argument out of range" );
749- }
750- else
751- {
752- if (argIndex < numFormatters)
753- width = formatters[argIndex++].toInt ();
754- else
755- TINYFORMAT_ERROR (" tinyformat: Not enough arguments to read variable width" );
756- }
757775 if (width < 0 )
758776 {
759777 // negative widths correspond to '-' flag set
@@ -762,45 +780,20 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode
762780 width = -width;
763781 }
764782 out.width (width);
765- ++c;
766783 }
767784 }
768785 // 3) Parse precision
769786 if (*c == ' .' )
770787 {
771788 ++c;
772789 int precision = 0 ;
773- if (*c == ' *' )
774- {
775- ++c;
776- if (positionalMode)
777- {
778- int pos = parseIntAndAdvance (c) - 1 ;
779- if (*c != ' $' )
780- TINYFORMAT_ERROR (" tinyformat: Non-positional argument used after a positional one" );
781- if (pos >= 0 && pos < numFormatters)
782- precision = formatters[pos].toInt ();
783- else
784- TINYFORMAT_ERROR (" tinyformat: Positional argument out of range" );
785- ++c;
786- }
787- else
788- {
789- if (argIndex < numFormatters)
790- precision = formatters[argIndex++].toInt ();
791- else
792- TINYFORMAT_ERROR (" tinyformat: Not enough arguments to read variable precision" );
793- }
794- }
795- else
796- {
797- if (*c >= ' 0' && *c <= ' 9' )
798- precision = parseIntAndAdvance (c);
799- else if (*c == ' -' ) // negative precisions ignored, treated as zero.
800- parseIntAndAdvance (++c);
801- }
802- out.precision (precision);
803- precisionSet = true ;
790+ parseWidthOrPrecision (precision, c, positionalMode,
791+ formatters, argIndex, numFormatters);
792+ // Presence of `.` indicates precision set, unless the inferred value
793+ // was negative in which case the default is used.
794+ precisionSet = precision >= 0 ;
795+ if (precisionSet)
796+ out.precision (precision);
804797 }
805798 // 4) Ignore any C99 length modifier
806799 while (*c == ' l' || *c == ' h' || *c == ' L' ||
0 commit comments