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