home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1427 < prev    next >
Internet Message Format  |  1990-12-28  |  29KB

  1. From: jtn@potomac.ads.com (John T. Nelson)
  2. Newsgroups: alt.sources
  3. Subject: ASCIIFY and BINAFY... programs for exchanging binary files...
  4. Message-ID: <8743@potomac.ads.com>
  5. Date: 7 Jun 90 17:22:23 GMT
  6.  
  7.  
  8. Asciify and binafy are a pair of programs for converting arbitrary
  9. format files into ASCII representation for later transmission through
  10. network mailers.  These programs are superior to Binhex, Mcvert, xbin,
  11. et al in that no assumptions are made concerning the type of file being
  12. encoded.  Also, Asciify and Binafy were written with ease of protability
  13. in mind.  A Macintosh port is now underway.
  14.  
  15. I welcome bug reports and suggestions for future improvement of this
  16. program.  I may be reached at kzin!speaker@mimsy.umd.edu or
  17. jtn@potomac.ads.com.
  18.  
  19. unzip here [O  ]-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-
  20.  
  21. echo x - asciify
  22. mkdir asciify
  23. echo x - asciify/asciify.1
  24. sed 's/^x//' >asciify/asciify.1 <<'!Funky!Stuff!'
  25. x.\" @(#)asciify.1 1.0 90/06/1 SMI;
  26. x.TH ASCIIFY 1 "01 June 1990"
  27. x.SH NAME
  28. x.LP
  29. xasciify \- convert file contents into asciified format
  30. x.LP
  31. xbinafy \- convert asciified file back to original format
  32. x.SH SYNOPSIS
  33. x.LP
  34. x.B asciify
  35. x[
  36. x.IR -c
  37. x]
  38. x.IR file
  39. x[ 
  40. x.IR asciified_file
  41. x]
  42. x.LP
  43. x.B binafy
  44. x.IR asciified_file
  45. x[
  46. x.IR file
  47. x]
  48. x
  49. x.SH DESCRIPTION
  50. x.LP
  51. x.B Asciify
  52. xand
  53. x.B binafy
  54. xare a pair of programs for converting arbitrary format files into
  55. xASCII representation for later transmission through network mailers.
  56. xThis program is superior to Binhex, Mcvert, xbin, et al in that
  57. xno assumptions have been made concerning the type of file being encoded.
  58. xAlso, asciify and binafy were written for ease of porting
  59. xbetween different machine architectures and thus facilitating
  60. xa common interchange standard for files of any format.
  61. x
  62. xI believe this calls for some diabolical laughter...  MWWAHHA HAH HAW
  63. xHA HA HA HA!!!
  64. x
  65. x.nf
  66. x.LP
  67. xHere's what an asciified file looks like:
  68. x
  69. x(This file must be decoded with Binafy)
  70. x!Asciify Version 1.00!File t!Chk!
  71. x7)GI;9*N*'3[;X7T*(+W>H[K=H>B:I+K;XCV$BK+=D#V<(6B;H_T;9/V*(_H*)3J!4327!
  72. x;4#P<8?J?"J,7XCC?$#K=8WQ>I3C=$#J:8[F*(_T*(7[;2J,2X_W=(2B;I+C=86B!4161!
  73. x .
  74. x .
  75. x .
  76. x?(C[*(;G:9+H?8RB>YGO=87V>IFa$d!2125!
  77. x!!
  78. x.fi
  79. x
  80. xAnything outside the parenthetical line and the final bangs are ignored.
  81. xAnything following the bang on each line is a checksum, used for error
  82. xdetection.  Unlike Binhex, the binafy program will tell you which line
  83. xhad a checksum error if one occurs, although there isn't much that the
  84. xprogram can do to correct the error.
  85. x
  86. x.SH USING ASCIIFY
  87. x.LP
  88. xThe command line...
  89. x.IP
  90. x.B
  91. xexample% asciify binary_file asciified_file
  92. x.LP
  93. xconverts binary_file into the
  94. x.B
  95. xasciify
  96. xformat and puts it into file
  97. x.B
  98. xasciified_file.
  99. xIf no target file is specified then the output is placed onto
  100. xstandard output.
  101. x
  102. xThe command line...
  103. x.IP
  104. x.B
  105. xexample% binafy asciified_file file
  106. x.LP
  107. xconverts the asciified format file into its original format
  108. xand places it in
  109. x.B
  110. xfile.
  111. x
  112. xIf no target file is specified then the output is placed onto
  113. xstandard output so in the case of binafy you'll want to redirect output
  114. xsomeplace.  For example:
  115. x.IP
  116. x.B
  117. xexample% binafy asciified_file > file
  118. x
  119. x.SH "SEE ALSO"
  120. x.BR binafy (1),
  121. x
  122. x.SH HOW IT WORKS
  123. x.LP
  124. xThree bytes of the original file are read and converted into 4
  125. xcharacters representing 6 bits each of the original 3 bytes.  Note that
  126. x6 divides into 12 ( 3 bytes times 8 bits per byte) quite evenly.  The 64
  127. xcharacters of the ASCII character set starting with the double quote
  128. x(hex 22) character are used.  The exclamation point character is
  129. xreserved as a special delimeter.
  130. x
  131. xNote that we have used only 64 of the 94 some printable characters.
  132. x
  133. xIn case the number of bytes in a file is not evenly divisible by 3, a
  134. xspecial encoding is used to represent the remaining piece of the byte.
  135. xThe remaining pieces can be either 2 bits or 4 bits and thus consume 20
  136. xmore ASCII printable characters.  Because these characters are unique in
  137. xthe encoding we will know when the end of a file has arrived and, more
  138. ximportantly, we will know what these characters represent because they
  139. xare outside of the main encoding scheme.
  140. x
  141. xThis encoding scheme yields a 4 for 3 decompression which I consider to
  142. xbe fairly effecient.
  143. x
  144. x.SH INSTALLATION
  145. x.LP
  146. xJust type
  147. x.B make asciify
  148. xto build
  149. x.B asciify
  150. xand
  151. x.B make binafy
  152. xto build
  153. x.B binafy
  154. x
  155. xBoth should compile and generate binaries called
  156. x.B asciify
  157. xand
  158. x.B binafy
  159. xrespectively.
  160. x
  161. x.SH FUTURE ENHANCEMENTS
  162. x.LP
  163. xSupport binafying of multipart files.  It's simple enough
  164. xto split files apart with the Unix "split" program.  It would
  165. xbe nice if asciify and binafy split and assembled multiple files
  166. xautomagically.  Note that the above example has a "part of" spec in the
  167. xheader.  That's how binafy will know what order to assemble the files
  168. xin.
  169. x
  170. xThe file format is incompatible with Binhex and uuencode/uudecode
  171. xformats.  I should probably provide compatibility and cross-conversion
  172. xfor these too, but since I can't find their source code you'll just
  173. xhave to use
  174. x.B asciify
  175. xformat for now.
  176. x
  177. xMagic strings.
  178. x
  179. x.SH BUGS
  180. x.LP
  181. xThe ANSI C standard actually makes no assumptions concerning
  182. xthe size of a character or byte, therefore this program will
  183. xprobably do the wrong thing on machines with 13-bit bytes.
  184. xThis should not be an immediate concern as most machines use 8 bit
  185. xbytes.
  186. x
  187. xAlso note that I have avoided the use of the fscanf/sscanf whenever
  188. xpossible.  This is because the behavior of these library routines
  189. xvaries from implementation to implementation.
  190. x
  191. x.SH AUTHOR
  192. x.LP
  193. x.nf
  194. x=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  195. xORGANIZATION:  Kzinti Embassy              GEOGRAPHIC: McLean, VA
  196. xUUCP:          kzin!speaker@mimsy.umd.edu  INTERNET:   jtn@potomac.ads.com
  197. xSPOKEN:        Hey Stupid Cat!             PHONE:      (703) 356-6514
  198. xPROJECT:       The Conrail Locomotive/Harpsichord Fusion Program
  199. x=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  200. x.fi
  201. !Funky!Stuff!
  202. echo x - asciify/DOC
  203. cat >asciify/DOC <<'!Funky!Stuff!'
  204.  
  205.  
  206.  
  207. ASCIIFY(1)               USER COMMANDS                 ASCIIFY(1)
  208.  
  209.  
  210.  
  211. NAME
  212.      asciify - convert file contents into asciified format
  213.  
  214.      binafy - convert asciified file back to original format
  215.  
  216. SYNOPSIS
  217.      asciify [ -_c ] _f_i_l_e [ _a_s_c_i_i_f_i_e_d__f_i_l_e ]
  218.  
  219.      binafy _a_s_c_i_i_f_i_e_d__f_i_l_e [ _f_i_l_e ]
  220.  
  221.  
  222. DESCRIPTION
  223.      Asciify and binafy are a pair  of  programs  for  converting
  224.      arbitrary  format  files into ASCII representation for later
  225.      transmission through network mailers.  This program is supe-
  226.      rior  to  Binhex, Mcvert, xbin, et al in that no assumptions
  227.      have been made concerning the type of  file  being  encoded.
  228.      Also,  asciify  and  binafy were written for ease of porting
  229.      between different machine architectures and thus  facilitat-
  230.      ing a common interchange standard for files of any format.
  231.  
  232.      I  believe  this  calls  for  some  diabolical   laughter...
  233.      MWWAHHA HAH HAW HA HA HA HA!!!
  234.  
  235.  
  236.      Here's what an asciified file looks like:
  237.  
  238.      (This file must be decoded with Binafy)
  239.      !Asciify Version 1.00!File t!Chk!
  240.      7)GI;9*N*'3[;X7T*(+W>H[K=H>B:I+K;XCV$BK+=D#V<(6B;H_T;9/V*(_H*)3J!4327!
  241.      ;4#P<8?J?"J,7XCC?$#K=8WQ>I3C=$#J:8[F*(_T*(7[;2J,2X_W=(2B;I+C=86B!4161!
  242.       .
  243.       .
  244.       .
  245.      ?(C[*(;G:9+H?8RB>YGO=87V>IFa$d!2125!
  246.      !!
  247.  
  248.      Anything outside the parenthetical line and the final  bangs
  249.      are  ignored.  Anything following the bang on each line is a
  250.      checksum, used for  error  detection.   Unlike  Binhex,  the
  251.      binafy program will tell you which line had a checksum error
  252.      if one occurs, although there isn't much  that  the  program
  253.      can do to correct the error.
  254.  
  255.  
  256. USING ASCIIFY
  257.      The command line...
  258.  
  259.           example% asciify binary_file asciified_file
  260.  
  261.      converts binary_file into the asciify  format  and  puts  it
  262.      into  file  asciified_file.   If no target file is specified
  263.  
  264.  
  265.  
  266. Sun Release 4.0     Last change: 01 June 1990                   1
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273. ASCIIFY(1)               USER COMMANDS                 ASCIIFY(1)
  274.  
  275.  
  276.  
  277.      then the output is placed onto standard output.
  278.  
  279.      The command line...
  280.  
  281.           example% binafy asciified_file file
  282.  
  283.      converts the asciified format file into its original  format
  284.      and places it in file.
  285.  
  286.      If no target file is specified then  the  output  is  placed
  287.      onto standard output so in the case of binafy you'll want to
  288.      redirect output someplace.  For example:
  289.  
  290.           example% binafy asciified_file > file
  291.  
  292.  
  293. SEE ALSO
  294.      binafy(1),
  295.  
  296.  
  297. HOW IT WORKS
  298.      Three bytes of the original file are read and converted into
  299.      4  characters  representing  6  bits  each of the original 3
  300.      bytes.  Note that 6 divides into 12 ( 3 bytes times  8  bits
  301.      per  byte)  quite  evenly.   The  64 characters of the ASCII
  302.      character set starting with the double quote (hex 22)  char-
  303.      acter are used.  The exclamation point character is reserved
  304.      as a special delimeter.
  305.  
  306.      Note that we have used only 64  of  the  94  some  printable
  307.      characters.
  308.  
  309.      In case the number of bytes in a file is not evenly  divisi-
  310.      ble  by  3,  a  special  encoding  is  used to represent the
  311.      remaining piece of the byte.  The remaining  pieces  can  be
  312.      either  2  bits  or  4  bits  and thus consume 20 more ASCII
  313.      printable characters.  Because these characters  are  unique
  314.      in  the  encoding  we  will  know when the end of a file has
  315.      arrived and, more importantly, we will know what these char-
  316.      acters represent because they are outside of the main encod-
  317.      ing scheme.
  318.  
  319.      This encoding scheme yields a 4 for 3 decompression which  I
  320.      consider to be fairly effecient.
  321.  
  322.  
  323. INSTALLATION
  324.      Just type make asciify to build asciify and make  binafy  to
  325.      build binafy
  326.  
  327.      Both should compile and generate binaries called asciify and
  328.      binafy respectively.
  329.  
  330.  
  331.  
  332. Sun Release 4.0     Last change: 01 June 1990                   2
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339. ASCIIFY(1)               USER COMMANDS                 ASCIIFY(1)
  340.  
  341.  
  342.  
  343. FUTURE ENHANCEMENTS
  344.      Support binafying of multipart files.  It's simple enough to
  345.      split  files  apart with the Unix "split" program.  It would
  346.      be nice if asciify could assemble multiple  files  automagi-
  347.      cally.   Note that the above example has a "part of" spec in
  348.      the header.  That's how  binafy  will  know  what  order  to
  349.      assemble the files in.
  350.  
  351.      The  file   format   is   incompatible   with   Binhex   and
  352.      uuencode/uudecode formats.  I should probably provide compa-
  353.      tibility and cross-conversion for these  too,  but  since  I
  354.      can't find their source code you'll just have to use asciify
  355.      format for now.
  356.  
  357.      Magic strings.
  358.  
  359.  
  360. BUGS
  361.      The ANSI C standard actually makes no assumptions concerning
  362.      the size of a character or byte, therefore this program will
  363.      probably do the wrong thing on machines with  13-bit  bytes.
  364.      This should not be an immediate concern as most machines use
  365.      8 bit bytes.
  366.  
  367.      Also note that I have avoided the use of  the  fscanf/sscanf
  368.      whenever  possible.   This  is because the behavior of these
  369.      library routines varies from implementation  to  implementa-
  370.      tion.
  371.  
  372.  
  373. AUTHOR
  374.      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  375.      ORGANIZATION:  Kzinti Embassy              GEOGRAPHIC: McLean, VA
  376.      UUCP:          kzin!speaker@mimsy.umd.edu  INTERNET:   jtn@potomac.ads.com
  377.      SPOKEN:        Hey Stupid Cat!             PHONE:      (703) 356-6514
  378.      PROJECT:       The Conrail Locomotive/Harpsichord Fusion Program
  379.      =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398. Sun Release 4.0     Last change: 01 June 1990                   3
  399.  
  400.  
  401.  
  402. !Funky!Stuff!
  403. echo x - asciify/Makefile
  404. cat >asciify/Makefile <<'!Funky!Stuff!'
  405. all: asciify binafy
  406.  
  407. asciify: asciify.c globals.c asciifyCore.c definitions.h globals.h Makefile
  408.     cc asciify.c globals.c asciifyCore.c -o asciify
  409.  
  410. binafy: binafy.c globals.c binafyCore.c definitions.h globals.h Makefile
  411.     cc binafy.c globals.c binafyCore.c -o binafy
  412.  
  413. clean:
  414.     rm -f *.o asciify binafy core #*
  415. !Funky!Stuff!
  416. echo x - asciify/README
  417. cat >asciify/README <<'!Funky!Stuff!'
  418. Asciify and binafy are a pair of programs for converting arbitrary
  419. format files into ASCII representation for later transmission through
  420. network mailers.  These programs are superior to Binhex, Mcvert, xbin,
  421. et al in that no assumptions are made concerning the type of file being
  422. encoded.  Also, Asciify and Binafy were written with ease of protability
  423. in mind.  A Macintosh port is now underway.
  424.  
  425. I welcome bug reports and suggestions for future improvement of this
  426. program.  I may be reached at kzin!speaker@mimsy.umd.edu or
  427. jtn@potomac.ads.com.
  428.  
  429.  
  430. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  431. ORGANIZATION:  Advanced Decision Systems   GEOGRAPHIC: Arlington, VA
  432. UUCP:          kzin!speaker@mimsy.umd.edu  INTERNET:   jtn@potomac.ads.com
  433. SPOKEN:        Yo... John!                 PHONE:      (703) 243-1611
  434. PROJECT:       The Conrail Locomotive/Harpsichord Fusion Program
  435. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  436. !Funky!Stuff!
  437. echo x - asciify/asciify.c
  438. cat >asciify/asciify.c <<'!Funky!Stuff!'
  439. #include <stdio.h>
  440. #include <fcntl.h>
  441. #include "definitions.h"
  442. #include "globals.h"
  443.  
  444. /*
  445.     This is "asciify", a program for converting files of arbitrary
  446.     format into an ASCII encoding for later transmission through network
  447.     mailers.  The program "binafy" should be used to convert the ASCII
  448.     encoding back into the original file.
  449.  
  450.     Usage: asciify [ -c ] <original file> [ <asciified file> ]
  451.  
  452.     -- John T. Nelson (a.k.a. Speaker-To-Animals) mimsy!kzin!speaker
  453. */
  454.  
  455. BOOLEAN parseFlags(argv)
  456. char    *argv[];
  457. {
  458. char            *s;
  459. unsigned int    k;
  460.  
  461. if ( *argv[0] == '-' ) {
  462.     k = 1;
  463.     header.useCheck = FALSE;
  464.     for ( s = argv[0] + 1; *s != '\0'; s++ ) {
  465.         switch ( *s ) {
  466.             case 'c':
  467.                 header.useCheck = TRUE;
  468.                 break;
  469.             }
  470.         k++;
  471.         }
  472.     return TRUE;
  473.     }
  474. else
  475.     return FALSE;
  476. }
  477.  
  478. main(argc, argv)
  479. int        argc;
  480. char *argv[];
  481. {
  482. int            fi;
  483. FILE        *fo;
  484.  
  485. unsigned int    counter;
  486. int                status;
  487.  
  488. if ( argc == 1 ) {
  489.     printf("Usage: asciify [ -c ] <original file> <target file>\n");
  490.     return;
  491.     }
  492. argv++;
  493. if ( argc == 2 ) {
  494.     if ( *argv[0] == '-' ) {
  495.         printf("Usage: asciify [ -c ] <original file> <target file>\n");
  496.         return;
  497.         }
  498.     else {
  499.         fi = open( *argv, O_RDONLY);
  500.         fo = stdout;
  501.         strcpy(header.fileName, "stdout");
  502.         }
  503.     }
  504.  
  505. if ( argc == 3 )
  506.     if ( parseFlags(argv) ) {
  507.         argv++;
  508.         fi = open( *argv, O_RDONLY);
  509.         fo = stdout;
  510.         strcpy(header.fileName, "stdout");
  511.         }
  512.     else {
  513.         fi = open( *argv, O_RDONLY);
  514.         argv++;
  515.         fo = fopen(*argv, "w");
  516.         strcpy(header.fileName, *argv);
  517.         }
  518.  
  519. if ( argc == 4 )
  520.     if ( parseFlags(argv) ) {
  521.         argv++;
  522.         fi = open( *argv, O_RDONLY);
  523.         argv++;
  524.         fo = fopen(*argv, "w");
  525.     strcpy(header.fileName, *argv);
  526.         }
  527.     else {
  528.         printf("More than 2 file names - I'm quiting\n");
  529.         return;
  530.         }
  531.  
  532. if ( argc > 4 ) {
  533.     printf("More than 2 file names - I'm quiting\n");
  534.     return;
  535.     }
  536.  
  537. asciify(fi, fo);
  538. }
  539. !Funky!Stuff!
  540. echo x - asciify/asciifyCore.c
  541. cat >asciify/asciifyCore.c <<'!Funky!Stuff!'
  542. #include <stdio.h>
  543. #include <fcntl.h>
  544. #include "definitions.h"
  545. #include "globals.h"
  546.  
  547. asciify(fi, fo)
  548. int    fi;
  549. FILE    *fo;
  550. {
  551. unsigned int    counter;
  552. int                status;
  553.  
  554. num = 0;
  555. cur = buffer;
  556.  
  557. putHerald(fo);
  558.  
  559. counter = 0;
  560. status = 0;
  561.  
  562. while ( status != EOF ) {
  563.     status = convertThree(fi, fo, header.useCheck);
  564.     fflush(fo);
  565.     }
  566.  
  567. fputc(DELIMETER, fo);
  568. fputc(DELIMETER, fo);
  569. fprintf(fo, "\n");
  570. fflush(fo);
  571.  
  572. close(fi);
  573. fclose(fo);
  574. }
  575.  
  576. errorCleanup(fi, fo)
  577. int        fi;
  578. FILE    *fo;
  579. {
  580. close(fi);
  581. fclose(fo);
  582. }
  583.  
  584. /* No... don't look!  It's EVIL! */
  585.  
  586. convertThree(fi, fo, check)
  587. int        fi;
  588. FILE    *fo;
  589. BOOLEAN    check;
  590. {
  591. int                status;
  592. unsigned int    i;
  593. char            byte1, byte2, byte3;
  594. char            c;
  595. unsigned int    checksum;
  596.  
  597. i = 1;
  598. checksum = 0;
  599. status = SUCCESS;
  600.  
  601. while (i < LINE_LENGTH && status != EOF) {
  602.     status = getAbyte(fi, &byte1);
  603.     if ( status == EOF ) {
  604.         break;
  605.         }
  606.     checksum = checksum + (unsigned char) byte1;
  607.     convert1(&byte1, &c);
  608.     fputc(c, fo);
  609.     i++;
  610.  
  611.     status = getAbyte(fi, &byte2);
  612.     if ( status == EOF ) {
  613.         putShortTwo(fo, byte1);
  614.         break;
  615.         }
  616.     checksum = checksum + (unsigned char) byte2;
  617.     convert2(&byte1, &byte2, &c);
  618.     fputc(c, fo);
  619.     i++;
  620.  
  621.     status = getAbyte(fi, &byte3);
  622.     if ( status == EOF ) {
  623.         putShortFour(fo, byte2);
  624.         break;
  625.         }
  626.     checksum = checksum + (unsigned char) byte3;
  627.     convert3(&byte2, &byte3, &c);
  628.     fputc(c, fo);
  629.     i++;
  630.  
  631.     convert4(&byte3, &c);
  632.     fputc(c, fo);
  633.  
  634.     i++;
  635.     byte1 = 0;
  636.     byte2 = 0;
  637.     byte3 = 0;
  638.     }
  639.  
  640. if ( i == 1 )
  641.     return EOF;
  642.  
  643. putCheckSum(fo, checksum, check);
  644.  
  645. return status;
  646. }
  647.  
  648. putCheckSum(fo, checksum, check)
  649. FILE            *fo;
  650. unsigned int    checksum;
  651. BOOLEAN            check;
  652. {
  653. if ( checksum < 0 )
  654.     check = check;
  655. if ( check == YES )
  656.     fprintf(fo,"%c%u%c\n", DELIMETER, checksum, DELIMETER);
  657. else {
  658.     fputc(DELIMETER, fo);
  659.     fputc('\n', fo);
  660.     }
  661. }
  662.  
  663. convert1(b1, c)
  664. char    *c;
  665. char    *b1;
  666. {
  667. char    byte;
  668.  
  669. byte = *b1;
  670.  
  671. byte &= UPPER_SIX_BITS;
  672. byte = byte >> 2;
  673. byte &= LOWER_SIX_BITS;
  674. byte += CODING_START;
  675.  
  676. *c = byte;
  677. return SUCCESS;
  678. }
  679.  
  680. convert2(b1, b2, c)
  681. char    *c;
  682. char    *b1, *b2;
  683. {
  684. char    byte1;
  685. char    byte2;
  686.  
  687. byte1 = *b1;
  688. byte2 = *b2;
  689.  
  690. byte1 &= LOWER_TWO_BITS;
  691. byte2 &= UPPER_FOUR_BITS;
  692.  
  693. byte1 = byte1 << 4;
  694. byte2 = byte2 >> 4;
  695.  
  696. byte1 &= 0x30;
  697. byte2 &= LOWER_FOUR_BITS;
  698.  
  699. byte1 |= byte2;
  700. byte1 &= LOWER_SIX_BITS;
  701. byte1 += CODING_START;
  702.  
  703. *c = byte1;
  704. return SUCCESS;
  705. }
  706.  
  707. convert3(b2, b3, c)
  708. char    *c;
  709. char    *b2, *b3;
  710. {
  711. char    byte2;
  712. char    byte3;
  713.  
  714. byte2 = *b2;
  715. byte3 = *b3;
  716.  
  717. byte2 &= LOWER_FOUR_BITS;
  718. byte3 &= UPPER_TWO_BITS;
  719.  
  720. byte2 = byte2 << 2;
  721. byte3 = byte3 >> 6;
  722.  
  723. byte2 &= 0x3C;
  724. byte3 &= LOWER_TWO_BITS;
  725.  
  726. byte2 |= byte3;
  727. byte2 &= LOWER_SIX_BITS;
  728. byte2 += CODING_START;
  729.  
  730. *c = byte2;
  731. return SUCCESS;
  732. }
  733.  
  734. convert4(b3, c)
  735. char    *c;
  736. char    *b3;
  737. {
  738. char    byte3;
  739.  
  740. byte3 = *b3;
  741. byte3 &= LOWER_SIX_BITS;
  742. byte3 += CODING_START;
  743.  
  744. *c = byte3;
  745. return SUCCESS;
  746. }
  747.  
  748. processChecksum()
  749. {
  750. }
  751.  
  752. getAbyte(fi, c)
  753. int        fi;
  754. char    *c;
  755. {
  756. if ( num == 0 ) {
  757.     num = read(fi, buffer, BUFFER_SIZE);
  758.     if ( num == 0 || num == EOF )
  759.         return EOF;
  760.     cur = buffer;
  761.     }
  762. *c = *cur;
  763. cur += 1;
  764. num -= 1;
  765.  
  766. return SUCCESS;
  767. }
  768.  
  769. putShortTwo(fo, b)
  770. FILE    *fo;
  771. char    b;
  772. {
  773. char    byte;
  774.  
  775. byte = b;
  776. byte &= LOWER_TWO_BITS;
  777. byte += START_TWO;
  778. fputc(byte, fo);
  779. }
  780.  
  781. putShortFour(fo, b)
  782. FILE    *fo;
  783. char    b;
  784. {
  785. char    byte;
  786.  
  787. byte = b;
  788. byte &= LOWER_FOUR_BITS;
  789. byte += START_FOUR;
  790. fputc(byte, fo);
  791. }
  792.  
  793. putHerald(fo)
  794. FILE    *fo;
  795. {
  796. fprintf(fo, "\n%s", HERALD);
  797.  
  798. fputc(DELIMETER, fo);
  799. fprintf(fo, VERSION_STRING, VERSION_NUM);
  800.  
  801. fputc(DELIMETER, fo);
  802. fprintf(fo, FILE_STRING,  header.fileName);
  803.  
  804. if ( header.useCheck == YES ) {
  805.     fputc(DELIMETER, fo);
  806.     fprintf(fo, CHECKSUM_STRING);
  807.     }
  808. fputc(DELIMETER, fo);
  809. fprintf(fo, "\n");
  810. }
  811. !Funky!Stuff!
  812. echo x - asciify/binafy.c
  813. cat >asciify/binafy.c <<'!Funky!Stuff!'
  814. #include <stdio.h>
  815. #include <fcntl.h>
  816. #include "definitions.h"
  817. #include "globals.h"
  818.  
  819. /*
  820.     This is "binafy", a program for converting "asciified" files
  821.     back into their original file formats.
  822.  
  823.     Usage: binafy <asciified file> <original file>
  824.  
  825.     -- John T. Nelson (a.k.a. Speaker-To-Animals) mimsy!kzin!speaker
  826. */
  827.  
  828. main(argc, argv)
  829. int    argc;
  830. char    *argv[];
  831. {
  832. FILE    *fi;
  833. int        fo;
  834.  
  835. if ( argc == 1 ) {
  836.     printf("Usage: binafy <asciify'd file> <original file>\n");
  837.     return;
  838.     }
  839. if ( argc == 2 ) {
  840.     fo = STANDARD_OUTPUT_FD;            /* Assume the shmuck knows what he wants */
  841.     }
  842. if ( argc == 2  || argc == 3) {
  843.     argv++;
  844.     fi = fopen( *argv, "r");
  845.     }
  846. if ( argc == 3 ) {
  847.     argv++;
  848. #ifndef THINK_C
  849.     fo = open(*argv, O_WRONLY | O_CREAT, 0640);
  850. #else
  851.     fo = open(*argv, O_WRONLY | O_CREAT);
  852. #endif
  853.     }
  854. if ( argc > 3 ) {
  855.     printf("More than 2 arguments - I'm quiting\n");
  856.     return;
  857.     }
  858.  
  859. binafy(fi, fo);
  860. }
  861. !Funky!Stuff!
  862. echo x - asciify/binafyCore.c
  863. cat >asciify/binafyCore.c <<'!Funky!Stuff!'
  864. #include <stdio.h>
  865. #include <fcntl.h>
  866. #include "definitions.h"
  867. #include "globals.h"
  868.  
  869. binafy(fi, fo)
  870. FILE    *fi;
  871. int    fo;
  872. {
  873.  
  874. num = -1;
  875. header.line = 1;
  876.  
  877. if ( flushHerald(fi) == FAILURE ) {
  878.     fclose(fi);
  879.     close(fo);
  880.     exit();
  881.     }
  882.  
  883. if ( readHeader(fi, header.header) == FAILURE ) {
  884.     fclose(fi);
  885.     close(fo);
  886.     exit();
  887.     }
  888.  
  889. parseHeader(&header);
  890.  
  891. if ( header.useCheck == YES )
  892.     processWithChecksums(fi, fo);
  893. else
  894.     processWithoutChecksums(fi, fo);
  895.  
  896. fclose(fi);
  897. flushBuffer(fo);
  898. close(fo);
  899. }
  900.  
  901. processWithChecksums(fi, fo)
  902. int        fi;
  903. FILE    *fo;
  904. {
  905. int                status;
  906.  
  907. status = SUCCESS;
  908.  
  909. while ( status != EOF ) {
  910.     status = processLine(fi, fo, &header);
  911.     if ( status == FAILURE )
  912.         return;
  913.     if ( checkChecksum(header) == FAILURE ) {
  914.         printf("Checksum error detected on line %d!\n", header.line);
  915.         return;
  916.         }
  917.     header.line += 1;
  918.     }
  919. }
  920.  
  921. processWithoutChecksums(fi, fo)
  922. int        fi;
  923. FILE    *fo;
  924. {
  925. int                status;
  926.  
  927. status = SUCCESS;
  928.  
  929. while ( status != EOF ) {
  930.     status = processLine(fi, fo, &header);
  931.     if ( status == FAILURE )
  932.         return;
  933.     header.line += 1;
  934.     }
  935. }
  936.  
  937. processLine(fi, fo, header)
  938. FILE            *fi;
  939. int                fo;
  940. struct HEADER_STRUCT    *header;
  941. {
  942. char            string[NUM_DATA_CHARS];
  943. char            errorChars[NUM_CHECKSUM_CHARS];
  944. unsigned int    i;
  945. unsigned int    lastChar;
  946. unsigned int    checksum;
  947.  
  948. char        byte1;
  949. char        byte2;
  950. char        byte3;
  951. int            status;
  952.  
  953. switch ( collectStrings(fi, string, errorChars) ) {
  954.     case SUCCESS:
  955.         break;
  956.     case FAILURE:
  957.         return FAILURE;
  958.     case DOUBLE_DELIMS:
  959.         return EOF;
  960.     default:
  961.         return FAILURE;
  962.     };
  963.  
  964. i = 0;
  965. checksum = 0;
  966.  
  967. lastChar = strlen(string) - 1;
  968. convertToNumber(errorChars, &(header -> checksumRead));
  969.  
  970. while( i <= lastChar ) {
  971.     if ( string[i] == DELIMETER ) {
  972.         header -> checksum = checksum;
  973.         return SUCCESS;
  974.         }
  975.  
  976.     status = SUCCESS;
  977.     status = convert1(string[i], &byte1);
  978.     if ( status == TRAILING_CHARS ) {
  979.         printf("Byte 1 started with a short byte!\n");
  980.         return FAILURE;
  981.         }
  982.     i++;
  983.     status = convert2(string[i], &byte1, &byte2);
  984.     if ( status == TRAILING_FOUR ) {
  985.         printf("Byte 1 decoded 4 bits not 2!\n");
  986.         return FAILURE;
  987.         }
  988.     checksum += (unsigned char) byte1;
  989.     if ( status == TRAILING_TWO ) {
  990.         putAchar(byte1, fo);
  991.         status = EOF;
  992.         break;
  993.         }
  994.     putAchar(byte1, fo);
  995.     i++;
  996.     status = convert3(string[i], &byte2, &byte3);
  997.     if ( status == TRAILING_TWO ) {
  998.         printf("Byte 2 decoded 2 bits not 4!\n");
  999.         return FAILURE;
  1000.         }
  1001.     checksum += (unsigned char) byte2;
  1002.     if ( status == TRAILING_FOUR ) {
  1003.         putAchar(byte2, fo);
  1004.         status = EOF;
  1005.         break;
  1006.         }
  1007.     putAchar(byte2, fo);
  1008.     i++;
  1009.     status = convert4(string[i], &byte3);
  1010.     if ( status == TRAILING_CHARS ) {
  1011.         printf("Byte 3 had a short byte!\n");
  1012.         return FAILURE;
  1013.         }
  1014.     putAchar(byte3, fo);
  1015.     checksum += (unsigned char) byte3;
  1016.     i++;
  1017.     byte1 = 0;
  1018.     byte2 = 0;
  1019.     byte3 = 0;
  1020.     }
  1021.  
  1022. header -> checksum = checksum;
  1023. return SUCCESS;
  1024. }
  1025.  
  1026. convert1(c, b1)
  1027. char    c;
  1028. char    *b1;
  1029. {
  1030. char    byte;
  1031.  
  1032. if ( c >= SHORT_START )
  1033.     return TRAILING_CHARS;
  1034.  
  1035. byte = c - CODING_START;
  1036. byte = byte << 2;
  1037. byte &= UPPER_SIX_BITS;
  1038.  
  1039. *b1 = byte;
  1040. return SUCCESS;
  1041. }
  1042.  
  1043. convert2(c, b1, b2)
  1044. char    c;
  1045. char    *b1, *b2;
  1046. {
  1047. char    byte1;
  1048. char    byte2;
  1049. char    byte;
  1050. char    cc;
  1051.  
  1052. if ( c >= START_FOUR )
  1053.     return TRAILING_FOUR;
  1054.  
  1055. byte1 = *b1;
  1056. if ( c >= START_TWO && c < START_FOUR ) {
  1057.     byte = c - SHORT_START;
  1058.     byte1 |= byte;
  1059.     *b1 = byte1;
  1060.     return TRAILING_TWO;
  1061.     }
  1062.  
  1063. cc = c - CODING_START;
  1064. byte = cc >> 4;                /* Extract the upper 2 bits */
  1065. byte &= LOWER_TWO_BITS;
  1066. byte1 |= byte;
  1067.  
  1068. byte = cc << 4;                /* The lower 4 bits */
  1069. byte2 = byte & UPPER_FOUR_BITS;
  1070.  
  1071. *b1 = byte1;
  1072. *b2 = byte2;
  1073. return SUCCESS;
  1074. }
  1075.  
  1076. convert3(c, b2, b3)
  1077. char    c;
  1078. char    *b2, *b3;
  1079. {
  1080. char    byte2;
  1081. char    byte3;
  1082. char    byte;
  1083. char    cc;
  1084.  
  1085. if ( c < START_FOUR  && c >= SHORT_START )
  1086.     return TRAILING_TWO;
  1087.  
  1088. byte2 = *b2;
  1089. if ( c >= START_FOUR && c <= SHORT_STOP ) {
  1090.     byte = c - (SHORT_START + MASK_TWO);
  1091.     byte2 |= byte;
  1092.     *b2 = byte2;
  1093.     return TRAILING_FOUR;
  1094.     }
  1095.  
  1096. cc = c - CODING_START;
  1097. byte = cc >> 2;                /* Extract the upper 4 bits */
  1098. byte &= LOWER_FOUR_BITS;
  1099. byte2 |= byte;
  1100.  
  1101. byte = cc << 6;                /* The lower 2 bits */
  1102. byte3 = byte & UPPER_TWO_BITS;
  1103.  
  1104. *b2 = byte2;
  1105. *b3 = byte3;
  1106. return SUCCESS;
  1107. }
  1108.  
  1109. convert4(c, b3)
  1110. char    c;
  1111. char    *b3;
  1112. {
  1113. char    byte3;
  1114. char    byte;
  1115.  
  1116. byte3 = SHORT_START;
  1117.  
  1118. if ( c >= SHORT_START )
  1119.     return TRAILING_CHARS;
  1120.  
  1121. byte3 = *b3;
  1122. byte = c - CODING_START;
  1123. byte &= LOWER_SIX_BITS;
  1124. byte3 |= byte;
  1125.  
  1126. *b3 = byte3;
  1127. return SUCCESS;
  1128. }
  1129.  
  1130. flushHerald(fi)
  1131. FILE *fi;
  1132. {
  1133. char        string[MAX_LINE_LENGTH];
  1134.  
  1135. while ( fgets(string, MAX_LINE_LENGTH, fi) != NULL ) {
  1136.     header.line++;
  1137.     if ( strcmp(string, HERALD) == 0 )
  1138.         return SUCCESS;
  1139.     }
  1140. printf("Geeze... I didn't even get to the herald!\n");
  1141. return FAILURE;
  1142. }
  1143.  
  1144. readHeader(fi, h)
  1145. FILE     *fi;
  1146. char    *h;
  1147. {
  1148.  
  1149. while ( fgets(h, MAX_LINE_LENGTH, fi) != NULL ) {
  1150.     header.line++;
  1151.     if ( h[0] == DELIMETER )
  1152.         return SUCCESS;
  1153.     }
  1154. printf("Couldn't find the header!\n");
  1155. return FAILURE;
  1156. }
  1157.  
  1158. putAchar(byte, fo)
  1159. char    byte;
  1160. int        fo;
  1161. {
  1162.  
  1163. num++;
  1164. if ( num > BUFFER_SIZE - 1 ) {
  1165.     write(fo, buffer, BUFFER_SIZE);
  1166.     num = 0;
  1167.     }
  1168. buffer[num] = byte;
  1169. }
  1170.  
  1171. flushBuffer(fo)
  1172. int    fo;
  1173. {
  1174. int    n;
  1175.  
  1176. if ( num > BUFFER_SIZE - 1 )
  1177.     num = BUFFER_SIZE;
  1178. else
  1179.     num++;
  1180.  
  1181. while ( num > 0 ) {
  1182.     n = write(fo, buffer, num);
  1183.     num -= n;
  1184.     }
  1185. }
  1186.  
  1187. parseHeader(header)
  1188. struct HEADER_STRUCT    *header;
  1189. {
  1190. char    *s;
  1191. char    h[MAX_LINE_LENGTH];
  1192.  
  1193. s = header -> header;
  1194. header -> useCheck = FALSE;
  1195.  
  1196. if ( *s != DELIMETER ) {
  1197.     printf("Bad header format!\n");
  1198.     return FAILURE;
  1199.     }
  1200. s++;
  1201. while ( *s != '\n' && *s != '\0' ) {
  1202.     if ( headerExtract(&s, h) == FAILURE )
  1203.         return FAILURE;
  1204.     if ( strcmp(h, CHECKSUM_STRING) == 0 )
  1205.         header -> useCheck = TRUE;
  1206.     }
  1207. }
  1208.  
  1209. headerExtract(s, h)
  1210. char    **s;
  1211. char    *h;
  1212. {
  1213.  
  1214. while ( **s == DELIMETER || **s == '\n' ) (*s)++;
  1215.  
  1216. while ( **s != DELIMETER ) {
  1217.     if ( **s == '\0' )
  1218.         return FAILURE;
  1219.  
  1220.     *h = **s;
  1221.     h++;
  1222.     (*s)++;
  1223.     }
  1224. *h = '\0';
  1225. return SUCCESS;
  1226. }
  1227.  
  1228. collectStrings(fi, s, e)
  1229. FILE        *fi;
  1230. char        *s;
  1231. char        *e;
  1232. {
  1233. char        c;
  1234.  
  1235. if ( getAchar(fi, &c) == EOF )
  1236.     return FAILURE;
  1237.  
  1238. while ( c != DELIMETER ) {
  1239.     *s = c;
  1240.     s++;
  1241.     if ( getAchar(fi, &c) == EOF )
  1242.         return FAILURE;
  1243.     }
  1244. *s = '\0';
  1245. if ( getAchar(fi, &c) == EOF )
  1246.     return FAILURE;
  1247. if ( c == DELIMETER && *s == '\0' )
  1248.     return DOUBLE_DELIMS;
  1249. if ( header.useCheck == NO ) {
  1250.     while ( c != '\n' ) {
  1251.         if ( getAchar(fi, &c) == EOF )
  1252.             return FAILURE;
  1253.         }
  1254.     }
  1255. else {
  1256.     if ( c == DELIMETER || c == '\n' ) {
  1257.         printf("So where's the checksum?\n");
  1258.         return FAILURE;
  1259.         }
  1260.     while ( c != DELIMETER ) {
  1261.         *e = c;
  1262.         if ( getAchar(fi, &c) == EOF )
  1263.             return FAILURE;
  1264.         e++;
  1265.         }
  1266.     if ( getAchar(fi, &c) == EOF )
  1267.         return FAILURE;
  1268.     if ( c != '\n' ) {
  1269.         printf("Expected a new-line here\n");
  1270.         return FAILURE;
  1271.         }
  1272.     }
  1273. *e = '\0';
  1274. return SUCCESS;
  1275. }
  1276.  
  1277. checkChecksum(header)
  1278. struct HEADER_STRUCT        header;
  1279. {
  1280. if ( header.checksum != header.checksumRead )
  1281.     return FAILURE;
  1282. else
  1283.     return SUCCESS;
  1284. }
  1285.  
  1286. getAchar(fi, c)
  1287. FILE    *fi;
  1288. char    *c;
  1289. {
  1290. if ( (*c = fgetc(fi)) == EOF ) {
  1291.     printf("Premature EOF encountered\n");
  1292.     return EOF;
  1293.     }
  1294. }
  1295.  
  1296. convertToNumber(errorChars, number)
  1297. char    *errorChars;
  1298. unsigned int    *number;
  1299. {
  1300. int        s;
  1301. int sum, n;
  1302. unsigned int    i;
  1303. char    c;
  1304.  
  1305. s = strlen(errorChars) - 1;
  1306. sum = 0;
  1307. i = 0;
  1308.  
  1309. while ( s >= 0 ) {
  1310.     c = errorChars[s];
  1311.     n = atoi(&c);
  1312.     if ( i == 0 )
  1313.         sum += n;
  1314.     else
  1315.         sum += (n * power(10, i));
  1316.     s--;
  1317.     i++;
  1318.     }
  1319. *number = (unsigned int) sum;
  1320. }
  1321.  
  1322. power(base, n)
  1323. int base, n;
  1324. {
  1325. int i, p;
  1326.  
  1327. p = 1;
  1328. for ( i = 1; i <= n; ++i )
  1329.     p = p * base;
  1330. return p;
  1331. }
  1332. !Funky!Stuff!
  1333. echo x - asciify/definitions.h
  1334. cat >asciify/definitions.h <<'!Funky!Stuff!'
  1335. #ifndef DEFINITIONS_DEFINED
  1336. #define DEFINITIONS_DEFINED
  1337.  
  1338. #define            TRUE            1
  1339. #define            FALSE            0
  1340. #define            YES                TRUE
  1341. #define            NO                FALSE
  1342.  
  1343. #define            VERSION_NUM        1.0
  1344. #define            VERSION_STRING    "Asciify Version %1.2f"
  1345. #define            FILE_STRING        "File %s"
  1346. #define            CHECKSUM_STRING    "Chk"
  1347.  
  1348. #define            DELIMETER        0x21
  1349. #define            CODING_START    0x22
  1350. #define            BIT_SPAN        0x3F    /* 6 bits worth */
  1351. #define            SHORT_START        (CODING_START + BIT_SPAN + 1)
  1352. #define            MASK_TWO        0x0003
  1353. #define            MASK_FOUR        0x000F
  1354. #define            START_TWO        SHORT_START
  1355. #define            START_FOUR        (SHORT_START + MASK_TWO + 1)
  1356. #define            SHORT_STOP        0x7E
  1357. #define            LOWER_CHAR        0x00FF
  1358. #define            UPPER_CHAR        0xFF00
  1359.  
  1360. #define            UPPER_TWO_BITS    0xC0
  1361. #define            UPPER_FOUR_BITS    0xF0
  1362. #define            UPPER_SIX_BITS    0xFC
  1363. #define            LOWER_TWO_BITS    0x03
  1364. #define            LOWER_FOUR_BITS    0x0F;
  1365. #define            LOWER_SIX_BITS    0x3F
  1366.  
  1367. #define            FAILURE            0
  1368. #define            SUCCESS            1
  1369. #define            NO_TRAILING        1
  1370. #define            TRAILING_CHARS    2
  1371. #define            TRAILING_TWO    3
  1372. #define            TRAILING_FOUR    4
  1373. #define            DOUBLE_DELIMS    5
  1374.  
  1375. #define            CHECKSUM        10
  1376. #define            NO_CHECKSUM        11
  1377.  
  1378. #define            BUFFER_SIZE                1024
  1379. #define            MAX_LINE_LENGTH            80
  1380. #define            LINE_LENGTH                64
  1381. #define            NUM_CHECKSUM_CHARS        10
  1382. #define            NUM_DATA_CHARS            80
  1383.  
  1384. #define            HERALD        "(This file must be decoded with Binafy)\n"
  1385.  
  1386. typedef        short        BOOLEAN;
  1387.  
  1388. typedef struct HEADER_STRUCT {
  1389.     char            fileName[MAX_LINE_LENGTH];
  1390.     char            header[MAX_LINE_LENGTH];
  1391.     BOOLEAN            useCheck;
  1392.     unsigned int    checksum;
  1393.     unsigned int    checksumRead;
  1394.     unsigned int    line;
  1395.     };
  1396.  
  1397. #define        STANDARD_OUTPUT_FD        1
  1398.  
  1399. #endif
  1400. !Funky!Stuff!
  1401. echo x - asciify/globals.c
  1402. cat >asciify/globals.c <<'!Funky!Stuff!'
  1403. #include "definitions.h"
  1404.  
  1405. char            buffer[BUFFER_SIZE];
  1406. int                num = 0;
  1407. char            *cur;
  1408.  
  1409. struct HEADER_STRUCT    header = {
  1410.         "",    /* The file we are processing */
  1411.             "",            /* The line read */
  1412.             NO,            /* Perform checksums? */
  1413.             0,            /* CHecksum calculated */
  1414.             0,            /* Checksum read */
  1415.             0            /* Line */
  1416.             };
  1417. !Funky!Stuff!
  1418. echo x - asciify/globals.h
  1419. cat >asciify/globals.h <<'!Funky!Stuff!'
  1420. #include "definitions.h"
  1421.  
  1422. extern char            buffer[BUFFER_SIZE];
  1423. extern int            num;
  1424. extern char            *cur;
  1425.  
  1426. extern struct HEADER_STRUCT    header;
  1427. !Funky!Stuff!
  1428. echo x - asciify/tyger
  1429. cat >asciify/tyger <<'!Funky!Stuff!'
  1430. Tyger, Tyger burning bright
  1431.  
  1432. In the forest of the night
  1433.  
  1434. What immortal hand or eye
  1435.  
  1436. Could frame thy fearful symmetry?
  1437. !Funky!Stuff!
  1438.