]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxSWIG/SWIG/comment.cxx
fix Borland makefile for xrc as per SF report 747099
[wxWidgets.git] / wxPython / wxSWIG / SWIG / comment.cxx
1 /*******************************************************************************
2 * Simplified Wrapper and Interface Generator (SWIG)
3 *
4 * Author : David Beazley
5 *
6 * Department of Computer Science
7 * University of Chicago
8 * 1100 E 58th Street
9 * Chicago, IL 60637
10 * beazley@cs.uchicago.edu
11 *
12 * Please read the file LICENSE for the copyright and terms by which SWIG
13 * can be used and distributed.
14 *******************************************************************************/
15
16 #include "internal.h"
17
18 /*******************************************************************************
19 * $Header$
20 *
21 * File : comment.cxx
22 *
23 * This is a semi-magical module for associating C/C++ comments with
24 * documentation entries. While this sounds like it might be easy,
25 * there are a number of subtle problems getting things to associate
26 * correctly.
27 *
28 * Here's the general idea :
29 *
30 * 1. The parser and scanner feed both C comments and documentation
31 * entries to this class. These may show up in really bizarre
32 * orders (not necessarily the order seen in an interface file).
33 *
34 * 2. We maintain separate lists of comments and documentation
35 * entries.
36 *
37 * 3. Periodically, we go through the list of documentation entries
38 * and see if we can associate any comments.
39 *
40 * 4. Upon completion of parsing, it's critical that we cleanup
41 * the lists using the cleanup() method.
42 *
43 *******************************************************************************/
44
45 // -----------------------------------------------------------------------------
46 // struct Comment
47 //
48 // Structure used to maintain a linked list of comments for later use.
49 // -----------------------------------------------------------------------------
50
51 class Comment {
52 public:
53 String *text; // Text of the comment
54 int first_line; // First line of the comment
55 int last_line; // Last line of the comment
56 int column; // First column of comment
57 char *file; // Name of the file that it was in
58 Comment *next; // Next comment (when in a linked list)
59 Comment *prev; // Previous comment
60 static Comment *comment_list; // List of all comments
61
62 Comment(char *t, int line, int col, char *f);
63 ~Comment();
64 static Comment *find(DocEntry *de, CommentHandler *ch);
65 void attach(DocEntry *de, CommentHandler *ch);
66 };
67
68
69 // -----------------------------------------------------------------------
70 // Create a new comment. Automatically puts it on the linked list
71 // -----------------------------------------------------------------------
72 Comment::Comment(char *t, int line, int col, char *f) {
73 int nlines = 0;
74 char *c;
75
76 text = new String(t);
77 c = t;
78 while (*c) {
79 if (*c == '\n') nlines++;
80 c++;
81 }
82 first_line = line;
83 column = col;
84 last_line = line + nlines - 1;
85 file = copy_string(f);
86 if (comment_list) {
87 comment_list->prev = this;
88 }
89 next = comment_list;
90 comment_list = this;
91 prev = 0;
92 }
93
94 // -----------------------------------------------------------------------
95 // Destroy a comment
96 // -----------------------------------------------------------------------
97 Comment::~Comment() {
98 delete text;
99 delete file;
100 // Remove from linked list (if applicable)
101 if (prev) {
102 prev->next = next;
103 }
104 if (next) {
105 next->prev = prev;
106 }
107 if (this == comment_list) comment_list = next;
108 }
109 // -----------------------------------------------------------------------
110 // find(DocEntry *de, CommentHandler *ch)
111 //
112 // This function tries to a find a comment matching the search criteria
113 // of a given comment handler and documentation entry.
114 // -----------------------------------------------------------------------
115
116 Comment *Comment::find(DocEntry *de, CommentHandler *ch) {
117 Comment *c;
118
119 c = comment_list;
120
121 // Start walking down our list of stored comments
122
123 while (c) {
124 // printf("Searching %x : %s\n", c, c->text->get());
125 if (strcmp(de->file,c->file) == 0) {
126
127 // At least comment is in the right file. Now check line numbers
128
129 if (ch->location == BEFORE) {
130
131 // Check to see if the last line of the comment is close
132 // enough to our declaration.
133
134 if ((c->last_line <= de->line_number) &&
135 ((de->line_number - c->last_line) <= ch->skip_lines)) {
136 return c;
137 }
138 } else { // AFTER mode
139 // Check to see if the first line of the comment is close
140 // enough to our declaration.
141
142 if ((c->first_line >= de->end_line) &&
143 ((c->first_line - de->end_line) <= ch->skip_lines)) {
144 return c;
145 }
146 }
147 // Check to see if the line numbers are too small. Comments
148 // are processed in order so there's no sense in checking
149 // all entries.
150
151 if (c->last_line < de->line_number)
152 return 0;
153
154 }
155 c = c->next;
156 }
157 return 0;
158 }
159
160 // -----------------------------------------------------------------------
161 // void attach(DocEntry *de, CommentHandler *ch)
162 //
163 // This function attachs a comment to a documentation entry and applies
164 // all of the style information in the comment handler.
165 // -----------------------------------------------------------------------
166 void Comment::attach(DocEntry *de, CommentHandler *ch) {
167 int nlines = 0;
168 char **split = 0;
169 char *c;
170 int i,lnum,el;
171 if (!de) return;
172
173 // If we're ignoring comments, forget it
174 if (ch->ignore) {
175 return;
176 }
177
178 // If the comment is formatted, no style processing is applied
179
180 if (de->format) {
181 de->text << *text;
182 return;
183 }
184
185 // Untabify the comment
186
187 if (ch->untabify) text->untabify();
188
189 // Count how many lines we have
190
191 c = text->get();
192 while (*c) {
193 if (*c == '\n') nlines++;
194 c++;
195 }
196
197 if (nlines == 0) return;
198
199 // Tokenize the documentation string into lines
200
201 split = new char*[nlines+1];
202 c = text->get();
203 i = 0;
204 split[i] = c;
205 while (*c) {
206 if (*c == '\n') {
207 *(c++) = 0;
208 split[++i] = c;
209 } else c++;
210 }
211 lnum = 0;
212
213 // Now process the chop_top and chop_bottom values
214 // if nlines < (chop_top + chop_bottom), then we do nothing
215
216 if (nlines > (ch->chop_top + ch->chop_bottom)) {
217 lnum += ch->chop_top;
218 el = nlines-ch->chop_bottom;
219 } else {
220 el = nlines;
221 }
222
223 // Now process in-between lines
224
225 while (lnum < el) {
226 /* Chop line */
227 if (split[lnum]) {
228 if (strlen(split[lnum]) > (unsigned) (ch->chop_left+ch->chop_right)) {
229 if (ch->chop_right > 0)
230 split[lnum][strlen(split[lnum]) - ch->chop_right] = 0;
231 de->text << &split[lnum][ch->chop_left];
232 }
233 }
234 lnum++;
235 de->text << "\n";
236 }
237
238 // printf("*** ATTACHING %s : %s\n", de->usage.get(), de->text.get());
239 delete split;
240 }
241
242
243 CommentHandler *comment_handler = 0;
244 Comment *Comment::comment_list = 0;
245
246 // ------------------------------------------------------------------------
247 // struct DocEntryList
248 //
249 // This structure manages a linked list of documentation entries that
250 // haven't had comments attached to them yet.
251 //
252 // As a general rule, this list tends to remain rather short.
253 // ------------------------------------------------------------------------
254
255 struct DocEntryList {
256 DocEntry *de;
257 CommentHandler *ch;
258 DocEntryList *next;
259 DocEntryList *prev;
260 static DocEntryList *doc_list;
261
262 // -----------------------------------------------------------------------
263 // Create a new list entry
264 // -----------------------------------------------------------------------
265 DocEntryList(DocEntry *d, CommentHandler *c) {
266
267 de = d;
268 ch = c;
269 next = doc_list;
270 prev = 0;
271 if (doc_list)
272 doc_list->prev = this;
273 doc_list = this;
274
275 // Only allow a few doc entries to survive
276
277 if (this->next) {
278 if (this->next->next) {
279 delete this->next->next;
280 }
281 }
282 }
283
284 // -----------------------------------------------------------------------
285 // Destroy a list entry
286 // -----------------------------------------------------------------------
287 ~DocEntryList() {
288 if (prev) {
289 prev->next = next;
290 }
291 if (next) {
292 next->prev = prev;
293 }
294 if (this == doc_list) doc_list = next;
295 };
296
297 // -----------------------------------------------------------------------
298 // static check()
299 //
300 // Checks the list of documentation entries to see if any can be associated.
301 // -----------------------------------------------------------------------
302
303 static void check() {
304
305 DocEntryList *dl, *dl_temp;
306 Comment *cmt;
307
308 // printf ("Checking\n");
309 dl = doc_list;
310 while (dl) {
311 cmt = Comment::find(dl->de,dl->ch);
312 if (cmt) {
313 // Okay, we found a matching comment. Attach it to this
314 // documentation entry.
315 cmt->attach(dl->de,dl->ch);
316
317 // Destroy the comment and doc list entry
318 delete cmt;
319
320 // Declarations are always coming in order so we're going
321 // to blow away all of them past this point
322
323 dl_temp = dl->next;
324 delete dl;
325 dl = dl_temp;
326 } else {
327 dl = dl->next;
328 }
329 }
330 }
331 };
332
333
334 DocEntryList *DocEntryList::doc_list = 0;
335
336 // -----------------------------------------------------------------------------
337 // CommentHandler::CommentHandler()
338 //
339 // Constructor. Creates a new comment handler. Sets up some default values
340 // for comment handling.
341 //
342 // Inputs : None
343 //
344 // Output : New CommentHandler object.
345 //
346 // Side Effects : Sets default comment handling parameters.
347 // -----------------------------------------------------------------------------
348
349 CommentHandler::CommentHandler() {
350 skip_lines = 1;
351 location = AFTER;
352 chop_top = 0;
353 chop_bottom = 0;
354 chop_left = 3;
355 chop_right = 0;
356 untabify = 1;
357 ignore = 0;
358 }
359
360 // -----------------------------------------------------------------------------
361 // CommentHandler::CommentHandler(CommentHandler *c)
362 //
363 // Constructor. Creates a new comment handler, but copies attributes from
364 // another handler.
365 //
366 // Inputs :
367 // c = A different comment handler.
368 //
369 // Output : A new CommentHandler object.
370 //
371 // Side Effects : None
372 // -----------------------------------------------------------------------------
373
374 CommentHandler::CommentHandler(CommentHandler *c) {
375 skip_lines = c->skip_lines;
376 location = c->location;
377 chop_top = c->chop_top;
378 chop_bottom = c->chop_bottom;
379 chop_left = c->chop_left;
380 chop_right = c->chop_right;
381 untabify = c->untabify;
382 ignore = c->ignore;
383 }
384
385 // -----------------------------------------------------------------------------
386 // CommentHandler::~CommentHandler()
387 //
388 // Destructor. Destroys a comment handler. Does nothing interesting at the
389 // moment.
390 //
391 // Inputs : None
392 //
393 // Output : None
394 //
395 // Side Effects : None
396 // -----------------------------------------------------------------------------
397
398 CommentHandler::~CommentHandler() {
399 }
400
401 // -----------------------------------------------------------------------------
402 // void CommentHandler::add_comment(char *text, int line_num, int col, char *file)
403 //
404 // This function takes a character string as comment text and appends
405 // it to the current comment string (which is held in Comment::comment_list)
406 //
407 // 1. If two comments appear in successive lines, they are
408 // concatenated. This is to handle C++ style comments like the
409 // one surrounding this text.
410 //
411 // 2. If a new comment appears, we simply create a new one
412 //
413 // Inputs :
414 // text = Text of the comment
415 // line_num = Starting line number of the comment
416 // col = Starting column of the comment
417 // file = File in which the comment was located.
418 //
419 // Output : None
420 //
421 // Side Effects :
422 // Saves the comment in an internal linked list.
423 // If multiple comments appear in succession, some may end up
424 // in our comment list permanently (ie. never attached to any
425 // particular declaration).
426 // -----------------------------------------------------------------------------
427
428 void CommentHandler::add_comment(char *text, int line_num, int col, char *file) {
429
430 char *c;
431 int nlines = 0;
432 Comment *cmt;
433
434 // printf("line_num = %d, %s\n", line_num,text);
435
436 // Count up how many lines are in this comment
437
438 c = text;
439 while (*c) {
440 if (*c == '\n') nlines++;
441 c++;
442 }
443
444 // Check to see if this comment is in a successive line to the last one
445
446 cmt = Comment::comment_list;
447
448 if (cmt) {
449
450 // Check for column alignment
451 if ((cmt->column == col) && (line_num == (cmt->last_line + 1)) &&
452 (nlines <= 1)) {
453 *(cmt->text) << text;
454 cmt->last_line = line_num + nlines - 1;
455 } else {
456 // This is a new comment, add it to our list
457 cmt = new Comment(text,line_num,col,file);
458 }
459 } else {
460 cmt = new Comment(text,line_num,col,file);
461 }
462 }
463
464 // -----------------------------------------------------------------------------
465 // void CommentHanlder::set_entry(DocEntry *d)
466 //
467 // This grabs a DocEntry and hangs onto it.
468 //
469 // We will place the doc entry into our documentation list and then
470 // check it to see if any comments are sitting around.
471 //
472 // Inputs : d = Documentation Entry
473 //
474 // Output : None
475 //
476 // Side Effects :
477 // May attach comments to the documentation entry. In this case,
478 // comments and DocEntries may be removed from internal lists.
479 // -----------------------------------------------------------------------------
480
481 void CommentHandler::set_entry(DocEntry *d) {
482
483 // printf("Set entry : file: %s, line %d, %s\n", d->file, d->line_number, d->usage.get());
484
485 // Create a new list entry and save it
486
487 new DocEntryList(d,this);
488
489 // Check all of the documentation entries to see if they can be placed
490
491 DocEntryList::check();
492
493 }
494
495 // -----------------------------------------------------------------------------
496 // static void CommentHandler::cleanup()
497 //
498 // Checks all documentation entries and sees if there are any comments available.
499 // If so, they are attached. This function is usually only called upon completion
500 // of parsing.
501 //
502 // Inputs : None
503 //
504 // Output : None
505 //
506 // Side Effects :
507 // Removes documentation entries and comments from internal lists.
508 //
509 // -----------------------------------------------------------------------------
510
511 void CommentHandler::cleanup() {
512 int nc, nd;
513 Comment *c;
514 DocEntryList *d;
515
516 DocEntryList::check();
517
518 // Figure out how bad we're doing on memory
519
520 nc = 0;
521 nd = 0;
522 c = Comment::comment_list;
523 while (c) {
524 nc++;
525 c = c->next;
526 }
527
528 d = DocEntryList::doc_list;
529 while(d) {
530 nd++;
531 d = d->next;
532 }
533
534 if (Verbose) {
535 printf("%d unprocessed comments, %d unprocessed doc entries.\n",nc,nd);
536 }
537 }
538
539 // -----------------------------------------------------------------------------
540 // void CommentHandler::style(char *name, char *value)
541 //
542 // Processes comment handling style parameters. The following parameters
543 // are available :
544 //
545 // after - Comments appear after a declaration
546 // before - Comments appear before a declaration
547 // skip - Number of blank lines between comment and decl.
548 // chop_top - Number of lines to chop from top of a comment
549 // chop_bottom - Number of lines to chop from bottom of a comment
550 // chop_left - Number of characters to chop from left
551 // chop_right - Number of characters to chop from right
552 // tabify - Leave tabs in comment text
553 // untabify - Strip tabs and convert them into spaces.
554 // ignore - Ignore comments
555 // enable - Enable comments
556 //
557 // Inputs :
558 // name - Name of style parameter
559 // value - Optional parameter value
560 //
561 // Output : None
562 //
563 // Side Effects : Changes style of comment handler object.
564 //
565 // -----------------------------------------------------------------------------
566
567 void CommentHandler::style(char *name, char *value) {
568
569 if (strcmp(name,"before") == 0) {
570 location = BEFORE;
571 } else if (strcmp(name,"after") == 0) {
572 location = AFTER;
573 } else if (strcmp(name,"skip") == 0) {
574 if (value)
575 skip_lines = atoi(value);
576 } else if (strcmp(name,"chop_top") == 0) {
577 if (value)
578 chop_top = atoi(value);
579 } else if (strcmp(name,"chop_bottom") == 0) {
580 if (value)
581 chop_bottom = atoi(value);
582 } else if (strcmp(name,"chop_left") == 0) {
583 if (value)
584 chop_left = atoi(value);
585 } else if (strcmp(name,"chop_right") == 0) {
586 if (value)
587 chop_right = atoi(value);
588 } else if (strcmp(name,"tabify") == 0) {
589 untabify = 0;
590 } else if (strcmp(name,"untabify") == 0) {
591 untabify = 1;
592 } else if (strcmp(name,"ignore") == 0) {
593 ignore = 1;
594 } else if (strcmp(name,"enable") == 0) {
595 ignore = 0;
596 }
597 }
598
599 // -----------------------------------------------------------------------------
600 // void CommentHandler::parse_args(int argc, char **argv)
601 //
602 // Function for processing command line options given on the SWIG command line.
603 // See the help string below for available options.
604 //
605 // Inputs :
606 // argc = Argument count
607 // argv = Argument strings
608 //
609 // Output : None
610 //
611 // Side Effects :
612 // Changes various style parameters for the top-level CommentHandler.
613 // -----------------------------------------------------------------------------
614
615 static char *comment_usage = "\
616 Comment Style Options : \n\
617 -Safter - Use comments after a declaration.\n\
618 -Sbefore - Use comments before a declaration.\n\
619 -Schop_bottom n - Chop n lines from bottom of comments.\n\
620 -Schop_left n - Chop n characters from left of a comment.\n\
621 -Schop_right n - Chop n characters from right of a comment.\n\
622 -Schop_top n - Chop n lines from top of comments.\n\
623 -Signore - Ignore comments.\n\
624 -Sskip n - Max lines between comment and declaration.\n\
625 -Stabify - Do not convert tabs.\n\
626 -Suntabify - Convert tabs into spaces (the default).\n\n";
627
628 void CommentHandler::parse_args(int argc, char **argv) {
629 int i;
630
631 for (i = 1; i < argc; i++) {
632 if (argv[i]) {
633 if (strcmp(argv[i],"-Sbefore") == 0) {
634 this->style("before",0);
635 mark_arg(i);
636 } else if (strcmp(argv[i],"-Safter") == 0) {
637 this->style("after",0);
638 mark_arg(i);
639 } else if (strcmp(argv[i],"-Schop_top") == 0) {
640 if (argv[i+1]) {
641 this->style("chop_top",argv[i+1]);
642 mark_arg(i);
643 mark_arg(i+1);
644 i++;
645 } else {
646 arg_error();
647 }
648 } else if (strcmp(argv[i],"-Schop_bottom") == 0) {
649 if (argv[i+1]) {
650 this->style("chop_bottom",argv[i+1]);
651 mark_arg(i);
652 mark_arg(i+1);
653 i++;
654 } else {
655 arg_error();
656 }
657 } else if (strcmp(argv[i],"-Schop_left") == 0) {
658 if (argv[i+1]) {
659 this->style("chop_left",argv[i+1]);
660 mark_arg(i);
661 mark_arg(i+1);
662 i++;
663 } else {
664 arg_error();
665 }
666 } else if (strcmp(argv[i],"-Schop_right") == 0) {
667 if (argv[i+1]) {
668 this->style("chop_right",argv[i+1]);
669 mark_arg(i);
670 mark_arg(i+1);
671 i++;
672 } else {
673 arg_error();
674 }
675 } else if (strcmp(argv[i],"-Sskip") == 0) {
676 if (argv[i+1]) {
677 this->style("skip",argv[i+1]);
678 mark_arg(i);
679 mark_arg(i+1);
680 i++;
681 } else {
682 arg_error();
683 }
684 } else if (strcmp(argv[i],"-Suntabify") == 0) {
685 this->style("untabify",0);
686 mark_arg(i);
687 } else if (strcmp(argv[i],"-Stabify") == 0) {
688 this->style("tabify",0);
689 mark_arg(i);
690 } else if (strcmp(argv[i],"-Signore") == 0) {
691 this->style("ignore",0);
692 } else if (strcmp(argv[i],"-help") == 0) {
693 fputs(comment_usage,stderr);
694 }
695 }
696 }
697 }