New tape manipulation tools

rawtap	Allows extract, create and append operations on .tap files.

cpytap	Copies a .tap file to a new .tap file while allowing file level edits; skip file, replace file,
		append files and insert files. Any files copied from the original source .tap will have
		their internal record structure maintained.

cosy		COSY is the compressed format used by the CDC1700. This program allows for
		extraction of all files from an archive and the creation of a new archive. It assumes
		that you would have used raw tap about to have extracted the COSY file from a
		tape.

dbtap	Utility to read, write and list .tap containers written in the DOS/BATCH-11 format. It
		understands ascii and binary modes and can be used to transfer files in and out of
		most PDP-11 operating systems (not sure about RSTS/E), early VMS and early
		TOPS-10 systems.
This commit is contained in:
John Forecast
2017-03-14 13:44:02 -07:00
committed by Mark Pizzolato
parent 94d94fe695
commit b08ebe8eb0
29 changed files with 4978 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ CC=gcc
all:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd cosy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
@@ -52,6 +53,7 @@ clean:
install:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd cosy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
@@ -73,6 +75,7 @@ install:
uninstall:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd cosy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall

21
converters/cosy/Makefile Normal file
View File

@@ -0,0 +1,21 @@
# all of these can be over-ridden on the "make" command line if don't suit
# your environment
TOOL=cosy
CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
BIN=/usr/local/bin
INSTALL=install
CC=gcc
$(TOOL): $(TOOL).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $(TOOL) $(TOOL).c $(LDLIBS)
.PHONY: clean install uninstall
clean:
rm -f $(TOOL)
install: $(TOOL)
$(INSTALL) -p -m u=rx,g=rx,o=rx $(TOOL) $(BIN)
uninstall:
rm -f $(BIN)/$(TOOL)

587
converters/cosy/cosy.c Normal file
View File

@@ -0,0 +1,587 @@
/* cosy.c: compress/decompress CDC1700 COSY format files
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JOHN FORECAST BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of John Forecast shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from John Forecast.
*/
/*
* The CDC1700 COSY format is well documented with respect to the compression
* algorithm (Run length encoding of 3 - 62 consecutive blanks) but less so
* for the higher level COSY constructs. This program is written to handle
* COSY format files found on bitsavers.org. It operates in one of 2 modes:
*
* 1. Decompress a sequence of one or more COSY compressed decks. Each deck
* will start with a CSY/ card and end with a END/ card. If the input
* consists of a single compressed deck, the CSY/ and END/ cards may be
* omitted. If a deck name (e.g. "xxx") is provided on the CSY/ card,
* the output file will be named "deck_xxx", if an empty deck name is
* provided or the CSY/ card is missing, the output file will be named
* "nnnnn.deck" where nnnnn is the number of the deck within the input
* file. The CSY/ and END/ cards will not be passed through to the
* output file.
*
* 2. Compress a series of input decks, generating a single compressed COSY
* file. A CSY/ card will be prepended to each input file and a END/
* card will be appended. If the input file name is "deck_yyy" the deck
* name on the CSY/ card will be yyy. Any other input file name will leave
* the deck name empty on the CSY/ card. The output file will be padded
* to a multiple of 192 words (384 bytes).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PREFIX 0x5F
/*
* Record lengths.
*/
#define RECLEN 384
#define CARDLEN 80
char card[CARDLEN + 1], pad[RECLEN];
int idx = 0, outcount = 0;
int compress = 0;
#define VALID(c) ((c >= 0x20) && (c <= 0x5E) && (c != 0x26))
/*
* Pre-defined strings to start and end a COSY deck.
*/
char *csy = " CSY/";
char *end = " END/";
/*
* Compression table
*/
#define MAXSPACES 62
char *compr[MAXSPACES+1] = {
NULL, " ", " ",
"\x5F\x21", "\x5F\x22", "\x5F\x23", "\x5F\x24", "\x5F\x25",
"\x5F\x27", "\x5F\x28", "\x5F\x29", "\x5F\x2A",
"\x5F\x2B", "\x5F\x2C", "\x5F\x2D", "\x5F\x2E",
"\x5F\x2F", "\x5F\x30", "\x5F\x31", "\x5F\x32",
"\x5F\x33", "\x5F\x34", "\x5F\x35", "\x5F\x36",
"\x5F\x37", "\x5F\x38", "\x5F\x39", "\x5F\x3A",
"\x5F\x3B", "\x5F\x3C", "\x5F\x3D", "\x5F\x3E",
"\x5F\x3F", "\x5F\x40", "\x5F\x41", "\x5F\x42",
"\x5F\x43", "\x5F\x44", "\x5F\x45", "\x5F\x46",
"\x5F\x47", "\x5F\x48", "\x5F\x49", "\x5F\x4A",
"\x5F\x4B", "\x5F\x4C", "\x5F\x4D", "\x5F\x4E",
"\x5F\x4F", "\x5F\x50", "\x5F\x51", "\x5F\x52",
"\x5F\x53", "\x5F\x54", "\x5F\x55", "\x5F\x56",
"\x5F\x57", "\x5F\x58", "\x5F\x59", "\x5F\x5A",
"\x5F\x5B", "\x5F\x5C", "\x5F\x5D"
};
int doCompress(FILE *, int, char **), doDecompress(FILE *);
/*++
* compressCard
*
* Write the current card, in COSY compressed format, to the destination
* COSY file.
*
* Inputs:
*
* dest - Destination COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 3 - File write error
* 4 - Invalid input character
*
--*/
int compressCard(
FILE *dest
)
{
int i, spcount = 0, len = strlen(card);
for (i = 0; i < len; i++) {
if (!VALID(card[i]))
return 4;
if (card[i] != ' ') {
if (spcount != 0) {
size_t l = strlen(compr[spcount]);
if (fwrite(compr[spcount], sizeof(char), l, dest) != l)
return 3;
outcount += l;
spcount = 0;
}
if (fputc(card[i], dest) == EOF)
return 3;
outcount++;
} else {
if (++spcount == MAXSPACES) {
size_t l = strlen(compr[spcount]);
if (fwrite(compr[spcount], sizeof(char), l, dest) != l)
return 3;
outcount += l;
spcount = 0;
}
}
}
/*
* Terminate the card image.
*/
fwrite("\x5F\x5E", sizeof(char), 2, dest);
outcount += 2;
return 0;
}
/*++
* decompressCard
*
* Read the next card image from a source file while performing COSY
* decompression. The card image will be null terminated.
*
* Inputs:
*
* src - Source COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* 0 - Card image successfully read
* -1 - EOF read
* -2 - End of deck read
*
--*/
int decompressCard(
FILE *src
)
{
int ch, i, spcount;
idx = 0;
while (((ch = fgetc(src)) != -1) && (ch != 0)) {
if (ch == PREFIX) {
if ((ch = fgetc(src)) == -1)
break;
switch (ch) {
case 0x21: case 0x22: case 0x23: case 0x24: case 0x25:
spcount = ch - 0x21 + 3;
goto fill;
case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B:
case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30:
case 0x31: case 0x32: case 0x33: case 0x34: case 0x35:
case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A:
case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
case 0x45: case 0x46: case 0x47: case 0x48: case 0x49:
case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E:
case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53:
case 0x54: case 0x55: case 0x56: case 0x57: case 0x58:
case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D:
spcount = ch - 0x27 + 8;
fill:
for (i = 0; i< spcount; i++) {
if (idx != CARDLEN)
card[idx++] = ' ';
}
break;
case 0x5E:
card[idx] = '\0';
return 0;
case 0x5F:
card[idx] = '\0';
return -2;
}
} else {
if (idx != CARDLEN)
card[idx++] = ch;
}
}
card[idx] = '\0';
return -1;
}
/*++
* writeCard
*
* Remove trailing spaces from the card image and write the resulting line
* to the destination file with a terminating newline character.
*
* Inputs:
*
* dest - Destination file
*
* Outputs:
*
* ...
*
* Returns:
*
* 0 - write was successful
* -1 - error on write
*
--*/
int writeCard(
FILE *dest
)
{
/*
* Remove trailing spaces.
*/
while (idx && (card[idx - 1] == ' '))
card[--idx] = '\0';
if (fprintf(dest, "%s\n", card) < 0)
return -1;
return 0;
}
/*++
* usage
*
* Display a usage message on stderr and exit.
*
* Inputs:
*
* None
*
* Outputs:
*
* None
*
* Returns:
*
* Never returns
*
--*/
void usage(void)
{
fprintf(stderr,
"Usage: cosy [-cd] <cosyfile> [file ...]\n");
fprintf(stderr,
" Compress/decompress a COSY file\n");
fprintf(stderr, "\nSwitches:\n\n");
fprintf(stderr, " -c Perform COSY compression\n");
fprintf(stderr, " -d Perform COSY decompression (the default)\n");
exit(1);
}
/*++
* main
*
* Entry point for cosy program.
*
* Inputs:
*
* argc - # of supplied arguments
* argv - Array of argument strings
*
* Outputs:
*
* None
*
* Returns:
*
* Exit status
*
--*/
int main(
int argc,
char *argv[]
)
{
int ch;
FILE *cosy;
while ((ch = getopt(argc, argv, "cd")) != -1) {
switch (ch) {
case 'c':
compress = 1;
break;
case 'd':
compress = 0;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < (compress ? 2 : 1))
usage();
/*
* Open the COSY file.
*/
if ((cosy = fopen(argv[0], compress ? "w" : "r")) == NULL) {
fprintf(stderr, "Failed to open COSY file - %s\n", argv[0]);
return 2;
}
argc--, argv++;
if (compress) {
return doCompress(cosy, argc, argv);
}
return doDecompress(cosy);
}
/*++
* doCompress
*
* Compress a sequence of 1 or more files into a single COSY file.
*
* Inputs:
*
* dest - Destination cosy file
* argc - # of source files to compress
* argv - Pointer to array of file names
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 2 - File open error
* 3 - File write error
* 4 - Invalid input character
*
--*/
int doCompress(
FILE *dest,
int argc,
char *argv[]
)
{
int status = 0;
unsigned int i;
char *filename;
FILE *src;
while (argc != 0) {
filename = argv[0];
if ((src = fopen(filename, "r")) == NULL) {
status = 2;
break;
}
/*
* Build a leading CSY/ card.
*/
strcpy(card, csy);
if (strncmp(filename, "deck_", 5) == 0) {
/*
* Possible deck name derived from filename.
*/
if (strlen(filename) <= 11) {
for (i = 5; i < strlen(filename); i++)
if (!VALID(filename[i]))
goto noname;
strncpy(card, &filename[5], strlen(filename) - 5);
goto named;
}
noname:
fprintf(stderr, "Unable to use filename (%s) for deck name\n", filename);
}
named:
if ((status = compressCard(dest)) != 0)
break;
/*
* Copy the source file to the destination while compressing.
*/
while (fgets(card, sizeof(card), src) != NULL) {
int len = strlen(card);
if (card[len - 1] == '\n')
card[len - 1] = '\0';
if ((status = compressCard(dest)) != 0)
goto error;
}
/*
* Build a trailing END/ card.
*/
strcpy(card, end);
if ((status = compressCard(dest)) != 0)
break;
fclose(src);
argc--, argv++;
}
error:
/*
* Report possible error.
*/
switch (status) {
case 0:
if ((outcount % RECLEN) != 0)
fwrite(pad, sizeof(char), outcount % RECLEN, dest);
break;
case 2:
fprintf(stderr, "Failed to open file - %s\n", filename);
break;
case 3:
fprintf(stderr, "Error writing COSY file\n");
break;
case 4:
fprintf(stderr, "Invalid character in file - %s\n", filename);
break;
default:
fprintf(stderr, "Unknown exit status - %u\n", status);
break;
}
fclose(dest);
return status;
}
/*++
* doDecompress
*
* Decompress a COSY file.
*
* Inputs:
*
* src - Source COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 2 - File open error
* 3 - File write error
*
--*/
int doDecompress(
FILE *src
)
{
int seqno = 0, valid;
char filename[32], *eofn;
FILE *dest = NULL;
while (decompressCard(src) == 0) {
/*
* First card of next deck has been read - is is a CSY/ card?
*/
sprintf(filename, "%05u.deck", seqno);
valid = 1;
if (strncmp("CSY/", &card[7], 4) == 0) {
if (card[0] != ' ') {
if ((eofn = strchr(card, ' ')) != NULL) {
int len = eofn - card;
if (len <= 6) {
*eofn = '\0';
sprintf(filename, "deck_%s", card);
}
}
}
valid = 0;
}
if ((dest = fopen(filename, "w")) == 0) {
fprintf(stderr, "Failed to create file - %s\n", filename);
return 2;
}
/*
* If the first line was not a CSY/ card, write to the destination file
*/
if (valid) {
if (writeCard(dest) == -1) {
fprintf(stderr, "Error writing to file - %s\n", filename);
fclose(dest);
return 3;
}
}
/*
* Now process the rest of this file.
*/
while (dest != NULL) {
switch (decompressCard(src)) {
case 0:
if (strncmp("END/", &card[7], 4) == 0) {
fclose(dest);
dest = NULL;
break;
}
if (writeCard(dest) == -1) {
fprintf(stderr, "Error writing to file%s\n", filename);
fclose(dest);
return 3;
}
break;
case -1:
fclose(dest);
return 0;
case -2:
fclose(dest);
dest = NULL;
break;
}
}
seqno++;
}
return 0;
}

24
converters/cosy/cosy.txt Normal file
View File

@@ -0,0 +1,24 @@
cosy manipulates files in the CDC1700 COSY format (note this is different from
the CDC3000 series COSY format). COSY is a format used for containing card
images as ASCII files using run length encoding of 3 or more spaces to reduce
the amount of space required. Multiple card decks may be present in a single
COSY file. File naming in the host environment makes use of the deck name
which is optionally present in the CSY/ cards. For decompression, if a deck
name is present, the host file will be named "deck_<deckname>" otherwise it
will be named "nnnnn.deck" where nnnnn is the position number of the deck
within the COSY file. On compression, source files named "deck_<deckname>"
will result in the CSY/ deckname being filled in otherwise an empty name wil
be used.
To compress a COSY format file:
cosy -c <cosyFile> file ...
To decompress a COSY format file:
cosy -d <cosyFile>
When decompressing a COSY format file, CSY/ and END/ card images are removed
from the output. On compression, a CSY/ card image is inserted at the start
of the output and a END/ card is appended to the output. The resulting
compressed file will be padded, with NULLs, to be a multiple of 384 bytes.

Binary file not shown.