home *** CD-ROM | disk | FTP | other *** search
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- /* Prototypes for functions defined in c7encode.c */
- void main(void);
- void encode(register char *c,int n);
- void flushout(void);
- void dumpcode(register char *p,register int n);
-
-
- #ifdef SCCSID
- static char *SccsId = "@(#)encode.c 1.3 5/15/85";
- #endif /* SCCSID */
-
- /*
- * Produce a 7 bit printable encoding of stdin on stdout.
- *
- * Encoding uses acsii chars from ' ' .. 'z'
- * (040 .. 0172) (0x20 - 0x7a) inclusive
- *
- * Method is to expand 3 chars -> 4 6 bit ones.
- * Then collect 13 6 bit chars, and spread the 13th over
- * the preceding 12, so that each of the 12 chars is now
- * 6.5 bits. These 2 6.5 bit chars are a little hard
- * to represent on most common machines (one of these days
- * sane hosts will have 1/2 bits just for this program)
- * so we take a pair of them, and represent that in 13 bits.
- * 13 bits (max value 8191) can be represented as
- * A * 91 + B
- * where A < 91, B < 91 (91^2 == 8281, so it fits!)
- *
- * Each of A and B is encoded as a character by adding 32
- * to make it printable (ie: 0x20).
- *
- * The termination conditions are foul beyond belief. Don't
- * monkey with them!
- *
- * If you think its a fluke that 040 .. 0171 just happen to
- * be the chars that Piet Beertema's uucp 'f' protocol transmits
- * as single bytes, you're insane. 0172 chars are produced
- * with lower frequency than any other (given random data)
- * so the doubling that occurs with that we will just suffer.
- * (A newer 'f' proto, sometime, will probably not use 0172)
- */
-
- /*
- * the following pair of characters cannot legally occur
- * in normal output (since 90*91 + 90 == 8280, which > 2^13)
- * so we use them to indicate that the data that follows is the
- * terminator. The character immediately following this
- * pair is the length of the (expanded) terminator (which
- * otherwise might be indeterminable)
- */
- #define ENDMARK1 ((90*91 + 90) / 91 + ' ')
- #define ENDMARK2 ((90*91 + 90) % 91 + ' ')
-
- void main()
- {
- register char *p;
- register char *e;
- register c;
- char b3[3];
-
- p = b3;
- e = b3 + 3;
- while ((c = getchar()) != EOF) {
- *p++ = c;
- if (p == e) {
- encode(b3, 3);
- p = b3;
- }
- }
- encode(b3, p - b3);
- flushout();
- exit(0);
- }
-
- static char b13[13];
- static int cnt = 0;
-
- void encode(c, n) register char *c; int n;
- {
- register char *p;
- register i = cnt;
- register j;
- char b4[4];
-
- p = b4;
-
- p[0] = (c[0] >> 2) & 0x3f;
- p[1] = ((c[0] & 0x3) << 4) | ((c[1] >> 4) & 0xf);
- p[2] = ((c[1] & 0xF) << 2) | ((c[2] >> 6) & 0x3);
- if (n == 3)
- p[3] = c[2] & 0x3f;
- else
- p[3] = n;
-
- c = &b13[i];
- for (j = 4; --j >= 0; i++) {
- if (i == 13) {
- dumpcode(b13, 13);
- c = b13;
- i = 0;
- }
- *c++ = *p++;
- }
- cnt = i;
- }
-
- void flushout()
- {
- putchar(ENDMARK1);
- putchar(ENDMARK2);
- putchar(cnt + ' ');
- dumpcode(b13, cnt);
- }
-
- void dumpcode(p, n) register char *p; register int n;
- {
- register last;
- register c;
-
- if (n == 13)
- n--, last = p[12];
- else if (n & 1)
- last = (1 << (6-1));
- else
- last = 0;
-
- for ( ; n > 0; n -= 2) {
- c = *p++ << 6;
- c |= *p++;
- if (last & (1 << (6-1)))
- c |= (1 << 12);
- last <<= 1;
-
- /*
- * note: 91^2 > 2^13, 90^2 < 2^13, (91 + ' ') is printable
- */
-
- /* oh for a compiler that would only do one division... */
- putchar((c / 91) + ' ');
- putchar((c % 91) + ' ');
- }
- }
-