# /* Unix command for system running under Ersatz-11 PDP-11 simulator to read * file from host file system into a Unix file; works with DOS device * device driver. * * If no Unix file name is given, it defaults to the same as the host * file name. If the full path fails on creation, it tries again with * just the last element (i.e. in the current directory). * * The -a flag (which defaults on), used with ASCII files, converts file * from DOS/WINDOWS standard for ACII files (CRLF line endings) to Unix * standard (LF endings). * The -b flag supresses the -a flag behaviour (i.e. it transfers the file * as a raw file). * The -t flag suppresses printing of the total amount transferred (given * in blocks+bytes). * The -d flag prints debugging info. */ /* DOS device information */ #include "/usr/sys/dos.h" struct hsterrs { int ds_errno; char *ds_errstr; }; int *herrtbl[] { RC_NXM, "Bus timeout", RC_NOT, "File or directory does not exist", RC_INVH, "Invalid handle", RC_INSM, "Insufficient memory", RC_PERM, "Permission denied", RC_FEX, "File exists", RC_CROSS, "Cross-device link", RC_INV, "Invalid command or argument", RC_TOO, "Too many open files", RC_NOSPC, "No space left on device", RC_RDEAD, "Resource deadlock would occur", 0, 0 }; struct sargs { char op; char mode; char *nm; int len; } sargs; /* Unix stuff */ extern int errno; extern char *sys_errlist[]; /* Command stuff */ #define BLKSIZ 512 /* Padding is for CR/LF conversion on */ #define BPAD 2 /* block boundary */ int dflg; /* Debugging */ int aflg 1; /* ASCII conversion */ int tflg; /* Suppress printing of totals */ int dosdev, ofile; char ibuf[BLKSIZ]; char obuf[BLKSIZ + BPAD]; /* Assume that read of less than requested amount indicated EOF. */ main(argc, argv) char **argv; { register char *ibp, *obp, *fnmp; char *arg, *ifnm, *ofnm, *bufp; char pc, c; int sval, nblks, skip; int iblksiz, blksiz, oblksiz; if (argc < 2) { printf("hostrd {-a} {-b} {-t} {-d} {unixfn}\n"); exit(1); } argv++; for (argc--; (argc > 0); argc--) { arg = *argv; if (*arg++ != '-') break; argv++; switch (*arg) { case 'a': aflg++; break; case 'b': aflg = 0; break; case 't': tflg++; break; case 'd': dflg++; break; default: printf("Bad flag: %c", *arg); exit(1); } } dosdev = open("/dev/dos", 0); if (dosdev < 0) serror("Cannot open DOS device"); if (dflg) printf("dosdev file %d\n", dosdev); ifnm = *argv++; argc--; sargs.op = DC_FOPEN; sargs.mode = CM_RO; sargs.nm = ifnm; sargs.len = strlen(ifnm); if (dflg) printf("'%s' %d\n", sargs.nm, sargs.len); sval = stty(dosdev, &sargs); if (sval < 0) hsterr("Can't open input file on host"); ofnm = ((argc == 0) ? ifnm : *argv++); ofile = creat(ofnm, 0664); if (ofile < 0) { fnmp = ofnm; while (*fnmp != '\0') if (*fnmp++ == '/') ofnm = fnmp; ofile = creat(ofnm, 0664); } if (ofile < 0) serror("Cannot open output file"); if (dflg) printf("unix file '%s' %d\n", ofnm, ofile); pc = '\0'; iblksiz = BLKSIZ; if (aflg) bufp = &obuf[0]; else bufp = &ibuf[0]; for (nblks = 0; (iblksiz >= BLKSIZ); nblks++) { iblksiz = read(dosdev, &ibuf[0], BLKSIZ); if (iblksiz < 0) hsterr("Can't read input file on host"); if (dflg) printf("read %d\n", iblksiz); /* Algorithm for de-stuffing is that if a CR is seen, * it is held until the next character is processed; at * that point, if it's not a NL, both the CR and the * next character are put in the buffer, otherwise just * the NL (and the buffer-size byte count is adjusted). * * At a block boundary, handling of a trailing CR is * deferred and done as the 'first' char in the next block * (to try and find a matching NL as the actual first char * in the new buffer-full). * This means that if the last char in the previous block * was a CR, and the first char in the new block is not a * NL, that CR is effectively prepended to the next output * buffer. * The exception is a trailing CR in the last block, which * is done then and there. * * The order of the two CR tests is important, if a CR-CR * sequence is to be handled properly. */ if (aflg) { ibp = &ibuf[0]; obp = &obuf[0]; skip = 0; if (pc == '\r') iblksiz++; for (blksiz = 0; (blksiz < iblksiz); blksiz++) { c = *ibp++; if ((pc == '\r') && (c == '\n')) { *obp++ = '\n'; skip++; pc = c; continue; } if (pc == '\r') *obp++ = '\r'; if (c == '\r') { pc = c; continue; } *obp++ = c; pc = c; } blksiz =- skip; if ((c == '\r') && (iblksiz >= BLKSIZ)) blksiz--; } else blksiz = iblksiz; oblksiz = write(ofile, bufp, blksiz); if (oblksiz < 0) serror("Output file write failed"); if (dflg) printf("write %d %d %d\n", iblksiz, blksiz, oblksiz); } if (iblksiz == BLKSIZ) blksiz = 0; else nblks--; if (!tflg) printf("Xfer complete: %d+%d\n", nblks, iblksiz); close(dosdev); close(ofile); exit(0); } hsterr(errstr) char *errstr; { register struct hsterrs *dp; int gval, hstrc; printf("%s\n", errstr); gval = gtty(dosdev, &sargs); if (gval < 0) serror("Can't retrieve host error code"); hstrc = sargs.op; for (dp = &herrtbl[0]; (dp->ds_errno != 0); dp++) if (dp->ds_errno == hstrc) break; if (dp->ds_errno == 0) printf("Unknown host error %d\n", hstrc); else printf("Host error: %s\n", dp->ds_errstr); serror("Unix error"); } serror(errstr) char *errstr; { char *s; if (errstr != 0) printf("%s: ", errstr); s = sys_errlist[errno]; printf("%s\n", s); exit(1); }