diff -r 14dc2103a631 -r ed1c9f64298a trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/rules/printf/PrintfTraceParserRule.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/rules/printf/PrintfTraceParserRule.java Wed Jun 23 14:35:40 2010 +0300 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). + * All rights reserved. + * This component and the accompanying materials are made available + * under the terms of "Eclipse Public License v1.0" + * which accompanies this distribution, and is available + * at the URL "http://www.eclipse.org/legal/epl-v10.html". + * + * Initial Contributors: + * Nokia Corporation - initial contribution. + * + * Contributors: + * + * Description: + * + * Parser for printf traces + * + */ +package com.nokia.tracebuilder.engine.rules.printf; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.nokia.tracebuilder.engine.TraceLocation; +import com.nokia.tracebuilder.engine.TraceBuilderErrorCodes.StringErrorParameters; +import com.nokia.tracebuilder.engine.TraceBuilderErrorCodes.TraceBuilderErrorCode; +import com.nokia.tracebuilder.engine.rules.SourceParserRuleBase; +import com.nokia.tracebuilder.engine.source.SourceParserResult; +import com.nokia.tracebuilder.engine.utils.TraceUtils; +import com.nokia.tracebuilder.model.TraceBuilderException; +import com.nokia.tracebuilder.source.FormatMapping; +import com.nokia.tracebuilder.source.SourceConstants; +import com.nokia.tracebuilder.source.SourceUtils; + +/** + * Parser for printf traces + * + */ +public class PrintfTraceParserRule extends SourceParserRuleBase { + + /** + * Default name for a parameter + */ + public static final String DEFAULT_PARAMETER_NAME = "arg"; //$NON-NLS-1$ + + /** + * Name of this parser + */ + private static final String PARSER_NAME = "PrintfParser"; //$NON-NLS-1$ + + /** + * Pattern for trimming c++ cast operator away from trace parameters + */ + private Pattern cppCastTrimPattern = Pattern.compile("\\s*(.+<.+>)\\s*"); //$NON-NLS-1$ + + /** + * Pattern for trimming c cast operator away from trace parameters + */ + private Pattern cCastTrimPattern = Pattern.compile("(\\([^(]+?\\))"); //$NON-NLS-1$ + + /** + * Pattern for getting a valid token from parameter data + */ + private Pattern parameterNamePattern = Pattern + .compile("[a-zA-Z][a-zA-Z\\d]*"); //$NON-NLS-1$ + + /** + * Symbian literal tags + */ + private String[] TRACE_TEXT_TAGS = { "_L8", //$NON-NLS-1$ + "_T8", //$NON-NLS-1$ + "_L", //$NON-NLS-1$ + "_T" //$NON-NLS-1$ + }; + + /** + * Constructor + * + * @param tag + * the tag to be found from source + */ + public PrintfTraceParserRule(String tag) { + super(tag, null); + } + + /** + * Constructor + * + * @param tag + * the tag to be searched from source + * @param tagSuffixes + * the list of allowed suffixes to the tag + */ + public PrintfTraceParserRule(String tag, String[] tagSuffixes) { + super(tag, tagSuffixes); + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracebuilder.engine.source.SourceParserRule#getName() + */ + public String getName() { + return PARSER_NAME; + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracebuilder.engine.source.SourceParserRule# + * parseParameters(java.util.List) + */ + public SourceParserResult parseParameters(String tag, List list) + throws TraceBuilderException { + SourceParserResult result = new SourceParserResult(); + result.traceText = trimTraceText(list.get(0)); + result.originalName = result.traceText; + result.convertedName = TraceUtils.convertName( + SourceUtils.removePrintfFormatting(result.traceText)) + .toUpperCase(); + result.parameters = list.subList(1, list.size()); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracebuilder.engine.rules.SourceParserRuleBase#getLocationGroup() + */ + @Override + public String getLocationGroup() { + return Messages.getString("PrintfTraceParserRule.Title"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see com.nokia.tracebuilder.engine.rules.SourceParserRuleBase# + * convertLocation(com.nokia.tracebuilder.engine.TraceLocation) + */ + @Override + public TraceConversionResult convertLocation(TraceLocation location) + throws TraceBuilderException { + // All parameter types are supported by default -> false is passed to + // buildParameterTypeList. + List types = buildParameterTypeList(location + .getTraceText(), false); + // Parameter count must match the number of format elements in trace + // text -> true is passed to convertLocation by default + return convertLocation(location, true, types); + } + + /** + * Converts a location to trace + * + * @param location + * the location to be converted + * @param useParametersFromLocation + * true if location parameters need to be checked + * @param types + * the parameter types list + * @return the conversion result + * @throws TraceBuilderException + * if conversion fails + */ + protected TraceConversionResult convertLocation(TraceLocation location, + boolean useParametersFromLocation, List types) + throws TraceBuilderException { + TraceConversionResult result = new TraceConversionResult(); + result.text = location.getTraceText(); + + // If trace text is in multiple lines, remove extra characters + int removableAreaBeging = -1; + for (int i = 0; i < result.text.length(); i++) { + char c = result.text.charAt(i); + if (c == SourceConstants.QUOTE_CHAR + && (i == 0 || result.text.charAt(i - 1) != SourceConstants.BACKSLASH_CHAR)) { + if (removableAreaBeging != -1) { + String startString = result.text.substring(0, + removableAreaBeging); + String endString = result.text.substring(i + 1, result.text + .length()); + result.text = startString + endString; + i = removableAreaBeging; + removableAreaBeging = -1; + } else { + removableAreaBeging = i; + } + } + } + + result.name = location.getConvertedName(); + + // If location parameters are used, the count must match the number of + // formats parsed from the trace string. + if (!useParametersFromLocation + || (types.size() == location.getParameterCount() && numberOfParametersInTagMatchSize( + location.getTag(), types.size()))) { + result.parameters = new ArrayList(types + .size()); + Iterator itr = location.getParameters(); + // The FormatMapping objects are converted to + // ParameterConversionResult objects: + // - Name is associated to the parameter + // - Extensions are created + for (int i = 0; i < types.size(); i++) { + FormatMapping mapping = types.get(i); + String name; + if (useParametersFromLocation) { + name = TraceUtils.convertName(trimParameter(itr.next(), i)); + } else { + name = DEFAULT_PARAMETER_NAME + (i + 1); + } + ParameterConversionResult param = mapFormatToConversionResult(mapping); + param.name = modifyDuplicateName(result.parameters, name); + result.parameters.add(param); + } + } else { + throw new TraceBuilderException( + TraceBuilderErrorCode.PARAMETER_FORMAT_MISMATCH, null, + location); + } + return result; + } + + /** + * Checks if the number of the parameters in the trace tag matches the size + * of parameter list + * + * @param tag + * the trace tag + * @param size + * size of the parameter list + * @return true is parameter count matches, false otherwise + */ + private boolean numberOfParametersInTagMatchSize(String tag, int size) { + boolean matches = true; + // Parse the last character of the tag to a integer + if (tag != null) { + try { + + // Check the tag parameter count and compare it to the size of + // the parameter list + String tagParamStr = tag.substring(tag.length() - 1); + int tagParamCount = Integer.parseInt(tagParamStr); + + if (tagParamCount != size) { + matches = false; + } + } catch (NumberFormatException e) { + } + } + return matches; + } + + /** + * Builds the parameter type array which is passed to convertLocation + * + * @param text + * the trace text + * @param simpleParameters + * true if only simple types are supported + * @return the list of types + * @throws TraceBuilderException + * if parser fails + */ + protected List buildParameterTypeList(String text, + boolean simpleParameters) throws TraceBuilderException { + Matcher matcher = SourceUtils.traceTextPattern.matcher(text); + ArrayList types = new ArrayList(); + boolean found = true; + do { + found = matcher.find(); + if (found) { + String tag = matcher.group(); + FormatMapping mapping = SourceUtils + .mapFormatToParameterType(tag); + if (simpleParameters && !mapping.isSimple) { + StringErrorParameters param = new StringErrorParameters(); + param.string = tag; + throw new TraceBuilderException( + TraceBuilderErrorCode.PARAMETER_FORMAT_NEEDS_EXT_MACRO, + param, null); + } + types.add(mapping); + } + } while (found); + return types; + } + + /** + * Changes a duplicate parameter name to unique + * + * @param parameters + * the list of existing parameters + * @param name + * the name + * @return the modified name + */ + private String modifyDuplicateName( + List parameters, String name) { + String retval = name; + for (ParameterConversionResult result : parameters) { + if (result.name.equals(name)) { + retval = name + (parameters.size() + 1); + break; + } + } + return retval; + } + + /** + * Trims extra stuff away from trace text + * + * @param data + * the data to be trimmed + * @return trimmed text + */ + protected String trimTraceText(String data) { + // Removes literal macros + for (String element : TRACE_TEXT_TAGS) { + if (data.startsWith(element)) { + data = data.substring(element.length()); + } + } + data = data.trim(); + // Removes the opening bracket and quotes + data = removeBrackets(data); + if (data.startsWith("\"") //$NON-NLS-1$ + && data.length() >= 2) { // CodForChk_Dis_Magic + data = data.substring(1, data.length() - 1); + } + return data; + } + + /** + * Removes the brackets around the given data + * + * @param data + * the data + * @return the modified data + */ + protected String removeBrackets(String data) { + boolean canRemove = true; + while (data.startsWith("(") //$NON-NLS-1$ + && data.endsWith(")") //$NON-NLS-1$ + && canRemove) { + // If closing bracket is found first, the first bracket cannot be + // removed. + // TODO: Does not work with for example ((Cast)abc).Func() + // -> (Cast)abc).Func( + for (int i = 1; i < data.length() - 1 && canRemove; i++) { + if (data.charAt(i) == '(') { + i = data.length(); + } else if (data.charAt(i) == ')') { + canRemove = false; + } + } + if (canRemove) { + data = data.substring(1, data.length() - 1).trim(); + } + } + return data; + } + + /** + * Trims extra stuff away from a parameter to create a parameter label + * + * @param data + * the parameter data + * @param index + * the parameter index. The index will be used as label if the + * label cannot be parsed + * @return the parameter label + */ + protected String trimParameter(String data, int index) { + // Removes possible literal macros + data = trimTraceText(data); + // Removes casting operations. + Matcher matcher = cppCastTrimPattern.matcher(data); + data = removeBrackets(matcher.replaceFirst("")); //$NON-NLS-1$ + matcher = cCastTrimPattern.matcher(data); + data = matcher.replaceFirst(""); //$NON-NLS-1$ + // Finds the next valid token from the data + matcher = parameterNamePattern.matcher(data); + if (matcher.find()) { + data = matcher.group(); + } else { + data = DEFAULT_PARAMETER_NAME + (index + 1); + } + return data; + } + +}