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