JFlexXref.java revision 1122
0N/A/*
0N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
0N/A * Common Development and Distribution License (the "License").
0N/A * You may not use this file except in compliance with the License.
0N/A *
0N/A * See LICENSE.txt included in this distribution for the specific
0N/A * language governing permissions and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at LICENSE.txt.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information: Portions Copyright [yyyy] [name of copyright owner]
0N/A *
0N/A * CDDL HEADER END
0N/A */
0N/A
0N/A/*
119N/A * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A */
0N/A
0N/Apackage org.opensolaris.opengrok.analysis;
65N/A
0N/Aimport java.io.CharArrayReader;
125N/Aimport java.io.IOException;
125N/Aimport java.io.Reader;
125N/Aimport java.io.Writer;
125N/Aimport java.lang.reflect.Field;
58N/Aimport java.util.Set;
77N/Aimport org.opensolaris.opengrok.configuration.Project;
125N/Aimport org.opensolaris.opengrok.configuration.RuntimeEnvironment;
125N/Aimport org.opensolaris.opengrok.history.Annotation;
125N/Aimport org.opensolaris.opengrok.web.Util;
125N/A
261N/A/**
261N/A * Base class for Xref lexers.
126N/A *
58N/A * @author Lubos Kosco
8N/A */
30N/Apublic abstract class JFlexXref {
0N/A public Writer out;
77N/A public String urlPrefix = RuntimeEnvironment.getInstance().getUrlPrefix();
0N/A public Annotation annotation;
0N/A public Project project;
0N/A protected Definitions defs;
0N/A /** EOF value returned by yylex(). */
0N/A private final int yyeof;
0N/A
0N/A protected JFlexXref() {
65N/A try {
65N/A // TODO when bug #16053 is fixed, we should add a getter to a file
65N/A // that's included from all the Xref classes so that we avoid the
65N/A // reflection.
0N/A Field f = getClass().getField("YYEOF");
30N/A yyeof = f.getInt(null);
58N/A } catch (Exception e) {
260N/A // The auto-generated constructors for the Xref classes don't
112N/A // expect a checked exception, so wrap it in an AssertionError.
0N/A // This should never happen, since all the Xref classes will get
0N/A // a public static YYEOF field from JFlex.
0N/A AssertionError ae = new AssertionError("Couldn't initialize yyeof");
260N/A ae.initCause(e);
0N/A throw ae; // NOPMD (stack trace is preserved by initCause(), but
0N/A // PMD thinks it's lost)
0N/A }
0N/A }
0N/A
11N/A /**
0N/A * Reinitialize the xref with new contents.
240N/A *
58N/A * @param contents a char buffer with text to analyze
58N/A * @param length the number of characters to use from the char buffer
58N/A */
58N/A public void reInit(char[] contents, int length) {
77N/A yyreset(new CharArrayReader(contents, 0, length));
207N/A annotation = null;
207N/A }
261N/A
260N/A public void setDefs(Definitions defs) {
77N/A this.defs = defs;
260N/A }
112N/A
77N/A protected void appendProject() throws IOException {
77N/A if (project != null) {
77N/A out.write("&project=");
77N/A out.write(project.getDescription());
260N/A }
77N/A }
77N/A
77N/A protected String getProjectPostfix() {
0N/A return project == null ? "" : ("&project=" + project.getDescription());
77N/A }
111N/A
111N/A /** Get the next token from the scanner. */
111N/A public abstract int yylex() throws IOException;
111N/A
111N/A /** Reset the scanner. */
111N/A public abstract void yyreset(Reader reader);
111N/A
111N/A /** Get the value of {@code yyline}. */
111N/A protected abstract int getLineNumber();
111N/A
111N/A /** Set the value of {@code yyline}. */
111N/A protected abstract void setLineNumber(int x);
77N/A
77N/A /**
77N/A * Write xref to the specified {@code Writer}.
207N/A *
207N/A * @param out xref destination
77N/A * @throws IOException on error when writing the xref
77N/A */
207N/A public void write(Writer out) throws IOException {
207N/A this.out = out;
77N/A setLineNumber(0);
77N/A startNewLine();
99N/A while (yylex() != yyeof) { // NOPMD while statement intentionally empty
77N/A // nothing to do here, yylex() will do the work
77N/A }
77N/A }
77N/A
77N/A /**
77N/A * Terminate the current line and insert preamble for the next line. The
77N/A * line count will be incremented.
77N/A *
0N/A * @throws IOException on error when writing the xref
77N/A */
77N/A protected void startNewLine() throws IOException {
77N/A int line = getLineNumber() + 1;
77N/A setLineNumber(line);
77N/A Util.readableLine(line, out, annotation);
77N/A }
77N/A
77N/A /**
77N/A * Write a symbol and generate links as appropriate.
77N/A *
77N/A * @param symbol the symbol to write
111N/A * @param keywords a set of keywords recognized by this analyzer (no links
111N/A * will be generated if the symbol is a keyword)
77N/A * @param line the line number on which the symbol appears
77N/A * @throws IOException if an error occurs while writing to the stream
77N/A */
240N/A protected void writeSymbol(String symbol, Set<String> keywords, int line)
173N/A throws IOException {
173N/A String[] strs = new String[1];
173N/A strs[0] = "";
173N/A
254N/A if (keywords != null && keywords.contains(symbol)) {
173N/A // This is a keyword, so we don't create a link.
173N/A out.append("<b>").append(symbol).append("</b>");
173N/A
254N/A } else if (defs != null && defs.hasDefinitionAt(symbol, line, strs)) {
173N/A // This is the definition of the symbol.
173N/A String type = strs[0];
173N/A String style_class = "d";
253N/A
253N/A if (type.startsWith("macro")) {
253N/A style_class = "xm";
253N/A } else if (type.startsWith("argument")) {
253N/A style_class = "xa";
253N/A } else if (type.startsWith("local")) {
253N/A style_class = "xl";
253N/A } else if (type.startsWith("variable")) {
253N/A style_class = "xv";
253N/A } else if (type.startsWith("class")) {
253N/A style_class = "xc";
253N/A } else if (type.startsWith("interface")) {
99N/A style_class = "xi";
77N/A } else if (type.startsWith("namespace")) {
77N/A style_class = "xn";
77N/A } else if (type.startsWith("enum")) {
77N/A style_class = "xe";
77N/A } else if (type.startsWith("enumerator")) {
0N/A style_class = "xer";
0N/A } else if (type.startsWith("struct")) {
77N/A style_class = "xs";
125N/A } else if (type.startsWith("typedef")) {
77N/A style_class = "xt";
77N/A } else if (type.startsWith("typedefs")) {
205N/A style_class = "xts";
205N/A } else if (type.startsWith("union")) {
205N/A style_class = "xu";
112N/A } else if (type.startsWith("field")) {
112N/A style_class = "xfld";
112N/A } else if (type.startsWith("member")) {
77N/A style_class = "xmb";
106N/A } else if (type.startsWith("function")) {
119N/A style_class = "xf";
106N/A } else if (type.startsWith("method")) {
119N/A style_class = "xmt";
106N/A } else if (type.startsWith("subroutine")) {
119N/A style_class = "xsr";
119N/A }
119N/A
119N/A // 1) Create an anchor for direct links. (Perhaps we should only
106N/A // do this when there's exactly one definition of the symbol in
106N/A // this file? Otherwise, we may end up with multiple anchors with
106N/A // the same name.)
99N/A out.append("<a class=\"");
99N/A out.append(style_class);
99N/A out.append("\" name=\"");
99N/A out.append(symbol);
99N/A out.append("\"/>");
99N/A
99N/A // 2) Create a link that searches for all references to this symbol.
99N/A out.append("<a href=\"");
99N/A out.append(urlPrefix);
125N/A out.append("refs=");
125N/A out.append(symbol);
125N/A appendProject();
125N/A out.append("\" class=\"");
125N/A out.append(style_class);
125N/A out.append("\" ");
125N/A // May have multiple anchors with the same function name,
125N/A // store line number for accurate location used in list.jsp.
125N/A out.append("ln=\"");
126N/A out.append(Integer.toString(line));
125N/A out.append("\">");
125N/A out.append(symbol);
125N/A out.append("</a>");
126N/A
126N/A } else if (defs != null && defs.occurrences(symbol) == 1) {
126N/A // This is a reference to a symbol defined exactly once in this file.
126N/A String style_class = "d";
126N/A
126N/A // Generate a direct link to the symbol definition.
126N/A out.append("<a class=\"");
126N/A out.append(style_class);
126N/A out.append("\" href=\"#");
126N/A out.append(symbol);
126N/A out.append("\">");
126N/A out.append(symbol);
126N/A out.append("</a>");
126N/A
126N/A } else {
126N/A // This is a symbol that is not defined in this file, or a symbol
126N/A // that is defined more than once in this file. In either case, we
126N/A // can't generate a direct link to the definition, so generate a
126N/A // link to search for all definitions of that symbol instead.
210N/A out.append("<a href=\"");
210N/A out.append(urlPrefix);
210N/A out.append("defs=");
210N/A out.append(symbol);
210N/A appendProject();
210N/A out.append("\">");
210N/A out.append(symbol);
126N/A out.append("</a>");
126N/A }
126N/A }
126N/A
144N/A /**
144N/A * Write HTML escape sequence for the specified Unicode character, unless
144N/A * it's an ISO control character, in which case it is ignored.
261N/A *
261N/A * @param c the character to write
261N/A * @throws IOException if an error occurs while writing to the stream
261N/A */
261N/A protected void writeUnicodeChar(char c) throws IOException {
261N/A if (!Character.isISOControl(c)) {
261N/A out.append("&#").append(Integer.toString((int) c)).append(';');
261N/A }
77N/A }
99N/A
0N/A /**
0N/A * Write an e-mail address.
0N/A *
77N/A * @param address the address to write
77N/A * @throws IOException if an error occurs while writing to the stream
205N/A */
77N/A protected void writeEMailAddress(String address) throws IOException {
77N/A out.write(address.replace("@", " (at) "));
77N/A }
77N/A}
77N/A