package net.sf.jabref.bst;
public class BibtexCaseChanger {
String s;
char format;
boolean prevColon = true;
int n;
Warn warn;
BibtexCaseChanger(String s, char format, Warn warn) {
this.s = s;
this.format = format;
this.n = s.length();
this.warn = warn;
}
public static String changeCase(String s, char format, Warn warn) {
return (new BibtexCaseChanger(s, format, warn)).changeCase();
}
private String changeCase() {
char[] c = s.toCharArray();
StringBuffer sb = new StringBuffer();
int i = 0;
while (i < n) {
if (c[i] == '{') {
braceLevel++;
if (braceLevel != 1 || i + 4 > n || c[i + 1] != '\\') {
prevColon = false;
sb.append(c[i]);
i++;
continue;
}
if (format == 't' && (i == 0 || (prevColon && Character.isWhitespace(c[i - 1])))) {
sb.append(c[i]);
i++;
prevColon = false;
continue;
}
i = convertSpecialChar(sb, c, i, format);
continue;
}
if (c[i] == '}') {
sb.append(c[i]);
i++;
braceLevel = decrBraceLevel(s, braceLevel);
prevColon = false;
continue;
}
if (braceLevel == 0) {
i = convertChar0(c, i, sb, format);
continue;
}
sb.append(c[i]);
i++;
}
checkBrace(s, braceLevel);
return sb.toString();
}
int braceLevel = 0;
int decrBraceLevel(String string, int braceLevel) {
if (braceLevel == 0) {
complain(string);
} else {
braceLevel--;
}
return braceLevel;
}
static void complain(String s) {
System.out.println("Warning -- String is not brace-balanced: " + s);
}
static void checkBrace(String s, int braceLevel) {
if (braceLevel > 0) {
complain(s);
}
}
/**
* We're dealing with a special character (usually either an undotted `\i'
* or `\j', or an accent like one in Table~3.1 of the \LaTeX\ manual, or a
* foreign character like one in Table~3.2) if the first character after the
* |left_brace| is a |backslash|; the special character ends with the
* matching |right_brace|. How we handle what's in between depends on the
* special character. In general, this code will do reasonably well if there
* is other stuff, too, between braces, but it doesn't try to do anything
* special with |colon|s.
*
* @param c
* @param i
* @param format
* @return
*/
public int convertSpecialChar(StringBuffer sb, char[] c, int i, char format) {
sb.append(c[i]); i++; // skip over open brace
while (i < c.length && braceLevel > 0) {
sb.append(c[i]); i++;
// skip over the |backslash|
String s = findSpecialChar(c, i);
if (s != null) {
i = convertAccented(c, i, s, sb, format);
}
while (i < c.length && braceLevel > 0 && c[i] != '\\') {
if (c[i] == '}')
braceLevel--;
else if (c[i] == '{') {
braceLevel++;
}
i = convertNonControl(c, i, sb, format);
}
}
return i;
}
/**
* Convert the given string according to the format character (title, lower,
* up) and append the result to the stringBuffer, return the updated
* position.
*
* @param c
* @param pos
* @param s
* @param sb
* @param format
* @return
*/
int convertAccented(char[] c, int pos, String s, StringBuffer sb, char format) {
pos += s.length();
switch (format) {
case TITLE_LOWERS:
case ALL_LOWERS:
if ("L O OE AE AA".indexOf(s) != -1)
sb.append(s.toLowerCase());
else
sb.append(s);
break;
case ALL_UPPERS:
if ("l o oe ae aa".indexOf(s) != -1)
sb.append(s.toUpperCase());
else if ("i j ss".indexOf(s) != -1) {
sb.deleteCharAt(sb.length() - 1); // Kill backslash
sb.append(s.toUpperCase());
while (pos < c.length && Character.isWhitespace(c[pos])) {
pos++;
}
} else {
sb.append(s);
}
break;
}
return pos;
}
int convertNonControl(char[] c, int pos, StringBuffer sb, char format) {
switch (format) {
case TITLE_LOWERS:
case ALL_LOWERS:
sb.append(Character.toLowerCase(c[pos]));
pos++;
break;
case ALL_UPPERS:
sb.append(Character.toUpperCase(c[pos]));
pos++;
break;
}
return pos;
}
public final static char TITLE_LOWERS = 't';
public final static char ALL_LOWERS = 'l';
public final static char ALL_UPPERS = 'u';
int convertChar0(char[] c, int i, StringBuffer sb, char format) {
switch (format) {
case TITLE_LOWERS:
if (i == 0) {
sb.append(c[i]);
} else if (prevColon && Character.isWhitespace(c[i - 1])) {
sb.append(c[i]);
} else {
sb.append(Character.toLowerCase(c[i]));
}
if (c[i] == ':')
prevColon = true;
else if (!Character.isWhitespace(c[i]))
prevColon = false;
break;
case ALL_LOWERS:
sb.append(Character.toLowerCase(c[i]));
break;
case ALL_UPPERS:
sb.append(Character.toUpperCase(c[i]));
}
i++;
return i;
}
static String findSpecialChar(char[] c, int pos) {
if (pos + 1 < c.length) {
if (c[pos] == 'o' && c[pos + 1] == 'e')
return "oe";
if (c[pos] == 'O' && c[pos + 1] == 'E')
return "OE";
if (c[pos] == 'a' && c[pos + 1] == 'e')
return "ae";
if (c[pos] == 'A' && c[pos + 1] == 'E')
return "AE";
if (c[pos] == 's' && c[pos + 1] == 's')
return "ss";
if (c[pos] == 'A' && c[pos + 1] == 'A')
return "AA";
if (c[pos] == 'a' && c[pos + 1] == 'a')
return "aa";
}
if (c[pos] == 'i')
return String.valueOf(c[pos]);
if (c[pos] == 'j')
return String.valueOf(c[pos]);
if (c[pos] == 'o')
return String.valueOf(c[pos]);
if (c[pos] == 'O')
return String.valueOf(c[pos]);
if (c[pos] == 'l')
return String.valueOf(c[pos]);
if (c[pos] == 'L')
return String.valueOf(c[pos]);
return null;
}
}