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

  1. /* The boo and de-boo programs do not work, and I found them too cumbersome
  2.  * and complicated to install on the DG.  In their place, I have provided
  3.  * a few other tools:
  4.  *
  5.  *      uuencode ansd uudecode:  
  6.  *          Convert any binary file to a non-binary file, and preserve the
  7.  *          DG record and file types, if done on DG systems.
  8.  *      sq and usq:
  9.  *          CP/M (and others) squeeze and unsqueeze programs.  Should be
  10.  *          compatible with Unix and other hosts.
  11.  *      compress:
  12.  *          a more efficient compression than sq/usq.  Also compatible with
  13.  *          many hosts.
  14.  *
  15.  * If anyone can get these other files working, more power to you.  The
  16.  * uudecode program is slow, but the squeeze programs are very fast.  The
  17.  * uudecode could be faster, but I did not want to wasted alot of time on
  18.  * it.  Anyway, the uudecode source is very simple, and should be easy to
  19.  * convert to another language.  If you do convert the uudecode program,
  20.  * please let me know, so that it can be distributed to hosts that do not
  21.  * have the C compiler.
  22.  *
  23.  *   Phil Julian, SAS Institute, Inc., Box 8000, Cary, NC 27512-8000
  24.  *
  25.  */
  26.  
  27. /* MSBMKB.C
  28.  *
  29.  * Update history:
  30.  *
  31.  * Modified 3/11/86 Howie Kaye -- Columbia University
  32.  * added UNIX and Microsoft C compatibility
  33.  * changed I/O to be buffered
  34.  * note: there is a bug built into the EOF handling which causes the 
  35.  * output file to grow everytime a file is packed/unpacked.  This is 
  36.  * because 2 nulls and a space are added at the end of each run.  As 
  37.  * the data is past the end of the file, it does not affect the program
  38.  * produced.
  39.  *
  40.  * [1]     Version adapted from the DEC-20 code to run on Lattice-C (v 2.14)
  41.  * on an IBM PC/AT under DOS 3.0.      Alan Phillips, Lancaster University UK
  42.  *
  43.  * Original by Bill Catchings, Columbia University, July 1984
  44.  */
  45.  
  46. /*
  47.  * This program takes a file and encodes it into printable characters.
  48.  * These printable files can then be decoded by the programs MSPCBOOT.BAS
  49.  * or MSPCTRAN.BAS as the need may be.    The file is encoded by taking
  50.  * three consecutive eight bit bytes and dividing them into four six bit
  51.  * bytes.  An ASCII zero was then added to the resulting four characters.
  52.  * to make them all printable ASCII characters in the range of the
  53.  * character zero to the character underscore.    In order to reduce the
  54.  * size of the file null repeat count was used.  The null repeat count
  55.  * compresses up to 78 consecutive nulls into only two characters.  This
  56.  * is done by using the character tilde (~) as an indication that a group
  57.  * of repetitive nulls has occured.  The character following the tilde is
  58.  * number of nulls in the group.  The number is also converted in to a
  59.  * printable character by adding an ASCII zero.  The highest number of
  60.  * nulls is therefore the highest printable character tilde.  This is
  61.  * equal to tilde minus zero nulls or 78 nulls.  Because of the three
  62.  * byte to four byte encoding the repeat counting can only start with
  63.  * the first character of a three byte triplet.
  64.  *
  65.  * This C program was written specifically for the DEC-20 and as such
  66.  * will not easily be transported to another system.  The main problem
  67.  * lies in the file I/O routines.  It is necessary to make sure that
  68.  * untranslated eight bit bytes are input from the input file.    The
  69.  * main change would be to make the OPEN statement reflect this for
  70.  * your particular system and brand of UNIX and C.  The rest of the
  71.  * program should be transportable with little or no problems.
  72.  */
  73.  
  74. /*
  75.  * set msdos if to be compiled on an msdos machine 
  76.  */     
  77.  
  78. #define MSDOS     0
  79. #define UNIX    0
  80. #define TOPS20  0
  81.  
  82. #include <stdio.h>        /* Standard UNIX i/o definitions */
  83.  
  84. #if    MSDOS         /* [1] */
  85. #include <fcntl.h>
  86. #endif
  87. #if UNIX
  88. #include <sys/file.h>
  89. #endif                /* [1] */
  90. #if TOPS20
  91. #include <file.h>
  92. #endif
  93. /* Datageneral is already defined */
  94. #ifdef datageneral
  95. #include <sys_calls.h>
  96. #include <packets/filestatus.h>         /* Used for ?GNFN */
  97. #include <packets:normal_io.h>
  98. #include <paru.h>
  99. struct p_nio_ex w_io_parms;             /* ?write system call structure */
  100. struct p_nio_ex r_io_parms;             /* ?read system call structure */
  101. P_FSTAT buf; 
  102. int ac0,ac2;
  103. char name[256];
  104. #define R_ACC 4
  105. #ifdef putc
  106. #undef putc
  107. #endif
  108. #define putc(c,file) { char ch = (char) (c); dg_binw(fchannel(file),&ch,1); }
  109. #define write(filen,chs,len) dg_binw(channel(filen),chs,len)
  110. #define read(filen,chs,len)  dg_binr(channel(filen),chs,len)
  111. #endif
  112.  
  113. /* Symbol Definitions */
  114.  
  115. #define MAXPACK     80    /* Maximum packet size */
  116.  
  117. #define MYRPTQ        '~'     /* Repeat count prefix I will use */
  118. #define DATALEN     78    /* Length of data buffer */
  119.  
  120. #define TRUE        -1    /* Boolean constants */
  121. #define FALSE        0
  122.  
  123. /* Macros */
  124.  
  125. #define tochar(ch)  ((ch) + '0')
  126.  
  127. /* Global Variables */
  128.  
  129. int    maxsize,        /* Max size for data field */
  130.     fd,            /* File pointer of file to read/write */
  131.     ofd,
  132. #if    !(MSDOS | UNIX)         /* [1] */
  133.     nc,            /* Count of input characters */
  134.     oc,            /* Count of output characters */
  135.     otot,            /* What char number we are processing */
  136. #endif
  137.     rpt,            /* repeat count */
  138.     rptq,            /* repeat quote */
  139.     rptflg,         /* repeat processing flag */
  140.     size,            /* size of present data */
  141. #if    (MSDOS|UNIX|datageneral) /* [1] */
  142.     t,            /* Current character value as 16 bit */
  143. #endif                /* [1] */
  144.     eoflag;         /* Set when file is empty. */
  145.  
  146. #if    (MSDOS|UNIX)            /* [1] */
  147. long    nc,            /* Count of input characters */
  148.     oc,            /* Number of output chars */
  149.     otot;            /* What char number we are processing */
  150. #endif                /* [1] */
  151.  
  152. char    one,
  153.     two,
  154.     three,
  155. #if    !(MSDOS|UNIX|datageneral)   /* [1] */
  156.     t,            /* Current character */
  157. #endif                /* [1] */
  158.     *filnam,        /* Current file name */
  159.     *ofile,
  160.     packet[MAXPACK];    /* Packet buffer */
  161.  
  162. main(argc,argv)             /* Main program */
  163. int argc;                /* Command line argument count */
  164. char **argv;                /* Pointers to args */
  165. {
  166.     char sfile();            /* Send file routine & ret code */
  167. #ifdef datageneral
  168.     /* Initialize the i/o block for putc() */
  169.     zero((char *) &w_io_parms, sizeof(w_io_parms));
  170.     w_io_parms.isti = $IBIN|$RTDY|$ICRF|$OFOT;
  171.     w_io_parms.isti &= ~$IPST;
  172.     w_io_parms.imrs = 2048;
  173.     w_io_parms.ibad = -1;
  174.     w_io_parms.ircl = -1;
  175.     
  176.     zero((char *) &r_io_parms, sizeof(r_io_parms));
  177.     r_io_parms.isti = $IBIN|$RTDY|$ICRF|$OFIN;
  178.     r_io_parms.isti &= ~$IPST;
  179.     r_io_parms.imrs = 2048;
  180.     r_io_parms.ibad = -1;
  181.     r_io_parms.ircl = -1;
  182.    
  183. #endif
  184.     if (--argc != 2) usage();        /* Make sure there's a command line. */
  185.     rptq = MYRPTQ;            /* Repeat Quote */
  186.     rptflg = TRUE;            /* Repeat Count Processing Flag */
  187.  
  188.     filnam = *++argv;            /* Get file to send */
  189.     ofile = *++argv;            /* Output file to create */
  190.     sfile();
  191. #if    (MSDOS|UNIX)             /* [1] */
  192.     printf("Done, in: %ld, out: %ld, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  193. #else
  194.     printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  195. #endif                    /* [1] */
  196. }
  197.  
  198. /*
  199.    S F I L E - Send a whole file
  200. */
  201.  
  202. char sfile()                /* Send a file */
  203. {
  204.     char *i;
  205.  
  206. #if    MSDOS             /* [1] */
  207. #ifndef O_RAW
  208. #define O_RAW O_BINARY
  209. #endif O_RAW
  210. #endif MSDOS
  211. #if UNIX
  212. #define O_RAW 0
  213. #endif UNIX
  214. #ifdef datageneral
  215.     FILE *temp1,*temp2;
  216.     /* temp1 = fopen(filnam,"j"); */
  217.     temp1 = dg_open(filnam,$OFIN|$IBIN|$ICRF|$RTDY,$FUNX); 
  218.     if (temp1 == NULL) fd = -1;
  219.     else               fd = fileno(temp1);
  220. #else
  221. #if (MSDOS | UNIX)
  222.     fd = open(filnam,O_RDONLY | O_RAW,0x1ff);
  223. #else
  224.     fd = open(filnam,FATT_RDONLY | FATT_BINARY | FATT_DEFSIZE,0x1ff);
  225. #endif                    /* [1] */
  226. #endif                    /* [1] */
  227.     if (fd < 0)             /* Report any errors */
  228.     {
  229.     printf("\n?Error opening file \"%s\"\n",filnam);
  230.     exit(1);
  231.     }
  232.  
  233. #ifdef datageneral
  234.     temp2 = dg_open(ofile,$OFOT|$IBIN|$OFCR|$OFCE|$RTDY,$FUDF);
  235.     if (temp2 == NULL) ofd = -1;
  236.     else ofd = fileno(temp2);
  237. #else
  238. #if (MSDOS | UNIX)
  239.     ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0x1ff);
  240. #else
  241.     ofd = open(ofile,FATT_WRONLY | FATT_CREATE | FATT_BINARY,0x1ff);
  242. #endif                    /* [1] */
  243. #endif                    /* [1] */
  244.  
  245.     if (ofd < 0)
  246.     {
  247.     printf("\n?error opening file \"%s\"\n",ofile);
  248.     exit(1);
  249.     }
  250.  
  251.     oc = strlen(filnam);        /* Get the string length. */
  252.     for (i=filnam; *i != '\0'; i++)     /* Uppercase the file name. */
  253.     if (*i >= 'a' && *i <= 'z') *i ^= 040;
  254.     write(ofd,filnam,oc);        /* Write the file name in the file. */
  255. #if (!UNIX && !datageneral)
  256.     write(ofd,"\r\n",2);
  257. #else
  258.     write(ofd,"\n",1);
  259. #endif
  260.     maxsize = DATALEN - 5;
  261.     rpt = 0;                /* Zero the repeat count. */
  262.     oc = nc = 0;            /* Output & input character counts. */
  263.     otot = 1;                /* Start with first char of triplet. */
  264.     while (getbuf() > 0)        /* While not EOF, get a packet. */
  265.     {
  266. #if (!UNIX && !datageneral)
  267.     packet[size++] = '\r';          /* Explicit CRLF. */
  268. #endif
  269.     packet[size++] = '\n';
  270.     packet[size] = '\0';
  271.     oc += size;            /* Count output size. */
  272.     write(ofd,packet,size);     /* Write the packet to the file. */
  273.      /* printf("%d: %s",size,packet);*/ /* Print on the screen for testing. */
  274.     }
  275. #if    (MSDOS|datageneral)        /* [1] */
  276.     close(fd);                /* close the files neatly */
  277.     close(ofd);
  278. #endif                    /* [1] */
  279. }
  280. /*
  281.    G E T B U F -- Do one packet.
  282. */
  283.  
  284. getbuf()               /* Fill one packet buffer. */
  285. {
  286.     if (eoflag != 0) return(-1);    /* If at the end of file, stop. */
  287.     size = 0;
  288.     while((t = getch()) >= 0)        /* t == -1 means EOF. */
  289.     {
  290.     nc++;                /* Count the character. */
  291.     process(t);            /* Process the character. */
  292.     if (size >= maxsize)        /* If the packet is full, */
  293.     {
  294.         packet[size] = '\0';        /*  terminate the string. */
  295.         return(size);
  296.     }
  297.     }
  298.     eoflag = -1;            /* Say we hit the end of the file. */
  299.     process(0);             /* Clean out any remaining chars. */
  300.     process(0);
  301.     process(' ');
  302.     packet[size] = '\0';                /* Return any partial final buffer. */
  303.     return(size);
  304. }
  305.  
  306. /* P R O C E S S -- Do one character. */
  307.  
  308. process(a)
  309. char a;
  310. {
  311.     if (otot == 1)            /* Is this the first of three chars? */
  312.     {
  313.     if (a == 0)            /* Is it a null? */
  314.     {
  315.         if (++rpt < 78)        /* Below max nulls, just count. */
  316.         return;
  317.         else if (rpt == 78)     /* Reached max number, must output. */
  318.         {
  319.         packet[size++] = rptq;    /* Put in null repeat char and */
  320.         packet[size++] = tochar(rpt); /* number of nulls. */
  321.         packet[size] = '\0';
  322.         rpt = 0;
  323.         return;
  324.         }
  325.     }
  326.     else
  327.     {
  328.         if (rpt == 1)        /* Just one null? */
  329.         {
  330.         one = 0;        /* Say the first char was a null. */
  331.         two = a;        /* This char is the second one. */
  332.         otot = 3;        /* Look for the third char. */
  333.         rpt = 0;        /* Restart null count. */
  334.         return;
  335.         }
  336.         if (rpt > 1)        /* Some number of nulls? */
  337.         {
  338.         packet[size++] = rptq;    /* Insert the repeat prefix */
  339.         packet[size++] = tochar(rpt); /* and count. */
  340.         packet[size] = '\0';
  341.         rpt = 0;        /* Reset repeat counter. */
  342.         }
  343.         one = a;            /* Set first character. */
  344.         otot = 2;            /* Say we are at the second char. */
  345.     }
  346.     }
  347.     else if (otot == 2)
  348.     {
  349.     two = a;            /* Set second character. */
  350.     otot = 3;            /* Say we are at the third char. */
  351.     }
  352.     else
  353.     {
  354.     three = a;
  355.     otot = 1;            /* Start over at one. */
  356.     pack(one,two,three);        /* Pack in the three characters. */
  357.     }
  358. }
  359.  
  360. /* This routine does the actual three character to four character encoding.
  361.  * The concept is relatively straight forward.    The first output character
  362.  * consists of the first (high order or most significant) six bits of the
  363.  * first input character.  The second output character is made from the
  364.  * remaining two low order bits of the first input character and the first
  365.  * four high order bits of the second input character.    The third output
  366.  * character is built from the last four low order bits of the second input
  367.  * character and the two high order bits of the third input character.    The
  368.  * fourth and last output character consists of the six low order bit of
  369.  * the third input character.  In this way the three eight bit input char-
  370.  * acters (for a total of 24 bits) are divided into four six bit output
  371.  * characters (also for a total of 24 bits).  In order to make the four
  372.  * output characters printable an ASCII zero is then added to each of them.
  373.  *
  374.  */
  375.  
  376. pack(x,y,z)
  377. char x,y,z;
  378. {
  379.     packet[size++] = tochar((x >> 2) & 077);
  380.     packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
  381.     packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
  382.     packet[size++] = tochar(z & 077);
  383.     packet[size] = '\0';
  384. }
  385.  
  386. int
  387. getch()                 /* Get next (or pushed) char. */
  388. {
  389. #if TOPS20
  390.                     /* really really inefficient. */
  391.    return((read(fd,&a,1) > 0) ? (int) (a&0xff) : -1); /* (or -1 if EOF) */
  392. #else
  393. #ifndef BSIZE
  394. #define BSIZE 500
  395. #endif
  396.    static int index = 0, count = 0;
  397.    static char buf[BSIZE];
  398.  
  399.    if (count == 0) {
  400.      count = read(fd,buf,BSIZE);
  401.      if (count <= 0) return(-1);
  402.      index = 0;
  403.    }
  404.    count--;
  405.    return(buf[index++]&0xff);
  406.  
  407. #endif
  408. }
  409.  
  410. usage()                 /* Give message if user makes */
  411. {                    /* a mistake in the command. */
  412.     fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
  413.     exit(1);
  414. }
  415.  
  416. #ifdef datageneral
  417. /* D G _ B I N W -- Output len characters to the file number filenum 
  418.  * 
  419.  *  The syntax is like the Unix write command.
  420.  *  This code was borrowed from my Kermit source -- ckdtio.c
  421.  */
  422.  
  423. dg_binw(channel,chs,len) int channel, len; char *chs; 
  424. {
  425.      int ac2,err;
  426.  
  427.      if (len == 0) return(0);
  428.  
  429.      w_io_parms.ich = channel;
  430.      w_io_parms.ibad = chs;
  431.      w_io_parms.ircl = len;
  432.      ac2 = &w_io_parms;
  433.      
  434.      if ((err = sys_write(ac2)) == 0) return(0);
  435.  
  436.      if ( err != ERLTL && err != EREOF ) {
  437.           perror("dg_binw: sys_write ");
  438.           exit(err);
  439.      }
  440. }
  441.  
  442. /* D G _ B I N R -- Binary input routine
  443.  *
  444.  *  The syntax is like the Unix read command.
  445.  *  This code was borrowed from my Kermit source -- ckdtio.c
  446.  */
  447.  
  448. dg_binr(channel,chs,len) int channel, len; char *chs; 
  449. {
  450.      int ac2,                       /* I/O parameter address block */
  451.          err,                       /* Error from sys_read */
  452.          irlr;                      /* Number of bytes read */
  453.  
  454.      r_io_parms.ich  = channel; 
  455.      r_io_parms.ibad = chs;
  456.      r_io_parms.ircl = len;
  457.      ac2 = &r_io_parms;
  458.      err = sys_read(ac2);
  459.      irlr = r_io_parms.irlr;
  460.      if (err == 0) return(irlr);
  461.  
  462.      if ((err != ERLTL) && (err != EREOF)) {
  463.           /* NOT line-too-long, or EOF errors. */
  464.           perror("dg_binr: sys_read ");
  465.           return(-err);
  466.      } else if (err == EREOF) return(-1);            /* EOF */
  467. }
  468. #endif datageneral
  469.  
  470.  
  471.