Hog Hog2024.2-4
reformat.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # Copyright 2018-2024 The University of Birmingham
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 # @file
17 # Format a .tcl file
18 
19 proc reformat {tclcode {pad 2}} {
20 
21  set lines [split $tclcode \n]
22  set out ""
23  set nquot 0 ;# count of quotes
24  set ncont 0 ;# count of continued strings
25  set line [lindex $lines 0]
26  set indent [expr {([string length $line]-[string length [string trimleft $line \ \t]])/$pad}]
27  set padst [string repeat " " $pad]
28  foreach orig $lines {
29  incr lineindex
30  if {$lineindex>1} {append out \n}
31  set newline [string trimleft $orig]
32  if {$newline==""} continue
33  set is_quoted $nquot
34  set is_continued $ncont
35  if {[string index $orig end] eq "\\"} {
36  incr ncont
37  } else {
38  set ncont 0
39  }
40  if { [string index $newline 0]=="#" } {
41  set line $orig ;# don't touch comments
42  } else {
43  set npad [expr {$indent * $pad}]
44  set line [string repeat $padst $indent]$newline
45  set i [set ns [set nl [set nr [set body 0]]]]
46  for {set n [string length $newline]} {$i<$n} {incr i} {
47  set ch [string index $newline $i]
48  if {$ch=="\\"} {
49  set ns [expr {[incr ns] % 2}]
50  } elseif {!$ns} {
51  if {$ch=="\""} {
52  set nquot [expr {[incr nquot] % 2}]
53  } elseif {!$nquot} {
54  switch $ch {
55  "\{" {
56  if {[string range $newline $i $i+2]=="\{\"\}"} {
57  incr i 2 ;# quote in braces - correct (though tricky)
58  } else {
59  incr nl
60  set body -1
61  }
62  }
63  "\}" {
64  incr nr
65  set body 0
66  }
67  }
68  }
69  } else {
70  set ns 0
71  }
72  }
73  set nbbraces [expr {$nl - $nr}]
74  incr totalbraces $nbbraces
75  if {$totalbraces<0} {
76  error "Line $lineindex: unbalanced braces!"
77  }
78  incr indent $nbbraces
79  if {$nbbraces==0} { set nbbraces $body }
80  if {$is_quoted || $is_continued} {
81  set line $orig ;# don't touch quoted and continued strings
82  } else {
83  set np [expr {- $nbbraces * $pad}]
84  if {$np>$npad} { ;# for safety too
85  set np $npad
86  }
87  set line [string range $line $np end]
88  }
89  }
90  append out $line
91  }
92  return $out
93 }
94 
95 proc eol {} {
96  switch -- $::tcl_platform(platform) {
97  windows {return \r\n}
98  unix {return \n}
99  macintosh {return \r}
100  default {error "no such platform: $::tc_platform(platform)"}
101  }
102 }
103 
104 proc count {string char} {
105  set count 0
106  while {[set idx [string first $char $string]]>=0} {
107  set backslashes 0
108  set nidx $idx
109  while {[string equal [string index $string [incr nidx -1]] \\]} {
110  incr backslashes
111  }
112  if {$backslashes % 2 == 0} {
113  incr count
114  }
115  set string [string range $string [incr idx] end]
116  }
117  return $count
118 }
119 
120 #parsing command options
121 if {[catch {package require cmdline} ERROR]} {
122  puts "$ERROR\n If you are running this script on tclsh, you can fix this by installing 'tcllib'"
123  return
124 }
125 
126 set parameters {
127  {tab_width.arg 2 "Width of the indentation tabs. Default: "}
128 }
129 
130 set usage "- USAGE: $::argv0 \[OPTIONS\] <tcl_file> \n. Options:"
131 set old_path [pwd]
132 set path [file normalize "[file dirname [info script]]/.."]
133 source $path/hog.tcl
134 
135 if {[catch {array set options [cmdline::getoptions ::argv $parameters $usage]}] || [llength $argv] < 1 } {
136  Msg Info [cmdline::usage $parameters $usage]
137  exit 1
138 } else {
139  set indent $options(tab_width)
140  set f [open $argv r]
141  set data [read $f]
142  close $f
143  set permissions [file attributes $argv -permissions]
144 
145  set filename "$argv.tmp"
146  set f [open $filename w]
147 
148  puts -nonewline $f [reformat [string map [list [eol] \n] $data] $indent]
149  close $f
150  file copy -force $filename $argv
151  file delete -force $filename
152  file attributes $argv -permissions $permissions
153 }