home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2733 / iiencode.icn < prev    next >
Encoding:
Text File  |  1991-02-10  |  6.4 KB  |  210 lines

  1. ############################################################################
  2. #
  3. #    Name:     iiencode.icn
  4. #
  5. #    Title:     iiencode (port of the Unix/C uuencode program to Icon)
  6. #
  7. #    Author:     Richard L. Goerwitz
  8. #
  9. #    Version: 1.7
  10. #
  11. ############################################################################
  12. #
  13. #  This is an Icon port of the Unix/C uuencode utility.  Since
  14. #  uuencode is publicly distributable BSD code, I simply grabbed a
  15. #  copy, and rewrote it in Icon.  The only basic functional changes I
  16. #  made to the program were:  1) To simplify the notion of file mode
  17. #  (everything is encoded with 0644 permissions), and 2) to add sup-
  18. #  port for xxencode format (which will generally pass unscathed even
  19. #  through EBCDIC sites).
  20. #
  21. #  Iiencode's usage is compatible with that of the Unix uuencode
  22. #  command, i.e. a first (optional) argument gives the name the file
  23. #  to be encoded.  If this is omitted, iiencode just uses the standard
  24. #  input.  The second argument specifies the name the encoded file
  25. #  should be given when it is ultimately decoded.
  26. #
  27. #  Extensions to the base uuencode command options include -x and -o.
  28. #  An -x tells iiencode to use xxencode (rather than uuencode) format.
  29. #  Option -o causes the following argument to be used as the file
  30. #  iiencode is to write its output to (the default is &output).  Note
  31. #  that, on systems with newline translation (e.g. MS-DOS), the -o
  32. #  argument should always be used.
  33. #
  34. #    iiencode [infile] [-x] remote-filename [-o] output-filename
  35. #
  36. #  BUGS:  Slow.  I decided to go for clarity and symmetry, rather than
  37. #  speed, and so opted to do things like use ishift(i,j) instead of
  38. #  straight multiplication (which under Icon v8 is much faster).  Note
  39. #  that I followed the format of the newest BSD release, which refuses
  40. #  to output spaces.  If you want to change things back around so that
  41. #  spaces are output, look for the string "BSD" in my comments, and
  42. #  then (un)comment the appropriate sections of code.
  43. #
  44. #  NOTE ON MS-DOS:  Systems for which newline translation is necessary
  45. #  can encode files.  The problem is that, since iiencode sends coded
  46. #  files to the standard output, it is impossible to avoid sending out
  47. #  OS-specific sequences at the end of each line.  While most uudecode
  48. #  programs will be able to handle the resulting file, they will not
  49. #  always decode the file *name* properly.  Binary files simply won't
  50. #  work, unless the program is modified to write to a file instead of
  51. #  the standard output.  If you do this, make sure you open the file
  52. #  for writing in untranslated mode.  If someone modifies this program
  53. #  so that it works really will under DOS, please send me the results.
  54. #
  55. ############################################################################
  56. #
  57. #  See also: iidecode.icn
  58. #
  59. ############################################################################
  60.  
  61.  
  62. procedure main(a)
  63.  
  64.     local ofs, in_filename, out_filename, in, out, is_xx, remotename
  65.  
  66.     usage := "usage:  iiencode [infile] [-x] _
  67.     remote-filename    [-o output-filename]"
  68.  
  69.     # Parse arguments.
  70.     ofs := 0
  71.     while (ofs +:= 1) <= *a do {
  72.         case a[ofs] of {
  73.         "-x"    : is_xx := 1
  74.         "-o"    : out_filename := a[ofs +:= 1] | stop(usage)
  75.         default : {
  76.         if not (/in_filename := a[ofs]) then
  77.             remotename := a[ofs]
  78.         }
  79.     }
  80.     }
  81.  
  82.     # If remotename is null, set it to in_filename.  If it's still
  83.     # null, then abort with usage message.
  84.     if /(/remotename :=: in_filename) then {
  85.         write(&errout,usage)
  86.         exit(2)
  87.     }
  88.  
  89.     # If no input filename was supplied, use &input.
  90.     if /in_filename then
  91.     /in := &input
  92.     else
  93.     in := open(in_filename) |
  94.     stop(&errout,"Can't open input file, ",in_filename,".\n",usage)
  95.  
  96.     # If an output filename was specified, open it for writing.
  97.     if \out_filename then
  98.     out := open(out_filename, "wu") |
  99.         stop("Can't open output file, ",out_filename,".\n",usage)
  100.     # Set null out to &output; advise DOS users to use -o option.
  101.     else {
  102.     out := &output
  103.     if find("MS-DOS",&features) then
  104.         write(&errout, "Okay, but the -o option is recommended for DOS.")
  105.     }
  106.  
  107.     # This generic version of uuencode treats file modes in a primitive
  108.     # manner so as to be usable in a number of environments.  Please
  109.     # don't get fancy and change this unless you plan on keeping your
  110.     # modified version on-site (or else modifying the code in such a
  111.     # way as to avoid dependence on a specific operating system).
  112.     writes(out, "begin 644 ",remotename,"\n")
  113.  
  114.     encode(out, in, is_xx)
  115.  
  116.     writes(out, "end\n")
  117.  
  118.     every close(in|out)
  119.     exit(0)
  120.  
  121. end
  122.  
  123.  
  124.  
  125. procedure encode(out, in, is_xx)
  126.  
  127.     # Copy from in to standard output, encoding as you go along.
  128.  
  129.     local line
  130.  
  131.     if \is_xx then
  132.     ENC := xxENC
  133.  
  134.     # 1 (up to) 45 character segment
  135.     while line := reads(in, 45) do {
  136.     writes(out, ENC(*line))
  137.     line ? {
  138.         while outdec(move(3), out)
  139.         pos(0) | outdec(left(tab(0), 3, " "), out)
  140.     }
  141.     writes(out, "\n")
  142.     }
  143.     # Uuencode adds a space and newline here, which is decoded later
  144.     # as a zero-length line (signals the end of the decoded text).
  145.     # writes(" \n")
  146.     # The new BSD code (compatible with the old) avoids outputting
  147.     # spaces by writing a ` (see also how it handles ENC() below).
  148.     if \is_xx
  149.     then writes(out, "+\n")
  150.     else writes(out, "`\n")
  151.     
  152. end
  153.  
  154.  
  155.  
  156. procedure outdec(s, out)
  157.  
  158.     # Output one group of 3 bytes (s) to standard output.  This is one
  159.     # case where C is actually more elegant than Icon.  Note well!
  160.  
  161.     local c1, c2, c3, c4
  162.  
  163.     c1 := ishift(ord(s[1]),-2)
  164.     c2 := ior(iand(ishift(ord(s[1]),+4), 8r060),
  165.           iand(ishift(ord(s[2]),-4), 8r017))
  166.     c3 := ior(iand(ishift(ord(s[2]),+2), 8r074),
  167.           iand(ishift(ord(s[3]),-6), 8r003))
  168.     c4 := iand(ord(s[3]),8r077)
  169.     every writes(out, ENC(c1 | c2 | c3 | c4))
  170.  
  171.     return
  172.  
  173. end
  174.  
  175.  
  176.  
  177. procedure ENC(c)
  178.  
  179.     # ENC is the basic 1 character encoding procedure to make a char
  180.     # printing.
  181.  
  182.     # New BSD code doesn't output spaces...
  183.     return " " ~== char(iand(c, 8r077) + 32) | "`"
  184.     # ...the way the old code does:
  185.     # return char(iand(c, 8r077) + 32)
  186.  
  187. end
  188.  
  189.  
  190.  
  191. procedure xxENC(c)
  192.  
  193.     # ENC is the basic 1 character encoding procedure to make a char
  194.     # printing.
  195.  
  196.     local k, ordval
  197.     static ordtbl
  198.     initial {
  199.     ordval := -1
  200.     ordtbl := table()
  201.     every k := !"+-0123456789ABCDEFGHIJKLMNOPQRST_
  202.              UVWXYZabcdefghijklmnopqrstuvwxyz"
  203.     do insert(ordtbl, ordval +:= 1, k)
  204.     oversizes := 0
  205.     }
  206.  
  207.     return ordtbl[iand(c, 8r077)]
  208.  
  209. end
  210.