panda3d/dtool/src/test_interrogate/test_interrogate.cxx
2004-10-22 23:13:49 +00:00

563 lines
16 KiB
C++

// Filename: test_interrogate.cxx
// Created by: drose (09Dec99)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "dtoolbase.h"
#include "interrogate_interface.h"
#include "interrogate_request.h"
#include "load_dso.h"
#include "filename.h"
#include "pystub.h"
#include <stdlib.h>
#ifndef HAVE_GETOPT
#include "gnu_getopt.h"
#else
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#endif
static ostream &
indent(ostream &out, int indent_level) {
for (int i = 0; i < indent_level; i++) {
out << ' ';
}
return out;
}
void
show_type(int type, bool verbose = false) {
cout << interrogate_type_name(type) << " ";
if (verbose) {
if (strcmp(interrogate_type_name(type),
interrogate_type_true_name(type)) != 0) {
cout << "(" << interrogate_type_true_name(type) << ") ";
}
}
cout << "(" << type << ")";
}
void
show_function(int function) {
cout << interrogate_function_scoped_name(function) << " (" << function << ")";
}
void
describe_wrapper(int wrapper, int indent_level) {
indent(cout, indent_level)
<< "Wrapper (" << wrapper << ")";
if (interrogate_wrapper_has_return_value(wrapper)) {
cout << " returns ";
show_type(interrogate_wrapper_return_type(wrapper));
} else {
cout << " no return value";
}
int num_params = interrogate_wrapper_number_of_parameters(wrapper);
cout << ", ";
if (num_params == 0) {
cout << "no parameters.\n";
} else if (num_params == 1) {
cout << "1 parameter:\n";
} else {
cout << num_params << " parameters:\n";
}
for (int i = 0; i < num_params; i++) {
indent(cout, indent_level + 4);
if (interrogate_wrapper_parameter_is_this(wrapper, i)) {
cout << "*";
} else {
cout << i;
}
cout << ": ";
show_type(interrogate_wrapper_parameter_type(wrapper, i));
if (interrogate_wrapper_parameter_has_name(wrapper, i)) {
cout << " '" << interrogate_wrapper_parameter_name(wrapper, i) << "'";
} else {
cout << " (no name)";
}
cout << "\n";
}
if (interrogate_wrapper_caller_manages_return_value(wrapper)) {
indent(cout, indent_level + 2)
<< "Caller manages return value using ";
show_function(interrogate_wrapper_return_value_destructor(wrapper));
cout << "\n";
}
indent(cout, indent_level + 2)
<< "Wrapper name: " << interrogate_wrapper_name(wrapper);
if (interrogate_wrapper_is_callable_by_name(wrapper)) {
cout << " (callable)";
}
cout << "\n";
if (interrogate_wrapper_has_pointer(wrapper)) {
indent(cout, indent_level + 2)
<< "Has pointer: " << interrogate_wrapper_pointer(wrapper) << "\n";
}
string unique_name = interrogate_wrapper_unique_name(wrapper);
indent(cout, indent_level + 2)
<< "Unique name is " << unique_name;
int reverse_lookup = interrogate_get_wrapper_by_unique_name(unique_name.c_str());
if (reverse_lookup == 0) {
cout << " (no reverse lookup)";
} else if (reverse_lookup != wrapper) {
cout << " (*** reverse lookup returns " << reverse_lookup << "! ***)";
}
cout << "\n";
}
void
describe_function(int function, int indent_level) {
indent(cout, indent_level)
<< "Function " << interrogate_function_scoped_name(function)
<< " (" << function << ")\n";
indent(cout, indent_level + 2)
<< "In C: " << interrogate_function_prototype(function) << "\n";
if (interrogate_function_is_method(function)) {
indent(cout, indent_level + 2)
<< "Method of ";
show_type(interrogate_function_class(function));
cout << "\n";
}
if (interrogate_function_is_virtual(function)) {
indent(cout, indent_level + 2) << "is virtual.\n";
}
int w;
int num_c_wrappers = interrogate_function_number_of_c_wrappers(function);
if (num_c_wrappers == 0) {
} else if (num_c_wrappers == 1) {
indent(cout, indent_level + 2)
<< "1 C-style wrapper:\n";
} else {
indent(cout, indent_level + 2)
<< num_c_wrappers << " C-style wrappers:\n";
}
for (w = 0; w < num_c_wrappers; w++) {
describe_wrapper(interrogate_function_c_wrapper(function, w),
indent_level + 4);
}
int num_python_wrappers =
interrogate_function_number_of_python_wrappers(function);
if (num_python_wrappers == 0) {
} else if (num_python_wrappers == 1) {
indent(cout, indent_level + 2)
<< "1 Python-style wrapper:\n";
} else {
indent(cout, indent_level + 2)
<< num_python_wrappers << " Python-style wrappers:\n";
}
for (w = 0; w < num_python_wrappers; w++) {
describe_wrapper(interrogate_function_python_wrapper(function, w),
indent_level + 4);
}
}
void
report_manifests() {
int num_manifests = interrogate_number_of_manifests();
cout << "\n" << num_manifests << " manifests:\n";
for (int i = 0; i < num_manifests; i++) {
int manifest = interrogate_get_manifest(i);
cout << " Manifest " << interrogate_manifest_name(manifest);
if (interrogate_manifest_has_type(manifest)) {
cout << " of type ";
show_type(interrogate_manifest_get_type(manifest));
cout << "\n";
} else {
cout << " of unknown type\n";
}
cout << " definition is \""
<< interrogate_manifest_definition(manifest) << "\"\n";
if (interrogate_manifest_has_getter(manifest)) {
cout << " value getter: ";
show_function(interrogate_manifest_getter(manifest));
cout << "\n";
}
if (interrogate_manifest_has_int_value(manifest)) {
cout << " int value = "
<< interrogate_manifest_get_int_value(manifest)
<< "\n";
}
}
}
void
describe_element(int element, int indent_level) {
indent(cout, indent_level)
<< "Element " << interrogate_element_scoped_name(element)
<< " of type ";
show_type(interrogate_element_type(element));
cout << "\n";
if (interrogate_element_has_getter(element)) {
indent(cout, indent_level + 2)
<< "Getter is ";
show_function(interrogate_element_getter(element));
cout << "\n";
}
if (interrogate_element_has_setter(element)) {
indent(cout, indent_level + 2)
<< "Setter is ";
show_function(interrogate_element_setter(element));
cout << "\n";
}
}
void
report_globals() {
int num_globals = interrogate_number_of_globals();
cout << "\n" << num_globals << " globals:\n";
for (int i = 0; i < num_globals; i++) {
describe_element(interrogate_get_global(i), 2);
}
}
void
describe_type(int type, int indent_level) {
indent(cout, indent_level) << "Type ";
show_type(type, true);
cout << "\n";
if (interrogate_type_is_nested(type)) {
indent(cout, indent_level + 2)
<< "Nested within ";
show_type(interrogate_type_outer_class(type));
cout << "\n";
}
if (interrogate_type_is_atomic(type)) {
indent(cout, indent_level + 2)
<< "atomic " << (int)interrogate_type_atomic_token(type) << "\n";
}
if (interrogate_type_is_unsigned(type)) {
indent(cout, indent_level + 2)
<< "unsigned\n";
}
if (interrogate_type_is_signed(type)) {
indent(cout, indent_level + 2)
<< "signed\n";
}
if (interrogate_type_is_long(type)) {
indent(cout, indent_level + 2)
<< "long\n";
}
if (interrogate_type_is_longlong(type)) {
indent(cout, indent_level + 2)
<< "long long\n";
}
if (interrogate_type_is_short(type)) {
indent(cout, indent_level + 2)
<< "short\n";
}
if (interrogate_type_is_wrapped(type)) {
indent(cout, indent_level + 2)
<< "wrapped ";
show_type(interrogate_type_wrapped_type(type));
cout << "\n";
}
if (interrogate_type_is_pointer(type)) {
indent(cout, indent_level + 2)
<< "pointer\n";
}
if (interrogate_type_is_const(type)) {
indent(cout, indent_level + 2)
<< "const\n";
}
if (interrogate_type_is_fully_defined(type)) {
indent(cout, indent_level + 2)
<< "fully defined\n";
}
if (interrogate_type_is_unpublished(type)) {
indent(cout, indent_level + 2)
<< "undefined because unpublished\n";
}
if (interrogate_type_is_enum(type)) {
indent(cout, indent_level + 2)
<< "is enum type\n";
}
if (interrogate_type_is_struct(type)) {
indent(cout, indent_level + 2)
<< "is struct type\n";
}
if (interrogate_type_is_class(type)) {
indent(cout, indent_level + 2)
<< "is class type\n";
}
if (interrogate_type_is_union(type)) {
indent(cout, indent_level + 2)
<< "is union type\n";
}
int num_enum_values = interrogate_type_number_of_enum_values(type);
if (num_enum_values > 0) {
for (int i = 0; i < num_enum_values; i++) {
indent(cout, indent_level + 4)
<< interrogate_type_enum_value_name(type, i)
<< " = " << interrogate_type_enum_value(type, i) << "\n";
}
}
int num_constructors = interrogate_type_number_of_constructors(type);
if (num_constructors > 0) {
indent(cout, indent_level + 2)
<< num_constructors << " constructors:\n";
for (int i = 0; i < num_constructors; i++) {
describe_function(interrogate_type_get_constructor(type, i), 6);
}
}
if (interrogate_type_has_destructor(type)) {
indent(cout, indent_level + 2)
<< "destructor:\n";
describe_function(interrogate_type_get_destructor(type), 6);
}
int num_casts = interrogate_type_number_of_casts(type);
if (num_casts > 0) {
indent(cout, indent_level + 2)
<< num_casts << " casts:\n";
for (int i = 0; i < num_casts; i++) {
describe_function(interrogate_type_get_cast(type, i), 6);
}
}
int num_methods = interrogate_type_number_of_methods(type);
if (num_methods > 0) {
indent(cout, indent_level + 2)
<< num_methods << " methods:\n";
for (int i = 0; i < num_methods; i++) {
describe_function(interrogate_type_get_method(type, i), 6);
}
}
int num_elements = interrogate_type_number_of_elements(type);
if (num_elements > 0) {
indent(cout, indent_level + 2)
<< num_elements << " elements:\n";
for (int i = 0; i < num_elements; i++) {
describe_element(interrogate_type_get_element(type, i), indent_level + 2);
}
}
int num_derivations = interrogate_type_number_of_derivations(type);
if (num_derivations > 0) {
indent(cout, indent_level + 2)
<< num_derivations << " derivations:\n";
for (int i = 0; i < num_derivations; i++) {
int derivation = interrogate_type_get_derivation(type, i);
indent(cout, indent_level + 4);
show_type(derivation);
if (interrogate_type_derivation_has_upcast(type, i)) {
cout << " (has upcast)";
}
if (interrogate_type_derivation_downcast_is_impossible(type, i)) {
cout << " (downcast is impossible)";
}
if (interrogate_type_derivation_has_downcast(type, i)) {
cout << " (has downcast)";
}
cout << "\n";
/*
if (interrogate_type_derivation_has_upcast(type, i)) {
describe_function(interrogate_type_get_upcast(type, i), 8);
}
if (interrogate_type_derivation_has_downcast(type, i)) {
describe_function(interrogate_type_get_downcast(type, i), 8);
}
*/
}
}
int num_nested_types = interrogate_type_number_of_nested_types(type);
if (num_nested_types > 0) {
indent(cout, indent_level + 2)
<< num_nested_types << " nested types:\n";
for (int i = 0; i < num_nested_types; i++) {
indent(cout, indent_level + 4);
show_type(interrogate_type_get_nested_type(type, i));
cout << "\n";
}
}
}
void
report_global_types() {
int num_types = interrogate_number_of_global_types();
cout << "\n" << num_types << " global types:\n";
for (int i = 0; i < num_types; i++) {
int type = interrogate_get_global_type(i);
describe_type(type, 2);
}
}
void
report_global_functions() {
int num_functions = interrogate_number_of_global_functions();
cout << "\n" << num_functions << " global functions:\n";
for (int i = 0; i < num_functions; i++) {
int function = interrogate_get_global_function(i);
describe_function(function, 2);
}
}
void
report_all_types() {
int num_types = interrogate_number_of_types();
cout << "\n" << num_types << " total types:\n";
for (int i = 0; i < num_types; i++) {
int type = interrogate_get_type(i);
describe_type(type, 2);
}
}
void
report_all_functions() {
int num_functions = interrogate_number_of_functions();
cout << "\n" << num_functions << " total functions:\n";
for (int i = 0; i < num_functions; i++) {
int function = interrogate_get_function(i);
describe_function(function, 2);
}
}
void
usage() {
cerr <<
"\n"
"test_interrogate [opts] libfile.so [libfile.so ...]\n\n"
"Loads the given shared library or libraries, if possible, and reports the\n"
"symbols, types, and functions available within those libraries as reported\n"
"by interrogate.\n\n"
"In lieu of loading a shared library, you may also read the interrogate\n"
"database file directly by specifying a filename like libfile.in. This will\n"
"report the symbols defined in that file only (without pulling in dependent\n"
"files), and will not have any function pointers available.\n\n"
"Options:\n\n"
" -p [path]\n"
" Specify the search path for *.in files. This option may be repeated.\n"
" -f Give a detailed report of each function in the database, including\n"
" synthesized functions like upcasts and downcasts.\n"
" -t Give a detailed report of every type in the database, including types\n"
" like pointers and const pointers.\n"
" -q Quickly load up each shared library, if possible, and then immediately\n"
" exit. Useful for quickly determining whether a library can even load.\n\n";
}
int
main(int argc, char *argv[]) {
extern char *optarg;
extern int optind;
const char *optstr = "p:ftqh";
bool all_functions = false;
bool all_types = false;
bool quick_load = false;
int flag = getopt(argc, argv, optstr);
while (flag != EOF) {
switch (flag) {
case 'p':
interrogate_add_search_path(optarg);
break;
case 'f':
all_functions = true;
break;
case 't':
all_types = true;
break;
case 'q':
quick_load = true;
break;
case 'h':
usage();
exit(0);
default:
exit(1);
}
flag = getopt(argc, argv, optstr);
}
argc -= (optind-1);
argv += (optind-1);
if (argc < 2) {
cerr << "No libraries specified.\n";
exit(1);
}
int return_status = 0;
for (int i = 1; i < argc; i++) {
string param = argv[i];
if (param.length() > 3 && param.substr(param.length() - 3) == ".in") {
// If the filename ends in ".in", it's an interrogate database
// file, not a shared library--read it directly.
interrogate_request_database(param.c_str());
} else {
// Otherwise, assume it's a shared library, and try to load it.
Filename pathname = Filename::dso_filename(argv[i]);
cerr << "Loading " << pathname << "\n";
void *dl = load_dso(pathname);
if (dl == NULL) {
cerr << "Unable to load: " << load_dso_error() << "\n";
return_status++;
}
}
}
if (!quick_load) {
if (all_types) {
report_all_types();
}
if (all_functions) {
report_all_functions();
}
if (!all_types && !all_functions) {
report_manifests();
report_globals();
report_global_types();
report_global_functions();
}
}
return (return_status);
}