# This H_Load module contains routines that deal with loading files of # various sorts. global docFil docPid Imgdly imgN objN Src waitchr waitchrs waitchrn waitstyle Source H_wait set Imgdly 0 set imgN 0 set objN 0 ;# Current object index. set Src {} ;# Current HTML input source line. set docFil {} ;# File handle for current document. set docPid {} ;# Process id for current w3get command. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Reader for file events. This routine reads from the w3get process that is # # reading a document from a remote web server. We get the data a line at a # # time, including the HTML HEAD lines. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc docRdr {w f} { global C D me imageBufsiz imagePipe errmsg folder docFil docPid in waitstyle set id "$me/docRdr" if {$D>5} {puts "$id: File \"$f\" docFil=\"$docFil\" in(HDR)=$in(HDR) in(HTML)=$in(HTML) in(IMAGE)=$in(IMAGE)"} if {$docFil != $f} { if {$D>2} {puts "$id: File \"$f\" is not current docFil=\"$docFil\""} set oldpid [pid $f] Msg "Kill old doc reader process $oldpid ..." if [catch {exec kill -TERM $oldpid} x] { Msg $x } if [catch {close $f} e] {Msg "docRdr: close $f gave $e"} else {Msg "Closed $f"} return } if {$D>7} {puts "$id: File \"$f\" is docFil=\"$docFil\""} if {$in(IMAGE) && ($f == $docFil || $f == $imagePipe)} { if {$D>2} {puts "$id: Ignore fileevent for $f because docFil=$docFil imagePipe=$imagePipe."} return } elseif {[gets $f line] >= 0} { if {$D>7} {puts "$id: line=\"$line\""} if {$waitstyle>0} {Tick} if {$in(HDR)} { if {$D>5} {puts "$id: Header line \"$line\""} Msg {Reading headers ...} hdrLine $line if {$D>6} {puts "$id: Header line \"$line\" done."} } else { if {$D>5} {puts "$id: Text line \"$line\""} .src.txt insert end $line\n HTML $w $line\n if {$D>6} {puts "$id: Text line \"$line\" done."} } update idletasks return } if {$D>4} {Msg "$id: Not in IMAGE and gets failed."} if {$docFil == {}} { if {$D>1} {Msg "$id: EOF on $f with no docFil"} if [catch {close $f} e] {Msg "close $f gave $e"} else {Msg "Closed $f"} return } if {$D>6} {Msg "EOF on $f"} if [catch {close $f} e] {if {$D} {Msg "docRdr: close $f gave $e"}} if {$D>3} {puts "$id: Closed $f"} set docFil {} WaitDone + Msg Done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # This is called to load a picture from Foto(f) into the nth image in window # # w. It must only be called after the picture has been successfully loaded. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc FotoIMG {w n U} { global B D IB me in Foto Fotx i2f link opt set id "$me/FotoIMG" if {$D>4} {puts "$id: w=\"$w\" n=\"$n\" U=\"$U\""} set i "$w.img$n.img" if {$D>4} {puts "$id: Load photo Foto($U) into $i ..."} if ![info exists Fotx($U)] { if {$D>0} {puts "$id: ### Foto($U) hasn't been loaded yet ###"} return 0 } if [winfo exists $i] { $i config -image Foto($U) } else { eval label $i -image Foto($U) $IB pack $i -in $w.img$n -side top } if {!$opt(ALT) && [winfo exists $w.img$n.alt]} { if {$D>2} {puts "$id: destroy $w.img$n.alt"} destroy $w.img$n.alt } if {$D>4} {puts "$id: $i should be filled in now."} if {$in(A)} {ButtonBindings $w $i $link} } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Here we talk to the URLcache server, sending it a URL and hoping to get # # back a local file path. If the URL isn't cached, URLcache will get it and # # later send us a message announding its arrival. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc GetCache {w i U} { global D me myname U2i U2f i2U set id "$me/GetCache" if {$D>1} {puts "$id: win \"$w\" image $i URL \"$U\""} if [info exists U2f($U)] { set p $U2f($U) if {$D>2} {puts "$id: URL \"$U\" is in file \"$p\""} } else { if {$D>2} {puts "$id: First time for \"$U\""} lappend U2i($U) $i if {$D>4} {puts "$id: $U is for images {$U2i($U)}"} set i2U($i) "$U" if {$D>2} {puts "$id: Item $i is \"$U\""} if [catch {send URLcache Find \"$myname\" \"$U\" "GotCache $i"} p] { Msg $p if {$D>1} {puts "$id: {send URLcache Find ...} request got \"$p\""} if {$D>2} {puts "$id: Can't send to URLcache; try to start it."} if [catch {exec URLcache &}] { if {$D>1} {puts "$id: Can't start URLcache."} CheckCache $w $i "$U" return } if {$D>2} {puts "$id: Started URLcache."} after 1000 if [catch {send URLcache Find \"$myname\" \"$U\" "GotCache $i"} p] { if {$D>1} {puts "$id: Still can't send to URLcache; give up."} if {$D>2} {puts "$id: {send URLcache Find ...} request got \"$p\""} CheckCache $w $i "$U" return } } } if {$D>1} {puts "$id: URL \"$U\" is in cache; p=\"$p\""} set U2f($U) $p LoadImgFile $w $i $p } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # The URLcache server will send us calls of this function when a URL has been # cached. By then, there may be a lot more references to the URL. We load the # image into a Foto() image widget, and call LoadImgFile to do the rest of # the processing. # proc GotCache {i p url} { global D B R me myname isRmt i2U U2i U2f set id "$me/GotCache" if {$D>2} {puts "$id: i=\"$i\" p=\"$p\" url=\"$url\""} set U $i2U($i) if {$D>2} {puts "$id: i=\"$i\" U=\"$U\"."} if {$url != $U} { if {$D>1} {puts "$id: Image $i wanted \"$U\" got \"$url\""} if [catch {send URLcache Find \"$myname\" $U "GotCache $i"} p] { if {$D>2} {puts "$id: URLcache didn't reply for \"$U\""} if {$D>2} {puts "$id: Returned p=\"$p\""} return } } if {$D>2} {puts "$id: Got \"$p\" for \"$U\""} set U2f($U) $p LoadImgFile .t.txt $i $p } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Load an image file into image n from local file p. The image may be needed # for several widgets, listed in U2i(). We proc LoadImgFile {w n p} { global B D me in Foto Fotx i2U iwU i2w U2i opt link set id "$me/LoadImgFile" if ![info exists i2w($n)] {if {$D>0} {puts "$id: i2w($n) unknown!!!"; return}} GetImgFile $n $p set U $i2U($n) set l $U2i($U) foreach i $l { if {$D>2} {puts "$id: Image $i ..."} set f $i2w($i) FotoIMG $w $n $i2U($n) } } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc GetImgFile {n p} { global B D me in Foto Fotx i2w i2U U2i set id "$me/GetImgFile" set f $i2w($n) set U $i2U($n) if {$D>2} {puts "$id: n=$n p=\"$p\" U=\"$U\""} if [regexp -nocase {\.xbm$} $p] {set type bitmap} else {set type photo} if [catch {image create $type Foto($U) -file $p} x] { if {$D>0} {puts "$id: #### Can't load $p ($x) ####"} return } set Fotx($U) 1 if {$D>4} {puts "$id: New $type Foto($U) from \"$p\""} } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc GetURL {w url meth} { global C D URL me folder getcmd docFil docPid in opt if {$D>2} {puts "$me/GetURL: url=\"$url\" meth={$meth}"} if {$D>3} {puts "$me/GetURL: #############################################################"} set URL $url if {$meth == {POST}} {set prog w3post} else {set prog w3get} Msg "Get URL \"$url\" via {$prog} ..." set getcmd "| $prog +T +H $url" if [catch {open $getcmd {RDWR NONBLOCK}} f] { Msg "Can't run \"$getcmd\" ($f)" return } Msg {Connecting ...} set in(HTML) $opt(HTML) set in(HDR) 1 if {$D>1} {puts "$me/GetURL: Started in(HDR)=$in(HDR) in(HTML)=$in(HTML) f=\"$f\" getcmd=\"$getcmd\""} set docFil $f set docPid [pid $f] Waiting fileevent $f readable "docRdr $w $f" } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Handle one header line. We only get these from web servers; for local # # files, this will never be called. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc hdrLine {l} { global D me docFil imageViewer imagePid imagePipe in opt doctype subtype URL W if {$D>4} {puts "$me/hdrLine: \"$l\""} if {$D>4} {puts "$me/hdrLine: \"$l\" insert ..."} .hdr.txt insert end $l\n if {$D>4} {puts "$me/hdrLine: \"$l\" inserted."} if {$l == {}} { if {$D>4} {puts "$me/hdrLine: Null line ends headers."} set in(HDR) 0 if {$D>4} {puts "$me/hdrLine: Check doctype=\"$doctype\" imagePipe=\"$imagePipe\""} if {$doctype == {image} && $imagePipe != {}} { if {$D>4} {puts "$me/hdrLine: Image file."} set in(IMAGE) 1 fconfigure $imagePipe -blocking 0 -buffering none -translation binary fconfigure $docFil -blocking 0 -buffering none -translation binary if {$D>2} {puts "$me/hdrLine: Start \"fcopy $docFil $imagePipe -command imageDone\""} fcopy $docFil $imagePipe -command imageDone } else { if {$D>4} {puts "$me/hdrLine: Text file."} } Msg {Reading document ...} } else { if {$D>4} {puts "$me/hdrLine: Header \"$l\""} if [regexp {^Content-Type: *(.*)/(.*)} $l {} t s] { if {$D>4} {puts "$me/hdrLine: Content-Type: t=\"$t\" s=\"$s\""} set doctype [string tolower $t] set subtype [string tolower $s] set in(HTML) $opt(HTML) if {$D>5} {puts "$me/hdrLine: doctype=\"$doctype\" subtype=\"$subtype\""} switch $doctype { text { switch $subtype { html {set in(HTML) 1} } } image { Msg "Document is image/$subtype" set in(HTML) 0 Htxt $W "Starting $imageViewer to view $URL ...\n" if [catch {open "| $imageViewer" w} f] { Msg "Can't run \"$imageViewer\" ($f)" if {$D>0} {puts "$me/hdrLine: Can't run \"$imageViewer\" ($f)"} return } set imagePipe $f set imagePid [pid $f] if {$D>2} {puts "$me/hdrLine: IMAGE/$subtype $imagePipe=\"$imageViewer\""} } default { set in(HTML) $opt(HTML) } } if {$D>5} {puts "$me/hdrLine: Content-Type: $doctype/$subtype done."} } elseif [regexp {^} $l {} t s] { Msg $t } elseif [regexp {^Location: *(.*)} $l {} t s] { Msg "Redirected to \"$t\"" LoadFile $W $t GET } else { if {$D>4} {puts "$me/hdrLine: Header \"$l\" ignored."} } if {$D>4} {puts "$me/hdrLine: Header \"$l\" done."} } if {$D>4} {puts "$me/hdrLine: Done."} } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Check to see if an image file is in the cache, and if so, we load it # # immediately into frame i. If not, we call GetCache to start a new # # background process to load the image. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc CheckCache {w i u} { global D B R me isRmt Foto Fotx i2f i2U U2i U2f set id "$me/CheckCache" if {$D>5} {puts "$id: win \"$w\" image $i url \"$u\""} set i2U($i) [set U [url2URL "$u"]] if {$D>4} {puts "$id: win \"$w\" image $i URL \"$i2U($i)\""} if ![info exists U2f($U)] { if {$D>4} {puts "$id: $U hasn't been loaded."} GetCache $w $i $U return } if {$D>4} {puts "$id: $U has been loaded."} set f $U2f($U) if {$D>4} {puts "$id: url $U is in file \"$f\" for images {$U2i($U)}"} if [regexp -nocase {\.xbm$} $f] {set type bitmap} else {set type photo} if [catch {image create $type Foto($U) -file $f} x] { if {$D>0} {puts "$id: ### Can't load image from \"$f\" ($x)"} GetCache $w $i $U return } set Fotx($U) 1 if {$D>4} {puts "$id: New $type Foto($U) from \"$U\" (Fotx=$Fotx($U))"} set U2f($U) $U set i2f($i) $f FotoIMG $w $i $U } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # This is called when we have a new URL to add to the history and stack. proc NewURL {name} { global D me history stk stkN if {[lsearch $history $name] < 0} { if {$D>1} {puts "NewURL: history doesn't contain \"$name\""} set history [linsert $history 0 $name] if {$D>4} {puts "NewURL: history={$history}"} } if {$stkN > 0} { set x [lindex $stk $stkN] if {$x == $name} { if {$D>1} {puts "NewURL: \"$name\" is stack $stkN \"$x\""} } else { if {$D>1} {puts "NewURL: \"$name\" differs from stack $stkN \"$x\""} incr stkN -1 set stk [lreplace $stk $stkN $stkN $name] if {$D>1} {puts "NewURL: Replaced stack $stkN with \"$name\""} } } else { if {[lindex $stk 0] != $name} { set stk [linsert $stk 0 $name] if {$D>1} {puts "NewURL: Inserted \"$name\" at top of stack"} } } } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # This is called when we finish copying in an image file. This is only used # # when the main "document file" is actually a graphic image file. For images # # embedded within HTML documents, we now rely on URLcache to fetch the file, # # and tell us what its cache name is. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc imageDone {args} { global D me docFil imagePipe in if {$D>2} {puts "$me/imageDone: docFil={$docFil} imagePipe={$imagePipe} args={$args}"} if {$docFil != {}} { if {$D>5} {puts "$me/imageDone: Close docFil={$docFil} ..."} close $docFil if {$D>6} {puts "$me/imageDone: Closed docFil={$docFil}"} } if {$imagePipe != {}} { if {$D>5} {puts "$me/imageDone: Close imagePipe={$imagePipe} ..."} close $imagePipe if {$D>6} {puts "$me/imageDone: Closed imagePipe={$imagePipe}"} } set in(IMAGE) 0 WaitDone + Msg Done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Here's the main routine for loading a document into the .src window, and # # loading the processed version into the .t.txt window. For remote files, we # # fire up a w3get process to fetch the file and feed us the data, which we # # read line at a time and parcel out to other functions for further # # processing. The meth arg is the method to use, GET or POST. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc LoadFile {w name meth} { global D me URL PROT HOST DIR docFil docPid history isRmt NL SP opt in tblN txtlvl ll waitstyle wm title . $name if {$D>4} {puts "$me/LoadFile: w=$w name=\"$name\" meth={$meth}"} set URL $name set NL 1 set SP 1 set isRmt 0 set Imgdly 0 set txtlvl 0 set tblN 0 foreach x {TABLE HEAD BODY comment PRE} {set in($x) 0} if {$D>4} {puts "$me/LoadFile: \"$name\" NL=$NL SP=$SP URL=\"$URL\""} if {$D>4} {puts "LoadFile: name=\"$name\""} if {$D>4} {puts "LoadFile: history={$history}"} if {$meth == {GET}} {NewURL $name} if [regexp {^#(.*)$} $name {} mark] { ToMark $w $mark return } if {$docFil != {}} { if {$D>1} {puts "LoadFile: Stop load from \"$docFil\" pid $docPid."} Msg "Stop current load f=\"$docFil\" p=$docPid ..." Stop } Clear $w .src.txt delete 1.0 end .hdr.txt delete 1.0 end if [file exists $name] { if {$D>4} {puts "LoadFile: name=\"$name\" is a local file."} if [catch {open $name r} h] {Msg $h; return} if [regexp {^(/)([^/]*)$} $name {} d f] { if {$D>4} {puts "LoadFile: Absolute directory \"$d\" + file \"$f\""} set DIR $d if {$D>4} {puts "LoadFile: DIR=\"$DIR\""} } elseif [regexp {^(/.*/)(.*$)} $name {} d f] { if {$D>4} {puts "LoadFile: Absolute directory \"$d\" + file \"$f\""} set DIR [Dir $d] if {$D>4} {puts "LoadFile: DIR=\"$DIR\""} } elseif [regexp {^(.*/)(.*$)} $name {} d f] { if {$D>4} {puts "LoadFile: Relative directory \"$d\" + file \"$f\""} set DIR [Dir $d] if {$D>4} {puts "LoadFile: DIR=\"$DIR\""} } else { if {$D>4} {puts "LoadFile: Simple file \"$name\""} } while {[gets $h line] >= 0} { if {$D>4} {puts "$me: line=\"$line\""} if {$waitstyle>0} {Tick} .src.txt insert end $line\n HTML $w $line\n } return } if [file isdirectory $name] { if {$D>4} {puts "LoadFile: name=\"$name\" is a local directory."} set DIR [set d [Dir "$name/"]] if {$DIR == {./}} {set DIR [pwd]/} GetURL $w $d $meth return } if [regexp {^([A-Za-z]+)://([-A-Za-z0-9_.:]*)/(.*)$} $name {} PROT HOST path] { if {$D>4} {puts "LoadFile: name=\"$name\" is a full URL."} if {$D>4} {puts "LoadFile: PROT=\"$PROT\" HOST=\"$HOST\" path=\"$path\""} if {$D>4} {puts "LoadFile: name=\"$name\" looks like a remote file."} if [regexp {^(.*)/(.*)$} $path {} d f] { if {$D>4} {puts "LoadFile: d=\"$d\""} set DIR /$d/ } GetURL $w $name $meth return } if {$PROT != {} && $HOST != {}} { if {$D>4} {puts "LoadFile: PROT=\"$PROT\" HOST=\"$HOST\" name=\"$name\" relative file."} if [regexp {^(/.*)/(.*$)} $name {} d f] { if {$D>4} {puts "LoadFile: Absolute directory \"$d\" + file \"$f\""} set url "$PROT://$HOST$name" if {$D>4} {puts "LoadFile: url=\"$url\""} } elseif [regexp {^(.*)/(.*$)} $name {} d f] { if {$D>4} {puts "LoadFile: Relative directory \"$d\" + file \"$f\""} set url "$PROT://$HOST$DIR$name" if {$D>4} {puts "LoadFile: url=\"$url\""} } else { if {$D>4} {puts "LoadFile: Simple file \"$name\""} set url "$PROT://$HOST$DIR$name" if {$D>4} {puts "LoadFile: url=\"$url\""} } GetURL $w $url $meth return } Msg "Can't handle \"$name\"" } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # The Reload button merely fetches a new copy of the current document, and # # loads it into the .t.txt and .src windows. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc Reload {w} { global URL docFil if {$docFil != {}} { Msg {Stop current transfer ...} Stop } LoadFile $w $URL GET } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Stop a load operation. It turns out that just closing the pipe has no # # effect on w3get, which is probably hung on a connect() call. But a TERM # # signal seems to get its attention. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc Stop {} { global docFil docPid waitchr if {$docFil != {}} { Msg {Stop the transfer ...} if {$docPid != {}} { if [catch {exec kill -TERM $docPid} x] { Msg $x } else { Msg "TERMed doc process $docPid." set docPid {} } } if [catch {close $docFil} x] { Msg $x } else { Msg "Closed doc file \"$docFil\"." set docFil {} } } else { Msg {No transfer in progress} } WaitDone * } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # We have encountered a new IMG tag. It is common for the same image to # # appear several times in a document, and so we try to keep track of images # # and only load each one once. We first create a frame to hold the image, and # # fill it with the ALT text if one exists. Then we try to load the image. If # # it's a local file, we can read it directly. If it's a remote file, we start # # up a w3get process to get it, and let it run asynchronously. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # proc tagIMG {w t a} { global B D FB IB R me ALT NL SP Foto Fotx in link Ltag imgN objN U2i i2w opt set id "$me/tagIMG" incr imgN incr objN set f "$w.img$imgN" if {$D>1} {puts "$id: Image $imgN Frame $f is <$t $a> ..."} if [winfo exists $f] {destroy $f} eval frame $f $FB if {$D>4} {puts "$id: Frame $f created."} set ALT($imgN) {___} eval label $f.alt -textvariable ALT($imgN) $IB pack $f.alt -in $f -side bottom set i2w($imgN) $f $w window create insert -window $f if {$D>4} {puts "$id: Frame $f inserted."} if {[regexp -nocase {ALT="([^"]*)"} $a {} alt] || [regexp -nocase {ALT=([^ ]*)} $a {} alt]} { if {$D>1} {puts "$id: ALT=\"$alt\""} set ALT($imgN) $alt bind $f "ObjEnter $f.alt $objN %X %Y {$alt}" bind $f "ObjLeave $f.alt $objN %X %Y" if {$D>1} {puts "$id: $f.alt filled with \"$alt\""} if {$in(A)} {ButtonBindings $w $f.alt $link} } if [regexp -nocase {SRC="([^"]+)"} $a {} src] { if {$opt(IMG)} { if {$D>4} {puts "$id: src=\"$src\""} set SRC [url2URL $src] if {$D>4} {puts "$id: src=\"$src\" SRC=\"$SRC\""} if [info exists Fotx($SRC)] { if {$D>4} {puts "$id: Foto($SRC) has been loaded already."} FotoIMG $w $imgN $SRC } else { if {$D>4} {puts "$id: Foto($SRC) must be loaded."} CheckCache $w $imgN $SRC } } else { if {$D>3} {puts "$id: Not showing images."} } } if {$Ltag == {Llink}} { if {$D>4} {puts "$id: We are inside Link $link."} $f configure -bd 3 -relief ridge if {$in(A)} {ButtonBindings $w $f $link} } set NL 0 set SP 0 }