tenaglia@mis.mcw.edu ("Chris Tenaglia - 257-8765") (09/15/90)
I have some files that I'd like to UUENCODE or UUDECODE. Being on a VMS system without a C compiler, having the sources still doesn't help. I've attempted a port to Icon of UUENCODE and UUDECODE. They are close, but not quite right. Would someone care to look them over and offer suggestions or corrections? Thanx. Chris Tenaglia (System Manager) about 160 lines follow Medical College of Wisconsin 8701 W. Watertown Plank Rd. Milwaukee, WI 53226 (414)257-8765 tenaglia@mis.mcw.edu, mcwmis!tenaglia ------------------- uuencode.icn --------------------------- ################################################################## # # # UUENCODE.ICN 09/14/90 BY TENAGLIA # # # # UUENCODE BINARY FILES FOR EMAIL TRANSFER # # # ################################################################## procedure main(param) source := param[1] | input("_Source:") target := param[2] | input("_Target:") (in := open(source)) | stop("Can't open ",source) (out := open(target,"w")) | stop("Can't open ",target) write("\fUUENCODE FROM ",source," TO ",target) write(out,"begin 0600 ",source) while line := reads(in,45) do { writes(*line,", ") writes(out,char(*line+32)) every i := 1 to *line by 3 do output(out,line[i+:3]) write(out,"") } write(out,"end") close(in) ; close(out) end # # THIS PROCEDURE TAKES AN OUTPUT FILE PARAMETER AND A 3 BYTE STRING # OF BINARY DATA. IT WRITES OUT 4 BYTES OF PRINTABLE/MAILABLE ASCII # procedure output(fo,str) c1 := ord(str[1])*4 c2 := ior( iand(ord(str[1])/16,8r060) , iand(ord(str[2])*16,8r017) ) c3 := ior( iand(ord(str[2])/4, 8r074) , iand(ord(str[3])*64,8r003) ) c4 := iand(ord(str[3]),8r077) writes(fo,char(enc(c1)), char(enc(c2)), char(enc(c3)), char(enc(c4))) end # # ENCRYPTION ASCIIZER ROUTINE # procedure enc(n) return iand(n,8r0077)+32 end # # PROMPT AND TAKE AN INPUT # procedure input(prompt) writes(prompt) return read() end ----------------------- uudecode.icn ------------------------------ ################################################################## # # # UUDECODE.ICN 09/14/90 BY TENAGLIA # # # # UUDECODE BINARY FILES FOR EMAIL TRANSFER # # # ################################################################## procedure main(param) source := param[1] | input("_Source:") target := param[2] | input("_Target:") (in := open(source)) | stop("Can't open ",source) (out := open(target,"w")) | stop("Can't open ",target) write("\fUUDECODE FROM ",source," TO ",target) until match("begin",(line := read(in))) write("Found ",parse(line,' ')[3]) while line := read(in) do { writes(*line,", ") p := 0 bytes := ord(line[1]) - 32 if bytes = 64 then bytes := 0 if (bytes=0) | match("end",line) then break count := integer(real(bytes)/3.0 + 0.9) * 4 buf := "" every i := 2 to count by 4 do { x1 := ord(line[i]) - 32 if x1 = 64 then x1 := 0 x2 := ord(line[i+1]) - 32 if x2 = 64 then x2 := 0 x3 := ord(line[i+2]) - 32 if x3 = 64 then x3 := 0 x4 := ord(line[i+3]) - 32 if x4 = 64 then x4 := 0 if p < bytes then { p +:= 1 buf ||:= char(x2 / 16 + x1 * 4) } if p < bytes then { p +:= 1 buf ||:= char(x3 / 4 + (x2 % 16) * 16) } if p < bytes then { p +:= 1 buf ||:= char(x4 + (x3 % 4) * 64) } } writes(out,buf) writes("(",*buf,"), ") } close(in) ; close(out) end # # PARSE A STRING WITH RESPECT TO A DELIMITER CSET # procedure parse(line,delims) static chars chars := &cset -- delims tokens := [] line ? while tab(upto(chars)) do put(tokens,tab(many(chars))) return tokens end # # THIS PROCEDURE TAKES AN OUTPUT FILE PARAMETER AND A 3 BYTE STRING # OF BINARY DATA. IT WRITES OUT 4 BYTES OF PRINTABLE/MAILABLE ASCII # procedure output(fo,str) c1 := ord(str[1])*4 c2 := ior( iand(ord(str[1])/16,8r060) , iand(ord(str[2])*16,8r017) ) c3 := ior( iand(ord(str[2])/4, 8r074) , iand(ord(str[3])*64,8r003) ) c4 := iand(ord(str[3]),8r077) writes(fo,char(enc(c1)), char(enc(c2)), char(enc(c3)), char(enc(c4))) end # # ENCRYPTION ASCIIZER ROUTINE # procedure enc(n) return iand(n,8r0077)+32 end # # PROMPT AND TAKE AN INPUT # procedure input(prompt) writes(prompt) return read() end
yost@DPW.COM (David A. Yost) (09/18/90)
In article <0093CBF0039A4D60.20400E83@mis.mcw.edu> tenaglia@mis.mcw.edu ("Chris Tenaglia - 257-8765") writes: > >I've attempted a port to Icon of UUENCODE and UUDECODE. Now there's a couple of programs I bet are really slow in Icon. I'd love to see how fast they run with the Icon compiler, compared to the interpreter and compared to the original C version. If the compiler can really do a good job on this sort of repetitive low-level stuff that kills Icon performance, it would be the dawning of a new day! Imagine: we could use Icon instead of C for everything! Ken, can we see a benchmark on this? --dave yost yost@dpw.com or uunet!esquire!yost Please don't use other mangled forms you may see in the From or Reply-To fields above.
kwalker@CS.ARIZONA.EDU ("Kenneth Walker") (09/20/90)
Date: 18 Sep 90 16:13:58 GMT From: esquire!yost@nyu.edu In article <0093CBF0039A4D60.20400E83@mis.mcw.edu> tenaglia@mis.mcw.edu ("Chris Tenaglia - 257-8765") writes: > >I've attempted a port to Icon of UUENCODE and UUDECODE. Now there's a couple of programs I bet are really slow in Icon. I'd love to see how fast they run with the Icon compiler, compared to the interpreter and compared to the original C version. If the compiler can really do a good job on this sort of repetitive low-level stuff that kills Icon performance, it would be the dawning of a new day! Imagine: we could use Icon instead of C for everything! Ken, can we see a benchmark on this? I tried 3 runs of each program using the Unix time command and got a range of results. The uuencode.icn I used has a fix that is not in the version Chris posted. I also removed the write() expressions that print the number of bytes in each group processed. uuencode: compiled is 4.0 - 5.8 times faster than interpreted system version is 21 - 40 times faster than compiled uudecode compiled is 2.4 - 2.9 times faster than interpreted system version is 22 - 36 times faster than compiled While the time command is clearly not a very accurate measure of program speed (I used the same data on all 3 runs), it does give a feeling for how much the compiler improves speed and how much work is left to do to get programs like these to run as fast as those coded in C. Ken Walker / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721 +1 602 621-4324 kwalker@cs.arizona.edu {uunet|allegra|noao}!arizona!kwalker
goer@quads.uchicago.edu (Richard L. Goerwitz) (09/20/90)
Kwalker@CS.ARIZONA.EDU ("Kenneth Walker") writes: > > uuencode: > compiled is 4.0 - 5.8 times faster than interpreted > system version is 21 - 40 times faster than compiled > > uudecode > compiled is 2.4 - 2.9 times faster than interpreted > system version is 22 - 36 times faster than compiled > >While the time command is clearly not a very accurate measure of program >speed (I used the same data on all 3 runs), it does give a feeling >for how much the compiler improves speed and how much work is left to >do to get programs like these to run as fast as those coded in C. For short programs like this, it would probably be better to use C. The real advantage of using Icon is in how it speeds up development time, and aids program maintenance by simply cutting down on the amount and complexity of the code. I guess what I'm trying to say is that getting a two to five-fold speed increase looks pretty good to people like me who can only think with horror about what some of our programs would look like - or how hard it would be to write/maintain them - if they had to be done in C. Don't be too deferential about the gap between compiled Icon and C. What you and Janalee have done is terriffic. -Richard
goer@quads.uchicago.edu (Richard L. Goerwitz) (09/20/90)
Tenaglia@mis.mcw.edu ("Chris Tenaglia") writes: > >I have some files that I'd like to UUENCODE or UUDECODE. Being on a VMS >system without a C compiler, having the sources still doesn't help. I've >attempted a port to Icon of UUENCODE and UUDECODE. They are close, but not >quite right. Would someone care to look them over and offer suggestions or >corrections? No C compiler? How do you exist? :-) Here are a couple of Icon uuXXcode functions. They should be pretty much compatible with the latest BSD version. Notes are offered on how to make them work the same as the "old" version, though the two versions are com- patible. I guess I'll post uuencode first (I call it iiencode). Iidecode will come in a subsequent posting. -Richard ############################################################################ # # Name: iiencode.icn # # Title: iiencode (port of the Unix/C uuencode program to Icon) # # Author: Richard L. Goerwitz # # Version: 1.2 # ############################################################################ # # This is an Icon port of the Unix/C uuencode utility. Since # uuencode is publicly distributable BSD code, I simply grabbed a # copy, and rewrote it in Icon. The only basic functional change I # made to the program was to simplify the notion of file mode. # Everything is encoded with 0644 permissions. Operating systems # differ so widely in how they handle this sort of thing that I # decided just not to worry about it. # # Usage is the same as the Unix uuencode command, i.e. a first # (optional) argument gives the name the file to be encoded. If this # is omitted, iiencode just uses the standard input. The second and # final argument gives the name the encoded file should be given when # it is ultimately decoded: # # iiencode [infile] remotefilename # # BUGS: Slow. I decided to go for clarity and symmetry, rather than # speed, and so opted to do things like use ishift(i,j) instead of # straight multiplication (which under Icon v8 is much faster). Note # that I followed the format of the newest BSD release, which refuses # to output spaces. If you want to change things back around so that # spaces are output, look for the string "BSD" in my comments, and # then (un)comment the appropriate sections of code. # ############################################################################ # # See also: iidecode.icn # ############################################################################ procedure main(a) local in, filename # optional 1st argument if *a = 2 then { filename := pop(a) if not (in := open(filename, "r")) then { write(&errout,"Can't open ",a[1],".") exit(1) } } else in := &input if *a ~= 1 then { write(&errout,"Usage: iiencode [infile] remotefile") exit (2) } # This generic version of uuencode treats file modes in a primitive # manner so as to be usable in a number of environments. Please # don't get fancy and change this unless you plan on keeping your # modified version on-site (or else modifying the code in such a # way as to avoid dependence on a specific operating system). writes("begin 644 ",a[1],"\n") encode(in) writes("end\n") exit(0) end procedure encode(in) # Copy from in to standard output, encoding as you go along. local line # 1 (up to) 45 character segment while line := reads(in, 45) do { writes(ENC(*line)) line ? { while outdec(move(3)) pos(0) | outdec(left(tab(0), 3, " ")) } writes("\n") } # Uuencode adds a space and newline here, which is decoded later # as a zero-length line (signals the end of the decoded text). # writes(" \n") # The new BSD code (compatible with the old) avoids outputting # spaces by writing a ` (see also how it handles ENC() below). writes("`\n") end procedure outdec(s) # Output one group of 3 bytes (s) to standard output. This is one # case where C is actually more elegant than Icon. Note well! local c1, c2, c3, c4 c1 := ishift(ord(s[1]),-2) c2 := ior(iand(ishift(ord(s[1]),+4), 8r060), iand(ishift(ord(s[2]),-4), 8r017)) c3 := ior(iand(ishift(ord(s[2]),+2), 8r074), iand(ishift(ord(s[3]),-6), 8r003)) c4 := iand(ord(s[3]),8r077) every writes(ENC(c1 | c2 | c3 | c4)) return end procedure ENC(c) # ENC is the basic 1 character encoding procedure to make a char # printing. # New BSD code doesn't output spaces... return " " ~== char(iand(c, 8r077) + 32) | "`" # ...the way the old code does: # return char(iand(c, 8r077) + 32) end
goer@quads.uchicago.edu (Richard L. Goerwitz) (09/20/90)
############################################################################ # # Name: iidecode.icn # # Title: iidecode (port of the Unix/C uudecode program to Icon) # # Author: Richard L. Goerwitz # # Version: 1.2 # ############################################################################ # # This is an Icon port of the Unix/C uudecode utility. Since # uudecode is publicly distributable BSD code, I simply grabbed a # copy, and rewrote it in Icon. The only basic functional change I # made to the program was to simplify the notion of file mode. # Everything is encodedwith 0644 permissions. Operating systems # differ so widely in how they handle this sort of thing that I # decided just not to worry about it. # # Usage is the same as the Unix uudecode command, i.e. a first # (optional) argument gives the name the file to be decoded. If this # is omitted, iidecode just uses the standard input: # # iidecode [infile] remotefilename # # Even people who do not customarily use Unix should be aware of # the uuen/decode program and file format. It is widely used, and has # been implemented on a wide variety of machines for sending 8-bit # "binaries" through networks designed for ASCII transfers only. # # BUGS: Slow. I decided to go for clarity and symmetry, rather than # speed, and so opted to do things like use ishift(i,j) instead of # straight multiplication (which under Icon v8 is much faster). # ############################################################################ # # See also: iiencode.icn # ############################################################################ procedure main(a) local in, filename, dest # optional 1st (and only) argument if *a = 1 then { filename := pop(a) if not (in := open(filename, "r")) then { write(&errout,"Can't open ",a[1],".") exit(1) } } else in := &input if *a ~= 0 then { write(&errout,"Usage: iidecode [infile] remotefile") exit (2) } # Find the "begin" line, and determine the destination file name. !in ? { tab(match("begin ")) & tab(many(&digits)) & # mode ignored tab(many(' ')) & dest := tab(0) } # If dest is null, the begin line either isn't present, or is # corrupt (which necessitates our aborting with an error msg.). if /dest then { write(&errout,"No begin line.") exit(3) } # Tilde expansion is heavily Unix dependent, and we can't always # safely write the file to the current directory. Our only choice # is to abort. if match("~",dest) then { write(&errout,"Please remove ~ from input file begin line.") exit(4) } out := open(dest, "w") decode(in, out) # decode checks for "end" line if not match("end", !in) then { write(&errout,"No end line.\n") exit(5) } exit(0) end procedure decode(in, out) # Copy from in to out, decoding as you go along. local line, chunk while line := read(in) do { if *line = 0 then { write(&errout,"Short file.\n") exit(10) } line ? { n := DEC(ord(move(1))) # Uuencode signals the end of the coded text by a space # and a line (i.e. a zero-length line, coded as a space). if n <= 0 then break while (n > 0) do { chunk := move(4) | tab(0) outdec(chunk, out, n) n -:= 3 } } } return end procedure outdec(s, f, n) # Output a group of 3 bytes (4 input characters). N is used to # tell us not to output all of the chars at the end of the file. local c1, c2, c3 c1 := iand( ior( ishift(DEC(ord(s[1])),+2), ishift(DEC(ord(s[2])),-4) ), 8r0377) c2 := iand( ior( ishift(DEC(ord(s[2])),+4), ishift(DEC(ord(s[3])),-2) ), 8r0377) c3 := iand( ior( ishift(DEC(ord(s[3])),+6), DEC(ord(s[4])) ), 8r0377) if (n >= 1) then writes(f,char(c1)) if (n >= 2) then writes(f,char(c2)) if (n >= 3) then writes(f,char(c3)) end procedure DEC(c) # single character decode return iand(c - 32, 8r077) end
tenaglia@mis.mcw.edu ("Chris Tenaglia - 257-8765") (09/20/90)
I'd like to thank Ken Walker for his corrective advice in getting the uuencode fixed. Apparently the uudecode was ok. Thanks also for the alternative iiencode/iidecode. It sure generated a stir. I was looking for a little unix-like functionality, but it seems to be of great interest to benchmarkers too. The uudecode is probably a pretty shabby example, since I converted it almost literally from a PC BASIC program. For VMS folks, uuencode and uudecode are nifty ways of converted binary data to printable/mailable ascii and back again. It expands 3 binary bytes into 4 printable bytes. This 33% increase is more compact than vms dump data. Unfortunately vms has oodles of file types, and not all will work. VMS Executables (.EXE) will compress and decompress just fine. Icon executables work too (.ICX). Object files (.OBJ) won't work at all. Text files almost work. Sometimes there is a little trailing garbage on the end of the file (or is that a bug in my program?) Is there any interest in a reposting of the finished programs? Chris Tenaglia (System Manager) Medical College of Wisconsin 8701 W. Watertown Plank Rd. Milwaukee, WI 53226 (414)257-8765 tenaglia@mis.mcw.edu, mcwmis!tenaglia