home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / batch / c7encode.c < prev    next >
C/C++ Source or Header  |  1989-02-20  |  3KB  |  142 lines

  1. #include <stdio.h>
  2.  
  3. #ifdef SCCSID
  4. static char    *SccsId = "@(#)encode.c    1.3    5/15/85";
  5. #endif /* SCCSID */
  6.  
  7. /*
  8.  * Produce a 7 bit printable encoding of stdin on stdout.
  9.  *
  10.  * Encoding uses acsii chars from ' ' .. 'z'
  11.  * (040 .. 0172) (0x20 - 0x7a) inclusive
  12.  *
  13.  * Method is to expand 3 chars -> 4 6 bit ones.
  14.  * Then collect 13 6 bit chars, and spread the 13th over
  15.  * the preceding 12, so that each of the 12 chars is now
  16.  * 6.5 bits.  These 2 6.5 bit chars are a little hard
  17.  * to represent on most common machines (one of these days
  18.  * sane hosts will have 1/2 bits just for this program)
  19.  * so we take a pair of them, and represent that in 13 bits.
  20.  * 13 bits (max value 8191) can be represented as
  21.  *    A * 91 + B
  22.  * where A < 91, B < 91  (91^2 == 8281, so it fits!)
  23.  *
  24.  * Each of A and B is encoded as a character by adding 32
  25.  * to make it printable (ie: 0x20).
  26.  *
  27.  * The termination conditions are foul beyond belief.  Don't
  28.  * monkey with them!
  29.  *
  30.  * If you think its a fluke that 040 .. 0171 just happen to
  31.  * be the chars that Piet Beertema's uucp 'f' protocol transmits
  32.  * as single bytes, you're insane.  0172 chars are produced
  33.  * with lower frequency than any other (given random data)
  34.  * so the doubling that occurs with that we will just suffer.
  35.  * (A newer 'f' proto, sometime, will probably not use 0172)
  36.  */
  37.  
  38. /*
  39.  * the following pair of characters cannot legally occur
  40.  * in normal output (since 90*91 + 90 == 8280, which > 2^13)
  41.  * so we use them to indicate that the data that follows is the
  42.  * terminator.  The character immediately following this
  43.  * pair is the length of the (expanded) terminator (which
  44.  * otherwise might be indeterminable)
  45.  */
  46. #define    ENDMARK1    ((90*91 + 90) / 91 + ' ')
  47. #define    ENDMARK2    ((90*91 + 90) % 91 + ' ')
  48.  
  49. main()
  50. {
  51.     register char *p;
  52.     register char *e;
  53.     register c;
  54.     char b3[3];
  55.  
  56.     p = b3;
  57.     e = b3 + 3;
  58.     while ((c = getchar()) != EOF) {
  59.         *p++ = c;
  60.         if (p == e) {
  61.             encode(b3, 3);
  62.             p = b3;
  63.         }
  64.     }
  65.     encode(b3, p - b3);
  66.     flushout();
  67.     exit(0);
  68. }
  69.  
  70. static char b13[13];
  71. static int cnt = 0;
  72.  
  73. encode(c, n)
  74.     register char *c;
  75.     int n;
  76. {
  77.     register char *p;
  78.     register i = cnt;
  79.     register j;
  80.     char b4[4];
  81.  
  82.     p = b4;
  83.  
  84.     p[0] = (c[0] >> 2) & 0x3f;
  85.     p[1] = ((c[0] & 0x3) << 4) | ((c[1] >> 4) & 0xf);
  86.     p[2] = ((c[1] & 0xF) << 2) | ((c[2] >> 6) & 0x3);
  87.     if (n == 3)
  88.         p[3] = c[2] & 0x3f;
  89.     else
  90.         p[3] = n;
  91.  
  92.     c = &b13[i];
  93.     for (j = 4; --j >= 0; i++) {
  94.         if (i == 13) {
  95.             dumpcode(b13, 13);
  96.             c = b13;
  97.             i = 0;
  98.         }
  99.         *c++ = *p++;
  100.     }
  101.     cnt = i;
  102. }
  103.  
  104. flushout()
  105. {
  106.     putchar(ENDMARK1);
  107.     putchar(ENDMARK2);
  108.     putchar(cnt + ' ');
  109.     dumpcode(b13, cnt);
  110. }
  111.  
  112. dumpcode(p, n)
  113.     register char *p;
  114.     register int n;
  115. {
  116.     register last;
  117.     register c;
  118.  
  119.     if (n == 13)
  120.         n--, last = p[12];
  121.     else if (n & 1)
  122.         last = (1 << (6-1));
  123.     else
  124.         last = 0;
  125.  
  126.     for ( ; n > 0; n -= 2) {
  127.         c = *p++ << 6;
  128.         c |= *p++;
  129.         if (last & (1 << (6-1)))
  130.             c |= (1 << 12);
  131.         last <<= 1;
  132.  
  133.         /*
  134.          * note: 91^2 > 2^13, 90^2 < 2^13, (91 + ' ') is printable
  135.          */
  136.  
  137.         /* oh for a compiler that would only do one division... */
  138.         putchar((c / 91) + ' ');
  139.         putchar((c % 91) + ' ');
  140.     }
  141. }
  142.