Adjust jdiff to be able to read both Doclava and "regular" Jdiff API xml files.

Bug: 19914336
Change-Id: I3b27c178840ac31da67c99270b47bce4dae308db
diff --git a/src/jdiff/API.java b/src/jdiff/API.java
index 2e8f117..800e752 100755
--- a/src/jdiff/API.java
+++ b/src/jdiff/API.java
@@ -177,7 +177,7 @@
      */
     public static void dumpCtor(ConstructorAPI c, int indent) {
         for (int i = 0; i < indent; i++) System.out.print(" ");
-        System.out.println("Ctor type: " + c.type_);
+        System.out.println("Ctor type: " + c.getSignature());
         // Display exceptions 
         System.out.print("exceptions: " + c.exceptions_ + " ");
         // Dump modifiers common to all
diff --git a/src/jdiff/APIComparator.java b/src/jdiff/APIComparator.java
index b0f42ed..c877785 100755
--- a/src/jdiff/APIComparator.java
+++ b/src/jdiff/APIComparator.java
@@ -379,10 +379,10 @@
                     // If there is one constructor in the oldClass and one
                     // constructor in the new class, then mark it as changed
                     MemberDiff memberDiff = new MemberDiff(oldClass.name_);
-                    memberDiff.oldType_ = oldCtor.type_;
+                    memberDiff.oldType_ = oldCtor.getSignature();
                     memberDiff.oldExceptions_ = oldCtor.exceptions_;
                     ConstructorAPI newCtor  = (ConstructorAPI)(newClass.ctors_.get(0));
-                    memberDiff.newType_ = newCtor.type_;
+                    memberDiff.newType_ = newCtor.getSignature();
                     memberDiff.newExceptions_ = newCtor.exceptions_;
                     // Track changes in documentation
                     if (docChanged(oldCtor.doc_, newCtor.doc_)) {
diff --git a/src/jdiff/APIHandler.java b/src/jdiff/APIHandler.java
index be1a6fc..21ed39a 100755
--- a/src/jdiff/APIHandler.java
+++ b/src/jdiff/APIHandler.java
@@ -26,12 +26,12 @@
         api_ = api;
         createGlobalComments_ = createGlobalComments;
         tagStack = new LinkedList();
-    }   
+    }
 
     /** If set, then check that each comment is a sentence. */
     public static boolean checkIsSentence = false;
 
-    /** 
+    /**
      * Contains the name of the current package element type
      * where documentation is being added. Also used as the level
      * at which to add documentation into an element, i.e. class-level
@@ -51,16 +51,16 @@
     /** The current text from deprecation, null if empty. */
     private String currentDepText = null;
 
-    /** 
-     * The stack of SingleComment objects awaiting the comment text 
-     * currently being assembled. 
+    /**
+     * The stack of SingleComment objects awaiting the comment text
+     * currently being assembled.
      */
     private LinkedList tagStack = null;
 
     /** Called at the start of the document. */
     public void startDocument() {
     }
-    
+
     /** Called when the end of the document is reached. */
     public void endDocument() {
         if (trace)
@@ -103,8 +103,9 @@
             XMLToAPI.addImplements(interfaceName);
         } else if (localName.compareTo("constructor") == 0) {
             currentElement = localName;
+            String ctorName = attributes.getValue("name");
             String ctorType = attributes.getValue("type");
-            XMLToAPI.addCtor(ctorType, getModifiers(attributes));
+            XMLToAPI.addCtor(ctorName, ctorType, getModifiers(attributes));
         } else if (localName.compareTo("method") == 0) {
             currentElement = localName;
             String methodName = attributes.getValue("name");
@@ -118,7 +119,7 @@
             boolean isSynchronized = false;
             if (attributes.getValue("synchronized").compareTo("true") == 0)
                 isSynchronized = true;
-            XMLToAPI.addMethod(methodName, returnType, isAbstract, isNative, 
+            XMLToAPI.addMethod(methodName, returnType, isAbstract, isNative,
                                isSynchronized, getModifiers(attributes));
         } else if (localName.compareTo("field") == 0) {
             currentElement = localName;
@@ -131,12 +132,12 @@
             if (attributes.getValue("volatile").compareTo("true") == 0)
                 isVolatile = true;
             String value = attributes.getValue("value");
-            XMLToAPI.addField(fieldName, fieldType, isTransient, isVolatile, 
+            XMLToAPI.addField(fieldName, fieldType, isTransient, isVolatile,
                               value, getModifiers(attributes));
-        } else if (localName.compareTo("param") == 0) {
+        } else if (localName.compareTo("param") == 0 || localName.compareTo("parameter") == 0) {
             String paramName = attributes.getValue("name");
             String paramType = attributes.getValue("type");
-            XMLToAPI.addParam(paramName, paramType);
+            XMLToAPI.addParam(paramName, paramType, currentElement.compareTo("constructor") == 0);
         } else if (localName.compareTo("exception") == 0) {
             String paramName = attributes.getValue("name");
             String paramType = attributes.getValue("type");
@@ -154,12 +155,12 @@
             }
         }
     }
-    
+
     /** Called when the end of an element is reached. */
-    public void endElement(java.lang.String uri, java.lang.String localName, 
+    public void endElement(java.lang.String uri, java.lang.String localName,
                            java.lang.String qName) {
-	if (localName.equals(""))
-	    localName = qName;
+        if (localName.equals(""))
+            localName = qName;
         // Deal with the end of doc blocks
         if (localName.compareTo("doc") == 0) {
             inDoc = false;
@@ -169,22 +170,22 @@
         } else if (inDoc) {
             // An element was found inside the HTML text
             addEndTagToText(localName);
-        } else if (currentElement.compareTo("constructor") == 0 && 
+        } else if (currentElement.compareTo("constructor") == 0 &&
                    localName.compareTo("constructor") == 0) {
             currentElement = "class";
-        } else if (currentElement.compareTo("method") == 0 && 
+        } else if (currentElement.compareTo("method") == 0 &&
                    localName.compareTo("method") == 0) {
             currentElement = "class";
-        } else if (currentElement.compareTo("field") == 0 && 
+        } else if (currentElement.compareTo("field") == 0 &&
                    localName.compareTo("field") == 0) {
             currentElement = "class";
         } else if (currentElement.compareTo("class") == 0 ||
                    currentElement.compareTo("interface") == 0) {
             // Feature request 510307 and bug 517383: duplicate comment ids.
-            // The end of a member element leaves the currentElement at the 
+            // The end of a member element leaves the currentElement at the
             // "class" level, but the next class may in fact be an interface
             // and so the currentElement here will be "interface".
-            if (localName.compareTo("class") == 0 || 
+            if (localName.compareTo("class") == 0 ||
                 localName.compareTo("interface") == 0) {
                 currentElement = "package";
             }
@@ -202,24 +203,24 @@
          }
     }
 
-    /** 
+    /**
      * Trim the current text, check it is a sentence and add it to the
-     * current program element. 
+     * current program element.
      */
     public void addTextToComments() {
         // Eliminate any whitespace at each end of the text.
-        currentText = currentText.trim();        
+        currentText = currentText.trim();
         // Convert any @link tags to HTML links.
         if (convertAtLinks) {
-            currentText = Comments.convertAtLinks(currentText, currentElement, 
+            currentText = Comments.convertAtLinks(currentText, currentElement,
                                                   api_.currPkg_, api_.currClass_);
         }
         // Check that it is a sentence
-        if (checkIsSentence && !currentText.endsWith(".") && 
+        if (checkIsSentence && !currentText.endsWith(".") &&
             currentText.compareTo(Comments.placeHolderText) != 0) {
             System.out.println("Warning: text of comment does not end in a period: " + currentText);
         }
-        // The construction of the commentID assumes that the 
+        // The construction of the commentID assumes that the
         // documentation is the final element to be parsed. The format matches
         // the format used in the report generator to look up comments in the
         // the existingComments object.
@@ -236,25 +237,25 @@
             api_.currCtor_.doc_ = currentText;
             commentID = api_.currPkg_.name_ + "." + api_.currClass_.name_ +
                 ".ctor_changed(";
-            if (api_.currCtor_.type_.compareTo("void") == 0)
+            if (api_.currCtor_.getSignature().compareTo("void") == 0)
                 commentID = commentID + ")";
             else
-                commentID = commentID + api_.currCtor_.type_ + ")";
+                commentID = commentID + api_.currCtor_.getSignature() + ")";
         } else if (currentElement.compareTo("method") == 0) {
             api_.currMethod_.doc_ = currentText;
             commentID = api_.currPkg_.name_ + "." + api_.currClass_.name_ +
-                "." + api_.currMethod_.name_ + "_changed(" + 
+                "." + api_.currMethod_.name_ + "_changed(" +
                 api_.currMethod_.getSignature() + ")";
         } else if (currentElement.compareTo("field") == 0) {
             api_.currField_.doc_ = currentText;
             commentID = api_.currPkg_.name_ + "." + api_.currClass_.name_ +
                 "." + api_.currField_.name_;
-        }            
+        }
         // Add to the list of possible comments for use when an
         // element has changed (not removed or added).
         if (createGlobalComments_ && commentID != null) {
             String ct = currentText;
-            // Use any deprecation text as the possible comment, ignoring 
+            // Use any deprecation text as the possible comment, ignoring
             // any other comment text.
             if (currentDepText != null) {
                 ct = currentDepText;
@@ -268,8 +269,8 @@
         }
     }
 
-    /** 
-     * Add the start tag to the current comment text. 
+    /**
+     * Add the start tag to the current comment text.
      */
     public void addStartTagToText(String localName, Attributes attributes) {
         // Need to insert the HTML tag into the current text
@@ -298,8 +299,8 @@
             currentText += tag;
     }
 
-    /** 
-     * Add the end tag to the current comment text. 
+    /**
+     * Add the end tag to the current comment text.
      */
     public void addEndTagToText(String localName) {
         // Close the current HTML tag
@@ -343,15 +344,15 @@
         e.printStackTrace();
         System.exit(1);
     }
-    
+
     public void fatalError(SAXParseException e) {
         System.out.println("Fatal Error (" + e.getLineNumber() + "): parsing XML API file:" + e);
         e.printStackTrace();
         System.exit(1);
-    }    
+    }
 
-    /** 
-     * If set, then attempt to convert @link tags to HTML links. 
+    /**
+     * If set, then attempt to convert @link tags to HTML links.
      * A few of the HTML links may be broken links.
      */
     private static boolean convertAtLinks = true;
diff --git a/src/jdiff/ConstructorAPI.java b/src/jdiff/ConstructorAPI.java
index 7390a4d..8fc7159 100755
--- a/src/jdiff/ConstructorAPI.java
+++ b/src/jdiff/ConstructorAPI.java
@@ -3,9 +3,9 @@
 import java.io.*;
 import java.util.*;
 
-/** 
- * Class to represent a constructor, analogous to ConstructorDoc in the 
- * Javadoc doclet API. 
+/**
+ * Class to represent a constructor, analogous to ConstructorDoc in the
+ * Javadoc doclet API.
  *
  * The method used for Collection comparison (compareTo) must make its
  * comparison based upon everything that is known about this constructor.
@@ -14,34 +14,56 @@
  * @author Matthew Doar, mdoar@pobox.com
  */
 class ConstructorAPI implements Comparable {
-    /** 
+    /**
+     * Name of the constructor.
+     * Either this or type_ must be non-null
+     */
+    public String name_ = null;
+
+    /**
      * The type of the constructor, being all the parameter types
      * separated by commas.
+     * Either this or name_ must be non-null.
      */
     public String type_ = null;
-    
-    /** 
+
+    /**
      * The exceptions thrown by this constructor, being all the exception types
      * separated by commas. "no exceptions" if no exceptions are thrown.
      */
     public String exceptions_ = "no exceptions";
-    
+
     /** Modifiers for this class. */
     public Modifiers modifiers_;
 
+    public List params_; // ParamAPI[]
+
     /** The doc block, default is null. */
     public String doc_ = null;
 
     /** Constructor. */
-    public ConstructorAPI(String type, Modifiers modifiers) {
+    public ConstructorAPI(String name, String type, Modifiers modifiers) {
+        if (name == null && type == null) {
+            throw new IllegalArgumentException("Cannot have constructor with both name and type"
+                + "being null");
+        }
+        name_ = name;
         type_ = type;
         modifiers_ = modifiers;
+        params_ = new ArrayList();
+    }
+
+    private static <T extends Comparable<? super T>> int compareNullIsLeast(T c1, T c2) {
+        return c1 == null ? (c2 == null ? 0 : -1) : (c2 == null ? 1 : c1.compareTo(c2));
     }
 
     /** Compare two ConstructorAPI objects by type and modifiers. */
     public int compareTo(Object o) {
         ConstructorAPI constructorAPI = (ConstructorAPI)o;
-        int comp = type_.compareTo(constructorAPI.type_);
+        int comp = compareNullIsLeast(name_, constructorAPI.name_);
+        if (comp != 0)
+            return comp;
+        comp = compareNullIsLeast(getSignature(), constructorAPI.getSignature());
         if (comp != 0)
             return comp;
         comp = exceptions_.compareTo(constructorAPI.exceptions_);
@@ -55,12 +77,46 @@
         return 0;
     }
 
-    /** 
-     * Tests two constructors, using just the type, used by indexOf(). 
+    /**
+     * Tests two constructors, using just the name and type, used by indexOf().
      */
     public boolean equals(Object o) {
-        if (type_.compareTo(((ConstructorAPI)o).type_) == 0)
+        ConstructorAPI constructorAPI = (ConstructorAPI)o;
+        if (compareNullIsLeast(name_, constructorAPI.name_) == 0 &&
+                compareNullIsLeast(type_, constructorAPI.type_) == 0)
             return true;
         return false;
     }
-}  
+
+    /**
+     * Tests two methods for equality, using just the signature.
+     */
+    public boolean equalSignatures(Object o) {
+        if (getSignature().compareTo(((MethodAPI)o).getSignature()) == 0)
+            return true;
+        return false;
+    }
+
+    /** Cached result of getSignature(). */
+    private String signature_ = null;
+
+    /** Return the signature of the method. */
+    public String getSignature() {
+        if (signature_ != null)
+            return signature_;
+        if (params_ == null)
+            return type_;
+        String res = "";
+        boolean first = true;
+        Iterator iter = params_.iterator();
+        while (iter.hasNext()) {
+            if (!first)
+                res += ", ";
+            ParamAPI param = (ParamAPI)(iter.next());
+            res += param.toString();
+            first = false;
+        }
+        signature_ = res;
+        return res;
+    }
+}
diff --git a/src/jdiff/HTMLIndexes.java b/src/jdiff/HTMLIndexes.java
index d39e023..9e65d96 100755
--- a/src/jdiff/HTMLIndexes.java
+++ b/src/jdiff/HTMLIndexes.java
@@ -561,12 +561,12 @@
                 Iterator iterCtor = classDiff.ctorsRemoved.iterator();
                 while ((indexType == 3 || indexType == 0) && iterCtor.hasNext()) {
                     ConstructorAPI ctor = (ConstructorAPI)(iterCtor.next());
-                    ctorNames.add(new Index(className, 0, pkgName, ctor.type_));
+                    ctorNames.add(new Index(className, 0, pkgName, ctor.getSignature()));
                 }
                 iterCtor = classDiff.ctorsAdded.iterator();
                 while ((indexType == 3 || indexType == 1) && iterCtor.hasNext()) {
                     ConstructorAPI ctor = (ConstructorAPI)(iterCtor.next());
-                    Index idx = new Index(className, 1, pkgName, ctor.type_);
+                    Index idx = new Index(className, 1, pkgName, ctor.getSignature());
                     idx.doc_ = ctor.doc_; // Used for checking @since
                     ctorNames.add(idx);
                 }
diff --git a/src/jdiff/HTMLReportGenerator.java b/src/jdiff/HTMLReportGenerator.java
index f6cf861..c896525 100755
--- a/src/jdiff/HTMLReportGenerator.java
+++ b/src/jdiff/HTMLReportGenerator.java
@@ -551,7 +551,7 @@
             Iterator iter = classDiff.ctorsRemoved.iterator();
             while (iter.hasNext()) {
                 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next());
-                String ctorType = ctorAPI.type_;
+                String ctorType = ctorAPI.getSignature();
                 if (ctorType.compareTo("void") == 0)
                     ctorType = "";
                 String id = className + "(" + ctorType + ")";
@@ -567,7 +567,7 @@
             Iterator iter = classDiff.ctorsAdded.iterator();
             while (iter.hasNext()) {
                 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next());
-                String ctorType = ctorAPI.type_;
+                String ctorType = ctorAPI.getSignature();
                 if (ctorType.compareTo("void") == 0)
                     ctorType = "";
                 String id = className + "(" + ctorType + ")";
diff --git a/src/jdiff/MergeChanges.java b/src/jdiff/MergeChanges.java
index a8a4c85..d253ff4 100755
--- a/src/jdiff/MergeChanges.java
+++ b/src/jdiff/MergeChanges.java
@@ -88,8 +88,8 @@
             ConstructorAPI addedCtor = (ConstructorAPI)(classDiff.ctorsAdded.get(startAdded));
             // Create a MemberDiff for this change
             MemberDiff ctorDiff = new MemberDiff(classDiff.name_);
-            ctorDiff.oldType_ = removedCtor.type_;
-            ctorDiff.newType_ = addedCtor.type_; // Should be the same as removedCtor.type
+            ctorDiff.oldType_ = removedCtor.getSignature();
+            ctorDiff.newType_ = addedCtor.getSignature(); // Should be the same as removedCtor.type
             ctorDiff.oldExceptions_ = removedCtor.exceptions_;
             ctorDiff.newExceptions_ = addedCtor.exceptions_;
             ctorDiff.addModifiersChange(removedCtor.modifiers_.diff(addedCtor.modifiers_));
diff --git a/src/jdiff/MethodAPI.java b/src/jdiff/MethodAPI.java
index 2afdc80..a9991ca 100755
--- a/src/jdiff/MethodAPI.java
+++ b/src/jdiff/MethodAPI.java
@@ -3,10 +3,10 @@
 import java.io.*;
 import java.util.*;
 
-/** 
- * Class to represent a method, analogous to MethodDoc in the 
- * Javadoc doclet API. 
- * 
+/**
+ * Class to represent a method, analogous to MethodDoc in the
+ * Javadoc doclet API.
+ *
  * The method used for Collection comparison (compareTo) must make its
  * comparison based upon everything that is known about this method.
  *
@@ -21,14 +21,14 @@
     /** Return type of the method. */
     public String returnType_ = null;
 
-    /** 
+    /**
      * The fully qualified name of the class or interface this method is
      * inherited from. If this is null, then the method is defined locally
      * in this class or interface.
      */
     public String inheritedFrom_ = null;
 
-    /** 
+    /**
      * The exceptions thrown by this method, being all the exception types
      * separated by commas. "no exceptions" if no exceptions are thrown.
      */
@@ -52,7 +52,7 @@
     public String doc_ = null;
 
     /** Constructor. */
-    public MethodAPI(String name, String returnType, boolean isAbstract, 
+    public MethodAPI(String name, String returnType, boolean isAbstract,
                      boolean isNative, boolean isSynchronized,
                      Modifiers modifiers) {
         name_ = name;
@@ -79,9 +79,9 @@
         signature_ = m.signature_; // Cached
     }
 
-    /** 
-     * Compare two methods, including the return type, and parameter 
-     * names and types, and modifiers. 
+    /**
+     * Compare two methods, including the return type, and parameter
+     * names and types, and modifiers.
      */
     public int compareTo(Object o) {
         MethodAPI oMethod = (MethodAPI)o;
@@ -96,11 +96,11 @@
         if (isAbstract_ != oMethod.isAbstract_) {
             return -1;
         }
-        if (Diff.showAllChanges && 
+        if (Diff.showAllChanges &&
 	    isNative_ != oMethod.isNative_) {
             return -1;
         }
-        if (Diff.showAllChanges && 
+        if (Diff.showAllChanges &&
 	    isSynchronized_ != oMethod.isSynchronized_) {
             return -1;
         }
@@ -117,17 +117,17 @@
             return -1;
         return 0;
     }
-  
-    /** 
-     * Tests two methods, using just the method name, used by indexOf(). 
+
+    /**
+     * Tests two methods, using just the method name, used by indexOf().
      */
     public boolean equals(Object o) {
         if (name_.compareTo(((MethodAPI)o).name_) == 0)
             return true;
         return false;
     }
-    
-    /** 
+
+    /**
      * Tests two methods for equality, using just the signature.
      */
     public boolean equalSignatures(Object o) {
@@ -135,9 +135,9 @@
             return true;
         return false;
     }
-    
+
     /** Cached result of getSignature(). */
-    public String signature_ = null;
+    private String signature_ = null;
 
     /** Return the signature of the method. */
     public String getSignature() {
@@ -154,6 +154,6 @@
             first = false;
         }
         signature_ = res;
-        return res; 
+        return res;
     }
 }
diff --git a/src/jdiff/XMLToAPI.java b/src/jdiff/XMLToAPI.java
index 046da4b..a7fe33a 100755
--- a/src/jdiff/XMLToAPI.java
+++ b/src/jdiff/XMLToAPI.java
@@ -13,35 +13,35 @@
 import org.xml.sax.helpers.*;
 
 /**
- * Creates an API object from an XML file. The API object is the internal 
+ * Creates an API object from an XML file. The API object is the internal
  * representation of an API.
  * All methods in this class for populating an API object are static.
- * 
+ *
  * See the file LICENSE.txt for copyright details.
  * @author Matthew Doar, mdoar@pobox.com
  */
 public class XMLToAPI {
 
-    /** The instance of the API object which is populated from the file. */ 
+    /** The instance of the API object which is populated from the file. */
     private static API api_ = null;
 
     /** Default constructor. */
     private XMLToAPI() {
-    }   
-  
-    /** 
+    }
+
+    /**
      * Read the file where the XML representing the API is stored.
      *
-     * @param filename The full name of the file containing the XML 
+     * @param filename The full name of the file containing the XML
      *                 representing the API
      * @param createGlobalComments If set, then store possible comments
-     * @param apiName The simple name of the API file. If -oldapidir and 
-     *                -newapidir are not used, then this is the same as 
+     * @param apiName The simple name of the API file. If -oldapidir and
+     *                -newapidir are not used, then this is the same as
      *                the filename parameter
      */
     public static API readFile(String filename, boolean createGlobalComments,
-			       String apiName) {
-        // The instance of the API object which is populated from the file. 
+            String apiName) {
+        // The instance of the API object which is populated from the file.
         api_ = new API();
         api_.name_ = apiName; // Checked later
         try {
@@ -91,7 +91,7 @@
         return api_;
     } //readFile()
 
-    /** 
+    /**
      * Add the inherited methods and fields to each class in turn.
      */
     public static void addInheritedElements() {
@@ -120,8 +120,8 @@
         } //while (iter.hasNext())
     }
 
-    /** 
-     * Add all the inherited methods and fields in the second class to 
+    /**
+     * Add all the inherited methods and fields in the second class to
      * the first class, marking them as inherited from the second class.
      * Do not add a method or a field if it is already defined locally.
      *
@@ -143,18 +143,18 @@
                 Iterator iter2 = child.methods_.iterator();
                 while (iter2.hasNext()) {
                     MethodAPI localM = (MethodAPI)(iter2.next());
-                    if (localM.name_.compareTo(m.name_) == 0 && 
+                    if (localM.name_.compareTo(m.name_) == 0 &&
                         localM.getSignature().compareTo(m.getSignature()) == 0)
                         overridden = true;
                 }
                 if (!overridden && m.inheritedFrom_ == null &&
-                    m.modifiers_.visibility != null && 
+                    m.modifiers_.visibility != null &&
                     m.modifiers_.visibility.compareTo("private") != 0) {
                     MethodAPI m2 = new MethodAPI(m);
                     m2.inheritedFrom_ = fqParentName;
                     child.methods_.add(m2);
                 }
-            }            
+            }
         }
         if (parent.fields_.size() != 0) {
             Iterator iter = parent.fields_.iterator();
@@ -162,13 +162,13 @@
                 FieldAPI f = (FieldAPI)(iter.next());
                 if (child.fields_.indexOf(f) == -1 &&
                     f.inheritedFrom_ == null &&
-                    f.modifiers_.visibility != null && 
+                    f.modifiers_.visibility != null &&
                     f.modifiers_.visibility.compareTo("private") != 0) {
                     FieldAPI f2 = new FieldAPI(f);
                     f2.inheritedFrom_ = fqParentName;
                     child.fields_.add(f2);
                 }
-            }            
+            }
         }
 
         // Look up any inherited classes or interfaces
@@ -192,30 +192,35 @@
 // Methods to add data to an API object. Called by the XML parser.
 //
 
-    /** 
+    /**
      * Set the name of the API object.
      *
      * @param name The name of the package.
      */
     public static void nameAPI(String name) {
         if (name == null) {
-            System.out.println("Error: no API identifier found in the XML file '" + api_.name_ + "'");
-            System.exit(3);
+            System.out.println("Warning: no API identifier found in the XML file '" + api_.name_ + "'");
+            String filename = api_.name_.substring(0, api_.name_.lastIndexOf(".xml"));
+            // System.out.println(" api level:" + filename);
+            System.out.println("Using '" + filename + "' as the API identifier.");
+            api_.name_ = filename;
+            // System.exit(3);
+            return;
         }
-        // Check the given name against the filename currently stored in 
+        // Check the given name against the filename currently stored in
         // the name_ field
         String filename2 = name.replace(' ','_');
         filename2 += ".xml";
         if (filename2.compareTo(api_.name_) != 0) {
-            System.out.println("Warning: API identifier in the XML file (" + 
+            System.out.println("Warning: API identifier in the XML file (" +
                                name + ") differs from the name of the file '" +
                                api_.name_ + "'");
         }
         api_.name_ = name;
     }
-   
-    /** 
-     * Create a new package and add it to the API. Called by the XML parser. 
+
+    /**
+     * Create a new package and add it to the API. Called by the XML parser.
      *
      * @param name The name of the package.
      */
@@ -223,15 +228,15 @@
         api_.currPkg_ = new PackageAPI(name);
         api_.packages_.add(api_.currPkg_);
     }
-   
-    /** 
-     * Create a new class and add it to the current package. Called by the XML parser. 
+
+    /**
+     * Create a new class and add it to the current package. Called by the XML parser.
      *
      * @param name The name of the class.
      * @param parent The name of the parent class, null if no class is extended.
      * @param modifiers Modifiers for this class.
      */
-    public static void addClass(String name, String parent, 
+    public static void addClass(String name, String parent,
                                 boolean isAbstract,
                                 Modifiers modifiers) {
         api_.currClass_ = new ClassAPI(name, parent, false, isAbstract, modifiers);
@@ -242,24 +247,24 @@
             System.out.println("Warning: duplicate class : " + fqName + " found. Using the first instance only.");
         }
     }
-  
-    /** 
-     * Add an new interface and add it to the current package. Called by the 
+
+    /**
+     * Add an new interface and add it to the current package. Called by the
      * XML parser.
      *
      * @param name The name of the interface.
-     * @param parent The name of the parent interface, null if no 
+     * @param parent The name of the parent interface, null if no
      *               interface is extended.
      */
-    public static void addInterface(String name, String parent, 
+    public static void addInterface(String name, String parent,
                                     boolean isAbstract,
                                     Modifiers modifiers) {
         api_.currClass_ = new ClassAPI(name, parent, true, isAbstract, modifiers);
         api_.currPkg_.classes_.add(api_.currClass_);
     }
-  
-    /** 
-     * Add an inherited interface to the current class. Called by the XML 
+
+    /**
+     * Add an inherited interface to the current class. Called by the XML
      * parser.
      *
      * @param name The name of the inherited interface.
@@ -267,31 +272,31 @@
     public static void addImplements(String name) {
        api_.currClass_.implements_.add(name);
     }
-  
-    /** 
+
+    /**
      * Add a constructor to the current class. Called by the XML parser.
      *
-     * @param name The name of the constructor.
+     * @param name The name of the constructor (optional).
      * @param type The type of the constructor.
      * @param modifiers Modifiers for this constructor.
      */
-    public static void addCtor(String type, Modifiers modifiers) {
+    public static void addCtor(String name, String type, Modifiers modifiers) {
         String t = type;
         if (t == null)
             t = "void";
-        api_.currCtor_ = new ConstructorAPI(t, modifiers);
+        api_.currCtor_ = new ConstructorAPI(name, t, modifiers);
         api_.currClass_.ctors_.add(api_.currCtor_);
     }
 
-    /** 
+    /**
      * Add a method to the current class. Called by the XML parser.
      *
      * @param name The name of the method.
      * @param returnType The return type of the method, null if it is void.
      * @param modifiers Modifiers for this method.
      */
-    public static void addMethod(String name, String returnType, 
-                                 boolean isAbstract, boolean isNative, 
+    public static void addMethod(String name, String returnType,
+                                 boolean isAbstract, boolean isNative,
                                  boolean isSynchronized, Modifiers modifiers) {
         String rt = returnType;
         if (rt == null)
@@ -301,7 +306,7 @@
         api_.currClass_.methods_.add(api_.currMethod_);
     }
 
-    /** 
+    /**
      * Add a field to the current class. Called by the XML parser.
      *
      * @param name The name of the field.
@@ -317,28 +322,33 @@
         api_.currClass_.fields_.add(api_.currField_);
     }
 
-    /** 
-     * Add a parameter to the current method. Called by the XML parser.
-     * Constuctors have their type (signature) in an attribute, since it 
+    /**
+     * Add a parameter to the current method or constructor. Called by the XML parser.
+     * Constuctors have their type (signature) in an attribute, since it
      * is often shorter and makes parsing a little easier.
      *
      * @param name The name of the parameter.
      * @param type The type of the parameter, null if it is void.
+     * @param isConstructor Whether the given parameter is for a constructor
      */
-    public static void addParam(String name, String type) {
+    public static void addParam(String name, String type, boolean isConstructor) {
         String t = type;
         if (t == null)
             t = "void";
         ParamAPI paramAPI = new ParamAPI(name, t);
-        api_.currMethod_.params_.add(paramAPI);
+        if (isConstructor) {
+            api_.currCtor_.params_.add(paramAPI);
+        } else {
+            api_.currMethod_.params_.add(paramAPI);
+        }
     }
 
-    /** 
-     * Add an exception to the current method or constructor. 
+    /**
+     * Add an exception to the current method or constructor.
      * Called by the XML parser.
      *
      * @param name The name of the parameter.
-     * @param type The type of the parameter. 
+     * @param type The type of the parameter.
      *             May be null in JDiff1.0.8 and earlier versions.
      * @param currElement Name of the current element.
      */
@@ -359,18 +369,18 @@
         }
     }
 
-    /** 
-     * If set, validate the XML which represents an API. By default, this is 
-     * not set for reasons of efficiency, and also because if JDiff generated 
-     * the XML, it should not need validating. 
+    /**
+     * If set, validate the XML which represents an API. By default, this is
+     * not set for reasons of efficiency, and also because if JDiff generated
+     * the XML, it should not need validating.
      */
     public static boolean validateXML = false;
 
-    /** 
+    /**
      * If set, then store and display the whole qualified name of exceptions.
-     * If not set, then store and display just the name of the exception, 
+     * If not set, then store and display just the name of the exception,
      * which is shorter, but may not detect when an exception changes class,
      * but retains the same name.
      */
     private static boolean showExceptionTypes = true;
-}  
+}