[Richard Suchenwirth] 2006-04-26 - A question on [comp.lang.tcl] brought me to experiment with code that rewrites itself. The idea is that settings are not saved in a separate resource file, but in the script itself, as setting a global variable with the desired value. So the next time the script is run, the previously saved setting applies. Here's what I did: proc save {filename varlist} { set f [open $filename] set data [read $f] close $f set lines {} foreach line [split $data \n] { foreach var $varlist { if [regexp "^ *set $var " $line] { set line [list set $var [set ::$var]] } } lappend lines $line } set f [open $filename w] puts $f [join $lines \n] close $f } #-- Now for a testing demo: package require Tk #-- We will test with this variable: set foo hello label .1 -text foo: entry .2 -textvar foo button .3 -text Save -command [list save [info script] foo] eval pack [winfo children .] -side left #-- Invaluable little helper for rapid restart: bind . {exec wish $argv0 &; exit} ---- [lexfiend] 2006-04-27 - Here's a modification that places all the state variables in a single section, so that [[save]] doesn't inadvertantly overwrite other [[set]]s of the state variables and thereby change the program logic. However, note that this forces you to pre-initialize any namespaces on which the state variables depend. # Create empty namespaces first namespace eval testns {} ### VARIABLE SAVE SECTION set test1 "I am here" set testns::test2 "Here as well" ### VARIABLE SAVE SECTION proc save {filename varlist} { set f [open $filename] set data [read $f] close $f set lines {} set inSaveSection 0 foreach line [split $data \n] { if [regexp "^ *#+ *VARIABLE SAVE SECTION" $line] { if {!$inSaveSection} { # Start of save section lappend lines "### VARIABLE SAVE SECTION" foreach var $varlist { lappend lines [list set $var [set ::$var]] } set inSaveSection 1 } else { # End of save section lappend lines "### VARIABLE SAVE SECTION" set inSaveSection 0 } } elseif {$inSaveSection} { # Somewhere in save section - do nothing } else { lappend lines $line } } set f [open $filename w] puts $f [join $lines \n] close $f } set testns::test2 "Gone forever" set test1 "Not here now" save [info script] {test1 testns::test2} ---- [EMJ] - 2006-04-26 - Aaaaargh! Self-modifying code, the slippery slope to certain unmaintainability! That of course is a remark from the distant past, when clever people wrote very fast but generally incomprehensible self-modifying assembly language. The warning is still valid, however - be careful! For the stated purpose, it's not actually too bad, but I think I would use an alias or something rather than just set, in order to make the regex more discriminating. I guess it's simply the reverse of what [tkbiff] does, writing most of its code to its config file! [IL] - This kind of stuff always makes me think of DNA, the assembly of the organic life. I suppose that makes tRNA the compiler and proteins the executable... heh. ---- [Category Example] - [Arts and crafts of Tcl-Tk programming]