TclX has some useful line-by-line file-scanning commands: scancontext, scanmatch and scanfile. Here's an implementation of them in pure Tcl:
namespace eval scancontext { namespace export * } proc scancontext::scancontext {cmd args} { switch -- $cmd { "create" { uplevel 1 { set __scan 0 while {1} { incr __scan variable scancontext$__scan if {![array exists scancontext$__scan]} { break } } set scancontext[set __scan]() 1 return scancontext$__scan } } "delete" { variable [lindex $args 0] unset [lindex $args 0] } } } proc scancontext::scanmatch {scanid regexp script args} { if {[string match "-*" $scanid]} { set flags $scanid set scanid $regexp set regexp [list $flags $script] set script [lindex $args 0] } else { set regexp [list -- $regexp] } variable $scanid set ${scanid}($regexp) $script return $scanid } proc scancontext::scanfile {scanid fid} { variable $scanid upvar matchInfo m set m(linenum) 0 set m(offset) 0 set m(handle) $fid set names [array names $scanid] while {[set count [gets $fid m(line)]] >= 0} { incr m(linenum) incr m(offset) [expr {$count +1}] foreach reg $names { if {$reg == ""} {continue} if {[regexp [lindex $reg 0] [lindex $reg 1] $m(line) \ "" m(submatch0) m(submatch1) m(submatch2)]} { incr m(offset) [expr {-[string length $m(submatch0)]}] uplevel 1 [set ${scanid}($reg)] incr m(offset) [string length $m(submatch0)] } } } } namespace import scancontext::*
AlphaTcl uses the scanXXX commands to scan for uses of proc when building tclIndex files (unlike the standard auto_mkindex, which mostly sources files and sees which commands get defined), and has very similar emulation code for the commands should TclX not be available: http://alphatcl.cvs.sourceforge.net/alphatcl/Tcl/SystemCode/Init/rebuilding.tcl?view=log