#<20240518.1943.11>
# AddConf does most of the writting of the configure file with all the comments.
#
# parameters:
#    fid      The file to 'put' to
#    var_var  The name of the variable we are to write instructions to set.
#             If var_var is a list e.g. {config menu,*} it is used to get 
#             an array of entries to set up. In this case, all config(menu,*)
#             entries.
#    setto    is a flag with values 
#             ""  -> single line set statment
#             1   -> print one line per each level entry in the list
#             2   -> print one line per first rest on second line
#             doubles -> print 2 elements per line
#             3 -> print 'set var {' caller to complete...
#    expl     This is the comment to be printed prior to the set statment.
#             If not empty, a line of "-----" is first printed to seperate 
#             the text from the prior entry in the file.
#
proc AddConf { fid var_var setto expl } {
  global glob config 
  if { $expl != "" } {
    # Lets turn this into a nice header...
    set hName " [regsub {config} $var_var {}] "
    # center in a 70 char line...
    set ln [string length $hName]
    set line "[string repeat "-" [expr {(70 - $ln) / 2}]]`{B $hName}``{fill -}`"
    putsTrim $fid $line
    putsTrim $fid $expl 
  }
  if {![info exists $var_var] && \
	  [lassign $var_var arrayname pattern] == {} &&\
	  [catch {array get $arrayname $pattern} varList] == 0} {
    # Check for something like {config menu,*}
    # Yep, break that up...
    set var_var {}
    foreach {ent dum} $varList {
      lappend var_var ${arrayname}($ent)
    }
  }
#    puts "$var_var"
  foreach val $var_var {
    #  upvar $var_var var
    if {[catch {upvar $val var}] == 0} {
      AddConfPutVar
    } else {
      puts $fid "\n Seems to be a serious problem finding \"$var\", skipping"
    }
  }
}


proc AddConfPutVar {} {
  uplevel {
    puts  -nonewline $fid "set $val"
    if { $setto == "" } {
      puts $fid " [list $var]"
    } elseif {$setto == "doubles"} {
      puts $fid " \{"
      foreach {first second} $var {
	puts $fid "    [list $first] [list $second]"
      }
      puts $fid "  \}"
    } elseif { $setto == "1" || $setto == "2"} {
      # make single line per first level entry
      puts $fid " \{"
      foreach kk $var {
	puts -nonewline $fid "    "
	if {$setto == "2"} {
	  puts $fid "[list $kk]"
	} else {
	  if {[set t [llength $kk]] != 1} {
	    puts -nonewline $fid "\{"
	  }
	  set in 0
	  foreach k $kk {
	    if {$in > 0} {
	      puts -nonewline $fid "\n        "
	    } 
	    puts -nonewline $fid "[list $k]"
	    incr in
	  }
	  if {$t != 1} {
	    puts $fid "\}"
	  } else {
	    puts $fid ""
	  }
	}
      }
      puts $fid "  \}\n"
    } else {
      puts -nonewline $fid " \{"
    }
    puts $fid ""
  }
}

proc ClearTheDecksHereComeANewConfig {} {
  global glob config
  # A call to this proc is in the front end of the config file.
  # What we need to do is eliminate any old stuff that it may not
  # overlay.  Mostly this will be array entries that have been eliminated.

  # Eliminate the old bind array so we don't pop it up after the user tried
  # to deep six it....
  # Also for the user buttons...
  array unset config bind*
  array unset config userButton,*
  array unset config menu,*

  set glob(savedButtonColors) {}
  # clear old overstrike and set up a new one
  # This will force a new parsing of the overstrike options (see about.tcl)
  catch {namespace delete overstrike}
  namespace eval overstrike {
    variable ::overstrike::boldOps
    variable ::overstrike::italicOps
  }
}

# Here we set up a refected channel so we can use the puts output
# to provide the browser window contents.
# cb is a callback function that we send the strings to.

proc reflectConfig {cb mode hand args} {
  switch $mode {
    watch      - 
    finalize   {return}
    initialize {
      return {write watch initialize finalize}
    }
    write      {
      $cb {*}$args
      return [string length {*}$args]
    }
  }
}

# and here is a proc to build it as needed

proc buildConfigLines {toFile} {
  global config env glob
  if {$toFile} {
    putsTrimSpace::init noComs
    # choose a save name...
    set tryFile $glob(configFile)
    set times 0
    while {[file exists $tryFile]} {
      set tryFile "$glob(configFile).part$times"
      # puts "try $tryFile"
      incr times
    }

    set r [catch {open $tryFile w} fid]
    if {$r != 0} { PopError "Saving config: $fid"; return "" }

    puts $fid "# Generated by FileRunner $::glob(displayVersion) on\
     \n# [clock format [clock seconds]]\n"
    set rtn [list $fid $tryFile]
  } else {
    putsTrimSpace::init
    set fid [chan create write {reflectConfig configCallBack}]
    set ::tmp {}
    set rtn $fid
  }
  # On entry we transfered all of config(gui*) to glob(gui,*) where gui*
  # was either guiE,* or gui,* depending of being elevated (E). This allows
  # a different 'LOOK' for E runs vs normal. Here we need to copy glob(gui,*)
  # back to the proper place.
  if {$glob(init_done)} {
    if {$::Elevated} {
      set pat "guiE"
    } else {
      set pat "gui"
    }
    foreach {lab ent} [array get glob gui,*] {
      lassign [split $lab ,] d val
      set config($pat,$val) $ent
    }
  }
  # initialize the line length
  set inotFm [expr {$::MSW ? "doubles" : ""}]
  foreach ent $::fr_config::RightSideConfig {
    eval $ent
  }
  return $rtn
}
    
proc SaveConfig {}  {
  global glob config env
  # lassign [getOldNewVersions] oldv newv
  if {![info exist glob(configFile)]} {
    # too early
    puts "reject early save"
    return
  }
  lassign [buildConfigLines 1] fid fileName
  puts $fid "\nreturn"
  close $fid

  if {$fileName != $glob(configFile)} {
    file rename -force $fileName $glob(configFile)
  }
  
  Log [_ "Configuration saved to %s" $glob(configFile)]
}

proc setDefaultConfig {} {
  global glob config env argv tcl_platform fast_checkboxes
  #########################################################################
  #
  #             Fast check boxes
  #
  #########################################################################
  # Each entry consist of a label, the "-command", the variable (may be a 
  # list i.e. {variable on-value off-value}) and the balloon help message

  # This is the master entry. The first entry in config(fast_checkboxes)
  # must match one of these. If not, during set up, that entry will be
  # removed from config(fast_checkboxes) and a message sent to the user.
  # If one (or more) of these is not in config(fast_checkboxes) it will
  # be quietly added at that time.
  #
  set fast_checkboxes {
    {{Expand Errors} "setupDebug \$glob(debug)" glob(debug) \
	 {[_b "Toggles expanded error messages"]}}
    {{Balloon Help} {preSetBalloon} \
	 config(balloonhelp) \
	 {[_b "Toggles the Balloon Help feature (what you are looking at)." ]}}
    {{Position to directories} {} config(positiondirs)\
	 {[_b "Toggles the directory vs file positioning for characters typed \
             in a directory panel"]}}
    {{Show All Files} ForceUpdate config(fileshow,all) \
	 {[_b "Toggles the show all files flag.\nIf\
            off 'hidden' files are not showen." ] }}
    {{Run Pwd After Cd} {} config(cd_pwd) \
	 {[_b "Toggles the do pwd after cd flag" ]}}
    {{Focus Follows Mouse} {after 1 "if {$config(focusFollowsMouse)== 1} \
                         {tk_focusFollowsMouse} "} \
	 config(focusFollowsMouse) \
	 {[_b "Toggles Focus Follows Mouse flag.\nTakes\
                effect immeadiatly if turned on. \nRequires\
                restart if turned off." ]}}
    {{Run Pwd After Cd (FTP)} {} config(ftp,cd_pwd) \
	 {[_b "Toggles the do pwd on FTP directroies after cd flag" ]}}
    {{Use FTP Proxy} {} config(ftp,useproxy) \
	 {[_b "Toggles the FTP Proxy flag.  If set use Proxy." ]}}
    {{No case on sort} {ForceUpdate} {config(sortoption) -nocase -ascii}\
	 {[_b "Sets the sort option to \"no case\".\
             \nOff sets \"ASCII\"." ]}}
    {{Dictionary sort} {ForceUpdate} {config(sortoption) -dictionary -ascii}\
	 {[_b "Sets the sort option to \"Dictionary\".\
             \n Off sets \"ASCII\"." ]}}
    {{Sort on aTime} { ForceUpdate} {config(fileshow,sort) atime nameonly}\
	 {[_b "Sets the sort option to \"Sort On aTime\".\
             \n Off sets \"Sort on Name\"." ]}}
    {{Sort on Reverse aTime} {ForceUpdate} {config(fileshow,sort) ratime nameonly}\
	 {[_b "Sets the sort option to \"Sort On Reverse aTime\".\
             \nOff sets \"Sort on Name\"." ]}}
    {{Sort on cTime} {ForceUpdate} {config(fileshow,sort) ctime nameonly}\
	 {[_b "Sets the sort option to \"Sort On cTime\".\
             \n Off sets \"Sort on Name\"." ]}}
    {{Sort on Reverse cTime} {ForceUpdate} {config(fileshow,sort) rctime nameonly}\
	 {[_b "Sets the sort option to \"Sort On Reverse cTime\".\
             \nOff sets \"Sort on Name\"." ]}}
    {{Sort on mTime} {ForceUpdate} {config(fileshow,sort) mtime nameonly}\
	 {[_b "Sets the sort option to \"Sort On mTime\".\
             \n Off sets \"Sort on Name\"." ]}}
    {{Sort on Reverse mTime} {ForceUpdate} {config(fileshow,sort) rmtime nameonly}\
	 {[_b "Sets the sort option to \"Sort On Reverse mTime\".\
             \nOff sets \"Sort on Name\"." ]}}
    {{Sort on Size} {ForceUpdate} {config(fileshow,sort) size nameonly}\
	 {[_b "Sets the sort option to \"Sort On Size\".\
             \nOff sets \"Sort on Name\"." ]}}
    {{Sort on Extension} {ForceUpdate} {config(fileshow,sort) extension nameonly}\
	 {[_b "Sets the sort option to \"Sort On Extension\".\
             \nOff sets \"Sort on Name\"." ]}}
    {{Ask on File Delete} {} ::config(ask,file_delete) \
	 {[_b "On will ask premission to\ndelete files."]}}
    {{Ask on Directory Delete} {} ::config(ask,dir_delete) \
	 {[_b "On will ask premission to\ndelete directory trees."]}}
    {{Ask on Delete} {set ::config(ask,dir_delete) \
			  [set ::config(ask,file_delete) $::askOnDelVar] } \
	 {askOnDelVar 1 0 0} {[_b "On will ask premission to\
             \ndelete files and directories\
             \n(combines the two config options)"]}}
  }
  
  if  {!$::MSW} {
    lappend fast_checkboxes \
	{{Create Relative Links} {} config(create_relative_links)\
	     {[_b "Toggles the create relative links flag" ]}}
  }

  #  puts "in InitConfig"
  global glob config env argv tcl_platform
  set glob(TraceColToEnabled) 0
  if {$::MSW} {
    set config(hotlist) [list [list -volume [file volume ]]]
  } else {
    set config(hotlist) ""
  }
  set config(runlist) {}
  set config(balloonhelp) 0
  set config(fileshow,all) 0
  set config(fileshow,sort) "nameonly"
  set config(fileshow,dirs) "dirsfirst"
  set config(columnScroll) 1
  set config(columnScrollSize) 8
  set config(positiondirs) 0
  set config(startpwd,left) ""
  set config(startpwd,right) ""
  set config(search,limit) 25
  set config(search,ViewEditStrings) {}
  set config(search,CmdConfStrings) {}
  
  if {$::MSW} {
    set config(focusFollowsMouse) 0
    set config(DisplayName) {{} <volume>}
    set config(DisplayNameShare) {format "%s(\\\\%s)(%s)" $share $server $drive}
    set config(cifs,shares) {}
  } else {
    set config(focusFollowsMouse) 1
    set config(DisplayName) {{} <volume>}
    set config(DisplayNameShare) {format "%s(\\\\%s)(%s)" $share $server $mp}
    # The "sizeinfo" list contains information on monitor workarea(s) and border
    # width. This is arranged by "display" which is the same as env(DISPLAY)
    # each known display consists of three parts: monitor(s) width height
    # where all numbers are in pixals and width & height are the combined
    # width of the side borders (width) and top & bottom borders (height).
    set config(monitors) [list [list $env(DISPLAY) [list monitors {} width 0 height 0]]]
  }
  set config(ask,dir_delete) "1"
  set config(ask,file_delete) "0"
  set config(ask,save_modified_file) "1"
  set config(ftp,fastlink) 0
  set config(ftp,proxy) ""
  set config(ftp,password) ""
  set config(ftp,timeout) "120"
  set config(ftp,useproxy) 1
  set config(ftp,login) {}
  set config(vfs,login) {}
  set config(passwordLocker) {}
  set config(vfs,cache,maxentries) 15
  set config(ftp,cd_pwd) 1
  set config(vfsII,config) {
    {{-use unarc
      -location $pwd
      -display  {Tar archive }
      -readonly  0}
      {*.tar.gz *.tar}
    }
    {{-mount {exec 7z x %s}
      -readonly 1
      -display {Zip Archive}
      -location $pwd}
      {*.msi *.exe *.zip *.gz}}
  }
  set config(rsync,table) {{{} {} shell -av {}}}
  set config(vfs,helptable) {}
  set config(http,proxy) {}
  #set config(gui,color_bg) FloralWhite
  set config(gray) "gray"
  set config(gui,color_bg) LemonChiffon
  set config(gui,color_fg) Black
  set config(gui,color_cmd) LightGoldenrod1
  set config(gui,color_select_bg) Yellow
  set config(gui,color_select_fg) black
  set config(gui,color_highlight_bg) white
  set config(gui,color_highlight_fg) red
  set config(gui,color_handle) red  
  set config(gui,color_scheme) "grey85"
  #set config(gui,color_scheme) {#bfeed0add9da}
  set config(gui,color_cursor) black
  set config(gui,color_flash) green
  set config(gui,color_balloonHelp_fg) yellow
  set config(gui,color_balloonHelp_bg) red
  set config(gui,GuiFont) TkDefaultFont

  set config(gui,ListBoxFont) TkFixedFont
  set config(gui,BalloonHelpFont) TkCaptionFont
  set config(overstrike,bold) {weight bold}
  set config(overstrike,italic) {slant italic}
  set config(overstrike,boldItalic) {slant italic weight bold}
  set config(overstrike,config) 1
 
  set config(ListBoxColumns,right) {
    {file 26   {[_ "File/Dir name" ]}}
    {size 7    {[_ "size" ]}}
    {mtime 15  {[_ "mtime" ]}}
    {owner 13  {[_ "owner" ]}} 
    {slink  26 {[_ "link to" ]}}
  }
  if {!$::MSW} {
    lappend config(ListBoxColumns,right) \
	{mode 9   {[_ "flags" ]}} \
	{links  3     {[_ "lk" ]}}
  } else {
      set config(useDIR) 0
  }
  set config(ListBoxColumns,left) $config(ListBoxColumns,right)

  set config(singleLineDisp) {}
  set config(hoverTime) 300
  
  set config(middle_button_colors) {
    { Delete -#ff4d4d }
  }
  foreach cmd $glob(cmds,list) {
    # We need the extra "list" to keep the middle button code from
    # thinking it may have a list longer than exactly 1
    lappend config(middle_button_list) [list [lindex $cmd 0]]
  }
  # The following gets filled in by the start up script...
  # The start up default is balloon help
  set config(fast_checkboxes) {
    {{Balloon Help} {Tool tips}                                y
      {Toggles the Balloon Help feature (what you are
       looking at).}}
  }
  set config(bind,[DarMou Button-3]) ViewOne
  set config(bind,[DarMou Control-3]) ViewDirOpposite
  set config(bind.Alt-1) PopupDir
  set config(bind,Alt-1) PopupListEntry
  set config(bine,[DarMou Alt-3]) PopupListDetail
  set config(bind,[DarMou Control-2]) {DoMenu,two}
  set config(bind,Double-1) Edit
  set config(global-bind,[DarMou Shift-3]) {DoMenu,two}
  set config(paste) [subst {
    {[DarMou <ButtonRelease-2>]}
    {<Control-Key-v>}
    {<Shift-Key-Insert>}
    {<Control-Lock-Key-V>}
  }]
   
  set config(bind,KeyPress-question) CmdWhatIs
  #
  # A menu to use with one of the bindings (user can build more)
  #
  set config(menu,sample) [list ViewOne Edit {} menu,two ViewDirOpposite]
  set config(menu,two) [concat {ViewOne} $config(middle_button_list)]
  set config(menu,three) {{{Send To} {CmdRunCmd 0}}}

  set config(no_selection) {ViewOne ViewDirOpposite}

  if {$::MSW} {
    set config(CB-paste) {{<Shift-ButtonRelease-2>}}
    set config(X-behave) 0
  }
  set config(space) {>sp<}
  set config(keyb_support) 0
  set config(dateformat) "yymmdd"
  set config(dateformatTop) "yymmdd"
  set config(autoupdate) 20
  set config(inotify_rate_limit) 2
  if {$::MSW} {
    set config(inotify_flags) {
      -access   0
      -attr     0
      -create   1
      -dirname  1
      -filename 1
      -size     1
      -write    1 }
    set config(inotify_nlflags) $config(inotify_flags)
  } else {
    set config(inotify_flags) "naCmMdw"
    set config(inotify_nlflags) ""
  }
  set config(logsize) 5000
  set config(check_ownership) 0
  set config(geometry,min) "fixed"
  set config(geometry,max) "fixed"
  set config(geometry,location) "random random"
  set config(geometry,main) "840x720+31+0"
  set config(geometry,mainops) "center"
  set config(geometry,textviewer) "80x30"
  set config(geometry,qedit) "80x30"
  set config(spellcheck,expect) 0
  set config(spellingFilter) {
    {None {}}
    {Comment(#&\") {qstrings {\" \"} "#"}}
    {C&C++Comments {qstrings {/* */} "//"}}
  }
  set config(shell,height,left) 10
  set config(shell,height,right) 10
  set config(shell,buffer) 1000
  set config(shell,aliases) {
    {.. {cd ..}} 
    {md mkdir} 
    {m view} 
    {more view} 
    {less view}
  }
  #
  # The helper list...
  set postfix [expr {$glob(cygwin) != {} ? ".exe" : ""}]
  set term xterm$postfix
  set editor "$term$postfix -e vi %s"
  set print "lpr %s"
  set diff "diff$postfix -r %s %s"
  set pack "gzip$postfix %s"
  set archive "tar+gz %s"

  set config(cmd,sh) "sh -c"
  set config(cmd,cp) "cp -pfr"
  set config(cmd,dircp) "cp -pfr"
  set config(cmd,hardlink) "cp -pfrl"
  set config(cmd,open) "xdg-open"
  set config(editor) "vi %s"
  set config(editor2) {emacsclient --no-wait -d $::env(DISPLAY) {%s}}
  set config(md5sum) {md5sum -c %s}

  if { $::MSW } {
    set config(cmd,open) {cmd /c start "started by fr"}
    set config(editor) "{C:/Program Files/Windows NT/Accessories/wordpad.exe} %s"
    if {[info exists env(CYGWIN)] == 0 } {
      # pure windows...
      set config(cmd,sh) "cmd /C"
      set config(cmd,cp) {}
      set config(cmd,dircp) {}
      set config(cmd,hardlink) {{fsutil hardlink create} {r}}
    } else {
      # windows with cygwin (NOT a cygwin version of tcl/tk but rather
      # cygwin is installed...
      # Use the non-windows defs...
    }
  } else {
    set config(manualMonitors) 1
  }
  if {[info exists env(EDITOR)]} {
    set config(editor) "$env(EDITOR) %s"
  }
  set config(cmd,chmod) "/bin/chmod$postfix"
  set config(cmd,chown) "/bin/chown$postfix"
  if {$postfix == "" && $::MSW} {
    set config(cmd,touch) {}
  } else {
    set config(cmd,touch) "touch$postfix"
  }
  set config(cmd,du) "du$postfix -s"
  set config(cmd,find) find$postfix

  if {!$::MSW} {
    set config(cmd,ucmd) {
      {Run fr as root}
      {exec echo [pwLocker::getPw $env(USER)] | sudo -HS fr $glob(left,pwd) $glob(right,pwd) &}
    }
  } else {
    set config(cmd,ucmd) {
      {Run fr elevated}
      {if {[namespace exists freewrap]} {
	frECF "twapi::shell_execute -path %s  -verb runas -params { %b }"\
	    [list $::argv0 $::glob(left,pwd) $::glob(right,pwd)]
      } else {
	frECF "twapi::shell_execute -path %s -verb runas -params { %b }"\
	    [list [info nameofex] [file norm $::argv0]\
		 $::glob(left,pwd) $::glob(right,pwd)]
      }
      }
    }
  }

  set config(globstar) 1
  if {$::MSW} {
    set config(expandWildCards) 1
    set config(cmd,rm) "twapi::recycle_file"
    set config(cmd,print) "twapi::shell_exec -verb print -path %s"
    set config(cmd,term)  "cmd.exe /c start"
  } else {
    set config(expandWildCards) 0
    set config(cmd,print) "lpr %s"
    if {$::tcl_platform(os) != "Darwin"} {
      set config(cmd,term) "Terminal"
    } else {
      set config(cmd,term) "xterm"
    }
    set config(cmd,rm) {}
  }
  set config(cmd,diff) "diff$postfix -r %s %s"
  set config(cmd,pack) "gzip$postfix %s"
  set config(cmd,archive) "tar+gz %s"
  
  set config(cmd,unarc,extensions) \
      [list \
	   [list  "gzip$postfix -cd %s | tar xfBp -" \
		{*.tgz *.taz *.tar.z *.tar.gz} ] \
	   [list "tar$postfix xfBp %s"\
		{*.tar} ]\
	   [list "unzip -oqq %s" \
		{*.zip} ]\
	   [list "lha$postfix -x %s" \
		{*.lha} ]\
	  ]
  
  set config(cmd,unpack,extensions) \
      [list \
	   [list "gzip$postfix -d %s" \
		{*.gz} ]\
	  ]
  set config(view,extensions) \
      [list \
	   [list "xmikmod$postfix %s" \
		{*.mod.gz *.s3m *.mtm *.stm *.xm *.uni *.mod} ]\
	   [list "timidity$postfix %s" \
		{*.midi.gz *.midi *.mid.gz *.mid} ]\
	   [list "xv$postfix -gamma 2.0 %s" \
		{ *.bmp *.iff *.jpg *.pbm *.pgm *.png \
		      *.ppm *.tga *.tif *.tiff *.xbm *.xpm *.gif} ]\
	   [list "gzip$postfix -dc %s | ghostview -" \
		{ *.ps.gz } ]\
	   [list "ghostview$postfix %s" \
		{ *.ps } ]\
	   [list "xanim$postfix %s" \
		{*.avi *.fli *.flc *.mpg} ]\
	   [list "gzip$postfix -cd %s | tar tvf -" \
		{ *.tgz *.taz *.tar.z *.tar.gz } \
		-viewtext ]\
	   [list "tar$postfix tvf %s" \
		{*.tar}\
		-viewtext ]\
	   [list "unzip$postfix -lv %s"\
		{*.zip}\
		-viewtext]\
	   [list "lha$postfix -v %s" \
		{*.lha}\
		-viewtext ]\
	   [list "gzip$postfix -cd %s"\
		{*.gz}\
		-viewtext ]\
	   [list "rpm$postfix -qilp %s"\
		{*.rpm}\
		-viewtext ]\
	   ]
  
  set config(open,extensions) {}
  if {$::MSW} {
    set config(open,extensions) [list "msiexec.exe /I %s" "*.msi"]
  }
  
  set config(mwheel,delta) 6
  set config(mwheel,neg) <4>
  set config(mwheel,pos) <5>
  set config(save_conf_at_exit) 1
  
 if {!$::MSW} {
    set config(create_relative_links) 1
  } else {
    set config(create_relative_links) 0
  }
  
  set config(cd_pwd) 1
  set config(sortoption) "-ascii"
  # Listbox column build scritps.  There should be one for each list box
  # column, by name.
  set config(ListBoxScripts) { 
    {ctime {expr {$ctime=="" ? "" : [GetTimeFromSecs $ctime]}}}
    {atime {expr {$atime=="" ? "" : [GetTimeFromSecs $atime]}}}
    {mtime {GetTimeFromSecs $mtime}}
    {file  {set ffile}}
    {mode  {set mode}}
    {owner {set usergroup}}
    {links {set nlink}}
    {size  {format %6s $size}}
    {slink {format %3s $link}}
    {blank {expr {""}}}
  }
  if {$::MSW } {
    lappend config(ListBoxScripts) {short {file attributes $file -shortname}} \
	{shortDIR {expr {"shortDir is obsolete"}}}
  }
}

proc InitConfig {} {
#  puts "in InitConfig"
  global glob config env argv tcl_platform
  setDefaultConfig
  set glob(df) df
  set glob(searchstring) ""
  set glob(log) ""
  set glob(history) ""
  foreach inst {left right} {
    set glob($inst,update_oldpwd) {} 
    set glob($inst,newpwd_oldpwd) {}
    set glob($inst,filelist) {}
    set glob($inst,pwd) {}
    set glob($inst,df) ?
    set glob($inst,dirstack) {}
    set glob($inst,shell,grided) 0
    set glob($inst,shell,history) {}
    set glob($inst,shell,complete,flipping) 0
    set glob($inst,shell,history,flipping) 0
    set glob($inst,shell,history,flipping,index) 0
    set glob($inst,shellcount) 0
    set glob(listbox,$inst) {}
  }
  set glob(abortcmd) 0
  set glob(toplevelidx) 0
  set glob(forceupdate) 0
  set glob(havedoneftp) 0
  set glob(enableautoupdate) 1
  set glob(shell,maxed) 0
  set glob(batchlist) {}
  # if {![file isdirectory $glob(tmpdir)]} {
  #   if {![file exists $glob(tmpdir)]} {
  #     set r [Try { file mkdir $glob(tmpdir) } "" 1]
  #     if {$r != 0} {
  # 	PopError [_ "Can't create %s. May be problems later" $glob(tmpdir)]
  #     }
  #   }
  # }	
  set glob(win,top) .fupper.ftop
  set glob(win,left) .fupper.fleft
  set glob(win,right) .fupper.fright
  set glob(win,middle) .fupper.can.fmiddle
  set glob(win,bottom) .flower

  set glob(winlist,color_xx) ""
  # These configuration have not been set yet, will be done in ReConfigColors
  # This picks up the initial set from setDefaultConfig
  array set glob [array get config gui*]
  set glob(async) 0

  foreach ev {USER USERNAME LOGNAME} {
    if {![info exists env($ev)]} { 
      continue 
    }
    if {"[string range $env($ev) 0 0][string range $env($ev) end end]" == \
	    "%%" } {
      if {[string equal -nocase $ev "USER" ]} {
	unset env(USER)
      }
      continue
    }
    set env(USER) $env($ev)
    break
  }
  if {![info exists env(USER)]} { 
    if {![info exists env(HOME)]} {
      PopInfo [_ "Cannot read environment variables\
                  USER or USERNAME or LOGNAME or HOME.\
                  \nFileRunner cannot work without HOME and \
                  \n one of USER or USERNAME or LOGNAME correctly set."]
      CleanUp 1
    } else {
      set env(USER) [file tail $env(HOME)]
      PopInfo [_ "Environment variables 'USER' ane 'USERNAME' are undefined.\
                 \nDefaulting to $env(USER).\
                 \nTo stop this error report each time you\
                  run filerunner define environment variable\
                  'USER' or 'USERNAME'."]
    }
  }
  
  if {![info exists env(HOST)]} {
    if {![info exist env(COMPUTERNAME)] } {
      set env(HOST) unknown
    } else {
      set env(HOST) $env(COMPUTERNAME)
    }
  }
  if {$env(HOST) == "unknown"} {
    set r [catch { exec uname -n } out]
    if {!$r} {
      set env(HOST) $out
    }
  }

  # read history from disk
  if { [file exists $glob(conf_dir)/history ] } {
    set r [catch {set fid [open $glob(conf_dir)/history r]
      gets $fid glob(history)
      close $fid} out]
    if {$r == 0} {
      set r [catch {llength $glob(history)} out]
    }
    if {$r} {
      puts [_ "FileRunner: Either can't read directory history or \
                  \nit is corrupt: \n$out\n Clearing histroy."]
      set glob(history) {}
    }
  }

  # set up a few default options
  #  option add *HighlightThickness 1 widgetDefault
  option add *InsertWidth           2 widgetDefault
  option add *Scrollbar.Width      11 widgetDefault
  option add *Button.BorderWidth    1 widgetDefault
  option add *Scrollbar.BorderWidth 2 widgetDefault

  option add *Frame.BorderWidth     2 widgetDefault
  option add *Entry.BorderWidth     2 widgetDefault
  option add *Font                  TkDefaultFont widgetDefault
}

proc ReadConfig {{re 0}} {
  set mess {}
  global glob glob config env argv argv0 tcl_platform
  set glob(select_pry_lr) {}
  lassign [getOldNewVersions] oldv newv

  # Here is where we set up a separate config file for instances where fr is run
  # from a link with a different name. In such cases we name the config file
  # config-$name-revdate. We except common variants... 

  set runName [file tail $argv0]
  foreach exception [list \
			 tclsh* \
			 wish* \
			 fr.tcl \
			 fr-$newv-32.exe \
			 fr-$newv-64.exe \
			] {
    if {[string match $exception $runName]} {
      set runName "fr"
      break
    }
  }
  
  set oRoot $glob(configFileRoot)
  if {$runName != "fr" && ![string match "*-$runName" $glob(configFileRoot)]} {
    set glob(configFileRoot) $glob(configFileRoot)-$runName
  }
  
  set desired $glob(configFileRoot)-$newv
  
  set trying $desired
  while {$trying != {} && [set sourceError [safeReadConfig $trying]] != "0"} {
    puts "$sourceError [winfo exists .error_dialog]"
    Log "Error trying to read user configuration from '$sourceError'."

    # why not.. 1 does not exist, 2 is not readable, 3 is corrupt
    # 1 find older one.. and move, else, do nothing
    # 2 attempt rename , ok, do 1, fail-> giveup
    # 3 do 2

    if {![file readable $trying]} {
      # ok, does it exist?
      if {[file exists $trying]} {
        # Yes, attempt to rename it
        set nrtime "nr[clock format [clock seconds] -format %Y%m%d%H%M%S]"
        Log "Renaming $trying to ${trying}.$nrtime"
        puts "Renaming $trying to ${trying}.$nrtime"
        if {[catch {file rename $desired ${trying}.$nrtime} er] != 0} {
          # Rename failed.. we MUST insist...
          Log "Rename of $trying to ${trying}.$nrtime failed with $er"
          puts "Rename of $trying to ${trying}.$nrtime failed with $er"
          puts "The file '$trying' must be made readable or removed."
          puts "We are done!"
          exit 1
        }
      }
      # Look for an older possibility...
         
      Log "Config file $trying not found & readable."
      set m \[0-9\]
      cd $glob(conf_dir)
      # This should find all our old (and newer) configuration files...
      foreach filePat [list $glob(configFileRoot) $oRoot] {
        set pos \
            [lsort -decreasing \
                 [glob -nocomplain -types {f r w} \
                      [file tail ${filePat}]-\[1-2\]$m$m$m$m$m ]]
        # on a new system or user there will be NO file...
        set trying {}
        foreach try $pos {
          # here we insure that what we use is from an older rev and not a newer
          set rv [string range $glob(conf_dir)/$try end-5 end]
          # puts "$glob(conf_dir)/$try >$rv >$newv"
          if {[string compare $rv $newv] != 1} {
            set trying $glob(conf_dir)/$try
            Log "Trying config file '$trying'"
            break
          }
        }
        if {$trying != {} || $glob(configFileRoot) == $oRoot} {
          break
        }
      }
    }
  }
  set glob(configFile) $desired
  if {$trying != $desired} {
    if {$trying != {}} {
      Log "Found Config file $trying. Moving to \"$desired\"."
    } else {
      Log "No Config file found."
      Log "Creating \"As shipped\" Config file \"$desired\"."
    }
    SaveConfig
  }

  startProc "After read config file"
  if {$glob(cygwin) != {}} {
    # make sure df is properly named.
    set ops [FilenameComplete df 1]
    if {[lindex $ops 0] == {}} {
      # found df exact
      set glob(df) df
    } else {
      set idx [lsearch -glob $ops ".exe*"]
      if {$idx != -1} {
	set glob(df) df[lindex $ops $idx]
      } else {
	set glob(df) {}
      }
    }
  }
  set ::spSTRING $config(space)
  # if this is a reload, remove the ones we saved
  # and then add what we just read.
  if {$glob(init_done)} {
    foreach {dir name} $savedDNs {
      delDN $name
    }
  }
  ::pwLocker::init ::config(passwordLocker) \
      [list encrypt $::env(USER)] \
      [list decrypt $::env(USER)] \
      [list SaveConfig]
 # encrypt any open text passwords
  FixPasswords
  FixHotList
  FixFileNative
  # passWordToDN
  
  # We are about to re do the dir listing windows
  # First we must prevent the inotify code from updating while
  # The window isn't
  foreach inst {left right} {
    if {[info exists glob(inotify_after,$inst)] && \
	    $glob(inotify_after,$inst) != {}} {
      catch {after cancel $glob(inotify_after,$inst)}
    }
    set glob(inotify_after,$inst) "no"
    ClearCherryPicker $inst
  }
    
  catch {destroy $glob(win,left).frame_listb}
  catch {destroy $glob(win,right).frame_listb}
  if {$config(ftp,password) == "" } {
    set r [catch {set config(ftp,password) "$env(USER)@[exec domainname]"}]
  }
  # force a rebuild of the runlist
  if {[info exists glob(runMenu)]} {
    destroy $glob(runMenu)
  }
  ################################ carry ftp logins over to vfs logins
  set messx {}
  ## set messx [update17.04.19]
  if {$messx != {}} {
    LogSilent $messx
  }
  lappend ::mess {*}$messx
  ###########################  end carry ftp logins over to vfs logins
  # Set up the GUI variables, either guiE,* (::Elevated true) or gui,*
  if {$::Elevated} {  frputs config(passwordLocker)

    foreach {name value} [array get config guiE,*] {
      lassign [split $name ,] gu nname
      set glob(gui,$nname) $value
    }
  } else {
    array set glob [array get config gui,*]
  }
  # build the listbox script array
  foreach val $config(ListBoxScripts) {
    lassign $val name script
    set glob(lbscript,$name) $script
  }
  foreach k { left right } {
    #    puts "$config(ListBoxColumns,$k)"
    foreach ent $config(ListBoxColumns,$k) {
      lappend glob(listboxNames) [lindex $ent 0]
    }
  }
  #  puts "$glob(listboxNames)"
  set glob(listboxNames) [lsort -unique $glob(listboxNames)]
  foreach inst {left right} {
    foreach lbname $glob(listboxNames) {
      set glob($inst,lv$lbname) {}
    }
    if { !$glob(init_done)} {
      # A safe initial directory to get things started
 	NewPwd $inst ~/
    }
  }
  if {$glob(notify,Available)} {
    set glob(inotify_flags) $config(inotify_flags)
  }
  if { $config(ftp,proxy) == "" } {
    set config(ftp,useproxy) 0
  }
  if { [info exists config(focusFollowsMouse)] == 1 } {
    if { $config(focusFollowsMouse) != 0 } {
      tk_focusFollowsMouse
    }
  }
  if {$::MSW} {
    set config(create_relative_links) 0
  } else {
    array set ::displays::monitors [list monitors {} width 0 height 0]
    foreach mons $config(monitors) {
      array set monsa $mons
      if {[info exists monsa($::env(DISPLAY))]} {
	array set ::displays::monitors $monsa($::env(DISPLAY))
      }
    }
  }
  if { $config(dateformat) == "ddmmyy" } {
    GetTimeFromSecsSetFormat 1
  } elseif { $config(dateformat) == "yymmdd" } {
    GetTimeFromSecsSetFormat 0
  } else {
    GetTimeFromSecsSetFormat  $config(dateformat)
  }
  # set ::balloon_help::enable $config(balloonhelp)
  startProc "After post config fixes  "
  set deletedFCB [postConfigShow]
  # # We always do a save config here, just incase (after a config browser read,
  # # this puts the overstrike chars back in the config file)
  # SaveConfig
  startProc "After post config show "
  BuildListBoxes
  startProc "After post config list box build"
  InitWindows
  startProc "After post config init "
  #ForceUpdate
  # Allow the inotify code to do its thing again
  foreach inst {left right} {
    set glob(inotify_after,$inst) {}
  }
  # Here we do deleate the old global bindings
  
  foreach val [bind .] {
    catch {bind . <$val> {} }
  }
  # New bindings are done in 'InitBindings' (in fr)
  startProc "After post config update "
  InitBindings
  startProc "After InitBindings "
  if {$::MSW} {
    if {$config(CB-paste) != {}} {
      event delete <<Paste>>
      event add    <<Paste>> {*}$config(CB-paste)
    }
    if {$config(paste) != {}} {
      event delete <<PasteSelection>>
      event add    <<PasteSelection>> {*}$config(paste)
    }
  } else {
    if {$config(paste) != {}} {
      event delete <<Paste>>
      event add    <<Paste>> {*}$config(paste)
    }
  }
  startProc "After <<Paste>> set up"
  set glob(TraceColToEnabled) 1
  if {$config(ListBoxColumns,left) != $config(ListBoxColumns,right)} {
    TraceColTo left right
  }
  after 1 {passWordToDN}
  # if {$::MSW} {
  #   startProc "Before WSL find"
  #   ::findUNC::findWSLshares
  #   startProc "After WSL find"
  # }
  # Putting this here allows user config override
  foreach {dir name} $config(DisplayName) {
    if {[catch {addDN [list $dir $name]} mes] != 0} {
      if {[string index $mes 0] != "-"} {
	lappend ::mess [list "From addDN (add display name) $name" $mes]
      }
    }
  }
  Try {preSetBalloon} -a
  # We always do a save config here, just incase (after a config browser read,
  # this puts the overstrike chars back in the config file)
  # This also picks up the changes to the password locker (encript and on
  # MSW possible deletion of bad entries.
  startProc "Only save config left"
  
  SaveConfig
  startProc "After save config"
  return [list {*}$deletedFCB]
}
proc FixPasswords {} {
  if {[info exists config(vfs,login)]} {
    foreach ent $config(vfs,login) {
      if {$ent ni $config(passwordLocker)} {
	lappend config(passwordLocker) ent
      }
    }
  }
  # frputs ::config(passwordLocker)'
  FixThesePasswords config(passwordLocker) {1}
  # frputs ::config(passwordLocker)'
}
proc FixThesePasswords {location indx} {
  global config env
  # encrypt any open text passwords
  set new {}
  set i 0
  foreach login [set $location] {
    if {[lindex $login {*}$indx] == {} || \
	    ([lindex $login {*}$indx 0] == ">>" &&\
	    [lindex $login {*}$indx end] == "<<") } {
    } else {
      lset $location $i {*}$indx [encrypt $env(USER) [lindex $login {*}$indx]]
    }
    incr i
  }
}

# this command puts each entry in the password locker that has a mount point
# in the Display Name, provided the flag allows. It returns a list of mount
# points that are put in the "Display Name" but flagged not to be not put in the
# "HotList". 

proc passWordToDN {} {
 
  set newpw {}
  if {[catch {setUpShare} ms] != 0} {
    set ms [list $ms]
    if {$ms != {}} {
      doDeferedMessages $ms
    }
  }
  return 
}



# We no longer want or need [file native construct] in the configuration file
# Here we carefully remove any that we find. We require:
#  "[<0-n spaces>file<1-n spaces>na<0-n of anything but space> <0-n of
#  anything but ]>]"

proc FixFileNative {} {
  global config
  set exp {\[\s*file\s+na[^\s]*( *[^\]]*)\]}
  foreach {ent value} [array get config] {
    if {[regsub -all $exp $value {\1} value]} {
      set config($ent) $value
    }
  }
}

# We fix the old "-" prefix entries...
proc FixHotList {} {
  global config
  set new {}
  foreach ent $config(hotlist) {
    if {[string index [lindex $ent 0] 0] == "-" && [lassign $ent label val] != {}} {
      lappend new [list $label [list {*}[lrange $ent 1 end]]]
    } else {
      lappend new $ent
    }
  }
  set config(hotlist) $new
}

proc ConfigPwd {} {
  global glob config env argv argv0
  # Normalize these just in case they are MS windows native names...
  set pwd(left) [file norm [lindex $argv 0]]
  set pwd(right) [file norm [lindex $argv 1]]
  foreach k { left right } {
    # allow various perversions on what we find...
    if {![file exists $pwd($k)] && $pwd($k) != {}} {
      # not a file or dir, does it lead with a dir?
      set pwd($k) [file dirname $pwd($k)]
    }
    if {![file exists $pwd($k)]} {
      # still not a file or dir, try the config name
      set pwd($k) $config(startpwd,$k)
    }
    if {![file exists $pwd($k)]} {
      # every thing failed, forget about it.
      #continue
      set pwd($k) $glob(start_path)
    }
    if {[file isdirectory $pwd($k)]} {
      # if it is a dir, just go there
      NewPwd $k $pwd($k)
      #UpdateWindow $k  
    } else {
      # if it is a full file name, go to that dir and highlight the file
      GotoFind $pwd($k) $pwd($k) $k
    }
  }
  AppendToDirHistory $glob(left,pwd)
  AppendToDirHistory $glob(right,pwd)
  set glob(left,dirstack) [list [list $glob(left,pwd) 0]]
  set glob(right,dirstack) [list [list $glob(right,pwd) 0]]
  UpdateWindow both
}

proc CheckConfigDir {} {
  global env glob

  if {! [file isdirectory $glob(conf_dir)]} {

    set r [catch [file mkdir $glob(conf_dir)] out]
    if {$r} {
      regsub -all {\\} $out {/} out
      PopInfo "$out"
      exit 1
    }
  }
  set glob(configFileRoot) $glob(conf_dir)/config$glob(cygwin)
}



proc ConfigBrowser {} {
  global glob config
  # lassign [getOldNewVersions] oldv newv

  if {![file exists $glob(configFile)]} { SaveConfig }
  set w .config_dialog
  if {[winfo exists $w]} {
    wm geo $w [wm geo .]
    wm deiconify $w
    #  PopWarn "Configuration window already open!"
    return
  }
  # Fill left frame with contents
  set cdl {}
  set width 0
  foreach k [::fr_config::getLeftSide] {
    if {[lindex $k 1] != {}} {
      lappend cdl [string toupper [lindex $k 0]]
    } else {
      set tmp [split $k ,_]
      set tmp2 {}
      foreach t $tmp {
	if {$t != {}} {
	  append tmp2 " " [string totitle $t]
	}       
      }
      if {[set prune [string last "Gui Color " $tmp2]] != -1} {
        set tmp2 [string range $tmp2 $prune+9 end]
      }
      lappend cdl " $tmp2"
    }
  }
  foreach ent $cdl {
    set width [expr {max($width,[string length $ent])}]
  }
  toplevel $w -class Dialog
  wm title $w "$glob(orgTitle) Configuration Browser"
  wm iconname $w "FR config browser"
  wm resizable $w true true
  wm transient $w [winfo toplevel [winfo parent $w]]

  frame $w.left
  frame $w.right
  frame $w.bot
  
  # Create left frame containing the list of config options
  scrollbar $w.left.scrollvert -command "$w.left.list yview" -orient vertical 
  listbox $w.left.list \
      -yscrollcommand "$w.left.scrollvert set" \
      -font $glob(gui,ListBoxFont) \
      -width $width \
      -height 40 
  grid  $w.left.list       -row 0 -column 1 -sticky news
  grid  $w.left.scrollvert -row 0 -column 2 -sticky news
  grid columnconfig $w.left 1 -weight 1
  grid rowconfig    $w.left 0 -weight 1
  # Create right frame containing the config text and a scrollbar
  text $w.right.text\
      -relief sunken \
      -bd 2 \
      -yscrollcommand "$w.right.scroll set" \
      -wrap word\
      -undo 1 \
      -font $glob(gui,ListBoxFont)\
      -highlightthickness 0 
  scrollbar $w.right.scroll -command "$w.right.text yview" 
  grid  $w.right.text   -row 3 -column 1 -sticky news
  grid  $w.right.scroll -row 3 -column 2 -sticky news
  grid columnconfig $w.right 1 -weight 1
  grid rowconfig    $w.right 3 -weight 1
  

  # Create bottom frame containing the OK/Cancel buttons
  button $w.bot.regen \
      -text {Readjust Line Lengths Above}  \
      -command "ConfigBrowserRegenerate $w.right.text $w.left.list"
  button $w.bot.ok -text OK -command "ConfigBrowserOK $w.right.text $w"
  button $w.bot.cancel \
      -text Cancel  \
      -command "set glob(config_dialog_return) {}; destroy $w"
  grid $w.bot.regen  -row 0 -column 1 -sticky nes
  grid $w.bot.ok     -row 0 -column 2 -sticky news
  grid $w.bot.cancel -row 0 -column 3 -sticky nws
  grid columnconfig $w.bot {1 3} -weight 1
  # Fill left frame with contents
  foreach ent $cdl {
    $w.left.list insert end $ent
  }

  # Create popup menu
  textSearch $w.right.text [_ "Cfg edit"] "+buildViewConfig CmdConfStrings" {} \
      [list \
      [_ "Undo"] [list ? "undoHelp $w.right.text undo" -accelerator C-z]\
      [_ "Redo"] [list ? "undoHelp $w.right.text redo" -accelerator C-Z]\
      {Test current} "ConfigTest \[$w.right.text index insert\]" \
      {Test All}    "ConfigTest All" \
      [_ "Save As..."] [list ? [list SaveToFile $w.right.text {} 1] \
			      -accelerator C-S]
      ]
  
  grid $w.left -row 1 -column 1 -sticky news
  grid $w.right -row 1 -column 2 -sticky news
  grid $w.bot -row 3 -column 1 -columnspan 3 -sticky news
  grid rowconfig $w 1 -weight 1
  grid columnconfig $w 2 -weight 1
  # Assign bindings
  bind $w.right.text $config(mwheel,neg) \
      "$w.right.text yview scroll -$config(mwheel,delta) units;break"
  bind $w.right.text $config(mwheel,pos) \
      "$w.right.text yview scroll $config(mwheel,delta) units;break"
  bind $w.left.list $config(mwheel,neg) \
      "$w.left.list yview scroll -$config(mwheel,delta) units;break"
  bind $w.left.list $config(mwheel,pos) \
      "$w.left.list yview scroll $config(mwheel,delta) units;break"
  bind $w.left.list <1> \
      "ConfigBrowserJumpToLoc $w.right.text \[$w.left.list nearest %y\]"
  #wm withdraw $w
  #  realWaitForIdle
  #  realWaitForIdle
  centerWin $w
  wm geo $w [set mwSize [wm geo .]]
  # Need to figure and set the width here
  # The 5 below has to do with borders and scroll bars...
  
  set nw [expr {([string length $::putsTrimSpace::preamble] + \
                     $::putsTrimSpace::length +\
                     $::fr_config::leftMax + 5) *\
                    [font measure $::glob(gui,ListBoxFont) " "]}]
  lassign [split $mwSize x+] -> oh
  wm geo $w ${nw}x$oh
  wm deiconify $w

  set fid [buildConfigLines 0]
  close $fid

  # set string [read -nonewline $fid]
  # carrage returns mess up the ability to edit the lines...
  fillTextWindow $w.right.text [regsub {\r} ::tmp {}]
#  unset ::tmp
  $w.right.text edit reset
  $w.right.text mark set insert 0.0
  $w.right.text see insert
}

proc configCallBack {bytes} {
  append ::tmp $bytes
}

# The idea here is to test the statement to see if it is error free
# Either "All" or at insert mark.  It is an error if the insert mark
# is not on a line with a "set" in it.

proc ConfigTest {what args} {
  set w .config_dialog.right.text
  # we keep config as a local var so the result is NOT written to the global
  # The following separates our config from the main.
  set config(0) {}
  lassign [split [$w index end] .] max ch
  if {$what != "All"} {
    lassign [split $what .] line char
  } else {
    set line 1
    set lines {}
  }
  set end [expr {$line + 1}].0
  set text [$w get $line.0 $end]
  if {$what != "All" &&\
	  ([string index [string trim $line] 0] == "#" || \
	       ![string match {set config(*} $text] ) } {
    $w tag add sel $line.0 $end
    PPopWarn "Line does not start with \"set config\""
    return
  }
  # Ok, here we will accumulate lines until we find another "set" or "#"
  while {$line < $max} {
    while {$line < $max && \
               ([string index \
                     [set tText\
                          [string trim\
                               [set text\
                                    [$w get $line.0 [expr {$line +1}].0]]]] 0] == "#" ||\
		  ![string match {set config(*} $tText])} {
      # this is comment or white space
      incr line
    }
    # eof?
    $w tag add sel $line.0 $end
    set startLine $line
    incr line
    if {$line >= $max} {
      if {$args == {}} {
	PPopWarn [_ "Looks good."]
      }
      return $lines
    }
    set stmt $text
    while {$line < $max && \
	       [string index \
		    [set tText\
                         [string trim\
                              [set text\
                                   [$w get $line.0 [expr $line + 1].0]]]] 0] != "#" && \
	       ! [string match {set config(*} $tText] && \
	       $tText != {}} {
      append stmt $text
      incr line  
    }
    #$w tag remove sel 0.0 end
    $w tag add sel $startLine.0 $line.0
    set r [catch "eval {$stmt}" rt]
    # puts "Testing: $stmt"
    set mid [expr {($startLine + $line) / 2}].0
    if {$r != 0} {
      $w see 1.0
      $w see $mid
      frputs stmt rt "==[array get config]<< "
      PopWarn "$::errorInfo"
      return 0
    }
    if {$what != "All"} {

      $w see 1.0
      $w see $mid
      frputs stmt
      frputs rt
      frputs "==[array get config]<< "
      PPopWarn [_ "Looks good."]
      return 
    }
    append lines $stmt
    $w tag remove sel 0.0 end
  }
  PPopWarn [_ "Looks good."]
  return $lines
  
}

# pop window up over the left side of the config window
proc PPopWarn {info} {
  smart_dialog .apop[incr ::uni] .config_dialog.left [_ "Info"] [list $info] 0 1 [_ "OK"]

}

proc ConfigBrowserJumpToLoc {w index} {
  global glob config
  set tmp [lindex [fr_config::getLeftSide] $index]
  set op {}
  # Only headings have length > 1
  if {[set searchfor [lindex $tmp 1]] != {}} {
    set heading 1
  } else {
    if {[string index $tmp end] == ","} {
      set searchfor config\\([string range $tmp 0 end-1].*\\)
      set op -regexp
    } else {
      set searchfor config($tmp)
    }
    set heading 0
  }

  set tag select
  $w tag configure $tag\
      -background $glob(gui,color_select_bg)\
      -foreground $glob(gui,color_select_fg) 
  $w tag remove $tag 0.0 end

  set idx [$w search -count len -backwards {*}$op -- $searchfor 0.0]
  if {$idx == ""} {
    PopWarn [_ "Can't find that location \"$searchfor\" in config file. \
      Try to regenerate configuration and try again."]
    return
  }
  $w mark set insert "$idx + $len chars"
  $w see end
  $w see insert
  #  puts "$idx $len"
  set line [lindex [split $idx .] 0]
  # The man page says the following is obsolete but it is just what is needed
  catch {$w yview $idx}
  if {$heading} {
    $w mark set insert $line.0
  } else {
    # search backwards for ------------ and make sure it's visible
    set idx [$w search -count len -backwards -- "-----------" insert]
    if {$idx != {}} {
      $w see $idx
      # The above may have pushed the object out.  Put it back.
      $w see insert
      # The man page says the following is obsolete but it is just what is needed
      catch {$w yview $idx}
    }
  }
  $w tag add $tag $line.0 [expr $line+1].0
}

proc ConfigBrowserOK { w wm} {
  if {[set newConfig [ConfigTest All No]] == 0} {return}
  global glob config
  lassign [getOldNewVersions] oldv newv
  set filename $glob(configFile)
  Log [_ "Configuration Browser: Saving %s" $filename]
  Try { set fid [open $filename w]
    fconfigure $fid -translation binary
    puts $fid "# Generated by FileRunner $::glob(displayVersion) on\
    \n# [clock format [clock seconds]]\n"
    puts -nonewline $fid $newConfig
    puts $fid "return\n"
    # puts -nonewline $fid [$w get 0.0 end]
    close $fid} "" 1

  file copy -force $filename ${filename}.tst
    
  # No more need for window
  destroy $wm
  catch {destroy $glob(win,left).frame_listb}
  catch {destroy $glob(win,right).frame_listb}
  set glob(select_pry_lr) {}
  # This gets rid of old menus and bindings.  
  array unset config menu,*
  array unset config bind,*
  doDeferedMessages {*}[ReadConfig]
  ForceUpdate
}

proc ConfigBrowserRegenerate { w wl} {
  global glob
  lassign [getOldNewVersions] oldv newv
  set loc [$w yview]
  set wt .config_dialog
  centerWin $wt
  wm geo $wt [wm geo .]
  $w delete 0.0 end
  set fid [buildConfigLines 0]
  fillTextWindow $w ::tmp
  unset ::tmp
  close $fid
  
  $w edit reset

  #ConfigBrowserJumpToLoc $w $loc
  $w yview moveto [lindex $loc 0]
}

# safe source of config. The only thing this should let through are
# 'config()' entries.

proc safeSource {file} {
  set sInter [interp create -safe]
  # old config files have the 'ClearTheDecks...', here we dumb it down
  # but allow it to exist.

  interp eval $sInter {proc ClearTheDecksHereComeANewConfig {} {return}}
  interp expose $sInter source saSource
  return [list [interp alias {} getConf $sInter saSource $file ] $sInter]
}

proc getTheConfig {arg} {
  lassign $arg tok sInter
  $tok
  return [interp eval $sInter {array get config}]
}

proc safeReadConfig {file} {
  upvar savedDNs savedDNs 
  global config glob
  Log "Trying to reading config file \"$file\"."
  if {[set r [catch {file size $file} er]] != 0 || $er > 1000000} {
    if {$r == 0} {
      Log "Config file '$file' appears to be corrupt (too large ($er bytes))."
    }
    return $er
  }
  set rtn 0
  if {[catch {getTheConfig [safeSource $file] } res] == 0} {
    
    if {!$glob(init_done)} {
      setDefaultConfig
    } else {
      set savedDNs $config(DisplayName)
    }
    
    ClearTheDecksHereComeANewConfig
    array set config $res
    # delete the interpiter... We assume this is the only slave...
  } else {
    set rtn $res
  }
    # delete the interpiter... We assume this is the only slave...
  foreach int [interp slaves] {
    interp delete $int
  }
  return $rtn
 }
