-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfinddup.tcl
executable file
·148 lines (118 loc) · 2.39 KB
/
finddup.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/tclsh
proc dir_iterator {path} {
set contents [glob -nocomplain $path/*]
return [list 0 $contents]
}
proc dir_next {p_it} {
upvar $p_it it
lset it 0 [expr {[lindex $it 0] + 1}]
}
proc dir_is_end {it} {
set fi [lindex $it 0]
return [expr { [lindex [lindex $it 1] $fi] == "" } ]
}
proc dir_at {it} {
return [lindex [lindex $it 1] [lindex $it 0]]
}
proc stack_push {st val} {
upvar $st stack
lappend stack $val
}
proc stack_size {st} { return [llength $st] }
proc stack_pop {st} {
upvar $st stack
if { [stack_size $stack] == 0 } {
error "Popping empty stack!"
}
set val [lindex $stack end]
set stack [lrange $stack 0 end-1]
return $val
}
proc machine_init {path} {
variable current
variable state
variable before
set state NEXT
set current [dir_iterator $path]
set before {} ;# empty stack
}
proc restate { val } {
set ::state $val
}
# Main machine executive
proc next_file {} {
variable current
variable state
variable before
#puts "Current: $current"
#puts "State: $state"
#puts "Before: $before"
while 1 {
switch $state {
FILE {
restate NEXT
set path [dir_at $current]
dir_next current
return [list [file size $path] $path]
}
NEXT {
if { [dir_is_end $current] } {
restate END
} else {
set path [dir_at $current]
if { [file isdirectory $path] } {
restate DIR
} else {
restate FILE
}
}
}
DIR {
stack_push before $current
set current [dir_iterator [dir_at $current]]
restate SUB
}
SUB {
if { [dir_is_end $current] } {
restate END
} else {
set path [dir_at $current]
if { [file isdirectory $path] } {
restate DIR
} else {
restate FILE
}
}
}
END {
if { [stack_size $before] == 0 } {
return { 0 "" }
}
set current [stack_pop before]
dir_next current
restate NEXT
}
}
}
}
set arg [lindex $argv 0]
if { ![file isdirectory $arg] } {
puts "$arg: not a directory"
exit 1
}
machine_init $arg
array set map {}
while 1 {
set sn [next_file]
set size [lindex $sn 0]
set name [lindex $sn 1]
if { $name == "" } {
break
}
lappend map($size) $name
}
foreach {size files} [array get map] {
if { [llength $files] > 1 } {
puts "$size: $files"
}
}