From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  7-AUG-1989 07:10
To:	MRGATE::"ARISIA::EVERHART"
Subj:	RE: uudecode and btoa

Message-Id:  <8908071100.AA01866@crdgw1.ge.com>
Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Sat,  5 AUG 89 13:20:08 PDT
Received: from Venus.YCC.Yale.Edu (YALE-ENG-VENUS.ARPA) by KL.SRI.COM with TCP; Sat, 5 Aug 89 12:56:38 PDT
Date: Sat, 5 Aug 89 15:01 EDT
From: "Jerry Leichter - LEICHTER-JERRY@CS.YALE.EDU"
 <LEICHTER@Venus.YCC.Yale.Edu>
Subject: RE: uudecode and btoa
To: dittman@skbat.csc.ti.COM, INFO-VAX@KL.SRI.COM
X-Vms-To: IN%"dittman@skbat.csc.ti.COM"

	Are uudecode and btoa available for VMS?  If they are not, does
	someone have the format available?

Someone else has already offered a version of uudecode (which is generally
more widely available).  Here are VMS versions of btoa and atob, modified
for VMS by Martin Minow.

In my next message, I will send another pair of programs, vbtoa and vatob,
which are my variations on the same theme.  These are INCOMPATIBLE with the
standard Unix versions - a fact they make obvious by using different headers
and trailers.  Their main claim to fame is that they preserve RMS file
characteristics.
							-- Jerry
----------------atob.c------------------
/*
 * stream filter to change printable ascii from "btoa" back into 8 bit bytes
 * if bad chars, or Csums do not match: exit(1) [and NO output]
 *
 *  Paul Rutter		Joe Orost
 *  philabs!per		petsd!joe
 */
#ifdef	DOCUMENTATION

title	atob	Ascii to Binary Conversion
index		Ascii to binary conversion

synopsis

	atob source destination

description

	atob reads a file created by btoa, converting it to
	its original binary format.  The checksums calculated
	by btoa are checked.

	If both files are missing, atob reads from the standard
	input and writes to the standard output.  Because of
	RMS file attributes, this may not work well on VMS
	or RSX-11M.

warning

	Neither btoa nor atob understand RMS file attributes.
	The output of atob is a "binary" file if it was specified
	on the command line, and a text (or stream) file if
	redirection was used.

vms note

	Redirection is intentionally missing from the VMS version.

author

	Paul Rutter	philabs!per

	Joe Orost	petsd!joe

	Martin Minow	minow%thundr.dec@decwrl.dec.com

#endif

/*)BUILD
		$(CPP)		= 1
		$(TKBOPTIONS)	= {
			TASK	= ...ATB
		}
*/

#include <stdio.h>

#ifdef	vms
#include		errno
#include		ssdef
#include		stsdef
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	(SS$_ABORT)
#define unlink(x)	delete(x)
#endif
/*
 * Define exit() codes.
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0			/* Normal exit		*/
#define	IO_ERROR	1			/* Error exit		*/
#endif

#define reg register

#ifndef decus
#define streq(s0, s1)  strcmp(s0, s1) == 0
#endif

long int Ceor = 0;
long int Csum = 0;
long int Crot = 0;
long int bcount = 0;
long int word = 0;
FILE *tempfd;


fatal() {
  fprintf(stderr, "bad format or Csum to atob\n");
  exit(IO_ERROR);
}


#define DE(c) ((c) - ' ')

decode(c) reg c;
{
  if (c == 'z') {
    if (bcount != 0) {
      fatal();
    }
    else {
      byteout(0);
      byteout(0);
      byteout(0);
      byteout(0);
    }
  }
  else if ((c >= ' ') && (c < (' ' + 85))) {
    if (bcount == 0) {
      word = DE(c);
      ++bcount;
    }
    else if (bcount < 4) {
      word *= 85;
      word += DE(c);
      ++bcount;
    }
    else {
      word = ((unsigned) word * (unsigned) 85) + DE(c);
      byteout((word >> 24) & 255);
      byteout((word >> 16) & 255);
      byteout((word >> 8) & 255);
      byteout(word & 255);
      word = 0;
      bcount = 0;
    }
  }
  else {
    fatal();
  }
}

byteout(c) reg c;
{
  Ceor ^= c;
  Csum += c;
  Csum += 1;
  if ((Crot & 0x80000000)) {
    Crot <<= 1;
    Crot += 1;
  }
  else {
    Crot <<= 1;
  }
  Crot += c;
  putc(c, tempfd);
}

main(argc, argv) char **argv;
{
  reg c;
  reg long int i;
  char tmpname[100];
  char buf[100];
  long int n1, n2, oeor, osum, orot;

  if (argc == 3) {
    if (freopen(argv[1], "r", stdin) == NULL) {
	perror(argv[1]);
	fatal();
    }
    if (freopen(argv[2], "wb", stdout) == NULL) {
	perror(argv[2]);
	fatal();
    }
  }
  else if (argc != 1) {
    fprintf(stderr,"bad args to %s\n", argv[0]);
    exit(IO_ERROR);
  }
#ifdef vms
  sprintf(tmpname, "%x.atob_temp;", getpid());		/* VMS		*/
#else
#ifdef rsx
  strcpy(tmpname, "atob.tmp;");				/* RSX-11M	*/
#else
#ifdef rt11 
  strcpy(tmpname, "atob.tmp");				/* RT11		*/
#else
  sprintf(tmpname, "/usr/tmp/atob.%x", getpid());	/* else Unix	*/
#endif
#endif
#endif
#ifdef decus
  tempfd = fopen(tmpname, "wb");
#else
  tempfd = fopen(tmpname, "wb+");
#endif
  if (tempfd == NULL) {
    perror(tmpname);
    fatal();
  }
  /*search for header line*/
  for (;;) {
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      fatal();
    }
    if (streq(buf, "xbtoa Begin\n")) {
      break;
    }
  }

  while ((c = getchar()) != EOF) {
    if (c == '\n') {
      continue;
    }
    else if (c == 'x') {
      break;
    }
    else {
      decode(c);

    }
  }
  if (scanf("btoa End N %d %x E %x S %x R %x\n", &n1, &n2, &oeor, &osum, &orot) != 5) {
    fatal();
  }
  if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot)) {
    fatal();
  }
  else {
    /*copy OK tmp file to stdout*/;
#ifdef decus
    fclose(tempfd)
    if (tempfd = fopen(tmpname, "rb")) == NULL) {
      perror(tmpname);
      fatal();
    }
#else
    fseek(tempfd, 0, 0);
#endif
    for (i = n1; --i >= 0;) {
      putchar(getc(tempfd));
    }
    unlink(tmpname);
  }
  exit(IO_SUCCESS);
}
----------------btoa.c------------------
/*
 * stream filter to change 8 bit bytes into printable ascii
 * computes the number of bytes, and three kinds of simple checksums
 * incoming bytes are collected into 32-bit words, then printed in base 85
 *  exp(85,5) > exp(2,32)
 * the ASCII characters used are between ' ' and 't'
 * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
 *
 *  Paul Rutter		Joe Orost
 *  philabs!per		petsd!joe
 * Mod: 2-Sep-87 MM for VMS: btoa in out acceptable.
 */
#ifdef	DOCUMENTATION

title	btoa	Binary to Ascii Conversion
index		Binary to Ascii conversion

synopsis

	btoa source destination

description

	btoa reads a (binary) file, converting it to a text file
	containing only readable characters which may then be
	mailed across various networks and re-converted by atob.
	Checksums are appended to the converted file.

	If both files are missing, btoa reads from the standard
	input and writes to the standard output.  Because of
	RMS file attributes, this may not work well on VMS
	or RSX-11M.

warning

	Neither btoa nor atob understand RMS file attributes.
	The output of atob is a "binary" file if it was specified
	on the command line, and a text (or stream) file if
	redirection was used.

vms note

	Redirection is intentionally missing from the VMS version.

author

	Paul Rutter	philabs!per

	Joe Orost	petsd!joe

	Martin Minow	minow%thundr.dec@decwrl.dec.com

#endif

/*)BUILD
		$(CPP)		= 1
		$(TKBOPTIONS)	= {
			TASK	= ...ATB
		}
*/

#include <stdio.h>

#ifdef	vms
#include		errno
#include		ssdef
#include		stsdef
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	(errno)
#endif
/*
 * Define exit() codes.
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0			/* Normal exit		*/
#define	IO_ERROR	1			/* Error exit		*/
#endif

#define reg register

#define MAXPERLINE 78

long int Ceor = 0;
long int Csum = 0;
long int Crot = 0;

long int ccount = 0;
long int bcount = 0;
long int word;

#define EN(c) ((c) + ' ')

encode(c) reg c;
{
  Ceor ^= c;
  Csum += c;
  Csum += 1;
  if ((Crot & 0x80000000)) {
    Crot <<= 1;
    Crot += 1;
  }
  else {
    Crot <<= 1;
  }
  Crot += c;

  word <<= 8;
  word |= c;
  if (bcount == 3) {
    wordout(word);
    bcount = 0;
  }
  else {
    bcount += 1;
  }
}

wordout(word) reg long int word;
{
  if (word == 0) {
    charout('z');
  }
  else {
    /*first division must be unsigned*/;
    charout((int) EN((unsigned) word / (unsigned)(85 * 85 * 85 * 85)));
    word = (unsigned) word % (unsigned)(85 * 85 * 85 * 85);
    charout(EN(word / (85 * 85 * 85)));
    word %= (85 * 85 * 85);
    charout(EN(word / (85 * 85)));
    word %= (85 * 85);
    charout(EN(word / 85));
    word %= 85;
    charout(EN(word));
  }
}

charout(c) {
  putchar(c);
  ccount += 1;
  if (ccount == MAXPERLINE) {
    putchar('\n');
    ccount = 0;

  }
}

main(argc,argv) char **argv;
{
  reg c;
  reg long int n;
  if (argc == 3) {
    if (freopen(argv[1], "rb", stdin) == NULL) {
	perror(argv[1]);
	exit(IO_ERROR);
    }
    if (freopen(argv[2], "w", stdout) == NULL) {
	perror(argv[2]);
	exit(IO_ERROR);
    }
  }
  else if (argc != 1) {
    fprintf(stderr,"bad args to %s\n", argv[0]);
    exit(IO_ERROR);
  }
  printf("xbtoa Begin\n");
  n = 0;
  while ((c = getchar()) != EOF) {
    encode(c);
    n += 1;
  }
  while (bcount != 0) {
    encode(0);
  }
  /* n is written twice as crude cross check*/
  printf("\nxbtoa End N %d %x E %x S %x R %x\n", n, n, Ceor, Csum, Crot);
  exit(IO_SUCCESS);
}

