auto import from //depot/cupcake/@135843
diff --git a/tools/droiddoc/src/Comment.java b/tools/droiddoc/src/Comment.java
new file mode 100644
index 0000000..3a24357
--- /dev/null
+++ b/tools/droiddoc/src/Comment.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
+public class Comment
+{
+    static final Pattern LEADING_WHITESPACE = Pattern.compile(
+                                "^[ \t\n\r]*(.*)$",
+                                Pattern.DOTALL);
+
+    static final Pattern TAG_BEGIN = Pattern.compile(
+                                "[\r\n][\r\n \t]*@",
+                                Pattern.DOTALL);
+
+    static final Pattern TAG = Pattern.compile(
+                                "(@[^ \t\r\n]+)[ \t\r\n]+(.*)",
+                                Pattern.DOTALL);
+
+    static final Pattern INLINE_TAG = Pattern.compile(
+                                "(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}",
+                                Pattern.DOTALL);
+
+    static final Pattern FIRST_SENTENCE = Pattern.compile(
+                                "((.*?)\\.)[ \t\r\n\\<](.*)",
+                                Pattern.DOTALL);
+
+    private static final String[] KNOWN_TAGS = new String[] {
+            "@author",
+            "@since",
+            "@version",
+            "@deprecated",
+            "@undeprecate",
+            "@docRoot",
+            "@inheritDoc",
+            "@more",
+            "@code",
+            "@samplecode",
+            "@sample",
+            "@include",
+            "@serial",
+            "@com.intel.drl.spec_ref",
+            "@ar.org.fitc.spec_ref",
+        };
+
+    public Comment(String text, ContainerInfo base, SourcePositionInfo sp)
+    {
+        mText = text;
+        mBase = base;
+        // sp now points to the end of the text, not the beginning!
+        mPosition = SourcePositionInfo.findBeginning(sp, text);
+    }
+
+    private void parseRegex(String text)
+    {
+        Matcher m;
+
+        m = LEADING_WHITESPACE.matcher(text);
+        m.matches();
+        text = m.group(1);
+
+        m = TAG_BEGIN.matcher(text);
+
+        int start = 0;
+        int end = 0;
+        while (m.find()) {
+            end = m.start();
+
+            tag(text, start, end);
+
+            start = m.end()-1; // -1 is the @
+        }
+        end = text.length();
+        tag(text, start, end);
+    }
+
+    private void tag(String text, int start, int end)
+    {
+        SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
+
+        if (start >= 0 && end > 0 && (end-start) > 0) {
+            text = text.substring(start, end);
+
+            Matcher m = TAG.matcher(text);
+            if (m.matches()) {
+                // out of line tag
+                tag(m.group(1), m.group(2), false, pos);
+            } else {
+                // look for inline tags
+                m = INLINE_TAG.matcher(text);
+                start = 0;
+                while (m.find()) {
+                    String str = m.group(1);
+                    String tagname = m.group(2);
+                    String tagvalue = m.group(3);
+                    tag(null, m.group(1), true, pos);
+                    tag(tagname, tagvalue, true, pos);
+                    start = m.end();
+                }
+                int len = text.length();
+                if (start != len) {
+                    tag(null, text.substring(start), true, pos);
+                }
+            }
+        }
+    }
+
+    private void tag(String name, String text, boolean isInline, SourcePositionInfo pos)
+    {
+        /*
+        String s = isInline ? "inline" : "outofline";
+        System.out.println("---> " + s
+                + " name=[" + name + "] text=[" + text + "]");
+        */
+        if (name == null) {
+            mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
+        }
+        else if (name.equals("@param")) {
+            mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
+        }
+        else if (name.equals("@see")) {
+            mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
+        }
+        else if (name.equals("@link") || name.equals("@linkplain")) {
+            mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
+        }
+        else if (name.equals("@throws") || name.equals("@exception")) {
+            mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
+        }
+        else if (name.equals("@return")) {
+            mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
+        }
+        else if (name.equals("@deprecated")) {
+            if (text.length() == 0) {
+                Errors.error(Errors.MISSING_COMMENT, pos,
+                        "@deprecated tag with no explanatory comment");
+                text = "No replacement.";
+            }
+            mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
+        }
+        else if (name.equals("@literal")) {
+            mInlineTagsList.add(new LiteralTagInfo(name, name, text, pos));
+        }
+        else if (name.equals("@hide") || name.equals("@doconly")) {
+            // nothing
+        }
+        else if (name.equals("@attr")) {
+            AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
+            mAttrTagsList.add(tag);
+            Comment c = tag.description();
+            if (c != null) {
+                for (TagInfo t: c.tags()) {
+                    mInlineTagsList.add(t);
+                }
+            }
+        }
+        else if (name.equals("@undeprecate")) {
+            mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
+        }
+        else if (name.equals("@include") || name.equals("@sample")) {
+            mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
+        }
+        else {
+            boolean known = false;
+            for (String s: KNOWN_TAGS) {
+                if (s.equals(name)) {
+                    known = true;
+                    break;
+                }
+            }
+            if (!known) {
+                Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
+                        "Unknown tag: " + name);
+            }
+            TagInfo t = new TextTagInfo(name, name, text, pos);
+            if (isInline) {
+                mInlineTagsList.add(t);
+            } else {
+                mTagsList.add(t);
+            }
+        }
+    }
+
+    private void parseBriefTags()
+    {
+        int N = mInlineTagsList.size();
+
+        // look for "@more" tag, which means that we might go past the first sentence.
+        int more = -1;
+        for (int i=0; i<N; i++) {
+            if (mInlineTagsList.get(i).name().equals("@more")) {
+                more = i;
+            } 
+        }
+          if (more >= 0) {
+            for (int i=0; i<more; i++) {
+                mBriefTagsList.add(mInlineTagsList.get(i));
+            }
+        } else {
+            for (int i=0; i<N; i++) {
+                TagInfo t = mInlineTagsList.get(i);
+                if (t.name().equals("Text")) {
+                    Matcher m = FIRST_SENTENCE.matcher(t.text());
+                    if (m.matches()) {
+                        String text = m.group(1);
+                        TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
+                        mBriefTagsList.add(firstSentenceTag);
+                        break;
+                    }
+                }
+                mBriefTagsList.add(t);
+                
+            }
+        }
+    }
+
+    public TagInfo[] tags()
+    {
+        init();
+        return mInlineTags;
+    }
+
+    public TagInfo[] tags(String name)
+    {
+        init();
+        ArrayList<TagInfo> results = new ArrayList<TagInfo>();
+        int N = mInlineTagsList.size();
+        for (int i=0; i<N; i++) {
+            TagInfo t = mInlineTagsList.get(i);
+            if (t.name().equals(name)) {
+                results.add(t);
+            }
+        }
+        return results.toArray(new TagInfo[results.size()]);
+    }
+
+    public ParamTagInfo[] paramTags()
+    {
+        init();
+        return mParamTags;
+    }
+
+    public SeeTagInfo[] seeTags()
+    {
+        init();
+        return mSeeTags;
+    }
+
+    public ThrowsTagInfo[] throwsTags()
+    {
+        init();
+        return mThrowsTags;
+    }
+
+    public TagInfo[] returnTags()
+    {
+        init();
+        return mReturnTags;
+    }
+
+    public TagInfo[] deprecatedTags()
+    {
+        init();
+        return mDeprecatedTags;
+    }
+
+    public TagInfo[] undeprecateTags()
+    {
+        init();
+        return mUndeprecateTags;
+    }
+
+    public AttrTagInfo[] attrTags()
+    {
+        init();
+        return mAttrTags;
+    }
+
+    public TagInfo[] briefTags()
+    {
+        init();
+        return mBriefTags;
+    }
+
+    public boolean isHidden()
+    {
+        if (mHidden >= 0) {
+            return mHidden != 0;
+        } else {
+            if (DroidDoc.checkLevel(DroidDoc.SHOW_HIDDEN)) {
+                mHidden = 0;
+                return false;
+            }
+            boolean b = mText.indexOf("@hide") >= 0;
+            mHidden = b ? 1 : 0;
+            return b;
+        }
+    }
+    
+    public boolean isDocOnly() {
+        if (mDocOnly >= 0) {
+            return mDocOnly != 0;
+        } else {
+            boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
+            mDocOnly = b ? 1 : 0;
+            return b;
+        }
+    }
+
+    private void init()
+    {
+        if (!mInitialized) {
+            initImpl();
+        }
+    }
+
+    private void initImpl()
+    {
+        isHidden();
+        isDocOnly();
+        parseRegex(mText);
+        parseBriefTags();
+        mText = null;
+        mInitialized = true;
+
+        mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
+        mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
+        mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
+        mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
+        mReturnTags = ParsedTagInfo.joinTags(mReturnTagsList.toArray(
+                                             new ParsedTagInfo[mReturnTagsList.size()]));
+        mDeprecatedTags = ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(
+                                        new ParsedTagInfo[mDeprecatedTagsList.size()]));
+        mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
+        mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
+        mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
+
+        mParamTagsList = null;
+        mSeeTagsList = null;
+        mThrowsTagsList = null;
+        mReturnTagsList = null;
+        mDeprecatedTagsList = null;
+        mUndeprecateTagsList = null;
+        mAttrTagsList = null;
+        mBriefTagsList = null;
+    }
+
+    boolean mInitialized;
+    int mHidden = -1;
+    int mDocOnly = -1;
+    String mText;
+    ContainerInfo mBase;
+    SourcePositionInfo mPosition;
+    int mLine = 1;
+
+    TagInfo[] mInlineTags;
+    TagInfo[] mTags;
+    ParamTagInfo[] mParamTags;
+    SeeTagInfo[] mSeeTags;
+    ThrowsTagInfo[] mThrowsTags;
+    TagInfo[] mBriefTags;
+    TagInfo[] mReturnTags;
+    TagInfo[] mDeprecatedTags;
+    TagInfo[] mUndeprecateTags;
+    AttrTagInfo[] mAttrTags;
+
+    ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
+    ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
+    ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
+    ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
+    ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
+    ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
+    ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
+    ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
+    ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
+    ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
+
+    
+}