home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
ckc190.zip
/
ckimkb.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-09
|
11KB
|
347 lines
/* MSBMKB.C
*
* Update history:
*
* 1/1/88 - Frank da Cruz. Add exit(0); to end of main() to give good
* return code upon success.
*
* Modified 3/11/86 Howie Kaye -- Columbia University
* added UNIX and Microsoft C compatibility
* changed I/O to be buffered
* note: there is a bug built into the EOF handling which causes the
* output file to grow everytime a file is packed/unpacked. This is
* because 2 nulls and a space are added at the end of each run. As
* the data is past the end of the file, it does not affect the program
* produced.
*
* [1] Version adapted from the DEC-20 code to run on Lattice-C (v 2.14)
* on an IBM PC/AT under DOS 3.0. Alan Phillips, Lancaster University UK
*
* Original by Bill Catchings, Columbia University, July 1984
*/
/*
* This program takes a file and encodes it into printable characters.
* These printable files can then be decoded by the programs MSPCBOOT.BAS
* or MSPCTRAN.BAS as the need may be. The file is encoded by taking
* three consecutive eight bit bytes and dividing them into four six bit
* bytes. An ASCII zero was then added to the resulting four characters.
* to make them all printable ASCII characters in the range of the
* character zero to the character underscore. In order to reduce the
* size of the file null repeat count was used. The null repeat count
* compresses up to 78 consecutive nulls into only two characters. This
* is done by using the character tilde (~) as an indication that a group
* of repetitive nulls has occured. The character following the tilde is
* number of nulls in the group. The number is also converted in to a
* printable character by adding an ASCII zero. The highest number of
* nulls is therefore the highest printable character tilde. This is
* equal to tilde minus zero nulls or 78 nulls. Because of the three
* byte to four byte encoding the repeat counting can only start with
* the first character of a three byte triplet.
*
* This C program was written specifically for the DEC-20 and as such
* will not easily be transported to another system. The main problem
* lies in the file I/O routines. It is necessary to make sure that
* untranslated eight bit bytes are input from the input file. The
* main change would be to make the OPEN statement reflect this for
* your particular system and brand of UNIX and C. The rest of the
* program should be transportable with little or no problems.
*/
/*
* set msdos if to be compiled on an msdos machine
*/
#define MSDOS 0
#define UNIX 0
#define TOPS20 0
#define AMIGA 1
#include <stdio.h> /* Standard UNIX i/o definitions */
#if MSDOS /* [1] */
#include <fcntl.h>
#endif
#if UNIX
#include <sys/file.h>
#endif /* [1] */
#if TOPS20
#include <file.h>
#endif
#if AMIGA
#include <fcntl.h>
#endif
/* Symbol Definitions */
#define MAXPACK 80 /* Maximum packet size */
#define MYRPTQ '~' /* Repeat count prefix I will use */
#define DATALEN 78 /* Length of data buffer */
#define TRUE -1 /* Boolean constants */
#define FALSE 0
/* Macros */
#define tochar(ch) ((ch) + '0')
/* Global Variables */
int maxsize, /* Max size for data field */
fd, /* File pointer of file to read/write */
ofd,
#if !(MSDOS | UNIX | AMIGA) /* [1] */
nc, /* Count of input characters */
oc, /* Count of output characters */
otot, /* What char number we are processing */
#endif
rpt, /* repeat count */
rptq, /* repeat quote */
rptflg, /* repeat processing flag */
size, /* size of present data */
#if (MSDOS|UNIX|AMIGA) /* [1] */
t, /* Current character value as 16 bit */
#endif /* [1] */
eoflag; /* Set when file is empty. */
#if (MSDOS|UNIX|AMIGA) /* [1] */
long nc, /* Count of input characters */
oc, /* Number of output chars */
otot; /* What char number we are processing */
#endif /* [1] */
char one,
two,
three,
#if !(MSDOS|UNIX|AMIGA) /* [1] */
t, /* Current character */
#endif /* [1] */
*filnam, /* Current file name */
*ofile,
packet[MAXPACK]; /* Packet buffer */
main(argc,argv) /* Main program */
int argc; /* Command line argument count */
char **argv; /* Pointers to args */
{
char sfile(); /* Send file routine & ret code */
if (--argc != 2) usage(); /* Make sure there's a command line. */
rptq = MYRPTQ; /* Repeat Quote */
rptflg = TRUE; /* Repeat Count Processing Flag */
filnam = *++argv; /* Get file to send */
ofile = *++argv; /* Output file to create */
sfile();
#if (MSDOS|UNIX|AMIGA) /* [1] */
printf("Done, in: %ld, out: %ld, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
#else
printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
#endif /* [1] */
exit(0);
}
/*
S F I L E - Send a whole file
*/
char sfile() /* Send a file */
{
char *i;
#if MSDOS /* [1] */
#ifndef O_RAW
#define O_RAW O_BINARY
#endif /* O_RAW */
#endif /* MSDOS */
#if UNIX | AMIGA
#define O_RAW 0
#endif /* UNIX */
#if (MSDOS | UNIX | AMIGA)
fd = open(filnam,O_RDONLY | O_RAW,0x1ff);
#else
fd = open(filnam,FATT_RDONLY | FATT_BINARY | FATT_DEFSIZE,0x1ff);
#endif /* [1] */
if (fd < 0) /* Report any errors */
{
printf("\n?Error opening file \"%s\"\n",filnam);
exit(1);
}
#if (MSDOS | UNIX | AMIGA)
ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0x1ff);
#else
ofd = open(ofile,FATT_WRONLY | FATT_CREATE | FATT_BINARY,0x1ff);
#endif /* [1] */
if (ofd < 0)
{
printf("\n?error opening file \"%s\"\n",ofile);
exit(1);
}
oc = strlen(filnam); /* Get the string length. */
for (i=filnam; *i != '\0'; i++) /* Uppercase the file name. */
if (*i >= 'a' && *i <= 'z') *i ^= 040;
write(ofd,filnam,oc); /* Write the file name in the file. */
#if (!UNIX & !AMIGA)
write(ofd,"\r\n",2);
#else
write(ofd,"\n",1);
#endif
maxsize = DATALEN - 5;
rpt = 0; /* Zero the repeat count. */
oc = nc = 0; /* Output & input character counts. */
otot = 1; /* Start with first char of triplet. */
while (getbuf() > 0) /* While not EOF, get a packet. */
{
#if (!UNIX & !AMIGA)
packet[size++] = '\r'; /* Explicit CRLF. */
#endif
packet[size++] = '\n';
packet[size] = '\0';
oc += size; /* Count output size. */
write(ofd,packet,size); /* Write the packet to the file. */
/* printf("%d: %s",size,packet);*/ /* Print on the screen for testing. */
}
#if MSDOS /* [1] */
close(fd); /* close the files neatly */
close(ofd);
#endif /* [1] */
}
/*
G E T B U F -- Do one packet.
*/
getbuf() /* Fill one packet buffer. */
{
if (eoflag != 0) return(-1); /* If at the end of file, stop. */
size = 0;
while((t = getch()) >= 0) /* t == -1 means EOF. */
{
nc++; /* Count the character. */
process(t); /* Process the character. */
if (size >= maxsize) /* If the packet is full, */
{
packet[size] = '\0'; /* terminate the string. */
return(size);
}
}
eoflag = -1; /* Say we hit the end of the file. */
process(0); /* Clean out any remaining chars. */
process(0);
process(' ');
packet[size] = '\0'; /* Return any partial final buffer. */
return(size);
}
/* P R O C E S S -- Do one character. */
process(a)
char a;
{
if (otot == 1) /* Is this the first of three chars? */
{
if (a == 0) /* Is it a null? */
{
if (++rpt < 78) /* Below max nulls, just count. */
return;
else if (rpt == 78) /* Reached max number, must output. */
{
packet[size++] = rptq; /* Put in null repeat char and */
packet[size++] = tochar(rpt); /* number of nulls. */
packet[size] = '\0';
rpt = 0;
return;
}
}
else
{
if (rpt == 1) /* Just one null? */
{
one = 0; /* Say the first char was a null. */
two = a; /* This char is the second one. */
otot = 3; /* Look for the third char. */
rpt = 0; /* Restart null count. */
return;
}
if (rpt > 1) /* Some number of nulls? */
{
packet[size++] = rptq; /* Insert the repeat prefix */
packet[size++] = tochar(rpt); /* and count. */
packet[size] = '\0';
rpt = 0; /* Reset repeat counter. */
}
one = a; /* Set first character. */
otot = 2; /* Say we are at the second char. */
}
}
else if (otot == 2)
{
two = a; /* Set second character. */
otot = 3; /* Say we are at the third char. */
}
else
{
three = a;
otot = 1; /* Start over at one. */
pack(one,two,three); /* Pack in the three characters. */
}
}
/* This routine does the actual three character to four character encoding.
* The concept is relatively straight forward. The first output character
* consists of the first (high order or most significant) six bits of the
* first input character. The second output character is made from the
* remaining two low order bits of the first input character and the first
* four high order bits of the second input character. The third output
* character is built from the last four low order bits of the second input
* character and the two high order bits of the third input character. The
* fourth and last output character consists of the six low order bit of
* the third input character. In this way the three eight bit input char-
* acters (for a total of 24 bits) are divided into four six bit output
* characters (also for a total of 24 bits). In order to make the four
* output characters printable an ASCII zero is then added to each of them.
*
*/
pack(x,y,z)
char x,y,z;
{
packet[size++] = tochar((x >> 2) & 077);
packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
packet[size++] = tochar(z & 077);
packet[size] = '\0';
}
int
getch() /* Get next (or pushed) char. */
{
#if TOPS20
/* really really inefficient. */
return((read(fd,&a,1) > 0) ? (int) (a&0xff) : -1); /* (or -1 if EOF) */
#else
#ifndef BSIZE
#define BSIZE 500
#endif
static int index = 0, count = 0;
static char buf[BSIZE];
if (count == 0) {
count = read(fd,buf,BSIZE);
if (count <= 0) return(-1);
index = 0;
}
count--;
return(buf[index++]&0xff);
#endif
}
usage() /* Give message if user makes */
{ /* a mistake in the command. */
fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
exit(1);
}