Program: 50902
Project: 50902
Buggy source:
/** 
 * Reads formatString up to the first semi-colon, or to the end if there are no semi-colons.  Adds a format to alternateFormatList, and returns the remains of formatString.
 */
private String parseFormatString(String formatString,List<BasicFormat> alternateFormatList,FormatType[] formatTypeOut){
  final String originalFormatString=formatString;
  int numberState=NOT_IN_A_NUMBER;
  StringBuilder ignored=new StringBuilder();
  String prevIgnored=null;
  boolean haveSeenNumber=false;
  int digitsLeftOfPoint=0, digitsRightOfPoint=0, digitsRightOfExp=0, zeroesLeftOfPoint=0, zeroesRightOfPoint=0, zeroesRightOfExp=0;
  boolean useDecimal=false, useThouSep=false, fillFromRight=true;
  int expFormat=FORMAT_NULL;
  if (macroTokenMap.containsKey(formatString)) {
    MacroToken macroToken=macroTokenMap.get(formatString);
    if (macroToken.translation == null) {
      if (macroToken.name.equals("String_Node_Str")) {
        formatString=locale.currencyFormat + "String_Node_Str" + locale.currencyFormat+ "String_Node_Str";
      }
 else {
        throw new Error("String_Node_Str" + macroToken.name + "String_Node_Str");
      }
    }
 else {
      formatString=macroToken.translation;
    }
  }
  if (!formatString.endsWith("String_Node_Str")) {
    formatString=formatString + "String_Node_Str";
  }
  List<BasicFormat> formatList=new ArrayList<BasicFormat>();
  loop:   while (formatString.length() > 0) {
    BasicFormat format=null;
    String newFormatString=null;
    boolean ignoreToken=false;
    for (int i=tokens.length - 1; i > 0; i--) {
      Token token=tokens[i];
      if (!formatString.startsWith(token.token)) {
        continue;
      }
      if (!token.compatibleWith(formatTypeOut[0])) {
        continue;
      }
      String matched=token.token;
      newFormatString=formatString.substring(matched.length());
      if (token.isSpecial()) {
switch (token.code) {
case FORMAT_SEMI:
          formatString=newFormatString;
        break loop;
case FORMAT_POUND:
switch (numberState) {
case NOT_IN_A_NUMBER:
        numberState=LEFT_OF_POINT;
case LEFT_OF_POINT:
      digitsLeftOfPoint++;
    break;
case RIGHT_OF_POINT:
  digitsRightOfPoint++;
break;
case RIGHT_OF_EXP:
digitsRightOfExp++;
break;
default :
throw new Error();
}
break;
case FORMAT_0:
switch (numberState) {
case NOT_IN_A_NUMBER:
numberState=LEFT_OF_POINT;
case LEFT_OF_POINT:
zeroesLeftOfPoint++;
break;
case RIGHT_OF_POINT:
zeroesRightOfPoint++;
break;
case RIGHT_OF_EXP:
zeroesRightOfExp++;
break;
default :
throw new Error();
}
break;
case FORMAT_M:
case FORMAT_MM:
{
boolean theyMeantMinute=false;
int j=formatList.size() - 1;
while (j >= 0) {
BasicFormat prevFormat=formatList.get(j);
if (prevFormat instanceof LiteralFormat) {
j--;
}
 else if (prevFormat.code == FORMAT_H || prevFormat.code == FORMAT_HH) {
theyMeantMinute=true;
break;
}
 else {
theyMeantMinute=false;
break;
}
}
if (theyMeantMinute) {
format=new DateFormat((token.code == FORMAT_M ? FORMAT_N : FORMAT_NN),matched,locale,false);
}
 else {
format=token.makeFormat(locale);
}
break;
}
case FORMAT_DECIMAL:
{
numberState=RIGHT_OF_POINT;
useDecimal=true;
break;
}
case FORMAT_THOUSEP:
{
if (numberState == LEFT_OF_POINT) {
useThouSep=true;
}
 else {
format=token.makeFormat(locale);
}
break;
}
case FORMAT_TIMESEP:
{
format=new LiteralFormat(locale.timeSeparator);
break;
}
case FORMAT_DATESEP:
{
format=new LiteralFormat(locale.dateSeparator);
break;
}
case FORMAT_BACKSLASH:
{
String s;
if (formatString.length() == 1) {
s="String_Node_Str";
newFormatString="String_Node_Str";
}
 else {
s=formatString.substring(1,2);
newFormatString=formatString.substring(2);
}
format=new LiteralFormat(s);
break;
}
case FORMAT_E_MINUS_UPPER:
case FORMAT_E_PLUS_UPPER:
case FORMAT_E_MINUS_LOWER:
case FORMAT_E_PLUS_LOWER:
{
numberState=RIGHT_OF_EXP;
expFormat=token.code;
if (zeroesLeftOfPoint == 0 && zeroesRightOfPoint == 0) {
zeroesLeftOfPoint=1;
}
break;
}
case FORMAT_QUOTE:
{
String s;
int j=formatString.indexOf("String_Node_Str",1);
if (j == -1) {
s=formatString.substring(1);
newFormatString="String_Node_Str";
}
 else {
s=formatString.substring(1,j);
newFormatString=formatString.substring(j + 1);
}
format=new LiteralFormat(s);
break;
}
case FORMAT_UPPER:
{
format=new StringFormat(StringCase.UPPER,"String_Node_Str",locale.locale);
break;
}
case FORMAT_LOWER:
{
format=new StringFormat(StringCase.LOWER,"String_Node_Str",locale.locale);
break;
}
case FORMAT_FILL_FROM_LEFT:
{
fillFromRight=false;
break;
}
case FORMAT_GENERAL_NUMBER:
{
format=new JavaFormat(locale.locale);
break;
}
case FORMAT_GENERAL_DATE:
{
format=new JavaFormat(locale.locale);
break;
}
case FORMAT_INTL_CURRENCY:
{
format=new LiteralFormat(locale.currencySymbol);
break;
}
default :
throw new Error();
}
if (formatTypeOut[0] == null) {
formatTypeOut[0]=token.getFormatType();
}
if (format == null) {
ignoreToken=true;
ignored.append(matched);
}
 else {
prevIgnored=ignored.toString();
ignored.setLength(0);
}
}
 else {
format=token.makeFormat(locale);
}
break;
}
if (format == null && !ignoreToken) {
format=new LiteralFormat(formatString.substring(0,1));
newFormatString=formatString.substring(1);
}
if (format != null) {
if (numberState != NOT_IN_A_NUMBER) {
NumericFormat numericFormat=new NumericFormat(prevIgnored,locale,expFormat,digitsLeftOfPoint,zeroesLeftOfPoint,digitsRightOfPoint,zeroesRightOfPoint,digitsRightOfExp,zeroesRightOfExp,useDecimal,useThouSep,originalFormatString);
formatList.add(numericFormat);
numberState=NOT_IN_A_NUMBER;
haveSeenNumber=true;
}
formatList.add(format);
if (formatTypeOut[0] == null) {
formatTypeOut[0]=format.getFormatType();
}
}
formatString=newFormatString;
}
if (numberState != NOT_IN_A_NUMBER) {
NumericFormat numericFormat=new NumericFormat(prevIgnored,locale,expFormat,digitsLeftOfPoint,zeroesLeftOfPoint,digitsRightOfPoint,zeroesRightOfPoint,digitsRightOfExp,zeroesRightOfExp,useDecimal,useThouSep,originalFormatString);
formatList.add(numericFormat);
numberState=NOT_IN_A_NUMBER;
haveSeenNumber=true;
}
boolean twelveHourClock=false;
int decimalShift=0;
for (int i=0; i < formatList.size(); i++) {
switch (formatList.get(i).code) {
case FORMAT_UPPER_AM_SOLIDUS_PM:
case FORMAT_LOWER_AM_SOLIDUS_PM:
case FORMAT_UPPER_A_SOLIDUS_P:
case FORMAT_LOWER_A_SOLIDUS_P:
case FORMAT_AMPM:
twelveHourClock=true;
break;
case FORMAT_PERCENT:
decimalShift+=2;
break;
case FORMAT_THOUSEP:
if (haveSeenNumber && i + 1 < formatList.size()) {
final BasicFormat nextFormat=formatList.get(i + 1);
if (nextFormat.code != FORMAT_THOUSEP && nextFormat.code != FORMAT_0 && nextFormat.code != FORMAT_POUND) {
for (int j=i; j >= 0 && formatList.get(j).code == FORMAT_THOUSEP; j--) {
decimalShift-=3;
formatList.remove(j);
--i;
}
}
}
break;
default :
}
}
if (twelveHourClock) {
for (int i=0; i < formatList.size(); i++) {
if (formatList.get(i) instanceof DateFormat) {
((DateFormat)formatList.get(i)).setTwelveHourClock(true);
}
}
}
if (decimalShift != 0) {
for (int i=0; i < formatList.size(); i++) {
if (formatList.get(i) instanceof NumericFormat) {
((NumericFormat)formatList.get(i)).decimalShift=decimalShift;
}
}
}
for (int i=0; i < formatList.size(); ++i) {
if (i > 0 && formatList.get(i) instanceof LiteralFormat && formatList.get(i - 1) instanceof LiteralFormat) {
formatList.set(i - 1,new LiteralFormat(((LiteralFormat)formatList.get(i - 1)).s + ((LiteralFormat)formatList.get(i)).s));
formatList.remove(i);
--i;
}
}
BasicFormat alternateFormat;
switch (formatList.size()) {
case 0:
alternateFormat=null;
break;
case 1:
alternateFormat=formatList.get(0);
break;
default :
alternateFormat=new CompoundFormat(formatList.toArray(new BasicFormat[formatList.size()]));
break;
}
alternateFormatList.add(alternateFormat);
return formatString;
}

Fixed version (ground truth):
/** 
 * Reads formatString up to the first semi-colon, or to the end if there are no semi-colons.  Adds a format to alternateFormatList, and returns the remains of formatString.
 */
private String parseFormatString(String formatString,List<BasicFormat> alternateFormatList,FormatType[] formatTypeOut){
  final String originalFormatString=formatString;
  int numberState=NOT_IN_A_NUMBER;
  StringBuilder ignored=new StringBuilder();
  String prevIgnored=null;
  boolean haveSeenNumber=false;
  int digitsLeftOfPoint=0, digitsRightOfPoint=0, digitsRightOfExp=0, zeroesLeftOfPoint=0, zeroesRightOfPoint=0, zeroesRightOfExp=0;
  boolean useDecimal=false, useThouSep=false, fillFromRight=true;
  int expFormat=FORMAT_NULL;
  if (macroTokenMap.containsKey(formatString)) {
    MacroToken macroToken=macroTokenMap.get(formatString);
    if (macroToken.translation == null) {
      if (macroToken.name.equals("String_Node_Str")) {
        formatString=locale.currencyFormat + "String_Node_Str" + locale.currencyFormat+ "String_Node_Str";
      }
 else {
        throw new Error("String_Node_Str" + macroToken.name + "String_Node_Str");
      }
    }
 else {
      formatString=macroToken.translation;
    }
  }
  if (!formatString.endsWith("String_Node_Str")) {
    formatString=formatString + "String_Node_Str";
  }
  List<BasicFormat> formatList=new ArrayList<BasicFormat>();
  List<Integer> thousands=new ArrayList<Integer>();
  int decimalShift=0;
  loop:   while (formatString.length() > 0) {
    BasicFormat format=null;
    String newFormatString;
    final Token token=findToken(formatString,formatTypeOut[0]);
    if (token != null) {
      String matched=token.token;
      newFormatString=formatString.substring(matched.length());
      if (token.isSpecial()) {
switch (token.code) {
case FORMAT_SEMI:
          break loop;
case FORMAT_POUND:
switch (numberState) {
case NOT_IN_A_NUMBER:
          numberState=LEFT_OF_POINT;
case LEFT_OF_POINT:
        digitsLeftOfPoint++;
      break;
case RIGHT_OF_POINT:
    digitsRightOfPoint++;
  break;
case RIGHT_OF_EXP:
digitsRightOfExp++;
break;
default :
throw new Error();
}
break;
case FORMAT_0:
switch (numberState) {
case NOT_IN_A_NUMBER:
numberState=LEFT_OF_POINT;
case LEFT_OF_POINT:
zeroesLeftOfPoint++;
break;
case RIGHT_OF_POINT:
zeroesRightOfPoint++;
break;
case RIGHT_OF_EXP:
zeroesRightOfExp++;
break;
default :
throw new Error();
}
break;
case FORMAT_M:
case FORMAT_MM:
{
boolean theyMeantMinute=false;
int j=formatList.size() - 1;
while (j >= 0) {
BasicFormat prevFormat=formatList.get(j);
if (prevFormat instanceof LiteralFormat) {
j--;
}
 else if (prevFormat.code == FORMAT_H || prevFormat.code == FORMAT_HH) {
theyMeantMinute=true;
break;
}
 else {
theyMeantMinute=false;
break;
}
}
if (theyMeantMinute) {
format=new DateFormat((token.code == FORMAT_M ? FORMAT_N : FORMAT_NN),matched,locale,false);
}
 else {
format=token.makeFormat(locale);
}
break;
}
case FORMAT_DECIMAL:
{
if (numberState == LEFT_OF_POINT) {
decimalShift=fixThousands(thousands,formatString,decimalShift);
}
numberState=RIGHT_OF_POINT;
useDecimal=true;
break;
}
case FORMAT_THOUSEP:
{
if (numberState == LEFT_OF_POINT) {
useThouSep=true;
thousands.add(formatString.length());
}
 else {
format=token.makeFormat(locale);
}
break;
}
case FORMAT_TIMESEP:
{
format=new LiteralFormat(locale.timeSeparator);
break;
}
case FORMAT_DATESEP:
{
format=new LiteralFormat(locale.dateSeparator);
break;
}
case FORMAT_BACKSLASH:
{
String s;
if (formatString.length() == 1) {
s="String_Node_Str";
newFormatString="String_Node_Str";
}
 else {
s=formatString.substring(1,2);
newFormatString=formatString.substring(2);
}
format=new LiteralFormat(s);
break;
}
case FORMAT_E_MINUS_UPPER:
case FORMAT_E_PLUS_UPPER:
case FORMAT_E_MINUS_LOWER:
case FORMAT_E_PLUS_LOWER:
{
if (numberState == LEFT_OF_POINT) {
decimalShift=fixThousands(thousands,formatString,decimalShift);
}
numberState=RIGHT_OF_EXP;
expFormat=token.code;
if (zeroesLeftOfPoint == 0 && zeroesRightOfPoint == 0) {
zeroesLeftOfPoint=1;
}
break;
}
case FORMAT_QUOTE:
{
String s;
int j=formatString.indexOf("String_Node_Str",1);
if (j == -1) {
s=formatString.substring(1);
newFormatString="String_Node_Str";
}
 else {
s=formatString.substring(1,j);
newFormatString=formatString.substring(j + 1);
}
format=new LiteralFormat(s);
break;
}
case FORMAT_UPPER:
{
format=new StringFormat(StringCase.UPPER,"String_Node_Str",locale.locale);
break;
}
case FORMAT_LOWER:
{
format=new StringFormat(StringCase.LOWER,"String_Node_Str",locale.locale);
break;
}
case FORMAT_FILL_FROM_LEFT:
{
fillFromRight=false;
break;
}
case FORMAT_GENERAL_NUMBER:
{
format=new JavaFormat(locale.locale);
break;
}
case FORMAT_GENERAL_DATE:
{
format=new JavaFormat(locale.locale);
break;
}
case FORMAT_INTL_CURRENCY:
{
format=new LiteralFormat(locale.currencySymbol);
break;
}
default :
throw new Error();
}
if (formatTypeOut[0] == null) {
formatTypeOut[0]=token.getFormatType();
}
if (format == null) {
ignored.append(matched);
}
 else {
prevIgnored=ignored.toString();
ignored.setLength(0);
}
}
 else {
format=token.makeFormat(locale);
}
}
 else {
format=new LiteralFormat(formatString.substring(0,1));
newFormatString=formatString.substring(1);
}
if (format != null) {
if (numberState != NOT_IN_A_NUMBER) {
if (numberState == LEFT_OF_POINT) {
decimalShift=fixThousands(thousands,formatString,decimalShift);
}
NumericFormat numericFormat=new NumericFormat(prevIgnored,locale,expFormat,digitsLeftOfPoint,zeroesLeftOfPoint,digitsRightOfPoint,zeroesRightOfPoint,digitsRightOfExp,zeroesRightOfExp,useDecimal,useThouSep,originalFormatString);
formatList.add(numericFormat);
numberState=NOT_IN_A_NUMBER;
haveSeenNumber=true;
}
formatList.add(format);
if (formatTypeOut[0] == null) {
formatTypeOut[0]=format.getFormatType();
}
}
formatString=newFormatString;
}
if (numberState != NOT_IN_A_NUMBER) {
if (numberState == LEFT_OF_POINT) {
decimalShift=fixThousands(thousands,formatString,decimalShift);
}
NumericFormat numericFormat=new NumericFormat(prevIgnored,locale,expFormat,digitsLeftOfPoint,zeroesLeftOfPoint,digitsRightOfPoint,zeroesRightOfPoint,digitsRightOfExp,zeroesRightOfExp,useDecimal,useThouSep,originalFormatString);
formatList.add(numericFormat);
numberState=NOT_IN_A_NUMBER;
haveSeenNumber=true;
}
if (formatString.startsWith("String_Node_Str")) {
formatString=formatString.substring(1);
}
boolean twelveHourClock=false;
for (int i=0; i < formatList.size(); i++) {
switch (formatList.get(i).code) {
case FORMAT_UPPER_AM_SOLIDUS_PM:
case FORMAT_LOWER_AM_SOLIDUS_PM:
case FORMAT_UPPER_A_SOLIDUS_P:
case FORMAT_LOWER_A_SOLIDUS_P:
case FORMAT_AMPM:
twelveHourClock=true;
break;
case FORMAT_PERCENT:
decimalShift+=2;
break;
case FORMAT_THOUSEP:
if (haveSeenNumber && i + 1 < formatList.size()) {
final BasicFormat nextFormat=formatList.get(i + 1);
if (nextFormat.code != FORMAT_THOUSEP && nextFormat.code != FORMAT_0 && nextFormat.code != FORMAT_POUND) {
for (int j=i; j >= 0 && formatList.get(j).code == FORMAT_THOUSEP; j--) {
decimalShift-=3;
formatList.remove(j);
--i;
}
}
}
break;
default :
}
}
if (twelveHourClock) {
for (int i=0; i < formatList.size(); i++) {
if (formatList.get(i) instanceof DateFormat) {
((DateFormat)formatList.get(i)).setTwelveHourClock(true);
}
}
}
if (decimalShift != 0) {
for (int i=0; i < formatList.size(); i++) {
if (formatList.get(i) instanceof NumericFormat) {
((NumericFormat)formatList.get(i)).decimalShift=decimalShift;
}
}
}
for (int i=0; i < formatList.size(); ++i) {
if (i > 0 && formatList.get(i) instanceof LiteralFormat && formatList.get(i - 1) instanceof LiteralFormat) {
formatList.set(i - 1,new LiteralFormat(((LiteralFormat)formatList.get(i - 1)).s + ((LiteralFormat)formatList.get(i)).s));
formatList.remove(i);
--i;
}
}
BasicFormat alternateFormat;
switch (formatList.size()) {
case 0:
alternateFormat=null;
break;
case 1:
alternateFormat=formatList.get(0);
break;
default :
alternateFormat=new CompoundFormat(formatList.toArray(new BasicFormat[formatList.size()]));
break;
}
alternateFormatList.add(alternateFormat);
return formatString;
}