1
0
mirror of https://github.com/DoctorWkt/unix-jun72.git synced 2026-01-11 23:53:34 +00:00

242 lines
4.2 KiB
C

/*
* conv2.c
* Tape file converter for simh
*
* This utility is for converting files to and from the tape format
* used by simh.
*
* 2004 Tim N.
* This code is in the public domain.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int
testeof(FILE *fp)
{
int ch;
if(!feof(fp) && (ch = fgetc(fp)) != -1) {
ungetc(ch, fp);
return 0;
}
return 1;
}
void
xperror(char *msg)
{
perror(msg);
exit(1);
}
FILE *
xfopen(char *fname, char *mode)
{
FILE *fp = fopen(fname, mode);
if(!fp)
xperror(fname);
return fp;
}
void
optfclose(FILE *fp)
{
if(fp)
fclose(fp);
}
int
xreadint(FILE *fp)
{
unsigned char buf[4];
if(fread(buf, sizeof buf, 1, fp) != 1) {
fprintf(stderr, "short read\n");
exit(1);
}
return buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
}
void
xwriteint(FILE *fp, int x)
{
unsigned char buf[4];
buf[0] = x & 0xff;
buf[1] = (x>>8) & 0xff;
buf[2] = (x>>16) & 0xff;
buf[3] = (x>>24) & 0xff;
fwrite(buf, sizeof buf, 1, fp);
}
void
xcopy(FILE *infp, FILE *outfp, int cnt, int allowshort)
{
char buf[512];
int x, r;
while(cnt > 0) {
r = (cnt > sizeof buf) ? sizeof buf : cnt;
if((x = fread(buf, 1, r, infp)) != r) {
if(x && allowshort) {
memset(buf + x, 0, (sizeof buf) - x);
} else {
fprintf(stderr, "short read\n");
exit(1);
}
}
fwrite(buf, 1, r, outfp);
cnt -= r;
}
}
int
convout(FILE *infp, char *fname, int vflag)
{
FILE *outfp = 0;
char buf[128], *p;
unsigned int l, reclen, i, cnt = 0;
int bsize = -1;
p = strrchr(fname, '.');
if(p)
l = p - fname;
else
l = strlen(fname);
if(l + 10 > sizeof buf) {
fprintf(stderr, "use a smaller name\n");
return -1;
}
i = 1;
while(!testeof(infp)) {
reclen = xreadint(infp);
if(reclen == 0x00000000) {
if(vflag) {
if(cnt)
fprintf(stderr, "%s %d@%d -- ", buf, cnt, bsize);
fprintf(stderr, "EOF\n");
}
optfclose(outfp);
outfp = 0;
cnt = 0;
} else if(reclen == 0xffffffff) {
if(vflag) {
if(cnt)
fprintf(stderr, "%s %d@%d -- ", buf, cnt, bsize);
fprintf(stderr, "EOT\n");
}
optfclose(outfp);
break;
} else {
if(reclen > 0x10000) {
/* XXX we dont handle high-bit == error block */
fprintf(stderr, "Bad Format? Got length %d\n", reclen);
return -1;
}
if(cnt && reclen != bsize) {
fprintf(stderr, "Expected %d bytes, got %d bytes\n", bsize, reclen);
return -1;
}
cnt ++;
bsize = reclen;
if(!outfp) {
sprintf(buf, "%.*s-%d.raw", l, fname, i++);
outfp = xfopen(buf, "wb");
}
xcopy(infp, outfp, reclen, 0);
if(xreadint(infp) != reclen) {
fprintf(stderr, "format error\n");
return -1;
}
}
}
return 0;
}
int
convin(FILE *ofile, char *fname, int bsize, int vflag)
{
FILE *ifile = xfopen(fname, "rb");
int cnt = 0;
while(!testeof(ifile)) {
xwriteint(ofile, bsize);
xcopy(ifile, ofile, bsize, 1);
xwriteint(ofile, bsize);
cnt ++;
}
xwriteint(ofile, 0); /* EOF */
if(vflag)
fprintf(stderr, "%s: %d@%d\n", fname, cnt, bsize);
return 0;
}
void
xusage(char *prog)
{
fprintf(stderr, "usage: %s [-v] [-i file.tap | -o file.tap file ...]\n"
"\tWhen using -o, files may be interspersed with [-b bsize]\n"
"\tto specify the block size to use for following files\n"
"\tThe default block size is 512.\n", prog);
exit(1);
}
int
main(int argc, char **argv)
{
FILE *ifile = 0, *ofile = 0;
char *prog;
int i, ocnt = 0, bsize = 512, vflag = 0;
char *ofname = 0, ch;
prog = argv[0];
for(i = 1; i < argc; i++) {
if (*argv[i] == '-') {
ch = argv[i][1];
if(ch == 'v')
vflag ++;
else if(ch == 'b') {
i++;
if(!ofile || !argv[i] || !(bsize = atoi(argv[i])))
xusage(prog);
} else if(ch == 'i') {
if(ifile || ofile || !argv[++i])
xusage(prog);
ifile = xfopen(argv[i], "rb");
if(convout(ifile, argv[i], vflag) == -1)
exit(1);
} else if(ch == 'o') {
if(ifile || ofile || !argv[++i])
xusage(prog);
ofile = xfopen(argv[i], "wb");
ofname = argv[i];
} else
xusage(prog);
continue;
}
if(!ofile)
xusage(prog);
if(convin(ofile, argv[i], bsize, vflag) == -1)
exit(1);
ocnt ++;
}
if(ofile)
xwriteint(ofile, 0); /*EOF*/ /* 0xffffffff); - EOT */
return 0;
}