home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / sendbatches.lzh / src / c7encode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-14  |  3.2 KB  |  147 lines

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