📄 ctagreader.java
字号:
package org.fife.ctags;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* A class capable of reading a ctags file and searching for identifiers in it.
* CTags are a useful little tool for things like programmers' text editors.
* See http://ctags.sourceforge.net for more information.<p>
*
* This file is simply a translation of readtags.c from the Exhuberant CTags'
* source distribution into Java. This particular class is public domain.
*
* @author Robert Futrell
* @version 0.01
*/
public class CTagReader {
/* Options for tagsSetSortType() */
public static final byte TAG_UNSORTED = 1;
public static final byte TAG_SORTED = 2;
public static final byte TAG_FOLDSORTED = 3;
/* Options for tagsFind() */
public static final int TAG_FULLMATCH = 0x00;
public static final int TAG_PARTIALMATCH = 0x01;
public static final int TAG_OBSERVECASE = 0x00;
public static final int TAG_IGNORECASE = 0x02;
// Formerly tagResult values.
public static final int TAGRESULT_FAILURE = 0x00;
public static final int TAGRESULT_SUCCESS = 0x01;
// Other #defines found in the code.
private static final int JUMP_BACK = 512;
// Random constants.
public static final String EmptyString = "";
public static final String PseudoTagPrefix = "!_";
private boolean initialized; /* has the file been opened and this structure initialized? */
private int format; /* format of tag file */
private int sortMethod; /* how is the tag file sorted? */
private RandomAccessFile fp; /* pointer to file structure */
private long pos; /* file position of first character of `line' */
private long size; /* size of tag file in seekable positions */
private String line; /* last line read */
private String name; /* name of tag in last line read */
// Was "search" struct.
private long searchPos; /* file position of last match for tag */
private String searchName; /* name of tag last searched for */
private boolean searchPartial; /* peforming partial match */
private boolean searchIgnoreCase; /* ignoring case */
// Was "program" struct.
private String programAuthor; /* name of program author */
private String programName; /* name of program */
private String programUrl; /* URL of distribution */
private String programVersion; /* program version */
/*****************************************************************************/
/**
* Creates a new CTagReader. After this you should call
* <code>tagsOpen</code>.
*/
public CTagReader() {
}
/*****************************************************************************/
/**
* Searches for an indentifier <code>name</code> in the current ctag file.
*
* @param entry The found identifier in the ctag file if success, ???
* or <code>null</code> if it wasn't found ???
* @param name The identifier for which you are searching.
* @param options A bit flag; checks for <code>TAG_PARTIALMATCH</code>
* and <code>TAG_IGNORECASE</code>.
* @return <code>true</code> iff the identifier was found.
*/
private boolean find(TagEntry entry, String name, int options) throws IOException {
boolean result = false;
searchName = name;
searchPartial = (options & TAG_PARTIALMATCH) != 0;
searchIgnoreCase = (options & TAG_IGNORECASE) != 0;
//size = fp.length();
fp.seek(0); // Start over at the beginning for the searches below.
if ((sortMethod == TAG_SORTED && !searchIgnoreCase) || (sortMethod == TAG_FOLDSORTED && searchIgnoreCase))
result = findBinary();
else
result = findSequential();
if (result != true)
searchPos = size;
else {
searchPos = pos;
if (entry != null)
entry.parseTagLine(line);
}
return result;
}
/*****************************************************************************/
private boolean findBinary() throws IOException {
boolean result = false;
long lower_limit = 0;
long upper_limit = size;
long last_pos = 0;
long pos = upper_limit / 2;
while (result != true) {
if (!readTagLineSeek(pos)) {
/* in case we fell off end of file */
result = findFirstMatchBefore();
break;
}
else if (pos == last_pos) {
/* prevent infinite loop if we backed up to beginning of file */
break;
}
else {
int comp = nameComparison();
last_pos = pos;
if (comp < 0) {
upper_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (comp > 0) {
lower_limit = pos;
pos = lower_limit + ((upper_limit - lower_limit) / 2);
}
else if (pos == 0)
result = true;
else
result = findFirstMatchBefore();
}
}
return result;
}
/*****************************************************************************/
private boolean findFirstMatchBefore() throws IOException {
boolean result = false;
boolean more_lines;
long start = pos;
findFirstNonMatchBefore();
do {
more_lines = readTagLine();
if (nameComparison() == 0)
result = true;
} while (more_lines && result!=true && pos<start);
return result;
}
/*****************************************************************************/
private void findFirstNonMatchBefore() {
boolean more_lines;
int comp;
long start = pos;
long pos = start;
do {
if (pos < JUMP_BACK)
pos = 0;
else
pos = pos - JUMP_BACK;
more_lines = readTagLineSeek(pos);
comp = nameComparison();
} while (more_lines && comp==0 && pos>0 && pos<start);
}
/*****************************************************************************/
private boolean findNext(TagEntry entry) throws IOException {
boolean result = false;
if ((sortMethod == TAG_SORTED && !searchIgnoreCase) ||
(sortMethod == TAG_FOLDSORTED && searchIgnoreCase))
{
result = tagsNext(entry);
if (result == true && nameComparison() != 0)
result = false;
}
else {
result = findSequential();
if (result == true && entry != null)
entry.parseTagLine(line);
}
return result;
}
/*****************************************************************************/
private boolean findSequential() throws IOException {
boolean result = false;
if (initialized) {
while (result == false && readTagLine()) {
if (nameComparison() == 0)
result = true;
}
}
return result;
}
/*****************************************************************************/
private int nameComparison() {
int result;
if (searchIgnoreCase) {
if (searchPartial)
//result = strnuppercmp (search.name, name,
result = searchName.compareToIgnoreCase(name.substring(0,searchName.length()));
else
result = searchName.compareToIgnoreCase(name);
}
else {
if (searchPartial)
//result = strncmp (search.name, name, search.nameLength);
result = searchName.compareTo(name.substring(0,searchName.length()));
else
result = searchName.compareTo(name);
}
return result;
}
/*****************************************************************************/
/**
* Retrieves the value associated with the extension field for a given
* key. It is passed a pointer to a structure already populated with
* values by a previous call to <code>tagsNext()</code>,
* <code>tagsFind()</code>, or <code>tagsFindNext()</code>, and a string
* containing the key of the desired extension field. If no such field
* of the specified key exists, the function will return null.
*/
private String readFieldValue(final TagEntry entry, final String key) {
if (key.equals("kind"))
return entry.kind;
else if (key.equals("file"))
return EmptyString;
String result = null;
int size = entry.fieldList.size();
for (int i=0 ; i<size && result==null; i++)
if (key.equals(entry.fieldList.get(i)))
result = (String)entry.fieldList.get(i);
return result;
}
/*****************************************************************************/
private boolean readNext(TagEntry entry) throws IOException {
boolean result = false;
if (!initialized)
result = false;
else if (!readTagLine())
result = false;
else {
if (entry!=null)
entry.parseTagLine(line);
result = true;
}
return result;
}
/*****************************************************************************/
/**
* Reads all the "pseudo-tags" from the top of the ctag file (author, version,
* etc.).
*
* param file The tag file from which to get the pseudotag information.
* @param info The structure in which to place the information.
*/
private void readPseudoTags(TagFileInfo info) throws IOException {
long startOfLine;
final int prefixLength = PseudoTagPrefix.length();
if (info==null)
return;
// Initialize the info structure.
info.format = 1;
info.sort = TAG_UNSORTED;
info.author = null;
info.name = null;
info.url = null;
info.version = null;
// Keep reading in lines until a non-pesudotag line is read.
while (true) {
startOfLine = fp.getFilePointer();
if (!readTagLine())
break;
if (!line.startsWith(PseudoTagPrefix))
break;
else {
TagEntry entry = new TagEntry();
String key, value;
entry.parseTagLine(line); // Fills in entry.
key = entry.name.substring(prefixLength);
value = entry.file;
if (key.equals("TAG_FILE_SORTED"))
sortMethod = Integer.parseInt(value);
else if (key.equals("TAG_FILE_FORMAT"))
format = Integer.parseInt(value);
else if (key.equals("TAG_PROGRAM_AUTHOR"))
programAuthor = value;
else if (key.equals("TAG_PROGRAM_NAME"))
programName = value;
else if (key.equals("TAG_PROGRAM_URL"))
programUrl = value;
else if (key.equals("TAG_PROGRAM_VERSION"))
programVersion = value;
if (info!=null) {
info.format = format;
info.sort = sortMethod;
info.author = programAuthor;
info.name = programName;
info.url = programUrl;
info.version = programVersion;
}
} // End of else.
} // End of while (true).
// Returns file pointer to where we were initially.
fp.seek(startOfLine);
}
/*****************************************************************************/
/**
* Reads the next line from the ctag file. This populates the
* <code>line</code> field so that it can later be passed to a
* <code>TagEntry</code> instance using <code>parseTagLine</code>.
*
* @return <code>true</code> if the next line is successfully read, or
* <code>false</code> if EOF is encountered.
* @throws IOException If an I/O exception occurs.
*/
private boolean readTagLine() throws IOException {
line = fp.readLine();
// Copy the name from the line into the main name field.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -