You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by ha...@apache.org on 2004/09/20 18:09:59 UTC
cvs commit: ws-axis/c/tools/trace/org/apache/axis/tracetool AddEntryAndExitTrace.java BodyPart.java Exclusions.java FilePart.java InputCppSourceCode.java MacroPart.java MethodPart.java Parameter.java ParsingException.java Signature.java Tracer.java Utils.java
hawkeye 2004/09/20 09:09:58
Added: c/tools/trace/org/apache/axis/tracetool
AddEntryAndExitTrace.java BodyPart.java
Exclusions.java FilePart.java
InputCppSourceCode.java MacroPart.java
MethodPart.java Parameter.java
ParsingException.java Signature.java Tracer.java
Utils.java
Log:
Create first version of trace entry/exit instrumentation tool
Revision Changes Path
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/AddEntryAndExitTrace.java
Index: AddEntryAndExitTrace.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* This class adds entry and exit trace to the directories given to it
* It works on any C++ file or directory. It contains a main program:-
*
* usage: Java AddEntryAndExitTrace startingDirectory
*/
public class AddEntryAndExitTrace {
public static boolean verbose = false;
public static boolean quiet = false;
private Tracer outputFile = null;
private final static Set extensions =
new HashSet(Arrays.asList(new Object[] { "cpp", "hpp", "c", "h" }));
private AddEntryAndExitTrace() {
}
/**
* Starts adding trace into the given file.
* If the given file is a directory then this the starting directory and all
* code beneath and in this directory will be given trace.
* @param startingFile - either the starting directory or one file to add trace to.
*/
private void addTrace(File startingFile, int depth) throws Exception {
depth++;
if (startingFile.isDirectory()) {
File[] filesInDirectory = startingFile.listFiles();
for (int i = 0; i < filesInDirectory.length; i++) {
File file = filesInDirectory[i];
String name = file.getName();
int dot = name.lastIndexOf('.');
String ext = null;
if (-1 != dot)
ext = name.substring(dot + 1);
if (file.isDirectory())
// recurse
addTrace(file, depth);
else if (
file.isFile()
&& !file.isHidden()
&& extensions.contains(ext))
// this is a file and we need to add trace into it !
addEntryAndExitTrace(file, depth);
}
} else {
addEntryAndExitTrace(startingFile, depth);
}
}
/**
* This method adds entry and exit trace to the given file. It farms out most of the work to
* other objects but it is the key orchestrator of the work.
*
* @param file the file to add trace to
*/
private void addEntryAndExitTrace(File file, int depth) throws Exception {
if (Exclusions.shouldTraceFile(file.getName())) {
String filename = file.toString();
outputDebugString("parsing " + filename + "...");
String backup = filename + ".back";
file.renameTo(new File(backup));
file = new File(backup);
// we'll put the new file into a tmp file for now so we don't
// screw things up
// TODO: this file should be a tmp file but for now rename
// so it's easier to find
File tracedFile = new File(filename);
// create a tracer to the output file
outputFile = new Tracer(new FileWriter(tracedFile), depth);
// OK, now we have the output file let's read in the input file !
FileReader fr = new FileReader(file);
BufferedReader inputFile = new BufferedReader(fr);
try {
parseFile(
new InputCppSourceCode(inputFile, file.getName()),
outputFile);
} catch (ParsingException pe) {
// TODO: clean up the output file here
}
outputFile.flush();
outputFile.close();
inputFile.close();
} else {
System.out.println("excluding file " + file);
}
}
/**
* Parses the given file and adds trace to it, placing the newly traced code
* into the outputfile
*
* @param inputFile the input file reader
* @param outputFile the output file writer
* @throws IOException if htere is a problem dealing with the files.
*/
private void parseFile(InputCppSourceCode inputFile, Tracer outputFile)
throws IOException, ParsingException {
Iterator it = inputFile.getPartIterator();
while (it.hasNext()) {
FilePart fp = (FilePart) (it.next());
if (fp.getType() == FilePart.METHOD) {
MethodPart mp = (MethodPart) fp;
outputFile.write(mp.getOriginalSignature() + "{");
outputFile.traceEntry(mp.getSignature());
BodyPart[] bps = mp.getBodyParts();
for (int i = 0; i < bps.length; i++) {
outputFile.write(bps[i].getCodeFragment());
if (bps[i].getReturnValue() != null)
outputFile.traceExit(bps[i].getReturnValue());
else if (i < bps.length - 1)
outputFile.traceExit();
}
} else {
outputFile.write(fp.toString());
}
}
}
public static void main(String[] args) {
if (0 == args.length) {
printUsage();
System.exit(-1);
}
int idx = 0;
if ("-v".equals(args[0])) {
verbose = true;
idx = 1;
} else if ("-q".equals(args[0])) {
quiet = true;
idx = 1;
}
// check that a filename was given
if (args.length < idx + 1) {
printUsage();
System.exit(-1);
}
File startFile = new File(args[idx]);
if (!startFile.isFile() && !startFile.isDirectory()) {
printUsage();
System.exit(-2);
}
// OK, go for it !
AddEntryAndExitTrace tracer = new AddEntryAndExitTrace();
try {
tracer.addTrace(startFile, 0);
} catch (Exception exception) {
exception.printStackTrace();
} finally {
outputDebugString("Finished!");
}
}
private static void printUsage() {
System.out.println(
"usage: Java AddEntryAndExitTrace startingDirectory");
}
private static void outputDebugString(String line) {
if (!quiet) {
if (verbose)
System.out.println();
System.out.println(line);
}
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/BodyPart.java
Index: BodyPart.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
/**
* A snippet of C or C++ source code. If this snippet ends with a return
* statement, this body part also contains the return value.
*/
public class BodyPart {
String codeFragment;
String returnValue = null;
BodyPart(String cf, String rv) {
codeFragment = cf;
if (null != rv && !Utils.isSpace(rv))
returnValue = rv;
}
String getCodeFragment() {
return codeFragment;
}
String getReturnValue() {
if (returnValue != null)
return returnValue.trim();
else
return null;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/Exclusions.java
Index: Exclusions.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Exclusions {
private final static Set badFiles =
new HashSet(Arrays.asList(new Object[] {
// Tool fails on these files
"Url.cpp",
"libAxiscpp.cpp",
"cpplex.cpp",
"cppyacc.cpp",
"asciitab.h",
"iasciitab.h",
"latin1tab.h",
"spp_converter.h",
"utf8tab.h",
"SoapBinInputStream.h",
"SoapInputSource.h",
"XMLParserXerces.h",
"apr_base64.c",
"apr_base64.h",
"apr_xlate.h",
//Don't trace trace
"AxisTrace.cpp", "AxisTrace.h", "GDefine.h", "AxisFile.h" }));
static boolean shouldTraceFile(String s) {
return !badFiles.contains(s);
}
// TODO: needs implementing
static boolean shouldTraceClass(String s) {
return true;
}
// TODO: needs implementing
static boolean shouldTraceMethod(String className, String method) {
return true;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/FilePart.java
Index: FilePart.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
/**
* A piece of C++ source code
*/
class FilePart {
final static int UNKNOWN = 0;
final static int COMMENT = 1;
final static int METHOD = 2;
final static int FIELD = 3;
final static int BEGINSCOPE = 4;
final static int ENDSCOPE = 5;
final static int DIRECTIVE = 6;
final static int WHITESPACE = 7;
final static int MACRO = 8;
final static int CLASSATTRIBUTE = 9;
final static int ENUM = 10;
protected String cppsource;
protected int type;
FilePart(String s, int type) {
cppsource = s;
this.type = type;
}
int getType() { return type; }
int length() {
return cppsource.length();
}
public String toString() {
return cppsource;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/InputCppSourceCode.java
Index: InputCppSourceCode.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;
class InputCppSourceCode {
private ArrayList parts = new ArrayList();
private String name;
InputCppSourceCode(BufferedReader br, String name) throws Exception {
this.name = name;
String s = null;
StringBuffer buff = new StringBuffer();
for (int i=1; ; i++) {
try {
s = br.readLine();
} catch (Exception e) {
System.err.println(
"Ignoring exception thrown parsing file "
+ name
+ " line number "
+ i);
e.printStackTrace();
break;
}
if (s == null)
break;
buff.append(s + "\n");
}
String str = buff.toString();
// TODO: When checking for rest.startsWith("struct") should
// check the next letter after struct is not alphanumeric otherwise
// we'll get false matches on a function called structify() for
// instance. Also applies to enum, union, public, typedef, etc
String rest, text = "";
int scopedepth = 0;
for (int idx = 0; idx < str.length(); /* No idx++ */
) {
rest = str.substring(idx);
if (Utils.isSpace(rest.charAt(0))) {
int ridx = 0;
while (ridx < rest.length()
&& Utils.isSpace(rest.charAt(ridx)))
ridx++;
text = rest.substring(0, ridx);
FilePart fp = new FilePart(text, FilePart.WHITESPACE);
parts.add(fp);
idx += ridx;
} else if (rest.startsWith("/*")) {
int ridx = rest.indexOf("*/"); // Don't use Utils here
text = str.substring(idx, idx + ridx + 2);
FilePart fp = new FilePart(text, FilePart.COMMENT);
parts.add(fp);
idx += text.length();
} else if (rest.startsWith("//")) {
text = str.substring(idx, idx + rest.indexOf("\n"));
FilePart fp = new FilePart(text, FilePart.COMMENT);
parts.add(fp);
idx += text.length();
} else if (rest.startsWith("#")) {
int ridx = rest.indexOf("\n");
char c = rest.charAt(ridx - 1);
while (-1 != ridx && '\\' == c) {
String rest2 = rest.substring(ridx + 1);
ridx += rest2.indexOf("\n") + 1;
c = rest.charAt(ridx - 1);
}
text = str.substring(idx, idx + ridx);
FilePart fp = new FilePart(text, FilePart.DIRECTIVE);
parts.add(fp);
idx += text.length();
} else if (rest.startsWith("}")) {
if (scopedepth <= 0)
Utils.rude(
"Braces do not match",
name,
lineNo(str, idx),
rest.substring(0, rest.indexOf("\n")));
else
scopedepth--;
parts.add(new FilePart("}", FilePart.ENDSCOPE));
idx++;
} else if (rest.startsWith(";")) {
parts.add(new FilePart(";", FilePart.FIELD));
idx++;
} else if (
!Utils.startsWithALetter(rest) && '~' != rest.charAt(0)) {
Utils.rude(
"Lines must start with a letter ",
name,
lineNo(str, idx),
rest.substring(0, rest.indexOf("\n")));
} else if (MacroPart.isAMacro(rest)) {
MacroPart mp = MacroPart.create(rest);
parts.add(mp);
idx += mp.length();
} else if (beginsScope(rest)) {
scopedepth++;
text = rest.substring(0, Utils.indexOf(rest, "{") + 1);
FilePart fp = new FilePart(text, FilePart.BEGINSCOPE);
parts.add(fp);
idx += text.length();
} else if (isEnumOrUnion(rest)) {
int ridx = Utils.findMatching(rest, '{', '}') + 1;
String rest2 = rest.substring(ridx);
ridx = idx + ridx + Utils.indexOf(rest2, ';') + 1;
text = str.substring(idx, ridx);
FilePart fp = new FilePart(text, FilePart.ENUM);
parts.add(fp);
idx += text.length();
} else if (
scopedepth > 0
&& (rest.startsWith("public")
|| rest.startsWith("protected")
|| rest.startsWith("private"))) {
int colon = rest.indexOf(":");
if (-1 == colon)
Utils.rude(
"No colon found after public or private ",
name,
lineNo(str, idx),
rest.substring(0, rest.indexOf("\n")));
text = str.substring(idx, idx + colon + 1);
FilePart fp = new FilePart(text, FilePart.CLASSATTRIBUTE);
parts.add(fp);
idx += text.length();
} else if (Utils.startsWith(rest, "typedef")) {
int semicolon = Utils.indexOf(rest, ';');
int brace = Utils.indexOf(rest, '{');
if (-1 == semicolon)
Utils.rude(
"No semicolon found after typedef",
name,
lineNo(str, idx),
rest.substring(0, rest.indexOf("\n")));
if (-1 == brace || semicolon < brace) {
// Simple typedef
text = str.substring(idx, idx + semicolon);
} else {
// Typedef of a struct, etc
int endbrace = Utils.findMatching(rest, '{', '}');
String rest2 = rest.substring(endbrace);
semicolon = Utils.indexOf(rest2, ';');
text = str.substring(idx, idx + endbrace + semicolon + 1);
}
FilePart fp = new FilePart(text, FilePart.FIELD);
parts.add(fp);
idx += text.length();
} else {
if (isMethod(rest)) {
int brace = Utils.indexOf(rest, '{');
Signature signature =
new Signature(str.substring(idx, idx + brace));
if (signature.failed())
Utils.rude(
"Signature parsing failed",
name,
lineNo(str, idx),
signature.getOriginal());
String body = rest.substring(brace);
int endBrace = Utils.findMatching(body, '{', '}');
body = body.substring(0, endBrace + 1);
int endIdx =
idx + signature.originalLength() + body.length();
text = str.substring(idx, endIdx);
MethodPart mp =
new MethodPart(text, FilePart.METHOD, signature, body);
parts.add(mp);
idx += text.length();
} else if (isField(rest)) {
int semicolon = Utils.indexOf(rest, ';');
text = str.substring(idx, idx + semicolon + 1);
FilePart fp = new FilePart(text, FilePart.FIELD);
parts.add(fp);
idx += text.length();
} else {
//TODO other file parts here - not sure if there are any others?
Utils.rude(
"Unrecognised file part",
name,
lineNo(str, idx),
rest.substring(0, rest.indexOf("\n")));
} // end if
} // end if
} // end for
}
Iterator getPartIterator() {
return parts.iterator();
}
private int lineNo(String s, int idx) {
int n = 0;
for (int i = 0; i < idx && i < s.length(); i++)
if ('\n' == s.charAt(i))
n++;
return n;
}
/**
* Find out whether we are defining a class, struct or extern "C" which
* may contain function implementations. These will have braces which
* begin a new scope. Ignore function prototypes that return a struct.
* struct mystr { int f1; };
* struct mystr func();
* struct mystr func() { struct mystr a; return a; }
*/
private static boolean beginsScope(String s) throws ParsingException {
if (isMethod(s))
return false;
if (Utils.startsWith(s, "class"))
return true;
if (Utils.startsWith(s, "struct")) {
int brace = Utils.indexOf(s, '{');
int semicolon = Utils.indexOf(s, ';');
if (-1 == brace || -1 == semicolon)
return false;
return brace < semicolon;
}
return startsWithExternScope(s);
}
/**
* There are 4 types of extern ...
* extern int field;
* extern int func();
* extern "C" int func() { return 2; }
* extern "C" { int func() { return 2; } }
* This method should return true only for the last of these three
* examples since only the last one creates a new scope using braces.
*/
private static boolean startsWithExternScope(String s)
throws ParsingException {
if (!s.startsWith("extern"))
return false;
int brace = Utils.indexOf(s, '{');
int semicolon = Utils.indexOf(s, ';');
int bracket = Utils.indexOf(s, '(');
if (-1 == brace)
return false;
return (-1 == semicolon || brace < semicolon)
&& (-1 == bracket || brace < bracket);
}
/**
* Find out whether we are defining an enum or union which will contain
* braces. Ignore function prototypes that return an enum or union.
* enum colour { red, blue };
* enum colour func();
* enum colour func() { return colour.red; }
*/
private static boolean isEnumOrUnion(String s) throws ParsingException {
if ((!Utils.startsWith(s, "enum") && !Utils.startsWith(s, "union"))
|| isMethod(s))
return false;
int brace = Utils.indexOf(s, '{');
int semicolon = Utils.indexOf(s, ';');
return -1 != brace && (-1 == semicolon || brace < semicolon);
}
/**
* Rules to recognise fields and methods...
*
* Fields must contain a semicolon
* Methods may or may not contain a semicolon
* Fields may or may not contain a brace (array initialisers do)
* Methods must contain a brace
* Fields may or may not contain a bracket (casts do)
* Methods must contain a bracket
*
* It's a method if it contains a bracket and then a brace
* before the first semicolon (if there is a semicolon).
* It's a field if it's not a method and it contains a semicolon.
* If it's not a field or a method and we haven't recognised it
* previously then it's an error.
*/
private static boolean isMethod(String s) throws ParsingException {
int semicolon = Utils.indexOf(s, ';');
int brace = Utils.indexOf(s, '{');
int bracket = Utils.indexOf(s, '(');
return (
-1 != bracket
&& -1 != brace
&& bracket < brace
&& (-1 == semicolon || brace < semicolon));
}
private static boolean isField(String s) throws ParsingException {
int semicolon = Utils.indexOf(s, ';');
return !isMethod(s) && -1 != semicolon;
}
public String toString() {
StringBuffer text = new StringBuffer();
for (int i = 0; i < parts.size(); i++) {
text.append(((FilePart) (parts.get(i))).toString());
}
return text.toString();
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/MacroPart.java
Index: MacroPart.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
/**
* A C or C++ macro as it is used in the source code
* TODO This is a simple implementation that could be improved considerably.
* This implementation is just good enough for Axis C++.
*/
class MacroPart extends FilePart {
private final static Set knownDefines =
new HashSet(
Arrays.asList(
new Object[] {
"AXIS_CPP_NAMESPACE_START",
"AXIS_CPP_NAMESPACE_END",
"AXIS_CPP_NAMESPACE_USE",
"AXIS_CPP_NAMESPACE_PREFIX",
"TXPP_NAMESPACE_START",
"TXPP_NAMESPACE_END" }));
private final static Set knownMacros =
new HashSet(
Arrays.asList(
new Object[] {
"DEFINE_UTF16_TO_UTF8",
"DEFINE_UTF16_TO_UTF16" }));
/**
* Factory method to create a MacroPart.
* @param s unparsed source code which may start with a define or macro.
*/
static MacroPart create(String s) {
String orig = getOriginalText(s);
if (null == orig)
return null;
return new MacroPart(orig);
}
MacroPart(String s) {
super(s, FilePart.MACRO);
}
/**
* @param s unparsed source code which may start with a define or macro.
* @return all of s up to the end of the define or macro.
*/
private static String getOriginalText(String s) {
String name = getName(s);
int len = name.length();
if (null == name)
return null;
else if (knownDefines.contains(name)) {
return s.substring(0, len);
} else if (knownMacros.contains(name)) {
String rest = s.substring(len);
len += Utils.findMatching(rest, '(', ')');
return s.substring(0, len + 1);
} else
return null;
}
static boolean isAMacro(String s) {
if (s == null || 0 == s.length())
return false;
String name = getName(s);
return knownMacros.contains(name) || knownDefines.contains(name);
}
private static String getName(String s) {
int i;
for (i = 0; i < s.length(); i++)
if (!Utils.isAlphaNumeric(s.charAt(i)) && '_' != s.charAt(i))
break;
if (s.length() == i)
return null;
return s.substring(0, i);
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/MethodPart.java
Index: MethodPart.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.util.ArrayList;
/**
* A C or C++ method from a piece of source code. The method has a signature and
* a body (the bit between the braces).
*/
class MethodPart extends FilePart {
private Signature signature;
private String body;
MethodPart(String s, int type, Signature signature, String body) {
super(s, type);
this.signature = signature;
this.body = body;
}
Signature getSignature() {
return signature;
}
String getOriginalSignature() {
return signature.getOriginal();
}
/**
* Returns the method body as code snippets, each ending with a place
* where a trace statement belongs. The end of the first code snippet is
* where the entry trace should go. The end of every other snippet is
* a return from the method.
*/
BodyPart[] getBodyParts() throws ParsingException {
String b = body; // Don't alter field member
if (b.startsWith("{"))
b = b.substring(1);
// Add in trace exit at all the return statements in the method.
ArrayList al = new ArrayList();
int idx;
while (-1 != (idx = Utils.indexOf(b, "return"))) {
String frag = b.substring(0, idx);
String rest = b.substring(idx + "return".length());
String retVal = rest.substring(0, Utils.indexOf(rest, ';'));
BodyPart bp = new BodyPart(frag, retVal);
al.add(bp);
b = b.substring(idx + "return".length() + retVal.length() + 1);
}
// Add in trace exit before the last } if there are no returns in
// the method or there is code after the last return and the method
// returns void.
// int f1(){try{return f2();}catch(Exception& e){throw;}}
// has code after the last return but having a traceexit before the
// last brace wouldn't compile since the method returns an int. We
// cope with this by only adding in a traceexit before the last brace
// if the method returns void. That may mean we add in an unreachable
// traceexit which may give a compiler warning, but that should be
// benign.
//
// TODO: Not quite good enough for
// void f(int a){if(a){printf("a");}else{printf("!a");return;}}
// as a trace exit is needed before the last } in case a>0 but
// void f(int a){if(a){printf("a");return;}else{printf("!a");return;}}
// would give compiler warnings about unreachable code if a trace
// exit is added before the last brace. This could be tricky to fix.
if ((0 == al.size() || -1 != Utils.indexOf(b, ';'))
&& null == signature.getReturnType().getType()) {
int last = b.lastIndexOf('}');
String b2 = b.substring(0, last);
al.add(new BodyPart(b2, null));
b = b.substring(last);
}
// The final body part is the last }
al.add(new BodyPart(b, null));
BodyPart[] bps = new BodyPart[al.size()];
System.arraycopy(al.toArray(), 0, bps, 0, al.size());
return bps;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/Parameter.java
Index: Parameter.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.util.Iterator;
import java.util.List;
/**
* A parameter from a method signature. The parameter is the datatype plus its
* name but not its value.
*/
class Parameter {
private String type = null;
private String name = null;
private boolean failed = false;
Parameter(List parts) {
this(parts, false);
}
Parameter(List parts, boolean isRetType) {
if (parts == null || parts.size() == 0)
return;
if (!isRetType && parts.size() == 1) {
if (!"void".equals(parts.get(0)))
failed = true; // Seems like bad C++ code here
return;
}
if (isRetType) {
Iterator it = parts.iterator();
while (it.hasNext()) {
String next = (String) it.next();
if (null == type)
type = next;
else if ("*".equals(next) || "&".equals(next))
type += next;
else
type += " " + next;
}
// Some methods return have void on their signature and others
// have nothing. So to make them both the same, if a method
// doesn't return anything make type null.
if ("void".equals(type))
type = null;
} else {
// Keeping track of next and prev ensures we don't append the
// parameter name onto the type.
Iterator it = parts.iterator();
String next = null, prev = (String) it.next();
while (it.hasNext()) {
next = (String) it.next();
if (null == type)
type = prev;
else if ("*".equals(prev) || "&".equals(prev))
type += prev;
else
type += " " + prev;
prev = next;
}
name = next;
}
}
boolean failed() {
return failed;
}
String getType() {
return type;
}
String getName() {
return name;
}
boolean isVoid() {
return null == type;
}
public String toString() {
if (null == type)
return "void";
if (null == name)
return type;
return type + " " + name;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/ParsingException.java
Index: ParsingException.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
class ParsingException extends Exception {
public ParsingException() {
super();
}
public ParsingException(String message) {
super(message);
}
public ParsingException(String message, Throwable cause) {
super(message, cause);
}
public ParsingException(Throwable cause) {
super(cause);
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/Signature.java
Index: Signature.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* A C or C++ method signature
* TODO: support variable length argument lists using "..."
* TODO: passing or returning function pointers (hopefully not needed)
* TODO: Cope with ~<space>Classname()
*/
class Signature {
private String originalText;
private String attributes;
private String className = null;
private String methodName = null;
private Parameter returnType = null;
private Parameter[] params = null;
private String trailingAttributes;
private boolean failed = false;
private boolean traceable = true;
private final static Set knownAttrs =
new HashSet(
Arrays.asList(
new Object[] {
"public",
"private",
"extern",
"\"C\"",
"virtual" }));
private final static Set specialOperators =
new HashSet(Arrays.asList(new Object[] { "(", ")", "*", ",", "&" }));
// TODO: Should optionally pass in the className here in case it's an
// inline method implementation inside the class{}. Just so the className
// comes out in the trace.
Signature(String s) {
originalText = s;
try {
List tokens = tokenise(s);
ArrayList alAttrs = new ArrayList();
ArrayList alName = new ArrayList();
ArrayList alParms = new ArrayList();
ArrayList alTrailAttrs = new ArrayList();
ArrayList alInits = new ArrayList();
if (!splitUp(tokens,
alAttrs,
alName,
alParms,
alTrailAttrs,
alInits)) {
failed = true;
return;
}
parseAttributes(alAttrs);
parseNameAndRetType(alName);
parseParameters(alParms);
parseTrailingAttributes(alTrailAttrs);
// Ignore any tokens after the ) since these are (hopefully)
// constructor initialisers
traceable = Exclusions.shouldTraceMethod(className, methodName);
} catch (NullPointerException npe) {
failed = true;
traceable = false;
}
}
/**
* Parse the signature into tokens. This removes whitespace and comments
* and separates out "*", ",", "(", ")" and "&".
*/
private static List tokenise(String s) {
ArrayList tokens = new ArrayList();
String tok = null;
boolean space = true;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Utils.isSpace(c)) {
space = true;
continue;
}
if (space) {
if (tok != null)
tokens.add(tok);
tok = "" + c;
} else
tok += c;
space = false;
if (tok.endsWith("/*")) {
String sub = s.substring(i);
int endcomm = sub.indexOf("*/");
if (endcomm == -1)
break;
i += endcomm + 1;
if (tok.equals("/*"))
tok = "";
else
tok = tok.substring(0, tok.length() - 2);
continue;
}
if (tok.endsWith("//")) {
String sub = s.substring(i);
int endcomm = sub.indexOf("\n");
if (endcomm == -1)
break;
i += endcomm;
if (tok.equals("//"))
tok = "";
else
tok = tok.substring(0, tok.length() - 1);
continue;
}
if (tok.endsWith("::"))
space = true;
String sc = "" + c;
if (specialOperators.contains(sc)) {
if (!tok.equals(sc)) {
tokens.add(tok.substring(0, tok.length() - 1));
tok = sc;
}
space = true;
}
}
tokens.add(tok);
return tokens;
}
/**
* Split up a tokenised method signature into a list of attributes, a list of
* name and return type tokens, a list of parameter tokens and a list of
* initialiser tokens.
*/
private static boolean splitUp(
List tokens,
List attrs,
List nameAndRet,
List parms,
List trailAttrs,
List inits) {
int nameStart;
for (nameStart = 0; nameStart < tokens.size(); nameStart++)
if (!knownAttrs.contains(tokens.get(nameStart)))
break;
if (nameStart == tokens.size())
return false;
int initStart = tokens.size();
for (int i = nameStart; i < tokens.size(); i++)
if (((String) tokens.get(i)).startsWith(":")
&& !((String) tokens.get(i)).startsWith("::"))
initStart = i;
int parmEnd;
for (parmEnd = initStart - 1; parmEnd > nameStart; parmEnd--)
if (")".equals(tokens.get(parmEnd)))
break;
if (parmEnd == nameStart)
return false;
int parmStart = parmEnd;
for (parmStart = parmEnd; parmStart > nameStart; parmStart--)
if ("(".equals(tokens.get(parmStart)))
break;
for (int i = 0; i < tokens.size(); i++) {
Object tok = tokens.get(i);
if (i < nameStart)
attrs.add(tok);
else if (i < parmStart)
nameAndRet.add(tok);
else if (i <= parmEnd)
parms.add(tok);
else if (i < initStart)
trailAttrs.add(tok);
else
inits.add(tok);
}
return true;
}
private void parseAttributes(List list) {
attributes = new String();
Iterator it = list.iterator();
while (it.hasNext()) {
if (attributes.length() > 0)
attributes += " ";
attributes += (String) it.next();
}
}
private void parseNameAndRetType(List list) {
int size = list.size();
int idx;
// "operator" is a key word so if it's present we know we're
// dealing with operator overloading. The operator that's been
// overloaded might have been split up into multiple tokens.
for (idx = 0; idx < size; idx++)
if ("operator".equals(list.get(idx)))
break;
if (idx < size) {
methodName = "";
for (int i = idx; i < size; i++)
methodName += (String) list.get(i);
} else { // No operator overloading
methodName = "" + list.get(size - 1);
idx = size - 1;
}
// The class name comes before the method name
if (idx > 0 && ((String) list.get(idx - 1)).endsWith("::")) {
className = (String) list.get(idx - 1);
idx--;
}
// Whatever's left before the classname/methodname must be the
// return type
ArrayList retParm = new ArrayList();
for (int i = 0; i < idx; i++)
retParm.add(list.get(i));
returnType = new Parameter(retParm, true);
}
/**
* Constructs the parameter list
*/
private void parseParameters(List list) {
ArrayList alParams = new ArrayList();
Iterator it = list.iterator();
it.next(); // step over the (
while (it.hasNext()) {
String token = (String) it.next();
int template = 0; // Depth of template scope
ArrayList parm = new ArrayList();
while (!token.equals(")")
&& (!token.equals(",") || template > 0)) {
parm.add(token);
if (contains(token, "<"))
template++;
if (contains(token, ">"))
template--;
token = (String) it.next();
}
if (token.equals(")"))
break;
Parameter p = new Parameter(parm);
if (p.failed()) {
failed = true;
return;
}
if (!p.isVoid())
alParams.add(p);
}
int size = alParams.size();
if (size > 0) {
params = new Parameter[size];
System.arraycopy(alParams.toArray(), 0, params, 0, size);
}
}
private void parseTrailingAttributes(List list) {
trailingAttributes = new String();
Iterator it = list.iterator();
while (it.hasNext()) {
if (trailingAttributes.length() > 0)
trailingAttributes += " ";
trailingAttributes += (String) it.next();
}
}
String getOriginal() {
return originalText;
}
int originalLength() {
return originalText.length();
}
boolean failed() {
return failed;
}
String getAttributes() {
return attributes;
}
String getClassName() {
return className;
}
String getMethodName() {
return methodName;
}
Parameter getReturnType() {
return returnType;
}
Parameter[] getParameters() {
return params;
}
/**
* Should this method be traced?
*/
boolean traceable() {
return traceable;
}
private static boolean contains(String src, String tgt) {
if (src == null || tgt == null)
return false;
if (-1 == src.indexOf(tgt))
return false;
return true;
}
public String toString() {
String s = attributes;
if (attributes.length() > 0)
s += " ";
if (returnType != null)
s += returnType + " ";
if (className != null)
s += className;
s += methodName + "(";
for (int i = 0; params != null && i < params.length; i++) {
if (i > 0)
s += ", ";
s += params[i].toString();
}
s += ")";
if (trailingAttributes.length() > 0)
s += " " + trailingAttributes;
return s;
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/Tracer.java
Index: Tracer.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
import java.awt.image.IndexColorModel;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
/**
* A Buffered write that also contains the methods to add in in trace
* TODO: Add in &this and threadid into each trace record
*/
class Tracer extends BufferedWriter {
private Signature signature = null;
private final static String SIGNATURE = " /* AUTOINSERTED TRACE */";
/**
* @param writer a writer to the output file.
*/
Tracer(Writer writer, int depth) throws IOException {
super(writer);
String prefix = "";
if (depth > 1)
for (int i = 1; i < depth; i++)
prefix += "../";
write(
"#ifdef ENABLE_AXISTRACE\n"
+ "/* TRACE ADDED BY THE AXISCPP TRACE TOOL */\n"
+ "#include \""
+ prefix
+ "common/AxisTrace.h\"\n"
+ "extern AXIS_CPP_NAMESPACE_PREFIX AxisTrace* g_pAT;\n"
+ "#endif\n");
flush();
}
/**
* @param signature the signature of this method
*/
void traceEntry(Signature signature) throws IOException {
this.signature = signature;
// TODO: System.out.println warm fuzzy about excluding
// method here would be nice
if (!signature.traceable())
return;
// TODO trace parameters
write(
"\n#ifdef ENABLE_AXISTRACE\n"
+ "if (g_pAT) AXISTRACE1(\"> "
+ pretty(signature.toString())
+ "\",INFO);"
+ SIGNATURE
+ "\n#endif\n");
flush();
}
void traceExit() throws IOException {
if (!signature.traceable())
return;
// TODO check this method returns void
// Enclose the printf/return in {} in case if/then doesn't have {}
write("{");
write(
"\n#ifdef ENABLE_AXISTRACE\n"
+ "if (g_pAT) AXISTRACE1(\"< "
+ signature.getMethodName()
+ "\",INFO);"
+ SIGNATURE
+ "\n#endif\n");
// now print out the return line itself
write("return; }");
flush();
}
/**
* Takes in the return statement and traces out the exit trace statement for it
* This method prints out the complete return line as well so the user
* does not need to print this out themselves.
*/
void traceExit(String value) throws IOException {
if (!signature.traceable())
return;
// TODO avoid side effects such as return i++;
// Enclose the printf/return in {} in case if/then doesn't have {}
write("{");
// write out the actual exit trace line
// TODO trace the return value properly
write(
"\n#ifdef ENABLE_AXISTRACE\n"
+ "if (g_pAT) AXISTRACE1(\"< "
+ signature.getMethodName()
+ " = "
+ pretty(value)
+ "\",INFO);"
+ SIGNATURE
+ "\n#endif\n");
// now print out the return line itself
write("return " + value + "; }");
flush();
}
public void write(String s) throws IOException {
super.write(s);
if (AddEntryAndExitTrace.verbose)
System.out.print(s);
}
/**
* Escapes special characters like " so that they can be output
* in a C string literal. Also removes newlines, since C string
* literals can't be split over lines.
*/
private String pretty(String s) {
StringBuffer sb = new StringBuffer(s);
for (int i = 0; i < sb.length(); i++)
switch (sb.charAt(i)) {
case '"' :
sb = sb.insert(i, '\\');
i++;
break;
case '\n' :
sb = sb.deleteCharAt(i);
i--;
break;
}
return sb.toString();
}
}
1.1 ws-axis/c/tools/trace/org/apache/axis/tracetool/Utils.java
Index: Utils.java
===================================================================
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tracetool;
/**
* Static utility methods. Some of these methods are similar to the methods on
* java.lang.String except they are aware of C/C++ comments and string literals.
*
* TODO: Many of these methods would perform better using StringBuffer not String
*/
final class Utils {
public static final String whitespace =
" \t" + System.getProperty("line.separator");
private static final String letters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String alphanumerics =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/** Never instantiate this class */
private Utils() {
}
static boolean isSpace(char c) {
return whitespace.indexOf(c) != -1;
}
/**
* Is this string all whitespace?
*/
static boolean isSpace(String s) {
for (int i = 0; i < s.length(); i++)
if (-1 != whitespace.indexOf(s.charAt(i)))
return false;
return true;
}
static boolean startsWithALetter(String s) {
return letters.indexOf(s.charAt(0)) != -1;
}
static boolean isAlphaNumeric(char c) {
return alphanumerics.indexOf(c) != -1;
}
// TODO look for other trailing chars like { (because of class{)
static boolean startsWith(String source, String target) {
if (source == null || target == null)
return false;
if (!source.startsWith(target))
return false;
if (source.length() == target.length())
return true;
if (isSpace(source.charAt(target.length())))
return true;
return false;
}
/**
* Performs a C-aware version of String.indexOf(char) in
* that it skips characters in string literals and comments.
*/
static int indexOf(String s, char c) throws ParsingException {
if ('"' == c)
rude("Utils.indexOf cannot be passed quotes");
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == c)
return i;
i = skip(s.substring(i), i);
if (-1 == i)
return -1;
}
return -1;
}
/**
* Performs a C-aware version of String.indexOf(String) in
* that it skips characters in string literals and comments and makes
* sure that the target string is not embedded in a longer word.
*/
static int indexOf(String s, String t) {
char t0 = t.charAt(0);
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == t0
&& s.substring(i).startsWith(t)
&& (0 == i || !Utils.isAlphaNumeric(s.charAt(i - 1)))
&& (s.length() == (i + t.length())
|| !Utils.isAlphaNumeric(s.charAt(i + t.length()))))
return i;
i = skip(s.substring(i), i);
if (-1 == i)
return -1;
}
return -1;
}
/**
* Matches braces or quotes and is C-aware.
* It skips characters in string literals and comments.
*/
static int findMatching(String s, char c1, char c2) {
int depth = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == c1)
depth++;
else if (s.charAt(i) == c2) {
depth--;
if (depth == 0)
return i;
} else {
i = skip(s.substring(i), i);
if (-1 == i)
return -1;
}
}
return -1;
}
/**
* Failed to parse the source code for some reason. This method
* prints out a suitably rude message, and then what? I haven't
* quite decided yet.
*
* TODO: Do something sensible here like throw an Exception which
* will give up on this file completely and tidy up the output file.
* It may be just too dangerous to try to carry on. But we need to
* fail in such a way that the build system knows that we've failed
* for this file and can build this file without trace.
*/
static void rude(
String reason,
String filename,
int lineno,
String codefragment)
throws ParsingException {
String text = "Bad C++ code!! ";
if (reason != null)
text += reason;
if (filename != null)
text += " " + filename + " lineno=" + lineno;
if (codefragment != null)
text += " <" + codefragment + ">";
System.err.println(text);
throw new ParsingException();
}
/**
* @see Utils.rude(String,String,int,String)
*/
static void rude(String reason) throws ParsingException {
rude(reason, null, 0, null);
}
private static boolean startsWithComment(String s) {
if (null == s || s.length() < 2)
return false;
if (s.startsWith("//"))
return true;
if (s.startsWith("/*"))
return true;
return false;
}
private static int endOfComment(String s) {
int idx;
if (s.startsWith("//"))
idx = s.indexOf("\n");
else {
idx = s.indexOf("*/");
if (-1 != idx)
idx++; // Step over */
}
return idx;
}
private static boolean startsWithStringLiteral(String s) {
if (null == s || s.length() < 1)
return false;
if (s.startsWith("\"") ||
s.startsWith("'"))
return true;
return false;
}
private static int endOfStringLiteral(String s) {
boolean escape = false;
char c0 = s.charAt(0);
for (int i = 1; i < s.length(); i++) {
if (!escape && s.charAt(i) == c0)
return i;
// \" or \' does not end the literal
if ('\\' == s.charAt(i))
escape = true;
else
escape = false;
}
return -1;
}
private static int skip(String s, int i) {
int j = 0;
if (startsWithStringLiteral(s)) {
j = endOfStringLiteral(s);
if (-1 == j)
return -1;
} else if (startsWithComment(s)) {
j = endOfComment(s);
if (-1 == j)
return -1;
}
return i + j;
}
}