--- /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<String> traceDeclarations = new ArrayList<String>();
+
+ /**
+ * 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<? extends TemplateCheckBase> 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<? extends TemplateIteratorEntry> 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<String> 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<String> getContributions(TraceHeaderContributionType type) {
+ Iterator<TraceHeaderContribution> contributions = header.getOwner()
+ .getExtensions(TraceHeaderContribution.class);
+ ArrayList<String> list = new ArrayList<String>();
+ 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<TraceParameter> 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<LocationListBase> 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<SourceExcludedArea> 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<TraceParameter> 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<LocationListBase> 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());
+ }
+
+}