1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-04-25 03:35:58 +00:00
Files
rcornwell.sims/SEL32/taptools/deblk.c

623 lines
23 KiB
C

/*
* deblk.c
*
* This program reads MPX blocked and/or MPX compressed files and
* deblocks blocked files and uncompresses compressed files and
* deletes trailing blanks from a source file. The program will
* also process standard ASCII newline ('\n') terminated files.
* input - stdin / filename
* output - stdout
*/
/*
* MPX blocked file format
* bytes 0-1 - not used and are zero
* bytes 2-3 - next record position in buffer
* byte 4 - start/end of block flag
* - 0x20 - EOB end of block
* - 0x40 - BOB start of block
* byte 5 - last record byte count
* byte 6 - this blocks flags
* - 0x00 - valid data
* - 0x20 - EOB end of block
* - 0x80 - EOF end of file
* - 0xa0 - EOB/EOF end of file
* byte 7 - bytes in this record
* data byte - cnt data bytes
* byte cnt+4- 0x20 EOB status
* byte cnt+5- last record count
*/
/*
* Compressed record
* byte 0 - 0xbf -> start of record
* 0x9f -> start of next record
* byte 1 - record count
* byte 2 - high order byte of 16 bit checksum
* byte 3 - low order byte of 16 bit checksum
*
*/
/*
*
* AN O.S. COMPRESSED RECORD CONSISTS OF 120 BYTES:
*
* 6 CONTROL BYTES AND 114 BYTES OF COMPRESSED SOURCE
*
* (THE LAST RECORD CAN BE LESS THAN 120 BYTES, ON THAT
* RECORD THE COMPRESSED SOURCE WILL BE FROM 4-114 BYTES).
*
* 6 CONTROL BYTES
*
* 1 BYTE- DATA TYPE CODE BF OR 9F (9F MEANS THIS IS LAST RECORD)
* 1 BYTE- SIZE OF COMPRESSED RECORD (- 6 FOR CONTROL BYTES)
* (USUALLY 114 (72(X)) IS THE SIZE EXCEPT LAST RECORD)
* 2 BYTE- CHECKSUM
* 2 BYTE- RECORD SEQUENCE NUMBER (STARTING FROM ZERO)
*
* 4-114 BYTES OF ONE OR MORE GROUPS OF COMPRESSED SOURCE AS FOLLOWS:
*
* A COMPRESSED GROUP CONSISTS OF:
* A BLANK COUNT BYTE, A DATA COUNT BYTE, DATA
*
* COMPRESSED GROUPS ARE REPEATED AND TERMINATED BY AN FF CHAR.
* COMPRESSED GROUPS ARE USUALLY TERMINATED AT 114 CHARS BY
* THE FF CHAR UNLESS THIS IS THE LAST RECORD IN THE FILE
*
* A LINE OF TEXT USUALLY IS COMPRESSED AS FOLLOWS:
* A BLANK COUNT BYTE, A DATA COUNT BYTE, COMPRESSED DATA
* (ONE OR MORE OF THESE COMPRESSED GROUPS FOR UP TO 72 CHARS OF SOURCE)
* FOLLOWED BY A BLANK COUNT BYTE,A DATA COUNT BYTE (OF 8),
* DATA (8 CHAR SEQUENCE NUMBER), TERMINATED BY A FF CHAR
*
* A WORKFILE LOGICAL COMPRESSED LINE IS SIMILIAR TO THE O.S.
* LOGICAL COMPRESSED LINE EXCEPT THAT AN 8 CHAR SEQUENCE NUMBER
* ALWAYS EXISTS IN THE WORKFILE FORMAT AND IT IS ALWAYS FIRST
* RATHER THAN AT THE END OF THE RECORD (IF SEQUENCE NUMBERS DID
* NOT EXIST IN COLUMNS 73-80 IN THE O.S. ORIGINAL COMPRESSED
* RECORDS THAN THE EDITOR GENERATES THEM). PRECEDING THE WORKFILE
* COMPRESSED RECORD IS A 2 BYTE PREVIOUS RECORD IN THE PAGE POINTER.
* ALSO NOTE THAT WORKFILES ARE NOT BLOCKED BY THE O.S., BUT HAVE
* THEIR OWN STRUCTURE OF HEADERS, DATA SPACE, AND FREE SPACE.
*
* IF THE SEQUENCE NUMBER DOES NOT EXIST OR THE PERIOD IS NOT IN
* THE PROPER PLACE (NNNN.NNN) OR THE SEQUENCE NUMBER CONTAINS
* ANYTHING OTHER THAN NUMBERS, THEN THE EDITOR WILL GENERATE
* ITS OWN SEQUENCE NUMBER
*
* THE FIRST BLANK COUNT CAN RANGE FROM 0-80 BLANK CHARS
* SUBSEQUENT BLANK COUNTS CAN RANGE FROM 3-79 MAX. THAT IS
* SINCE IT TAKES 2 BYTES TO DO BLANK COMPRESSION (A BLANK COUNT
* AND A DATA COUNT), ONLY 3 OR MORE BLANK CHARS AFTER THE FIRST
* NON-BLANK CHAR IN A LINE ARE COMPRESSED.
* RECORDS TO BE COMPRESSED ARE ASSUMED TO BE 80 CHARS OR LESS
* (INCLUDING AN 8 CHAR SEQUENCE NUMBER).
*
* THE CHECKSUM IS SIMPLY THE ADDITION OF ALL THE 120 CHARS IN THE
* COMPRESSED RECORD EXCEPT FOR THE 6 CONTROL BYTES
*
* THE SMALLEST COMPRESSED LINE CONSISTS OF 14 CHARS :
* A BLANK COUNT BYTE (OF 71), A DATA COUNT BYTE (OF 8),
* DATA (AN 8 CHAR SEQUENCE NUMBER, A BLANK COUNT BYTE (OF ZERO),
* A DATA COUNT BYTE (OF 1), DATA (ONE CHAR), AND AN FF TERMINATOR
* COMPRESSED RECORD FORMAT CAN BE PROCESSED ONLY BY THE FOLLOWING:
*
* ASSEMBLER,P4,SOURCE UPDATE,EDITOR AND SOME FUNCTIONS OF MEDIA
* AND OF COURSE SOME UTILITY PROGRAMS LIKE FLIP.
*
* NOTE THAT A TEXT LINE CAN BE SPREAD ACROSS SEVERAL COMPRESSED
* RECORDS.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BLKSIZE 768 /* MPX block file sector size */
extern int rbl();
extern int getloi(); /* right from my mind */
extern int putloi(); /* write line */
/* read file and output to stdout */
int main(argc, argv)
int argc;
char *argv[];
{
FILE *fp, *fopen();
unsigned char s[BUFSIZ];
if(argc == 1) /* no args; copy std in */
{
while (1) {
if (rbl(stdin, s, BUFSIZ) <= 0) /* read til EOF */
exit(0);
putloi(s);
}
} else {
while (--argc > 0)
if ((fp = fopen(*++argv, "r")) == NULL) {
fprintf(stderr, "list: can't open %s\n", *argv);
exit(1);
} else {
while (1) {
if (rbl(fp, s, BUFSIZ) <= 0) /* read til EOF */
exit(0);
putloi(s);
}
fclose(fp);
}
}
exit(0);
}
/*
* This function computes and checks the checksum of a compressed file
*/
int checksum(buf)
char *buf;
{
int i = 0;
// unsigned int ccs = 0; /*zero checksum */
short int ccs = 0; /*zero checksum */
unsigned int rcs = (((buf[2] << 8) & 0xff00) | (buf[3] & 0xff)); /* get checksum */
int cnt = buf[1]; /* record count */
// fprintf(stderr, "checksum data %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]);
while (cnt > 0) {
// unsigned int v = buf[i+6];
short v = buf[i+6] & 0xff;
ccs += v; /* add the byte */
// fprintf(stderr, "checksum cnt %x val %x sum %x\n", i, v, ccs);
i++; /* bump address */
cnt--; /* reduce count */
}
// fprintf(stderr, "checksum size %x read %x calc %x\n", buf[1], rcs, ccs);
if (ccs == rcs)
return 0; /* return OK */
return 1; /* return error */
}
int bin = 0;
unsigned char si[BLKSIZE];
unsigned char bi[BLKSIZE];
int ubdp = 0; /* unblocked data pointer */
int ubdc = 0; /* unblocked data count */
int bdp = 0; /* blocked data pointer */
int bdc = 0; /* blocked data count */
short filetype = 0;
#define unknown 0x00
#define blocked 0x01
#define compress 0x02
#define ascii 0x04
/*
* This function reads MPX blocked files
*/
int readbb(fp, ip, cnt)
FILE *fp;
char *ip;
int cnt;
{
int c;
int i = 0;
if (bin == 0) {
//fprintf(stderr, "read sector a\n");
if (fread(si, 1, BLKSIZE, fp) <= 0)
return (0); /* this means eof */
bin = 6;
}
/* check for EOF */
if (si[bin] & 0x80) {
bin = 0;
return(0); /* we have EOF */
}
/* check for EOB in last record */
if (si[bin - 2] & 0x20) {
//fprintf(stderr, "read sector b\n");
if (fread(si, 1, BLKSIZE, fp) <= 0)
return (0); /* this means eof */
bin = 6;
}
//fprintf(stderr, "copy block from sector @ bin %x\n", bin);
/* copy the block into users buffer */
if ((c = si[bin+1]) > 0) {
for (i = 0; i < c; i++) {
ip[i] = si[bin + 2 + i];
if (i >= cnt)
break;
}
bin += (c + 4);
ip[i] = '\0';
return (i);
}
bin = 0;
return (i);
}
/* function to read a byte from an unblocked file */
int getb(fp)
FILE *fp;
{
int c;
/* file is unblocked, get next record */
if (ubdp >= ubdc) { /* is count exhausted */
/* need to read next block, if not first time */
/* we need a new buffer */
/* read in 768 byte block of the file */
if ((ubdc = fread(si, 1, BLKSIZE, fp)) <= 0)
return (-1); /* this means eof */
//fprintf(stderr, "getb - read unblocked file ubdc=%x\n", ubdc);
ubdp = 0;
}
c = si[ubdp++] & 0xff; /* copy char */
return (c);
}
/* get a line of input */
int getloi(fp, s, lim) /* right from my mind */
FILE *fp;
unsigned char s[];
int lim;
{
int c, i, cc, rc = 0;
/* see how we are to process data */
if (filetype & blocked) {
/* file is blocked, get next record */
if (bdp == 0) {
/* we need a new buffer */
newbuf:
if ((bdc = readbb(fp, bi, lim)) <= 0)
return (0); /* this means eof */
//fprintf(stderr, "getloi read blocked file %x\n", bdc);
bdp = 0;
}
/* check for compressed data */
if (filetype & compress) {
if ((bi[bdp] & 0x9f) != 0x9f) {
fprintf(stderr, "blocked compressed file read error %x\n", bi[bdp]);
return (0); /* this means error */
}
/* checksum the record */
if (checksum(&bi[bdp])) {
fprintf(stderr, "blocked compressed file checksum error\n");
return (0); /* this means error */
}
//fprintf(stderr, "getloi blocked compressed file checksum OK @ %x cnt %x\n", bdp, bdc);
/* copy in the next record */
/* get chars until EOF or limit reached */
cc = bi[bdp+1]+6; /* get count */
for (i = 0; (--lim > 0) && (i < cc); i++) {
s[rc++] = bi[bdp++]; /* copy char */
}
if ((bdp >= bdc) || (i == cc)) {
bdp = 0; /* read new buffer next time */
//fprintf(stderr, "getloi blocked compressed read return %x bdc %x bdp %x\n", rc, bdc, bdp);
}
return (rc); /* return data count */
}
/* file is uncompressed, so copy MPX records */
//fprintf(stderr, "getloi blocked data rc=%x bdc=%x\n", rc, bdc);
for (i=0; i<bdc; i++)
s[rc++] = bi[bdp++]; /* copy chars */
s[rc++] = 0; /* null terminate */
bdp = 0; /* read next buffer */
return (i); /* return data */
}
else {
/* check for compressed data */
if (filetype & compress) {
cc = 120;
rc = 0;
while ((c = getb(fp)) != -1) {
/* skip any optional newline from previous record */
// if ((rc == 0) && (c == '\n'))
// continue;
/* make sure this is a compressed record */
if ((rc == 0) && ((c & 0x9f) != 0x9f)) {
fprintf(stderr, "getloi - unblocked compressed file read error %x\n", c);
return (0); /* this means error */
}
if (rc == 1)
cc = c + 6; /* get 'real' record count */
s[rc++] = c; /* save the char */
if (rc == cc)
// if (rc == 120) /* compressed is always 120 char buffers */
break; /* done */
}
if (c == -1)
return (0); /* this means EOF */
/* skip any extra chars from short records */
while ((c = getb(fp)) != '\n')
;
/* checksum the record */
if (checksum(s)) {
fprintf(stderr, "getloi - unblocked compressed file checksum error\n");
//fprintf(stderr, "getloi A unblocked compressed read return rc=%x cc=%x %x %x\n", rc, cc, s[0], s[rc-1]);
//fprintf(stderr, "getloi C unblocked compressed read return %x ubdc %x ubdp %x\n", rc, ubdc, ubdp);
return (0); /* this means error */
}
//fprintf(stderr, "getloi B unblocked compressed read return rc=%x cc=%x %x\n", rc, cc, s[1]);
return (rc); /* return data count */
}
/* file is uncompressed, so copy UNIX records */
while ((c = getb(fp)) != -1) {
s[rc++] = c; /* save the char */
if (c == 0x0a) {
//fprintf(stderr, "getloi C unblocked compressed read return %x ubdc %x ubdp %x\n", rc, ubdc, ubdp);
s[rc++] = 0; /* terminate the line */
return (rc); /* return data */
}
}
return (0); /* EOF */
}
return (0);
#ifdef JUNK
/* get chars until EOF or limit reached */
for (i = 0; (--lim > 0) && ((c = getchar()) != EOF)) {
if ((i >= 6) && ((c == 0xbf) || (c == 0x9f)))
{
ungetc(c, stdin);
return (i);
}
s[i++] = c;
if ((*s != 0xbf) && (*s != 0x9f))
{
if (c == '\n')
{
if ((s[i - 1] == '\n') && (i > 1))
{
while ((s[i - 2] == ' ') && (i > 1))
--i;
s[i - 1] = '\n';
}
s[i] = '\0';
return (i);
}
}
}
#ifdef JUNK
for (i = 0; --lim > 0 && (c = getchar()) != EOF && (s[i++] = c) != '\n';);
if ((s[i - 1] == '\n') && (i > 1))
{
while ((s[i - 2] == ' ') && (i > 1))
--i;
s[i - 1] = '\n';
}
s[i] = '\0';
#endif
return (i);
#endif
}
/*
** output line of text from the source
*/
int putloi(s)
unsigned char *s;
{
printf("%s", s);
}
unsigned char line[BUFSIZ];
int cmpop = 0;
int cmpflg = 0;
int bcnt = 0;
unsigned char *bptr = 0;
int binary = 1;
int recl = 0;
int ubin = 0;
/* read lines of data from the source file */
/* files can be blocked w/wo compression */
/* files can be blocked ascii */
/* files can be byte strings, newline terminated */
int rbl(fp, buf, n)
FILE *fp;
unsigned char *buf;
int n;
{
register int count = 0;
register unsigned char *cp;
int i;
unsigned char *linadrs = line;
if (filetype == unknown) /* see if we know type of file to read */
{
bin = 0;
ubin = 0;
bdp = 0;
bdc = 0;
ubdp = 0;
ubdc = 0;
/* read in 1st 768 Byte block of the file */
if ((ubdc = fread(si, 1, BLKSIZE, fp)) <= 0)
return (0); /* this means eof */
/* test 1st byte for 0x06 and bytes 2, 3, and 4 zero */
if ((si[0] == 0x06) && (si[1] == 0) && (si[2] == 0) && (si[3] == 0)) {
/* we have a library file, giver error and abort */
fprintf(stderr, "deblk - Cannot list library file, aborting\n");
return (0); /* this means error exit */
}
/* test for a directory file, 8 ascii char then 4 zeros */
if ((si[8] == 0) && (si[9] == 0) && (si[10] == 0) && (si[11] == 0)) {
for (i=0; i<8; i++) {
if (!isprint(si[i])) {
/* unknown file type, abort */
fprintf(stderr, "deblk - Unknown binary file type, aborting\n");
return (0); /* this means error exit */
}
}
/* must be directory, abort */
fprintf(stderr, "deblk - Cannot list directory file, aborting\n");
return (0); /* this means error exit */
}
i = ((si[2] << 8) & 0xff00) | (si[3] & 0xff); /* get file offset pointer, bytes 2 & 3 */
/* test 1st 2 byte of file for zero */
if ((si[0] == 0) && (si[1] == 0) && (i < BLKSIZE)) {
/* most likely blocked file if 1st 2 bytes 0 and next 2 bytes are less than 768 */
filetype |= blocked; /* we have blocked file */
bin = 6; /* where we start for data block */
/* see if we have compressed data */
if ((si[bin + 2] == 0xbf) || (si[bin + 2] == 0x9f))
{
filetype |= compress; /* data is compressed */
bcnt = 0; /* no data in buffer */
}
else
{
/* data is not compressed, just ascii without newlines */
filetype |= ascii; /* blocked ascii data */
}
}
else
/* test for a diag blocked ascii file */
/* test 1st 2 byte of file for zero */
if ((si[0] == 0) && (si[1] == 3) && (i == 0xf3b8)) {
filetype |= blocked; /* we have blocked file */
bin = 6; /* where we start for data block */
/* see if we have compressed data */
if ((si[bin + 2] == 0xbf) || (si[bin + 2] == 0x9f))
{
filetype |= compress; /* data is compressed */
bcnt = 0; /* no data in buffer */
}
else
{
/* data is not compressed, just ascii without newlines */
filetype |= ascii; /* blocked ascii data */
}
}
else
{
/* data is unblocked, see if compressed or not */
if ((si[ubin] == 0xbf) || (si[ubin] == 0x9f))
{
filetype |= compress; /* data is compressed */
bcnt = 0; /* no data in buffer */
}
else
if ((si[ubin] == 0xef) || (si[ubin] == 0xcf))
{
/* file is an macro library, so abort */
fprintf(stderr, "deblk - Cannot list macro library file, aborting\n");
return (0); /* this means error exit */
}
else
{
/* data is not compressed or blocked, just ascii with newlines */
filetype |= ascii; /* blocked ascii data */
}
}
}
if ((filetype & compress) && !cmpop) { /* see if we tested for compressed */
cmpop = 1; /* set comp tested flag */
/* read in the first record */
if ((recl = getloi(fp, line, BUFSIZ)) == 0)
return (0); /* this means eof */
linadrs = line;
if (*linadrs == 0xbf)
{ /* is this file compressed */
cmpflg = 1; /* set comp data flag */
bcnt = linadrs[1]; /* set record count */
bptr = &linadrs[6]; /* set data address */
//fprintf(stderr, "rbl - read 1st compressed record cnt %x %x\n", bcnt, linadrs[0]);
}
else
goto re00;
}
if (cmpflg) { /* reading compressed data? */
if (bcnt == 0) { /* any data left in buffer */
re18:
/* read in a data record */
if ((recl = getloi(fp, line, BUFSIZ)) == 0)
return (0); /* this means eof */
linadrs = line;
//fprintf(stderr, "rbl re18 - read compressed record cnt %x %x\n", bcnt, linadrs[0]);
if ((*linadrs & 0x9f) != 0x9f) /* is this valid rec */
return (EOF); /* error if not */
bcnt = linadrs[1]; /* set record count */
bptr = &linadrs[6]; /* set data address */
//fprintf(stderr, "rbl - read nth compressed record cnt %x %x\n", bcnt, linadrs[0]);
}
re20:
/* see if any blanks */
if (i = *bptr++) { /* next buffer pointer */
if (i == 0xff)
goto re60; /* if eol, get out */
while (i--) {
if (count < n) {
*buf++ = ' '; /* put blank in buffer */
count++;
}
}
}
if (--bcnt <= 0)
goto re18; /* read next record */
/* get character count */
if (i = *bptr++) { /* next buffer pointer */
while (i--) {
if (count < n)
*buf++ = *bptr; /* put char in buffer */
bcnt--; /* decr count */
bptr++; /* next buffer pointer */
count++;
}
}
if (--bcnt <= 0)
goto re18; /* read next record */
goto re20;
re60:
bcnt--; /* decr count */
if ((*--buf == ' ') && (count == 1)) {
*buf = '\n'; /* put new line at eol */
}
else {
*++buf = '\n'; /* put new line at eol */
count++;
}
}
else {
/* non compressed read here */
/* read the next record */
if ((recl = getloi(fp, line, BUFSIZ)) == 0)
return (0); /* this means eof */
linadrs = line; /* reset line pointer */
re00:
//fprintf(stderr, "rbl - read nth uncompressed record cnt %x %s\n", recl, line);
#if 0
/* here we need to strip off blank put in during write */
/* this is because mpx does not support zero length blocks */
if ((recl == 1) && (*linadrs == ' ')) {
recl = 0;
/* now append new line to end of buffer */
if (!binary)
line[recl] = '\n';
}
#endif
count = 0;
/* copy this layer buffer to upper caller's buffer */
while ((count < n) && (count < recl)) {
buf[count] = line[count];
count++;
}
/* if no newline, add one and null terminate */
if (line[count-1] != '\n')
buf[count++] = '\n';
buf[count] = '\0';
}
//fprintf(stderr, "rbl - read return cnt %x %s\n", count, line);
return (count);
}