mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-11 14:23:00 -04:00
563 lines
16 KiB
C++
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);
|
|
}
|