package org.jabref.logic.bst; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * The |built_in| function {\.{purify\$}} pops the top (string) literal, removes * nonalphanumeric characters except for |white_space| and |sep_char| characters * (these get converted to a |space|) and removes certain alphabetic characters * contained in the control sequences associated with a special character, and * pushes the resulting string. If the literal isn't a string, it complains and * pushes the null string. * */ public class BibtexWidth { private static final Log LOGGER = LogFactory.getLog(BibtexWidth.class); /* * Quoted from Bibtex: * * Now we initialize the system-dependent |char_width| array, for which * |space| is the only |white_space| character given a nonzero printing * width. The widths here are taken from Stanford's June~'87 $cmr10$~font * and represent hundredths of a point (rounded), but since they're used * only for relative comparisons, the units have no meaning. */ private static int[] widths; static { if (BibtexWidth.widths == null) { BibtexWidth.widths = new int[128]; for (int i = 0; i < 128; i++) { BibtexWidth.widths[i] = 0; } BibtexWidth.widths[32] = 278; BibtexWidth.widths[33] = 278; BibtexWidth.widths[34] = 500; BibtexWidth.widths[35] = 833; BibtexWidth.widths[36] = 500; BibtexWidth.widths[37] = 833; BibtexWidth.widths[38] = 778; BibtexWidth.widths[39] = 278; BibtexWidth.widths[40] = 389; BibtexWidth.widths[41] = 389; BibtexWidth.widths[42] = 500; BibtexWidth.widths[43] = 778; BibtexWidth.widths[44] = 278; BibtexWidth.widths[45] = 333; BibtexWidth.widths[46] = 278; BibtexWidth.widths[47] = 500; BibtexWidth.widths[48] = 500; BibtexWidth.widths[49] = 500; BibtexWidth.widths[50] = 500; BibtexWidth.widths[51] = 500; BibtexWidth.widths[52] = 500; BibtexWidth.widths[53] = 500; BibtexWidth.widths[54] = 500; BibtexWidth.widths[55] = 500; BibtexWidth.widths[56] = 500; BibtexWidth.widths[57] = 500; BibtexWidth.widths[58] = 278; BibtexWidth.widths[59] = 278; BibtexWidth.widths[60] = 278; BibtexWidth.widths[61] = 778; BibtexWidth.widths[62] = 472; BibtexWidth.widths[63] = 472; BibtexWidth.widths[64] = 778; BibtexWidth.widths[65] = 750; BibtexWidth.widths[66] = 708; BibtexWidth.widths[67] = 722; BibtexWidth.widths[68] = 764; BibtexWidth.widths[69] = 681; BibtexWidth.widths[70] = 653; BibtexWidth.widths[71] = 785; BibtexWidth.widths[72] = 750; BibtexWidth.widths[73] = 361; BibtexWidth.widths[74] = 514; BibtexWidth.widths[75] = 778; BibtexWidth.widths[76] = 625; BibtexWidth.widths[77] = 917; BibtexWidth.widths[78] = 750; BibtexWidth.widths[79] = 778; BibtexWidth.widths[80] = 681; BibtexWidth.widths[81] = 778; BibtexWidth.widths[82] = 736; BibtexWidth.widths[83] = 556; BibtexWidth.widths[84] = 722; BibtexWidth.widths[85] = 750; BibtexWidth.widths[86] = 750; BibtexWidth.widths[87] = 1028; BibtexWidth.widths[88] = 750; BibtexWidth.widths[89] = 750; BibtexWidth.widths[90] = 611; BibtexWidth.widths[91] = 278; BibtexWidth.widths[92] = 500; BibtexWidth.widths[93] = 278; BibtexWidth.widths[94] = 500; BibtexWidth.widths[95] = 278; BibtexWidth.widths[96] = 278; BibtexWidth.widths[97] = 500; BibtexWidth.widths[98] = 556; BibtexWidth.widths[99] = 444; BibtexWidth.widths[100] = 556; BibtexWidth.widths[101] = 444; BibtexWidth.widths[102] = 306; BibtexWidth.widths[103] = 500; BibtexWidth.widths[104] = 556; BibtexWidth.widths[105] = 278; BibtexWidth.widths[106] = 306; BibtexWidth.widths[107] = 528; BibtexWidth.widths[108] = 278; BibtexWidth.widths[109] = 833; BibtexWidth.widths[110] = 556; BibtexWidth.widths[111] = 500; BibtexWidth.widths[112] = 556; BibtexWidth.widths[113] = 528; BibtexWidth.widths[114] = 392; BibtexWidth.widths[115] = 394; BibtexWidth.widths[116] = 389; BibtexWidth.widths[117] = 556; BibtexWidth.widths[118] = 528; BibtexWidth.widths[119] = 722; BibtexWidth.widths[120] = 528; BibtexWidth.widths[121] = 528; BibtexWidth.widths[122] = 444; BibtexWidth.widths[123] = 500; BibtexWidth.widths[124] = 1000; BibtexWidth.widths[125] = 500; BibtexWidth.widths[126] = 500; } } private BibtexWidth() { } private static int getSpecialCharWidth(char[] c, int pos) { if ((pos + 1) < c.length) { if ((c[pos] == 'o') && (c[pos + 1] == 'e')) { return 778; } if ((c[pos] == 'O') && (c[pos + 1] == 'E')) { return 1014; } if ((c[pos] == 'a') && (c[pos + 1] == 'e')) { return 722; } if ((c[pos] == 'A') && (c[pos + 1] == 'E')) { return 903; } if ((c[pos] == 's') && (c[pos + 1] == 's')) { return 500; } } return BibtexWidth.getCharWidth(c[pos]); } public static int getCharWidth(char c) { if ((c >= 0) && (c < 128)) { return BibtexWidth.widths[c]; } else { return 0; } } /** * * @param toMeasure * @param warn * may-be-null * @return */ public static int width(String toMeasure) { /* * From Bibtex: We use the natural width for all but special characters, * and we complain if the string isn't brace-balanced. */ int i = 0; int n = toMeasure.length(); int braceLevel = 0; char[] c = toMeasure.toCharArray(); int result = 0; /* * From Bibtex: * * We use the natural widths of all characters except that some * characters have no width: braces, control sequences (except for the * usual 13 accented and foreign characters, whose widths are given in * the next module), and |white_space| following control sequences (even * a null control sequence). * */ while (i < n) { if (c[i] == '{') { braceLevel++; if ((braceLevel == 1) && ((i + 1) < n) && (c[i + 1] == '\\')) { i++; // skip brace while ((i < n) && (braceLevel > 0)) { i++; // skip backslash int afterBackslash = i; while ((i < n) && Character.isLetter(c[i])) { i++; } if ((i < n) && (i == afterBackslash)) { i++; // Skip non-alpha control seq } else { if (BibtexCaseChanger.findSpecialChar(c, afterBackslash).isPresent()) { result += BibtexWidth.getSpecialCharWidth(c, afterBackslash); } } while ((i < n) && Character.isWhitespace(c[i])) { i++; } while ((i < n) && (braceLevel > 0) && (c[i] != '\\')) { if (c[i] == '}') { braceLevel--; } else if (c[i] == '{') { braceLevel++; } else { result += BibtexWidth.getCharWidth(c[i]); } i++; } } continue; } } else if (c[i] == '}') { if (braceLevel > 0) { braceLevel--; } else { LOGGER.warn("Too many closing braces in string: " + toMeasure); } } result += BibtexWidth.getCharWidth(c[i]); i++; } if (braceLevel > 0) { LOGGER.warn("No enough closing braces in string: " + toMeasure); } return result; } }