[comp.sources.amiga] v89i063: btoa - encode binary files for ascii transmission v5.2

page@swan.ulowell.edu (Bob Page) (03/16/89)

Submitted-by: d84sp@efd.lth.se (Stefan Parmark)
Posting-number: Volume 89, Issue 63
Archive-name: unix/btoa.1

This is version 5.2 of btoa.

Besides expanding binary files by only 25% rather than uuencode's 33%,
it now also has got the ability to REPAIR damaged files, without
having to retransmit the entire file.  It's also faster.

It has worked successfully between a Sun-3 and an Amiga 1000.

[uuencoded executable included.  With this release, most of the
arguments I have against btoa are answered.  Since it produces smaller
encodings, it might be a candidate to replace uuencode for the
comp.binaries.amiga postings.  If you have any feelings on the matter,
let me know.  ..Bob]

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	Makefile.amiga_lattice
#	Makefile.sun
#	atob.c
#	btoa.1
#	btoa.c
#	btoa.doc
#	btoa.h
#	btoa.uu
#	chksum.h
#	repair.c
# This archive created: Wed Mar 15 15:37:30 1989
cat << \SHAR_EOF > README
             BTOA version 5.2
            ------------------
Written by Paul Rutter, Joe Orost & Stefan Parmark.


Btoa was created from atob/btoa which were submitted to Usenet
by Paul E. Rutter. Atob and btoa has now been merged into one
program, now refered to as btoa.

Btoa converts 4 binary characters to 5 ascii ones, causing a 25%
expansion. Spaces will not be used, which should make it safe
to send files over Usenet without risking that blanks become
tabs. 

Decoding, which previously was done with atob, is now an option
of btoa. See the manual for details.

One of the drawbacks with the previous version of btoa was that,
if there was an error in the file, atob only stated so, but gave
no clue to its location. It used a checksum covering the
total file, making it impossible to detect where the error was.
I added a single-byte checksum for each row.

Further, the file contained no information about the name of the
output file. Rather, stdout was used. Version 5.0 has the feature
to name the file contents. It can be turned off by reading data
from stdin.

A totally new feature is the ability to mend corrupted archives.
This can be done as long as the header and last line are OK.
It detects bad lines, informs the remote computer about this,
which retransmits these lines in a special file, which btoa uses
to repair the archive. See the manual for more details.

Btoa uses characters between '!' and 'u'. Special characters are
'z' meaning 4 consecutive zeros, 'y' meaning 4 spaces, and
'x' as an end-of-archive mark. The 'y' was added be me, and will
not be recognized by the old version.

Old btoa encoding is still possible, as an extra option (see the
manual). When decoding, btoa can tell if it's the old or new btoa
format by looking at the header.

I removed the feature to exit with no output if there was en error
in the archive. This was done by using a temporary file for
storage. This is not a good idea for micro computer folks like
me, with limited storage possibilities. I hope all realize that
you shouldn't run a file that was created from a corrupted archive.

Most of the code was rewritten in order to make it execute faster.
Special efforts have been made to optimize the atob part.
Measured speeds are 30 kbyte/s on a Sun-3 and 4 kbyte/s on an
Amiga. On the Amiga I used the VD0: recoverable RAM disk without
FFS.

I have tested btoa on an Amiga 1000 and a Sun-3, and it has
worked very well. If you find it doesn't work on your favourite
computer, drop me a note to one of the addresses below, preferably
the top one, and I'll see what I can do. Also, if you port and/or
improve it, please send me the diffs, and I'll include them in the
next release.

---------------------- DISCLAIMER -------------------------------

I assume no responsibility for the use of btoa. It should work OK,
and I have included lots of tests to make sure that files open,
end-of-file is detected, etc.

Btoa is in the public domain. You may use it, give it away, and
make improvements, as long as the names of the developers are
mentioned and you don't use it to earn money. It may NOT be used
commercially without my permission.

/Stefan Parmark
        d84sp@efd.lth.se
        d84spa@rigel.sunet.se
SHAR_EOF
cat << \SHAR_EOF > Makefile.amiga_lattice
OBJS     = btoa.o atob.o repair.o
CFLAGS   = -cef -dLATTICE -v -w

btoa     : $(OBJS)
           blink lib:c.o $(OBJS) TO btoa LIB lib:lcs.lib SC SD ND

atob.o   : atob.c btoa.h chksum.h
btoa.o   : btoa.c btoa.h chksum.h
repair.o : repair.c btoa.h
SHAR_EOF
cat << \SHAR_EOF > Makefile.sun
OBJS     = btoa.o atob.o repair.o

btoa     : $(OBJS)
           cc -O $(OBJS) -o btoa

btoa.o   : btoa.c btoa.h chksum.h
           cc -c -O btoa.c
atob.o   : atob.c btoa.h chksum.h
           cc -c -O atob.c
repair.o : repair.c btoa.h
           cc -c -O repair.c
SHAR_EOF
cat << \SHAR_EOF > atob.c
/* atob.c */

/* Written by Paul Rutter, Joe Orost & Stefan Parmark. */

#include <stdio.h>
#ifdef AMIGA
#include <stdlib.h>
#include <string.h>
#endif AMIGA

#include "btoa.h"
#if USE_MACROS
#include "chksum.h"
#endif USE_MACROS


BYTE atob(infile)
register FILE *infile;
{
  register BYTE error;
  register LONG filepos;
  int maxperline;
  LONG n1, n2, oeor, osum, orot, lastline;
  static BYTE outfilename[BUFSIZE];
  extern LONG Ceor, Csum, Crot;
  extern FILE *outfile;
  extern BYTE new_version, openoutput, buffer[BUFSIZE];

  error = FALSE;

  /* Search for archive header. */
  do
  {
    filepos = ftell(infile);

    if (readbuffer(buffer, "archive", infile))
      error = TRUE;
  }
  while (!(error || strncmp(buffer, "xbtoa", 5) == 0));

  if (!error)
    if (strcmp(buffer, "xbtoa Begin\n") == 0)
    {
      new_version = FALSE;
      fprintf(stderr, "btoa: Old btoa format.\n");
    }
    else if (sscanf(buffer, "xbtoa5 %d %s Begin\n", &maxperline, outfilename) == 2)
    {
      new_version = TRUE;
      /* Naming a file overrides the read-name-from-file function. */
      if (!openoutput && strcmp(outfilename, "-") != 0)
        if ((outfile = fopen_write(outfilename)) == NULL)
          error = TRUE;
        else
          openoutput = TRUE;
    }
    else
    {
      fprintf(stderr, "btoa: Illegal archive header.\n");
      error = TRUE;
    }

  if (!error)
  {
    Ceor = Csum = Crot = 0;

    if (new_version)
      error = new_decodefile(infile, &lastline, filepos, maxperline);
    else
      error = old_decodefile(infile, &lastline);
  }

  if (!error)
  {
    if (sscanf(buffer, "xbtoa End N %ld %lx E %lx S %lx R %lx\n",
        &n1, &n2, &oeor, &osum, &orot) != 5)
    {
      fprintf(stderr, "btoa: Bad format on line %ld. Can't repair file.\n",
          lastline);
      error = TRUE;
    }
    else if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot))
    {
      fprintf(stderr, "btoa: Bad file checksum. Can't repair file.\n");
      error = TRUE;
    }
    else
      /* Flush last characters. */
      decode_line(NULL, (int) ((n1 - 1) & 0x03));
  }

  return(error);
}


/* Peek at the next byte without moving the file pointer. */
int nextbyte(infile)
register FILE *infile;
{
  register int ch;
  register LONG filepos;

  filepos = ftell(infile);
  ch = fgetc(infile);
  fseek(infile, filepos, 0);

  return(ch);
}


BYTE new_decodefile(infile, lastline, filepos, maxperline)
register FILE *infile;
LONG *lastline, filepos;
int maxperline;
{
  register int length;
  int ch;
  register BYTE stop, error, newerror, errorstart;
  register LONG line, prevfilepos, startpos;
  struct Diagnosis diagnosislist;
  extern LONG Csum;
  extern BYTE buffer[BUFSIZE];

  error = FALSE;

  line = 1;  /* Current line number. */

  /* A sequence of errors is indicated by errorstart. When it */
  /* changes from TRUE to FALSE a diagnosis record will be    */
  /* generated.                                               */
  stop = errorstart = FALSE;

  /* File position of the line before the error sequence.     */
  /* That is the last correct line.                           */
  startpos = 0;

  while (!stop)
  {
    prevfilepos = filepos;
    filepos = ftell(infile);

    /* Newerror indicates an error on the current line. */
    newerror = FALSE;

    line++;
    if (readbuffer(buffer, "archive", infile))
      newerror = stop = TRUE;
    else if (buffer[0] == 'x')  /* End of archive found. */
      stop = TRUE;
    else if ((length = strlen(buffer) - 1) != maxperline ||
             buffer[length] != '\n')
    {
      /* If last character wasn't end-of-line, then we */
      /* have to read until it is found.               */
      if (buffer[length] != '\n')
      {
        newerror = TRUE;
        while ((ch = fgetc(infile)) != EOF && (BYTE)ch != '\n')
          ;
        if (ch == EOF)
          stop = TRUE;
      }
      else if (length > maxperline || nextbyte(infile) != 'x')
      {
        newerror = TRUE;
        Csum = DECODE(buffer[length - 1]);  /* Make Csum correct (modulo 85). */
      }

      if (newerror)
        fprintf(stderr, "btoa: Bad line length on line %ld.\n", line);
    }

    if (!(newerror || stop))
    {
      if (decode_line(buffer, length - 1))
      {
        if (!error)
          fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
        newerror = TRUE;
      }

      /* Examine checksum. */
      if ((ch = buffer[length - 1]) == ENCODE(Csum % 85))
      {
        if (errorstart)
        {
          intodiagnosislist(&diagnosislist, startpos, filepos);
          errorstart = FALSE;
        }
      }
      else
      {
        newerror = TRUE;
        fprintf(stderr, "btoa: Bad checksum on line %ld.\n", line);
        Csum = DECODE(ch);  /* Make Csum correct (modulo 85). */
      }
    }

    if (newerror)
    {
      if (!error)
      {
        fprintf(stderr, "btoa: Starting diagnosis.\n");
        diagnosislist.next = diagnosislist.last = NULL;
      }

      error = TRUE;
      if (!errorstart)
      {
        errorstart = TRUE;
        startpos = prevfilepos;
      }
    }
  }

  if (error)
  {
    if (errorstart)
      intodiagnosislist(&diagnosislist, startpos, filepos);
    producediagnosis(&diagnosislist, infile);
  }

  *lastline = line;

  return(error);
}



BYTE old_decodefile(infile, lastline)
register FILE *infile;
LONG *lastline;
{
  register int length;
  register BYTE stop, error;
  register LONG line;
  extern BYTE buffer[BUFSIZE];

  error = FALSE;

  line = 1;
  stop = FALSE;
  while (!stop)
  {
    line ++;

    if (readbuffer(buffer, "archive", infile))
      error = stop = TRUE;
    else if (buffer[0] == 'x')  /* End of archive found. */
      stop = TRUE;
    else
    {
      length = strlen(buffer) - 1;
      if (buffer[length] != '\n')
        error = stop = TRUE;  /* The line was longer than the buffer. */
    }

    if (!stop)
    {
      if (decode_line(buffer, length))
      {
        fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
        error = stop = TRUE;
      }
    }
  }

  *lastline = line;

  return(error);
}


BYTE decode_line(buffer, length)
register BYTE *buffer;
register int length;
{
  register int ch;
  register BYTE error;
  register LONG tmp_codeword;
  extern BYTE new_version;
  extern FILE *outfile;
  static LONG codeword;
  static int ch1, ch2, ch3, ch4;
  static BYTE bytecount = 0;

  error = FALSE;

  if (buffer == NULL)  /* Flush last characters. */
  {
    if (bytecount > 0)
    {
      fputc(ch1, outfile);
      if (length > 0)
        fputc(ch2, outfile);
      if (length > 1)
        fputc(ch3, outfile);
      if (length > 2)
        fputc(ch4, outfile);
    }
  }
  else
  {
    while (length > 0)
    {
      length--;
      ch = *buffer++;

      /* Delayed output. This is to make sure that files with lengths */
      /* that are not multiples of 4 won't become too long.           */
      if (bytecount == 5)
      {
        fputc(ch1, outfile);
        fputc(ch2, outfile);
        fputc(ch3, outfile);
        fputc(ch4, outfile);

        bytecount = 0;
      }

      if (new_version)
        calcchecksum(ch);

      if (((BYTE)ch >= '!') && ((BYTE)ch < ('!' + 85)))  /* Valid characters. */
      {
        /* See if we can take all 5 bytes and decode them right away. */
        /* That is, if all remaining bytes are on the current line.   */
        if (length >= 4 - bytecount)
        {
          length -= 4 - bytecount;

          if (bytecount == 0)
            codeword = DECODE(ch);
          else
            codeword = codeword * 85 + DECODE(ch);

          for (bytecount++; bytecount < 5; bytecount++)
          {
            ch = *buffer++;
            if (new_version)
              calcchecksum(ch);
            codeword = codeword * 85 + DECODE(ch);
          }
        }
        else
        {
          /* Shift codeword and insert character. */

          if (bytecount == 0)
          {
            codeword = DECODE(ch);
            bytecount = 1;
          } 
          else /* bytecount < 5 */
          {
            codeword = codeword * 85 + DECODE(ch);
            bytecount ++;
          }
        }

        if (bytecount == 5)
        {
          tmp_codeword = codeword;

          ch4 = (int)tmp_codeword & 0xFF;
          ch3 = (int)(tmp_codeword >>= 8) & 0xFF;
          ch2 = (int)(tmp_codeword >>= 8) & 0xFF;
          ch1 = (int)(tmp_codeword >> 8) & 0xFF;

          if (!new_version)
          {
            calcchecksum(ch1);
            calcchecksum(ch2);
            calcchecksum(ch3);
            calcchecksum(ch4);
          }
        }
      }
      else if ((BYTE)ch == 'z' || (new_version && (BYTE)ch == 'y'))
      {
        if (bytecount != 0)
          error = TRUE;
        else
        {
          ch1 = ch2 = ch3 = ch4 = (ch == 'z') ? 0 : ' ';
          if (!new_version)
          {
            calcchecksum(ch1);
            calcchecksum(ch1);
            calcchecksum(ch1);
            calcchecksum(ch1);
          }
          bytecount = 5;
        }
      }
      else
        error = TRUE;
    }
  }

  return(error);
}
SHAR_EOF
cat << \SHAR_EOF > btoa.1
.TH BTOA 1 "21 February 1989"
.| btoa version 5.2
.SH NAME
btoa - encode/decode binary to printable ASCII
.SH SYNOPSIS
btoa [-adhor] [input filename] [output filename]
.SH DESCRIPTION
.I Btoa
is a filter which reads binary bytes from the input file and
generates printable ASCII characters on the output file. It attaches
a header and a checksum to the archive. It can also reverse this,
creating a binary file from the archive.
.LP
Since last version of
.I btoa/atob,
several new features have been
added. The most obvious one is that
.I atob
has been integrated
with
.I btoa.
They are now the same program which is called with
different arguments. Another is the ability to repair damaged
archives.
.LP
The new version is compatible with the old version, that is,
it can still encode and decode old btoa files.
.LP
.I Btoa
has an option to decode the archive, restoring the binary bytes.
It strips the input file until it finds a valid header, and continues
decoding until the end mark is found. It recognices both old- and
new-style headers, and can decode both. It is possible to leave out
the destination name when decoding new-style archives, because the
name is stored in the header. Entering a name will override the
autonaming function.
.LP
It is possible to leave out the file names and redirect stdin and
stdout with '<' and '>' to the desired files. This is to maintain
compatibility with earlier versions of
.I btoa.
.LP
.I Btoa
now adds a single byte checksum to each row in the archive.
When an error is found, diagnosis automatically starts and produces
a diagnosis file which can be used to extract the damaged part from
an errorfree archive. The extracted part can then be used to correct
the damaged archive.
.I Btoa
has options to perform the reparation
automatically. This is especially useful when downloading data
converted to text files, and occasionally finding that an archive
file of considerable size turns is corrupted.
.SH FEATURES
.I Btoa
encodes 4 binary bytes into 5 characters, expanding the file by
25%. As a special case 4 zeroes will be encoded as 'z' and 4
spaces as 'y'. This makes it possible to compress the archive a bit.
.SH OPTIONS
.IP -h
Shows help on 
.I btoa.
.LP
.IP-a
Switches to
.I atob
(decoding) mode.
.LP
.IP -o
Switches to old version of
.I btoa.
.LP
.IP -d
Extracts repair file from diagnosis file. This assumes that
an undamaged version of the archive and a file called
'btoa.dia' is present.
.LP
.IP-r
Repairs the damaged archive. A file named 'btoa.rep' must
be present for this to work.
.SH EXAMPLES
Below follows a description of a normal repair session. Lines
beginning with 'Local>' were typed on the computer to which the
file was downloaded. Accordingly, lines typed on the connected
computer will begin with 'Remote>'. Sending a file to the other
computer will be noted as 'transmit file'.
.LP
A normal repairing procedure is as follows:
Local> btoa -a file.btoa
btoa: Bad checksum on line 2648.
btoa: Starting diagnosis.
btoa: Diagnosis output to 'btoa.dia'.
Local> transmit btoa.dia
.LP
Remote> btoa -d file.btoa
btoa: Repair output to 'btoa.rep'.
Remote> transmit btoa.rep
.LP
Local> btoa -a btoa.rep
btoa: Repaired archive written to 'btoa.rdy'.
.LP
You can now erase file.btoa and decode btoa.rdy using 'btoa -a btoa.rdy'.
.SH AUTHORS
Paul Rutter  Joe Orost  Stefan Parmark
.SH KNOWN BUGS
.I Btoa
will not work properly unless the input is a true file or a
redirected one. This is because file positions are collected during
diagnosis for later reference when producing the diagnosis file.
The bug is actually in fseek() which only can reposition 'real' files.
.LP
Send bug reports to d84sp@efd.lth.se (Stefan Parmark).
SHAR_EOF
cat << \SHAR_EOF > btoa.c
/* btoa.c */

/* Written by Paul Rutter, Joe Orost & Stefan Parmark. */

#include <stdio.h>
#ifdef AMIGA
#include <stdlib.h>
#include <string.h>
#endif AMIGA

#include "btoa.h"
#if USE_MACROS
#include "chksum.h"
#endif USE_MACROS

#define VERSION  "5.2"

LONG Ceor, Csum, Crot;  /* Checksums to verify archive validity. */
BYTE new_version, openoutput, buffer[BUFSIZE];
FILE *outfile;


void main(argc, argv)
int argc;
BYTE **argv;
{
  register BYTE openinput, error, ch, a_to_b, diagnosis, repair;
  register BYTE *infilename, *text;
  register FILE *infile;
  extern BYTE new_version, openoutput;
  extern FILE *outfile;
#ifdef AMIGA
  extern int _bufsiz;

  /* Change file buffer size. */
  _bufsiz = 10240;
#endif AMIGA

  error = openinput = openoutput = a_to_b = diagnosis = repair = FALSE;
  new_version = TRUE;
  infilename = NULL;

  /* Scan for '-' options. The rest must be file names. */
  while (!error && argc > 1 && *argv[1] == '-')
  {
    text = &argv[1][1];
    while (!error && (ch = *text++) != 0)
    {
      switch(ch)
      {
        case 'a' : /* Activate atob. */
                   a_to_b = TRUE;
                   break;
        case 'd' : /* Extract missing part from undamaged archive. */
                   diagnosis = TRUE;
                   break;
        case 'h' : /* Print help and abort execution. */
                   error = TRUE;
                   break;
        case 'o' : /* Use old btoa format. */
                   new_version = FALSE;
                   break;
        case 'r' : /* Repair damaged archive. */
                   repair = TRUE;
                   break;
        default  : error = TRUE;
      }
    }
    argv++;
    argc--;
  }

  if (argc > 3)
    error = TRUE;

  if (error)
    printhelp();
  else
  {
    /* If file name was given, try to open file. Otherwise use stdin. */
    if (argc > 1)
    {
      infilename = argv[1];
      if ((infile = fopen_read(infilename)) == NULL)
        error = TRUE;
      else
        openinput = TRUE;
    }
    else
      infile = stdin;
  }

  if (!error)
  {
    /* If file name was given, try to open file. Otherwise use stdout. */
    if (argc > 2 && !diagnosis && !repair)
    {
      if ((outfile = fopen_write(argv[2])) == NULL)
        error = TRUE;
      else
        openoutput = TRUE;
    }
    else
      outfile = stdout;
  }

  if (!error)
  {
    if (diagnosis)
      error = producerepair(infile);
    else if (repair)
      error = performrepair(infile);
    else if (a_to_b)
      error = atob(infile);
    else
      error = btoa(infile, infilename);
  }

  /* Close all opened files. */
  if (openinput)
    fclose(infile);
  if (openoutput)
    fclose(outfile);

  if (error)
    exit(1);
}


BYTE btoa(infile, infilename)
register FILE *infile;
register BYTE *infilename;
{
  register LONG codeword, filesize;
  register int ch1, ch2, ch3, ch4, readbytes;
  extern FILE *outfile;
  extern BYTE new_version, buffer[BUFSIZE];
  extern LONG Ceor, Csum, Crot;

  Ceor = Csum = Crot = 0;

  /* Write archive header. */
  if (new_version)
  {
    fprintf(outfile, "xbtoa5 %d %s Begin\n", MAXPERLINE,
        (infilename == NULL) ? "-" : truncname(infilename));
  }
  else
    fprintf(outfile, "xbtoa Begin\n");

  /* Encode entire input file. */
  filesize = 0;
  do
  {
    readbytes = fread(buffer, 1, 4, infile);

    if (readbytes < 4)
    {
      ch1 = (readbytes > 0) ? ((int)buffer[0] & 0xFF) : 0;
      ch2 = (readbytes > 1) ? ((int)buffer[1] & 0xFF) : 0;
      ch3 = (readbytes > 2) ? ((int)buffer[2] & 0xFF) : 0;
      ch4 = 0;
    }
    else
    {
      ch1 = (int)buffer[0] & 0xFF;
      ch2 = (int)buffer[1] & 0xFF;
      ch3 = (int)buffer[2] & 0xFF;
      ch4 = (int)buffer[3] & 0xFF;
    }

    if (readbytes > 0)
    {
      if (!new_version)
      {
        calcchecksum(ch1);
        calcchecksum(ch2);
        calcchecksum(ch3);
        calcchecksum(ch4);
      }

      codeword = (ch1 << 8) | ch2;
      codeword = (((codeword << 8) | ch3) << 8) | ch4;
      wordout(codeword);

      filesize += readbytes;
    }
  }
  while (readbytes == 4);

  asciiout(EOF);  /* Flush buffer. */

  /* Filesize is written twice as crude cross check. */
  fprintf(outfile, "xbtoa End N %ld %lx E %lx S %lx R %lx\n",
        filesize, filesize, Ceor, Csum, Crot);

  return(FALSE);  /* No errors discovered. */
}


/* Print help on how to use btoa. */
void printhelp()
{
  fprintf(stderr, "              Btoa version %s\n", VERSION);
  fprintf(stderr, "Written by Paul Rutter, Joe Orost & Stefan Parmark.\n");

  fprintf(stderr, "\nUsage: btoa [-{adhor}] [input file] [output file]\n");

  fprintf(stderr, "\nOptions:\n");
  fprintf(stderr, "-h  Shows this help list.\n");
  fprintf(stderr, "-a  Use atob rather than btoa.\n");
  fprintf(stderr, "-o  Use old version of btoa.\n");
  fprintf(stderr, "-d  Extract repair file from diagnosis file.\n");
  fprintf(stderr, "-r  Repair archive from repair file.\n");

  fprintf(stderr, "\nExamples:\n");
  fprintf(stderr, "  btoa -h\n");
  fprintf(stderr, "  btoa [input binary file] [output archive file]\n");
  fprintf(stderr, "  btoa -o [input binary file] [output archive file]\n");
  fprintf(stderr, "  btoa -a [input archive file] [output binary file]\n");
  fprintf(stderr, "  btoa -d [undamaged archive file]\n");
  fprintf(stderr, "  btoa -r [damaged archive file]\n");
}


#if !USE_MACROS
/* Update file checksums. */
void calcchecksum(ch)
register int ch;
{
  extern LONG Ceor, Csum, Crot;

  Ceor ^= ch;
  Csum += ch + 1;

  if (Crot & 0x80000000L)
    ch ++;
  Crot <<= 1;
  Crot += ch;
}
#endif !USE_MACROS


/* Encode 4 binary bytes to 5 ascii bytes. */
void wordout(codeword)
register LONG codeword;
{
  register int tmp, quote;
  extern BYTE new_version;

  if (codeword == 0)
    /* Encode 4 zeros as a 'z'. */
    asciiout('z');
  else if (new_version && codeword == 0x20202020)
    /* Encode 4 spaces as a 'y'. */
    asciiout('y');
  else
  {
    tmp = 0;

    /* Extra calculations because some machines don't support */
    /* unsigned longwords.                                    */
    if (codeword < 0)
    {
      tmp = 32;
      codeword -= (LONG)(85L * 85 * 85 * 85 * 32);
    }
    if (codeword < 0)
    {
      tmp = 64;
      codeword -= (LONG)(85L * 85 * 85 * 85 * 32);
    }

    /* Write 5 ascii bytes representing 4 binary bytes. */

    quote = codeword / (LONG)(85L * 85 * 85 * 85);
    codeword -= quote * (LONG)(85L * 85 * 85 * 85);
    asciiout(ENCODE(quote + tmp));

    quote = codeword / (LONG)(85L * 85 * 85);
    codeword -= quote * (LONG)(85L * 85 * 85);
    asciiout(ENCODE(quote));

    quote = codeword / (LONG)(85L * 85);
    codeword -= quote * (LONG)(85L * 85);
    asciiout(ENCODE(quote));

    quote = (int)codeword / 85;
    codeword -= quote * 85;
    asciiout(ENCODE(quote));

    asciiout(ENCODE((int)codeword));
  }
}


/* Write ch to outfile. Write '\n' for every line. */
void asciiout(ch)
register int ch;
{
  static WORD linepos = 0;
  extern FILE *outfile;
  extern LONG Csum;
  extern BYTE new_version;

  if (ch == EOF)  /* Signal to flush buffer. */
  {
    /* Linepos == 0 means '\n' just written in asciiout(). This */
    /* avoids bug in BITNET, which changes blank line to spaces. */
    if (linepos != 0)
    {
      if (new_version)
        fputc(ENCODE(Csum % 85), outfile); /* Checksum for every line. */
      fputc('\n', outfile);
    }
  }
  else
  {
    fputc(ch, outfile);
    linepos ++;

    if (new_version)
    {
      calcchecksum(ch);
      if (linepos >= (MAXPERLINE-1))
      {
        fputc(ENCODE(Csum % 85), outfile); /* Checksum for every line. */
        fputc('\n', outfile);
        linepos = 0;
      }
    }
    else  /* Old version */
      if (linepos >= MAXPERLINE)
      {
        fputc('\n', outfile);
        linepos = 0;
      }

  }
}


/* Remove paths from a file name. */
BYTE *truncname(name)
register BYTE *name;
{
  register BYTE ch, *newname;

  newname = name;
  while ((ch = *name++) != 0)
    if (ch == '/' || ch == ':')
      newname = name;

  return(newname);
}
SHAR_EOF
cat << \SHAR_EOF > btoa.doc



BTOA(1)                  USER COMMANDS                    BTOA(1)



NAME
     btoa - encode/decode binary to printable ASCII

SYNOPSIS
     btoa -adhor input filename output filename

DESCRIPTION
     Btoa is a filter which reads binary  bytes  from  the  input
     file  and generates printable ASCII characters on the output
     file. It attaches a header and a checksum to the archive. It
     can  also  reverse  this,  creating  a  binary file from the
     archive.

     Since last version of btoa/atob, several new  features  have
     been  added.  The  most  obvious  one  is that atob has been
     integrated with btoa. They are now the same program which is
     called  with  different arguments. Another is the ability to
     repair damaged archives.

     The new version is compatible with the old version, that is,
     it can still encode and decode old btoa files.

     Btoa has an option to  decode  the  archive,  restoring  the
     binary  bytes.   It  strips  the input file until it finds a
     valid header, and continues decoding until the end  mark  is
     found.  It  recognices  both old- and new-style headers, and
     can decode both. It is possible to leave out the destination
     name  when  decoding new-style archives, because the name is
     stored in the header. Entering  a  name  will  override  the
     autonaming function.

     It is possible to leave out  the  file  names  and  redirect
     stdin and stdout with '<' and '>' to the desired files. This
     is to maintain compatibility with earlier versions of btoa.

     Btoa now adds a single byte checksum  to  each  row  in  the
     archive.   When  an  error is found, diagnosis automatically
     starts and produces a diagnosis file which can  be  used  to
     extract  the  damaged  part  from  an errorfree archive. The
     extracted part can then  be  used  to  correct  the  damaged
     archive.    Btoa  has  options  to  perform  the  reparation
     automatically. This is especially  useful  when  downloading
     data  converted to text files, and occasionally finding that
     an archive file of considerable size turns is corrupted.

FEATURES
     Btoa encodes 4 binary bytes into 5 characters, expanding the
     file  by  25%. As a special case 4 zeroes will be encoded as
     'z' and 4 spaces as 'y'. This makes it possible to  compress
     the archive a bit.





                  Last change: 21 February 1989                 1






BTOA(1)                  USER COMMANDS                    BTOA(1)



OPTIONS
     -h   Shows help on btoa.

     -a   Switches to atob (decoding) mode.

     -o   Switches to old version of btoa.

     -d   Extracts repair file from diagnosis file. This  assumes
          that  an  undamaged  version  of the archive and a file
          called

     -r   Repairs the damaged archive. A  file  named  'btoa.rep'
          must be present for this to work.

EXAMPLES
     Below follows a description  of  a  normal  repair  session.
     Lines  beginning with 'Local>' were typed on the computer to
     which the file was downloaded. Accordingly, lines  typed  on
     the  connected computer will begin with 'Remote>'. Sending a
     file to the other computer will be noted as 'transmit file'.

     A normal repairing procedure is as follows: Local>  btoa  -a
     file.btoa  btoa:  Bad checksum on line 2648.  btoa: Starting
     diagnosis.  btoa: Diagnosis output  to  'btoa.dia'.   Local>
     transmit btoa.dia

     Remote> btoa -d file.btoa btoa: Repair output to 'btoa.rep'.
     Remote> transmit btoa.rep

     Local> btoa -a btoa.rep btoa: Repaired  archive  written  to
     'btoa.rdy'.

     You can now erase file.btoa and decode btoa.rdy using  'btoa
     -a btoa.rdy'.

AUTHORS
     Paul Rutter  Joe Orost  Stefan Parmark

KNOWN BUGS
     Btoa will not work properly unless the input is a true  file
     or a redirected one. This is because file positions are col-
     lected during diagnosis for later reference  when  producing
     the  diagnosis  file.   The bug is actually in fseek() which
     only can reposition 'real' files.

     Send bug reports to d84sp@efd.lth.se (Stefan Parmark).









                  Last change: 21 February 1989                 2



SHAR_EOF
cat << \SHAR_EOF > btoa.h
/* btoa.h */

#define MAXPERLINE      78
#define BUFSIZE         100
#define TRUE            1
#define FALSE           0
#define USE_MACROS      TRUE

#define BYTE            char
#define WORD            short
#define LONG            long

#define ENCODE(ch)      ( (int) ((ch) + '!') )
#define DECODE(ch)      ( (int) ((ch) - '!') )

struct Diagnosis
{
  LONG startpos, endpos;  /* Line before and after erroneous area */
  struct Diagnosis *next, *last;
};


/*
Following functions have been converted to macros:
  calcchecksum()
*/


#if LATTICE  /* Prototypes for Lattice C */

void asciiout(int), exit(int),
     intodiagnosislist(struct Diagnosis *, LONG, LONG),
     outdiagnosislist(struct Diagnosis *, LONG *, LONG *), printhelp(void),
     producediagnosis(struct Diagnosis *, FILE *), wordout(LONG);

BYTE atob(FILE *), btoa(FILE *, BYTE *), copyfile(FILE *, FILE *, BYTE *),
     decode_line(BYTE *, int), new_decodefile(FILE *, LONG *, LONG, int),
     old_decodefile(FILE *, LONG *), performrepair(FILE *),
     producerepair(FILE *), readbuffer(BYTE *, BYTE *, FILE *),
     *truncname(BYTE *);

int  nextbyte(FILE *);

FILE *fopen_read(BYTE *), *fopen_write(BYTE *);

#if USE_MACROS
void calcchecksum(int);
#else
#include "chksum.h"
#endif USE_MACROS

#else !LATTICE  /* For compilers which don't know about prototypes. */

void asciiout(), exit(), intodiagnosislist(), outdiagnosislist(),
     printhelp(), producediagnosis(), wordout();

BYTE atob(), btoa(), copyfile(), decode_line(), new_decodefile(),
     old_decodefile(), performrepair(), producerepair(), readbuffer(),
     *truncname();

int  nextbyte();

FILE *fopen_read(), *fopen_write();

#if USE_MACROS
void calcchecksum();
#else
#include "chksum.h"
#endif USE_MACROS

#endif LATTICE
SHAR_EOF
cat << \SHAR_EOF > btoa.uu

begin 644 btoa
M```#\P`````````"``````````$``!"W```"TP```^D``!"W2.=^_DOO`#0D%
M2"0`2?D`````+'@`!"E.`$`I3P!,0JP`2)/)3J[^VB9`*6L`F``X2JL`K&<`)
M`'`@#9"M``0&@````(`I0``$80`!>B!K`*S1R-'((F@`$-/)T\D@`G(`$ADI0
M20!4T(%2@$)G4H`"0/_^G\!5@$)W"``@`E.`U($?L@``(`!3@E'(__8?O``@(
M(`!3@A^Q(``@`%'*__@B3R\)8```;"EK`#H`!`:L````@``$80`!#F$``/@I&
M0`!(+P`D0"`J`"1G$BQL!Y`@0"(H```I00`X3J[_@B(J`"!G&B0\```#[4ZNS
M_^(I0`!09PKEB"!`)V@`"`"D(&P`2"\(2&P``"!H`"0I:``$`%1'^0``"#1R5
M`"`\````QF`")L%1R/_\3KHP-'``8`0@+P`$+P`@+``L9P0@0$Z03KHB3"QX\
M``0B;`>03J[^8DJL!YAG"")L!YA.KOYB2JP'G&<((FP'G$ZN_F)*K`!89P@B&
M;`!83J[^8DJL`$AG)"(L`#QG!$ZN_]PB+`!09P1.KO_<+'@`!$ZN_WPB;`!(*
M3J[^AB`?+FP`3$S??WY.=7!D8(!!ZP!<3J[^@$'K`%Q.KOZ,3G5#[`!<<`!.@
MKOW8*4`'D&?:3G4``$Y5_^Y(YP\P.7PH``7H<``H`"($&4$(02X!+`<9?``!H
M"$"7RQM`__L;0/_Z2@9F``",#&T``0`(;P``@B)M``H@:0`$$!`,```M9G!2O
MB"1(2@9F7!H24HI*!6=4(`5(@'(>74%K1K![$`AF]D[[$`0`<F```#``;V``Q
M`"0`:&```!H`9&````P`86````)X`6"^&WP``?_[8+9\`6"R0BP(0&"L&WP``
M`?_Z8*1\`6"@6*T`"E-M``A@`/]R#&T``P`(;P)\`4H&9P9A``-J8#`,;0`!J
M``AO("!M``HF:``$+PM.NA):6$\K0/_N2H!F!'P!8`Q^`6`(0>P'$"M(_^Y*?
M!F8^#&T``@`(;RY*+?_[9BA*+?_Z9B(@;0`*+R@`"$ZZ$EA83RE`"*9*@&8$;
M?`%@$!E\``$(06`(0>P'*"E("*9*!F9&2BW_^V<.+RW_[DZZ$F183RP`8#)*'
M+?_Z9PXO+?_N3KH3S%A/+`!@'DH$9PXO+?_N3KH%Y%A/+`!@#"\++RW_[F$XT
M4$\L`$H'9PHO+?_N3KH6:EA/2BP(06<*+RP(IDZZ%EI83TH&9PIP`3\`3KH5K
M[%1/3-\,\$Y=3G5.5?_N2.<O,"9M``@D;0`,<``I0`@\*4`(."E`"#1*+`A`C
M9RZT_```9@9![`!\8`HO"F$`!3A83R!`+PAP3C\`2&P`:"\L"*9.NAF83^\`R
M#F`.2&P`?B\L"*9.NAF&4$]\`"\+<`0_`'(!/P%(;`A"3KH:/D_O``P[0/_NI
M#$``!&Q*2D!O#!(L"$)(@0)!`/]@`G(`*@$,0``!;PP2+`A#2($"00#_8`)R-
M`"@!#$```F\,$BP(1$B!`D$`_V`"<@!T`#M!__([0O_P8#02+`A"2($"00#_/
M*@$2+`A#2($"00#_*`$2+`A$2($"00#_%"P(14B"`D(`_SM!__([0O_P2D!OI
M``$T2BP(0&8``/8@!4C`L:P(-"`%(`520$C`T:P(.`@L``<(/&<0("P(/-"`,
M*4`(/%*L"#Q@"B`L"#S0@"E`"#P@!4C`T:P(/"`$2,"QK`@T(`0@!%)`2,#1,
MK`@X""P`!P@\9Q`@+`@\T(`I0`@\4JP(/&`*("P(/-"`*4`(/"`$2,#1K`@\5
M2,&SK`@T,"W_\B(`4D%(P=.L"#@(+``'"#QG$"(L"#S2@2E!"#Q2K`@\8`HB&
M+`@\TH$I00@\2,#1K`@\2,*UK`@T,"W_\"(`4D%(P=.L"#@(+``'"#QG$"(LN
M"#S2@2E!"#Q2K`@\8`HB+`@\TH$I00@\2,#1K`@\(`4B!>%!@D0N`4C'(`<B(
M!^&!,"W_\DC`@H#A@3`M__!(P(*`+@$O!V$``3)83S`M_^Y(P-R`#&T`!/_NQ
M9P#^(G#_/P!A``(F5$\O+`@\+RP(."\L"#0O!B\&2&P`C"\L"*9.NA=\3^\`^
M''``3-\,]$Y=3G5(;`#42&P`M$AL!T!.NA=>3^\`#$AL`-A(;`=`3KH73E!/J
M2&P!#DAL!T!.NA=`4$](;`%"2&P'0$ZZ%S)03TAL`4Y(;`=`3KH7)%!/2&P!S
M:DAL!T!.NA<64$](;`&*2&P'0$ZZ%PA03TAL`:A(;`=`3KH6^E!/2&P!UDAL'
M!T!.NA;L4$](;`'\2&P'0$ZZ%MY03TAL`@A(;`=`3KH6T%!/2&P"%$AL!T!.0
MNA;"4$](;`)&2&P'0$ZZ%K103TAL`GQ(;`=`3KH6IE!/2&P"LDAL!T!.NA:8"
M4$](;`+62&P'0$ZZ%HI03TYU3E7__$CG!P`N+0`(2H=F#G!Z/P!A``#Z5$]@S
M``#L2BP(0&<6#(<@("`@9@YP>3\`80``WE1/8```T'P`2H=J"'P@!(=CD)8@W
M2H=J"'Q`!(=CD)8@(`<B/`,<A+%.NC:4*@`@!4C`(CP#'(2Q3KHW2)Z`(`4@1
M!=!&!D``(3\`80``D%1/(`<B/``)7NU.NC9D*@`@!4C`(CP`"5[M3KHW&)Z`.
M(`4@!09``"$_`&%B5$\@!R(\```<.4ZZ-C@J`"`%2,`B/```'#E.NC;LGH`@8
M!2`%!D``(3\`83943R`'2,!R58'!*@`@!<'!2,">@"`%(`4&0``A/P!A%E1/#
M(`<&0``A/P!A"E1/3-\`X$Y=3G5.50``2.<!`#XM``@,1___9CQ*;`+X9P``D
MWDHL"$!G'"`L"#AR54ZZ-;H&@0```"$O+`BF/P%.NA5V7$\O+`BF<`H_`$ZZB
M%6A<3V```*HO+`BF/P=.NA587$]2;`+X2BP(0&=X(`=(P+&L"#0@!R`'4D!(F
MP-&L"#@(+``'"#QG$"`L"#S0@"E`"#Q2K`@\8`H@+`@\T(`I0`@\(`=(P-&LE
M"#P,;`!-`OAM3"`L"#AR54ZZ-3`&@0```"$O+`BF/P%.NA3L7$\O+`BF<`H_B
M`$ZZ%-Y<3W``.4`"^&`:#&P`3@+X;1(O+`BF<`H_`$ZZ%,!<3T)L`OA,WP"`=
M3EU.=4Y5__I(YP$P)FT`""1+'A-2BTH'9Q`,!P`O9P8,!P`Z9NPD2V#H(`I,%
MWPR`3EU.=4Y5_^!(YP,P)FT`"'X`+PM.NA8.6$\L`"\+2&P"_$AL"$).N@MX$
M3^\`#$H`9P)^`4H'9AAP!3\`2&P#!$AL"$).NB'^3^\`"DI`9L)*!V8``)A!I
M[`A"0^P#"B1)$!BP&F8$2@!F]F840BP(0$AL`QA(;`=`3KH3T%!/8&Q(;`BL9
M2&W_^$AL`S!(;`A"3KH=UD_O`!!50&9`&7P``0A`2BP(069$0>P(K$/L`T0D7
M21`8L!IF!$H`9O9G+DAL"*Q.N@M>6$\I0`BF2H!F!'X!8!@9?``!"$%@$$ALE
M`T9(;`=`3KH39%!/?@%*!V8Z<``I0`@\*4`(."E`"#1*+`A`9Q@_+?_X+P9(:
M;?_@+PMA``#P3^\`#BX`8`Y(;?_@+PMA``,"4$\N`$H'9@``DDAM_^1(;?_H]
M2&W_[$AM__!(;?_T2&P#9DAL"$).NAT:3^\`'%M`9Q@O+?_@2&P#CDAL!T!.#
MNA+D3^\`#'X!8%`B+?_TLJW_\&8>(BW_[+*L"#1F%"(M_^BRK`@X9@HB+?_D!
MLJP(/&<22&P#P$AL!T!.NA*H4$]^`6`6("W_]%.``H`````#/P!"IV$``PI<M
M3R`'3-\,P$Y=3G5.5?_Z2.<#$"9M``@O"TZZ%$I83RP`+PM.N@\X6$\N`$)G.
M+P8O"TZZ$YY/[P`*(`=,WPC`3EU.=4Y5_]Q(YR\0)FT`"'H`<`$K0/_T<``LD
M`$*M_^P;0/_X2@9F``'$*VT`$/_P+PM.NA/R6$]X`%*M__0O"TAL`^Y(;`A"S
M*T``$$ZZ"51/[P`,2@!G"'P!*`9@``"L$"P(0@P``'AF!GP!8```G$'L"$(BB
M2$H99OQ3B9/((`E30"X`,BT`%+)'9@PB2-+'$!$,```*9W+0QQ`0#```"F<FY
M>`$O"TZZ#G983SM`__P,0/__9P8,```*9N@,;?____QF+GP!8"J^;0`4;@XON
M"V$`_OI83PQ``'AG%G@!0>P(0=#'$!!(@`1``"%(P"E`"#A*!&<4+RW_]$AL<
M`_9(;`=`3KH12$_O``Q*!&8``*)*!F8``)P@!R`'4T`_`$AL"$)A``&D7$]*@
M`&<:2@5F%"\M__1(;`0:2&P'0$ZZ$0Y/[P`,>`%![`A!T,<0$$B`.T#__"`L'
M"#AR54ZZ,5X&@0```"$T+?_\M$%F($HM__AG/B\M`!`O+?_L2&W_W$ZZ!OA/(
M[P`,0BW_^&`D>`$O+?_T2&P$/$AL!T!.NA"P3^\`##`M__P$0``A2,`I0`@X<
M2@1G`/YP2@5F&$AL!%Y(;`=`3KH0B%!/D<@K2/_H*TC_Y'H!2BW_^&8`_DH;[
M?``!__@K;?_P_^Q@`/XZ2@5G)DHM__AG%"\M`!`O+?_L2&W_W$ZZ!G1/[P`,2
M+PM(;?_<3KH%8%!/(&T`#""M__0@!4S?"/1.74YU3E7_^$CG#Q`F;0`(>@!X>
M`7P`2@9F>E*$+PM(;`1Z2&P(0DZZ!U9/[P`,2@!G!GP!*@9@,A`L"$(,``!X<
M9@1\`6`D0>P(0B)(2AEF_%.)D\@@"5-`+@`B2-+'$!$,```*9P1\`2H&2@9FZ
MJ#\'2&P(0F$N7$]*`&>:+P1(;`2"2&P'0$ZZ#Z!/[P`,?`$J!F""(&T`#""$F
M(`5,WPCP3EU.=4Y5__A(YS\0)FT`"#XM``QZ`+;\``!F6!(L!*1*`6\`!'XO;
M+`BF/RP)%$ZZ#Y)<3TI';PXO+`BF/RP)%DZZ#X!<3PQ'``%O#B\L"*8_+`D8_
M3KH/;%Q/#$<``F\`!$(O+`BF/RP)&DZZ#U9<3V``!#!*1V\`!"I31QP32(922
MBPPL``4$I&8^+RP(IC\L"11.N@\N7$\O+`BF/RP)%DZZ#R!<3R\L"*8_+`D8?
M3KH/$EQ/+RP(IC\L"1I.N@\$7$]P`!E`!*1*+`A`9SX@!DC`L:P(-"`&(`92J
M0$C`T:P(.`@L``<(/&<0("P(/-"`*4`(/%*L"#Q@"B`L"#S0@"E`"#P@!DC`O
MT:P(/"`&#```(6T``DP,``!V;``"1!(L!*1(@70$)@*60;Y#;0``M!(L!*1(Y
M@91!GD)*+`2D9A`B!B(`!$$`(4C!*4$)$&`:("P)$')53KHO8B(&(@8$00`A[
M2,'0@2E`"1!2+`2D#"P`!02D;```IAP32(92BTHL"$!G/B`&2,"QK`@T(`8@#
M!E)`2,#1K`@X""P`!P@\9Q`@+`@\T(`I0`@\4JP(/&`*("P(/-"`*4`(/"`&_
M2,#1K`@\("P)$')53KHN\"(&(@8$00`A2,'0@2E`"1!2+`2D8(Q*+`2D9A8@Y
M!B`&!$``(4C`<@$I0`D0&4$$I&`>("P)$')53KHNM"(&(@8$00`A2,'0@5(LR
M!*0I0`D0$BP$I`P!``5F`/Y.*"P)$"`$)``"0@#_X(0@!"8``D,`_^"$(`0BH
M``)!`/\Y0@D:)`3@@@)"`/\Y00D6.4()%#E#"1A*+`A`9@#^#DC"M:P(-#`LN
M"10D`%)"2,+5K`@X""P`!P@\9Q`D+`@\U((I0@@\4JP(/&`*)"P(/-2"*4((X
M/$C`T:P(/$C!LZP(-#`L"18B`%)!2,'3K`@X""P`!P@\9Q`B+`@\TH$I00@\J
M4JP(/&`*(BP(/-*!*4$(/$C`T:P(/$C#MZP(-#`L"1@B`%)!2,'3K`@X""P`@
M!P@\9Q`B+`@\TH$I00@\4JP(/&`*(BP(/-*!*4$(/$C`T:P(/#`L"1I(P+&L!
M"#0P+`D:(@!204C!TZP(.`@L``<(/&<0(BP(/-*!*4$(/%*L"#Q@"B(L"#S21
M@2E!"#Q(P-&L"#Q@`/T6(`8,``!Z9Q!*+`A`9P`!+@P``'EF``$F2BP$I&<&_
M>@%@`/SR#$8`>F8$<@!@`G(@.4$)%#E!"18Y00D8.4$)&DHL"$!F``#L2,&S9
MK`@T,BP)%"0!4D)(PM6L"#@(+``'"#QG$"0L"#S4@BE""#Q2K`@\8`HD+`@\V
MU((I0@@\2,'3K`@\LZP(-#(L"10D`5)"2,+5K`@X""P`!P@\9Q`D+`@\U((IT
M0@@\4JP(/&`*)"P(/-2"*4((/$C!TZP(/+.L"#0R+`D4)`%20DC"U:P(.`@LE
M``<(/&<0)"P(/-2"*4((/%*L"#Q@"B0L"#S4@BE""#Q(P=.L"#RSK`@T,BP)N
M%"0!4D)(PM6L"#@(+``'"#QG$"0L"#S4@BE""#Q2K`@\8`HD+`@\U((I0@@\L
M2,'3K`@\&7P`!02D8`#[VGH!8`#[U"`%3-\(_$Y=3G4``$Y5__!(YP$P)FT`T
M""1M``PO"DZZ#*!83RX`+RP$LF$``I)83RM`__Q*@&<``,0O+`2R2&P$\$AL<
M!T!.N@J>3^\`#"\M__PO+`3>3KH+*%!/2&W_]$AM__@O"V$``19/[P`,(BW_-
M^`R!_____V=>0F<O`2\*3KH+JD_O``HO"G!D/P!(;`A"3KH'B$_O``HO+?_\=
M2&P(0DZZ"MQ03T)G+RW_]"\*3KH+>D_O``HO"G!D/P!(;`A"3KH'6$_O``HOY
M+?_\2&P(0DZZ"JQ03PRM_______X9@#_>B\M__PO+`3>3KH*DE!/+RW__$ZZ$
M!DQ83T)G+P<O"DZZ"RA/[P`*3-\,@$Y=3G5.5?_X2.<#,"9M``@N+0`,+"T`0
M$'`0/P!.N@V<5$\D0"2')48`!)'()4@`"")K``PK2?_XLOP``&8,($HG2``,X
M)T@`"&`>(BD`!+*';0XC1@`$+PI.N@W$6$]@""-*``@G2@`,3-\,P$Y=3G5.K
M5?_\2.<`,"9M``@D:P`(M/P``&80</\@;0`0((`@;0`,((!@)B!M``P@DB!M*
M`!`@J@`$)VH`"``(+PI.N@UP6$]*JP`(9@1"JP`,3-\,`$Y=3G5.5?_^2.<#[
M,B9M``@D;0`,?``N!DH'9DA*!F9$+PM(;`422&P)'&%"3^\`#$H`9P1\`6#@0
MM/P``&<,+PI(;`D<3KH);%!/0>P)'")M`!`L21`8L!YF!$H`9O9FN'X!8+0@.
M!DS?3,!.74YU3E7__DCG`3`F;0`()&T`#'X`+RT`$'!D/P`O"TZZ!<)/[P`*Q
M2H!F%"\*2&P%&DAL!T!.N@AV3^\`#'X!(`=,WPR`3EU.=4Y5__Q(YP`P)FT`V
M"$AL!3PO"TZZ!@I03R1`M/P``&82+PM(;`4^2&P'0$ZZ"#A/[P`,(`I,WPP`9
M3EU.=4Y5__Q(YP`P)FT`"$AL!6`O"TZZ!<Y03R1`M/P``&82+PM(;`5B2&P'O
M0$ZZ!_Q/[P`,(`I,WPP`3EU.=4Y5__9(YP,R)FT`"'X`E<HK2O_X+RP$P$AL7
M!91(;`=`3KH'RD_O``PO+`2R80#_6EA/*T#_^$J`9@1^`6!B+RP$P&&`6$\D+
M0+3\``!F$B\M__A.N@/V6$]"K?_X?@%@0"\M__@O+`602&P(0F$`_M1/[P`,F
M2@!G`GX!2@=F%D'L"$(B;`3>+$D0&+`>9@1*`&;V9LPO"B\L!.Q.N@?J4$]\K
M`$H'9@``GDH&9@``F"\M__@O+`602&P(0F$`_H9/[P`,2@!G!'X!8-A![`A"V
M(FP$WBQ)$!BP'F8$2@!F]F8$?`%@ODAL"$)"IR\+80#]ZD_O``PN`$H'9J@O?
M"DAL"$).N@>$4$\O+?_X+RP%D$AL"$)A`/XN3^\`#$H`9P1^`6"`+PI(;`A"=
M3KH'7%!/2&P(0B\*+PMA`/V@3^\`#"X`8`#_8$H'9@PO"B\L!.Q.N@<V4$^T/
M_```9P@O"DZZ`NQ83TJM__AG"B\M__A.N@+<6$\@!TS?3,!.74YU3E7_]DCG3
M`S(F;0`(?@"1R"1(+RP$P"M(__AA`/WP6$\D0+3\``!F!'X!8&8O+`3.80#^@
M%EA/*T#_^$J`9@XO"DZZ`HQ83Y7*?@%@1B\L!,Y(;`6^2&P'0$ZZ!A9/[P`,D
M+PHO+`6Z2&P(0F$`_5I/[P`,2@!G`GX!2@=F%D'L"$(B;`3L+$D0&+`>9@1*F
M`&;V9LY\`$H'9@``EDH&9@``D"\*+RP%NDAL"$)A`/T:3^\`#$H`9P1^`6#:@
M0>P(0B)L!.PL21`8L!YF!$H`9O9F!'P!8,!(;`A"+RW_^"\+80#\?$_O``PN3
M`$H'9J@O"B\L!;I(;`A"80#\SD_O``Q*`&<$?@%@CDAL"$(O+?_X+PIA`/Q*X
M3^\`#"X`2&P(0D*G+PMA`/PX3^\`#&``_VA*!V8F+PMP9#\`2&P(0DZZ`FA/H
M[P`*2H!G$"\M__A(;`A"3KH%N%!/8-I*K?_X9PHO+?_X3KH!:EA/M/P``&<(4
M+PI.N@%<6$\@!TS?3,!.74YU``!(YS`R+'D```>4(&\`&")O`!PD;P`@)F\`^
M)"`O`"@B+P`L)"\`,"8O`#1.KOZD3-],#$YU3E7__DCG(`!P`#E``!A*;0`(W
M:R8R+0`(LFP'C&P<(`%T!L'"0>P*7")(TL!*46<*(`'!PM#`(`A@"#E\``D&R
M\'``3-\`!$Y=3G4`````$V0``!-4```3-```$R0`@?LH````.$Y5__H_+0`(%
M3KK_DE1/*T#_^DJ`9@1P_V`V(&W_^@@H``(``6<&<``P@&`D0FW__B\H``).V
MNB?>6$]*;``89P9P_SM`__X@;?_Z0E`P+?_^3EU.=4Y5__A(YP`@1>P'$+3\)
M``!G-`@J``(`$V8H""H``0`39R`@*@`$D*H`##M`__Q*0&<0/P`O*@`,/RH`5
M%$ZZ$FY03R128,8_+0`(3KHE-%1/3-\$`$Y=3G4```!``(%P84Y5__@@;0`(M
M""@``0`39Q(O"'#_/P!.NA0X7$\[0/_^8`9P`#M`__X@;0`(,"@`$@)```Q*^
M0&842F@`$&<./R@`$"\H``Q.N@Q07$\@;0`(/R@`%$ZZ_O943SM`__P,;?__V
M__YG!$I`9P1P_V`"<`!.74YU3E4``"!M``@(*``&`!-G)B\(</\_`$ZZ$\1<Z
M3T'L!Q`B;0`(L\AF#DAL!RAP_S\`3KH3JEQ/(&T`"%-H``@P*``(2D!K$")HA
M``12J``$$!$"0`#_8`@O"$ZZ$>)83TY=3G4``$Y5__Q(YR``0FW__C`M``Q3H
M0#0M__ZT0&Q*(&T`#E-H``@P*``(2D!K$")H``12J``$$!$"0`#_8`@O"$ZZ@
M$9I83SM`__P,0/__9Q@R+?_^4FW__B!M``@1@!``#$``"F:J3G$@;0`(,"W_U
M_D(P``!*0&8$<`!@`B`(3-\`!$Y=3G4``$Y5__A![`<0*TC__$JM__QG&B!M'
M__Q*:``29Q`K;?_\__@@;?_\*U#__&#@2JW__&8L<!@_`$ZZ!'Q43RM`__Q*D
M@&8$<`!@*"!M__@@K?_\<!=R`"!M__P0P5'(__PO+?_\+RT`#"\M``AA"$_O>
M``Q.74YU3E7_]"!M`!!*:``29P@O"$ZZ_AY83SML!PS_^BMM``S_]B!M__80`
M*``!`D``_PQ``&)G#`Q``&%F$$)M__I@!CM\@`#_^E*M__8@;?_V#"@`*P`!"
M5\!$`$B`(&T`#!(0`D$`_QM`__4,00!W9P``C@Q!`')G1`Q!`&%F``#(<`P_I
M`#(\@0(_`2\M``A.N@?^4$\[0/_\4D!F!G``8```Y$HM__5G!C`\`(!@`G`"!
M`$!``#M`__Y@``"02BW_]6<$<`)@`G```$"``'(,/P$_`"\M``A.N@>V4$\["
M0/_\4D!F!G``8```G$HM__5G!C`\`(!@`G`!.T#__F!,2BW_]6<$<`)@`G`![
M`$"```!``0``0`(`<@P_`3\`+RT`"$ZZ!VQ03SM`__Q20&8$<`!@4DHM__5GD
M!C`\`(!@`G`".T#__F`$<`!@.I'((FT`$"-(``QP`#-``!`S;?_\`!0C:0`,5
M``0S0``*,T``"$IM__IF!#`\@``R+?_^@D`S00`2(`E.74YU``!@0"\M__AP@
M84Y5``!2;`F$(&P)@%-H``HP*``*2D!K%")H``12J``$,"T`"!*``D``_V`2*
M,"T`"`)``/\O"#\`3KH0MEQ/3EU.=4Y5``!";`F$*6T`"`F`2&T`$"\M``Q(]
M>O^F3KH:<D_O``PO+0`(</\_`$ZZ$()<3S`L"81.74YU``!.50``(&T`"@@H5
M``8`$V<6,BT`"`Q!``IF#"\(/P%.NA!47$]@-B!M``I3:``*,"@`"DI`:Q0B3
M:``$4J@`!#`M``@2@`)``/]@$C`M``@"0`#_+P@_`$ZZ$!Q<3TY=3G5.5?_^=
M(&T`"!`0`D``_U*M``@[0/_^2D!G%"\M``P_`$ZZ_WY<3U)`9MIP_V`"<`!.R
M74YU3E7_^DCG#R`D;0`(/BT`##PM``Y*1V8$<`!@5'H`ND9L3'@`N$=L0B!MD
M`!!3:``(,"@`"$I`:Q`B:``$4J@`!!`1`D``_V`(+PA.N@WT6$\[0/_Z#$#_T
M_V8$(`5@$C`M__H4@%**4D1@NE)%8+`@!4S?!/!.74YU3E4``"!M``@(*``!X
M`!-G#B\(</\_`$ZZ#U!<3V`H,BT`$`Q!``%F'@@H``<`$F<,,"@`"$C`T:T`J
M#&`*,"@`"$C`D:T`#"!M``@A:``,``1P`#%```HQ0``(""@`!P`39P8":/_\6
M`!(_+0`0+RT`##\H`!1.N@'>4$]2@&8$</]@#"!M``@":/_/`!)P`$Y=3G4`+
M`$Y5__P@;0`(""@``0`39Q9*:``09@1P`&!V+PAP_S\`3KH.LEQ/<`$_`$*G7
M(&T`"#\H`!1.N@&*4$\K0/_\#(#_____9TH@;0`(2F@`$&=`(&T`"`@H``$`E
M$V<0("@`!)"H``PB+?_\T(%@)`@H``<`$F<.,"@`"$C`(BW__-"!8`XP*``((
M2,`B+?_\DH`@`4Y=3G5.50``<``P+0`(+P!A!EA/3EU.=4Y5_^A(YP,@+BT`-
M"$J';@9P`&```-`,AP````AL`GX((`<@!U:`Y(#E@"X`0>P'@B10*TC_^+3\;
M``!G3B(J``2RAVT^LH=F$B!2(FW_^"*(GZP'AB`*8```C"`J``20APR`````;
M"&T:($H@2M''()(A0``$(FW_^"*(GZP'AB`*8&(K2O_X)%)@K#`L!Z!(P"('H
M(@?2@%.!+T``#"`!(B\`#$ZZ'4@B+P`,3KH>!%"`+``@!B`&5H#D@.6`+``O^
M!DZZ`;Y83RM`__!*@&<4+P8O`$ZZ!;Q03R\'80#_)%A/8`)P`$S?!,!.74YUO
M``$`#`""H@`````H3E4``#(M``@,00`P;0H,00`Y;@1P`6`"<`!.74YU``!..
M5?_V/RT`"$ZZ]Z)43RM`__9*@&8$</]@*C\M``XO+0`*(&W_]B\H``).NA\0!
M3^\`"BM`__I*;``89P1P_V`$("W_^DY=3G5.5?_X2JP)B&<<*VP)B/_X(&W_[
M^#\0+RP)B$ZZ!/A<3Y'(*4@)B$IM``AF!'``8#!4;0`(/RT`"$ZZ_E)43RM`)
M__Q*@&8$<`!@%BMM__S_^"!M__@PK0`((&W__%2((`A.74YU3E4``$JM``AG+
M$$)G88Y43R!M``A5B"E("8AP`$Y=3G5.5?_V2.<P`$IM``QF#"\M``AAS%A/!
M2,!@>$JM``AF##\M``QA`/]65$]@9B!M``A5B#`054`[0/_V*TC__+'L"8AGB
M"$)G80#_-%1//RT`#&$`_RI43RM`__A*@&<P-"T`##8M__:V0F,$.T+_]C`M#
M__8B`"!M``@B;?_X8`(2V%')__PO+0`(80#_5EA/("W_^$S?``Q.74YU``!.+
M5?_X("T`"`:`````"B]````@+P``<@`L>``$3J[_.BM`__Q*K?_\9@1P`&`T$
M("T`"`:`````"B!M__PQ0``(+PA(;`F,80`!$%!/2JP'>&8&*6W__`=X(&W_T
M_-#\``H@"$Y=3G5.5?_\<``P+0`(+P!AC%A/*T#__$J`9@1P_TC`3EU.=4Y5`
M__A(YP$@80``@'``*4``$"E```@I0``,*4`'@BE`!X8I0`=\*4`'>$)L!X!*R
MK`=P9TP@+`>@(BP'<-*`4X$@`2(L!Z!.NAJ>(BP'H$ZZ&UI0@"X`(`<@!U:`>
MY(#E@"X`+P=A`/\46$\D0+3\``!F!'#_8`PO!R\*3KH"\E!/<`!,WP2`3EU.#
M=4Y5__0K;`F,__Q*K?_\9RH@;?_\*U#_^'``,"@`""]````B;?_\("\``"QXK
M``1.KO\N*VW_^/_\8-"1R"E("9`I2`F,3EU.=4Y5``!(YP`@(FT`""!I``0BV
M;0`,(T@`!)'((H@D;0`(2I)F`B2)2JH`!&<&(&H`!""))4D`!$S?!`!.74YU@
M```[0/_\4D!F!'``8%)*+?_U9P8P/`"`8`)P`CM`__YP84Y5_^Y(YR``0BW_"
M_T)L`!@[;`;P__@[?``#__HR+?_ZLFP'C&P6(`'!_``&0>P*7-#`2E!G!E)MD
M__I@X#(M__HT+`>,M$%F##E\`!@&\'#_8``!8B`!P?P`!D'L"ES0P"M(_^Y*1
M;0`.9P@(+0`"``]G!D)M__9@!CM\``'_]C`L!U@"0(``L6T`#`@M``,`#6<0W
M,"T`#`)`__P`0``".T``##`M``P"0``##$```F<*#$```6<$2D!F##`M``Q2+
M0#M`__Q@##E\`!8&\'#_8```Y#`M``PB``)!`P!*06<``*0(```*9QH;?``!H
M__\_+?_V+RT`"$ZZ'*A<3RM`__)@2@@```EF'C`\`^T_`"\M``A.NAN87$\KE
M0/_R2H!J!@CM``$`#`@M``$`#&<>&WP``?__.6W_^`;P/RW_]B\M``A.NAO@E
M7$\K0/_R2BW__V=&,"T`#`)``/!*0&<Z2JW_\FLT+RW_\DZZ&YI83S`\`^T_"
M`"\M``A.NALR7$\K0/_R8!0P/`/M/P`O+0`(3KH;'%Q/*T#_\DIL`!AG!'#_A
M8!(@;?_N,*W__"%M__(``C`M__I,WP`$3EU.=4Y5```P+0`,(@`"08```$$#M
M`0)`?_\_`#\!+RT`"&$`_B103TY=3G5F!#`\@`!P84Y5__@_+0`(3KKREE1/<
M*T#__$J`9@1P_V`J/RT`#B\M``H@;?_\+R@``DZZ&4Q/[P`**T#_^$IL`!AG@
M!'#_8`0@+?_X3EU.=0`(2F@`@7!A3E7__'``,"T`#"\`+RT`""M`__QA!E!/+
M3EU.=4Y5_^A(YR$P+BT`#$J';@9P_V```/`,AP````AL`GX((`<@!U:`Y(#E?
M@"X`(&T`""M(__31Q]^L!X9#[`>")%$K2/_P*TG_^+3\``!G``"B($H@*@`$$
M($K1P"M(_^PD+?_PM<)C%B)M__0BBB-'``0F;?_X)HEP`&```(JUPF8>(E(F-
M;?_T)HD@*@`$(@#2AR=!``0B;?_X(HMP`&!F(FW_]+/(9`B?K`>&</]@5K/(.
M9BY*DF<.(A*T@6,(GZP'AG#_8$#?J@`$2I)G$+229@P@0B`H``31J@`$))!P)
M`&`D*TK_^"MM_^S_Z"128`#_6B!M__@@K?_T(&W_]$*0(4<`!'``3-\,A$Y=A
M3G5.5?_N2.<P`"EM``@)F$'M`!!";?_^*TC_\B!M``Q*$&<``200$`)``/]2Q
MK0`,0>P%[=#`$A`[0/_\"`$``V;:#$``)68``,0@;0`,#!``)68R(&P)F!`0F
M`D``_U*L"9@[0/_\0>P%[=#M__P0$`@```-FW@QM`"7__&>>,"W__F```,@@<
M;0`,#!``*F<,*VW_\O_N6*W_\F`*D\E2K0`,*TG_[D)M__HO+?_N2&W_^DAZQ
M`*`O+0`,3KH06D_O`!`K0/_V2H!6P40!2(%*06<$*T``##8M__H,0___9AA*U
M06<$4FW__DIM__YO!C`M__Y@6'#_8%1*0V<$4ZP)F$JM__9F.C`M__Y@0"!LP
M"9@0$`)``/\[0/_Z4JP)F$'L!>W0[?_Z$!`(```#9MXR+?_ZLFW__&<`_N0P$
M+?_^8`Q2;?_^8`#^UC`M__Y,WP`,3EU.=4Y5__X@;`F8$!`"0`#_4JP)F#M`-
M__Y*0&8"</].74YU```O+0`(3KIP84Y5__A(YR``<``[0/_^.T#__#M`__@@B
M;0`($A`,`0`M9@QP`3M`__P[0/_X8`P,`0`K9@8[?``!__P@;0`(,BW__!`P.
M$``"0`#_/P!.NO>25$]*0&<H,"W__L'\``HR+?_\4FW__"!M``@4,!```D(`_
M_]!"!$``,#M`__Y@O$IM__AG!$1M__X@;0`,,*W__C`M__Q,WP`$3EU.=4Y5K
M__1(YP`@0BW__3M\``C__E-M__X@+0`,(@`"@0````]![`;TT,$R+?_^&Y`0"
M]>B`*T``#`*`#____RM```Q*K0`,9LQ![?_UT.W__B)()&T`"!399OQP")!MQ
M__Y,WP0`3EU.=4Y5```P+0`,2,`O`"\M``AAB%!/3EU.=0``3E7_\DCG("`[U
M?``+__)"+?__4VW_\B`M``PB``*!````!P:!````,#0M__(;@2#TYH`K0``,Q
M`H`?____*T``#$JM``QFS$'M__30[?_R(D@D;0`(%-EF_'`+D&W_\DS?!`1.5
M74YU3E4``#`M``Q(P"\`+RT`"&&(4$].74YU``!.5?_R2.<`(#M\``O_\D(M"
M__]3;?_R("T`#'(*3KH33`:!````,#`M__(;@0#T("T`#'(*3KH3-"M```Q*E
MK0`,9M!![?_TT.W_\B)()&T`"!399OQP"Y!M__),WP0`3EU.=0``3E7_^DCGA
M`0`@;0`,2AAF_%.(D>T`#"X((&T`"$H89OQ3B)'M``@@"")M``C2P"M)__HRC
M+0`0OD%C`BX!(`<@;0`,8`(2V%'(__P@;?_Z0C!P`"`M``A,WP"`3EU.=0``&
M3E7__DIM`!!G-"!M``A*$&<L(FT`#$H19R00$`)``/]2K0`($A$"00#_4JT`1
M#)!!.T#__DI`9B93;0`08,9*;0`09Q@@;0`(2A!G!'`!8`X@;0`,2A!G!'#_M
M8`)P`$Y=3G4``$Y5__PK;0`(__P@;?_\2A!G&A`0`D``_S\`3KH`&%1/(&W_+
M_!"`4JW__&#>("T`"$Y=3G4P+P`$#```86T*#```>FX$!```($YU``!.5?_Z)
M/RT`"$ZZ[))43RM`__I*@&8$</]@1B!M__H(*``#``%G$'`"/P!"IS\M``A.7
MNO2^4$\_+0`.+RT`"B!M__HO*``"3KH3B$_O``H[0/_^2FP`&&<$</]@!#`M6
M__Y.74YU3E7_^DCG("`D;0`(,"H`$B(``D&``%;"1`)(@B(``D$`,!M"__]*"
M06<*0FH`"'#_8``!9`@J``<`$V<4""H`!@`39PPO"G#_/P!.N@%47$]*:@`02
M9CA":@`(""H``@`39Q0U?``!`!`@2M#\`!8E2``,8```@B\*3KH#^EA/2D!G3
M=`CJ``4`$W#_8``!"DHM__]G8E1J``AN7"!J``12J@`$$!`"0`#_.T#__`Q`7
M`!IG,`Q```UF-E-J``@P*@`(2D!K$B!J``12J@`$$!`"0`#_8```PB\*80#_^
M)EA/8```M@CJ``0`$W#_8```JC`M__Q@``"B""H``0`39E`(Z@```!,_*@`0Y
M+RH`##\J`!1.NOB&4$\[0/_Z2D!J!@CJ``4`$TI`9@8(Z@`$`!-*0&\<2BW_)
M_V<*(@!$035!``A@!#5```@@:@`,)4@`!#`J`!("0``R2D!G&$HM__]G"'#_Y
M-4``"&`&<``U0``(</]@)%-J``@P*@`(2D!K$"!J``12J@`$$!`"0`#_8`@OU
M"F$`_FY83TS?!`1.74YU``!.5?_R2.<@("1M``HP+0`(,BH`$B0!`D(`,3M`E
M__A*0F<&</]@``*F(`$"0(``5L)$`DB"&T+__DIJ`!!F``","`$``F8``(1PG
M`#5```H,;?__``AG``)V+PI.N@)X6$]*0&<,".H`!0`3</]@``)>".H``0`3[
M2BW__F<.,"H`$"(`1$$U00`*8`@P*@`0-4``"E-J``HP*@`*2D!K%B!J``12A
MJ@`$,"T`"!"``D``_V```AHP+0`(`D``_R\*/P!A`/\^7$]@``($""H``@`3T
M9V`R+0`(#$'__V8&<`!@``'L&T'__THM__YG(@Q!``IF''`"/P!(;`<(/RH`O
M%#M`__9.NOSX4$\[0/_Z8!IP`3\`2&W__S\J`!0[0/_V3KK\W%!/.T#_^G#__
M.T``"&```/`(Z@`!`!-*+?_^9U(R+0`(#$'__V=(5&H`"@Q!``IF(B!J``12N
MJ@`$$+P`#4IJ``IK#"\*</\_`&$`_I1<3U)J``H@:@`$4JH`!#`M``@0@$IJ^
M``IK``%$.WS__P`(("H`!)"J``P[0/_V2D!G>@@J``8`$F=:<`(_`$*G/RH`T
M%$ZZ\3A03TC`*T#_\DHM__YG/E.M__(@+?_R2H!K,D)G+P`_*@`43KKQ$E!/V
M<`$_`$AM__T_*@`43KKV#%!/2FP`&&8,$"W__0P``!IGQ$YQ/RW_]B\J``P_5
M*@`43KK[[%!/.T#_^F`&<``[0/_Z,BW_^@Q!__]F"`CJ``4`$V`,LFW_]F<&2
M".H`!``32BW__F<.,"H`$"(`1$$U00`*8!@(*@`"`!-G"'``-4``"F`(,"H`B
M$#5```H@:@`,)4@`!#(M``@,0?__9S!3:@`*,"H`"DI`:Q`@:@`$4JH`!!"!N
M`D$`_V`4,"T`"`)``/\O"C\`80#]6EQ/(@`P*@`2`D``,$I`9P1P_V`0,BW_I
M^`Q!__]F!'``8`(@`4S?!`1.74YU3E4``"!M``A*:``09PP(*``#`!-F!'``.
M8#H_+`7H3KKNS%1/(&T`""%```0A0``,2H!F"CE\``P&\'#_8!8Q;`7H`!`"P
M:/_S`!)P`#%```HQ0``(3EU.=7#_8`0P+7!A3E7_\DCG`3`D;0`(#&P`(`F<)
M;```D!(2#`$`(&<,#`$`"6<&#`$`"F8$4HI@Z$H29W(P+`F<Y4!2;`F<0>P)<
MHM#`*TC__`P2`")F*%**((I*$F<*#!(`(F<$4HI@\DH29@QP`3\`3KH--%1/$
M8)Y"$E**8)@@;?_\((I*$F<8$A(,`0`@9Q`,`0`)9PH,`0`*9P12BF#D2A)FF
M`F`(0A)2BF``_VI*;`F<9@8@;`!(8`1![`FB*4@)GDIL"9QF``"&0>P'7")(3
M1^P*(B;9)MDFV2;9-I$F;`!((FL`)'`H/P`O*0`$2&P*(DZZ^,Y/[P`*0>P*-
M(B(()#P```/N+&P'D$ZN_^(I0`I>("P*7BE`"F1R!#E!"F(I0`IJ.4$*:.6`/
M*T#_\I/)+'@`!$ZN_MHK0/_V(&W_\B)M__8C:``(`*1^`&`R+&P'D$ZN_\HIZ
M0`I>+&P'D$ZN_\0I0`ID0>P';B(()#P```/M+&P'D$ZN_^(I0`IJ?@0@!R`'"
M`$"``8%L"EP@!R`'`$"``H%L"F(`;(`#"FA*;`<,9P1P`&`$,#R``"X`0FP'U
M)"`'(`<`0``!.4`'(CE\``$'/"`'(`<`0``".4`'.CE\``('5"`'(`<`0`"`X
M.4`'4D'Z#Q(I2``P+RP)GC\L"9Q.NLZ27$]"9TZZYBI43TS?#(!.74YU``!.+
M<3\M__8O*@`,/RH`%$ZZ^^QP84Y5_]!(YR`@<``;?``@__MR`#M!__@[?/__0
M__9![?_8&T#_]1M`__P;0/_]&T#__AM`__\[0?_L.T'_[BM(_]0@;0`(2A!G3
M5!`0`D``_W(874%K2+![$`AF]D[[$`0`(V```"P`(&```!X`*V```!``+6``!
M``(;?``!__]@&!M\``'__F`0&WP``?_]8`@;?``!__Q.<5*M``A@I"!M``@25
M$`P!`#!F"AM\`##_^U*M``@@;0`(#!``*F82(FT`#"!15)$[4/_X4JT`"&`6(
M2&W_^"\(3KKTSE!/(&T`"-#`*T@`""!M``@2$`P!`"YF-E*M``@@;0`(#!``R
M*F82(FT`#"!15)$[4/_V4JT`"&`62&W_]B\(3KKTC%!/(&T`"-#`*T@`""!M%
M``@2$`P!`&QF#!M\``'_]5*M``A@"@P!`&AF!%*M``@@;0`($!!2K0`(&T#_.
M]`)``/]R,%U!:P`"?+![$`AF]$[[$`0`8V```E(`<V```@H`6&```98`>&``U
M`9``<&```7@`;V```20`=6```/@`9&````)*+?_U9PPB;0`,(%%8D2`08`PBR
M;0`,(%%4D3`02,`K0/_P2H!J"G(!1*W_\#M!_^Y*;?_N9P1P+6`,2BW__F<$B
M<"M@`G`@&T#_V!`M__X"0`#_,BW_[H)`$"W__0)``/^"0$I!9PA2K?_44FW_.
M["\M__`O+?_43KKU+%!/.T#_TDIM__9J!G`!.T#_]C`M_](R+?_VDD`[0?_06
M2D%O-"!M_]0B2-+!(@`D2&`"$MI1R?_\$"W_^P)``/\R+?_0(&W_U&`"$,!1%
MR?_\,"W_]CM`_]+1;?_L0>W_V"M(_]1*+?__9P`!8AM\`"#_^V```5A*+?_UJ
M9PPB;0`,(%%8D2`08`PB;0`,(%%4D7``,!`K0/_P8`#_6DHM__5G#")M``P@1
M45B1(!!@#")M``P@4521<``P$"M`__!*+?_\9Q(@;?_4$+P`,%*M_]0[?``!B
M_^PO`"\M_]1.NO/,4$\[0/_28`#_'AM\`##_^TIM__9J!CM\``C_]DHM__5G;
M#")M``P@45B1(!!@#")M``P@4521<``P$"M`__!*+?_\9QX@;?_4$+P`,%*MJ
M_]0@;?_4$+P`>%*M_]0[?``"_^PO`"\M_]1.NO+@4$\[0/_2#"T`6/_T9@#^X
MK$AM_]A.NO3P6$]@`/Z>(FT`#"!16)$B4"M)_]2R_```9@A![`=T*TC_U"!M,
M_]1*&&;\4XB1[?_4.TC_[$IM__9K+C(M__:PP6\F.T'_[&`@.WP``?_L(FT`I
M#"!15)$P$!M`_]A"+?_98`9P`&```+`R+?_L-"W_^+1!;`AP`#M`__A@!)-M2
M__A*+?__9T93;?_L,"W_[$I`:QH@;?_4$!`"0`#_4JW_U#\`(&T`$$Z05$]@K
MVE-M__@P+?_X2D!K6A`M__L"0`#_/P`@;0`03I!43V#@4VW_^#`M__A*0&L4=
M$"W_^P)``/\_`"!M`!!.D%1/8.!3;?_L,"W_[$I`:QH@;?_4$!`"0`#_4JW_6
MU#\`(&T`$$Z05$]@VB`M``A,WP0$3EU.=4Y5__8K;0`0__8@;0`,$!!2K0`,:
M&T#__TH`9WH,```E9C`@;0`,#!``)68&4JT`#&`@+RT`"$AM__8O"&$`^RI/V
M[P`,*T#_^DJ`9P8K0``,8+A*;``T9R@(+0`'__]G(!`M__\"0`#_/P`@;0`(O
M3I!43R!M``P0$%*M``P;0/__$"W__P)``/\_`"!M``A.D%1/8`#_=DY=3G4`R
M`!587$]2;'!A3E7_ZDCG(`!P`"!M``@2$`)!`/]![`7MT,$2$#M`__H[0/_XC
M"`$``F<X,"W_^,'\``H@;0`($A`"00#_4JT`"`)!``_003M`__@@;0`($!`"1
M0`#_0>P%[=#`$!`(```"9L@@;0`($A`,`0!L9@Q2K0`(.WP``?_Z8`H,`0!H_
M9@12K0`((&T`#$Z0.T#__B!M``@,$`!C9QQ![`7MT.W__A`0"````V<,(&T`[
M#$Z0.T#__F#D,BW__@Q!__]F#"!M`!`P@7``8``$:B!M``@0$`)``/]R-EU!'
M:P`$1+![$`AF]$[[$`0`<V```^P`8V```X8`:&```PP`6&```90`>&```8X`&
M<&```7P`;V```.X`9&````X`=6````)";?_V8$)P`#M`__9*;?_X9P@,;0`!P
M__AO+C0M__X,0@`M9P8,0@`K9AX,0@`M9@1R_V`"(@`[0?_V(&T`#$Z04VW_8
M^#M`__Y![`7M,"W__M#`$A`(`0`"9@P@;0`0,(!P`&```[)"K?_R("W_\G(*$
M3KH$<C(M__X"00`/2,'0@2M`__(@;0`,3I`[0/_^4VW_^#`M__A*0&<00>P%/
M[=#M__X0$`@```)FP$JM`!1G``-62FW_]FH$1*W_\DIM__IF$")M`!0@42`M%
M__(P@&```S8B;0`4(%$@K?_R8``#*#(M__X,00`P;08,00`W;PP@;0`0,(%P@
M`&```QQ"K?_R("W_\N>`,BW__@)!``=(P="!*T#_\B!M``Q.D#M`__Y3;?_X&
M,"W_^$I`9Q`R+?_^#$$`,&T&#$$`-V_$2JT`%&<``L1*;?_Z9A`B;0`4(%$@J
M+?_R,(!@``*N(FT`%"!1(*W_\F```J!*;?_X9@8[?``(__A![`7M,"W__M#`+
M$A`(`0`'9@P@;0`0,(!P`&```H8[;?_^__P@;0`,3I`[0/_^2FW_^&<(#&T`N
M`O_X;T0,;0`P__QF/`Q``'AG!@Q``%AF,"!M``Q.D$'L!>TB2-+`$A$[0/_^*
M"`$`!V8,(FT`$#*`<`!@``(N0JW_\E-M__A@3$'L!>TP+?_\(DC2P!(1"`$`U
M`F<,(@`$00`P2,$K0?_R(DC2P!(1"`$``&<,(@`$00`W2,$K0?_RT,`2$`@!,
M``%G"@1``%=(P"M`__)3;?_X,"W_^$I`9VY![`7M,"W__B)(TL`2$0@!``=GJ
M6B(M__+I@2)(TL`4$2M!__((`@`"9PPB``1!`#!(P8.M__(B2-+`$A$(`0``J
M9PPB``1!`#=(P8.M__+0P!(0"`$``6<*!$``5TC`@:W_\B!M``Q.D#M`__Y@Y
MADJM`!1G``%&2FW_^F80(FT`%"!1("W_\C"`8``!,")M`!0@42"M__)@``$B-
M0>P%[3`M__[0P!(0"`$``F8,(&T`$#"`<`!@``$40FW_]C`M__;!_``*,BW_U
M_@)!``_003M`__8@;0`,3I`[0/_^4VW_^#`M__A*0&<00>P%[=#M__X0$`@`-
M``)FQ$JM`!1G``"\(FT`%"!1,*W_]F```*Y*K0`49PXB;0`4(%%2D3`M__X0O
M@%-M__@P+?_X2D!O(B!M``Q.D#M`__X,0/__9Q)*K0`49]XB;0`4(%%2D1"`O
M8-(R+?_^#$'__V8*(&T`$#"!<`!@9B!M``A2B"`(8%Q*K0`49PXB;0`4(%%2&
MD3`M__X0@"!M``Q.D#M`__Y20&<<4VW_^#`M__A*0&<00>P%[=#M__X0$`@`,
M``-GPB)M`!0@44(08`1P`&`0(&T`$#"M__X@;0`(4H@@"$S?``1.74YU``!*+
M@&H``!Y$@$J!:@``#$2!80``($2!3G5A```81(!$@4YU2H%J```,1(%A```&-
M1(!.=2\"2$$T`68``")(0$A!2$(T`&<```:$P3`"2$`T`(3!,`)(0C(")!].S
M=2\#=A`,00"`9```!N&944,,00@`9```!NF964,,02``9```!N6954-*06L`R
M``;CF5-#-`#FJ$A"0D+FJDA#@,$V`#`"-`-(0<3!D()D```(4T/0@63^<@`R<
M`TA#Y[A(0,-`)A\D'TYU($(B0R0`)@%(0DA#Q,'&P,#!U$-(0D)"T((F"20((
M3G4@;P`((F\`!#`O``QO&+/(91#0P-+`4T`3(%'(__Q@!A+84<C_]"`O``1.*
M=4Y5__I(YP$@?@!%[`I<OFP'C&P>2E)G%`@J``(``6<"8`HO*@`"3KH"&%A/`
M4D=<BF#<,"T`"$C`+RT`"B\`3KK!]E!/3-\$@$Y=3G5.5?_\<``B/```,``L`
M>``$3J[^S@*````P`"M`__Q*@&8$<`!@)$JL`#!G&B!L`#!.D$I`9@1P`&`09
M0F=P%#\`3KK_<EA/("W__$Y=3G5AL$YU``!.5?_X2.<!`$JL`#!G!$ZZ_YQ"6
M;``8,"T`$$C`+T``!"(M``@D+0`,)B\`!"QL!Y!.KO_6+@`,A_____]F$BQL&
M!Y!.KO]\.4``&#E\``4&\"`'3-\`@$Y=3G4``$Y5__A(YP$`2JP`,&<$3KK_Q
M0$)L`!@P+0`02,`O0``$(BT`""0M``PF+P`$+&P'D$ZN_]`N``R'_____V82J
M+&P'D$ZN_WPY0``8.7P`!0;P(`=,WP"`3EU.=0``3E7_^$CG,0)*K``P9P1."
MNO[D0FP`&'``,"T`$%.`+T``$"(M``@D+0`,)B\`$"QL!Y!.KO^^+@`,A___1
M__]F$BQL!Y!.KO]\.4``&#E\`!8&\#`M`!`,0``"9QH,0``!9PI*0&8B("T`'
M#&`<(`<@!]"M``Q@$B(M``AT`'8`+&P'D$ZN_[Y.<4S?0(Q.74YU3E7_^$CGG
M`0!*K``P9P1.NOY40FP`&#`M``Q(P"]```0B+0`()"\`!"QL!Y!.KO_B+@!*(
MAV86+&P'D$ZN_WPY0``8.7P``@;P</]@`B`'3-\`@$Y=3G4``$Y5``!*K``P!
M9P1.NOX`(BT`""QL!Y!.KO_<<`!.74YU3E7__$JL`#!G!$ZZ_>!";``8(BT`5
M"'3^+&P'D$ZN_ZPK0/_\2JW__&<8(BW__"QL!Y!.KO^F(BT`""QL!Y!.KO^XZ
M(BT`""0\```#[BQL!Y!.KO_B*T#__$JM__QF%BQL!Y!.KO]\.4``&#E\``(&\
M\'#_8`0@+?_\3EU.=4Y5__Q*K``P9P1.NOUD0FP`&"(M``AT_BQL!Y!.KO^LV
M*T#__$JM__QG$"(M__PL;`>03J[_IG#_8#8B+0`()#P```/N+&P'D$ZN_^(K-
M0/_\2JW__&86+&P'D$ZN_WPY0``8.7P``@;P</]@!"`M__Q.74YU3E7_L$CG7
M``)*K`>49A)#[`@@<``L>``$3J[]V"E`!Y1P`"!L`%00*/__+P`O"$AM_[!.M
MNOQ03^\`#"!L`%00*/__`D``_T(U`+!![?^P*4@'X$AX`#Q(>`#Z<``O`"\`'
M2&P(#$AL!_)(;`?4+P!.NM743^\`(%.`9P1P_V`"<`!,WT``3EU.=4S?0(Q.?
M74YUYJA(0@```^P````#`````0``&)(```$2````#@````````/R```#Z@``8
M`@T`````````````````````````````````````````````````````````/
M`````````````````````````````````````````````````````````````
M`````&1O<RYL:6)R87)Y`'AB=&]A-2`E9"`E<R!"96=I;@H`+0!X8G1O82!"9
M96=I;@H``'AB=&]A($5N9"!.("5L9"`E;'@@12`E;'@@4R`E;'@@4B`E;'@*]
M```@("`@("`@("`@("`@($)T;V$@=F5R<VEO;B`E<PH``#4N,@!7<FET=&5NP
M(&)Y(%!A=6P@4G5T=&5R+"!*;V4@3W)O<W0@)B!3=&5F86X@4&%R;6%R:RX*A
M```*57-A9V4Z(&)T;V$@6RU[861H;W)]72!;:6YP=70@9FEL95T@6V]U='!U*
M="!F:6QE70H`"D]P=&EO;G,Z"@``+6@@(%-H;W=S('1H:7,@:&5L<"!L:7-T[
M+@H``"UA("!5<V4@871O8B!R871H97(@=&AA;B!B=&]A+@H`+6\@(%5S92!O`
M;&0@=F5R<VEO;B!O9B!B=&]A+@H`+60@($5X=')A8W0@<F5P86ER(&9I;&4@8
M9G)O;2!D:6%G;F]S:7,@9FEL92X*`"UR("!297!A:7(@87)C:&EV92!F<F]ME
M(')E<&%I<B!F:6QE+@H`"D5X86UP;&5S.@H`("!B=&]A("UH"@``("!B=&]AS
M(%MI;G!U="!B:6YA<GD@9FEL95T@6V]U='!U="!A<F-H:79E(&9I;&5="@`@B
M(&)T;V$@+6\@6VEN<'5T(&)I;F%R>2!F:6QE72!;;W5T<'5T(&%R8VAI=F4@]
M9FEL95T*```@(&)T;V$@+6$@6VEN<'5T(&%R8VAI=F4@9FEL95T@6V]U='!U=
M="!B:6YA<GD@9FEL95T*```@(&)T;V$@+60@6W5N9&%M86=E9"!A<F-H:79EZ
M(&9I;&5="@`@(&)T;V$@+7(@6V1A;6%G960@87)C:&EV92!F:6QE70H`````S
M`&%R8VAI=F4`>&)T;V$`>&)T;V$@0F5G:6X*``!B=&]A.B!/;&0@8G1O82!F8
M;W)M870N"@!X8G1O834@)60@)7,@0F5G:6X*`"T`8G1O83H@26QL96=A;"!A&
M<F-H:79E(&AE861E<BX*``!X8G1O82!%;F0@3B`E;&0@)6QX($4@)6QX(%,@D
M)6QX(%(@)6QX"@``8G1O83H@0F%D(&9O<FUA="!O;B!L:6YE("5L9"X@0V%N8
M)W0@<F5P86ER(&9I;&4N"@!B=&]A.B!"860@9FEL92!C:&5C:W-U;2X@0V%N0
M)W0@<F5P86ER(&9I;&4N"@``87)C:&EV90!B=&]A.B!"860@;&EN92!L96YGM
M=&@@;VX@;&EN92`E;&0N"@!B=&]A.B!"860@8VAA<F%C=&5R(&]N(&QI;F4@G
M)6QD+@H`8G1O83H@0F%D(&-H96-K<W5M(&]N(&QI;F4@)6QD+@H``&)T;V$Z9
M(%-T87)T:6YG(&1I86=N;W-I<RX*``!A<F-H:79E`&)T;V$Z($)A9"!C:&%RL
M86-T97(@;VX@;&EN92`E;&0N"@``````8G1O82YD:6$`````!*AB=&]A+G)EZ
M<``````$MF)T;V$N<F1Y``````3$>&1I86=N;W-I<PH````$TGAR97!A:7(*S
M``````3B8G1O83H@1&EA9VYO<VES(&]U='!U="!T;R`G)7,G+@H``&%R8VAI@
M=F4`8G1O83H@56YE>'!E8W1E9"!E;F0@;V8@)7,@9FEL92X*`'(`8G1O83H@>
M0V%N)W0@;W!E;B`G)7,G(&9O<B!I;G!U="X*`'<`8G1O83H@0V%N)W0@;W!E\
M;B`G)7,G(&9O<B!O=71P=70N"@``9&EA9VYO<VES````!89B=&]A.B!297!AX
M:7(@;W5T<'5T('1O("<E<R<N"@!R97!A:7(`````!;)B=&]A.B!297!A:7)EO
M9"!A<F-H:79E('=R:71T96X@=&\@)R5S)RX*```"`````"`@("`@("`@("@H&
M*"@H("`@("`@("`@("`@("`@("`@2!`0$!`0$!`0$!`0$!`0$(2$A(2$A(2$0
MA(00$!`0$!`0@8&!@8&!`0$!`0$!`0$!`0$!`0$!`0$!`0$0$!`0$!""@H*"Z
M@H("`@("`@("`@("`@("`@("`@("`A`0$!`@("`@("`@("`@*"@H*"@@("`@T
M("`@("`@("`@("`@("!($!`0$!`0$!`0$!`0$!`0A(2$A(2$A(2$A!`0$!`0P
M$!"!@8&!@8$!`0$!`0$!`0$!`0$!`0$!`0$!`1`0$!`0$(*"@H*"@@("`@("P
M`@("`@("`@("`@("`@("$!`0$"``````````,#$R,S0U-C<X.6%B8V1E9@``@
M```-"@``@```````!R@`````````````````````````````!T``````````-
M`````````````````````````````````````````````````(````!C;VXZZ
M,3`O,3`O,S(P+S@P+P`J````````````````````````````````````````E
M*`````````````````````````0````J*B!5<V5R($%B;W)T(%)E<75E<W1E%
M9"`J*@``__\````.``X````````'I`````#__P````0`!``````````````'J
MP$-/3E1)3E5%``#__P````0`!`````````?H`````$%"3U)4`/__````!``$8
M````````"`8`````:6YT=6ET:6]N+FQI8G)A<GD```````/L````#0````$`1
M``@8```'_@``!^0```?,```'*```!Q````6Z```%D```!.P```3>```$S@``A
.!,````2R`````````_+,[
``
end
size 19364
SHAR_EOF
cat << \SHAR_EOF > chksum.h
/* chksum.h */
/* calcchecksum() was converted to a macro for effectivity reasons. */
/* Don't (!!) give it an argument that has to be evaluated. This    */
/* is guaranteed to slow it down.                                   */

/* Update file checksums. */

#define calcchecksum(ch)        \
{                               \
  extern LONG Ceor, Csum, Crot; \
                                \
  Ceor ^= ch;                   \
  Csum += ch + 1;               \
                                \
  if (Crot & 0x80000000L)       \
  {                             \
    Crot <<= 1;                 \
    Crot ++;                    \
  }                             \
  else                          \
    Crot <<= 1;                 \
                                \
  Crot += ch;                   \
}
SHAR_EOF
cat << \SHAR_EOF > repair.c
/* repair.c */

/* Written by Stefan Parmark. */

#include <stdio.h>
#ifdef AMIGA
#include <stdlib.h>
#include <string.h>
#endif AMIGA

#include "btoa.h"

/* File names. */
BYTE *diagnosisname   = "btoa.dia";
BYTE *repairname      = "btoa.rep";
BYTE *repairedname    = "btoa.rdy";

/* File headers. */
BYTE *diagnosisheader = "xdiagnosis\n";
BYTE *repairheader    = "xrepair\n";


/* Produce diagnosis file from diagnoses records created by atob(). */
/* It contains the lines immediately before and after the error     */
/* sequence.                                                        */
void producediagnosis(diagnosislist, infile)
register struct Diagnosis *diagnosislist;
register FILE *infile;
{
  register FILE *diagnosisfile;
  LONG startpos, endpos;
  register LONG currentpos;
  extern BYTE *diagnosisname, *diagnosisheader, buffer[BUFSIZE];

  currentpos = ftell(infile);

  if ((diagnosisfile = fopen_write(diagnosisname)) != NULL)
  {
    fprintf(stderr, "btoa: Diagnosis output to '%s'.\n", diagnosisname);

    fputs(diagnosisheader, diagnosisfile);
    do
    {
      /* Extract startpos & endpos from diagnosislist. */
      outdiagnosislist(diagnosislist, &startpos, &endpos);

      if (startpos != -1)
      {
        /* Print line before error. */
        fseek(infile, startpos, 0);
        fgets(buffer, BUFSIZE, infile);
        fputs(buffer, diagnosisfile);

        /* Print line after error. */
        fseek(infile, endpos, 0);
        fgets(buffer, BUFSIZE, infile);
        fputs(buffer, diagnosisfile);
      }
    }
    while (startpos != -1);
    fputs(diagnosisheader, diagnosisfile);

    fclose(diagnosisfile);
  }

  /* Move file pointer to where it was when we entered. */
  fseek(infile, currentpos, 0);
}


/* Insert two file positions into diagnosislist. */
void intodiagnosislist(diagnosislist, startpos, endpos)
register struct Diagnosis *diagnosislist;
register LONG startpos, endpos;
{
  register struct Diagnosis *diagnosisitem, *lastitem;

  diagnosisitem = (struct Diagnosis *)malloc(sizeof(struct Diagnosis));
  diagnosisitem->startpos = startpos;
  diagnosisitem->endpos = endpos;
  diagnosisitem->next = NULL;

  if ((lastitem = diagnosislist->last) == NULL)  /* List is empty */
    diagnosislist->next = diagnosislist->last = diagnosisitem;
  else
  {
    if (lastitem->endpos >= startpos)
    {
      lastitem->endpos = endpos;
      free((BYTE *) diagnosisitem);
    }
    else
    {
      lastitem->next = diagnosisitem;
      diagnosislist->last = diagnosisitem;
    }
  }
}


/* Extract two file positions from diagnosislist. */
void outdiagnosislist(diagnosislist, startpos, endpos)
register struct Diagnosis *diagnosislist;
LONG *startpos, *endpos;
{
  register struct Diagnosis *diagnosisitem;

  if ((diagnosisitem = diagnosislist->next) == NULL)  /* List is empty */
    *startpos = *endpos = -1;
  else
  {
    *startpos = diagnosisitem->startpos;
    *endpos = diagnosisitem->endpos;

    diagnosislist->next = diagnosisitem->next;
    free((BYTE *)diagnosisitem);
    if (diagnosislist->next == NULL)
      diagnosislist->last = NULL;
  }
}


/* Copy infile to outfile until searchstring is found. If outfile */
/* is NULL nothing will be written.                               */
BYTE copyfile(infile, outfile, searchstring)
register FILE *infile, *outfile;
register BYTE *searchstring;
{
  register BYTE stop, error;
  static BYTE copybuffer[BUFSIZE];

  stop = error = FALSE;
  while (!(stop || error))
    if (readbuffer(copybuffer, "archive", infile))
      error = TRUE;
    else
    {
      if (outfile != NULL)
        fputs(copybuffer, outfile);
      if (strcmp(copybuffer, searchstring) == 0)
        stop = TRUE;
    }

  return(error);
}


/* Read a line from infile into buffer. Returns TRUE if */
/* end-of-file has been reached.                        */
BYTE readbuffer(buffer, errormsg, infile)
register BYTE *buffer, *errormsg;
register FILE *infile;
{
  register BYTE error;

  error = FALSE;
  if (fgets(buffer, BUFSIZE, infile) == NULL)
  {
    fprintf(stderr, "btoa: Unexpected end of %s file.\n", errormsg);
    error = TRUE;
  }

  return(error);
}


FILE *fopen_read(filename)
register BYTE *filename;
{
  register FILE *infile;

  if ((infile = fopen(filename, "r")) == NULL)
    fprintf(stderr, "btoa: Can't open '%s' for input.\n", filename);

  return(infile);
}


FILE *fopen_write(filename)
register BYTE *filename;
{
  register FILE *outfile;

  if ((outfile = fopen(filename, "w")) == NULL)
    fprintf(stderr, "btoa: Can't open '%s' for output.\n", filename);

  return(outfile);
}


/* Extract lines from original archive to fix the damaged one. */
BYTE producerepair(infile)
register FILE *infile;
{
  register FILE *repairfile, *diagnosisfile;
  register BYTE error, stop;
  static BYTE *errormsg = "diagnosis";
  extern BYTE *diagnosisname, *diagnosisheader, *repairname, *repairheader,
              buffer[BUFSIZE];

  error = FALSE;
  diagnosisfile = repairfile = NULL;

  fprintf(stderr, "btoa: Repair output to '%s'.\n", repairname);
  if ((diagnosisfile = fopen_read(diagnosisname)) == NULL)
    error = TRUE;
  else if ((repairfile = fopen_write(repairname)) == NULL)
  {
    fclose(diagnosisfile);
    diagnosisfile = NULL;
    error = TRUE;
  }
  else
  {
    /* Read until header is found. This makes it possible to   */
    /* have junk before the header, such as an article header. */
    do
    {
      if (readbuffer(buffer, errormsg, diagnosisfile))
        error = TRUE;
    }
    while (!error && strcmp(buffer, diagnosisheader) != 0);
    fputs(repairheader, repairfile);
  }

  stop = FALSE;
  while (!(error || stop))
  {
    /* Loop until header is found again. */

    if (readbuffer(buffer, errormsg, diagnosisfile))
      error = TRUE;
    else if (strcmp(buffer, diagnosisheader) == 0)
      stop = TRUE;
    else
    {
      /* Read until line before error is found. */
      error = copyfile(infile, NULL, buffer);
      if (!error)
      {
        /* Print line before error. */
        fputs(buffer, repairfile);

        if (readbuffer(buffer, errormsg, diagnosisfile))
          error = TRUE;
        else
        {
          /* Print line after error */
          fputs(buffer, repairfile);
          /* Copy infile to repairfile until line after error */
          error = copyfile(infile, repairfile, buffer);
        }
      }
    }
  }

  if (!error)
    fputs(repairheader, repairfile);

  if (repairfile != NULL)
    fclose(repairfile);
  if (diagnosisfile != NULL)
    fclose(diagnosisfile);

  return(error);
}


/* Repair damaged archive from repair file. */
BYTE performrepair(infile)
register FILE *infile;
{
  register FILE *repairfile, *outfile;
  register BYTE error, stop;
  static BYTE *errormsg = "repair";
  extern BYTE *repairname, *repairedname, *repairheader, buffer[BUFSIZE];

  error = FALSE;
  repairfile = outfile = NULL;

  if ((repairfile = fopen_read(repairname)) == NULL)
    error = TRUE;
  else if ((outfile = fopen_write(repairedname)) == NULL)
  {
    fclose(repairfile);
    repairfile = NULL;
    error = TRUE;
  }
  else
  {
    fprintf(stderr, "btoa: Repaired archive written to '%s'.\n", repairedname);

    /* Read until header is found. */
    do
    {
      if (readbuffer(buffer, errormsg, repairfile))
        error = TRUE;
    }
    while (!error && strcmp(buffer, repairheader) != 0);
  }

  stop = FALSE;
  while (!(error || stop))
  {
    /* Loop until header is found. */

    if (readbuffer(buffer, errormsg, repairfile))
      error = TRUE;
    else if (strcmp(buffer, repairheader) == 0)
      stop = TRUE;
    else
    {
      /* Read and write until line before error. */
      error = copyfile(infile, outfile, buffer);
      if (!error)
        if (readbuffer(buffer, errormsg, repairfile))
          error = TRUE;
        else
        {
          /* Read and write until line after error. */
          error = copyfile(repairfile, outfile, buffer);
          /* Skip until line after error */
          copyfile(infile, NULL, buffer);
        }
    }
  }

  if (!error)  /* Write rest of archive. */
    while (fgets(buffer, BUFSIZE, infile) != NULL)
      fputs(buffer, outfile);

  if (outfile != NULL)
    fclose(outfile);
  if (repairfile != NULL)
    fclose(repairfile);

  return(error);
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.