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

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