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