c90f71dd8c
special cases and other things in wxPython, and since I plan on making several more, I've decided to put the SWIG sources in wxPython's CVS instead of relying on maintaining patches. This effectivly becomes a fork of an obsolete version of SWIG, :-( but since SWIG 1.3 still doesn't have some things I rely on in 1.1, not to mention that my custom patches would all have to be redone, I felt that this is the easier road to take. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15307 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
608 lines
16 KiB
C++
608 lines
16 KiB
C++
/*******************************************************************************
|
|
* Simplified Wrapper and Interface Generator (SWIG)
|
|
*
|
|
* Author : David Beazley
|
|
*
|
|
* Department of Computer Science
|
|
* University of Chicago
|
|
* 1100 E 58th Street
|
|
* Chicago, IL 60637
|
|
* beazley@cs.uchicago.edu
|
|
*
|
|
* Please read the file LICENSE for the copyright and terms by which SWIG
|
|
* can be used and distributed.
|
|
*******************************************************************************/
|
|
/***********************************************************************
|
|
* $Header$
|
|
*
|
|
* newdoc.cxx
|
|
*
|
|
* SWIG Documentation system. (2nd attempt)
|
|
*
|
|
* SWIG organizes documentation as a tree structure where each node is a
|
|
* documentation entry (DocEntry) of some kind. To generate documentation,
|
|
* we simply traverse the tree and call output methods.
|
|
*
|
|
* A sample documentation tree looks something like the following :
|
|
*
|
|
* TITLE ----> SECTION 1 ----> func1
|
|
* ----> func2
|
|
* ----> func3
|
|
* ----> class ---> func1
|
|
* ---> func2
|
|
* ---> var1
|
|
* ----> func4
|
|
*
|
|
* ----> SECTION 2 ----> func1
|
|
* ----> var1
|
|
*
|
|
* and so on.
|
|
*
|
|
* This structure makes it possible to organize C++ classes and more
|
|
* complicated structures. Hopefully this will provide enough structure
|
|
* for later versions of SWIG.
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include "internal.h"
|
|
#include <ctype.h>
|
|
|
|
extern char *get_time();
|
|
static char *last_name = 0;
|
|
|
|
DocEntry *DocEntry::dead_entries = 0;
|
|
|
|
// Utility function for converting a string to upper case
|
|
|
|
static void str_toupper(char *str) {
|
|
char *c;
|
|
c = str;
|
|
while (*c) {
|
|
*c = toupper(*c);
|
|
c++;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocEntry::~DocEntry
|
|
//
|
|
// Destroy a documentation entry. Destroys this entry and all of
|
|
// its children.
|
|
// --------------------------------------------------------------------
|
|
|
|
DocEntry::~DocEntry() {
|
|
DocEntry *de, *de1;
|
|
|
|
if (name) delete name;
|
|
|
|
// Now kill all of the children (well, figuratively speaking)
|
|
|
|
de = child;
|
|
while (de) {
|
|
de1 = de->next;
|
|
delete de;
|
|
de = de1;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// void DocEntry::sort_children()
|
|
//
|
|
// Sort children by name (not height). This function gathers all
|
|
// of the children up into an array of pointers. Then we do an
|
|
// insertion sort on it and place the children back in order.
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocEntry::sort_children() {
|
|
|
|
int count = 0;
|
|
int i,j;
|
|
DocEntry *d;
|
|
DocEntry **list;
|
|
DocEntry *v;
|
|
|
|
if (!child) return; // Nothing to sort
|
|
|
|
d = child;
|
|
while (d) {
|
|
count++;
|
|
d = d->next;
|
|
}
|
|
|
|
// allocate a temporary array for sorting everything
|
|
|
|
list = new DocEntry *[count+2];
|
|
|
|
// Now put pointers into list
|
|
|
|
d = child;
|
|
i = 0;
|
|
while (d) {
|
|
list[i] = d;
|
|
d = d->next;
|
|
i++;
|
|
}
|
|
|
|
// Do an insertion sort by name
|
|
|
|
for (i = 1; i < count; i++) {
|
|
v = list[i];
|
|
j = i;
|
|
while((j > 0) && (strcmp(list[j-1]->name,v->name) > 0)) {
|
|
list[j] = list[j-1];
|
|
j--;
|
|
}
|
|
list[j] = v;
|
|
}
|
|
|
|
// Now, we're going to reorganize the children in order
|
|
|
|
list[count] = 0;
|
|
child = list[0]; // Our child is the first one in the list
|
|
d = child;
|
|
for (i = 0; i < count; i++) {
|
|
d->next = list[i+1];
|
|
d = d->next;
|
|
}
|
|
delete list;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// void DocEntry::output()
|
|
//
|
|
// Output this entry
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocEntry::output(Documentation *) {
|
|
fprintf(stderr,"SWIG (internal) : No output method defined for DocEntry.\n");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocEntry::add(DocEntry *de)
|
|
//
|
|
// Adds a new DocEntry as a sibling. Basically we just walk down the
|
|
// linked list and append ourselves to the end. The documentation
|
|
// Entry we're adding may, in fact, have siblings too, but this function
|
|
// Should still work.
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocEntry::add(DocEntry *de) {
|
|
DocEntry *d,*d1;
|
|
d = next;
|
|
d1 = this;
|
|
while (d) {
|
|
d1 = d;
|
|
d = d->next;
|
|
}
|
|
d1->next = de;
|
|
de->previous = d1; // Set up the previous list member
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocEntry::addchild(DocEntry *de)
|
|
//
|
|
// Adds a new DocEntry as a child. If we're in Ignore mode, the
|
|
// documentation entry is still created, but we simply abandon it.
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocEntry::addchild(DocEntry *de) {
|
|
if (!IgnoreDoc) {
|
|
if (child) child->add(de);
|
|
else child = de;
|
|
} else {
|
|
if (dead_entries) dead_entries->add(de);
|
|
else dead_entries = de;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocEntry::remove()
|
|
//
|
|
// Removes a documentation entry from the tree and places it on
|
|
// the dead_entries list
|
|
// -------------------------------------------------------------------
|
|
|
|
void DocEntry::remove() {
|
|
|
|
if (previous) {
|
|
if (next)
|
|
previous->next = next; // Take out of the linked list
|
|
else
|
|
previous->next = 0;
|
|
} else { // Make sure our parent isn't pointing to us
|
|
if (parent)
|
|
parent->child = next;
|
|
}
|
|
|
|
previous = 0;
|
|
next = 0;
|
|
|
|
if (!dead_entries) dead_entries = this;
|
|
else dead_entries->add(this);
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// void DocEntry::style(char *name, char *value)
|
|
//
|
|
// Set style parameters of a documentation entry
|
|
// -------------------------------------------------------------------
|
|
|
|
void DocEntry::style(char *pname, char *) {
|
|
if (strcmp(pname,"sort") == 0) {
|
|
sorted = 1;
|
|
} else if (strcmp(pname,"nosort") == 0) {
|
|
sorted = 0;
|
|
} else if (strcmp(pname,"info") == 0) {
|
|
print_info = 1;
|
|
} else if (strcmp(pname,"noinfo") == 0) {
|
|
print_info = 0;
|
|
} else if (strcmp(pname,"pre") == 0) {
|
|
format = 0;
|
|
} else if (strcmp(pname,"format") == 0) {
|
|
format = 1;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// void DocEntry::parse_args(int argc, char **argv)
|
|
//
|
|
// Take command line options and process them. This really only
|
|
// applies to the top-level documentation entry.
|
|
// -------------------------------------------------------------------
|
|
|
|
static char *doc_usage = "\
|
|
Documentation Processing : \n\
|
|
-Sformat - Reformat comment text\n\
|
|
-Sinfo - Print C formatting information (the default)\n\
|
|
-Snoinfo - Omit C formatting information.\n\
|
|
-Snosort - Print everything in order (the default)\n\
|
|
-Spre - Assume comments are pre-formatted (the default)\n\
|
|
-Ssort - Sort documentation alphabetically\n\n";
|
|
|
|
void DocEntry::parse_args(int argc, char **argv) {
|
|
int i;
|
|
for (i = 1; i < argc; i++) {
|
|
if (argv[i]) {
|
|
if (strcmp(argv[i],"-Ssort") == 0) {
|
|
this->style("sort",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-Snosort") == 0) {
|
|
this->style("nosort",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-Sinfo") == 0) {
|
|
this->style("info",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-Snoinfo") == 0) {
|
|
this->style("noinfo",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-Spre") == 0) {
|
|
this->style("pre",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-Sformat") == 0) {
|
|
this->style("format",0);
|
|
mark_arg(i);
|
|
} else if (strcmp(argv[i],"-help") == 0) {
|
|
fputs(doc_usage,stderr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocTitle::DocTitle(char *title, DocEntry *_parent);
|
|
//
|
|
// Create a new title documentation entry. The name of the entry
|
|
// is the title.
|
|
//
|
|
// The body text is optional, but may be filled in with a description
|
|
// as well.
|
|
// -------------------------------------------------------------------
|
|
|
|
DocTitle::DocTitle(char *title, DocEntry *_parent) {
|
|
name = copy_string(title);
|
|
str_toupper(name);
|
|
parent = _parent;
|
|
child = 0;
|
|
next = 0;
|
|
previous = 0;
|
|
usage << title << "\n";
|
|
counter = 1;
|
|
is_separator = 1;
|
|
line_number = ::start_line;
|
|
end_line = ::line_number;
|
|
file = copy_string(input_file);
|
|
if (_parent) {
|
|
sorted = _parent->sorted;
|
|
format = _parent->format;
|
|
print_info = _parent->print_info;
|
|
} else {
|
|
sorted = SWIGDEFAULT_SORT;
|
|
format = SWIGDEFAULT_FORMAT;
|
|
print_info = SWIGDEFAULT_INFO;
|
|
}
|
|
comment_handler->set_entry(this);
|
|
if (last_name) delete last_name;
|
|
last_name = 0;
|
|
}
|
|
// --------------------------------------------------------------------
|
|
// DocTitle::output(Documentation *d)
|
|
//
|
|
// Output a title to the Documentation module
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocTitle::output(Documentation *d) {
|
|
DocEntry *de;
|
|
|
|
d->title(this);
|
|
if (sorted) {
|
|
sort_children();
|
|
}
|
|
|
|
// Now output my children
|
|
|
|
de = child;
|
|
while (de) {
|
|
de->output(d);
|
|
de = de->next;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocSection::DocSection(char *section, DocEntry *_parent);
|
|
//
|
|
// Create a new documentation section. The name and description is
|
|
// set to the name of the section. The text field is optional
|
|
// but could contain a more complete description.
|
|
//
|
|
// The sorted field indicates whether members of this section are
|
|
// sorted or not.
|
|
// -------------------------------------------------------------------
|
|
|
|
DocSection::DocSection(char *section, DocEntry *_parent) {
|
|
name = copy_string(section);
|
|
str_toupper(name);
|
|
parent = _parent;
|
|
child = 0;
|
|
next = 0;
|
|
previous = 0;
|
|
usage << section;
|
|
counter = 1;
|
|
is_separator = 1;
|
|
if (_parent) _parent->addchild(this);
|
|
line_number = ::start_line;
|
|
end_line = ::line_number;
|
|
file = copy_string(input_file);
|
|
if (_parent) {
|
|
sorted = _parent->sorted;
|
|
format = _parent->format;
|
|
print_info = _parent->print_info;
|
|
} else {
|
|
sorted = SWIGDEFAULT_SORT;
|
|
format = SWIGDEFAULT_FORMAT;
|
|
print_info = SWIGDEFAULT_INFO;
|
|
}
|
|
comment_handler->set_entry(this);
|
|
if (last_name) delete last_name;
|
|
last_name = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocSection::output(Documentation *d)
|
|
//
|
|
// Output a section to the documentation module
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocSection::output(Documentation *d) {
|
|
DocEntry *de;
|
|
|
|
// Make a new section
|
|
|
|
d->newsection(this,this->parent->counter++); // Make a new section
|
|
|
|
// Sort the children if necessary
|
|
|
|
if (sorted) {
|
|
sort_children();
|
|
}
|
|
|
|
// Now output my children
|
|
|
|
de = child;
|
|
while (de) {
|
|
de->output(d);
|
|
de = de->next;
|
|
}
|
|
|
|
// End this section
|
|
|
|
d->endsection();
|
|
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocDecl::DocDecl(char *fname, DocEntry *_parent);
|
|
//
|
|
// Create documentation for a function declaration.
|
|
// -------------------------------------------------------------------
|
|
|
|
DocDecl::DocDecl(char *fname, DocEntry *_parent) {
|
|
name = copy_string(fname);
|
|
str_toupper(name);
|
|
parent = _parent;
|
|
child = 0;
|
|
next = 0;
|
|
previous = 0;
|
|
is_separator = 0;
|
|
if (_parent) _parent->addchild(this);
|
|
line_number = ::start_line;
|
|
end_line = ::line_number;
|
|
file = copy_string(input_file);
|
|
if (_parent) {
|
|
sorted = _parent->sorted;
|
|
format = _parent->format;
|
|
print_info = _parent->print_info;
|
|
} else {
|
|
sorted = SWIGDEFAULT_SORT;
|
|
format = SWIGDEFAULT_FORMAT;
|
|
print_info = SWIGDEFAULT_INFO;
|
|
}
|
|
comment_handler->set_entry(this);
|
|
if (last_name) delete last_name;
|
|
last_name = copy_string(name);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocDecl::DocDecl(DocEntry *de, DocEntry *_parent)
|
|
//
|
|
// Make a new declaration entry, but copy attributes from someone else
|
|
// --------------------------------------------------------------------
|
|
|
|
DocDecl::DocDecl(DocEntry *de, DocEntry *_parent) {
|
|
name = copy_string(de->name);
|
|
usage = de->usage.get();
|
|
cinfo = de->cinfo.get();
|
|
text = de->text.get();
|
|
line_number = de->line_number;
|
|
end_line = de->end_line;
|
|
file = copy_string(de->file);
|
|
print_info = de->print_info;
|
|
format = de->format;
|
|
if (_parent) {
|
|
_parent->addchild(this);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocDecl::output(Documentation *d)
|
|
//
|
|
// Output a function to the documentation module
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocDecl::output(Documentation *d) {
|
|
d->print_decl(this);
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocClass::DocClass(char *classname, DocEntry *_parent);
|
|
//
|
|
// Create a new class section. Classes are created as funny sorts of
|
|
// sections.
|
|
//
|
|
// The sorted field indicates whether members of this section are
|
|
// sorted or not.
|
|
// -------------------------------------------------------------------
|
|
|
|
DocClass::DocClass(char *classname, DocEntry *_parent) {
|
|
name = copy_string(classname);
|
|
str_toupper(name);
|
|
parent = _parent;
|
|
child = 0;
|
|
next = 0;
|
|
previous = 0;
|
|
usage << classname<< "\n";
|
|
counter = 1;
|
|
is_separator = 1;
|
|
if (_parent) _parent->addchild(this);
|
|
line_number = ::start_line;
|
|
end_line = ::line_number;
|
|
file = copy_string(input_file);
|
|
if (_parent) {
|
|
sorted = _parent->sorted;
|
|
format = _parent->format;
|
|
print_info = _parent->print_info;
|
|
} else {
|
|
sorted = SWIGDEFAULT_SORT;
|
|
format = SWIGDEFAULT_FORMAT;
|
|
print_info = SWIGDEFAULT_INFO;
|
|
}
|
|
comment_handler->set_entry(this);
|
|
if (last_name) delete last_name;
|
|
last_name = copy_string(name);
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocClass::output(Documentation *d)
|
|
//
|
|
// Output a section to the documentation module
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocClass::output(Documentation *d) {
|
|
DocEntry *de;
|
|
|
|
// Make a new section
|
|
|
|
d->newsection(this,this->parent->counter++); // Make a subsection for this
|
|
|
|
// Sort the children if necessary
|
|
|
|
if (sorted) {
|
|
sort_children();
|
|
}
|
|
|
|
// Now output my children
|
|
|
|
de = child;
|
|
while (de) {
|
|
de->output(d);
|
|
de = de->next;
|
|
}
|
|
|
|
// End this section
|
|
|
|
d->endsection();
|
|
|
|
// We now check to see if the next thing is a separator. If not, we'll
|
|
// emit a separator
|
|
|
|
if (next) {
|
|
if (!next->is_separator)
|
|
d->separator();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// DocText::DocText(char *_text, DocEntry *_parent);
|
|
//
|
|
// Create documentation for a function declaration.
|
|
// -------------------------------------------------------------------
|
|
|
|
DocText::DocText(char *_text, DocEntry *_parent) {
|
|
if (!last_name)
|
|
name = copy_string(""); // There is no name for text
|
|
else
|
|
name = copy_string(last_name);
|
|
parent = _parent;
|
|
child = 0;
|
|
next = 0;
|
|
previous = 0;
|
|
text << _text;
|
|
is_separator = 0;
|
|
if (_parent) _parent->addchild(this);
|
|
if (_parent) {
|
|
sorted = _parent->sorted;
|
|
format = _parent->format;
|
|
print_info = _parent->print_info;
|
|
} else {
|
|
sorted = SWIGDEFAULT_SORT;
|
|
format = SWIGDEFAULT_FORMAT;
|
|
print_info = SWIGDEFAULT_INFO;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// DocText::output(Documentation *d)
|
|
//
|
|
// Output a function to the documentation module
|
|
// --------------------------------------------------------------------
|
|
|
|
void DocText::output(Documentation *d) {
|
|
d->print_text(this);
|
|
}
|
|
|