home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Linux
/
DDD331
/
DDD-3_1_.000
/
DDD-3_1_
/
ddd-3.1.1
/
ddd
/
java.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-12-06
|
11KB
|
468 lines
// $Id: java.C,v 1.5.4.2 1998/12/06 13:53:18 zeller Exp $ -*- C++ -*-
// Java class lookup
// Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
//
// This file is part of DDD.
//
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page,
// `http://www.cs.tu-bs.de/softech/ddd/',
// or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
char java_rcsid[] =
"$Id: java.C,v 1.5.4.2 1998/12/06 13:53:18 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
#include "java.h"
#include "SmartC.h"
#include "SourceView.h"
#include "assert.h"
#include "cook.h"
#include "ddd.h"
#include "filetype.h"
#include "glob.h"
#include "regexps.h"
#include "status.h"
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
// Suffixes for Java sources and classes
#define JAVA_SRC_SUFFIX ".java"
#define JAVA_CLASS_SUFFIX ".class"
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
// Don't rely on libiberty basename() because we don't want to depend
// on libiberty include files
static const char *file_basename(const char *name)
{
const char *base = name;
while (*name)
{
if (*name++ == '/')
base = name;
}
return base;
}
#define basename file_basename
static bool is_archive(const string& loc)
{
return loc.contains(".jar", -1) ||
loc.contains(".zip", -1) ||
loc.contains(".JAR", -1) ||
loc.contains(".ZIP", -1);
}
static string concat_dir(const string& dir, const string& file)
{
string mask;
if (dir == "")
mask = file;
else if (dir.contains('/', -1))
mask = dir + file;
else
mask = dir + "/" + file;
return mask;
}
// Store all classes in DIR in CLASSES_LIST. BASE is the initial dir. If
// WITH_SOURCE_ONLY is set, consider only classes with loadable sources.
static void get_java_classes(const string& dir, const string& base,
StringArray& classes_list, bool with_source_only)
{
StatusDelay delay("Scanning " + quote(dir) + " for classes");
assert((base == "" && dir == "") || dir.contains(base, 0));
string mask = concat_dir(dir, "*" JAVA_CLASS_SUFFIX);
// Check for `.class' files in this directory.
char **files = glob_filename(mask);
if (files == (char **)0)
{
delay.outcome = mask + ": glob failed";
}
if (files == (char **)-1)
{
// No `*.class' in this directory
}
else
{
for (int i = 0; files[i] != 0; i++)
{
string file = files[i];
// Build a class name from file name
string class_name;
if (base == "")
{
class_name = file;
}
else
{
class_name = file.after((int)base.length());
if (class_name.contains('/', 0))
class_name = class_name.after('/');
}
strip_java_suffix(class_name);
class_name.gsub('/', '.');
bool have_source = true;
if (with_source_only)
{
// Check whether we have some .java source for
// this class
string class_file = java_class_file(class_name);
have_source = (class_file != "");
}
if (have_source)
{
// Okay - we have a class and a corresponding
// .java source file. Go for it.
classes_list += class_name;
}
free(files[i]);
}
free((char *)files);
}
// Check for `.class' files in subdirectories.
mask = concat_dir(dir, "*");
files = glob_filename(mask);
if (files == (char **)0)
{
delay.outcome = mask + ": glob failed\n";
}
else if (files == (char **)-1)
{
// No `*' in this directory
}
else
{
for (int i = 0; files[i] != 0; i++)
{
string file = basename(files[i]);
free(files[i]);
if (file.matches(rxidentifier))
{
file = concat_dir(dir, file);
if (is_directory(file))
get_java_classes(file, base, classes_list,
with_source_only);
}
}
free((char *)files);
}
}
//-----------------------------------------------------------------------------
// Main functions
//-----------------------------------------------------------------------------
// Store all classes in current use path in CLASSES_LIST. If
// WITH_SOURCE_ONLY is set, consider only classes with loadable sources.
void get_java_classes(StringArray& classes_list, bool with_source_only)
{
string use = source_view->class_path();
while (use != "")
{
// Determine current USE entry
string loc;
if (use.contains(':'))
loc = use.before(':');
else
loc = use;
use = use.after(':');
if (is_archive(loc))
{
// Archive file.
// Should we search this for classes? (FIXME)
continue;
}
if (!is_directory(loc))
{
// Not a directory.
continue;
}
// Get all classes in this directory
get_java_classes(loc, loc, classes_list, with_source_only);
}
smart_sort(classes_list);
}
// Remove `.java' and `.class' suffix from S
void strip_java_suffix(string& s)
{
string s_down = downcase(s);
if (s_down.contains(JAVA_SRC_SUFFIX, -1))
s = s.before(int(int(s.length()) - strlen(JAVA_SRC_SUFFIX)));
if (s_down.contains(JAVA_CLASS_SUFFIX, -1))
s = s.before(int(int(s.length()) - strlen(JAVA_CLASS_SUFFIX)));
}
// Read FILE into S
static void slurp_file(const string& file, string& s)
{
s = "";
FILE *fp = fopen(file, "r");
if (fp == NULL)
return;
while (!feof(fp))
{
char buffer[BUFSIZ];
int nitems = fread(buffer, sizeof(char), BUFSIZ, fp);
s += string(buffer, nitems);
}
fclose(fp);
}
// Return the position of CLASS_NAME definition in TEXT; -1 if none
int java_class_start(const string& text, const string& class_name,
bool first_line)
{
// We search for `class [whitespace] CLASS_NAME [whitespace]'.
int i = -1;
while ((i = text.index("class", i + 1)) >= 0)
{
while (i < int(text.length()) && !isspace(text[i]))
i++;
while (i < int(text.length()) && isspace(text[i]))
i++;
if (text.contains(class_name, i))
{
int start = i;
i += class_name.length();
if (i < int(text.length()) && isspace(text[i]))
{
// Be sure the class name is followed by `{'
while (i < int(text.length()) &&
text[i] != ';' && text[i] != '{')
i++;
if (i < int(text.length()) && text[i] == '{')
{
// Okay, we got it.
if (first_line)
{
// Return first line after `{'
while (i < int(text.length()) &&
text[i - 1] != '\n' && text[i - 1] != '}')
i++;
return i;
}
else
{
// Return start of class definition.
return start;
}
}
}
}
}
return -1;
}
// Check if FILE_NAME has a definition of CLASS_NAME
static bool has_class(const string& file_name, const string& class_name)
{
string src_file;
slurp_file(file_name, src_file);
return java_class_start(src_file, class_name) > 0;
}
// Return source file of CLASS_NAME; "" if none.
static string _java_class_file(const string& class_name, bool search_classes)
{
// We use 4 iterations:
// Trial 0. Search for CLASS_NAME.java; make sure it defines CLASS_NAME.
// Trial 1. Search for CLASS_NAME.class and its .java file, as in 0.
// Trial 2. Search for CLASS_NAME.java, even if CLASS_NAME is not def'd.
// Trial 3. Search for CLASS_NAME.class and its .java file, as in 2.
for (int trial = 0; trial < 4; trial++)
{
string base = class_name;
strip_java_suffix(base);
base.gsub(".", "/");
switch (trial)
{
case 0:
case 2:
base += JAVA_SRC_SUFFIX;
break;
case 1:
case 3:
if (!search_classes)
continue;
base += JAVA_CLASS_SUFFIX;
break;
default:
return ""; // No such trial
}
string use = source_view->class_path();
while (use != "")
{
string loc;
if (use.contains(':'))
loc = use.before(':');
else
loc = use;
use = use.after(':');
if (is_archive(loc))
{
// Archive file.
// Should we search this for classes? (FIXME)
continue;
}
if (!is_directory(loc))
{
// Not a directory.
continue;
}
string file_name;
if (loc == "" || loc == ".")
{
file_name = base;
}
else
{
if (!loc.contains('/', -1))
loc += '/';
file_name = loc + base;
}
switch (trial)
{
case 0:
case 2:
// Look for CLASS_NAME.java
if (is_source_file(file_name) &&
(trial > 0 || has_class(file_name, class_name)))
return file_name;
break;
case 1:
case 3:
{
// Look for CLASS_NAME.class and scan it for
// `SRC.java' occurrences.
if (is_regular_file(file_name))
{
string class_file;
slurp_file(file_name, class_file);
// We begin searching at the end of the file,
// because that's where debugging information is
// usually placed.
int i = class_file.length();
while ((i =
class_file.index(JAVA_SRC_SUFFIX,
i - class_file.length() - 1)) > 0)
{
// The class file contains `.java' at I
string src_class;
string c;
// Find start of name
int start = i;
while (start > 0 && isalnum(class_file[start - 1]))
start--;
src_class = class_file(start, i - start);
// Search for this class file instead.
c = java_class_file(src_class, false);
if (c != "")
return c;
// JDK javac places source file names as \001
// LENGTH NAME, where LENGTH is the length of
// NAME in 2-byte (lo/hi) format. Try this.
while (start >= 0 && class_file[start] != '\001')
start--;
start += 3; // Skip \001 LENGTH
src_class = class_file(start, i - start);
c = java_class_file(src_class, false);
if (c != "")
return c;
}
}
}
}
}
}
return ""; // Not found
}
// Same, but with diagnostics
string java_class_file(const string& class_name, bool search_classes)
{
StatusDelay delay("Searching for " + quote(class_name) + " source");
string c = _java_class_file(class_name, search_classes);
if (c == "")
delay.outcome = "failed";
else
delay.outcome = quote(c);
return c;
}