############################################################################ # # File: iiencode.icn # # Subject: Program to encode text in the style of uuencode # # Author: Richard L. Goerwitz, enhanced by Frank J. Lhota # # Date: May 2, 2001 # ########################################################################### # # This file is in the public domain. # ############################################################################ # # Version: 2.0 # ########################################################################### # # 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 changes I # made to the program were: (1) To simplify the notion of file mode # (everything is encoded with 0644 permissions), and (2) to add sup- # port for xxencode format (which will generally pass unscathed even # through EBCDIC sites). # # Iiencode's usage is compatible with that of 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 argument specifies the name the encoded file # should be given when it is ultimately decoded. # # Extensions to the base uuencode command options include -x and -o. # An -x tells iiencode to use xxencode (rather than uuencode) format. # Option -o causes the following argument to be used as the file # iiencode is to write its output to (the default is &output). Note # that, on systems with newline translation (e.g. MS-DOS), the -o # argument should always be used. # # iiencode [infile] [-x] remote-filename [-o output-filename] # # # FIXES: Speeded up substantially (more than twice as fast on my # machine) by using a more icon-ish algorithm. We encode in two # steps: # # 1) We first "unpack" the bytes by taking groups of 3 bytes (24 # bits) and spreading them out by inserting two 0 bits before # every block of 6 bits. The result is that each group of 3 # bytes is unpacked to 4 "small bytes", each <<= "\x3F". # 2) The unpacked bytes are mapped to the coded line by using the # Icon map function. # # There are numerous advantages to this approach. The Icon map # function is much faster than the 'C'-ish alternatives. We can # process the file one line at a time. Also, the different encoding # mechanisms (old BSD, new BSD, xxencode) can be produces by simply # using different map parameters. # ############################################################################ # # See also: iidecode.icn # ############################################################################ link options procedure main ( a ) local in_filename, out_filename, in, out, is_xx, remotename, opt # Parse arguments. opt := options ( a, "-o:-x", Usage ) is_xx := opt [ "x" ] out_filename := opt [ "o" ] case *a of { 1 : in_filename := remotename := a [ 1 ] 2 : { in_filename := a [ 1 ] remotename := a [ 2 ] } default : Usage ( "", write, 2 ) } # If no input filename was supplied, use &input. if /in_filename then in := &input else in := open ( in_filename, "ru" ) | Usage ( "Can't open input file " || in_filename || "." ) # If an output filename was specified, open it for writing. if /out_filename then out := &output else out := open ( out_filename, "w" ) | Usage ( "Can't open output file " || out_filename || "." ) # 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). write ( out, "begin 644 ", remotename ) encode ( out, in, is_xx ) write ( out, "end" ) every close ( ( &input ~=== in ) | ( &output ~=== out ) ) exit ( 0 ) end ########################################################################### # # Writes msg and the Usage line to &errout using the output procedure Show, # which defaults to stop. If Show does not stop processing and \errcode, # exit with errcode. # ########################################################################### procedure Usage ( msg, Show, errcode ) static usage initial usage := "usage: iiencode [infile] [-x] _ remote-filename [-o output-filename]" /Show := stop Show ( &errout, msg, "\n", usage ) exit ( \errcode ) return msg end ########################################################################### # # Reads all of file in, encodes it, and writes the encoded lines to out. # "uu" encoding is used unless \is_xx, in which case "xx" encoding is used. # ########################################################################### procedure encode ( out, in, is_xx ) # Copy from in to out, encoding as you go along. local line, coded static unpacked initial unpacked := "_ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F_ \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F_ \x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F_ \x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F" if \is_xx then { coded := "_ +-0123456789ABCD_ EFGHIJKLMNOPQRST_ UVWXYZabcdefghij_ klmnopqrstuvwxyz" } else { # # To get the BSD old code, replace the next 2 lines with: # coded := " _ # !\"#$%&'()*+,-./_ # coded := "_ `!\"#$%&'()*+,-./_ 0123456789:;<=>?_ @ABCDEFGHIJKLMNO_ PQRSTUVWXYZ[\\]^_" } # 1 (up to) 45 character segment while line := reads ( in, 45 ) do { write ( out, map ( char ( *line ) || unpack ( line ), unpacked, coded ) ) } # Output a zero-length line. write ( out, coded [ 1 ] ) end ########################################################################### # # Takes groups of 3 bytes in s and expands the groups to 4 bytes. Each # byte in the unpacked group has 2 zero high bits, i.e. is <<= "\x3F". # If *s is not divisible by 3, we pad s with blanks on the right # to make up the last group. # ########################################################################### procedure unpack ( s ) local n, grp s ? { s := "" while grp := ( move ( 3 ) | left ( "" ~== tab ( 0 ), 3 ) ) do { n := 0 grp ? while n := ord ( move ( 1 ) ) + ( n * 16r100 ) s ||:= char ( ishift ( iand ( n, 16rFC0000 ), -18 ) ) || char ( ishift ( iand ( n, 16r03F000 ), -12 ) ) || char ( ishift ( iand ( n, 16r000FC0 ), - 6 ) ) || char ( iand ( n, 16r00003F ) ) } } return s end