home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckimkb.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  10KB  |  347 lines

  1. /* MSBMKB.C
  2.  *
  3.  * Update history:
  4.  *
  5.  * 1/1/88 - Frank da Cruz.  Add exit(0); to end of main() to give good
  6.  * return code upon success.
  7.  *
  8.  * Modified 3/11/86 Howie Kaye -- Columbia University
  9.  * added UNIX and Microsoft C compatibility
  10.  * changed I/O to be buffered
  11.  * note: there is a bug built into the EOF handling which causes the 
  12.  * output file to grow everytime a file is packed/unpacked.  This is 
  13.  * because 2 nulls and a space are added at the end of each run.  As 
  14.  * the data is past the end of the file, it does not affect the program
  15.  * produced.
  16.  *
  17.  * [1]     Version adapted from the DEC-20 code to run on Lattice-C (v 2.14)
  18.  * on an IBM PC/AT under DOS 3.0.      Alan Phillips, Lancaster University UK
  19.  *
  20.  * Original by Bill Catchings, Columbia University, July 1984
  21.  */
  22.  
  23. /*
  24.  * This program takes a file and encodes it into printable characters.
  25.  * These printable files can then be decoded by the programs MSPCBOOT.BAS
  26.  * or MSPCTRAN.BAS as the need may be.    The file is encoded by taking
  27.  * three consecutive eight bit bytes and dividing them into four six bit
  28.  * bytes.  An ASCII zero was then added to the resulting four characters.
  29.  * to make them all printable ASCII characters in the range of the
  30.  * character zero to the character underscore.    In order to reduce the
  31.  * size of the file null repeat count was used.  The null repeat count
  32.  * compresses up to 78 consecutive nulls into only two characters.  This
  33.  * is done by using the character tilde (~) as an indication that a group
  34.  * of repetitive nulls has occured.  The character following the tilde is
  35.  * number of nulls in the group.  The number is also converted in to a
  36.  * printable character by adding an ASCII zero.  The highest number of
  37.  * nulls is therefore the highest printable character tilde.  This is
  38.  * equal to tilde minus zero nulls or 78 nulls.  Because of the three
  39.  * byte to four byte encoding the repeat counting can only start with
  40.  * the first character of a three byte triplet.
  41.  *
  42.  * This C program was written specifically for the DEC-20 and as such
  43.  * will not easily be transported to another system.  The main problem
  44.  * lies in the file I/O routines.  It is necessary to make sure that
  45.  * untranslated eight bit bytes are input from the input file.    The
  46.  * main change would be to make the OPEN statement reflect this for
  47.  * your particular system and brand of UNIX and C.  The rest of the
  48.  * program should be transportable with little or no problems.
  49.  */
  50.  
  51. /*
  52.  * set msdos if to be compiled on an msdos machine 
  53.  */     
  54.  
  55. #define MSDOS     0
  56. #define UNIX    0
  57. #define TOPS20  0
  58. #define AMIGA    1
  59.  
  60. #include <stdio.h>        /* Standard UNIX i/o definitions */
  61.  
  62. #if    MSDOS         /* [1] */
  63. #include <fcntl.h>
  64. #endif
  65. #if UNIX
  66. #include <sys/file.h>
  67. #endif                /* [1] */
  68. #if TOPS20
  69. #include <file.h>
  70. #endif
  71. #if AMIGA
  72. #include <fcntl.h>
  73. #endif
  74.  
  75. /* Symbol Definitions */
  76.  
  77. #define MAXPACK     80    /* Maximum packet size */
  78.  
  79. #define MYRPTQ        '~'     /* Repeat count prefix I will use */
  80. #define DATALEN     78    /* Length of data buffer */
  81.  
  82. #define TRUE        -1    /* Boolean constants */
  83. #define FALSE        0
  84.  
  85. /* Macros */
  86.  
  87. #define tochar(ch)  ((ch) + '0')
  88.  
  89. /* Global Variables */
  90.  
  91. int    maxsize,        /* Max size for data field */
  92.     fd,            /* File pointer of file to read/write */
  93.     ofd,
  94. #if    !(MSDOS | UNIX | AMIGA)    /* [1] */
  95.     nc,            /* Count of input characters */
  96.     oc,            /* Count of output characters */
  97.     otot,            /* What char number we are processing */
  98. #endif
  99.     rpt,            /* repeat count */
  100.     rptq,            /* repeat quote */
  101.     rptflg,         /* repeat processing flag */
  102.     size,            /* size of present data */
  103. #if    (MSDOS|UNIX|AMIGA)    /* [1] */
  104.     t,            /* Current character value as 16 bit */
  105. #endif                /* [1] */
  106.     eoflag;         /* Set when file is empty. */
  107.  
  108. #if    (MSDOS|UNIX|AMIGA)    /* [1] */
  109. long    nc,            /* Count of input characters */
  110.     oc,            /* Number of output chars */
  111.     otot;            /* What char number we are processing */
  112. #endif                /* [1] */
  113.  
  114. char    one,
  115.     two,
  116.     three,
  117. #if    !(MSDOS|UNIX|AMIGA)    /* [1] */
  118.     t,            /* Current character */
  119. #endif                /* [1] */
  120.     *filnam,        /* Current file name */
  121.     *ofile,
  122.     packet[MAXPACK];    /* Packet buffer */
  123.  
  124. main(argc,argv)             /* Main program */
  125. int argc;                /* Command line argument count */
  126. char **argv;                /* Pointers to args */
  127. {
  128.     char sfile();            /* Send file routine & ret code */
  129.     if (--argc != 2) usage();        /* Make sure there's a command line. */
  130.     rptq = MYRPTQ;            /* Repeat Quote */
  131.     rptflg = TRUE;            /* Repeat Count Processing Flag */
  132.  
  133.     filnam = *++argv;            /* Get file to send */
  134.     ofile = *++argv;            /* Output file to create */
  135.     sfile();
  136. #if    (MSDOS|UNIX|AMIGA)        /* [1] */
  137.     printf("Done, in: %ld, out: %ld, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  138. #else
  139.     printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  140. #endif                    /* [1] */
  141.     exit(0);
  142. }
  143.  
  144. /*
  145.    S F I L E - Send a whole file
  146. */
  147.  
  148. char sfile()                /* Send a file */
  149. {
  150.     char *i;
  151.  
  152. #if    MSDOS             /* [1] */
  153. #ifndef O_RAW
  154. #define O_RAW O_BINARY
  155. #endif /* O_RAW */
  156. #endif /* MSDOS */
  157. #if UNIX | AMIGA
  158. #define O_RAW 0
  159. #endif /* UNIX */
  160. #if (MSDOS | UNIX | AMIGA)
  161.     fd = open(filnam,O_RDONLY | O_RAW,0x1ff);
  162. #else
  163.     fd = open(filnam,FATT_RDONLY | FATT_BINARY | FATT_DEFSIZE,0x1ff);
  164. #endif                    /* [1] */
  165.     if (fd < 0)             /* Report any errors */
  166.     {
  167.     printf("\n?Error opening file \"%s\"\n",filnam);
  168.     exit(1);
  169.     }
  170.  
  171. #if (MSDOS | UNIX | AMIGA)
  172.     ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0x1ff);
  173. #else
  174.     ofd = open(ofile,FATT_WRONLY | FATT_CREATE | FATT_BINARY,0x1ff);
  175. #endif                    /* [1] */
  176.  
  177.     if (ofd < 0)
  178.     {
  179.     printf("\n?error opening file \"%s\"\n",ofile);
  180.     exit(1);
  181.     }
  182.  
  183.     oc = strlen(filnam);        /* Get the string length. */
  184.     for (i=filnam; *i != '\0'; i++)     /* Uppercase the file name. */
  185.     if (*i >= 'a' && *i <= 'z') *i ^= 040;
  186.     write(ofd,filnam,oc);        /* Write the file name in the file. */
  187. #if (!UNIX & !AMIGA)
  188.     write(ofd,"\r\n",2);
  189. #else
  190.     write(ofd,"\n",1);
  191. #endif
  192.     maxsize = DATALEN - 5;
  193.     rpt = 0;                /* Zero the repeat count. */
  194.     oc = nc = 0;            /* Output & input character counts. */
  195.     otot = 1;                /* Start with first char of triplet. */
  196.     while (getbuf() > 0)        /* While not EOF, get a packet. */
  197.     {
  198. #if (!UNIX & !AMIGA)
  199.     packet[size++] = '\r';          /* Explicit CRLF. */
  200. #endif
  201.     packet[size++] = '\n';
  202.     packet[size] = '\0';
  203.     oc += size;            /* Count output size. */
  204.     write(ofd,packet,size);     /* Write the packet to the file. */
  205.      /* printf("%d: %s",size,packet);*/ /* Print on the screen for testing. */
  206.     }
  207. #if    MSDOS             /* [1] */
  208.     close(fd);                /* close the files neatly */
  209.     close(ofd);
  210. #endif                    /* [1] */
  211. }
  212. /*
  213.    G E T B U F -- Do one packet.
  214. */
  215.  
  216. getbuf()               /* Fill one packet buffer. */
  217. {
  218.     if (eoflag != 0) return(-1);    /* If at the end of file, stop. */
  219.     size = 0;
  220.     while((t = getch()) >= 0)        /* t == -1 means EOF. */
  221.     {
  222.     nc++;                /* Count the character. */
  223.     process(t);            /* Process the character. */
  224.     if (size >= maxsize)        /* If the packet is full, */
  225.     {
  226.         packet[size] = '\0';        /*  terminate the string. */
  227.         return(size);
  228.     }
  229.     }
  230.     eoflag = -1;            /* Say we hit the end of the file. */
  231.     process(0);             /* Clean out any remaining chars. */
  232.     process(0);
  233.     process(' ');
  234.     packet[size] = '\0';                /* Return any partial final buffer. */
  235.     return(size);
  236. }
  237.  
  238. /* P R O C E S S -- Do one character. */
  239.  
  240. process(a)
  241. char a;
  242. {
  243.     if (otot == 1)            /* Is this the first of three chars? */
  244.     {
  245.     if (a == 0)            /* Is it a null? */
  246.     {
  247.         if (++rpt < 78)        /* Below max nulls, just count. */
  248.         return;
  249.         else if (rpt == 78)     /* Reached max number, must output. */
  250.         {
  251.         packet[size++] = rptq;    /* Put in null repeat char and */
  252.         packet[size++] = tochar(rpt); /* number of nulls. */
  253.         packet[size] = '\0';
  254.         rpt = 0;
  255.         return;
  256.         }
  257.     }
  258.     else
  259.     {
  260.         if (rpt == 1)        /* Just one null? */
  261.         {
  262.         one = 0;        /* Say the first char was a null. */
  263.         two = a;        /* This char is the second one. */
  264.         otot = 3;        /* Look for the third char. */
  265.         rpt = 0;        /* Restart null count. */
  266.         return;
  267.         }
  268.         if (rpt > 1)        /* Some number of nulls? */
  269.         {
  270.         packet[size++] = rptq;    /* Insert the repeat prefix */
  271.         packet[size++] = tochar(rpt); /* and count. */
  272.         packet[size] = '\0';
  273.         rpt = 0;        /* Reset repeat counter. */
  274.         }
  275.         one = a;            /* Set first character. */
  276.         otot = 2;            /* Say we are at the second char. */
  277.     }
  278.     }
  279.     else if (otot == 2)
  280.     {
  281.     two = a;            /* Set second character. */
  282.     otot = 3;            /* Say we are at the third char. */
  283.     }
  284.     else
  285.     {
  286.     three = a;
  287.     otot = 1;            /* Start over at one. */
  288.     pack(one,two,three);        /* Pack in the three characters. */
  289.     }
  290. }
  291.  
  292. /* This routine does the actual three character to four character encoding.
  293.  * The concept is relatively straight forward.    The first output character
  294.  * consists of the first (high order or most significant) six bits of the
  295.  * first input character.  The second output character is made from the
  296.  * remaining two low order bits of the first input character and the first
  297.  * four high order bits of the second input character.    The third output
  298.  * character is built from the last four low order bits of the second input
  299.  * character and the two high order bits of the third input character.    The
  300.  * fourth and last output character consists of the six low order bit of
  301.  * the third input character.  In this way the three eight bit input char-
  302.  * acters (for a total of 24 bits) are divided into four six bit output
  303.  * characters (also for a total of 24 bits).  In order to make the four
  304.  * output characters printable an ASCII zero is then added to each of them.
  305.  *
  306.  */
  307.  
  308. pack(x,y,z)
  309. char x,y,z;
  310. {
  311.     packet[size++] = tochar((x >> 2) & 077);
  312.     packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
  313.     packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
  314.     packet[size++] = tochar(z & 077);
  315.     packet[size] = '\0';
  316. }
  317.  
  318. int
  319. getch()                 /* Get next (or pushed) char. */
  320. {
  321. #if TOPS20
  322.                     /* really really inefficient. */
  323.    return((read(fd,&a,1) > 0) ? (int) (a&0xff) : -1); /* (or -1 if EOF) */
  324. #else
  325. #ifndef BSIZE
  326. #define BSIZE 500
  327. #endif
  328.    static int index = 0, count = 0;
  329.    static char buf[BSIZE];
  330.  
  331.    if (count == 0) {
  332.      count = read(fd,buf,BSIZE);
  333.      if (count <= 0) return(-1);
  334.      index = 0;
  335.    }
  336.    count--;
  337.    return(buf[index++]&0xff);
  338.  
  339. #endif
  340. }
  341.  
  342. usage()                 /* Give message if user makes */
  343. {                    /* a mistake in the command. */
  344.     fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
  345.     exit(1);
  346. }
  347.