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;
  	}
  }