1fd20cd773b144dcec1440d11f111da4e8d94168
[platform/upstream/doxygen.git] / src / tclscanner.l
1 /*****************************************************************************
2  * Parser for Tcl subset
3  *
4  * Copyright (C) 2010      by Rene Zaumseil
5  * based on the work of Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */ 
17 %{
18 #include <stdio.h> 
19 #include <stdlib.h>
20 #include <assert.h>
21 #include <ctype.h>
22 #include <unistd.h> 
23
24 #include <qstring.h>
25 #include <qstringlist.h>
26 #include <qlist.h>
27 #include <qmap.h>
28 #include <qarray.h>
29 #include <qstack.h>
30 #include <qregexp.h>
31 #include <qfile.h>
32 #include <qdict.h>
33
34 #include "entry.h"
35 #include "message.h"
36 #include "config.h"
37 #include "doxygen.h"
38 #include "util.h"
39 #include "defargs.h"
40 #include "language.h"
41 #include "commentscan.h" 
42 #include "pre.h"
43 #include "tclscanner.h"
44 #include "outputlist.h"
45 #include "membername.h"
46 #include "searchindex.h"
47 #include "commentcnv.h"
48 #include "bufstr.h"
49 #include "portable.h"
50 #include "arguments.h"
51 #include "namespacedef.h"
52 #include "filedef.h"
53
54 #define YY_NEVER_INTERACTIVE 1
55 #define YY_NO_INPUT 1
56
57 #define MAX_INCLUDE_DEPTH 10
58
59 //! Application error.
60 #define tcl_err \
61   printf("Error %d %s() at line %d! ",__LINE__,tcl.file_name.data(),yylineno); \
62   yy_push_state(ERROR); \
63   yyless(0); \
64   printf
65
66 //! Application warning.
67 #define tcl_war \
68   printf("Warning %d %s() at line %d: ",__LINE__,tcl.file_name.data(),yylineno); \
69   printf
70
71 //! Application message.
72 #define tcl_inf \
73   if (0) printf("--- %.4d %d@%d: ",__LINE__,yylineno,yy_start_stack_ptr) && printf
74
75 //! Debug message.
76 #define D\
77   if (0) printf("--- %.4d %d@%d: %s\n",__LINE__,yylineno,yy_start_stack_ptr,yytext);
78
79 // BEGIN of copy from tclUtil.c
80 // - Tcl_Interp removed
81 // - changes are marked with RZ
82 // #define's to adapt the code:
83 #define CONST           const
84 #define UCHAR           (unsigned char)
85 #define TCL_ERROR       1
86 #define TCL_OK          0
87 #define ckalloc         malloc
88 #define ckfree          free
89 #define TclCopyAndCollapse(size,src,dest) memcpy(dest,src,size); *(dest+size)=0
90 int TclFindElement(
91       CONST char *list,         /* Points to the first byte of a string
92                                  * containing a Tcl list with zero or more
93                                  * elements (possibly in braces). */
94       int listLength,           /* Number of bytes in the list's string. */
95       CONST char **elementPtr,  /* Where to put address of first significant
96                                  * character in first element of list. */
97       CONST char **nextPtr,     /* Fill in with location of character just
98                                  * after all white space following end of
99                                  * argument (next arg or end of list). */
100       int *sizePtr,             /* If non-zero, fill in with size of
101                                  * element. */
102       int *bracePtr)            /* If non-zero, fill in with non-zero/zero to
103                                  * indicate that arg was/wasn't in braces. */
104 {
105   CONST char *p = list;
106   CONST char *elemStart;        /* Points to first byte of first element. */
107   CONST char *limit;            /* Points just after list's last byte. */
108   int openBraces = 0;           /* Brace nesting level during parse. */
109   int inQuotes = 0;
110   int size = 0;         /* lint. */
111   //RZ    int numChars;
112
113   /*
114    * Skim off leading white space and check for an opening brace or quote.
115    * We treat embedded NULLs in the list as bytes belonging to a list
116    * element.
117    */
118
119   limit = (list + listLength);
120   while ((p < limit) && (isspace(UCHAR(*p)))) 
121   { /* INTL: ISO space. */
122     p++;
123   }
124   if (p == limit) 
125   {             /* no element found */
126     elemStart = limit;
127     goto done;
128   }
129
130   if (*p == '{')   /* } to keep vi happy */
131   {
132     openBraces = 1;
133     p++;
134   } 
135   else if (*p == '"') 
136   {
137     inQuotes = 1;
138     p++;
139   }
140   elemStart = p;
141   if (bracePtr != 0) 
142   {
143     *bracePtr = openBraces;
144   }
145
146   /*
147    * Find element's end (a space, close brace, or the end of the string).
148    */
149
150   while (p < limit) 
151   {
152     switch (*p) 
153     {
154       /*
155        * Open brace: don't treat specially unless the element is in
156        * braces. In this case, keep a nesting count.
157        */
158
159       case '{':
160         if (openBraces != 0) 
161         {
162           openBraces++;
163         }
164         break;
165
166         /*
167          * Close brace: if element is in braces, keep nesting count and
168          * quit when the last close brace is seen.
169          */
170
171       case '}':
172         if (openBraces > 1) 
173         {
174           openBraces--;
175         } 
176         else if (openBraces == 1) 
177         {
178           size = (int)(p - elemStart);
179           p++;
180           if ((p >= limit) || isspace(UCHAR(*p))) 
181           {     /* INTL: ISO space. */
182             goto done;
183           }
184
185           /*
186            * Garbage after the closing brace; return an error.
187            */
188
189           return TCL_ERROR;
190         }
191         break;
192
193         /*
194          * Backslash: skip over everything up to the end of the backslash
195          * sequence.
196          */
197
198       case '\\':
199         //RZ        Tcl_UtfBackslash(p, &numChars, NULL);
200         //RZ        p += (numChars - 1);
201         p++; //RZ
202         break;
203
204         /*
205          * Space: ignore if element is in braces or quotes; otherwise
206          * terminate element.
207          */
208
209       case ' ':
210       case '\f':
211       case '\n':
212       case '\r':
213       case '\t':
214       case '\v':
215         if ((openBraces == 0) && !inQuotes) 
216         {
217           size = (int)(p - elemStart);
218           goto done;
219         }
220         break;
221
222         /*
223          * Double-quote: if element is in quotes then terminate it.
224          */
225
226       case '"':
227         if (inQuotes) 
228         {
229           size = (int)(p - elemStart);
230           p++;
231           if ((p >= limit) || isspace(UCHAR(*p))) 
232           {     /* INTL: ISO space */
233             goto done;
234           }
235
236           /*
237            * Garbage after the closing quote; return an error.
238            */
239           return TCL_ERROR;
240         }
241         break;
242     }
243     p++;
244   }
245
246   /*
247    * End of list: terminate element.
248    */
249
250   if (p == limit) 
251   {
252     if (openBraces != 0) 
253     {
254       return TCL_ERROR;
255     } 
256     else if (inQuotes) 
257     {
258       return TCL_ERROR;
259     }
260     size = (int)(p - elemStart);
261   }
262
263 done:
264   while ((p < limit) && (isspace(UCHAR(*p)))) 
265   { /* INTL: ISO space. */
266     p++;
267   }
268   *elementPtr = elemStart;
269   *nextPtr = p;
270   if (sizePtr != 0) 
271   {
272     *sizePtr = size;
273   }
274   return TCL_OK;
275 }
276
277 int Tcl_SplitList(
278     CONST char *list,           /* Pointer to string with list structure. */
279     int *argcPtr,               /* Pointer to location to fill in with the
280                                  * number of elements in the list. */
281     CONST char ***argvPtr)      /* Pointer to place to store pointer to array
282                                  * of pointers to list elements. */
283 {
284   CONST char **argv, *l, *element;
285   char *p;
286   int length, size, i, result, elSize, brace;
287
288   /*
289    * Figure out how much space to allocate. There must be enough space for
290    * both the array of pointers and also for a copy of the list. To estimate
291    * the number of pointers needed, count the number of space characters in
292    * the list.
293    */
294
295   for (size = 2, l = list; *l != 0; l++) 
296   {
297     if (isspace(UCHAR(*l))) 
298     {                   /* INTL: ISO space. */
299       size++;
300
301       /*
302        * Consecutive space can only count as a single list delimiter.
303        */
304
305       while (1) 
306       {
307         char next = *(l + 1);
308
309         if (next == '\0') 
310         {
311           break;
312         }
313         ++l;
314         if (isspace(UCHAR(next))) 
315         {               /* INTL: ISO space. */
316           continue;
317         }
318         break;
319       }
320     }
321   }
322   length = (int)(l - list);
323   argv = (CONST char **) ckalloc((unsigned)
324       ((size * sizeof(char *)) + length + 1));
325   for (i = 0, p = ((char *) argv) + size*sizeof(char *);
326       *list != 0;  i++) 
327   {
328     CONST char *prevList = list;
329
330     result = TclFindElement(list, length, &element, &list,
331         &elSize, &brace);
332     length -= (int)(list - prevList);
333     if (result != TCL_OK) 
334     {
335       ckfree((char *) argv);
336       return result;
337     }
338     if (*element == 0) 
339     {
340       break;
341     }
342     if (i >= size) 
343     {
344       ckfree((char *) argv);
345       return TCL_ERROR;
346     }
347     argv[i] = p;
348     if (brace) 
349     {
350       memcpy(p, element, (size_t) elSize);
351       p += elSize;
352       *p = 0;
353       p++;
354     } 
355     else 
356     {
357       TclCopyAndCollapse(elSize, element, p);
358       p += elSize+1;
359     }
360   }
361
362   argv[i] = NULL;
363   *argvPtr = argv;
364   *argcPtr = i;
365   return TCL_OK;
366 }
367 // END of tclUtil.c
368
369 void tcl_split_list(QString &str, QStringList &list)
370 {
371   int argc;
372   const char **argv;
373
374   list.clear();
375   if (str.left(1)=="{" && str.right(1)=="}")
376   {
377     str=str.mid(1,str.length()-2);
378   }
379   else if (str.left(1)=="\"" && str.right(1)=="\"")
380   {
381     str=str.mid(1,str.length()-2);
382   }
383   if (Tcl_SplitList(str.ascii(),&argc,&argv) != TCL_OK)
384   {
385     list.append(str);
386   }
387   else
388   {
389     for (int i = 0; i < argc; i++)
390     {
391       list.append(argv[i]);
392     }
393     ckfree((char *) argv);
394   }
395 }
396
397 //! Structure containing information about current scan context.
398 typedef struct
399 {
400   char type[2]; // type of scan context: "\"" "{" "[" "?" " "
401   int line0; // start line of scan context
402   int line1; // end line of scan context
403   YY_BUFFER_STATE buffer_state; // value of scan context
404   QCString ns; // current namespace
405   Entry *entry_fn; // if set contains the current proc/method/constructor/destructor
406   Entry *entry_cl; // if set contain the current class
407   Entry *entry_scan; // current scan entry
408   Protection protection; // current protections state
409   QStringList after; // option/value list (options: NULL comment keyword script)
410 } tcl_scan;
411
412 //* Structure containing all internal global variables.
413 static struct
414 {
415   CodeOutputInterface * code; // if set then we are codifying the file
416   int code_line; // current line of code
417   int code_linenumbers; // if true create line numbers in code
418   const char *code_font; // used font to codify
419   bool config_autobrief; // value of configuration option
420   QMap<QString,QString> config_subst; // map of configuration option values
421   QCString input_string; // file contents
422   int input_position; // position in file
423   QCString file_name; // name of used file
424   ParserInterface *this_parser; // myself
425   int command; // true if command was found
426   int comment; // set true if comment was scaned
427   int brace_level; // bookkeeping of braces
428   int bracket_level; // bookkeeping of brackets
429   int bracket_quote; // bookkeeping of quotes (toggles)
430   char word_is; // type of current word: "\"" "{" "[" "?" " "
431   int line_comment; // line number of comment
432   int line_commentline; // line number of comment after command
433   int line_command; // line number of command
434   int line_body0; // start line of body
435   int line_body1; // end line of body
436   QCString string_command; // contain current command
437   QCString string_commentline; // contain current comment after command
438   QCString string_commentcodify; // current comment string used in codifying
439   QCString string_comment; // contain current comment
440   QCString string_last; // contain last read word or part of word
441   QCString string; // temporary string value
442   Entry*                entry_main; // top level entry
443   Entry*                entry_file; // entry of current file
444   Entry*                entry_current; // currently used entry
445   Entry*                entry_inside; // contain entry of current scan context
446   QStringList list_commandwords; // list of command words
447   QList<tcl_scan> scan; // stack of scan contexts
448   QAsciiDict<Entry> ns; // all read namespace entries
449   QAsciiDict<Entry> cl; // all read class entries
450   QAsciiDict<Entry> fn; // all read function entries
451   QList<Entry> entry; // list of all created entries, will be deleted after codifying
452   Protection protection; // current protections state
453   MemberDef *memberdef; // contain current MemberDef when codifying
454 } tcl;
455
456 // scanner functions
457 static int yyread(char *buf,int max_size);
458 static tcl_scan *tcl_scan_start(char type, QString content, QCString ns, Entry *entry_cls, Entry *entry_fn);
459 static void tcl_scan_end();
460 static void tcl_comment(int what,const char *text);
461 static void tcl_word(int what,const char *text);
462 static void tcl_command(int what,const char *text);
463
464 // helper functions
465
466 //! Create new entry.
467 // @return new initialised entry
468 Entry* tcl_entry_new()
469 {
470   Entry *myEntry = new Entry;
471   myEntry->section    = Entry::EMPTY_SEC;
472   myEntry->name       = "";
473 //  myEntry->type       = "";
474   myEntry->brief      = "";
475 //  myEntry->doc        = "";
476   myEntry->protection = Public;
477 //  myEntry->mtype      = Method;
478 //  myEntry->virt       = Normal;
479 //  myEntry->stat       = FALSE;
480   myEntry->fileName   = tcl.file_name;
481   myEntry->lang       = SrcLangExt_Tcl;
482   initGroupInfo(myEntry);
483   // collect entries
484   if (!tcl.code)
485   {
486     tcl.entry.insert(0,myEntry);
487   }
488   return myEntry;
489 }
490
491 //! Set protection level.
492 void tcl_protection(Entry *entry) 
493 {
494   if (entry->protection!=Public&&entry->protection!=Protected&&entry->protection!=Private)
495   {
496     entry->protection = tcl.protection;
497   }
498   if (entry->protection!=Protected&&entry->protection!=Private)
499   {
500     entry->protection = Public;
501   }
502 }
503
504 //! Check name.
505 // @return 'ns' and 'name' of given current 'ns0' and 'name0'
506 static void tcl_name(const QCString &ns0, const QCString &name0, QCString &ns, QCString &name)
507 {
508   QCString myNm;
509   int myStart;
510
511   if (qstrncmp(name0.data(),"::",2)==0)
512   {
513     myNm = name0.mid(2);
514   }
515   else if (ns0.length() && ns0 != " ")
516   {
517     myNm = ns0 + "::" + name0;
518   }
519   else
520   {
521     myNm = name0;
522   }
523   myStart = myNm.findRev("::");
524   if (myStart == -1)
525   {
526     ns = "";
527     name = myNm;
528   }
529   else
530   {
531     ns = myNm.mid(0,myStart);
532     name = myNm.mid(myStart+2);
533   }
534 }
535
536 // Check and return namespace entry.
537 // @return namespace entry
538 Entry* tcl_entry_namespace(const QCString ns)
539 {
540   Entry *myEntry;
541   if (ns.length())
542   {
543     myEntry = tcl.ns.find(ns);
544   }
545   else
546   {
547     myEntry = tcl.ns.find("::");
548   }
549   if (myEntry == NULL)
550   {
551     myEntry = tcl_entry_new();
552     myEntry->section    = Entry::NAMESPACE_SEC;
553     myEntry->name       = ns;
554     tcl.entry_main->addSubEntry(myEntry);
555     tcl.ns.insert(ns,myEntry);
556   }
557   return myEntry;
558 }
559
560 // Check and return class entry.
561 // @return class entry
562 Entry* tcl_entry_class(const QCString cl)
563 {
564   Entry *myEntry;
565   if (!cl.length()) return(NULL);
566
567   myEntry = tcl.cl.find(cl);
568   if (myEntry == NULL)
569   {
570     myEntry = tcl_entry_new();
571     myEntry->section    = Entry::CLASS_SEC;
572     myEntry->name       = cl;
573     tcl.entry_main->addSubEntry(myEntry);
574     tcl.cl.insert(cl,myEntry);
575   }
576   return myEntry;
577 }
578
579 //! Check for keywords.
580 // @return 1 if keyword and 0 otherwise
581 static int tcl_keyword(QCString str)
582 {
583   static QStringList myList;
584   static int myInit=1;
585   if (myInit)
586   {
587     // tcl keywords
588     myList <<"append"<<"apply"<<"array"<<"auto_execok"<<"auto_import"<<"auto_load"<<"auto_mkindex"<<"auto_qualify"<<"auto_reset";
589     myList <<"binary";
590     myList <<"catch"<<"cd"<<"close"<<"clock"<<"concat";
591     myList <<"eof"<<"eval"<<"exec"<<"exit"<<"expr";
592     myList <<"fblocked"<<"fconfigure"<<"file"<<"fileevent"<<"flush"<<"for"<<"foreach"<<"format";
593     myList <<"gets"<<"global";
594     myList <<"http";
595     myList <<"if"<<"incr"<<"info"<<"interp";
596     myList <<"join";
597     myList <<"lappend"<<"lassign"<<"lindex"<<"linsert"<<"llength"<<"load"<<"lrange"<<"lrepeat"<<"lreplace"<<"lreverse"<<"lset";
598     myList <<"namespace";
599     myList <<"package"<<"parray"<<"pid"<<"pkg_mkIndex"<<"proc"<<"puts"<<"pwd";
600     myList <<"registry"<<"rename"<<"return";
601     myList <<"scan"<<"set"<<"split"<<"string"<<"switch";
602     myList <<"tclLog"<<"tcl_endOfWord"<<"tcl_findLibrary"<<"tcl_startOfNextWord"<<"tcl_startOfPreviousWord"<<"tcl_wordBreakAfter"<<"tcl_wordBreakBefore"<<"tell"<<"time";
603     myList <<"unknown"<<"upvar";
604     myList <<"variable"<<"vwait";
605 // tk keywords
606     myList <<"bell"<<"bind"<<"bindtags";
607     myList <<"clipboard"<<"console"<<"consoleinterp";
608     myList <<"destroy";
609     myList <<"event";
610     myList <<"focus";
611     myList <<"grid";
612     myList <<"lower";
613     myList <<"option";
614     myList <<"pack"<<"place";
615     myList <<"raise";
616     myList <<"send";
617     myList <<"tkerror"<<"tkwait"<<"tk_bisque"<<"tk_focusNext"<<"tk_focusPrev"<<"tk_focusFollowsMouse"<<"tk_popup"<<"tk_setPalette"<<"tk_textCut"<<"tk_TextCopy"<<"tk_textPaste"<<"chooseColor"<<"tk_chooseColor"<<"tk_chooseDirectory"<<"tk_dialog"<<"tk_getOpenFile"<<"tkDialog"<<"tk_getSaveFile"<<"tk_messageBox";
618     myList <<"winfo"<<"wm";
619     myList <<"button"<<"canvas"<<"checkbutton"<<"entry"<<"frame"<<"image"<<"label"<<"labelframe"<<"listbox"<<"menu"<<"menubutton"<<"message"<<"panedwindow"<<"radiobutton"<<"scale"<<"scrollbar"<<"spinbox"<<"toplevel";
620     myList.sort();
621     myInit=0;
622   }
623   str=str.stripWhiteSpace();
624   if (str.left(2)=="::") {str=str.mid(2);}
625   if (myList.findIndex(str) != -1) return(1);
626   return 0;
627 }
628
629 //! End codifying with special font class.
630 static void tcl_font_end()
631 {
632   if (!tcl.code) return;
633   if (tcl.code_font)
634   {
635     tcl.code->endFontClass();
636     tcl.code_font=NULL;
637   }
638 }
639
640 //! Codify 'str' with special font class 's'.
641 static void tcl_codify(const char *s,char *str)
642 {
643   if (!tcl.code || !str) return;
644   if (s && qstrcmp(s,"NULL")!=0)
645   {
646     tcl_font_end();
647     tcl.code->startFontClass(s);
648     tcl.code_font=s;
649   }
650   char *p=str,*sp=p;
651   char c;
652   bool done=FALSE;
653   while (!done)
654   {
655     sp=p;
656     while ((c=*p++) && c!='\n') {}
657     if (c=='\n')
658     {
659       tcl.code_line++;
660       *(p-1)='\0';
661       tcl.code->codify(sp);
662       if (tcl.code_font)
663       {
664         tcl.code->endFontClass();
665       }
666       tcl.code->endCodeLine();
667       tcl.code->startCodeLine(tcl.code_linenumbers);
668       if (tcl.code_linenumbers)
669       {
670         tcl.code->writeLineNumber(0,0,0,tcl.code_line);
671       }
672       if (tcl.code_font)
673       {
674         tcl.code->startFontClass(tcl.code_font);
675       }
676     }
677     else
678     {
679       tcl.code->codify(sp);
680       done=TRUE;
681     }
682   }
683   tcl_font_end();
684 }
685
686 #if 0
687 //! Codify 'str' with special font class 's'.
688 static void tcl_codify(const char *s,const char *str)
689 {
690   if (tcl.code==NULL) return;
691   char *tmp= (char *) malloc(strlen(str)+1);
692   strcpy(tmp, str);
693   tcl_codify(s,tmp);
694   free(tmp);
695 }
696
697 //! Codify 'str' with special font class 's'.
698 static void tcl_codify(const char *s,const QString &str)
699 {
700   if (tcl.code==NULL) return;
701   tcl_codify(s,str.utf8());
702 }
703 #endif
704
705 //! Codify 'str' with special font class 's'.
706 static void tcl_codify(const char *s,const QCString &str)
707 {
708   if (!tcl.code) return;
709   tcl_codify(s,str.data());
710 }
711
712 static void tcl_codify_cmd(const char *s,int i)
713 {
714   tcl_codify(s,(*tcl.list_commandwords.at(i)).utf8());
715 }
716
717 //-----------------------------------------------------------------------------
718 #undef  YY_INPUT
719 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
720 //-----------------------------------------------------------------------------
721 %}
722 ws              ([ \t]|\\\n)
723
724 %option yylineno
725 %option noyywrap
726 %option stack
727
728 %x ERROR
729 %x TOP
730 %x COMMAND
731 %x WORD
732 %x COMMENT
733 %x COMMENT_NL
734 %x COMMENT_CODE
735 %x COMMENT_VERB
736 %x COMMENTLINE
737 %x COMMENTLINE_NL
738 %%
739 <ERROR>. {
740 D
741   yyterminate();
742 }
743 <<EOF>> {
744 D
745   if (tcl.scan.count()<1)
746   {// error
747 D
748     tcl_err("Tcl parser stack empty! Parser error in file '%s'.\n",tcl.file_name.data());
749     yyterminate();
750   }
751   else if (tcl.scan.count()==1)
752   {// exit, check on input?
753 D
754     yyterminate();
755   }
756   else
757   {// continue
758 D
759     tcl_command(-1,"");
760     tcl_scan_end();
761   }
762 }
763 <TOP>"#" {
764 D
765   yyless(0);
766   tcl.line_comment=yylineno;
767   tcl_comment(0,"");
768 }
769 <TOP>({ws}|[\;\n])+ {
770 D
771   tcl_codify(NULL,yytext);
772 }
773 <TOP>. {
774 D
775   yyless(0);
776   tcl.line_command=yylineno;
777   tcl_command(0,"");
778 }
779
780 <COMMENT>[ \t]* {
781 D
782   tcl_codify("comment",yytext);
783 }
784 <COMMENT>"###".*\n {
785 D
786   tcl_codify("comment",yytext);
787   tcl_comment(2,yytext+1);
788 }
789 <COMMENT>"##".*\\\n {
790 D
791   tcl_codify("comment",yytext);
792   QCString t=yytext;
793   t = t.mid(2,t.length()-3);
794   t.append("\n");
795   tcl_comment(1,t.data());
796   yy_push_state(COMMENT_NL);
797 }
798 <COMMENT>"##".*\n {
799 D
800   tcl_codify("comment",yytext);
801   tcl_comment(1,yytext+2);
802 }
803 <COMMENT>"#"[@\\]"code"\n[ \t]*[^#] {
804 D
805   QCString t=yytext;
806   tcl_codify("comment",t.left(7));
807   tcl_comment(2,"\n@code\n");
808   yyless(7);
809   yy_push_state(COMMENT_CODE);
810 }
811 <COMMENT>"#"[@\\]"verbatim"\n[ \t]*[^#] {
812 D
813   QCString t=yytext;
814   tcl_codify("comment",t.left(11));
815   tcl_comment(2,"\n@verbatim\n");
816   yyless(11);
817   yy_push_state(COMMENT_VERB);
818 }
819 <COMMENT>"#".*\\\n {
820 D
821   tcl_codify("comment",yytext);
822   QCString t=yytext;
823   t = t.mid(1,t.length()-3);
824   t.append("\n");
825   tcl_comment(2,t.data());
826   yy_push_state(COMMENT_NL);
827 }
828 <COMMENT>"#".*\n {
829 D
830   tcl_codify("comment",yytext);
831   tcl_comment(2,yytext+1);
832 }
833 <COMMENT>"#".*\x1A {
834 D
835   QCString t=yytext;
836   t = t.mid(0,t.length()-1);
837   tcl_codify("comment",t.data());
838   t = t.mid(1,t.length());
839   tcl_comment(-2,t.data());
840   unput(0x1A);
841 }
842 <COMMENT>\x1A {
843 D
844   tcl_comment(-2,"");
845   unput(0x1A);
846 }
847 <COMMENT>.|\n {
848 D
849   tcl_comment(-2,yytext);
850   yyless(0);
851 }
852
853 <COMMENT_CODE>"#"[@\\]"endcode"\n {
854 D
855   QCString t=yytext;
856   t = t.left(t.length()-10);
857   tcl_comment(2,t.data());
858   tcl_comment(2,"\n@endcode\n");
859   yy_pop_state();
860   yyless(0);
861 }
862 <COMMENT_CODE>.*\n {
863 D
864   yymore();
865 }
866 <COMMENT_CODE>.*\x1A {
867 D
868   yy_pop_state();
869   yyless(0);
870 }
871
872 <COMMENT_VERB>"#"[@\\]"endverbatim"\n {
873 D
874   QCString t=yytext;
875   t = t.left(t.length()-14);
876   tcl_comment(2,t.data());
877   tcl_comment(2,"\n@endverbatim\n");
878   yy_pop_state();
879   yyless(0);
880 }
881 <COMMENT_VERB>.*\n {
882 D
883   yymore();
884 }
885 <COMMENT_VERB>.*\x1A {
886 D
887   yy_pop_state();
888   yyless(0);
889 }
890
891 <COMMENT_NL>.*\\\n {
892 D
893   tcl_codify("comment",yytext);
894   tcl_comment(2,yytext);
895 }
896 <COMMENT_NL>.*\n {
897 D
898   tcl_codify("comment",yytext);
899   tcl_comment(2,yytext);
900   yy_pop_state();
901 }
902 <COMMENT_NL>.*\x1A {
903 D
904   yy_pop_state();
905   yyless(0);
906 }
907
908 <COMMENTLINE>.*\x1A {
909 D
910   yy_pop_state();
911   yyless(0);
912 }
913 <COMMENTLINE>[ \t]* {
914 D
915   tcl.string_commentcodify += yytext;
916 }
917 <COMMENTLINE>"#<".*\\\n {
918 D
919   tcl.string_commentcodify += yytext;
920   QCString t=yytext;
921   t = t.mid(2,t.length()-4);
922   t.append("\n");
923   tcl.string_commentline += t;
924   yy_push_state(COMMENTLINE_NL);
925 }
926 <COMMENTLINE>"#<".*\n {
927 D
928   tcl.string_commentcodify += yytext;
929   tcl.string_commentline += (yytext+2);
930 }
931 <COMMENTLINE>.|\n {
932 D
933   yy_pop_state();
934   if (tcl.string_commentline.length())
935   {
936     tcl.entry_current->brief = tcl.string_commentline;
937     tcl.entry_current->briefLine = tcl.line_commentline;
938     tcl.entry_current->briefFile = tcl.file_name;
939   }
940   yyless(0);
941   tcl_command(-1,tcl.string_commentcodify.data());
942   tcl.string_commentline="";
943   tcl.string_commentcodify="";
944 }
945
946 <COMMENTLINE_NL>.*\\\n {
947 D
948   tcl.string_commentcodify += yytext;
949   QCString t=yytext;
950   t = t.left(t.length()-3);
951   t.append("\n");
952   tcl.string_commentline += t;
953 }
954 <COMMENTLINE_NL>.*\n {
955 D
956   tcl.string_commentcodify += yytext;
957   tcl.string_commentline += yytext;
958   yy_pop_state();
959 }
960 <COMMENTLINE_NL>.*\x1A {
961 D
962   QCString t=yytext;
963   t = t.left(t.length()-1);
964   tcl.string_commentcodify += t;
965   tcl.string_commentline += t;
966   yy_pop_state();
967   unput(0x1A);
968 }
969
970 <COMMAND>{ws}*[\;]{ws}*"#<" {
971 D
972   tcl.string_commentcodify = yytext;
973   tcl.string_commentcodify = tcl.string_commentcodify.left(tcl.string_commentcodify.length()-2);
974   tcl.string_commentline = "";
975   tcl.line_commentline = yylineno;
976   tcl.line_body1=yylineno;
977   unput('<');
978   unput('#');
979   yy_push_state(COMMENTLINE);
980 }
981 <COMMAND>{ws}*\x1A {
982 D
983   tcl.string_commentcodify = "";
984   tcl.string_commentline = "";
985   tcl.line_body1=yylineno;
986   tcl_command(-1,"");
987 }
988 <COMMAND>{ws}*; {
989 D
990   tcl.string_commentcodify = "";
991   tcl.string_commentline = "";
992   tcl.line_body1=yylineno;
993   tcl_command(-1,yytext);
994 }
995 <COMMAND>{ws}*\n {
996 D
997   tcl.string_commentcodify = "";
998   tcl.string_commentline = "";
999   tcl.line_body1=yylineno-1;
1000   tcl_command(-1,yytext);
1001 }
1002 <COMMAND>{ws}+ {
1003 D
1004   tcl_command(1,yytext);
1005 }
1006 <COMMAND>"{*}". {
1007 D
1008   tcl.word_is = ' ';
1009   tcl.string_last = "{*}";
1010   tcl_word(0,&yytext[3]);
1011 }
1012 <COMMAND>"\\"[\{\}\[\]\;\" \t] {
1013 D
1014   tcl.word_is=' ';
1015   tcl.string_last = "";
1016   tcl_word(0,yytext);
1017 }
1018 <COMMAND>. {
1019 D
1020   tcl.word_is=' ';
1021   if (yytext[0]=='{'||yytext[0]=='['||yytext[0]=='"') tcl.word_is = yytext[0];
1022   tcl.string_last = "";
1023   tcl_word(0,yytext);
1024 }
1025
1026 <WORD>"\\\\" |
1027 <WORD>"\\"[\{\}\[\]\;\" \t] {
1028   tcl_word(1,yytext);
1029 }
1030 <WORD>"\\\n" {
1031   tcl_word(2,yytext);
1032 }
1033 <WORD>"{" {
1034   tcl_word(3,yytext);
1035 }
1036 <WORD>"}" {
1037   tcl_word(4,yytext);
1038 }
1039 <WORD>"[" {
1040   tcl_word(5,yytext);
1041 }
1042 <WORD>"]" {
1043   tcl_word(6,yytext);
1044 }
1045 <WORD>"\"" {
1046   tcl_word(7,yytext);
1047 }
1048 <WORD>" " {
1049   tcl_word(8,yytext);
1050 }
1051 <WORD>"\t" {
1052   tcl_word(9,yytext);
1053 }
1054 <WORD>";" {
1055   tcl_word(10,yytext);
1056 }
1057 <WORD>"\n" {
1058   tcl_word(11,yytext);
1059 }
1060 <WORD>\x1A {
1061   tcl_word(12,yytext);
1062 }
1063 <WORD>. {
1064   tcl_word(1,yytext);
1065 }
1066 %%
1067
1068 //! Start new scan context for given 'content'.
1069 // @return created new scan context.
1070 static tcl_scan *tcl_scan_start(char type, QString content, QCString ns, Entry *entry_cl, Entry *entry_fn)
1071 {
1072   tcl_scan *myScan=tcl.scan.at(0);
1073   QCString myName;
1074 tcl_inf("line=%d type=%d '%s'\n",tcl.line_body0,type,content.ascii());
1075
1076   myScan->line1=yylineno;
1077   yy_push_state(TOP);
1078
1079   myScan=new tcl_scan;
1080   myScan->type[0] =' ';
1081   myScan->type[1] = '\0'; 
1082   switch (type) {
1083     case '"':
1084     case '{':
1085     case '[':
1086       myScan->type[0] = type;
1087       break;
1088     case '?':
1089       if (content[0]=='"' && content[content.length()-1]=='"') myScan->type[0]='"';
1090       if (content[0]=='{' && content[content.length()-1]=='}') myScan->type[0]='{';
1091       if (content[0]=='[' && content[content.length()-1]==']') myScan->type[0]='[';
1092   }
1093   if (myScan->type[0]!=' ')
1094   {
1095     tcl_codify(NULL,&myScan->type[0]);
1096     content = content.mid(1,content.length()-2);
1097   }
1098   content += (char)0x1A;// for detection end of scan context
1099   myScan->ns = ns;
1100   myScan->entry_cl = entry_cl;
1101   myScan->entry_fn = entry_fn;
1102   myScan->entry_scan = tcl.entry_current;
1103   myScan->buffer_state=yy_scan_string(content.ascii());
1104   myScan->line0=tcl.line_body0;
1105   myScan->line1=tcl.line_body1;
1106   myScan->after.clear();
1107   yylineno=myScan->line0;
1108   myScan->protection = tcl.protection;
1109
1110   tcl.entry_inside = myScan->entry_scan;
1111   tcl.entry_current = tcl_entry_new();
1112   tcl.scan.insert(0,myScan);
1113   yy_switch_to_buffer(myScan->buffer_state);
1114   return (myScan);
1115 }
1116
1117 //! Close current scan context.
1118 static void tcl_scan_end()
1119 {
1120   tcl_scan *myScan=tcl.scan.at(0);
1121   tcl_scan *myScan1=tcl.scan.at(1);
1122 tcl_inf("line=%d\n",myScan->line1);
1123
1124   if (myScan->type[0]=='{') myScan->type[0]='}';
1125   if (myScan->type[0]=='[') myScan->type[0]=']';
1126   if (myScan->type[0]!=' ') tcl_codify(NULL,&myScan->type[0]);
1127   int myStart=-1;
1128   for (unsigned int i=0;i<myScan->after.count();i=i+2)
1129   {
1130     if (myScan->after[i]=="script") {
1131       myStart=i;
1132       break;
1133     }
1134     tcl_codify(myScan->after[i].utf8(),myScan->after[i+1].utf8());
1135   }
1136   yy_delete_buffer(myScan->buffer_state);
1137   yy_pop_state();
1138   tcl.entry_inside = myScan1->entry_scan;
1139   yy_switch_to_buffer(myScan1->buffer_state);
1140   yylineno=myScan1->line1;
1141   tcl.protection = myScan1->protection;
1142   if (myStart>=0)
1143   {
1144     myScan1 = tcl_scan_start('?', myScan->after[myStart+1], myScan->ns, myScan->entry_cl, myScan->entry_fn);
1145     for (unsigned int i=myStart+2;i<myScan->after.count();i++)
1146     {
1147       myScan1->after.append(myScan->after[i]);
1148     }
1149     tcl.scan.remove(1);
1150   }
1151   else
1152   {
1153     tcl.scan.removeFirst();
1154   }
1155 }
1156
1157 //! Handling of word parsing.
1158 static void tcl_word(int what,const char *text) 
1159 {
1160   static char myList[1024]="";// nesting level list
1161   static int myLevel=0;// number of current nesting level
1162   static int myWhite=0;// set true when next char should be whitespace
1163   static char myWord;// internal state
1164
1165   switch (what)
1166   {
1167   case 0:// start
1168     yy_push_state(WORD);
1169     switch (text[0])
1170     {
1171       case '{':
1172       case '[':
1173       case '"': myWord = text[0]; break;
1174       default: myWord = '.';
1175     }
1176     myList[0]=myWord;
1177     myLevel=1;
1178     myWhite=0;
1179   break;
1180   case 1:// all other chars
1181     if (myWhite)
1182     {// {x}y "x"y
1183       tcl_err("expected word separator: %s\n",text);
1184       return;
1185     }
1186     if (myLevel==0)
1187     {
1188       myWord='.';
1189       myList[0]=myWord;
1190       myLevel=1;
1191     }
1192   break;
1193   case 2:// \\\n
1194     if (myLevel==0)
1195     {
1196       myWord=' ';
1197       yy_pop_state();
1198       yyless(0);
1199 tcl_inf("(\\\n) ?%s?\n",tcl.string_last.data());
1200       return;
1201     }
1202     switch (myList[myLevel-1])
1203     {
1204       case '{':
1205       case '[':
1206       case '"':
1207       break;
1208       case '.':
1209         if (myLevel==1)
1210         {
1211           myWord=' ';
1212           yy_pop_state();
1213           yyless(0);
1214 tcl_inf("(\\\n) ?%s?\n",tcl.string_last.data());
1215           return;
1216         }
1217       break;
1218     }
1219     myWhite=0;
1220   break;
1221   case 3:// {
1222     if (myWhite)
1223     {// {x}{ "x"{
1224       tcl_err("expected word separator: %s\n",text);
1225       return;
1226     }
1227     switch (myList[myLevel-1])
1228     {
1229       case '{':
1230       case '[':
1231         myList[myLevel++]='{';
1232       break;
1233       case '"':
1234       case '.':
1235       break;
1236     }
1237     myWhite=0;
1238   break;
1239   case 4:// }
1240     if (myWhite)
1241     {// {x}{ "x"{
1242       tcl_err("expected word separator: %s\n",text);
1243       return;
1244     }
1245     switch (myList[myLevel-1])
1246     {
1247       case '{':// {{x}}
1248         myLevel--;
1249         if (myLevel==0 && !tcl.code) 
1250         {
1251           myWhite=1;
1252         }
1253       break;
1254       case '[':
1255       case '"':
1256       case '.':
1257       break;
1258     }
1259   break;
1260   case 5:// [
1261     if (myWhite)
1262     {// {x}[
1263       tcl_err("expected word separator: %s\n",text);
1264       return;
1265     }
1266     switch (myList[myLevel-1])
1267     {
1268       case '{':
1269       break;
1270       case '[':
1271       case '"':
1272       case '.':
1273         myList[myLevel++]='[';
1274       break;
1275     }
1276     myWhite=0;
1277   break;
1278   case 6:// ]
1279     if (myWhite)
1280     {// {x}]
1281       tcl_err("expected word separator: %s\n",text);
1282       return;
1283     }
1284     switch (myList[myLevel-1])
1285     {
1286       case '{':
1287       break;
1288       case '[':
1289         myLevel--;
1290       break;
1291       case '"':
1292       case '.':
1293       break;
1294     }
1295     myWhite=0;
1296   break;
1297   case 7:// "
1298     if (myWhite)
1299     {// {x}"
1300       tcl_err("expected word separator: %s\n",text);
1301       return;
1302     }
1303     switch (myList[myLevel-1])
1304     {
1305       case '{':
1306       break;
1307       case '[':
1308         myList[myLevel++]='"';
1309       break;
1310       case '"':
1311         myLevel--;
1312       case '.':
1313       break;
1314     }
1315   break;
1316   case 8:// ' '
1317   case 9:// \t
1318   case 10:// ;
1319   case 11:// \n
1320     if (myLevel==0)
1321     {
1322       myWord=' ';
1323       yy_pop_state();
1324       yyless(0);
1325 tcl_inf("(%d) ?%s?\n",what,tcl.string_last.data());
1326       return;
1327     }
1328     switch (myList[myLevel-1])
1329     {
1330       case '{':
1331       case '[':
1332       case '"':
1333       break;
1334       case '.':
1335         if (myLevel==1)
1336         {
1337           myWord=' ';
1338           yy_pop_state();
1339           yyless(0);
1340 tcl_inf("(.%d) ?%s?\n",what,tcl.string_last.data());
1341           return;
1342         }
1343         else
1344         {
1345           myLevel--;
1346         }
1347       break;
1348     }
1349     myWhite=0;
1350   break;
1351   case 12:// \x1A
1352     if (myLevel==0)
1353     {
1354       myWord=' ';
1355       yy_pop_state();
1356       yyless(0);
1357 tcl_inf("(%d) ?%s?\n",what,tcl.string_last.data());
1358       return;
1359     }
1360     if (myLevel!=1 || myList[0] != '.')
1361     {
1362       tcl_war("level=%d expected=%c\n",myLevel,myList[myLevel-1]);
1363     }
1364     myWord=' ';
1365     yy_pop_state();
1366     yyless(0);
1367 tcl_inf("(.%d) ?%s?\n",what,tcl.string_last.data());
1368     return;
1369     myWhite=0;
1370   break;
1371   default:
1372     tcl_err("wrong state: %d\n",what);
1373     return;
1374   }
1375   tcl.string_last += text;
1376 }
1377
1378 //! Handling of comment parsing.
1379 static void tcl_comment(int what,const char *text)
1380 {
1381   if (what==0)
1382   { // begin of comment
1383     if (tcl.comment)
1384     {
1385       tcl_err("comment in comment\n");
1386       return;
1387     }
1388     yy_push_state(COMMENT);
1389 tcl_inf("<- %s\n",text);
1390     tcl.string_comment="";
1391     tcl.comment=0;
1392   }
1393   else if (what==1)
1394   { // start new comment
1395     if (tcl.comment)
1396     {
1397       tcl_comment(99,""); // inbody
1398     }
1399     tcl.string_comment=text;
1400     tcl.comment=1;
1401   }
1402   else if (what==2)
1403   { // add to comment
1404     if (tcl.comment)
1405     {
1406       tcl.string_comment+=text;
1407     }
1408   }
1409   else if (what==-1 || what == -2)
1410   { // end of comment without/with command
1411     if (tcl.comment)
1412     {
1413       tcl.string_last=tcl.string_comment;
1414       tcl_comment(100+what,"");
1415     }
1416     else
1417     {
1418       tcl.string_last = "";
1419 tcl_inf("-> %s\n",(const char *)tcl.string_comment);
1420     }
1421     yy_pop_state();
1422     tcl.string_comment="";
1423     tcl.comment=0;
1424   }
1425   else if (what==98 || what==99)
1426   { // 98=new 99=inbody
1427     if (tcl.this_parser && tcl.string_comment.length())
1428     {
1429 tcl_inf("-> %s\n",(const char *)tcl.string_comment);
1430       int myPos=0;
1431       bool myNew=0;
1432       int myLine=tcl.line_comment;
1433       BufStr myI(1024);
1434       BufStr myO(1024);
1435       Protection myProt=tcl.protection;
1436
1437       // resolve ALIASES
1438       myI.addArray("/*!",3);
1439       myI.addArray(tcl.string_comment.data(),tcl.string_comment.length());
1440       myI.addArray("*/",2);
1441       convertCppComments(&myI,&myO,tcl.file_name);
1442       myO.dropFromStart(3);
1443       myO.shrink(myO.curPos()-2);
1444       myO.addChar('\0');
1445       QCString myDoc = myO.data();
1446       if (what==99)
1447       { // inbody comment file or namespace or class or proc/method
1448         int myPos0;
1449         int myLine0;
1450         Entry myEntry0; // used to test parsing
1451         Entry *myEntry;
1452
1453         Entry *myEntry1=NULL;
1454         if (tcl.scan.at(0)->entry_fn)
1455         {
1456           myEntry1=tcl.scan.at(0)->entry_fn;
1457         }
1458         else if (tcl.scan.at(0)->entry_cl)
1459         {
1460           myEntry1=tcl.scan.at(0)->entry_cl;
1461         }
1462
1463         myPos0=myPos;
1464         myLine0=myLine;
1465         while (parseCommentBlock(tcl.this_parser, &myEntry0, myDoc, tcl.file_name,
1466           myLine, FALSE, tcl.config_autobrief, FALSE, myProt, myPos, myNew))
1467         {
1468           if (myNew)
1469           { // we need a new entry in this case
1470             myNew=0;
1471             myEntry = tcl_entry_new();
1472             parseCommentBlock(tcl.this_parser, myEntry, myDoc, tcl.file_name,
1473               myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
1474             tcl.entry_inside->addSubEntry(myEntry);
1475           }
1476           else
1477           { // we can add to current entry in this case
1478             if (!myEntry1)
1479             {
1480               myEntry1=tcl_entry_namespace(tcl.scan.at(0)->ns);
1481             }
1482             parseCommentBlock(tcl.this_parser, myEntry1, myDoc, tcl.file_name,
1483               myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
1484           }
1485           myPos0=myPos;
1486           myLine0=myLine;
1487         }
1488         if (myNew)
1489         { // we need a new entry
1490           myNew=0;
1491           myEntry = tcl_entry_new();
1492           parseCommentBlock(tcl.this_parser, myEntry, myDoc, tcl.file_name,
1493             myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
1494           tcl.entry_inside->addSubEntry(myEntry);
1495         }
1496         else
1497         { // we can add to current entry
1498           if (!myEntry1)
1499           {
1500             myEntry1=tcl_entry_namespace(tcl.scan.at(0)->ns);
1501           }
1502           parseCommentBlock(tcl.this_parser, myEntry1, myDoc, tcl.file_name,
1503             myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
1504         }
1505       }
1506       else
1507       { // new entry
1508         tcl.entry_current = tcl_entry_new();
1509         while (parseCommentBlock(tcl.this_parser, tcl.entry_current, myDoc,
1510           tcl.file_name, myLine, FALSE, tcl.config_autobrief, FALSE,
1511           myProt, myPos, myNew))
1512         {
1513           if (myNew)
1514           {
1515             tcl.entry_inside->addSubEntry(tcl.entry_current);
1516             tcl.entry_current = tcl_entry_new();
1517           }
1518           else
1519           {
1520             tcl.entry_current->section = tcl.entry_inside->section;
1521             tcl.entry_current->name = tcl.entry_inside->name;
1522           }
1523         }
1524         if (myNew)
1525         {
1526           tcl.entry_inside->addSubEntry(tcl.entry_current);
1527           tcl.entry_current = tcl_entry_new();
1528         }
1529         else
1530         {
1531           tcl.entry_current->section = tcl.entry_inside->section;
1532           tcl.entry_current->name = tcl.entry_inside->name;
1533         }
1534       }
1535       if (tcl.protection != myProt)
1536       {
1537         tcl.scan.at(0)->protection = tcl.protection = myProt;
1538       }
1539     }
1540   }
1541   else
1542   {
1543     tcl_err("what %d\n",what);
1544     return;
1545   }
1546 }
1547
1548 //! Parse given \c arglist .
1549 static void tcl_command_ARGLIST(QString &arglist)
1550 {
1551 D
1552   Argument *myArg;
1553   QStringList myArgs;
1554   QString myArglist="";
1555
1556   if (!tcl.entry_current->argList)
1557   {
1558     tcl.entry_current->argList=new ArgumentList;
1559   }
1560   tcl_split_list(arglist,myArgs);
1561   for (uint i=0;i<myArgs.count();i++)
1562   {
1563     QStringList myArgs1;
1564     myArg=new Argument;
1565
1566     tcl_split_list(*myArgs.at(i),myArgs1);
1567     if (myArgs1.count()==2)
1568     {
1569       myArg->name= (*myArgs1.at(0)).utf8();
1570       myArg->defval= (*myArgs1.at(1)).utf8();
1571       if (myArg->defval.isEmpty())
1572       {
1573         myArg->defval = " ";
1574       }
1575       myArglist += "?" + QCString(myArg->name) + "? ";
1576     }
1577     else
1578     {
1579       myArg->name= (*myArgs.at(i)).utf8();
1580       myArglist += QString(myArg->name) + " ";
1581     }
1582     tcl.entry_current->argList->append(myArg);
1583   }
1584   arglist = myArglist;
1585   tcl.entry_current->args = arglist.utf8();
1586 }
1587
1588 //! Create link.
1589 static void tcl_codify_link(QCString name)
1590 {
1591   if (tcl.code == NULL || name.isEmpty()) return;
1592   static int init=0;
1593   static QAsciiDict<MemberDef> fn;
1594   if (init==0) 
1595   {
1596     init=1;
1597     MemberNameSDict::Iterator mni(*Doxygen::memberNameSDict);
1598     MemberNameSDict::Iterator fni(*Doxygen::functionNameSDict);
1599     MemberName *mn=0;
1600     MemberDef *md;
1601     for (mni.toFirst();(mn=mni.current());++mni) 
1602     {
1603       MemberNameIterator mi(*mn);
1604       for (mi.toFirst();(md=mi.current());++mi) 
1605       {
1606         fn.insert(md->qualifiedName(),md);
1607       }
1608     }
1609     for (fni.toFirst();(mn=fni.current());++fni) 
1610     {
1611       MemberNameIterator fi(*mn);
1612       for (fi.toFirst();(md=fi.current());++fi) 
1613       {
1614         fn.insert(md->qualifiedName(),md);
1615       }
1616     }
1617   }
1618   MemberDef *myDef;
1619   QCString myName=name; 
1620   if (name.mid(0,2)=="::") // fully qualified global command
1621   {
1622     myName = myName.mid(2);
1623     myDef = fn.find(myName);
1624   }
1625   else // not qualified name
1626   {
1627     QCString myName1=myName; 
1628     myDef = NULL;
1629     myName1 = tcl.scan.at(0)->ns;
1630     if (myName1 == " " || myName1 == "")
1631     {
1632       myName1 = myName;
1633     }
1634     else
1635     {
1636       myName1 = myName1 + "::" + myName;
1637     }
1638     myDef = fn.find(myName1); // search namespace command
1639     if (myDef == NULL)
1640     {
1641       myDef = fn.find(myName); // search global command
1642     }
1643   }
1644   if (myDef != NULL) // documented command
1645   {
1646     tcl.code->writeCodeLink(myDef->getReference().data(),
1647                 myDef->getOutputFileBase().data(),
1648                 myDef->anchor().data(),
1649                 name,
1650                 myDef->qualifiedName().data());
1651     if (tcl.memberdef)
1652     {
1653         myDef->addSourceReferencedBy(tcl.memberdef);
1654         tcl.memberdef->addSourceReferences(myDef);
1655     }
1656   }
1657   else if (tcl_keyword(myName)) // check keyword
1658   {
1659     tcl_codify("keyword",name);
1660   }
1661   else
1662   {
1663     tcl_codify(NULL,name); // something else
1664   }
1665   
1666 }
1667
1668 //! Handle internal tcl commands.
1669 // "if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else?  ?bodyN?"
1670 static void tcl_command_IF(QStringList type)
1671 {
1672 D
1673   tcl_codify_cmd("keyword",0);
1674   tcl_codify_cmd(NULL,1);
1675   tcl_scan *myScan=tcl.scan.at(0);
1676   myScan = tcl_scan_start('?',*tcl.list_commandwords.at(2),
1677         myScan->ns,myScan->entry_cl,myScan->entry_fn);
1678   for (unsigned int i = 3;i<tcl.list_commandwords.count();i++)
1679   {
1680     myScan->after << type[i] << tcl.list_commandwords[i];
1681   }
1682 }
1683 //! Handle internal tcl commands.
1684 // "for start test next body"
1685 static void tcl_command_FOR()
1686 {
1687 D
1688   tcl_codify_cmd("keyword",0);
1689   tcl_codify_cmd(NULL,1);
1690   tcl_scan *myScan=tcl.scan.at(0);
1691   myScan = tcl_scan_start('?',*tcl.list_commandwords.at(2),
1692         myScan->ns,myScan->entry_cl,myScan->entry_fn);
1693   myScan->after << "NULL" << tcl.list_commandwords[3];
1694   myScan->after << "script" << tcl.list_commandwords[4];
1695   myScan->after << "NULL" << tcl.list_commandwords[5];
1696   myScan->after << "script" << tcl.list_commandwords[6];
1697   myScan->after << "NULL" << tcl.list_commandwords[7];
1698   myScan->after << "script" << tcl.list_commandwords[8];
1699 }
1700
1701 ///! Handle internal tcl commands.
1702 // "foreach varname list body" and
1703 // "foreach varlist1 list1 ?varlist2 list2 ...? body"
1704 static void tcl_command_FOREACH()
1705 {
1706 D
1707   unsigned int i;
1708   tcl_codify_cmd("keyword",0);
1709   for (i = 1;i<tcl.list_commandwords.count()-1;i++)
1710   {
1711     tcl_codify_cmd(NULL,i);
1712   }
1713   tcl_scan *myScan=tcl.scan.at(0);
1714   myScan = tcl_scan_start('?',*tcl.list_commandwords.at(tcl.list_commandwords.count()-1),
1715         myScan->ns,myScan->entry_cl,myScan->entry_fn);
1716 }
1717
1718 ///! Handle internal tcl commands.
1719 // "while test body"
1720 static void tcl_command_WHILE()
1721 {
1722 D
1723   tcl_codify_cmd("keyword",0);
1724   tcl_codify_cmd(NULL,1);
1725   tcl_scan *myScan=tcl.scan.at(0);
1726   myScan = tcl_scan_start('?',*tcl.list_commandwords.at(2),
1727         myScan->ns,myScan->entry_cl,myScan->entry_fn);
1728   myScan->after << "NULL" << tcl.list_commandwords[3];
1729   myScan->after << "script" << tcl.list_commandwords[4];
1730 }
1731
1732 //! Handle all other commands.
1733 // Create links of first command word or first command word inside [].
1734 static void tcl_command_OTHER()
1735 {
1736   if (tcl.code == NULL) return;
1737 D
1738   QCString myName;
1739   for (unsigned int i=0; i< tcl.list_commandwords.count(); i++)
1740   {
1741     myName = (*tcl.list_commandwords.at(i)).utf8();
1742     if (i==0)
1743     {
1744       tcl_codify_link(myName);
1745     }
1746     else if (i%2 != 0)
1747     {
1748       tcl_codify(NULL,myName);
1749     }
1750     else
1751     {
1752       QCString myStr="";
1753       int myCmd=0;
1754       unsigned int i;
1755       for (i=0;i<myName.length();i++)
1756       {
1757         QChar c = myName[i];
1758         if (myCmd) 
1759         {
1760           if (c==' '||c=='\t'||c=='\n'||c==']') 
1761           {//end of command
1762             tcl_codify_link(myStr);
1763             myStr="";
1764             myCmd=0;
1765           }
1766           myStr+=c;
1767         } 
1768         else 
1769         {
1770           myStr+=c;
1771           if (c=='[') 
1772           {//start of command
1773             for (;i<myName.length();i++)
1774             {
1775               c = myName[i+1];
1776               if (c!=' ' && c!='\t' && c!='\n') break;
1777               myStr+=c;
1778             }
1779             tcl_codify(NULL,myStr);
1780             myStr="";
1781             myCmd=1;
1782           }
1783         }
1784       }
1785       tcl_codify(NULL,myStr);
1786     }
1787   }
1788 }
1789
1790 //! Handle \c proc statements.
1791 static void tcl_command_PROC()
1792 {
1793 D
1794   QCString myNs, myName;
1795   Entry *myEntryNs;
1796   Entry *myEntry;
1797   tcl_scan *myScan = tcl.scan.at(0);
1798
1799   tcl_codify_cmd("keyword",0);
1800   tcl_codify_cmd(NULL,1);
1801   tcl_codify_cmd(NULL,2);
1802   tcl_codify_cmd(NULL,3);
1803   tcl_codify_cmd(NULL,4);
1804   tcl_codify_cmd(NULL,5);
1805   tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
1806   if (myNs.length())
1807   {
1808     myEntryNs = tcl_entry_namespace(myNs);
1809   }
1810   else
1811   {
1812     myEntryNs = tcl_entry_namespace(myScan->ns);
1813   }
1814   //why not needed here? tcl.fn.remove(myName);
1815   tcl.entry_current->section = Entry::FUNCTION_SEC;
1816   tcl.entry_current->mtype = Method;
1817   tcl.entry_current->name = myName;
1818   tcl.entry_current->startLine = tcl.line_command;
1819   tcl.entry_current->bodyLine = tcl.line_body0;
1820   tcl.entry_current->endBodyLine = tcl.line_body1;
1821   tcl_protection(tcl.entry_current);
1822   tcl_command_ARGLIST(*tcl.list_commandwords.at(4));
1823   myEntryNs->addSubEntry(tcl.entry_current);
1824   myEntry = tcl.entry_current;
1825   tcl.fn.insert(myName,myEntry);
1826   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(6),
1827         myEntryNs->name,NULL,myEntry);
1828 }
1829
1830 //! Handle \c itcl::body statements and \c oo::define method and method inside \c itcl::class statements.
1831 static void tcl_command_METHOD()
1832 {
1833 D
1834   QCString myNs, myName;
1835   Entry *myEntryCl, *myEntry;
1836   tcl_scan *myScan = tcl.scan.at(0);
1837
1838   tcl_codify_cmd("keyword",0);
1839   tcl_codify_cmd(NULL,1);
1840   tcl_codify_cmd(NULL,2);
1841   tcl_codify_cmd(NULL,3);
1842   tcl_codify_cmd(NULL,4);
1843   tcl_codify_cmd(NULL,5);
1844   tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
1845   if (myNs.length())
1846   {
1847     myEntryCl = tcl_entry_class(myNs);
1848   }
1849   else
1850   {
1851     myNs = myScan->ns;
1852     myEntryCl = myScan->entry_cl;
1853   }
1854   // needed in case of more then one definition p.e. itcl::method and itcl::body
1855   // see also bug #
1856   tcl.fn.remove(myName);
1857   tcl.entry_current->section = Entry::FUNCTION_SEC;
1858   tcl.entry_current->mtype = Method;
1859   tcl.entry_current->name = myName;
1860   tcl.entry_current->startLine = tcl.line_command;
1861   tcl.entry_current->bodyLine = tcl.line_body0;
1862   tcl.entry_current->endBodyLine = tcl.line_body1;
1863   tcl_protection(tcl.entry_current);
1864   tcl_command_ARGLIST(*tcl.list_commandwords.at(4));
1865   myEntryCl->addSubEntry(tcl.entry_current);
1866   tcl.fn.insert(myName,tcl.entry_current);
1867   myEntry = tcl.entry_current;
1868   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(6),
1869         myNs, myEntryCl, myEntry);
1870 }
1871
1872 //! Handle \c constructor statements inside class definitions.
1873 static void tcl_command_CONSTRUCTOR()
1874 {
1875 D
1876   QCString myNs, myName;
1877   Entry *myEntryCl, *myEntry;
1878   tcl_scan *myScan = tcl.scan.at(0);
1879
1880   tcl_codify_cmd("keyword",0);
1881   tcl_codify_cmd(NULL,1);
1882   tcl_codify_cmd(NULL,2);
1883   tcl_codify_cmd(NULL,3);
1884   tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)).utf8(),myNs,myName);
1885   if (myNs.length())
1886   {
1887     myEntryCl = tcl_entry_class(myNs);
1888   }
1889   else
1890   {
1891     myNs = myScan->ns;
1892     myEntryCl = myScan->entry_cl;
1893   }
1894   tcl.entry_current->section = Entry::FUNCTION_SEC;
1895   tcl.entry_current->mtype = Method;
1896   tcl.entry_current->name = myName;
1897   tcl.entry_current->startLine = tcl.line_command;
1898   tcl.entry_current->bodyLine = tcl.line_body0;
1899   tcl.entry_current->endBodyLine = tcl.line_body1;
1900   tcl_protection(tcl.entry_current);
1901   tcl_command_ARGLIST(*tcl.list_commandwords.at(2));
1902   if (myEntryCl) myEntryCl->addSubEntry(tcl.entry_current);
1903   myEntry = tcl.entry_current;
1904   tcl.fn.insert(myName,myEntry);
1905   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(4),
1906         myNs, myEntryCl, myEntry);
1907 }
1908
1909 //! Handle \c destructor statements inside class definitions.
1910 static void tcl_command_DESTRUCTOR()
1911 {
1912 D
1913   QCString myNs, myName;
1914   Entry *myEntryCl, *myEntry;
1915   tcl_scan *myScan = tcl.scan.at(0);
1916
1917   tcl_codify_cmd("keyword",0);
1918   tcl_codify_cmd(NULL,1);
1919   tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)).utf8(),myNs,myName);
1920   if (myNs.length())
1921   {
1922     myEntryCl = tcl_entry_class(myNs);
1923   }
1924   else
1925   {
1926     myNs = myScan->ns;
1927     myEntryCl = myScan->entry_cl;
1928   }
1929   tcl.entry_current->section = Entry::FUNCTION_SEC;
1930   tcl.entry_current->mtype = Method;
1931   tcl.entry_current->name = myName;
1932   tcl.entry_current->startLine = tcl.line_command;
1933   tcl.entry_current->bodyLine = tcl.line_body0;
1934   tcl.entry_current->endBodyLine = tcl.line_body1;
1935   tcl_protection(tcl.entry_current);
1936   myEntryCl->addSubEntry(tcl.entry_current);
1937   myEntry = tcl.entry_current;
1938   tcl.fn.insert(myName,myEntry);
1939   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(2),
1940         myNs, myEntryCl, myEntry);
1941 }
1942
1943 //! Handle \c namespace statements.
1944 static void tcl_command_NAMESPACE()
1945 {
1946 D
1947   QCString myNs, myName, myStr;
1948   //Entry *myEntryNs=NULL;
1949   tcl_scan *myScan = tcl.scan.at(0);
1950
1951   tcl_codify_cmd("keyword",0);
1952   tcl_codify_cmd(NULL,1);
1953   tcl_codify_cmd("keyword",2);
1954   tcl_codify_cmd(NULL,3);
1955   tcl_codify_cmd(NULL,4);
1956   tcl_codify_cmd(NULL,5);
1957   tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)).utf8(),myNs,myName);
1958   if (myNs.length())
1959   {
1960     myName = myNs+"::"+myName;
1961   }
1962   tcl.entry_current->section = Entry::NAMESPACE_SEC;
1963   tcl.entry_current->name = myName;
1964   tcl.entry_current->startLine = tcl.line_command;
1965   tcl.entry_current->bodyLine = tcl.line_body0;
1966   tcl.entry_current->endBodyLine = tcl.line_body1;
1967   tcl.entry_main->addSubEntry(tcl.entry_current);
1968   tcl.ns.insert(myName,tcl.entry_current);
1969   //myEntryNs = tcl.entry_current;
1970   myStr = (*tcl.list_commandwords.at(6)).utf8();
1971   if (tcl.list_commandwords.count() > 7)
1972   {
1973     for (uint i=7;i<tcl.list_commandwords.count();i++)
1974     {
1975       myStr.append((*tcl.list_commandwords.at(i)).utf8());
1976     }
1977     tcl.word_is=' ';
1978   }
1979   myScan = tcl_scan_start(tcl.word_is,myStr, myName, NULL, NULL);
1980 }
1981
1982 //! Handle \c itcl::class statements.
1983 static void tcl_command_ITCL_CLASS()
1984 {
1985 D
1986   QCString myNs, myName, myStr;
1987   Entry *myEntryCl;
1988   tcl_scan *myScan = tcl.scan.at(0);
1989
1990   tcl_codify_cmd("keyword",0);
1991   tcl_codify_cmd(NULL,1);
1992   tcl_codify_cmd("NULL",2);
1993   tcl_codify_cmd("NULL",3);
1994   tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
1995   if (myNs.length())
1996   {
1997     myName = myNs+"::"+myName;
1998   }
1999   tcl.entry_current->section = Entry::CLASS_SEC;
2000   tcl.entry_current->name = myName;
2001   tcl.entry_current->startLine = tcl.line_command;
2002   tcl.entry_current->bodyLine = tcl.line_body0;
2003   tcl.entry_current->endBodyLine = tcl.line_body1;
2004   tcl.entry_main->addSubEntry(tcl.entry_current);
2005   tcl.cl.insert(myName,tcl.entry_current);
2006   myEntryCl = tcl.entry_current;
2007   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(4),
2008         myName, myEntryCl, NULL);
2009 }
2010
2011 //! Handle \c oo::class statements.
2012 static void tcl_command_OO_CLASS()
2013 {
2014 D
2015   QCString myNs, myName, myStr;
2016   //Entry *myEntryNs;
2017   Entry *myEntryCl;
2018   tcl_scan *myScan = tcl.scan.at(0);
2019
2020   tcl_codify_cmd("keyword",0);
2021   tcl_codify_cmd(NULL,1);
2022   tcl_codify_cmd("NULL",2);
2023   tcl_codify_cmd("NULL",3);
2024   tcl_codify_cmd("NULL",4);
2025   tcl_codify_cmd("NULL",5);
2026   tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)).utf8(),myNs,myName);
2027   if (myNs.length())
2028   {
2029     myName = myNs+"::"+myName;
2030   }
2031   tcl.entry_current->section = Entry::CLASS_SEC;
2032   tcl.entry_current->name = myName;
2033   tcl.entry_current->startLine = tcl.line_command;
2034   tcl.entry_current->bodyLine = tcl.line_body0;
2035   tcl.entry_current->endBodyLine = tcl.line_body1;
2036   tcl.entry_main->addSubEntry(tcl.entry_current);
2037   //myEntryNs = tcl_entry_namespace(myName);
2038   tcl.cl.insert(myName,tcl.entry_current);
2039   myEntryCl = tcl.entry_current;
2040   myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(6),
2041         myName, myEntryCl, NULL);
2042 }
2043
2044 //! Handle \c oo::define statements.
2045 static void tcl_command_OO_DEFINE()
2046 {
2047 D
2048   QCString myNs, myName, myStr;
2049   Entry *myEntryCl;
2050   tcl_scan *myScan = tcl.scan.at(0);
2051
2052   tcl_codify_cmd("keyword",0);
2053   tcl_codify_cmd(NULL,1);
2054   tcl_codify_cmd("NULL",2);
2055   tcl_codify_cmd("NULL",3);
2056   tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
2057   if (myNs.length())
2058   {
2059     myName = myNs+"::"+myName;
2060   }
2061   myEntryCl = tcl_entry_class(myName);
2062   myStr = (*tcl.list_commandwords.at(4)).utf8();
2063   if (tcl.list_commandwords.count() > 5)
2064   {
2065     for (uint i=5;i<tcl.list_commandwords.count();i++)
2066     {
2067       myStr.append((*tcl.list_commandwords.at(i)).utf8());
2068     }
2069     tcl.word_is=' ';
2070   }
2071   myScan = tcl_scan_start(tcl.word_is,myStr,myName,myEntryCl,NULL);
2072 }
2073
2074 //! Handle \c variable statements.
2075 static void tcl_command_VARIABLE(int inclass)
2076 {
2077 D
2078   QCString myNs, myName;
2079   Entry *myEntry;
2080   tcl_scan *myScan = tcl.scan.at(0);
2081
2082   tcl_codify_cmd("keyword",0);
2083   for (unsigned int i=1; i< tcl.list_commandwords.count(); i++)
2084   {
2085     tcl_codify_cmd(NULL,i);
2086   }
2087   tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
2088   if (myNs.length())
2089   {// qualified variables go into namespace
2090     myEntry = tcl_entry_namespace(myNs);
2091     tcl.entry_current->stat = true;
2092   }
2093   else
2094   {
2095     if (inclass)
2096     {
2097       myEntry = myScan->entry_cl;
2098       tcl.entry_current->stat = false;
2099     }
2100     else
2101     {
2102       myEntry = tcl_entry_namespace(myScan->ns);
2103       tcl.entry_current->stat = true;
2104     }
2105   }
2106   tcl.entry_current->section = Entry::VARIABLE_SEC;
2107   tcl.entry_current->name = myName;
2108   tcl.entry_current->startLine = tcl.line_command;
2109   tcl.entry_current->bodyLine = tcl.line_body0;
2110   tcl.entry_current->endBodyLine = tcl.line_body1;
2111   tcl_protection(tcl.entry_current);
2112   myEntry->addSubEntry(tcl.entry_current);
2113   tcl.entry_current = tcl_entry_new();
2114 }
2115
2116 //! Handling of command parsing.
2117 //! what=0  -> ...
2118 //! what=1  -> ...
2119 //! what=-1 -> ...
2120 static void tcl_command(int what,const char *text)
2121 {
2122   int myLine=0;
2123   if (what==0)
2124   {
2125     tcl.scan.at(0)->line1=yylineno;// current line in scan context
2126     tcl.line_body0=yylineno;// start line of command
2127 tcl_inf("<- %s\n",text);
2128     yy_push_state(COMMAND);
2129     tcl.list_commandwords.clear();
2130     tcl.string_command="";
2131     tcl.string_last="";
2132     tcl.command=1;
2133     return;
2134   }
2135   else if (what==1)
2136   {
2137     if (tcl.string_last.length())
2138     {
2139       tcl.list_commandwords.append(tcl.string_last);
2140       tcl.string_last="";
2141     }
2142     if (text) 
2143     {
2144       tcl.list_commandwords.append(text);
2145     }
2146     return;
2147   }
2148   else if (what!=-1)
2149   {// should not happen
2150     tcl_err("what %d\n",what);
2151     return;
2152   }
2153   QCString myText = text;
2154 tcl_inf("->\n");
2155   if (tcl.command==0)
2156   {
2157     return; //TODO check on inside comment
2158   }
2159   if (tcl.string_last != "")
2160   {// get last word
2161     tcl.list_commandwords.append(tcl.string_last);
2162     tcl.string_last="";
2163   }
2164   yy_pop_state();
2165
2166   // check command
2167   QCString myStr = (*tcl.list_commandwords.at(0)).utf8();
2168   int myLevel = 0;
2169   Protection myProt = tcl.protection;
2170
2171   if (tcl.list_commandwords.count() < 3)
2172   {
2173     tcl_command_OTHER();
2174     goto command_text;
2175   }
2176   // remove leading "::" and apply TCL_SUBST
2177   if (myStr.left(2)=="::") myStr = myStr.mid(2);
2178   if (tcl.config_subst.contains(myStr))
2179   {
2180     myStr=tcl.config_subst[myStr].utf8();
2181   }
2182   if (myStr=="private")
2183   {
2184     tcl.protection = Private;
2185     myLevel = 1;
2186   }
2187   else if (myStr=="protected")
2188   {
2189     tcl.protection = Protected;
2190     myLevel = 1;
2191   }
2192   else if (myStr=="public")
2193   {
2194     tcl.protection = Public;
2195     myLevel = 1;
2196   }
2197   if (myLevel)
2198   {
2199     tcl_codify_cmd("keyword",0);
2200     tcl_codify_cmd(NULL,1);
2201     tcl.list_commandwords.remove(tcl.list_commandwords.at(1));
2202     tcl.list_commandwords.remove(tcl.list_commandwords.at(0));
2203     if (tcl.list_commandwords.count()==1)
2204     {
2205       tcl_scan *myScan = tcl.scan.at(0);
2206       myScan = tcl_scan_start(tcl.word_is,*tcl.list_commandwords.at(0),
2207         myScan->ns,myScan->entry_cl,myScan->entry_fn);
2208       myProt = tcl.protection;
2209       goto command_end;
2210     }
2211     myStr       = (*tcl.list_commandwords.at(0)).utf8();
2212     // remove leading "::" and apply TCL_SUBST
2213     if (myStr.left(2)=="::") myStr = myStr.mid(2);
2214     if (tcl.config_subst.contains(myStr))
2215     {
2216       myStr=tcl.config_subst[myStr].utf8();
2217     }
2218   }
2219   if (myStr=="proc")
2220   {
2221     if (tcl.list_commandwords.count() == 5)
2222     {// itcl::proc
2223       tcl.list_commandwords.append("");
2224       tcl.list_commandwords.append("");
2225     }
2226     if (tcl.list_commandwords.count() != 7) {myLine=__LINE__;goto command_warn;}
2227     tcl_command_PROC();
2228     goto command_end;
2229   }
2230   if (myStr=="method")
2231   {
2232     if (tcl.list_commandwords.count() == 5)
2233     {// itcl::method
2234       tcl.list_commandwords.append("");
2235       tcl.list_commandwords.append("");
2236     }
2237     if (tcl.list_commandwords.count() != 7) {myLine=__LINE__;goto command_warn;}
2238     tcl_command_METHOD();
2239     goto command_end;
2240   }
2241   if (myStr=="constructor")
2242   {
2243     if (tcl.list_commandwords.count() != 5) {myLine=__LINE__;goto command_warn;}
2244     tcl_command_CONSTRUCTOR();
2245     goto command_end;
2246   }
2247   if (myStr=="destructor")
2248   {
2249     if (tcl.list_commandwords.count() != 3) {myLine=__LINE__;goto command_warn;}
2250     tcl_command_DESTRUCTOR();
2251     goto command_end;
2252   }
2253   if (myStr=="namespace")
2254   {
2255     if ((*tcl.list_commandwords.at(2)).utf8()=="eval")
2256     {
2257       if (tcl.list_commandwords.count() < 7) {myLine=__LINE__;goto command_warn;}
2258       tcl_command_NAMESPACE();
2259       goto command_end;
2260     }
2261     tcl_command_OTHER();
2262     goto command_text;
2263   }
2264   if (myStr=="itcl::class")
2265   {
2266     if (tcl.list_commandwords.count() != 5) {myLine=__LINE__;goto command_warn;}
2267     tcl_command_ITCL_CLASS();
2268     goto command_end;
2269   }
2270   if (myStr=="itcl::body")
2271   {
2272     if (tcl.list_commandwords.count() != 7) {myLine=__LINE__;goto command_warn;}
2273     tcl_command_METHOD();
2274     goto command_end;
2275   }
2276   if (myStr=="oo::class")
2277   {
2278     if ((*tcl.list_commandwords.at(2)).utf8()=="create")
2279     {
2280       if (tcl.list_commandwords.count() != 7) {myLine=__LINE__;goto command_warn;}
2281       tcl_command_OO_CLASS();
2282       goto command_end;
2283     }
2284     tcl_command_OTHER();
2285     goto command_text;
2286   }
2287   if (myStr=="oo::define")
2288   {
2289     if (tcl.list_commandwords.count() < 5) {myLine=__LINE__;goto command_warn;}
2290     tcl_command_OO_DEFINE();
2291     goto command_end;
2292   }
2293   if (myStr=="variable")
2294   {
2295     if (tcl.list_commandwords.count() < 3) {myLine=__LINE__;goto command_warn;}
2296     if (tcl.scan.at(0)->entry_fn == NULL)
2297     {// only parsed outside functions
2298       tcl_command_VARIABLE(tcl.scan.at(0)->entry_cl && tcl.scan.at(0)->entry_cl->name!="");
2299       goto command_text;
2300     }
2301   }
2302   if (myStr=="common")
2303   {
2304     if (tcl.list_commandwords.count() < 3) {myLine=__LINE__;goto command_warn;}
2305     if (tcl.scan.at(0)->entry_fn == NULL)
2306     {// only parsed outside functions
2307       tcl_command_VARIABLE(0);
2308       goto command_text;
2309     }
2310   }
2311   if (myStr=="inherit" || myStr=="superclass")
2312   {
2313     if (tcl.list_commandwords.count() < 3) {myLine=__LINE__;goto command_warn;}
2314     if (tcl.scan.at(0)->entry_cl && tcl.scan.at(0)->entry_cl->name!="")
2315     {
2316       for (unsigned int i = 2; i < tcl.list_commandwords.count(); i = i + 2)
2317       {
2318         tcl.scan.at(0)->entry_cl->extends->append(new BaseInfo((*tcl.list_commandwords.at(i)).utf8(),Public,Normal));
2319       }
2320     }
2321     goto command_end;
2322   }
2323   /*
2324    * Start of internal tcl keywords
2325    * Ready: if, for, foreach, while
2326    * TODO: switch, eval, ?
2327    */
2328   if (myStr=="for")
2329   {
2330     if (tcl.list_commandwords.count() != 9) {myLine=__LINE__;goto command_warn;}
2331     tcl_command_FOR();
2332     goto command_end;
2333   }
2334   if (myStr=="foreach")
2335   {
2336     if (tcl.list_commandwords.count() < 7 || tcl.list_commandwords.count()%2==0) {myLine=__LINE__;goto command_warn;}
2337     tcl_command_FOREACH();
2338     goto command_end;
2339   }
2340   /*
2341 if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else?  ?bodyN?
2342   */
2343   if (myStr=="if" && tcl.list_commandwords.count() > 4)
2344   {
2345     QStringList myType;
2346     myType << "keyword" << "NULL" << "script" << "NULL";
2347     char myState='x';// last word: e'x'pr 't'hen 'b'ody 'e'lse else'i'f..
2348     for (unsigned int i = 4; i < tcl.list_commandwords.count(); i = i + 2)
2349     {
2350       QCString myStr=(*tcl.list_commandwords.at(i)).utf8();
2351       if (myState=='x')
2352       {
2353         if (myStr=="then") 
2354         {
2355           myState='t';
2356           myType << "keyword" << "NULL";
2357         }
2358         else
2359         {
2360           myState='b';
2361           myType << "script" << "NULL";
2362         }
2363       }
2364       else if (myState=='t')
2365       {
2366         myState='b';
2367         myType << "script" << "NULL";
2368       }
2369       else if (myState=='b')
2370       {
2371         if (myStr=="elseif") {
2372           myState='i';
2373           myType << "keyword" << "NULL";
2374         }
2375         else if (myStr=="else" && i==tcl.list_commandwords.count()-3)
2376         {
2377           myState = 'b';
2378           myType << "keyword" << "NULL" << "script";
2379           i = tcl.list_commandwords.count();
2380         }
2381         else if (i==tcl.list_commandwords.count()-1)
2382         {
2383           myState = 'b';
2384           myType << "script";
2385           i = tcl.list_commandwords.count();
2386         }
2387         else
2388         {
2389           myLine=__LINE__;goto command_warn;
2390         }
2391       }
2392       else if (myState=='i')
2393       {
2394         myState='x';
2395         myType << "script" << "NULL";
2396       }
2397     }
2398     if (myState != 'b') {myLine=__LINE__;goto command_warn;}
2399     tcl_command_IF(myType);
2400     goto command_end;
2401   }
2402   if (myStr=="while")
2403   {
2404     if (tcl.list_commandwords.count() != 5) {myLine=__LINE__;goto command_warn;}
2405     tcl_command_WHILE();
2406     goto command_end;
2407   }
2408   tcl_command_OTHER();
2409   goto command_text;
2410   command_warn:// print warning message because of wrong used syntax
2411     tcl_war("%d count=%d: %s\n",myLine,tcl.list_commandwords.count(),tcl.list_commandwords.join(" ").ascii());
2412     tcl_command_OTHER();
2413   command_text:// print remaining text as comment
2414     if (!myText.isEmpty()) tcl_codify("comment",myText);
2415     myText = "";
2416   command_end:// add remaining text to current context
2417     if (!myText.isEmpty()) tcl.scan.at(0)->after << "comment" << myText;
2418     tcl.list_commandwords.clear();
2419     tcl.command = 0;
2420     tcl.protection = myProt;
2421 }
2422
2423 //----------------------------------------------------------------------------
2424 //! Common initializations.
2425 static void tcl_init()
2426 {
2427   // Get values from option TCL_SUBST
2428   tcl.config_subst.clear();
2429   if (Config::instance()->get("TCL_SUBST")) 
2430   {
2431     QStrList myStrList = Config_getList("TCL_SUBST");
2432     const char *s=myStrList.first();
2433     while (s) 
2434     {
2435       QCString myStr=s;
2436       int i=myStr.find('=');
2437       if (i>0)
2438       {
2439         QCString myName=myStr.left(i).stripWhiteSpace();
2440         QCString myValue=myStr.right(myStr.length()-i-1).stripWhiteSpace();
2441         if (!myName.isEmpty() && !myValue.isEmpty())
2442 tcl_inf("TCL_SUBST: use '%s'\n",s);
2443         tcl.config_subst[myName] = myValue;
2444       }
2445       s = myStrList.next();
2446     }
2447   }
2448
2449   if (tcl.input_string.at(tcl.input_string.length()-1) == '\n') 
2450   {
2451     tcl.input_string[tcl.input_string.length()-1] = 0x1A;
2452   } 
2453   else 
2454   {
2455     tcl.input_string += 0x1A;
2456   }
2457   tcl.code = NULL;
2458   tcl.code_font=NULL;
2459   tcl.code_line=1;
2460   tcl.code_linenumbers=1;
2461   tcl.config_autobrief = Config_getBool("JAVADOC_AUTOBRIEF");
2462   tcl.input_position = 0;
2463   tcl.file_name = NULL;
2464   tcl.this_parser = NULL;
2465   tcl.command=0;
2466   tcl.comment=0;
2467   tcl.brace_level=0;
2468   tcl.bracket_level=0;
2469   tcl.bracket_quote=0;
2470   tcl.word_is=' ';
2471   tcl.string_command="";
2472   tcl.string_commentline="";
2473   tcl.string_commentcodify="";
2474   tcl.string_comment    = "";
2475   tcl.string_last       = "";
2476   tcl.entry_main        = NULL;
2477   tcl.entry_file        = NULL;
2478   tcl.entry_current     = NULL;
2479   tcl.entry_inside      = NULL;
2480   tcl.list_commandwords.clear();
2481   tcl.scan.clear();
2482   tcl.ns.clear();
2483   tcl.cl.clear();
2484   tcl.fn.clear();
2485   yylineno              = 1;
2486   tcl.protection        = Public;
2487   tcl.memberdef         = NULL;
2488 }
2489
2490 //! Start parsing.
2491 static void tcl_parse(const QCString ns, const QCString cls)
2492 {
2493   tcl_scan *myScan;
2494
2495   tcl.entry_file          = tcl_entry_new();
2496   tcl.entry_file->name    = tcl.file_name;
2497   tcl.entry_file->section = Entry::SOURCE_SEC;
2498   tcl.entry_file->protection = Public;
2499   tcl.entry_main->addSubEntry(tcl.entry_file);
2500   Entry *myEntry=tcl_entry_new();
2501   myEntry->name="";
2502   tcl.entry_main->addSubEntry(myEntry);
2503   tcl.ns.insert("::",myEntry);
2504   tcl.entry_current = tcl_entry_new();
2505
2506   tclscannerYYrestart( tclscannerYYin );
2507   BEGIN( TOP );
2508   yylineno=1;
2509   myScan = new tcl_scan;
2510   myScan->type[0]=' ';myScan->type[1]='\n';
2511   myScan->after.clear();
2512   myScan->line0=yylineno;
2513   myScan->line1=yylineno;
2514   myScan->buffer_state=YY_CURRENT_BUFFER;
2515   myScan->ns=ns;
2516   myScan->entry_cl=tcl_entry_class(cls);
2517   myScan->entry_fn=NULL;
2518   tcl.entry_inside = tcl.entry_file;
2519   myScan->entry_scan = tcl.entry_inside;
2520   tcl.scan.insert(0,myScan);
2521   tclscannerYYlex();
2522   tcl.scan.clear();
2523   tcl.ns.clear();
2524   tcl.cl.clear();
2525   tcl.fn.clear();
2526   tcl.entry.clear();
2527 }
2528
2529 //! Parse text file and build up entry tree.
2530 void TclLanguageScanner::parseInput(const char *fileName,
2531                                     const char *input,
2532                                     Entry *root,
2533                                     bool /*sameTranslationUnit*/,
2534                                     QStrList & /*filesInSameTranslationUnit*/)
2535 {
2536   QFile            myFile;
2537 tcl_inf("%s\n",fileName);
2538   myFile.setName(fileName);
2539   if (!myFile.open(IO_ReadOnly)) return;
2540   if (strlen(input)<1) return;
2541
2542   tcl.input_string = input;
2543   if (tcl.input_string.length()<1) return;
2544   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2545
2546   msg("Parsing %s...\n",fileName);
2547   groupEnterFile(fileName,yylineno);
2548
2549   tcl_init();
2550   tcl.code = NULL;
2551   tcl.file_name = fileName;
2552   tcl.this_parser = this;
2553   tcl.entry_main          = root; /* toplevel entry */
2554   tcl_parse("","");
2555   groupLeaveFile(tcl.file_name,yylineno);
2556   root->program.resize(0);
2557   myFile.close();
2558   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2559 }
2560
2561 //! Parse file and codify.
2562 void TclLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2563                    const char * scopeName,
2564                    const QCString & input,
2565                    SrcLangExt lang,
2566                    bool isExampleBlock,
2567                    const char * exampleName,
2568                    FileDef * fileDef,
2569                    int startLine,
2570                    int endLine,
2571                    bool inlineFragment,
2572                    MemberDef *memberDef,
2573                    bool showLineNumbers,
2574                    Definition *searchCtx,
2575                    bool collectXRefs
2576                   )
2577 {
2578   (void)scopeName;
2579   (void)lang;
2580   (void)exampleName;
2581   (void)fileDef;
2582   (void)endLine;
2583   (void)inlineFragment;
2584   (void)searchCtx;
2585   (void)collectXRefs;
2586
2587   if (input.length()<1) return;
2588   printlex(yy_flex_debug, TRUE, __FILE__, fileDef ? fileDef->fileName().data(): NULL);
2589   tcl.input_string = input;
2590
2591   QCString myNs="";
2592   QCString myCls="";
2593   if (memberDef)
2594   {
2595     if (memberDef->getClassDef())
2596     {
2597       myCls = memberDef->getClassDef()->displayName();
2598       myNs = myCls;
2599     }
2600     else if (memberDef->getNamespaceDef())
2601     {
2602       myNs = memberDef->getNamespaceDef()->displayName();
2603     }
2604   }
2605
2606   QString myStr="Codifying..";
2607   if (scopeName)
2608   {
2609     myStr +=" scope=";
2610     myStr+=scopeName;
2611   }
2612   if (exampleName)
2613   {
2614     myStr+=" example=";
2615     myStr+=exampleName;
2616   }
2617   if (memberDef)
2618   {
2619     myStr+=" member=";
2620     myStr+=memberDef->memberTypeName();
2621     myStr+=" ";
2622     myStr+=memberDef->qualifiedName();
2623   }
2624   if (fileDef)
2625   {
2626     myStr+=" file=";
2627     myStr+=fileDef->fileName();
2628   }
2629 tcl_inf("%s (%d,%d) %d %d\n",myStr.ascii(),startLine,endLine,isExampleBlock,inlineFragment);
2630 //tcl_inf("%s\n"input.data());
2631   if (isExampleBlock)
2632   {
2633     tcl_codify(NULL,input);
2634     return;
2635   }
2636   tcl_init();
2637   tcl.memberdef = memberDef;
2638   tcl.code = &codeOutIntf;
2639   if (startLine<0) 
2640   {
2641     startLine=1;
2642   }
2643   yylineno=startLine;
2644   tcl.code_linenumbers = showLineNumbers;
2645   tcl.code_line=yylineno;
2646   tcl.code->startCodeLine(tcl.code_linenumbers);
2647   if (tcl.code_linenumbers) 
2648   {
2649     tcl.code->writeLineNumber(0,0,0,tcl.code_line);
2650   }
2651   tcl.file_name = "";
2652   tcl.this_parser = NULL;
2653   tcl.entry_main = tcl_entry_new();
2654   tcl_parse(myNs,myCls);
2655   tcl.code->endCodeLine();
2656   tcl.scan.clear();
2657   tcl.ns.clear();
2658   tcl.cl.clear();
2659   tcl.fn.clear();
2660   tcl.entry.clear();
2661   printlex(yy_flex_debug, FALSE, __FILE__, fileDef ? fileDef->fileName().data(): NULL);
2662 }
2663
2664 bool TclLanguageScanner::needsPreprocessing(const QCString &extension)
2665 {
2666   (void)extension;
2667   return FALSE;
2668 }
2669
2670 void TclLanguageScanner::resetCodeParserState()
2671 {
2672 }
2673
2674 void TclLanguageScanner::parsePrototype(const char *text)
2675 {
2676   (void)text;
2677 }
2678
2679 static int yyread(char *buf,int max_size)
2680 {
2681   int c=0;
2682
2683   *buf = '\0';
2684   while ( c < max_size && tcl.input_string.at(tcl.input_position) )
2685   {
2686     *buf = tcl.input_string.at(tcl.input_position++) ;
2687     c++; buf++;
2688   }
2689   //printf("Read from=%d size=%d max=%d c=%d\n",tcl.input_position,strlen(&tcl.input_string[tcl.input_position]),max_size,c);
2690   return c;
2691 }
2692
2693 //----------------------------------------------------------------------------
2694
2695 // to avoid a warning
2696 void tclDummy()
2697 {
2698   yy_top_state();
2699 }
2700
2701 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
2702 //----------------------------------------------------------------------------
2703 extern "C" { // some bogus code to keep the compiler happy
2704   void tclscannerYYdummy() { yy_flex_realloc(0,0); } 
2705 }
2706 #endif
2707