]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wxSWIG/SWIG/comment.cxx
Since I have made several changes to SWIG over the years to accomodate
[wxWidgets.git] / wxPython / wxSWIG / SWIG / comment.cxx
diff --git a/wxPython/wxSWIG/SWIG/comment.cxx b/wxPython/wxSWIG/SWIG/comment.cxx
new file mode 100644 (file)
index 0000000..5aade8c
--- /dev/null
@@ -0,0 +1,697 @@
+/*******************************************************************************
+ * 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.
+ *******************************************************************************/
+
+#include "internal.h"
+
+/*******************************************************************************
+ * $Header$
+ *
+ * File : comment.cxx
+ *
+ * This is a semi-magical module for associating C/C++ comments with 
+ * documentation entries.   While this sounds like it might be easy,
+ * there are a number of subtle problems getting things to associate
+ * correctly.
+ *
+ * Here's the general idea :
+ *
+ *      1.   The parser and scanner feed both C comments and documentation
+ *           entries to this class.    These may show up in really bizarre
+ *           orders (not necessarily the order seen in an interface file). 
+ *
+ *      2.   We maintain separate lists of comments and documentation 
+ *           entries.
+ *
+ *      3.   Periodically, we go through the list of documentation entries
+ *           and see if we can associate any comments.
+ *
+ *      4.   Upon completion of parsing, it's critical that we cleanup
+ *           the lists using the cleanup() method.
+ *
+ *******************************************************************************/
+
+// -----------------------------------------------------------------------------
+// struct Comment
+// 
+// Structure used to maintain a linked list of comments for later use.
+// -----------------------------------------------------------------------------
+
+class Comment {
+public:  
+  String          *text;                   // Text of the comment
+  int              first_line;             // First line of the comment
+  int              last_line;              // Last line of the comment
+  int              column;                 // First column of comment
+  char            *file;                   // Name of the file that it was in
+  Comment         *next;                   // Next comment (when in a linked list)
+  Comment         *prev;                   // Previous comment
+  static Comment  *comment_list;           // List of all comments
+
+  Comment(char *t, int line, int col, char *f);
+  ~Comment();
+  static Comment *find(DocEntry *de, CommentHandler *ch);
+  void attach(DocEntry *de, CommentHandler *ch);
+};
+
+
+// -----------------------------------------------------------------------
+// Create a new comment.  Automatically puts it on the linked list
+// -----------------------------------------------------------------------
+Comment::Comment(char *t, int line, int col, char *f) {
+    int   nlines = 0;
+    char *c;
+
+    text = new String(t);
+    c = t;
+    while (*c) {
+      if (*c == '\n') nlines++;
+      c++;
+    }
+    first_line = line;
+    column = col;
+    last_line = line + nlines - 1;
+    file = copy_string(f);
+    if (comment_list) {
+      comment_list->prev = this;
+    }
+    next = comment_list;
+    comment_list = this;
+    prev = 0;
+}
+
+// -----------------------------------------------------------------------
+// Destroy a comment
+// -----------------------------------------------------------------------
+Comment::~Comment() {
+    delete text;
+    delete file;
+    // Remove from linked list (if applicable)
+    if (prev) {
+      prev->next = next;
+    }
+    if (next) {
+      next->prev = prev;
+    }
+    if (this == comment_list) comment_list = next;
+}
+// -----------------------------------------------------------------------
+// find(DocEntry *de, CommentHandler *ch)
+// 
+// This function tries to a find a comment matching the search criteria
+// of a given comment handler and documentation entry.
+// -----------------------------------------------------------------------
+  
+Comment *Comment::find(DocEntry *de, CommentHandler *ch) {
+    Comment *c;
+
+    c = comment_list;
+
+    // Start walking down our list of stored comments
+
+    while (c) {
+      //      printf("Searching %x : %s\n", c, c->text->get());
+      if (strcmp(de->file,c->file) == 0) {
+
+       // At least comment is in the right file.  Now check line numbers
+
+       if (ch->location == BEFORE) {
+         
+         // Check to see if the last line of the comment is close
+         // enough to our declaration.
+
+         if ((c->last_line <= de->line_number) && 
+             ((de->line_number - c->last_line) <= ch->skip_lines)) {
+           return c;
+         }
+       } else {     // AFTER mode
+         // Check to see if the first line of the comment is close
+         // enough to our declaration.
+
+         if ((c->first_line >= de->end_line) &&
+             ((c->first_line - de->end_line) <= ch->skip_lines)) {
+           return c;
+         }
+       }
+       // Check to see if the line numbers are too small.  Comments
+       // are processed in order so there's no sense in checking
+       // all entries.
+
+       if (c->last_line < de->line_number)
+         return 0;
+
+      }
+      c = c->next;
+    }
+    return 0;
+}
+
+// -----------------------------------------------------------------------
+// void attach(DocEntry *de, CommentHandler *ch)
+// 
+// This function attachs a comment to a documentation entry and applies
+// all of the style information in the comment handler.
+// -----------------------------------------------------------------------
+void Comment::attach(DocEntry *de, CommentHandler *ch) {
+    int    nlines = 0;
+    char   **split = 0;
+    char   *c;
+    int    i,lnum,el;
+    if (!de) return;
+
+    // If we're ignoring comments, forget it
+    if (ch->ignore) {
+      return;
+    }
+
+    // If the comment is formatted, no style processing is applied
+
+    if (de->format) {
+      de->text << *text;
+      return;
+    }
+
+    // Untabify the comment
+
+    if (ch->untabify) text->untabify(); 
+
+    // Count how many lines we have
+
+    c = text->get();
+    while (*c) {
+      if (*c == '\n') nlines++;
+      c++;
+    }
+
+    if (nlines == 0) return;
+
+    // Tokenize the documentation string into lines
+
+    split = new char*[nlines+1];
+    c = text->get();
+    i = 0;
+    split[i] = c;
+    while (*c) {
+      if (*c == '\n') {
+       *(c++) = 0;
+       split[++i] = c;
+      } else c++;
+    }
+    lnum = 0;
+
+    // Now process the chop_top and chop_bottom values
+    // if nlines < (chop_top + chop_bottom), then we do nothing
+
+    if (nlines > (ch->chop_top + ch->chop_bottom)) {
+      lnum += ch->chop_top;
+      el = nlines-ch->chop_bottom;
+    } else {
+      el = nlines;
+    }
+
+    // Now process in-between lines
+
+    while (lnum < el) {
+      /* Chop line */
+      if (split[lnum]) {
+       if (strlen(split[lnum]) > (unsigned) (ch->chop_left+ch->chop_right)) {
+         if (ch->chop_right > 0) 
+           split[lnum][strlen(split[lnum]) - ch->chop_right] = 0;
+         de->text << &split[lnum][ch->chop_left];
+       }
+      }
+      lnum++;
+      de->text << "\n";
+    }
+
+    //    printf("*** ATTACHING %s : %s\n", de->usage.get(), de->text.get());
+    delete split;
+}
+
+
+CommentHandler     *comment_handler = 0;
+Comment            *Comment::comment_list = 0;
+
+// ------------------------------------------------------------------------
+// struct DocEntryList
+//
+// This structure manages a linked list of documentation entries that
+// haven't had comments attached to them yet.
+//
+// As a general rule, this list tends to remain rather short.
+// ------------------------------------------------------------------------
+
+struct DocEntryList {
+  DocEntry         *de;
+  CommentHandler   *ch;
+  DocEntryList     *next;
+  DocEntryList     *prev;
+  static DocEntryList *doc_list;
+  
+  // -----------------------------------------------------------------------
+  // Create a new list entry
+  // -----------------------------------------------------------------------
+  DocEntryList(DocEntry *d, CommentHandler *c) {
+
+    de = d;
+    ch = c;
+    next = doc_list;
+    prev = 0;
+    if (doc_list)
+      doc_list->prev = this;
+    doc_list = this;
+
+    // Only allow a few doc entries to survive
+
+    if (this->next) {
+      if (this->next->next) {
+       delete this->next->next;
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------------
+  // Destroy a list entry
+  // -----------------------------------------------------------------------
+  ~DocEntryList() {
+    if (prev) {
+      prev->next = next;
+    }
+    if (next) {
+      next->prev = prev;
+    }
+    if (this == doc_list) doc_list = next;
+  };
+  
+  // -----------------------------------------------------------------------
+  // static check()
+  //
+  // Checks the list of documentation entries to see if any can be associated.
+  // -----------------------------------------------------------------------
+
+  static void check() {
+    
+    DocEntryList *dl, *dl_temp;
+    Comment      *cmt;
+
+    //    printf ("Checking\n");
+    dl = doc_list;
+    while (dl) {
+      cmt = Comment::find(dl->de,dl->ch);
+      if (cmt) {
+       // Okay, we found a matching comment. Attach it to this
+       // documentation entry.
+       cmt->attach(dl->de,dl->ch);
+
+       // Destroy the comment and doc list entry
+       delete cmt;
+
+       // Declarations are always coming in order so we're going
+       // to blow away all of them past this point
+
+       dl_temp = dl->next;
+       delete dl;
+       dl = dl_temp;
+      } else {
+       dl = dl->next;
+      }
+    }
+  }
+};
+
+
+DocEntryList  *DocEntryList::doc_list = 0;
+
+// -----------------------------------------------------------------------------
+// CommentHandler::CommentHandler()
+//
+// Constructor.  Creates a new comment handler.  Sets up some default values
+// for comment handling. 
+// 
+// Inputs : None
+//
+// Output : New CommentHandler object.
+//
+// Side Effects : Sets default comment handling parameters.
+// -----------------------------------------------------------------------------
+
+CommentHandler::CommentHandler() {
+  skip_lines = 1;
+  location = AFTER;
+  chop_top = 0;
+  chop_bottom = 0;
+  chop_left = 3;
+  chop_right = 0;
+  untabify = 1;
+  ignore = 0;
+}
+
+// -----------------------------------------------------------------------------
+// CommentHandler::CommentHandler(CommentHandler *c) 
+// 
+// Constructor.  Creates a new comment handler, but copies attributes from 
+// another handler.
+//
+// Inputs : 
+//          c   = A different comment handler.
+//
+// Output : A new CommentHandler object.
+//
+// Side Effects : None
+// -----------------------------------------------------------------------------
+
+CommentHandler::CommentHandler(CommentHandler *c) {
+  skip_lines = c->skip_lines;
+  location = c->location;
+  chop_top = c->chop_top;
+  chop_bottom = c->chop_bottom;
+  chop_left = c->chop_left;
+  chop_right = c->chop_right; 
+  untabify = c->untabify;
+  ignore = c->ignore;
+}
+
+// -----------------------------------------------------------------------------
+// CommentHandler::~CommentHandler()
+// 
+// Destructor.  Destroys a comment handler.  Does nothing interesting at the
+// moment.
+//
+// Inputs : None
+//
+// Output : None
+//
+// Side Effects : None
+// -----------------------------------------------------------------------------
+
+CommentHandler::~CommentHandler() {
+}
+
+// -----------------------------------------------------------------------------
+// void CommentHandler::add_comment(char *text, int line_num, int col, char *file)
+//
+// This function takes a character string as comment text and appends
+// it to the current comment string (which is held in Comment::comment_list)
+//
+//     1.   If two comments appear in successive lines, they are
+//          concatenated.   This is to handle C++ style comments like the
+//          one surrounding this text.
+//
+//     2.   If a new comment appears, we simply create a new one
+// 
+// Inputs :
+//          text     = Text of the comment
+//          line_num = Starting line number of the comment
+//          col      = Starting column of the comment
+//          file     = File in which the comment was located.
+//
+// Output : None
+//
+// Side Effects :
+//          Saves the comment in an internal linked list.
+//          If multiple comments appear in succession, some may end up
+//          in our comment list permanently (ie. never attached to any
+//          particular declaration).
+// -----------------------------------------------------------------------------
+
+void CommentHandler::add_comment(char *text, int line_num, int col, char *file) {
+
+  char *c;
+  int  nlines = 0;
+  Comment *cmt;
+
+  //  printf("line_num = %d, %s\n", line_num,text);
+
+  // Count up how many lines are in this comment
+
+  c = text;
+  while (*c) {
+    if (*c == '\n') nlines++;
+    c++;
+  }
+
+  // Check to see if this comment is in a successive line to the last one
+
+  cmt = Comment::comment_list;
+  
+  if (cmt) {
+    
+    // Check for column alignment
+    if ((cmt->column == col) && (line_num == (cmt->last_line + 1)) &&
+       (nlines <= 1)) {
+      *(cmt->text) << text;
+      cmt->last_line = line_num + nlines - 1;
+    } else {
+    // This is a new comment, add it to our list
+      cmt = new Comment(text,line_num,col,file);
+    }
+  } else {
+    cmt = new Comment(text,line_num,col,file);
+  }
+}
+
+// -----------------------------------------------------------------------------
+// void CommentHanlder::set_entry(DocEntry *d)
+//
+// This grabs a DocEntry and hangs onto it.
+//
+// We will place the doc entry into our documentation list and then
+// check it to see if any comments are sitting around.
+// 
+// Inputs : d = Documentation Entry
+//
+// Output : None
+//
+// Side Effects :
+//          May attach comments to the documentation entry.  In this case,
+//          comments and DocEntries may be removed from internal lists.
+// -----------------------------------------------------------------------------
+
+void CommentHandler::set_entry(DocEntry *d) {
+
+  //  printf("Set entry : file: %s, line %d, %s\n", d->file, d->line_number, d->usage.get());
+
+  // Create a new list entry and save it
+
+  new DocEntryList(d,this);
+
+  // Check all of the documentation entries to see if they can be placed
+
+  DocEntryList::check();
+
+}
+
+// -----------------------------------------------------------------------------
+// static void CommentHandler::cleanup() 
+// 
+// Checks all documentation entries and sees if there are any comments available.
+// If so, they are attached.  This function is usually only called upon completion
+// of parsing.
+//
+// Inputs : None
+//
+// Output : None
+//
+// Side Effects : 
+//          Removes documentation entries and comments from internal lists.
+//          
+// -----------------------------------------------------------------------------
+
+void CommentHandler::cleanup() {
+  int nc, nd;
+  Comment *c;
+  DocEntryList *d;
+
+  DocEntryList::check();
+
+  // Figure out how bad we're doing on memory
+
+  nc = 0;
+  nd = 0;
+  c = Comment::comment_list;
+  while (c) {
+    nc++;
+    c = c->next;
+  }
+  
+  d = DocEntryList::doc_list;
+  while(d) {
+    nd++;
+    d = d->next;
+  }
+
+  if (Verbose) {
+    printf("%d unprocessed comments, %d unprocessed doc entries.\n",nc,nd);
+  }
+}
+
+// -----------------------------------------------------------------------------
+// void CommentHandler::style(char *name, char *value)
+// 
+// Processes comment handling style parameters. The following parameters
+// are available :
+//
+//          after           - Comments appear after a declaration
+//          before          - Comments appear before a declaration
+//          skip            - Number of blank lines between comment and decl.
+//          chop_top        - Number of lines to chop from top of a comment
+//          chop_bottom     - Number of lines to chop from bottom of a comment
+//          chop_left       - Number of characters to chop from left
+//          chop_right      - Number of characters to chop from right
+//          tabify          - Leave tabs in comment text
+//          untabify        - Strip tabs and convert them into spaces.
+//          ignore          - Ignore comments
+//          enable          - Enable comments
+//
+// Inputs :
+//          name            - Name of style parameter
+//          value           - Optional parameter value
+//
+// Output : None
+//
+// Side Effects : Changes style of comment handler object.
+//           
+// -----------------------------------------------------------------------------
+
+void CommentHandler::style(char *name, char *value) {
+
+  if (strcmp(name,"before") == 0) {
+    location = BEFORE;
+  } else if (strcmp(name,"after") == 0) {
+    location = AFTER;
+  } else if (strcmp(name,"skip") == 0) {
+    if (value) 
+      skip_lines = atoi(value);
+  } else if (strcmp(name,"chop_top") == 0) {
+    if (value) 
+      chop_top = atoi(value);
+  } else if (strcmp(name,"chop_bottom") == 0) {
+    if (value) 
+      chop_bottom = atoi(value);
+  } else if (strcmp(name,"chop_left") == 0) {
+    if (value) 
+      chop_left = atoi(value);
+  } else if (strcmp(name,"chop_right") == 0) {
+    if (value) 
+      chop_right = atoi(value);
+  } else if (strcmp(name,"tabify") == 0) {
+    untabify = 0;
+  } else if (strcmp(name,"untabify") == 0) {
+    untabify = 1;
+  } else if (strcmp(name,"ignore") == 0) {
+    ignore = 1;
+  } else if (strcmp(name,"enable") == 0) {
+    ignore = 0;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// void CommentHandler::parse_args(int argc, char **argv)
+//
+// Function for processing command line options given on the SWIG command line.
+// See the help string below for available options.
+// 
+// Inputs : 
+//          argc = Argument count
+//          argv = Argument strings
+//
+// Output : None
+//
+// Side Effects :
+//          Changes various style parameters for the top-level CommentHandler.
+// -----------------------------------------------------------------------------
+
+static char *comment_usage = "\
+Comment Style Options : \n\
+     -Safter         - Use comments after a declaration.\n\
+     -Sbefore        - Use comments before a declaration.\n\
+     -Schop_bottom n - Chop n lines from bottom of comments.\n\
+     -Schop_left n   - Chop n characters from left of a comment.\n\
+     -Schop_right n  - Chop n characters from right of a comment.\n\
+     -Schop_top n    - Chop n lines from top of comments.\n\
+     -Signore        - Ignore comments.\n\
+     -Sskip n        - Max lines between comment and declaration.\n\
+     -Stabify        - Do not convert tabs.\n\
+     -Suntabify      - Convert tabs into spaces (the default).\n\n";
+
+void CommentHandler::parse_args(int argc, char **argv) {
+  int i;
+
+  for (i = 1; i < argc; i++) {
+      if (argv[i]) {
+         if (strcmp(argv[i],"-Sbefore") == 0) {
+           this->style("before",0);
+           mark_arg(i);
+         } else if (strcmp(argv[i],"-Safter") == 0) {
+           this->style("after",0);
+           mark_arg(i);
+         } else if (strcmp(argv[i],"-Schop_top") == 0) {
+           if (argv[i+1]) {
+             this->style("chop_top",argv[i+1]);
+             mark_arg(i);
+             mark_arg(i+1);
+             i++;
+           } else {
+             arg_error();
+           }
+         } else if (strcmp(argv[i],"-Schop_bottom") == 0) {
+           if (argv[i+1]) {
+             this->style("chop_bottom",argv[i+1]);
+             mark_arg(i);
+             mark_arg(i+1);
+             i++;
+           } else {
+             arg_error();
+           }
+         } else if (strcmp(argv[i],"-Schop_left") == 0) {
+           if (argv[i+1]) {
+             this->style("chop_left",argv[i+1]);
+             mark_arg(i);
+             mark_arg(i+1);
+             i++;
+           } else {
+             arg_error();
+           }
+         } else if (strcmp(argv[i],"-Schop_right") == 0) {
+           if (argv[i+1]) {
+             this->style("chop_right",argv[i+1]);
+             mark_arg(i);
+             mark_arg(i+1);
+             i++;
+           } else {
+             arg_error();
+           }
+         } else if (strcmp(argv[i],"-Sskip") == 0) {
+           if (argv[i+1]) {
+             this->style("skip",argv[i+1]);
+             mark_arg(i);
+             mark_arg(i+1);
+             i++;
+           } else {
+             arg_error();
+           }
+         } else if (strcmp(argv[i],"-Suntabify") == 0) {
+           this->style("untabify",0);
+           mark_arg(i);
+         } else if (strcmp(argv[i],"-Stabify") == 0) {
+           this->style("tabify",0);
+           mark_arg(i);
+         } else if (strcmp(argv[i],"-Signore") == 0) {
+           this->style("ignore",0);
+         } else if (strcmp(argv[i],"-help") == 0) {
+           fputs(comment_usage,stderr);
+         }
+      }
+  }
+}