[clug] stdio library, feof(3) can't detect EOF in a script [was Re: using 'dd' in a pipeline.]

John Mills johnmi at effect.net.au
Thu Dec 11 11:38:08 MST 2014


On Tue, Nov 25, 2014 at 01:22:12PM +1100, steve jenkin wrote:
> 
> On 25 Nov 2014, at 11:10 am, John Mills <johnmi at effect.net.au> wrote:
> 
> > Well, my solution is not correct. Nor complete so far...:-)
> 
> John,
> 
> Thanks for continuing to help and work through this.
> 
> How many mistakes can I make in the one thread?
> Apparently it’s unlimited :)
> My bad for not actually running your script & checking for myself :(
> 
> I checked and stdio (fread()) ignored / deleted nulls, at least on one system. Not sure how to count the nulls (\0) in those files.
> 
> This behaviour goes back to the earliest days of ‘C’ where everything was an int and logical “false” was zero, “true” was non-zero, nulls marked the end of strings [still do] and simple input/output was not “8-bit safe”...
> 
> This, roughly, was all you needed to copy from stdin to stdout. No, I haven’t compiled any version of this :)
> 
>  while (ch=getc(stdin))
>     (void) putc(ch, stdout) ;
> 
> It incorrectly terminates when a null is encountered (at least, it used to).
> While stdio library is very useful for line-based text, if you needed to process binary files, read(2) & write(2) syscalls were needed - which meant handling buffering and syncs yourself.
> 
> All my best
> steve
> 
> --
> Steve Jenkin, IT Systems and Design 
> 0412 786 915 (+61 412 786 915)
> PO Box 48, Kippax ACT 2615, AUSTRALIA
> 
> mailto:sjenkin at canb.auug.org.au http://members.tip.net.au/~sjenkin
> 

If anyone needs a more correct version of my Tcl eof-aware filter, herewith:
It uses a pipe open to get around a quirk in exec in this context.
(http://wiki.tcl.tk/1180
"When spawning an application which returns binary data via stdout do not 
"use exec, but the [open "|..."] idiom as only the latter allows you to 
change the pipe channel to binary...")

for f in white.jpg brown.jpg; do echo -n "$f";cat $f|./pipetestj3.tcl;done

# ==================== pipetestj3.tcl ==========================
set bs 4096
set blocks 0
set data {}

proc GetData {chan} {
    upvar data data bs bs blocks blocks
    set blk [read $chan $bs]
    if {$blocks eq 0} { puts " blocksize=$bs" }
    if {$blk ne {}} {
	append data $blk
	incr blocks
 	puts -nonewline "$blocks "
 	set mcmd [open "|/usr/bin/md5sum -" r+]
	fconfigure $mcmd -buffering none -blocking 1 -translation binary
	puts -nonewline $mcmd "$data"
	flush $mcmd
	chan close $mcmd write
	set mymd [read -nonewline $mcmd]
	close $mcmd
	puts $mymd
    }
    if {[eof $chan]} {
	exit
    }
}

fconfigure stdin -blocking 0 -encoding binary -translation binary -buffering none
fileevent stdin readable [list GetData stdin]

vwait forever
======================================================================

HTH
John Mills


More information about the linux mailing list