/******************************************************************************* * 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 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); }