OSDN Git Service

Updated to tcl 8.4.1
[pf3gnuchains/sourceware.git] / tcl / tools / man2help2.tcl
1 # man2help2.tcl --
2 #
3 # This file defines procedures that are used during the second pass of
4 # the man page conversion.  It converts the man format input to rtf
5 # form suitable for use by the Windows help compiler.
6 #
7 # Copyright (c) 1996 by Sun Microsystems, Inc.
8 #
9 # See the file "license.terms" for information on usage and redistribution
10 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
12 # RCS: @(#) $Id$
13
14
15 # Global variables used by these scripts:
16 #
17 # state -       state variable that controls action of text proc.
18 #                               
19 # topics -      array indexed by (package,section,topic) with value
20 #               of topic ID.
21 #
22 # keywords -    array indexed by keyword string with value of topic ID.
23 #
24 # curID -       current topic ID, starts at 0 and is incremented for
25 #               each new topic file.
26 #
27 # curPkg -      current package name (e.g. Tcl).
28 #
29 # curSect -     current section title (e.g. "Tcl Built-In Commands").
30 #
31
32 # initGlobals --
33 #
34 # This procedure is invoked to set the initial values of all of the
35 # global variables, before processing a man page.
36 #
37 # Arguments:
38 # None.
39
40 proc initGlobals {} {
41     uplevel \#0 unset state
42     global state chars
43
44     set state(paragraphPending) 0
45     set state(breakPending) 0
46     set state(firstIndent) 0
47     set state(leftIndent) 0
48
49     set state(inTP) 0
50     set state(paragraph) 0
51     set state(textState) 0
52     set state(curFont) ""
53     set state(startCode) "{\\b "
54     set state(startEmphasis) "{\\i "
55     set state(endCode) "}"
56     set state(endEmphasis) "}"
57     set state(noFill) 0
58     set state(charCnt) 0
59     set state(offset) [getTwips 0.5i]
60     set state(leftMargin) [getTwips 0.5i]
61     set state(nestingLevel) 0
62     set state(intl) 0
63     set state(sb) 0
64     setTabs 0.5i
65
66 # set up international character table
67
68     array set chars {
69         o^ F4
70     }
71 }
72
73
74 # beginFont --
75 #
76 # Arranges for future text to use a special font, rather than
77 # the default paragraph font.
78 #
79 # Arguments:
80 # font -                Name of new font to use.
81
82 proc beginFont {font} {
83     global file state
84
85     textSetup
86     if {[string equal $state(curFont) $font]} {
87         return
88     }
89     endFont
90     puts -nonewline $file $state(start$font)
91     set state(curFont) $font
92 }
93
94
95 # endFont --
96 #
97 # Reverts to the default font for the paragraph type.
98 #
99 # Arguments:
100 # None.
101
102 proc endFont {} {
103     global state file
104
105     if {[string compare $state(curFont) ""]} {
106         puts -nonewline $file $state(end$state(curFont))
107         set state(curFont) ""
108     }
109 }
110
111
112 # textSetup --
113 #
114 # This procedure is called the first time that text is output for a
115 # paragraph.  It outputs the header information for the paragraph.
116 #
117 # Arguments:
118 # None.
119
120 proc textSetup {} {
121     global file state
122
123     if $state(breakPending) {
124         puts $file "\\line"
125     }
126     if $state(paragraphPending) {
127         puts $file [format "\\par\n\\pard\\fi%.0f\\li%.0f" \
128                         $state(firstIndent) $state(leftIndent)]
129         foreach tab $state(tabs) {
130             puts $file [format "\\tx%.0f" $tab]
131         }
132         set state(tabs) {}
133         if {$state(sb)} {
134             puts $file "\\sb$state(sb)"
135             set state(sb) 0
136         }
137     }
138     set state(breakPending) 0
139     set state(paragraphPending) 0
140 }
141
142
143 # text --
144 #
145 # This procedure adds text to the current state(paragraph).  If this is
146 # the first text in the state(paragraph) then header information for the
147 # state(paragraph) is output before the text.
148 #
149 # Arguments:
150 # string -              Text to output in the state(paragraph).
151
152 proc text {string} {
153     global file state chars
154
155     textSetup
156     set string [string map [list \
157             "\\"        "\\\\" \
158             "\{"        "\\\{" \
159             "\}"        "\\\}" \
160             "\t"        {\tab } \
161             ''          "\\rdblquote " \
162             ``          "\\ldblquote " \
163             ] $string]
164
165     # Check if this is the beginning of an international character string.
166     # If so, look up the sequence in the chars table and substitute the
167     # appropriate hex value.
168
169     if {$state(intl)} {
170         if {[regexp {^'([^']*)'} $string dummy ch]} {
171             if {[info exists chars($ch)]} {
172                 regsub {^'[^']*'} $string "\\\\'$chars($ch)" string
173             } else {
174                 puts stderr "Unknown international character '$ch'"
175             }
176         }
177         set state(intl) 0
178     }
179
180     switch $state(textState) {
181         REF { 
182             if {$state(inTP) == 0} {
183                 set string [insertRef $string]
184             }
185         }
186         SEE { 
187             global topics curPkg curSect
188             foreach i [split $string] {
189                 if {![regexp -nocase {^[a-z_0-9]+} [string trim $i] i ]} {
190                     continue
191                 }
192                 if {![catch {set ref $topics($curPkg,$curSect,$i)} ]} {
193                     regsub $i $string [link $i $ref] string
194                 }
195             }
196         }
197         KEY {
198             return
199         }
200     }
201     puts -nonewline $file "$string"
202 }
203
204
205
206 # insertRef --
207 #
208 # This procedure looks for a string in the cross reference table and
209 # generates a hot-link to the appropriate topic.  Tries to find the
210 # nearest reference in the manual.
211 #
212 # Arguments:
213 # string -              Text to output in the state(paragraph).
214
215 proc insertRef {string} {
216     global NAME_file curPkg curSect topics curID
217     set path {}
218     set string [string trim $string]
219     set ref {}
220     if {[info exists topics($curPkg,$curSect,$string)]} {
221         set ref $topics($curPkg,$curSect,$string)
222     } else {
223         set sites [array names topics "$curPkg,*,$string"]
224         set count [llength $sites]
225         if {$count > 0} {
226             set ref $topics([lindex $sites 0])
227         } else {
228             set sites [array names topics "*,*,$string"]
229             set count [llength $sites]
230             if {$count > 0} {
231                 set ref $topics([lindex $sites 0])
232             }
233         }
234     }
235
236     if {($ref != {}) && ($ref != $curID)} {
237         set string [link $string $ref]
238     }
239     return $string
240 }
241
242
243
244 # macro --
245 #
246 # This procedure is invoked to process macro invocations that start
247 # with "." (instead of ').
248 #
249 # Arguments:
250 # name -                The name of the macro (without the ".").
251 # args -                Any additional arguments to the macro.
252
253 proc macro {name args} {
254     global state file
255     switch $name {
256         AP {
257             if {[llength $args] != 3 && [llength $args] != 2} {
258                 puts stderr "Bad .AP macro: .$name [join $args " "]"
259             }
260             newPara 3.75i -3.75i
261             setTabs {1.25i 2.5i 3.75i}
262             font B
263             text [lindex $args 0]
264             tab
265             font I
266             text [lindex $args 1]
267             tab
268             font R
269             if {[llength $args] == 3} {
270                 text "([lindex $args 2])"
271             }
272             tab
273         }
274         AS {
275             # next page and previous page
276         }
277         br {
278             lineBreak   
279         }
280         BS {}
281         BE {}
282         CE {
283             puts -nonewline $::file "\\f0\\fs20 "
284             set state(noFill) 0
285             set state(breakPending) 0
286             newPara ""
287             set state(leftIndent) [expr {$state(leftIndent) - $state(offset)}]
288             set state(sb) 80
289         }
290         CS {
291             # code section
292             set state(noFill) 1
293             newPara ""
294             set state(leftIndent) [expr {$state(leftIndent) + $state(offset)}]
295             set state(sb) 80
296             puts -nonewline $::file "\\f1\\fs18 "
297         }
298         DE {
299             set state(noFill) 0
300             decrNestingLevel
301             newPara 0i
302         }
303         DS {
304             set state(noFill) 1
305             incrNestingLevel
306             newPara 0i
307         }
308         fi {
309             set state(noFill) 0
310         }
311         IP {
312             IPmacro $args
313         }
314         LP {
315             newPara 0i
316             set state(sb) 80
317         }
318         ne {
319         }
320         nf {
321             set state(noFill) 1
322         }
323         OP {
324             if {[llength $args] != 3} {
325                 puts stderr "Bad .OP macro: .$name [join $args " "]"
326             }
327             set state(nestingLevel) 0
328             newPara 0i
329             set state(sb) 120
330             setTabs 4c
331             text "Command-Line Name:"
332             tab
333             font B
334             set x [lindex $args 0]
335             regsub -all {\\-} $x - x
336             text $x
337             lineBreak
338             font R
339             text "Database Name:"
340             tab
341             font B
342             text [lindex $args 1]
343             lineBreak
344             font R
345             text "Database Class:"
346             tab
347             font B
348             text [lindex $args 2]
349             font R
350             set state(inTP) 0
351             newPara 0.5i
352             set state(sb) 80
353         }
354         PP {
355             newPara 0i
356             set state(sb) 120
357         }
358         RE {
359             decrNestingLevel
360         }
361         RS {
362             incrNestingLevel
363         }
364         SE {
365             font R
366             set state(noFill) 0
367             set state(nestingLevel) 0
368             newPara 0i
369             text "See the "
370             font B
371             set temp $state(textState)
372             set state(textState) REF
373             text options
374             set state(textState) $temp
375             font R
376             text " manual entry for detailed descriptions of the above options."
377         }
378         SH {
379             SHmacro $args
380         }
381         SO {
382             SHmacro "STANDARD OPTIONS"
383             set state(nestingLevel) 0
384             newPara 0i
385             setTabs {4c 8c 12c}
386             font B
387             set state(noFill) 1
388         }
389         so {
390             if {$args != "man.macros"} {
391                 puts stderr "Unknown macro: .$name [join $args " "]"
392             }
393         }
394         sp {                                    ;# needs work
395             if {$args == ""} {
396                 set count 1
397             } else {
398                 set count [lindex $args 0]
399             }
400             while {$count > 0} {
401                 lineBreak
402                 incr count -1
403             }
404         }
405         ta {
406             setTabs $args
407         }
408         TH {
409             THmacro $args
410         }
411         TP {
412             TPmacro $args
413         }
414         UL {                                    ;# underline
415             puts -nonewline $file "{\\ul "
416             text [lindex $args 0]
417             puts -nonewline $file "}"
418             if {[llength $args] == 2} {
419                 text [lindex $args 1]
420             }
421         }
422         VE {}
423         VS {}
424         default {
425             puts stderr "Unknown macro: .$name [join $args " "]"
426         }
427     }
428 }
429
430
431 # link --
432 #
433 # This procedure returns the string for  a hot link to a different
434 # context location.
435 #
436 # Arguments:
437 # label -               String to display in hot-spot.
438 # id -                  Context string to jump to.
439
440 proc link {label id} {
441     return "{\\uldb $label}{\\v $id}"
442 }
443
444
445 # font --
446 #
447 # This procedure is invoked to handle font changes in the text
448 # being output.
449 #
450 # Arguments:
451 # type -                Type of font: R, I, B, or S.
452
453 proc font {type} {
454     global state
455     switch $type {
456         P -
457         R {
458             endFont
459             if {$state(textState) == "REF"} {
460                 set state(textState) INSERT
461             }
462         }
463         C -
464         B {
465             beginFont Code
466             if {$state(textState) == "INSERT"} {
467                 set state(textState) REF
468             }
469         }
470         I {
471             beginFont Emphasis
472         }
473         S {
474         }
475         default {
476             puts stderr "Unknown font: $type"
477         }
478     }
479 }
480
481
482
483 # formattedText --
484 #
485 # Insert a text string that may also have \fB-style font changes
486 # and a few other backslash sequences in it.
487 #
488 # Arguments:
489 # text -                Text to insert.
490
491 proc formattedText {text} {
492     global chars
493
494     while {$text != ""} {
495         set index [string first \\ $text]
496         if {$index < 0} {
497             text $text
498             return
499         }
500         text [string range $text 0 [expr {$index-1}]]
501         set c [string index $text [expr {$index+1}]]
502         switch -- $c {
503             f {
504                 font [string index $text [expr {$index+2}]]
505                 set text [string range $text [expr {$index+3}] end]
506             }
507             e {
508                 text "\\"
509                 set text [string range $text [expr {$index+2}] end]
510             }
511             - {
512                 dash
513                 set text [string range $text [expr {$index+2}] end]
514             }
515             | {
516                 set text [string range $text [expr {$index+2}] end]
517             }
518             o {
519                 text "\\'"
520                 regexp {'([^']*)'(.*)} $text all ch text
521                 text $chars($ch)
522             }
523             default {
524                 puts stderr "Unknown sequence: \\$c"
525                 set text [string range $text [expr {$index+2}] end]
526             }
527         }
528     }
529 }
530
531
532 # dash --
533 #
534 # This procedure is invoked to handle dash characters ("\-" in
535 # troff).  It outputs a special dash character.
536 #
537 # Arguments:
538 # None.
539
540 proc dash {} {
541     global state
542     if {[string equal $state(textState) "NAME"]} {
543         set state(textState) 0
544     }
545     text "-"
546 }
547
548
549 # tab --
550 #
551 # This procedure is invoked to handle tabs in the troff input.
552 # Right now it does nothing.
553 #
554 # Arguments:
555 # None.
556
557 proc tab {} {
558     global file
559
560     textSetup
561     puts -nonewline $file "\\tab "
562 }
563
564
565 # setTabs --
566 #
567 # This procedure handles the ".ta" macro, which sets tab stops.
568 #
569 # Arguments:
570 # tabList -     List of tab stops, each consisting of a number
571 #                       followed by "i" (inch) or "c" (cm).
572
573 proc setTabs {tabList} {
574     global file state
575
576     set state(tabs) {}
577     foreach arg $tabList {
578         set distance [expr {$state(leftMargin) \
579                 + ($state(offset) * $state(nestingLevel)) + [getTwips $arg]}]
580         lappend state(tabs) [expr {round($distance)}]
581     }
582 }
583
584
585
586 # lineBreak --
587 #
588 # Generates a line break in the HTML output.
589 #
590 # Arguments:
591 # None.
592
593 proc lineBreak {} {
594     global state
595     textSetup
596     set state(breakPending) 1
597 }
598
599
600
601 # newline --
602 #
603 # This procedure is invoked to handle newlines in the troff input.
604 # It outputs either a space character or a newline character, depending
605 # on fill mode.
606 #
607 # Arguments:
608 # None.
609
610 proc newline {} {
611     global state
612
613     if {$state(inTP)} {
614         set state(inTP) 0
615         lineBreak
616     } elseif {$state(noFill)} {
617         lineBreak
618     } else {
619         text " "
620     }
621 }
622
623
624 # pageBreak --
625 #
626 # This procedure is invoked to generate a page break.
627 #
628 # Arguments:
629 # None.
630
631 proc pageBreak {} {
632     global file curVer
633     if {[string equal $curVer ""]} {
634         puts $file {\page}
635     } else {
636         puts $file {\par}
637         puts $file {\pard\sb400\qc}
638         puts $file "Last change: $curVer\\page"
639     }
640 }
641
642
643 # char --
644 #
645 # This procedure is called to handle a special character.
646 #
647 # Arguments:
648 # name -                Special character named in troff \x or \(xx construct.
649
650 proc char {name} {
651     global file state
652
653     switch -exact $name {
654         \\o {
655             set state(intl) 1
656         }
657         \\\  {
658             textSetup
659             puts -nonewline $file " "
660         }
661         \\0 {
662             textSetup
663             puts -nonewline $file " \\emspace "
664         }
665         \\\\ {
666             textSetup
667             puts -nonewline $file "\\\\"
668         }
669         \\(+- {
670             textSetup
671             puts -nonewline $file "\\'b1 "
672         }
673         \\% -
674         \\| {
675         }
676         \\(bu {
677             textSetup
678             puts -nonewline $file "·"
679         }
680         default {
681             puts stderr "Unknown character: $name"
682         }
683     }
684 }
685
686
687 # macro2 --
688 #
689 # This procedure handles macros that are invoked with a leading "'"
690 # character instead of space.  Right now it just generates an
691 # error diagnostic.
692 #
693 # Arguments:
694 # name -                The name of the macro (without the ".").
695 # args -                Any additional arguments to the macro.
696
697 proc macro2 {name args} {
698     puts stderr "Unknown macro: '$name [join $args " "]"
699 }
700
701
702
703 # SHmacro --
704 #
705 # Subsection head; handles the .SH macro.
706 #
707 # Arguments:
708 # name -                Section name.
709
710 proc SHmacro {argList} {
711     global file state
712
713     set args [join $argList " "]
714     if {[llength $argList] < 1} {
715         puts stderr "Bad .SH macro: .SH $args"
716     }
717
718     # control what the text proc does with text
719     
720     switch $args {
721         NAME {set state(textState) NAME}
722         DESCRIPTION {set state(textState) INSERT}
723         INTRODUCTION {set state(textState) INSERT}
724         "WIDGET-SPECIFIC OPTIONS" {set state(textState) INSERT}
725         "SEE ALSO" {set state(textState) SEE}
726         KEYWORDS {set state(textState) KEY; return}
727     }
728
729     if {$state(breakPending) != -1} {
730         set state(breakPending) 1
731     } else {
732         set state(breakPending) 0
733     }
734     set state(noFill) 0
735     nextPara 0i
736     font B
737     text $args
738     font R
739     nextPara .5i
740 }
741
742
743
744 # IPmacro --
745 #
746 # This procedure is invoked to handle ".IP" macros, which may take any
747 # of the following forms:
748 #
749 # .IP [1]                       Translate to a "1Step" state(paragraph).
750 # .IP [x] (x > 1)       Translate to a "Step" state(paragraph).
751 # .IP                           Translate to a "Bullet" state(paragraph).
752 # .IP text count        Translate to a FirstBody state(paragraph) with special
753 #                                       indent and tab stop based on "count", and tab after
754 #                                       "text".
755 #
756 # Arguments:
757 # argList -             List of arguments to the .IP macro.
758 #
759 # HTML limitations: 'count' in '.IP text count' is ignored.
760
761 proc IPmacro {argList} {
762     global file state
763
764     set length [llength $argList]
765     if {$length == 0} {
766         newPara 0.5i
767         return
768     }
769     if {$length == 1} {
770         newPara 0.5i -0.5i
771         set state(sb) 80
772         setTabs 0.5i
773         formattedText [lindex $argList 0]
774         tab
775         return
776     }
777     if {$length == 2} {
778         set count [lindex $argList 1]
779         set tab [expr $count * 0.1]i
780         newPara $tab -$tab
781         set state(sb) 80
782         setTabs $tab
783         formattedText [lindex $argList 0]
784         tab
785         return
786     }
787     puts stderr "Bad .IP macro: .IP [join $argList " "]"
788 }
789
790
791 # TPmacro --
792 #
793 # This procedure is invoked to handle ".TP" macros, which may take any
794 # of the following forms:
795 #
796 # .TP x         Translate to an state(indent)ed state(paragraph) with the
797 #                       specified state(indent) (in 100 twip units).
798 # .TP           Translate to an state(indent)ed state(paragraph) with
799 #                       default state(indent).
800 #
801 # Arguments:
802 # argList -             List of arguments to the .IP macro.
803 #
804 # HTML limitations: 'x' in '.TP x' is ignored.
805
806 proc TPmacro {argList} {
807     global state
808     set length [llength $argList]
809     if {$length == 0} {
810         set val 0.5i
811     } else {
812         set val [expr {([lindex $argList 0] * 100.0)/1440}]i
813     }
814     newPara $val -$val
815     setTabs $val
816     set state(inTP) 1
817     set state(sb) 120
818 }
819
820
821 # THmacro --
822 #
823 # This procedure handles the .TH macro.  It generates the non-scrolling
824 # header section for a given man page, and enters information into the
825 # table of contents.  The .TH macro has the following form:
826 #
827 # .TH name section date footer header
828 #
829 # Arguments:
830 # argList -             List of arguments to the .TH macro.
831
832 proc THmacro {argList} {
833     global file curPkg curSect curID id_keywords state curVer bitmap
834
835     if {[llength $argList] != 5} {
836         set args [join $argList " "]
837         puts stderr "Bad .TH macro: .TH $args"
838     }
839     incr curID
840     set name    [lindex $argList 0]             ;# Tcl_UpVar
841     set page    [lindex $argList 1]             ;# 3
842     set curVer  [lindex $argList 2]             ;# 7.4
843     set curPkg  [lindex $argList 3]             ;# Tcl
844     set curSect [lindex $argList 4]             ;# {Tcl Library Procedures}
845     
846     regsub -all {\\ } $curSect { } curSect      ;# Clean up for [incr\ Tcl]
847
848     puts $file "#{\\footnote $curID}"           ;# Context string
849     puts $file "\${\\footnote $name}"           ;# Topic title
850     set browse "${curSect}${name}"
851     regsub -all {[ _-]} $browse {} browse
852     puts $file "+{\\footnote $browse}"          ;# Browse sequence
853
854     # Suppress duplicates
855     foreach i $id_keywords($curID) {
856         set keys($i) 1
857     }
858     foreach i [array names keys] {
859         set i [string trim $i]
860         if {[string length $i] > 0} {
861             puts $file "K{\\footnote $i}"       ;# Keyword strings
862         }
863     }
864     unset keys
865     puts $file "\\pard\\tx3000\\sb100\\sa100\\fs24\\keepn"
866     font B
867     text $name
868     tab
869     text $curSect
870     font R
871     if {[info exists bitmap]} {
872         # a right justified bitmap
873         puts $file "\\\{bmrt $bitmap\\\}"
874     }
875     puts $file "\\fs20"
876     set state(breakPending) -1
877 }
878
879 # nextPara --
880 #
881 # Set the indents for a new paragraph, and start a paragraph break
882 #
883 # Arguments:
884 # leftIndent -          The new left margin for body lines.
885 # firstIndent -         The offset from the left margin for the first line.
886
887 proc nextPara {leftIndent {firstIndent 0i}} {
888     global state
889     set state(leftIndent) [getTwips $leftIndent]
890     set state(firstIndent) [getTwips $firstIndent]
891     set state(paragraphPending) 1
892 }
893
894
895 # newPara --
896 #
897 # This procedure sets the left and hanging state(indent)s for a line.
898 # State(Indent)s are specified in units of inches or centimeters, and are
899 # relative to the current nesting level and left margin.
900 #
901 # Arguments:
902 # leftState(Indent) -           The new left margin for lines after the first.
903 # firstState(Indent) -          The new left margin for the first line of a state(paragraph).
904
905 proc newPara {leftIndent {firstIndent 0i}} {
906     global state file
907     if $state(paragraph) {
908         puts -nonewline $file "\\line\n"
909     }
910     if {$leftIndent != ""} {
911         set state(leftIndent) [expr {$state(leftMargin) \
912                 + ($state(offset) * $state(nestingLevel)) \
913                 + [getTwips $leftIndent]}]
914     }
915     set state(firstIndent) [getTwips $firstIndent]
916     set state(paragraphPending) 1
917 }
918
919
920 # getTwips --
921 #
922 # This procedure converts a distance in inches or centimeters into
923 # twips (1/1440 of an inch).
924 #
925 # Arguments:
926 # arg -                 A number followed by "i" or "c"
927
928 proc getTwips {arg} {
929     if {[scan $arg "%f%s" distance units] != 2} {
930         puts stderr "bad distance \"$arg\""
931         return 0
932     }
933     switch -- $units {
934         c       {
935             set distance [expr {$distance * 567}]
936         }
937         i       {
938             set distance [expr {$distance * 1440}]
939         }
940         default {
941             puts stderr "bad units in distance \"$arg\""
942             continue
943         }
944     }
945     return $distance
946 }
947
948 # incrNestingLevel --
949 #
950 # This procedure does the work of the .RS macro, which increments
951 # the number of state(indent)ations that affect things like .PP.
952 #
953 # Arguments:
954 # None.
955
956 proc incrNestingLevel {} {
957     global state
958
959     incr state(nestingLevel)
960     set oldp $state(paragraph)
961     set state(paragraph) 0
962     newPara 0i
963     set state(paragraph) $oldp
964 }
965
966 # decrNestingLevel --
967 #
968 # This procedure does the work of the .RE macro, which decrements
969 # the number of indentations that affect things like .PP.
970 #
971 # Arguments:
972 # None.
973
974 proc decrNestingLevel {} {
975     global state
976     
977     if {$state(nestingLevel) == 0} {
978         puts stderr "Nesting level decremented below 0"
979     } else {
980         incr state(nestingLevel) -1
981     }
982 }
983