+#!/opt/ActiveTcl-8.6/bin/tclsh
+# Hey Emacs, use -*- Tcl -*- mode
+set scriptname [file rootname $argv0]
+# ---------------------- Command line parsing -------------------------
+set usage "usage: [file tail $argv0] \[options] filename"
+ array set params [::cmdline::getoptions argv $options $usage]
+} trap {CMDLINE USAGE} {msg o} {
+ # Trap the usage signal, print the message, and exit the application.
+ # Note: Other errors are not caught and passed through to higher levels!
+# After cmdline is done, argv will point to the last argument
+if {[llength $argv] == 1} {
+ puts [cmdline::usage $options $usage]
+proc read_file {filename} {
+ # Return a list of lines from an input file
+ # The file consists of capacitance measurements.
+ if { [catch {open $filename r} fid] } {
+ puts "Could not open file $filename"
+ set datafile_list [split [read $fid] "\n"]
+proc get_drill_diameters {raw_line_list} {
+ # Returns a dictionary of (tool code) : (tool diameter)
+ # raw_line_list -- List of lines from a NC drill file
+ set tool_diameter_dict [dict create]
+ foreach line $raw_line_list {
+ if {[string first % $line] == 0} {
+ # This is the start of the data section
+ if {[string first T $line] == 0} {
+ # This is a tool code line
+ set linelist [split $line C]
+ set toolcode [lindex $linelist 0]
+ set diameter [lindex $linelist 1]
+ dict set tool_diameter_dict $toolcode $diameter
+ return $tool_diameter_dict
+proc get_drill_units {raw_line_list} {
+ # Returns either inch or mm for the drill diameter units
+ # raw_line_list -- List of lines from a NC drill file
+ foreach line $raw_line_list {
+ if {[string first % $line] == 0} {
+ # This is the start of the data section
+ if {[string first INCH $line] == 0} {
+ # The dimensions are in inches
+ if {[string equal $units none]} {
+ # We could not determine the units
+ puts "Error -- could not determine drill diameter units"
+proc init_drill_count_dict {drill_diameter_dict} {
+ # Return an initialized dictionary of (tool code) : (tool count)
+ # drill_diameter_dict -- Dictionary of (tool code) : (tool diameter)
+ set drill_count_dict [dict create]
+ foreach tool [dict keys $drill_diameter_dict] {
+ dict set drill_count_dict $tool 0
+ return $drill_count_dict
+proc update_drill_count {drill_count_dict raw_line_list} {
+ # Return an updated dictionary of (tool code) : (tool count)
+ # drill_count_dict -- Dictionary of (tool code) : (tool count)
+ # raw_line_list -- List of lines from a NC drill file
+ foreach line $raw_line_list {
+ if {[string first % $line] == 0} {
+ # This is the start of the data section
+ if {[string first T $line] == 0 && $data_started} {
+ # This is the start of a new tool section
+ if {[string first X $line] == 0 && ![string equal $current_tool none]} {
+ # This is a new drill location
+ dict incr drill_count_dict $current_tool
+ return $drill_count_dict
+proc write_drill_table {drill_diameter_dict drill_count_dict drill_units} {
+ # Write a pipe-delimited drill table
+ set drill_diameter_dict [lsort -stride 2 -index 1 -real $drill_diameter_dict]
+ set separator "|-[string repeat - $tool_width]-"
+ append separator "+-[string repeat - $size_width]-"
+ append separator "+-[string repeat - $count_width]-|"
+ puts [format "| %-*s | %-*s | %-*s | " \
+ $size_width "Hole size ($drill_units)" \
+ foreach tool [dict keys $drill_diameter_dict] {
+ puts [format "| %-*s | %-*s | %-*s | " $tool_width $tool \
+ $size_width [dict get $drill_diameter_dict $tool] \
+ $count_width [dict get $drill_count_dict $tool]
+# Start processing the file
+set raw_line_list [read_file $datafile]
+set drill_diameter_dict [get_drill_diameters $raw_line_list]
+set drill_count_dict [init_drill_count_dict $drill_diameter_dict]
+set drill_units [get_drill_units $raw_line_list]
+set drill_count_dict [update_drill_count $drill_count_dict $raw_line_list]
+write_drill_table $drill_diameter_dict $drill_count_dict $drill_units