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