/* TokODDListResourceBundle */ package com.company.g11n.ExtSamp.tokenizer; import com.g11ntoolkit.levblock.TokContext; import com.g11ntoolkit.levblock.XLEntry; import com.g11ntoolkit.strfile.EmptyStrFile; import com.g11ntoolkit.strfile.StrFile; import com.g11ntoolkit.token.MalformedToken; import com.g11ntoolkit.token.Token; import com.g11ntoolkit.tokenizer.FileTokenizerError; import com.g11ntoolkit.tokenizer.FileTokRunError; import com.g11ntoolkit.tokenizer.TokListResourceBundle; import com.g11ntoolkit.tokfile.TokFile; import com.g11ntoolkit.util.Arguments; import gnu.regexp.RE; import gnu.regexp.REException; import gnu.regexp.REMatch; import gnu.regexp.RESyntax; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.text.StringCharacterIterator; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; //------------------------------------------------------------ /** Tokenizes the specified input file as though it were a ListResourceBundle file with the slightly strange coding. *

It uses the super class to do most of the work. The main reason for this class is to handle the parsing to find the contents section of the file.

*

Normally, the contents of a ListResourceBundle is defined as a static variable in the class. Just to be different, the ODD folks decided to make life difficult by defining the getContents method so that it checks to see if the static variable is null and, if it is, calls a buildContents method to assign the static information to the contents variable.

*

In doing this the original static contents variable is set to null then later assigned the values. So here we need to check if the static variable is assigned a null. Then go looking for the real assignment.

* @see TokListResourceBundle * @version 2005/09/19 * @author Bill Rich, Wilandra Consulting LLC *
Copyright © 2005, Wilandra Consulting LLC. All rights reserved. *

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

*

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

*

See License Agreement.

*/ //------------------------------------------------------------ public class TokODDListResourceBundle extends TokListResourceBundle { /** The log used for all messages from this class.**/ private static Logger log = Logger.getLogger(TokODDListResourceBundle.class.getPackage().getName()); /** The locale for the target language.**/ private static Locale targetLocale = null; /** The tokenized skeleton of the input file.**/ private static TokFile tokFile = null; /** The translatable strings extracted from the input file.**/ private static StrFile strFile = null; /** The locale for the input file.**/ private static String localeString = null; //-------------------------------------------------------------- /** Allows this tool to be run from the command line. *

Sets up the environment then uses the tokenize method to extract the strings.

* @param args a String array specifying the command line parameters. The order does not matter except the arguments that are paired must be paired in order. The arguments are not case sensitive. */ public static void main(String args[]) throws FileTokRunError { /** The string file.*/ StrFile strFile = null; log.logp(Level.FINE, "TokODDListResourceBundle", "main", "Begin processing"); String inFileName = null; String strFileName = null; Arguments argHandler = new Arguments(); argHandler.setUsage( new String[] { mrb.getString("help.toklistresourcebundle") } ); // Is there anything to do? log.logp(Level.FINER, "TokODDListResourceBundle", "main", "Number of args: [" + args.length + "]"); if (args.length == 0) { argHandler.printUsage(); System.exit(1); } argHandler.parseArgumentTokens(args, new char[]{}); int c; String arg = null; outer: while ((c = argHandler.getArguments())!= -1) { switch (c) { case '?': case 'h': case '-': argHandler.printUsage(); System.exit(1); break; case -1: break outer; default: break; } } // End outer // Loop through all the other arguments. while((arg = argHandler.getlistFiles()) != null) { if (arg.toUpperCase().compareTo("/IN") == 0) { inFileName = argHandler.getlistFiles(); } else if (arg.toUpperCase().compareTo("/STR") == 0) { strFileName = argHandler.getlistFiles(); } else if (arg.toUpperCase().compareTo("/INLOC") == 0) { localeString = argHandler.getlistFiles(); } else if (arg.toUpperCase().compareTo("/CONTEXT") == 0) { theContextFileName = argHandler.getlistFiles(); } else if (arg.toUpperCase().compareTo("/PRODUCT") == 0) { setProductName(argHandler.getlistFiles()); } else if (arg.toUpperCase().compareTo("/PRODUCT-VERSION") == 0) { setProductVersion(argHandler.getlistFiles()); } else { } } log.logp(Level.FINE, "TokODDListResourceBundle", "main", "inFileName[" + inFileName + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "main", "strFileName[" + strFileName + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "main", "localeString[" + localeString + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "main", "theContextFileName[" + theContextFileName + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "main", "productName[" + getProductName() + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "main", "productVersion[" + getProductVersion() + "]"); boolean nogo = false; if (inFileName == null) { log.logrb(Level.SEVERE, "TokODDListResourceBundle", "main", "com.g11ntoolkit.resources.messages", "errormsg.infilemissing"); nogo = true; } if (strFileName == null) { log.logrb(Level.SEVERE, "TokODDListResourceBundle", "main", "com.g11ntoolkit.resources.messages", "errormsg.strfilemissing"); nogo = true; } if (nogo) { System.exit(1); } // Set the context file name if none was specified. if (theContextFileName == null) { theContextFileName = inFileName; } try { if (localeString == null) { localeString = vrb.getString("locale.default"); } targetLocale = new Locale(vrb.getString("language."+localeString), vrb.getString("country."+localeString)); } catch (Exception e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "main", e.getMessage()); e.printStackTrace(); System.exit(1); } // Now go do it. try { strFile = tokenize(inFileName, theContextFileName, targetLocale, localeString); } catch (FileTokenizerError e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "main", e.getMessage()); e.printStackTrace(); log.logrb(Level.SEVERE, "TokODDListResourceBundle", "main", "com.g11ntoolkit.resources.messages", "errormsg.runfalse"); } catch (TokODDFileError e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "main", e.getMessage()); e.printStackTrace(); log.logrb(Level.SEVERE, "TokODDListResourceBundle", "main", "com.g11ntoolkit.resources.messages", "errormsg.runfalse"); } // Finally write the STR file in XLIFF format. log.logp(Level.FINE, "TokODDListResourceBundle", "main", "writing StrFile in XLIFF format. [" + strFileName + "]"); try { strFile.writeXLIFF(new OutputStreamWriter(new FileOutputStream(strFileName), vrb.getString("encoding.intermediatefiles")), false, false); // Write a source only XLIFF file with no BOM. } catch (EmptyStrFile esf) { } catch (Exception e) { log.logrb(Level.SEVERE, "TokODDListResourceBundle", "main", "com.g11ntoolkit.resources.messages", "errormsg.xliffwrite"); log.logp(Level.SEVERE, "TokODDListResourceBundle", "main", e.getMessage()); e.printStackTrace(); } log.logp(Level.FINE, "TokODDListResourceBundle", "main", "End processing"); } //------------------------------------------------------------ /** Establishes an instance of the class with no input information. It is useful for setting up the class for the check function. */ public TokODDListResourceBundle() { super(); log.logp(Level.FINER, "TokODDListResourceBundle", "constructor", "Begin (0 args)"); } //------------------------------------------------------------ /** Tokenizes the buffer and writes the extracted string output file. *

It uses the super class setupTok method to do the common work of reading the file into a string buffer.

* @param inFileName a String specifying the input file name * @param contextFileName a String containing the name of the input file to use for the token id and context * @param targetLocale a Locale specifying the intended target locale * @return a StrFile representing the extracted strings for the input file * @throws TokODDFileError when something goes wrong */ public static StrFile tokenize(String inFileName, String contextFileName, Locale targetLocale, String localeString) throws FileTokenizerError, TokODDFileError { log.logp(Level.FINE, "TokODDListResourceBundle", "tokenize", "Begin"); log.logp(Level.FINE, "TokODDListResourceBundle", "tokenize", "localeString[" + localeString + "]"); setEncoding(vrb.getString("encoding." + localeString)); token = new Token(theContextFileName, 0); setupTok(inFileName, theContextFileName); log.logp(Level.FINER, "TokODDListResourceBundle", "tokenize", "Input file ready."); theInputFileName = inFileName; log.logp(Level.FINER, "TokODDListResourceBundle", "tokenize", "Input file[" + theInputFileName + "]"); tokFile = new TokFile(); tokFile.setType(vrb.getString("filetype.oddlrb")); strFile = new StrFile(); strFile.setLocale(new Locale(vrb.getString("language." + vrb.getString("locale.default")), vrb.getString("country." + vrb.getString("locale.default")))); strFile.setTargetLocale(targetLocale); strFile.setProductName(getProductName()); strFile.setProductVersion(getProductVersion()); strFile.setSourceFileName(inFileName); strFile.setContextFileName(contextFileName); strFile.setDatatype(xliffrb.getString("xliff.file.datatype.lrb")); strFile.setTokFile(tokFile); try { StringBuffer procBuff = getProcessingBuffer(inFileBuffer); String buf = procBuff.toString(); int bufLen = buf.length(); int crstart = buf.indexOf("public"); int crend = buf.indexOf("{", crstart); if (buf.indexOf("class", crstart) < crend) { log.logp(Level.FINER, "TokODDListResourceBundle", "tokenize", "Class record[" + buf.substring(crstart, crend) + "]"); } int idxop = contentSectionStart(buf, crend); int idxcl = 0; // Now identify the boundaries of the contents section then only work within that section. idxop is the begining of the contents section, idxcl is the end. int bracketCount = 1; int bracketIndex = idxop + 1; log.logp(Level.FINER, "TokODDListResourceBundle", "tokenize", "crend[" + crend + "] idxop[" + idxop + "] contents section begin[" + buf.substring(idxop-12, idxop) + "] contents section at bracketIndex[" + buf.substring(bracketIndex, bracketIndex) + "] contents section at idxop[" + buf.substring(idxop, idxop) + "]"); while (bracketCount > 0) { log.logp(Level.FINEST, "TokODDListResourceBundle", "tokenize", "bracketCount[" + bracketCount + "] bracketIndex[" + bracketIndex + "]"); if (buf.charAt(bracketIndex) == '{') { bracketCount++; if (bracketCount > 5) { log.logp(Level.INFO, "TokODDListResourceBundle", "tokenize", "Extra open bracket at[" + bracketIndex + "] [" + buf.substring(bracketIndex, bracketIndex + 40) + "]"); } } else if (buf.charAt(bracketIndex) == '}') { bracketCount--; } bracketIndex++; } idxcl = bracketIndex - 1; log.logp(Level.FINEST, "TokODDListResourceBundle", "tokenize", "crend[" + crend + "] idxop[" + idxop + "] idxcl[" + idxcl + "] bracketCount[" + bracketCount + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokenize", "tokStrings(buf.substring[" + buf.substring(0, idxop + 1) + "]"); tokStrings(buf.substring(0, idxop + 1), tokFile, strFile); tokContents(buf.substring(idxop, idxcl + 1), tokFile, strFile); tokStrings(buf.substring(idxcl + 1), tokFile, strFile); } catch (Exception e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokenize", e.getMessage()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.tokenize3")); } return strFile; } //------------------------------------------------------------ /** Finds only the pertinent information in the input file buffer and puts it into a separate buffer. *

This gets rid of all the comments in the file and only keeps the code. The file should be a syntactically correct file when finished.

* @param aFileBuffer a StringBuffer object specifying the string buffer in which to find the processing buffer * @return a StringBuffer object representing the processing buffer */ protected static StringBuffer getProcessingBuffer(StringBuffer aFileBuffer) { log.logp(Level.FINE, "TokODDListResourceBundle", "getProcessingBuffer", "Begin."); StringBuffer processingBuffer = new StringBuffer(aFileBuffer.length()); boolean inLineComment = false; boolean inBlockComment = false; boolean inQuotedString = false; StringBuffer quotedString = new StringBuffer(); char lineCommentStart1 = '/'; char lineCommentStart2 = '/'; char lineCommentEnd = '\n'; char blockCommentStart1 = '/'; char blockCommentStart2 = '*'; char blockCommentEnd1 = '*'; char blockCommentEnd2 = '/'; char quoteDelim = '"'; StringCharacterIterator ci = new StringCharacterIterator(aFileBuffer.toString()); char c = ci.first(); scan: for (char nc = ci.next(); nc != StringCharacterIterator.DONE; nc = ci.next()) { if (inQuotedString) { // Accumulate the characters in the quoted string and process it when the end is reached. if (c == '\\') { quotedString.append(c); quotedString.append(nc); nc = ci.next(); } else { quotedString.append(c); // Add character to quoted string. if (c == quoteDelim) { // This is the end of the quoted string. inQuotedString = false; processingBuffer.append(quotedString.toString()); // Add quoted string to processing buffer. } } c = nc; continue scan; } // end quoted string if (inLineComment) { // Ignore comments, but, check to see when we get to the end. if (c == lineCommentEnd) { // End of line comment. inLineComment = false; processingBuffer.append(c); } else { // Still in the line comment. } c = nc; continue scan; } // end line comment if (inBlockComment) { // Ignore comments, but, check to see when we get to the end. if (c == blockCommentEnd1 && nc == blockCommentEnd2) { // At end of block comment. Stop throwing stuff away. inBlockComment = false; nc = ci.next(); } else { // Still in the block comment. } c = nc; continue scan; } // end block comment // We are not in any of the special blocks. switch (c) { case '/': if (nc == '/') { inLineComment = true; } else if (nc == '*') { inBlockComment = true; } else { processingBuffer.append(c); processingBuffer.append(nc); } nc = ci.next(); break; case '"': quotedString = new StringBuffer(); quotedString.append(c); inQuotedString = true; quoteDelim = '"'; break; case '\'': quotedString = new StringBuffer(); quotedString.append(c); inQuotedString = true; quoteDelim = '\''; break; case '\\': processingBuffer.append(c); processingBuffer.append(nc); nc = ci.next(); break; default: processingBuffer.append(c); } c = nc; } // end scan processingBuffer.append(c); log.logp(Level.FINE, "TokODDListResourceBundle", "getProcessingBuffer", "processingBuffer: [" + processingBuffer + "]"); return processingBuffer; } //------------------------------------------------------------ /** Locates the contents section of a ListResourceBundle and returns its starting offset in the specified string. *

In order to find the contents section of the LRB we need to know what it might be called. To find this we look for the method that is called to return the contents. The object that it returns is the name of the contents section.

* @param buf a String specifying the processing buffer that contains the content section * @param start an int specifying the starting offset where to begin looking for the content section * @return an int representing the offset to the content section or -1 if no content section is found * @throws TokODDFileError when something goes wrong */ protected static int contentSectionStart(String buf, int start) throws TokODDFileError { log.logp(Level.FINE, "TokODDListResourceBundle", "contentSectionStart", "Begin"); RE exp1 = null; RE exp2 = null; RE exp2a = null; RE exp2b = null; RE exp2c = null; RE exp2d = null; RE exp2e = null; REMatch m1 = null; REMatch m2 = null; RE connull = null; int idxop = 0; int idxcl = 0; String type = ""; RESyntax res = new RESyntax(RESyntax.RE_SYNTAX_AWK); res = res.set(RESyntax.RE_CHAR_CLASSES); // Look for the getContents method to find out what the name of the contents will be. Must honor case for this search. try { exp1 = new RE("[[:space:]]+getContents()", 0, res); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "contentSectionStart", e.getMessage()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } m1 = exp1.getMatch(buf, start); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "Look for getContents results in m1[" + m1 + "]"); if (m1 == null) { throw new TokODDFileError(mrb.getString("errormsg.contentsmethodnotfound")); } else { int xx = m1.getEndIndex(); try { // Look for return object; exp1 = new RE("return[[:space:]]+([^;[:space:]]*)([;[:space:]])", 0, res); // Look for return (object); exp2 = new RE("return[[:space:]]*\\([[:space:]]*([^\\)[:space:]]*)[:space:]]*\\)", 0, res); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "contentSectionStart", e.getMessage()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } m2 = exp2.getMatch(buf, xx); // Look for return (object); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "Look for return (object); results in m2[" + m2 + "]"); m1 = exp1.getMatch(buf, xx); // Look for return object; log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "Look for return object; results in m1[" + m1 + "]"); if (m2 == null && m1 == null) { throw new TokODDFileError(mrb.getString("errormsg.returncontentsnotfound")); } else { if (m2 == null) { type = buf.substring(m1.getStartIndex(1),m1.getEndIndex(1)); } else { type = buf.substring(m2.getStartIndex(1),m2.getEndIndex(1)); } } // Limit this to only the name of the contents section. Some people have a habit of coding it as this.contents. if (type.lastIndexOf(".") >= 0) { type = type.substring(type.lastIndexOf(".") + 1); } log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "type[" + type + "]"); } // At this point we know what to look for to find the contents section of the LRB. if (type.toUpperCase().compareTo("NEW") == 0) { // Special case for some contents sections. idxop = buf.indexOf("{", m1.getEndIndex()); } else { // Now look for the contents section using the information from the previous search. For this one we do not need to honor case. If the return value is not found as the label of the contents section, default to "contents" and try again. If still not found, Houston we have a problem. try { // Look for static final [] ...type...=... exp2 = new RE("static[[:space:]]+final.*\\[\\].*" + type + ".*=", RE.REG_ICASE, res); // Look for static ...[]...type...=... exp2a = new RE("static[[:space:]]+.*\\[\\].*" + type + ".*=", RE.REG_ICASE, res); // Look for static final...type...[]...= exp2b = new RE("static[[:space:]]+final.*" + type + ".*\\[\\].*=", RE.REG_ICASE, res); // Look for static ...type...[]...=... exp2c = new RE("static[[:space:]]+.*" + type + ".*\\[\\].*=", RE.REG_ICASE, res); // Look for ...type []...=... exp2d = new RE(".*" + type + "[[:space:]]*\\[\\].*=", RE.REG_ICASE, res); // Look for ...[] type =... exp2e = new RE(".*\\[\\][[:space:]]*" + type + "[[:space:]]*=", RE.REG_ICASE, res); } catch (REException e) { // There was something wrong with the type that caused a bad expression to be built. We will now try to use just plain old contents for the search. type = "contents"; try { // Look for static final [] ...type...=... exp2 = new RE("static[[:space:]]+final.*\\[\\].*" + type + ".*=", RE.REG_ICASE, res); // Look for static ...[]...type...=... exp2a = new RE("static[[:space:]]+.*\\[\\].*" + type + ".*=", RE.REG_ICASE, res); // Look for static final...type...[]...= exp2b = new RE("static[[:space:]]+final.*" + type + ".*\\[\\].*=", RE.REG_ICASE, res); // Look for static ...type...[]...=... exp2c = new RE("static[[:space:]]+.*" + type + ".*\\[\\].*=", RE.REG_ICASE, res); // Look for ...type []...=... exp2d = new RE(".*" + type + "[[:space:]]*\\[\\].*=", RE.REG_ICASE, res); // Look for ...[] type =... exp2e = new RE(".*\\[\\][[:space:]]*" + type + "[[:space:]]*=", RE.REG_ICASE, res); } catch (REException e2) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "contentSectionStart", e.getMessage()); e2.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } } m2 = exp2.getMatch(buf, start); REMatch m2a = exp2a.getMatch(buf, start); REMatch m2b = exp2b.getMatch(buf, start); REMatch m2c = exp2c.getMatch(buf, start); REMatch m2d = exp2d.getMatch(buf, start); REMatch m2e = exp2e.getMatch(buf, start); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "type[" + type + "] m2[" + m2 + "] m2a[" + m2a + "] m2b[" + m2b + "] m2c[" + m2c + "] m2d[" + m2d + "] m2e[" + m2e + "]"); if (m2 == null && m2a == null && m2b == null && m2c == null && m2d == null && m2e == null) { type = "contents"; m2 = exp2.getMatch(buf, start); m2a = exp2a.getMatch(buf, start); m2b = exp2b.getMatch(buf, start); m2c = exp2c.getMatch(buf, start); m2d = exp2d.getMatch(buf, start); m2e = exp2e.getMatch(buf, start); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "type[" + type + "] m2[" + m2 + "] m2a[" + m2a + "] m2b[" + m2b + "] m2c[" + m2c + "] m2d[" + m2d + "] m2e[" + m2e + "]"); if (m2 == null && m2a == null && m2b == null && m2c == null && m2d == null && m2e == null) { throw new TokODDFileError(mrb.getString("errormsg.contentsnotfound")); } } if (m2 != null) { idxop = m2.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2 adjusted idxop[" + idxop + "] m2 end[" + m2.getEndIndex() + "]"); } else if (m2a != null) { idxop = m2a.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2a adjusted idxop[" + idxop + "] m2a end[" + m2a.getEndIndex() + "]"); } else if (m2b != null) { idxop = m2b.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2b adjusted idxop[" + idxop + "] m2b end[" + m2b.getEndIndex() + "]"); } else if (m2c != null) { idxop = m2c.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2c adjusted idxop[" + idxop + "] m2c end[" + m2c.getEndIndex() + "]"); } else if (m2d != null) { idxop = m2d.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2d adjusted idxop[" + idxop + "] m2d end[" + m2d.getEndIndex() + "]"); } else { idxop = m2e.getEndIndex(); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "m2e adjusted idxop[" + idxop + "] m2e end[" + m2e.getEndIndex() + "]"); } } log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "idxop[" + idxop + "]"); int nsc = buf.indexOf(";", idxop); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "nsc[" + nsc + "][" + buf.substring(idxop, nsc).trim() + "]"); if (buf.substring(idxop, nsc).trim().compareTo("null") == 0) { try { // Look for type = new ... connull = new RE(type + "[[:space:]]+=[[:space:]]+new.*[[:space:]]+{", RE.REG_ICASE, res); REMatch cn = connull.getMatch(buf, start); log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "cn[" + cn + "]"); if (cn != null) { idxop = cn.getEndIndex(); } else { idxop = -1; } log.logp(Level.FINEST, "TokODDListResourceBundle", "contentSectionStart", "idxop[" + idxop + "]"); } catch (REException e2) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "contentSectionStart", e2.getMessage()); e2.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } } log.logp(Level.FINE, "TokODDListResourceBundle", "contentSectionStart", "final idxop[" + idxop + "]"); return idxop; } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that may contain strings. *

The section of the file processed may not be the contents section. The section of the file is appended to the TokFile with an appropriate token inserted for each string found. The strings are appended to the StrFile with their tokens. No attempt is made to find elements of an array. The entire array of strings is treated as a single string.

*

If the entire string is numeric it is ignored and left intact in the file.

*

If the string is found in a System.out.println statement and it is a quoted string, an error is reported but the string is not replaced with a token nor is it written to the StrFile. At some later time we may decide to tokenize these strings.

* @param fileSection a String specifying the part of the buffer to use * @param tokFile a TokFile object to use for the tokenized file * @param strFile a StrFile object to use for the extracted string file * @throws TokODDFileError when something goes wrong */ protected static void tokStrings(String fileSection, TokFile tokFile, StrFile strFile) throws TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokStrings", "Begin"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokStrings", "fileSection: [" + fileSection + "]"); RE s = null; // Search for string declarations RE sop = null; // System.out.println int nextStart = 0; try { RESyntax res = new RESyntax(RESyntax.RE_SYNTAX_AWK); res = res.set(RESyntax.RE_CHAR_CLASSES); res = res.set(RESyntax.RE_DOT_NEWLINE); s = new RE("([[:space:]]String[[:space:]][^;=]+=)([^;]+)(;)", 0, res); // System.out.println(...); // If there are any double quotes in the string then report it, otherwise, ignore it. // Do not remove concats. // There is no real key, sub(1) contains the value. RESyntax resop = new RESyntax(RESyntax.RE_SYNTAX_AWK); resop = resop.set(RESyntax.RE_CHAR_CLASSES); sop = new RE("System.out.println[[:space:]]*\\([[:space:]]*(.*)[[:space:]]*\\)[[:space:]]*;", 0, resop); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokStrings", e.toString()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } REMatch ms = s.getMatch(fileSection); log.logp(Level.FINER, "TokODDListResourceBundle", "tokStrings", "ms[" + ms + "]"); while (ms != null) { nextStart = ms.getEndIndex(); boolean ignoreString = false; tokContext = new TokContext(theContextFileName, ms.toString(1), null, null); try { Integer test = new Integer(ms.toString(2).replace('"', ' ').trim()); ignoreString = false; } catch (Exception e) { ignoreString = true; } if (!ignoreString) { try { XLEntry ts = new XLEntry(targetLocale, ms.toString(2).trim()); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); fileSection = fileSection.substring(0, ms.getStartIndex()) + ms.toString(1) + " " + token.getDecoratedToken() + ms.toString(3) + fileSection.substring(ms.getEndIndex()); } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokStrings", mt.toString()); mt.printStackTrace(); } } ms = s.getMatch(fileSection, nextStart); } REMatch msop = sop.getMatch(fileSection); while (msop != null) { // Begin Pattern sop nextStart = msop.getEndIndex(); fileSection = tokSOP(fileSection, msop); msop = sop.getMatch(fileSection, nextStart); } // End Pattern sop tokFile.append(fileSection); } //------------------------------------------------------------ /** Parses the contents section of a ListResourceBundle and extracts the translatable values. *

This looks for quoted strings in the specified string. When it finds a quoted string it replaces it with a token and adds the token and extracted string to the specified StrFile. It adds the tokenized string to the specified TokFile.

* @param contentStr a String specifying the content section of the buffer * @param tokFile a TokFile object to use for the tokenized file * @param strFile a StrFile object to use for the extracted string file * @throws TokODDFileError when something goes wrong */ protected static void tokContents(String contentStr, TokFile tokFile, StrFile strFile) throws TokODDFileError { log.logp(Level.FINE, "TokODDListResourceBundle", "tokContents", "tokContents: [" + contentStr + "]"); try { // At this point we have found the contents section of the LRB. Now it is a matter of finding each value string within this section and replacing it with a token. We only want the value strings since they are all that is translatable. We should also take font and color specs since they can change based on locale, but no integers or other such objects. int cnt = 0; int startidx = 0; String keyvalue[] = new String[5]; int i; for(i = 1; i < contentStr.length(); i++) { if (cnt < 0) { tokFile.append(contentStr.charAt(i)); } else if (contentStr.charAt(i) == '{') { if (cnt == 0) { startidx = i; } else if (cnt < 0) { tokFile.append(contentStr.charAt(i)); } cnt += 1; } else if (contentStr.charAt(i) == '}') { cnt -= 1; if (cnt == 0) { log.logp(Level.FINER, "TokODDListResourceBundle", "tokContents", "} found: at [" + i + "] cnt [" + cnt + "] string is [" + contentStr.substring(startidx, i+1) + "]"); tokKeyValue(contentStr.substring(startidx, i+1), tokFile, strFile); } if (cnt < 0) { log.logp(Level.FINER, "TokODDListResourceBundle", "tokContents", "} found: at [" + i + "] cnt [" + cnt + "] char is [" + contentStr.charAt(i) + "]"); tokFile.append(contentStr.charAt(i)); } } else if (cnt <= 0) { tokFile.append(contentStr.charAt(i)); } } } catch (Exception e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokContents", e.toString()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.tokenize3")); } log.logp(Level.FINE, "TokODDListResourceBundle", "tokContents", "Done"); return; } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that has the pattern of a System.out.println. *

The section of the file is updated with the appropriate token inserted and returned.

* @param keyvalStr a String specifying the key/value string * @param m a REMatch object specifying the regular expression match * @return a String representing the tokenized key/value string * @throws TokODDFileError when something goes wrong */ protected static String tokSOP(String keyvalStr, REMatch m) throws TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokSOP", "found sop pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokSOP", "key: [" + "NoKey" + "] value: [" + m.toString(1) + "]"); tokContext = new TokContext(theContextFileName, "NoKey", null, null); int valstart = m.getStartIndex(1); int valend = m.getEndIndex(1); String val = keyvalStr.substring(valstart, valend); if (val.indexOf("\"") >= 0) { // String has some part of it as a quoted string so Tok it. Otherwise, ignore it. // Do not remove the concats since these may be variables so may be needed in the final version of the string. // Since this is truly an I18N bug we decided to only report that it is there and not Tok it. Object[] c = { m.toString() }; log.logrb(Level.INFO, "TokODDListResourceBundle", "tokSOP", "com.g11ntoolkit.resources.messages", "errormsg.soppattern", c); } return keyvalStr; } //------------------------------------------------------------ /** Parses a key/value string to find the value strings that need to be extracted. *

This looks for quoted value strings in the specified key/value string. When it finds a quoted value string it replaces it with a token and adds the token and the extracted string to the specified StrFile and adds the tokenized record to the TokFile file.

* @param keyvalStr a String specifying the key/value string * @param tokFile a TokFile object to use for the tokenized file * @param strFile a StrFile object to use for the extracted string file * @throws TokODDFileError when something goes wrong */ protected static void tokKeyValue(String keyvalStr, TokFile tokFile, StrFile strFile) throws FileTokenizerError, TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "Begin. keyvalStr[" + keyvalStr + "]"); RE kv = null; // key, value RE qkv = null; // quoted key, value RE kmv = null; // key, multi value RE qkmv = null; // quoted key, multi value RE qkqv = null; // quoted key, quoted value RE kqv = null; // key, quoted value RE niniqv = null; // new integer, new integer, quoted value RE niniqv2 = null; // new integer, new integer, quoted value, quoted value RE ksa = null; // key, string array RE qksa = null; // quoted key, string array RE sop = null; // System.out.println try { RESyntax res = new RESyntax(RESyntax.RE_SYNTAX_AWK); res = res.set(RESyntax.RE_CHAR_CLASSES); res = res.set(RESyntax.RE_DOT_NEWLINE); // The following patterns represent all of the important parts of the LRB. These will find all of the quoted strings that represent values. These are the only things we are interested in for L10N. // { key, multi value } // sub(1) is the key, sub(2) is the value list kmv = new RE("{[[:space:]]*([^,]*),[[:space:]]*({.*[[:space:]]*})[[:space:]]*}", 0, res); // { "key", multi value } // sub(1) is the key, sub(2) is the value list qkmv = new RE("{[[:space:]]*(\"[^\"]*\"),[[:space:]]*(.*{.*[[:space:]]*})[[:space:]]*}", 0, res); // { key, value } // sub(1) is the key, sub(2) is the value kv = new RE("{[[:space:]]*([^,]*),[[:space:]]*(.*)[[:space:]]*}", 0, res); // { "key", value } // sub(1) is the key, sub(2) is the value qkv = new RE("{[[:space:]]*(\"[^\"]*\"),[[:space:]]*(.*)[[:space:]]*}", 0, res); // { "key", "value" } // sub(1) is the key, sub(2) is the value qkqv = new RE("{[[:space:]]*(\"[^\"]*\"),[[:space:]]*(\".*\")[[:space:]]*}", 0, res); // { key, "value" } // sub(1) is the key, sub(2) is the value kqv = new RE("{[[:space:]]*([^,]*),[[:space:]]*(\".*\")[[:space:]]*}", 0, res); // { key, new String[]{...} } // sub(1) is the key, sub(2) is the string array ksa = new RE("{[[:space:]]*([^,]*),[[:space:]]*(new[[:space:]]*String\\[\\][[:space:]]*{.*})[[:space:]]*}", 0, res); // { "key", new String[]{...} } // sub(1) is the key, sub(2) is the string array qksa = new RE("{[[:space:]]*(\"[^\"]*\"),[[:space:]]*(new[[:space:]]*String\\[\\][[:space:]]*{.*})[[:space:]]*}", 0, res); // { new Integer(...), new Integer(...), "value1", "value2" } // sub(1) is the key (new Integer(...), new Integer(...)), sub(2) is the value 1, sub(3) is value 2 // Must evaluate this one before niniqv since niniqv will also find this pattern. This will not find the niniqv pattern. niniqv2 = new RE("{[[:space:]]*(new[[:space:]]+Integer[^,]*,[[:space:]]*new[[:space:]]+Integer[^,]*),[[:space:]]*(\"[^\"]*\"),[[:space:]]*(\"[^\"]*\")[[:space:]]*}", 0, res); // { new Integer(...), new Integer(...), "value" } OR { new Integer(...), new Integer(...), "value1", "value2" } // sub(1) is the key (new Integer(...), new Integer(...)), sub(2) is the value // Must evaluate niniqv2 before this one since this one will find the niniqv2 pattern too. niniqv = new RE("{[[:space:]]*(new[[:space:]]+Integer[^,]*,[[:space:]]*new[[:space:]]+Integer[^,]*),[[:space:]]*(\"[^\"]*\")[[:space:]]*}", 0, res); // System.out.println(...); // If there are any double quotes in the string then report it, otherwise, ignore it. // Do not remove concats. // There is no real key, sub(1) contains the value. sop = new RE("System.out.println[[:space:]]*\\([[:space:]]*(.*)[[:space:]]*\\)[[:space:]]*;", 0, res); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKeyValue", e.toString()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } REMatch mqkqv = qkqv.getMatch(keyvalStr); REMatch mkqv = kqv.getMatch(keyvalStr); REMatch mniniqv2 = niniqv2.getMatch(keyvalStr); REMatch mniniqv = niniqv.getMatch(keyvalStr); REMatch mksa = ksa.getMatch(keyvalStr); REMatch mqksa = qksa.getMatch(keyvalStr); REMatch mkmv = kmv.getMatch(keyvalStr); REMatch mqkmv = qkmv.getMatch(keyvalStr); REMatch mkv = kv.getMatch(keyvalStr); REMatch mqkv = qkv.getMatch(keyvalStr); REMatch msop = sop.getMatch(keyvalStr); int end = 0; while (!(mqkqv == null && mkqv == null && mniniqv == null && mniniqv2 == null && mksa == null && mqksa == null && mqkv == null && mkv == null && mqkmv == null && mkmv == null && msop == null)) { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "Pattern match begin (shown in order processed):"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "msop[" + msop + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqksa[" + mqksa + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mksa[" + mksa + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mniniqv2[" + mniniqv2 + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mniniqv[" + mniniqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkmv[" + mqkmv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkmv[" + mkmv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkqv[" + mqkqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkqv[" + mkqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkv[" + mqkv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkv[" + mkv + "]"); log.logp(Level.FINE, "TokODDListResourceBundle", "tokKeyValue", "Pattern match end"); int nextStart = 0; try { if (!(msop == null)) { // Begin Pattern sop nextStart = msop.getEndIndex(); keyvalStr = tokSOP(keyvalStr, msop); } // End Pattern sop if (!(mqksa == null)) { // Begin Pattern qksa nextStart = mqksa.getEndIndex(); keyvalStr = tokKSA(keyvalStr, mqksa); } // End Pattern qksa else if (!(mksa == null)) { // Begin Pattern ksa nextStart = mksa.getEndIndex(); keyvalStr = tokKSA(keyvalStr, mksa); } // End Pattern ksa else if (!(mniniqv2 == null)) { // Begin Pattern niniqv2 // Must check this before niniqv since niniqv will also find this pattern. This will not find the niniqv pattern. log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "found niniqv2 pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "key: [" + mniniqv2.toString(1).trim() + "] value: [" + mniniqv2.toString(2) + "]"); tokContext = new TokContext(theContextFileName, mniniqv2.toString(1).trim(), null, null); nextStart = mniniqv2.getEndIndex(); String val = new String(); REMatch mconcats = null; XLEntry ts = null; // Begin processing for sub(3). Do this first so the offsets in keyvalStr do not change as a result of substituting the tag for the value string. val = mniniqv2.toString(3); while (val.indexOf("@@r@@") >= 0) { val = val.substring(0, val.indexOf("@@r@@")) + " " + val.substring(val.indexOf("@@r@@") + 5); } while (val.indexOf("@@n@@") >= 0) { val = val.substring(0, val.indexOf("@@n@@")) + " " + val.substring(val.indexOf("@@n@@") + 5); } while (val.indexOf("@@f@@") >= 0) { val = val.substring(0, val.indexOf("@@f@@")) + " " + val.substring(val.indexOf("@@f@@") + 5); } // Tokenize the value. ts = new XLEntry(targetLocale, cleanConcats(val)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); keyvalStr = keyvalStr.substring(0, mniniqv2.getStartIndex(3)) + token.getDecoratedToken() + keyvalStr.substring(mniniqv2.getEndIndex(3)); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); // End Processing for sub(3). // Begin Processing for sub(2). val = mniniqv2.toString(2); while (val.indexOf("@@r@@") >= 0) { val = val.substring(0, val.indexOf("@@r@@")) + " " + val.substring(val.indexOf("@@r@@") + 5); } while (val.indexOf("@@n@@") >= 0) { val = val.substring(0, val.indexOf("@@n@@")) + " " + val.substring(val.indexOf("@@n@@") + 5); } while (val.indexOf("@@f@@") >= 0) { val = val.substring(0, val.indexOf("@@f@@")) + " " + val.substring(val.indexOf("@@f@@") + 5); } // Tokenize the value. ts = new XLEntry(targetLocale, cleanConcats(val)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); keyvalStr = keyvalStr.substring(0, mniniqv2.getStartIndex(2)) + token.getDecoratedToken() + keyvalStr.substring(mniniqv2.getEndIndex(2)); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); // End if processing for sub(2) } // End Pattern niniqv2 else if (!(mniniqv == null)) { // Begin Pattern niniqv // Must check this after niniqv2 since this will find the niniqv2 pattern also. niniqv2 will not find this pattern. nextStart = mniniqv.getEndIndex(); keyvalStr = tokKQV(keyvalStr, mniniqv); } // End Pattern niniqv else if (!(mqkmv == null)) { // Begin Pattern qkmv nextStart = mqkmv.getEndIndex(); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "keyvalStr: [" + keyvalStr + "] nextStart: [" + nextStart + "]"); keyvalStr = tokKMV(keyvalStr, mqkmv); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "next keyvalStr: [" + keyvalStr + "]"); } // End Pattern qkmv else if (!(mkmv == null)) { // Begin Pattern kmv nextStart = mkmv.getEndIndex(); keyvalStr = tokKMV(keyvalStr, mkmv); } // End Pattern kmv else if (!(mqkqv == null)) { // Begin Pattern qkqv nextStart = mqkqv.getEndIndex(); keyvalStr = tokKQV(keyvalStr, mqkqv); } // End Pattern qkqv else if (!(mkqv == null)) { // Begin Pattern kqv log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkqv found"); nextStart = mkqv.getEndIndex(); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "keyvalStr before: [" + keyvalStr + "]"); keyvalStr = tokKQV(keyvalStr, mkqv); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "keyvalStr after: [" + keyvalStr + "]"); } // End Pattern kqv else if (!(mqkv == null)) { // Begin Pattern qkv // This must come near the end of the patterns to process since it may match other patterns as well. log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkv found"); nextStart = mqkv.getEndIndex(); keyvalStr = tokKV(keyvalStr, mqkv); } // End Pattern qkv else if (!(mkv == null)) { // Begin Pattern kv // This must come near the end of the patterns to process since it may match other patterns as well. log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkv found"); nextStart = mkv.getEndIndex(); keyvalStr = tokKV(keyvalStr, mkv); } // End Pattern kv else { // Begin Pattern Unknown throw new TokODDFileError(mrb.getString("errormsg.nopatternmatch")); } // End Pattern Unknown } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKeyValue", mt.toString()); mt.printStackTrace(); } // Do the RE find again. Sometimes start the next search just past the previous results. Don't do that for all patterns since in some cases we are processing a pattern that is located at a higher offset than the next one. If we search from the end of the first search result we will miss what comes before it. mkmv = kmv.getMatch(keyvalStr, nextStart); mqkmv = qkmv.getMatch(keyvalStr, nextStart); mqkqv = qkqv.getMatch(keyvalStr); mkqv = kqv.getMatch(keyvalStr); mniniqv2 = niniqv2.getMatch(keyvalStr); mniniqv = niniqv.getMatch(keyvalStr); mksa = ksa.getMatch(keyvalStr, nextStart); mqksa = qksa.getMatch(keyvalStr, nextStart); mqkv = qkv.getMatch(keyvalStr, nextStart); mkv = kv.getMatch(keyvalStr, nextStart); msop = sop.getMatch(keyvalStr, nextStart); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "pattern match at end of look begin (shown in order processed):"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "msop[" + msop + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqksa[" + mqksa + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mksa[" + mksa + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mniniqv2[" + mniniqv2 + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mniniqv[" + mniniqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkmv[" + mqkmv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkmv[" + mkmv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkqv[" + mqkqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkqv[" + mkqv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mqkv[" + mqkv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "mkv[" + mkv + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "pattern match at end of loop end."); } // while (!(... == null && ...)) log.logp(Level.FINER, "TokODDListResourceBundle", "tokKeyValue", "keyvalStr after loop has ended: [" + keyvalStr + "]"); tokFile.append(keyvalStr); } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that has the pattern of a key with a string array for a value. *

The section of the file is updated with the appropriate token inserted and returned.

* @param keyvalStr a String specifying the key/value string * @param m a REMatch object specifying the regular expression match * @return a String representing the tokenized key/value string * @throws TokODDFileError when something goes wrong */ protected static String tokKSA(String keyvalStr, REMatch m) throws FileTokenizerError, TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKSA", "found ksa pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKSA", "key: [" + m.toString(1).trim() + "] value: [" + m.toString(2) + "]"); tokContext = new TokContext(theContextFileName, m.toString(1).trim(), null, null); RE vs = null; RESyntax res = new RESyntax(RESyntax.RE_SYNTAX_AWK); res = res.set(RESyntax.RE_CHAR_CLASSES); res = res.set(RESyntax.RE_DOT_NEWLINE); try { // Look for a value set. vs = new RE("([^{]*)({.*})(.*)", 0, res); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKSA", e.toString()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } int qscount = 0; String val = new String(); int valstart = m.getStartIndex(2); int valend = valstart; String s = null; String workVal = m.toString(2); REMatch mvs = vs.getMatch(workVal); if (!(mvs == null)) { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKSA", "valstart: [" + valstart + "] valend: [" + valend + "]"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKSA", "mvs(2) start: [" + mvs.getStartIndex(2) + "] mvs(2) end: [" + mvs.getEndIndex(2) + "]"); valstart += mvs.getStartIndex(2); valend += mvs.getEndIndex(2); val = keyvalStr.substring(valstart, valend); // Tokenize the value. try { XLEntry ts = new XLEntry(targetLocale, cleanConcats(val)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); keyvalStr = keyvalStr.substring(0, valstart) + token.getDecoratedToken() + keyvalStr.substring(valend); } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKSA", mt.toString()); mt.printStackTrace(); } } return keyvalStr; } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that has the pattern of a key with a quoted string for a value. *

The section of the file is updated with the appropriate token inserted and returned.

* @param keyvalStr a String specifying the key/value string * @param m a REMatch object specifying the regular expression match * @return a String representing the tokenized key/value string * @throws TokODDFileError when something goes wrong */ protected static String tokKQV(String keyvalStr, REMatch m) throws FileTokenizerError, TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKQV", "found kqv pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKQV", "key: [" + m.toString(1).trim() + "] value: [" + m.toString(2) + "]"); tokContext = new TokContext(theContextFileName, m.toString(1).trim(), null, null); RE qs = null; RE vs = null; RESyntax res = new RESyntax(RESyntax.RE_SYNTAX_AWK); res = res.set(RESyntax.RE_CHAR_CLASSES); res = res.set(RESyntax.RE_DOT_NEWLINE); try { // Look for quoted strings separated either by commas. This is used to determine if a value is a single element or an array of elements. qs = new RE("(\"[^\"]*\")[^\"]*", 0, res); // Look for a value set. vs = new RE("([^{]*)({[^}]*})(.*)", 0, res); } catch (REException e) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKQV", e.toString()); e.printStackTrace(); throw new TokODDFileError(mrb.getString("errormsg.badexpression")); } String val = new String(); char quoteDelim = '"'; StringBuffer quotedString = new StringBuffer(); boolean inQuotedString = false; StringCharacterIterator ci = new StringCharacterIterator(keyvalStr.substring(m.getStartIndex(2), m.getEndIndex(2))); int qsstart = m.getStartIndex(2); int qsend = 0; char c = ci.first(); scan: for (char nc = ci.next(); nc != StringCharacterIterator.DONE; nc = ci.next()) { if (inQuotedString) { // Accumulate the characters in the quoted string and process it when the end is reached. if (c == '\\') { quotedString.append(c); qsend++; quotedString.append(nc); qsend++; nc = ci.next(); } else { quotedString.append(c); // Add character to quoted string. qsend++; if (c == quoteDelim) { // This is the end of the quoted string. inQuotedString = false; } } } else { // Not in a quoted string. } means that is the end of everything. " means start a new quoted string. Set qsstart if this is the first quoted string. if (c == '}') { // End of everything. break scan; } if (c == quoteDelim && qsend <= qsstart) { // Begin the quoted string. inQuotedString = true; quotedString.append(c); qsend = qsstart + 1; } else if (qsend <= qsstart) { // No quoted string found yet so move the potential start. qsstart++; } else { // Drop the character and replace it with a blank in the current quoted string. quotedString.append(c); qsend++; if (c == quoteDelim) { inQuotedString = true; } } } // end quoted string c = nc; } // scan if (inQuotedString) { quotedString.append(c); qsend++; } val = quotedString.toString(); while (val.indexOf("@@r@@") >= 0) { val = val.substring(0, val.indexOf("@@r@@")) + " " + val.substring(val.indexOf("@@r@@") + 5); } while (val.indexOf("@@n@@") >= 0) { val = val.substring(0, val.indexOf("@@n@@")) + " " + val.substring(val.indexOf("@@n@@") + 5); } while (val.indexOf("@@f@@") >= 0) { val = val.substring(0, val.indexOf("@@f@@")) + " " + val.substring(val.indexOf("@@f@@") + 5); } // Tokenize the value. try { XLEntry ts = new XLEntry(targetLocale, cleanConcats(val)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); keyvalStr = keyvalStr.substring(0, qsstart) + token.getDecoratedToken() + keyvalStr.substring(qsend); } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKQV", mt.toString()); mt.printStackTrace(); } return keyvalStr; } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that has the pattern of a key with multiple values. *

The section of the file is updated with the appropriate token inserted and returned.

* @param keyvalStr a String specifying the key/value string * @param m a REMatch object specifying the regular expression match * @return a String representing the tokenized key/value string * @throws TokODDFileError when something goes wrong */ protected static String tokKMV(String keyvalStr, REMatch m) throws FileTokenizerError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKMV", "found kmv pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKMV", "key: [" + m.toString(1).trim() + "] value: [" + m.toString(2) + "]"); tokContext = new TokContext(theContextFileName, m.toString(1).trim(), null, null); int valstart = m.getStartIndex(2); int valend = m.getEndIndex(2); String val = keyvalStr.substring(valstart, valend); // Tokenize the value. try { XLEntry ts = new XLEntry(targetLocale, cleanConcats(val)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); keyvalStr = keyvalStr.substring(0, valstart) + token.getDecoratedToken() + keyvalStr.substring(valend); } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKMV", mt.toString()); mt.printStackTrace(); } return keyvalStr; } //------------------------------------------------------------ /** Tokenizes a section of the ListResourceBundle that has the pattern of a key with a non-quoted string for a value. *

The section of the file is updated with the appropriate token inserted and returned.

*

This pattern is important for things like font specifications and sizing information. These things tend to be specified as something other than a quoted string. It is not consistent as to how they are specified so we use this general pattern to describe them.

* @param keyvalStr a String specifying the key/value string * @param m a REMatch object specifying the regular expression match * @return a String representing the tokenized key/value string * @throws TokODDFileError when something goes wrong */ protected static String tokKV(String keyvalStr, REMatch m) throws TokODDFileError { log.logp(Level.FINER, "TokODDListResourceBundle", "tokKV", "found kv pattern"); log.logp(Level.FINER, "TokODDListResourceBundle", "tokKV", "key: [" + m.toString(1).trim() + "] value: [" + m.toString(2) + "]"); tokContext = new TokContext(theContextFileName, m.toString(1).trim(), null, null); int vstart = m.getStartIndex(2); int vend = m.getEndIndex(2); // Tokenize the value. try { XLEntry ts = new XLEntry(targetLocale, keyvalStr.substring(vstart, vend)); ts.clean(); ts.setContext(tokContext); strFile.append(new com.g11ntoolkit.token.Token(token.nextToken()), ts); tokFile.setContext(tokContext, new com.g11ntoolkit.token.Token(token.getToken())); keyvalStr = keyvalStr.substring(0, vstart) + token.getDecoratedToken() + keyvalStr.substring(vend); } catch (MalformedToken mt) { log.logp(Level.SEVERE, "TokODDListResourceBundle", "tokKV", mt.toString()); mt.printStackTrace(); } return keyvalStr; } //------------------------------------------------------------ } //------------------------------------------------------------ /** Reports errors while tokenizing the file. * @version 2005/09/19 * @author Bill Rich, Wilandra Consulting LLC *
Copyright © 2005, Wilandra Consulting LLC. All rights reserved. */ class TokODDFileError extends Exception { /** * Constructs a TokODDFileError object. * @param s a String specifying the error message */ TokODDFileError(String s) { super(s); } } //------------------------------------------------------------