diff -r a151135b0cf9 -r aa2539c91954 tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/header/TraceHeaderWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/engine/header/TraceHeaderWriter.java Fri Oct 08 14:56:39 2010 +0300 @@ -0,0 +1,1401 @@ +/* + * Copyright (c) 2009-2010 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: + * + * Writes the TraceHeader to a file + * + */ +package com.nokia.tracecompiler.engine.header; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +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.tracecompiler.TraceCompilerLogger; +import com.nokia.tracecompiler.engine.LocationListBase; +import com.nokia.tracecompiler.engine.LocationProperties; +import com.nokia.tracecompiler.engine.TraceCompilerEngineGlobals; +import com.nokia.tracecompiler.engine.TraceLocation; +import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.TraceCompilerErrorCode; +import com.nokia.tracecompiler.engine.source.SourceFormatter; +import com.nokia.tracecompiler.engine.source.TraceFormattingRule; +import com.nokia.tracecompiler.engine.source.TraceParameterFormattingRule; +import com.nokia.tracecompiler.file.FileCompareOutputStream; +import com.nokia.tracecompiler.file.FileUtils; +import com.nokia.tracecompiler.model.Trace; +import com.nokia.tracecompiler.model.TraceCompilerException; +import com.nokia.tracecompiler.model.TraceGroup; +import com.nokia.tracecompiler.model.TraceModel; +import com.nokia.tracecompiler.model.TraceParameter; +import com.nokia.tracecompiler.plugin.TraceFormatConstants; +import com.nokia.tracecompiler.plugin.TraceHeaderContribution; +import com.nokia.tracecompiler.plugin.TraceAPIFormatter.TraceFormatType; +import com.nokia.tracecompiler.plugin.TraceHeaderContribution.TraceHeaderContributionType; +import com.nokia.tracecompiler.rules.FillerParameterRule; +import com.nokia.tracecompiler.source.SourceConstants; +import com.nokia.tracecompiler.source.SourceExcludedArea; +import com.nokia.tracecompiler.source.SourceParser; +import com.nokia.tracecompiler.source.SourceUtils; +import com.nokia.tracecompiler.source.SymbianConstants; +import com.nokia.tracecompiler.utils.TraceCompilerVersion; + +/** + * Writes the TraceHeader to a file + * + */ +final class TraceHeaderWriter { + + /** + * return type text of a generated OstTraceGenx function. + */ + private static final String INLINE_TBOOL = "inline TBool"; + + /** + * open bracket in a type cast + */ + private static final String BEGINCAST = "OBR"; //$NON-NLS-1$ + + /** + * closing bracket in a type cast + */ + private static final String ENDCAST = "CBR"; //$NON-NLS-1$ + + /** + * REF replaces & in a function guard + */ + private static final String REF = "REF"; //$NON-NLS-1$ + + /** + * & character + */ + private static final String AMPERSANT = "&"; //$NON-NLS-1$ + + /** + * closing bracket + */ + private static final String CLOSING_BRACKET = ")"; //$NON-NLS-1$ + + /** + * open bracket + */ + private static final String OPEN_BRACKET = "("; //$NON-NLS-1$ + + /** + * TUint32 definition + */ + private static final String TUINT32_DEF = "TUint32 "; //$NON-NLS-1$ + + /** + * TInt32 definition + */ + private static final String TINT32_DEF = "TInt32 "; //$NON-NLS-1$ + + /** + * TUint definition + */ + private static final String TUINT_DEF = "TUint "; //$NON-NLS-1$ + + /** + * TInt definition + */ + private static final String TINT_DEF = "TInt "; //$NON-NLS-1$ + + /** + * Length variable defined flag + */ + private boolean lenghtVariableDefined = false; + + + /** + * List of dynamic elements that can be used from the templates + * + */ + enum HeaderTemplateElementType { + + /** + * Licence text + */ + LICENCE_TEXT, + + /** + * TraceCompiler version number + */ + TRACE_COMPILER_VERSION, + + /** + * Header guard based on file name + */ + HEADER_GUARD, + + /** + * Opening brace + */ + OPEN_BRACE, + + /** + * Closing brace + */ + CLOSE_BRACE, + + /** + * New line and indent based on open brace count + */ + NEW_LINE, + + /** + * Writes currentTraceFormatted + */ + FORMATTED_TRACE, + + /** + * Adds all closing braces except the one that closes the function + */ + CLOSE_EXTRA_BRACES, + + /** + * Type of current parameter + */ + PARAMETER_TYPE, + + /** + * Name of current parameter + */ + PARAMETER_NAME, + + /** + * Name of current trace + */ + TRACE_NAME, + + /** + * ID of current trace + */ + TRACE_ID_HEX, + + /** + * Calls a function to add the trace buffer initialization code + */ + BUILD_TRACE_BUFFER_CHECK, + + /** + * Calls a function to add the function body + */ + TRACE_FUNCTION_BODY, + + /** + * Calls a function to add function parameters + */ + TRACE_FUNCTION_PARAMETERS, + + /** + * Writes the fixedBufferSize member variable + */ + FIXED_BUFFER_SIZE, + + /** + * Writes the dynamicBufferSize member variable + */ + DYNAMIC_BUFFER_SIZE, + + /** + * Index of the parameter being processed + */ + PARAMETER_INDEX + } + + /** + * Group ID shift bits + */ + private static final int GROUP_SHIFT = 16; // CodForChk_Dis_Magic + + /** + * Number of bytes in parameter + */ + private static final int BYTES_IN_PARAMETER = 4; // CodForChk_Dis_Magic + + /** + * Indent + */ + private static final String INDENT = " "; //$NON-NLS-1$ + + /** + * The header file to be updated + */ + private TraceHeader header; + + /** + * Output stream for the header + */ + private OutputStream headerOutput; + + /** + * Temporary flag that specifies if a trace requires a trace buffer or it + * can be represented by the default trace macros + */ + private boolean buildTraceBuffer; + + /** + * Temporary variable for fixed size + */ + private int fixedBufferSize; + + /** + * Dynamic size flag + */ + private boolean dynamicBufferSizeFlag; + + /** + * Flag which is set it trace needs #endif for __KERNEL_MODE__ + */ + private boolean needsKernelEndif; + + /** + * Used via HeaderTemplateElementType.FORMATTED_TRACE + */ + private String currentTraceFormatted; + + /** + * Type of current parameter + */ + private String currentParameterType; + + /** + * Name of current parameter + */ + private String currentParameterName; + + /** + * Index of current parameter + */ + private int currentParameterIndex; + + /** + * Number of opened brackets + */ + private int openBraceCount; + + /** + * Trace being processed + */ + private Trace currentTrace; + + /** + * Parameter being processed + */ + private TraceParameter currentParameter; + + /** + * List of trace functions already in the header + */ + private ArrayList traceDeclarations = new ArrayList(); + + /** + * Number of sequential new lines + */ + private int newLineCount; + + /** + * Number of allowed sequential new lines + */ + private int maxNewLines; + + /** + * Indicates that writing a function to the header file is going + */ + private boolean firstOpenBraceFound; + + /** + * boolean indication that we are buffering a function text + */ + private boolean bufferingFunction; + + /** + * While writing a function to the header file, it's gathered to this + * member. The member is then checked if the function parameters contain + * TInt or TUint values. If so, the function is replicated so that TInt is + * replaced by TInt32 and TUint with TUint32. + */ + private StringBuilder functionText = new StringBuilder(); + + /** + * Number of brackets seen when writing a function. When it gets to 0, the + * function in previousFunction variable is complete and can be written. + */ + private int numberOfBrackets; + + /** + * string to hold the function guard + */ + private String ostTraceGenxFunGuard; + + /** + * Creates a new header writer + * + * @param header + * the header to be written + */ + TraceHeaderWriter(TraceHeader header) { + this.header = header; + } + + /** + * Writes the header + * + * @return true if header was written, false if it matched the existing + * header + * @throws TraceCompilerException + * if writing fails + */ + boolean write() throws TraceCompilerException { + boolean headerWritten = false; + try { + openBraceCount = 0; + createHeader(); + writeTemplate(HeaderTemplate.HEADER_TEMPLATE); + headerWritten = closeHeader(); + } catch (IOException e) { + e.printStackTrace(); + throw new TraceCompilerException( + TraceCompilerErrorCode.CANNOT_WRITE_PROJECT_FILE, e); + } finally { + traceDeclarations.clear(); + if (headerOutput != null) { + try { + headerOutput.close(); + } catch (IOException e) { + } + } + headerOutput = null; + } + return headerWritten; + } + + /** + * Creates the header file + * + * @throws IOException + * if creation fails + */ + private void createHeader() throws IOException { + File file = new File(header.getAbsolutePath()); + if (file.exists()) { + // If header exists, data is written to a byte array and compared + // with existing file. If they are the same, the file is not + // updated. + headerOutput = new FileCompareOutputStream(file); + } else { + // If header does not exist, the data is written directly to file + headerOutput = FileUtils.createOutputStream(file); + } + } + + /** + * Closes the header file. If data was written to a byte buffer this + * compares the contents of the buffer with the existing file and re-writes + * the file if contents do not match. + * + * @return true if header was written, false if it matched the existing + * header + * @throws IOException + * if closing fails + */ + private boolean closeHeader() throws IOException { + boolean headerWritten = true; + if (headerOutput instanceof FileCompareOutputStream) { + headerWritten = ((FileCompareOutputStream) headerOutput) + .writeFile(); + } + headerOutput.close(); + headerOutput = null; + return headerWritten; + } + + /** + * Writes a template to the stream + * + * @param template + * the template + * @throws IOException + * if writing fails + */ + void writeTemplate(Object[] template) throws IOException { + for (Object o : template) { + if (o instanceof String) { + write((String) o); + } else if (o instanceof TraceHeaderContributionType) { + writeHeaderContributions((TraceHeaderContributionType) o); + } else if (o instanceof HeaderTemplateElementType) { + writeTemplateElement((HeaderTemplateElementType) o); + } else if (o instanceof Object[]) { + // Template within template + writeTemplate((Object[]) o); + } else if (o instanceof TemplateChoice) { + TemplateChoice choice = (TemplateChoice) o; + // Gets the array index from template + Class c = choice.getChoiceClass(); + try { + // Creates a switch-case object based on array index + TemplateCheckBase check = c.newInstance(); + check.setWriter(this); + // Gets the case from the switch-case object and uses it to + // get the correct template + if (check.check()) { + writeTemplate(choice.getTrueTemplate()); + } else { + writeTemplate(choice.getFalseTemplate()); + } + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } + } else if (o instanceof TemplateIterator) { + Class c = ((TemplateIterator) o) + .getIteratorClass(); + try { + // Creates an iterator object based on array index + TemplateIteratorEntry itr = c.newInstance(); + itr.setWriter(this); + itr.iterate(((TemplateIterator) o).getTemplate()); + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } + } else if (o instanceof SetNewLineCount) { + maxNewLines = ((SetNewLineCount) o).getLineCount(); + } else if (o instanceof TraceFormatType) { + // Stores the formatted trace, but does not write anything + // HeaderTemplateElementType.FORMATTED_TRACE writes the trace + currentTraceFormatted = SourceFormatter.formatTrace( + currentTrace, (TraceFormatType) o); + } + } + } + + /** + * Writes an element from the HeaderTemplateElementType enumeration + * + * @param type + * the element type + * @throws IOException + * if writing fails + */ + private void writeTemplateElement(HeaderTemplateElementType type) + throws IOException { // CodForChk_Dis_ComplexFunc + switch (type) { + case NEW_LINE: + writeNewLine(); + break; + case OPEN_BRACE: + writeOpenBrace(); + break; + case CLOSE_BRACE: + writeCloseBrace(); + break; + case PARAMETER_INDEX: + write(String.valueOf(currentParameterIndex)); + break; + case PARAMETER_TYPE: + write(currentParameterType); + break; + case PARAMETER_NAME: + write(currentParameterName); + break; + case FORMATTED_TRACE: + writeFormattedTrace(currentTraceFormatted); + break; + case TRACE_NAME: + write(currentTrace.getName()); + break; + case TRACE_ID_HEX: + writeTraceID(); + break; + case FIXED_BUFFER_SIZE: + write(String.valueOf(fixedBufferSize)); + break; + case TRACE_FUNCTION_BODY: + writeFunctionBody(currentTrace); + break; + case TRACE_FUNCTION_PARAMETERS: + writeParameter(currentParameter); + break; + case BUILD_TRACE_BUFFER_CHECK: + buildTraceBuffer = traceNeedsBuffer(currentTrace); + break; + case HEADER_GUARD: + write(SourceUtils.createHeaderGuard(header.getFileName())); + break; + case TRACE_COMPILER_VERSION: + write(TraceCompilerVersion.getVersion()); + break; + case CLOSE_EXTRA_BRACES: + while (openBraceCount > 1) { + writeCloseBrace(); + } + break; + case LICENCE_TEXT: + writeLicence(); + break; + } + } + + /** + * Writes the trace ID to header + * + * @throws IOException + * if writing fails + */ + private void writeTraceID() throws IOException { + int gid = currentTrace.getGroup().getID() << GROUP_SHIFT; + write(Integer.toHexString(gid | currentTrace.getID())); + ComplexHeaderRule rule = currentTrace + .getExtension(ComplexHeaderRule.class); + if (rule != null) { + String ext = rule.getTraceIDDefineExtension(); + if (ext != null) { + write(ext); + } + } + } + + /** + * Writes the header contributions from plug-in's + * + * @param type + * the contribution type + * @throws IOException + * if writing fails + */ + private void writeHeaderContributions(TraceHeaderContributionType type) + throws IOException { + Iterator contributions = getContributions(type); + boolean written = false; + while (contributions.hasNext()) { + writeContribution(contributions.next(), type); + written = true; + } + if (written) { + writeNewLine(); + } + } + + /** + * Gets a list of contributions from plug-in's + * + * @param type + * the contribution type + * @return the contributions + */ + private Iterator getContributions(TraceHeaderContributionType type) { + Iterator contributions = header.getOwner() + .getExtensions(TraceHeaderContribution.class); + ArrayList list = new ArrayList(); + while (contributions.hasNext()) { + String[] s = contributions.next().getContribution(type); + if (s != null) { + for (String element : s) { + list.add(element); + } + } + } + return list.iterator(); + } + + /** + * Writes a contribution to the stream + * + * @param contribution + * the contribution + * @param type + * the contribution type + * @throws IOException + * if writing fails + */ + private void writeContribution(String contribution, + TraceHeaderContributionType type) throws IOException { + switch (type) { + case GLOBAL_DEFINES: + writeDefine(contribution); + break; + case GLOBAL_INCLUDES: + writeSystemInclude(contribution); + break; + case MAIN_HEADER_CONTENT: + // Handled by HeaderEngine + break; + } + } + + /** + * write start of function guard + * @throws IOException + */ + private void writeStartFunctionGuard() throws IOException { + Pattern p = Pattern.compile("inline\\s+TBool\\s+([^\\(]+)\\s*\\((.*)\\)\\s*\\{"); //$NON-NLS-1$ + String guard = null; + String functionName = null; + + // Get the function definition line + int startIndex = functionText.indexOf(SourceConstants.OPENING_BRACE) + 1; + String funcDef = functionText.substring(0, startIndex); + + Matcher m = p.matcher(funcDef); + if (m.matches()) { + //get function name + functionName = m.group(1); + if (functionName == null || functionName.length() == 0) { + throw new IOException(Messages.getString("TraceHeader.internalError1")); //$NON-NLS-1$ + } + //get raw parameters + String parameters = m.group(2); + if (parameters == null || parameters.length() == 0) {//there must be at least TraceID + throw new IOException(Messages.getString("TraceHeader.internalError2")); //$NON-NLS-1$ + } + + functionName = functionName.trim(); + parameters = parameters.trim(); + //remove parameters names + guard = parameters.replaceAll("(\\S+,)|(\\S+\\s*$)", ""); //$NON-NLS-1$ //$NON-NLS-2$ + //replace repeated spaces by one space + guard = guard.replaceAll("\\s+", SourceConstants.SPACE).trim(); //$NON-NLS-1$ + //replace space by underscore + guard = guard.replace(SourceConstants.SPACE, SourceConstants.UNDERSCORE); + //replace ampersant by REF + guard = guard.replace(AMPERSANT, REF); + //replace ( by OBR + guard = guard.replace(OPEN_BRACKET, BEGINCAST); + //replace ) by CBR + guard = guard.replace(CLOSING_BRACKET, ENDCAST); + } else { + throw new IOException(Messages.getString("TraceHeader.internalError3")); //$NON-NLS-1$ + } + + guard = SourceConstants.DOUBLE_UNDERSCORE + + functionName.toUpperCase() + + SourceConstants.UNDERSCORE + + guard.toUpperCase() + + SourceConstants.DOUBLE_UNDERSCORE; + + ostTraceGenxFunGuard = guard; + write( SourceConstants.IFNDEF + SourceConstants.SPACE_CHAR + ostTraceGenxFunGuard); + write(SourceConstants.LINE_FEED); + write( SourceConstants.DEFINE +SourceConstants.SPACE_CHAR + ostTraceGenxFunGuard); + write(SourceConstants.LINE_FEED); + write(SourceConstants.LINE_FEED); + } + + /** + * write end of function guard + * @throws IOException + */ + private void writeEndFunctionGuard() throws IOException { + if (ostTraceGenxFunGuard != null) { + write(SourceConstants.LINE_FEED); + write(SourceConstants.LINE_FEED); + write(SourceConstants.ENDIF + + SourceConstants.SPACE_CHAR + + SourceConstants.FORWARD_SLASH_CHAR + + SourceConstants.FORWARD_SLASH_CHAR + + SourceConstants.SPACE_CHAR + + ostTraceGenxFunGuard); + write(SourceConstants.LINE_FEED); + } + } + /** + * Writes the function body to the stream + * + * @param trace + * the trace to be written + * @throws IOException + * if writing fails + */ + private void writeFunctionBody(Trace trace) throws IOException { + writeTraceBufferAllocation(trace); + writeTemplate(HeaderTemplate.PARAMETERS_TEMPLATE); + // If buffer is not used (single descriptor parameter), trace line is + // already written in template + if (isTraceBufferBuilt()) { + writeTraceLine(trace); + } + } + + /** + * Writes trace buffer allocation code to the function + * + * @param trace + * the trace to be written + * @throws IOException + * if writing fails + */ + private void writeTraceBufferAllocation(Trace trace) throws IOException { + // If buffer is not used (single descriptor parameter), this function + // does nothing + if (isTraceBufferBuilt()) { + Iterator parameters = trace.getParameters(); + lenghtVariableDefined = false; + int fixedSizeParametersTotalSize = 0; + while (parameters.hasNext()) { + TraceParameter parameter = parameters.next(); + TraceParameterFormattingRule sourceRule = parameter + .getExtension(TraceParameterFormattingRule.class); + if (sourceRule == null || sourceRule.isShownInSource() + || sourceRule instanceof FillerParameterRule) { + // Fillers do not increment parameter index + if (!(sourceRule instanceof FillerParameterRule)) { + currentParameterIndex++; + } + int paramSize = SourceUtils + .mapParameterTypeToSize(parameter); + // calculateParameterSize returns 0 for dynamic parameters, + // but 4 extra bytes need to be reserved for the length + if (paramSize == 0) { + paramSize = BYTES_IN_PARAMETER; + } + fixedBufferSize += paramSize; + fixedSizeParametersTotalSize += paramSize; + if (SourceUtils.isParameterSizeDynamic(parameter)) { + + // Define length variable only once + if (lenghtVariableDefined == false) { + writeTemplate(HeaderTemplate.LENGTH_VARIABLE_DEFINITION_TEMPLATE); + lenghtVariableDefined = true; + } + + // Increase length variable if needed + // This is needed in case that there has been fixed size + // parameter + // before dynamic parameter + if (fixedSizeParametersTotalSize - paramSize > 0) { + fixedSizeParametersTotalSize -= paramSize; + writeTemplate(HeaderTemplate.LENGTH_VARIABLE_INCREASE_TEMPLATE_BEGIN); + write(String.valueOf(fixedSizeParametersTotalSize)); + writeTemplate(HeaderTemplate.LENGTH_VARIABLE_INCREASE_TEMPLATE_END); + } + + fixedSizeParametersTotalSize = 0; + + writeTemplate(HeaderTemplate.DYNAMIC_PARAMETER_LENGTH_TEMPLATE); + dynamicBufferSizeFlag = true; + } + } + } + writeTemplate(HeaderTemplate.BUFFER_ALLOCATION_TEMPLATE); + currentParameterIndex = 0; + } + } + + /** + * Writes the given parameter to the header + * + * @param parameter + * the parameter + * @throws IOException + * if writing fails + */ + void writeParameter(TraceParameter parameter) throws IOException { + TraceParameterFormattingRule sourceRule = parameter + .getExtension(TraceParameterFormattingRule.class); + if (sourceRule == null || sourceRule.isShownInSource() + || sourceRule instanceof FillerParameterRule) { + String paramType = SourceUtils + .mapParameterTypeToSymbianType(parameter); + if (SourceUtils.isParameterSizeDynamic(parameter)) { + currentParameterIndex++; + currentParameterName = SymbianConstants.PARAMETER_DECLARATION_PREFIX + + currentParameterIndex; + writeTemplate(HeaderTemplate.DYNAMIC_PARAMETER_TEMPLATE); + } else { + currentParameterType = paramType; + if (sourceRule instanceof FillerParameterRule) { + currentParameterName = "0"; //$NON-NLS-1$ + writeTemplate(HeaderTemplate.FIXED_PARAMETER_TEMPLATE); + } else { + currentParameterIndex++; + currentParameterName = SymbianConstants.PARAMETER_DECLARATION_PREFIX + + currentParameterIndex; + if (lenghtVariableDefined == true) { + writeTemplate(HeaderTemplate.FIXED_PARAMETER_TEMPLATE_WITH_LENGTH_CHECK); + } else { + writeTemplate(HeaderTemplate.FIXED_PARAMETER_TEMPLATE); + } + } + } + } + } + + /** + * Writes the trace line to the function + * + * @param trace + * the trace to be written + * @throws IOException + * if writing fails + */ + private void writeTraceLine(Trace trace) throws IOException { + StringBuffer sb; + StringBuffer bufferData = new StringBuffer(); + StringBuffer lengthData = new StringBuffer(); + if (isBufferSizeDynamic()) { + sb = writeBufferedTraceLine(trace, bufferData, lengthData); + } else { + // If buffer size is 4, the buffer can be traced using the + // the 32-bit parameter trace macro instead of data macro + if (fixedBufferSize / BYTES_IN_PARAMETER == 1) { + sb = writePackedTraceLine(trace, bufferData); + } else { + sb = writeBufferedTraceLine(trace, bufferData, lengthData); + } + } + int index = sb.indexOf(TraceFormatConstants.DATA_BUFFER_FORMAT); + if (index >= 0) { + sb.replace(index, index + + TraceFormatConstants.DATA_BUFFER_FORMAT.length(), + bufferData.toString()); + } + index = sb.indexOf(TraceFormatConstants.DATA_LENGTH_FORMAT); + if (index >= 0) { + sb.replace(index, index + + TraceFormatConstants.DATA_LENGTH_FORMAT.length(), + lengthData.toString()); + } + String s = sb.toString(); + write("retval = "); //$NON-NLS-1$ + writeFormattedTrace(s); + writeNewLine(); + } + + /** + * Writes a trace line when the parameters can be fitted into a direct API + * call + * + * @param trace + * the trace + * @param bufferData + * the buffer + * @return formatted trace + */ + private StringBuffer writePackedTraceLine(Trace trace, + StringBuffer bufferData) { + StringBuffer sb; + // The formatting rule is used to get the API macro + sb = new StringBuffer(SourceFormatter.formatTrace(trace, + TraceFormatType.TRACE_PACKED)); + TraceFormattingRule rule = trace + .getExtension(TraceFormattingRule.class); + if (rule == null) { + rule = trace.getModel().getExtension(TraceFormattingRule.class); + } + int index = sb.indexOf(TraceFormatConstants.PARAM_COUNT_FORMAT); + if (index >= 0) { + // Single parameter is supported + sb.replace(index, index + + TraceFormatConstants.PARAM_COUNT_FORMAT.length(), rule + .mapParameterCountToSource(trace, 1)); + } + bufferData.append("*( ( TUint32* )ptr )"); //$NON-NLS-1$ + return sb; + } + + /** + * Writes a trace line when the trace contains more data that the API + * supports + * + * @param trace + * the trace + * @param bufferData + * the trace buffer + * @param lengthData + * the trace length buffer + * @return the formatted trace + */ + private StringBuffer writeBufferedTraceLine(Trace trace, + StringBuffer bufferData, StringBuffer lengthData) { + StringBuffer sb; + // Buffer parameter + // *( ( TUint32* )ptr ), *( ( TUint32* )( ptr + 4 ) ), ..., ptr + x + sb = new StringBuffer(SourceFormatter.formatTrace(trace, + TraceFormatType.TRACE_BUFFER)); + if (isTraceBufferBuilt()) { + bufferData.append("ptr"); //$NON-NLS-1$ + if (isBufferSizeDynamic()) { + // In case of dynamic buffer, the length has been calculated + // into length variable + lengthData.append("length"); //$NON-NLS-1$ + } else { + // Fixed size case + lengthData.append(String.valueOf(fixedBufferSize)); + } + } else { + // In case of no-buffer, the size variable contain the data size + bufferData.append("ptr"); //$NON-NLS-1$ + lengthData.append("size"); //$NON-NLS-1$ + } + return sb; + } + + /** + * Writes a formatted trace to the stream. This removes the newline from the + * trace if it exists + * + * @param trace + * the trace + * @throws IOException + * if writing fails + */ + private void writeFormattedTrace(String trace) throws IOException { + if (trace.endsWith(SourceConstants.LINE_FEED)) { + write(trace.substring(0, trace.length() + - SourceConstants.LINE_FEED.length())); + } else { + write(trace); + } + } + + /** + * Increases indent and writes a new line, brace, new line combination + * + * @throws IOException + * if writing fails + */ + private void writeOpenBrace() throws IOException { + openBraceCount++; + writeNewLine(); + write(SourceConstants.OPENING_BRACE); + writeNewLine(); + } + + /** + * Write brace, decreases indent and writes a new line + * + * @throws IOException + * if writing fails + */ + private void writeCloseBrace() throws IOException { + write(SourceConstants.CLOSING_BRACE); + openBraceCount--; + writeNewLine(); + } + + /** + * write licence Text + * @throws IOException if write fails + */ + private void writeLicence() throws IOException { + String licence = null; + SourceParser parser = null; + //first get any of the traces belonging to this header + TraceModel model = header.getOwner().getModel(); + for (TraceGroup group : model) { + for (Trace trace : group) { + Iterator itr = trace.getExtensions(LocationListBase.class); + // The trace must have at least one location that belong to this header + while (itr.hasNext() && parser == null) { + LocationListBase list = itr.next(); + for (LocationProperties loc : list) { + if (isValidTraceForHeader(loc.getFileName())) { + parser = ((TraceLocation)loc).getParser(); + break; + } + } + } + if (parser!= null) { + break; + } + } + if (parser != null) { + break; + } + } + + if (parser!= null) { + List excludedAreas = parser.getExcludedAreas(); + //try to find licence from the source + if (!excludedAreas.isEmpty()) { + SourceExcludedArea sourceExcludedArea = excludedAreas.get(0); + int offset = sourceExcludedArea.getOffset(); + int type = sourceExcludedArea.getType(); + int length = sourceExcludedArea.getLength(); + if (offset == 0 && type == SourceExcludedArea.MULTILINE_COMMENT) { + String data = sourceExcludedArea.getParser().getData(offset, length); + if (data.contains("Copyright")) { //$NON-NLS-1$ + // licence found write it + TraceCompilerLogger.printInfo("Add Licence text from: " + sourceExcludedArea.getFileName() + " to : " + header.getAbsolutePath()); //$NON-NLS-1$ + licence = data; + write(licence); + } + } + } + } + + if (licence == null) { + //get default licence from the licence file + licence = TraceCompilerEngineGlobals.getDefaultLicence(true); + + if(licence != null) { + TraceCompilerLogger.printInfo("Add default EPL Licence to : " + header.getAbsolutePath()); //$NON-NLS-1$ + write(licence); + } + } + } + + /** + * Writes a new line and indent to the stream + * + * @throws IOException + * if writing fails + */ + private void writeNewLine() throws IOException { + int newLines = newLineCount; + while (newLines < maxNewLines) { + write(SourceConstants.LINE_FEED); + for (int i = 0; i < openBraceCount; i++) { + write(INDENT); + } + newLines++; + } + newLineCount = maxNewLines; + } + + /** + * Writes a define to stream + * + * @param name + * the name for the define + * @throws IOException + * if writing fails + */ + private void writeDefine(String name) throws IOException { + write(SourceConstants.DEFINE); + write(SourceConstants.SPACE); + write(name); + writeNewLine(); + } + + /** + * Writes include to header + * + * @param name + * the header name + * @throws IOException + * if writing fails + */ + private void writeSystemInclude(String name) throws IOException { + write(SourceConstants.INCLUDE); + write(SourceConstants.SPACE); + write("<"); //$NON-NLS-1$ + write(name); + write(">"); //$NON-NLS-1$ + writeNewLine(); + } + + /** + * Writes data to a stream + * + * @param data + * the string of data + * @throws IOException + * if writing fails + */ + private void write(String data) throws IOException { + // Check if function starts + if (data.contains(INLINE_TBOOL) || bufferingFunction) { + bufferingFunction = true; + functionText.append(data); + } else { + headerOutput.write(data.getBytes()); + } + newLineCount = 0; + + //try to duplicate function if the current function processing is complete and duplicate is needed. + writeAndDuplicateFunction(data); + } + + /** + * Duplicates the function if needed + * + * @param data + * data String + * @throws IOException + * if writing fails + */ + private void writeAndDuplicateFunction(String data) throws IOException { + // This assumes there is only one start or end bracket in one line! + if (data.contains(SourceConstants.OPENING_BRACE)) { + firstOpenBraceFound = true; + numberOfBrackets++; + } else if (data.contains(SourceConstants.CLOSING_BRACE)) { + numberOfBrackets--; + + // Function ends + if (numberOfBrackets == 0 && firstOpenBraceFound) { + firstOpenBraceFound = false; + bufferingFunction = false; + //write start function guard + writeStartFunctionGuard(); + //write the function + headerOutput.write(functionText.toString().getBytes()); + //write end function guard + writeEndFunctionGuard(); + + //process duplicate if needed + // Get the function definition line + int startIndex = functionText.indexOf(SourceConstants.OPENING_BRACE); + String funcDef = functionText.substring(0, startIndex); + + // Replace TInt with TInt32 and TUint with TUint32 from the + // header and write the function back again + if (funcDef.contains(TINT_DEF) + || funcDef.contains(TUINT_DEF)) { + //replace and duplicate + funcDef = funcDef.replace(TINT_DEF, TINT32_DEF); + funcDef = funcDef.replace(TUINT_DEF, TUINT32_DEF); + functionText.replace(0, startIndex, funcDef); + + //write start function guard for duplicate + write(SourceConstants.LINE_FEED); + write(SourceConstants.LINE_FEED); + writeStartFunctionGuard(); + + //write duplicate function + headerOutput.write(functionText.toString().getBytes()); + + //write end function guard for duplicate + writeEndFunctionGuard(); + } + + functionText.setLength(0); + } + } + } + + /** + * Checks if a trace needs a buffer or it can be represented with regular + * trace macros. + * + * @param trace + * the trace + * @return true if trace needs a buffer + */ + private boolean traceNeedsBuffer(Trace trace) { + // A single dynamic parameter can be passed through the regular + // API macros. In that case the parameter length is determined + // by the trace message length + Iterator parameters = trace.getParameters(); + boolean needsBuffer = false; + boolean dynamicFound = false; + while (parameters.hasNext() && !needsBuffer) { + TraceParameter parameter = parameters.next(); + if (isParameterVisible(parameter)) { + if (SourceUtils.isParameterSizeDynamic(parameter)) { + if (dynamicFound) { + needsBuffer = true; + } else { + dynamicFound = true; + } + } else { + needsBuffer = true; + } + } + } + return needsBuffer; + } + + /** + * Checks if a parameter is visible + * + * @param parameter + * the parameter to be checked + * @return true if visible, false if not + */ + private boolean isParameterVisible(TraceParameter parameter) { + boolean retval; + TraceParameterFormattingRule sourceRule = parameter + .getExtension(TraceParameterFormattingRule.class); + if (sourceRule == null || sourceRule.isShownInSource()) { + retval = true; + } else { + retval = false; + } + return retval; + } + + /** + * Gets the formatted trace + * + * @return the trace + */ + String getCurrentTraceFormatted() { + return currentTraceFormatted; + } + + /** + * Checks if trace is already formatted to header + * + * @return true if formatted + */ + boolean isTraceFormatDuplicate() { + boolean retval; + if (traceDeclarations.contains(currentTraceFormatted)) { + retval = true; + } else { + traceDeclarations.add(currentTraceFormatted); + retval = false; + } + return retval; + } + + /** + * Checks if the buffer size for current trace is fixed + * + * @return the flag + */ + boolean isTraceBufferFixed() { + return fixedBufferSize != 0; + } + + /** + * Checks if the buffer is built + * + * @return the flag + */ + boolean isTraceBufferBuilt() { + return buildTraceBuffer; + } + + /** + * Gets the current trace + * + * @return the trace + */ + Trace getCurrentTrace() { + return currentTrace; + } + + /** + * Gets the header + * + * @return the header + */ + TraceHeader getHeader() { + return header; + } + + /** + * Starts writing a trace + * + * @param trace + * the trace + * @return true if trace can be written, false if not + */ + boolean startTrace(Trace trace) { + boolean validTrace = false; + Iterator itr = trace + .getExtensions(LocationListBase.class); + // The trace must have at least one location that belong to this header + while (itr.hasNext() && !validTrace) { + LocationListBase list = itr.next(); + for (LocationProperties loc : list) { + validTrace = isValidTraceForHeader(loc.getFileName()); + if (validTrace) { + break; + } + } + } + if (validTrace) { + currentTrace = trace; + fixedBufferSize = 0; + dynamicBufferSizeFlag = false; + buildTraceBuffer = false; + currentTraceFormatted = null; + currentParameterName = null; + currentParameterType = null; + currentParameterIndex = 0; + } + return validTrace; + } + + /** + * Checks if the location belongs to this header + * + * @param locFileName + * the location + * @return true if location belongs here + */ + private boolean isValidTraceForHeader(String locFileName) { + boolean valid = false; + if (locFileName != null) { + int index = locFileName.lastIndexOf('.'); + if (index >= 0) { + locFileName = locFileName.substring(0, index); + } + if (locFileName.equals(header.getProjectName())) { + valid = true; + } + } + return valid; + } + + /** + * Starts writing a parameter + * + * @param parameter + * the parameter + */ + void startParameter(TraceParameter parameter) { + currentParameterName = null; + currentParameterType = null; + currentParameter = parameter; + } + + /** + * Sets the kernel mode #endif needed flag + * + * @param flag + * the flag + */ + void setKernelModeEndifNeeded(boolean flag) { + needsKernelEndif = flag; + } + + /** + * Gets the kernel mode endif needed flag + * + * @return the flag + */ + boolean isKernelModeEndifNeeded() { + return needsKernelEndif; + } + + /** + * Returns the dynamic buffer size flag + * + * @return true if buffer size is dynamic + */ + boolean isBufferSizeDynamic() { + return dynamicBufferSizeFlag; + } + + /** + * Checks if current parameter needs alignment + * + * @return true if needed + */ + boolean isParameterAlignmentNeeded() { + return SourceUtils.isParameterAlignementNeeded(currentParameter + .getType()); + } + +}