dick@tjalk.UUCP (Dick Grune) (12/23/84)
This is part 2 of 2 of my magtape handing package. Dick Grune Vrije Universiteit de Boelelaan 1081 1081 HV Amsterdam the Netherlands ... and my name isn't Richard! : ------------------------------------------ cut here and feed to /bin/sh echo x \a\n\s\i\w\.\c cat >\a\n\s\i\w\.\c <<'<<>EndOfFile<>>' #define MSGUSE "Usage: ansiw [-cfhlmignpv] [ file ... ]" #include "ansi.h" #include <sys/types.h> #include <pwd.h> #include <time.h> #include <ident.h> /* declares char myname[] */ /* * Name: ansiw, write ANSI standard labelled tape * Author: Dick Grune * Version: 820314 */ #define MAXBLK 2048 #define MINBLK 18 #define FILLER '^' extern time_t time(); extern struct tm *localtime(); extern struct passwd *getpwuid(); char iflag = FALSE, gflag = FALSE, pflag = FALSE, vflag = FALSE; char block[MAXBLK]; struct DD { long size; long lrecl; char ascii95; char example; } dd; struct DD empty_dd = {0L, 0L, TRUE, EOS}; #define divis(m, n) ((n)!=0&&(m)%(n)==0) main(argc, argv) int argc; char *argv[]; { argc--; argv++; if (argc > 0) { if (argv[0][0] == '-') { char *pp = argv[0]; while (*++pp) switch (*pp) { case 'c': unit = TP_CDEV; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'f': unit = TP_IMAG; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'g': gflag = TRUE; break; case 'h': nmdns = TP_DENH; break; case 'i': iflag = TRUE; break; case 'l': nmdns = TP_DENL; break; case 'm': unit = *++pp - '0'; break; case 'n': unit = TP_IMAG; nmdns = "/dev/null"; break; case 'p': pflag = TRUE; break; case 'v': vflag = TRUE; break; default: goto Lbad; } argc--; argv++; } } tf = tpopen(unit, nmdns, "w"); check_args(argc, argv); lblVOL1(iflag || vflag ? ASK_SUG : ASK_NO); while (argc-- != 0) { strcpy(filename, argv[filseqnum]); filseqnum++; blkcount = 0; opendd(filename); if (file == NULL) { printf(">>> File %s ", filename); errors("has suddenly disappeared!!!"); } lblHDR1(iflag ? ASK_SUG : ASK_NO); lblHDR2(iflag ? ASK_SUG : ASK_NO); wrt_tm(); copy(); wrt_tm(); lblEOF1(); lblEOF2(); wrt_tm(); } wrt_tm(); tpclose(tf); exit(0); Lbad: errors(MSGUSE); } check_args(c, v) char *v[]; { char ok = TRUE; while (c-- > 0) { int f = open(*v, 0); if (f < 0) { printf("Cannot open %s\n", *v); ok = FALSE; } else VOID(close(f)); v++; } if (!ok) errors("Stop"); } wrt_tm() /*writes a tapemark*/ { tpwrite(tf, "", 0); } long tab(p) long p; { /* the position in which a tab from p would land */ return (p/8+1)*8; } /* * `opendd' opens the file `fn' and determines its `dd' parameters */ opendd(fn) char *fn; { int ch; long lr; dd = empty_dd; if ((file = fopen(fn, "r")) == NULL) return; lr = 0L; while ((ch = getc(file)) != EOF) { dd.size++; if (ch == NL) { if (lr > dd.lrecl) dd.lrecl = lr; lr = 0L; } else if (ch == TAB) { lr = tab(lr); } else { lr++; if (!Ascii95(ch)) { dd.ascii95 = FALSE; dd.example = ch; } } } if (lr > dd.lrecl) dd.lrecl = lr; VOID(fclose(file)); file = fopen(fn, "r"); } /* * the writing of labels */ lblVOL1(md) { struct passwd *pwd = getpwuid(getuid()); str2fld("", Whole(VOL1buf)); str2fld("VOL1", Labidf(VOL1buf)); enq_fld("\ The `volume serial number' is the six-character identification\n\ number of the tape itself, as it should appear on the sticker on\n\ the reel. When in doubt, use the default %s.\n", md, "222222", Volidf(VOL1buf)); enq_fld("\ The `volume accessibility symbol' is a single character,\n\ recorded on the tape, which indicates how publicly accessible the\n\ whole tape is. It is not well defined, but a single space is\n\ generally taken to mean: accessible by anybody.\n", md, " ", Volacc(VOL1buf)); enq_fld("\ The `owner identification' is the name of the owner, as recorded\n\ on the tape. On some systems it interacts with the file\n\ accessibility symbol. When in doubt, specify a short string of\n\ letters.\n", pwd == NULL ? ASK_YES : md, pwd->pw_name, Ownidf(VOL1buf)); str2fld("1", Labvers(VOL1buf)); tpwrite(tf, Whole(VOL1buf)); } lblHDR1(md) { time_t tnow = time((time_t*)0); struct tm *timeptr = localtime(&tnow); str2fld("", Whole(HDR1buf)); str2fld("HDR1", Labidf(HDR1buf)); enq_fld("\ The `file identifier' is the name of the file, as recorded on\n\ the tape. When in doubt, specify a six-letter mnemonic name.\n", md, filename, Fileidf(HDR1buf)); fld2fld(Volidf(VOL1buf), Filesetidf(HDR1buf)); int2fld(filsecnum, Filsecnum(HDR1buf)); int2fld(filseqnum, Filseqnum(HDR1buf)); enq_num("\ The `generation number' is a counter that some operating systems\n\ attach to a file and that is increased each time the file is\n\ updated. Use 1.\n", gflag ? md : ASK_NO, 1, Gennum(HDR1buf)); enq_num("\ The `generation version number' tells how often an attempt to\n\ write the file to tape has failed. Use 0.\n", gflag ? md : ASK_NO, 0, Genversnum(HDR1buf)); dat2fld(timeptr->tm_year, timeptr->tm_yday+1, Creatdate(HDR1buf)); enq_dat("\ The `expiration date' is the date, recorded on the tape, after\n\ which the file may be overwritten. The format is 2 digits for\n\ the year, followed by 3 digits for the day in the year, e.g.,\n\ 82365 for the last day of 1982. When in doubt, use today's date,\n\ %s, to make the receiver's life easier.\n", md, timeptr->tm_year, timeptr->tm_yday+1, Expirdate(HDR1buf)); enq_fld("\ The `file accessibility symbol' is a single character, recorded\n\ on the tape, which indicates how publicly accessible the file is.\n\ It is not well defined, but a single space is generally taken to\n\ mean: accessible by anybody.\n", md, " ", Fileacc(HDR1buf)); int2fld(blkcount, Blkcount(HDR1buf)); str2fld(myname /* from ident.h */, Syscode(HDR1buf)); tpwrite(tf, Whole(HDR1buf)); } lblHDR2(md) { str2fld("", Whole(HDR2buf)); str2fld("HDR2", Labidf(HDR2buf)); if (!iflag) { str2fld("F", Whole(rectype)); blklength = 1920; reclength = 80; } if (!dd.ascii95) { printf("`%s' contains non-ASCII95 characters, e.g., %s\n", filename, char2str(dd.example)); printf("Perhaps the file code should have been BINARY"); str2fld("U", Whole(rectype)); } if (dd.lrecl > MAXBLK) { printf("`%s' has a record length > %d\n", filename, MAXBLK); printf("Only U-format is possible\n"); str2fld("U", Whole(rectype)); recformat = format('U'); } else inmood (!dd.ascii95 ? ASK_SUG : md) char *rct = enq_str("\ The `record format' tells how lines from the disk file should be\n\ converted to records to be packed into blocks to be recorded on\n\ tape. Although many formats exist, only two are any good in\n\ Information Interchange:\n\ F (Fixed): spaces are added at the end of the line until its\n\ length is `record length', and `block length'/`record length'\n\ of these records form a block;\n\ U (Undefined): `block length' characters are stored in a block.\n\ Unless the disk file contains non-ASCII characters, use F.\n", mood, fld2str(Whole(rectype))); iferr (strlen(rct) != 1 || (recformat = format(rct[0])) == NULL || recformat->cpblk == NULL) printf( "Only F- and U-formats are allowed for portability\n" ); enderr; str2fld(rct, Whole(rectype)); endmood; (*recformat->checkpar)(md); fld2fld(Whole(rectype), Recformat(HDR2buf)); int2fld(blklength, Blklength(HDR2buf)); int2fld(reclength, Reclength(HDR2buf)); int2fld(bufoffset, Bufoffset(HDR2buf)); tpwrite(tf, Whole(HDR2buf)); } checkF(md) { int lr; inmood (md) getBlklength(mood); iferr (blklength < reclength) printf("Block length < phys. record length (=%D)\n", dd.lrecl); enderr; endmood; lr = dd.lrecl; while (!divis(blklength, lr)) lr++; if (lr < 80 && divis(blklength, 80)) lr = 80; reclength = lr; inmood (md) reclength = enq_int("\ The `record length' is the number of characters into which each\n\ line (record) is stretched before it is written to tape. It must\n\ divide the block length. Unless the receiver has been very\n\ specific, use %s.\n", mood, reclength, blklength); iferr (reclength == 0 || !divis(blklength, reclength)) printf( "The block length is not a multiple of the record length\n" ); enderr; iferr (reclength < dd.lrecl) printf("Record length < phys. record length (=%D)\n", dd.lrecl); enderr; endmood; } checkU(md) { getBlklength(md); reclength = blklength; } getBlklength(md) { inmood (md) blklength = enq_int("\ The `block length' is the number of characters in each physical\n\ block written to tape. Unless the receiver has specified\n\ something else, use %s.\n", mood, rectype[0] == 'F' && dd.lrecl > 1920 ? MAXBLK : !iflag ? 1920 : blklength, MAXBLK); iferr (blklength < MINBLK) printf("The minimum block length is %d\n", MINBLK); enderr; endmood; } lblEOF1() { str2fld("EOF1", Labidf(HDR1buf)); int2fld(blkcount, Blkcount(HDR1buf)); tpwrite(tf, Whole(HDR1buf)); } lblEOF2() { str2fld("EOF2", Labidf(HDR2buf)); tpwrite(tf, Whole(HDR2buf)); } /* * the copying of the file */ copy() { int size; blkcount = reccount = 0; while ((size = (*recformat->cpblk)()) > 0) { while (size < MINBLK) block[size++] = FILLER; tpwrite(tf, block, size); ++blkcount; } VOID(fclose(file)); if (pflag) { printf("File name: %s\n", filename); printf("Record format: %s\n", rectype); printf("Block length: %d; number of blocks: %d\n", blklength, blkcount); printf("Record length: %d; number of records: %d\n\n", reclength, reccount); } } int cpFblk() { int ch; int count = 0; while (count < blklength && (ch = getc(file)) != EOF) { int rpos = 0; reccount++; while (ch != NL && ch != EOF) { if (ch == TAB) { int nrpos = (int)tab((long)rpos); while (rpos < nrpos) { block[count++] = SP; rpos++; } } else { block[count++] = ch; rpos++; } ch = getc(file); } while (rpos < reclength) { block[count++] = SP; rpos++; } } return count; } int cpUblk() { int ch; int count = 0; while (count < blklength && (ch = getc(file)) != EOF) { block[count++] = ch; } if (count > 0) reccount++; return count; } FORMAT formats[] = { {'F', checkF, cpFblk}, {'U', checkU, cpUblk}, {'D', NULL, NULL}, {'S', NULL, NULL}, {EOS, NULL, NULL} }; /* * the setting of fields */ int2fld(n, addr, size) char *addr; { addr += size; while (size-- > 0) { *--addr = n % 10 + '0'; n = n / 10; } } dat2fld(y, d, date, size) char *date; { if (size != 6) abort(); str2fld("", Sp(date)); int2fld(y, Year(date)); int2fld(d, Yday(date)); } enq_fld(expl, md, def, addr, size) char *expl, *def, *addr; { char *ans; inmood (md) ans = enq_str(expl, mood, def); iferr (strlen(ans) == 0) printf("No empty answer allowed\n"); enderr; iferr (strlen(ans) > size) printf("The %s is too long\n", expl2str(expl)); printf("The maximum length is %d character%s\n", english(size)); enderr; iferr (!isascstr(ans)) printf("The %s `%s' contains non-printing chars\n", expl2str(expl), ans); enderr; endmood; str2fld(ans, addr, size); } enq_num(expl, md, n, addr, size) char *expl, *addr; { int2fld(enq_int(expl, md, n, tento(size)-1), addr, size); } int tento(n) { int res = 1; while (n--) res *= 10; return res; } enq_dat(expl, md, y, d, date, size) char *expl; char *date; { dat2fld(y, d, date, size); inmood (md) char *ans = enq_str(expl, mood, fld2str(date, size)); char *adt = (*ans == SP ? ans : ans - 1); y = fld2int(Year(adt)); d = fld2int(Yday(adt)); iferr (y < 0 || d <= 0 || d > (divis(y, 4) ? 366 : 365)) printf("`%s' is not an acceptable date\n", ans); enderr; endmood; dat2fld(y, d, date, size); } locate() { return; } <<>EndOfFile<>> if test "43395 12" != "`sum \a\n\s\i\w\.\c`" then echo Checksum error; fi echo x \c\p\t\p\.\1 cat >\c\p\t\p\.\1 <<'<<>EndOfFile<>>' .TH CPTP I .SH NAME cptp \- copy from tape to tape .SH SYNOPSIS .B cptp [ .B \-x ] [ .BR of= file | .BR if= file ] .SH DESCRIPTION .I Cptp converts between real tapes and tape images on disk. The .B of= parameter causes .I cptp to read the real magtape and produce a tape image on the indicated file. A call with an .B if= parameter will write back the tape image from the indicated file to the real magtape. .PP The program accepts the usual .B \-cfhlm parameters to describe the tape (see .IR mag (I)). If the .BI \-x -option is given, copying will continue regardless of read-errors or consecutive tape marks (default is stopping after 4 consecutive TMs). .SH "SEE ALSO" mag(I), rawtp(I), survey(I) <<>EndOfFile<>> if test "58332 1" != "`sum \c\p\t\p\.\1`" then echo Checksum error; fi echo x \c\p\t\p\.\c cat >\c\p\t\p\.\c <<'<<>EndOfFile<>>' #define MSGUSE "Usage is: cptp [-cfhlmx] [of=file | if=file]" #include <stdio.h> #include "tp.h" /* * Name: cptp, copy tape * Author: Dick Grune * Version: 820314 * * `Cptp' converts between real tapes and tape images on disk. */ int unit = 0; char *nmdns = TP_DENN; char *rx = "r"; TPFILE *from, *to; extern FILE *tperr; char *filename; int size; char buff[TP_MAXB]; main (argc, argv) char *argv[]; { char *arg; argc--; argv++; if (argc > 0) { if (argv[0][0] == '-') { char *pp = argv[0]; while (*++pp) switch (*pp) { case 'c': unit = TP_CDEV; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'f': unit = TP_IMAG; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'h': nmdns = TP_DENH; break; case 'l': nmdns = TP_DENL; break; case 'm': unit = *++pp - '0'; break; case 'x': rx = "rx"; break; default: goto Lbad; } argc--; argv++; } } if (argc != 1) goto Lbad; arg = argv[0]; if (arg[0] == '\0' || arg[1] != 'f' || arg[2] != '=') goto Lbad; filename = &arg[3]; tperr = stdout; switch (arg[0]) { case 'o': if (open(filename, 0) > 0) error("Output file already exists"); from = tpopen(unit, nmdns, rx); to = tpopen(TP_IMAG, filename, "w"); break; case 'i': from = tpopen(TP_IMAG, filename, "r"); to = tpopen(unit, nmdns, "w"); break; default: goto Lbad; } while ((size = tpread(from, buff, TP_MAXB)) != EOF) { if (size == TP_MAXB) printf("Block too long; information may be lost\n"); tpwrite(to, buff, size); } tpclose(from); tpclose(to); exit(0); Lbad: error(MSGUSE); } error(str) char *str; { fprintf(stderr, "%s\n", str); exit(1); } <<>EndOfFile<>> if test "38362 2" != "`sum \c\p\t\p\.\c`" then echo Checksum error; fi echo x \e\t\o\a\.\c cat >\e\t\o\a\.\c <<'<<>EndOfFile<>>' char _etoa[] = { 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041, 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136, 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377 }; <<>EndOfFile<>> if test "55504 2" != "`sum \e\t\o\a\.\c`" then echo Checksum error; fi echo x \l\l\i\b\-\l\m\a\g cat >\l\l\i\b\-\l\m\a\g <<'<<>EndOfFile<>>' /*LINTLIBRARY*/ #include "etoa.c" #include "tpread.c" #include "tpwrite.c" #include "tpopen.c" #include "tpclose.c" #include "tpname.c" #include "tpwtmloc.c" #include "tprdloc.c" #include "tpwloc.c" printf(f, p1, p2, p3, p4, p5, p6, p7, p8, p9) char *f; int p1, p2, p3, p4, p5, p6, p7, p8, p9; {return;} fprintf(ff, f, p1, p2, p3, p4, p5, p6, p7, p8, p9) FILE *ff; char *f; int p1, p2, p3, p4, p5, p6, p7, p8, p9; {return;} <<>EndOfFile<>> if test "40648 1" != "`sum \l\l\i\b\-\l\m\a\g`" then echo Checksum error; fi echo x \m\a\g\.\1 cat >\m\a\g\.\1 <<'<<>EndOfFile<>>' .TH MAG I .SH NAME mag \- generalized magnetic tape .SH SYNOPSIS .PP .B cptp [ .B -x ] [ .BR of= file | .BR if= file ] .PP .B rawtp name [ .B \-x ] [ param ... ] .PP .B survey [ .B \-px ] .PP .B ansir [ .B \-ijnpg ] [ name ... ] .PP .B ansiw [ .B \-ignpv ] [ file ... ] .PP .B NOSsplit [ .B \-s N ] [ name ] .SH DESCRIPTION These programs have in common that they use a 'generalized magtape'. Such a generalized magtape may correspond to a real magtape or to a tape image i.e., a normal file with a specific structure which contains all information present on a tape, including block sizes and tape marks. Conversion between real tapes and tape images is done by .IR cptp (I). .PP The generalized magtape is described by the following parameters which apply to all the above programs. .TP .BI \-m d the magtape is real and on unit .IR d . .TP .B \-h the magtape is real and in high density. .TP .B \-l the magtape is real and in low density. .TP .BI \-f " name" the magtape is a tape image on file .IR name . .TP .BI \-c " name" the magtape is the character-device .IR name . .SH AUTHOR Dick Grune. .SH BUGS Conflicts between options are not detected. <<>EndOfFile<>> if test "59389 2" != "`sum \m\a\g\.\1`" then echo Checksum error; fi echo x \m\a\g\.\3 cat >\m\a\g\.\3 <<'<<>EndOfFile<>>' .TH MAG III .SH NAME mag \- implement generalized magtape .SH SYNOPSIS .PP .B "#include <tp.h>" .PP .B "TPFILE *tpopen(unit, nmdns, rwx) char *nmdns, *rwx;" .PP .B "tpclose(tf) TPFILE *tf;" .PP .B "int tpread(tf, buf, size) TPFILE *tf; char *buf;" .PP .B "tpwrite(tf, buf, size) TPFILE *tf; char *buf;" .PP .B "FILE *tperr;" .SH DESCRIPTION These routines implement the generalized magtape described in .IR mag (I). Such a generalized magtape is viewed as a sequence of blocks each of which is written and read in one piece. A tape mark is represented as a block of length 0. The blocks correspond to physical blocks on tape (as separated by Interrecord Gaps). On a tape image each block is preceded by its length in format "%08d". .PP A generalized magtape is handled by these routines as a pointer to a TPFILE. Such a pointer is obtained from .IR tpopen . The .I unit and the .I nmdns describe the generalized magtape; these are the possibilities: .PP a real magtape: .I unit is a small non-negative integer (the unit number); .I nmdns is TP_DENL, TP_DENN or TP_DENH (for low, normal or high density). .PP a tape image: .I unit is TP_IMAG; .I nmdns is the file name. .PP a character device: .I unit is TP_CDEV; .I nmdns is the device name. .PP The third parameter .I rwx is either "r" or "rx" for reading or "w" for writing; "rx" suppresses the recognition of end-of-file in real magtapes (see .IR tpread ). .PP .I Tpclose closes a generalized magtape; this causes a rewind and makes room for other such files, since only a limited number (specified in _TP_MOPEN) can be open at the same time. .PP .I Tpread reads one block into .I buf to a maximum of .I size characters. The rest of the block, if present, is skipped. It returns the number of characters read, or 0 for a tape mark, or EOF for an end-of-file. On a tape image file the end-of-file coincides with the actual end-of-file. On a real magtape or on a character device three conditions can cause an end-of-file: .IP 4 consecutive tape marks, .br 2 consecutive read errors, or .br 1 read error preceded by a tape mark, .PP unless "rx" was specified in the call of .IR tpopen , in which case only 100 consecutive read errors will cause an end-of-file (to prevent the program from looping on end-of-reel). .PP .I Tpwrite writes one block from .I buf if .I size > 0, or a tape mark if .I size = 0. .SH DIAGNOSTICS If an error condition (other than end-of-file) is found, a message is printed on the stream .I tperr (default is .IR stderr ), and the program exits. .SH AUTHOR Dick Grune. <<>EndOfFile<>> if test "43710 3" != "`sum \m\a\g\.\3`" then echo Checksum error; fi echo x \r\a\w\t\p\.\1 cat >\r\a\w\t\p\.\1 <<'<<>EndOfFile<>>' .TH RAWTP I .SH NAME rawtp \- read raw tape .SH SYNOPSIS .B rawtp name [ .B \-x ] [ param ... ] .SH DESCRIPTION .I Rawtp extracts arbitrary portions from a magtape. .PP The program accepts the usual .B \-cfhlm parameters to describe the tape (see .IR mag (I)). The additional .BR \-x -option will cause .I rawtp to continue reading regardless of read-errors or consecutive tape marks (normally .I rawtp stops after 4 consecutive tape marks). .PP The tape is considered as a series of files, each terminated by a tape mark (TM); a file is considered as a series of blocks, each terminated by an InterRecord Gap (IRG); a block consists of characters. .PP An instruction .I +t.i.c or .I \-t.i.c moves the tape over .I t TM's, .I i IRG's (but not over a TM) and .I c characters (but not over an IRG). If the instruction begins with a .I + the contents are copied to a file, a .I \- just skips the contents. .PP Instructions may be concatenated into an instruction series. If an instruction sequence is followed by .BI x n the effect is repeated .I n times. If .I n is absent or 0, the instruction series is repeated until it becomes ineffective. E.g., .I +.1\-1x will give you the first block of each file on tape. Default parameter is .I +1x which splits the tape into its separate files. .PP The produced files are named .I namepprrrii where .I name is the first argument, .I pp is the two-digit parameter number, .I rrr is a three-letter counter counting the number of repetitions of the parameter, and .I ii is the two-digit instruction number within the parameter. .PP Example: .br rawtp tp \-10 +..80\-3x will skip 10 files, and then give the first 80 characters of the first block of every third file on the files .IR tp02aaa01 , .IR tp02aab01 , etc, (if present.) .SH "SEE ALSO" mag(I), cptp(I), survey(I) <<>EndOfFile<>> if test "03147 2" != "`sum \r\a\w\t\p\.\1`" then echo Checksum error; fi echo x \r\a\w\t\p\.\c cat >\r\a\w\t\p\.\c <<'<<>EndOfFile<>>' #define MSGUSE "Usage is: rawtp [-cfhlmx] XX [ param ... ]" #include <stdio.h> #include "tp.h" /* * Name: rawtp, read raw tape * Author: Dick Grune * Version: 820314 * Selected portions are read from tape and written to files. */ #define TRUE 1 #define FALSE 0 #define EOS '\0' #define EOB 0 /* End Of Block */ #define EOX -1 /* End Of File (to avoid confusion with EOF) */ #define EOT -2 /* End Of Tape */ #define AT_EOB (ilength <= EOB) #define AT_EOX (ilength <= EOX) #define AT_EOT (ilength <= EOT) char name [128]; char *eoname = &name[0]; FILE *ofile = NULL; TPFILE *tape; extern FILE *tperr; int unit = 0; char *nmdns = TP_DENN; char *rx = "r"; char buff[TP_MAXB]; char *strins(); main(argc, argv) char **argv; { extern int ilength; argc--; argv++; if (argc > 0) { if (argv[0][0] == '-') { char *pp = argv[0]; while (*++pp) switch (*pp) { case 'c': unit = TP_CDEV; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'f': unit = TP_IMAG; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'h': nmdns = TP_DENH; break; case 'l': nmdns = TP_DENL; break; case 'm': unit = *++pp - '0'; break; case 'x': rx = "rx"; break; default: goto Lbad; } argc--; argv++; } } if (argc < 1) goto Lbad; if (**argv == '+' || **argv == '-') goto Lbad; set_name(argv); argc--; argv++; ilength = EOT; /* fake empty tape to test parameters */ params(argc, argv); tape = tpopen(unit, nmdns, rx); tperr = stdout; ilength = EOB; /* and now for keeps */ skipIRG(); params(argc, argv); tpclose(tape); exit(0); Lbad: error(MSGUSE, ""); } set_name(argv) char **argv; { register char *pt; eoname = strins(eoname, *argv); eoname = strins(eoname, "01aaa01"); *eoname = EOS; for (pt = eoname; pt > name; pt--) if (pt[-1] == '/') break; if (eoname - pt > 14) error("%s: file name too long", name); } params(argc, argv) char **argv; { VOID(strins(eoname-7, "01")); if (!argc) param("+1x"); else while (argc--) { param(*argv++); incr(eoname-6); } } char *ppar; /* parameter being processed */ param(arg) char *arg; { register int repl; ppar = arg; repl = getxrepl(ppar); if (repl == 0) repl--; VOID(strins(eoname-5, "aaa")); while (repl-- && instr()) incr(eoname-3); } int moved; int instr() { char *p = ppar; moved = FALSE; VOID(strins(eoname-2, "01")); while (simp_instr(&p)) incr(eoname-1); return moved; } int copy = FALSE; int simp_instr(pp) char **pp; { register int cnt; switch (**pp) { case EOS: case 'x': return FALSE; case '+': copy = TRUE; break; case '-': copy = FALSE; break; default: error("%s: bad parameter", ppar); } (*pp)++; cnt = getint(pp); while (cnt-- && copyfile()) {} if (**pp == '.') (*pp)++; cnt = getint(pp); while (cnt-- && copyblock()) {} if (**pp == '.') (*pp)++; cnt = getint(pp); while (cnt-- && copychar()) {} if (copy) dropfile(); return TRUE; } int ilength; /* ilength contains the number of characters the tape is ahead of the user; * or it is EOX or EOT */ char *iptr; int copyfile() { if (AT_EOT) return FALSE; while (copyblock()) {} skipTM(); return TRUE; } int copyblock() { if (AT_EOX) return FALSE; if (!copy) ilength = EOB; else while (copychar()) {} skipIRG(); return TRUE; } int copychar() { if (AT_EOB) return FALSE; outchar(*iptr); iptr++; ilength--; return TRUE; } outchar(c) { if (!copy) return; if (ofile == NULL) { getfile(); moved = TRUE; } putc(c, ofile); } /* physical tape movers */ skipTM() { if (AT_EOT) return; ilength = EOB; skipIRG(); } skipIRG() { int size; if (AT_EOX) return; size = tpread(tape, buff, TP_MAXB); ilength = size == EOF ? EOT : size == 0 ? EOX : size; iptr = buff; if (!AT_EOT) moved = TRUE; } /* output file registration */ getfile() { if ((ofile = fopen(name, "w")) == NULL) error("%s: cannot create", name); } dropfile() { if (ofile != NULL) VOID(fclose(ofile)); ofile = NULL; } /* service routines */ char * strins(s1, s2) char *s1, *s2; { while (*s2 != EOS) *s1++ = *s2++; return s1; } int getint(pp) char **pp; { register int val, res = 0; for (;;) { val = **pp - '0'; if (val < 0 || val > 9) return res; (*pp)++; res = res*10 + val; } } incr(p) char *p; { (*p)++; if (*p == '9' + 1) { *p = '0'; incr(p-1); } else if (*p == 'z' + 1) { *p = 'a'; incr(p-1); } } int getxrepl(p) char *p; { register int r; while (*p != 'x') if (!*p++) return 1; p++; r = getint(&p); if (*p) error("%s: bad replicator", p); return r; } error(p1, p2) char *p1, *p2; { printf(p1, p2); printf("\n"); exit(1); } <<>EndOfFile<>> if test "12914 5" != "`sum \r\a\w\t\p\.\c`" then echo Checksum error; fi echo x \s\u\r\v\e\y\.\1 cat >\s\u\r\v\e\y\.\1 <<'<<>EndOfFile<>>' .TH SURVEY I .SH NAME survey \- survey contents of a magtape .SH SYNOPSIS .B survey [ .B \-px ] .SH DESCRIPTION .I Survey lists the lengths of the blocks on a magtape. If the .B \-p option is given, the first characters of each block are displayed in ASCII, EBCDIC and hexadecimal. .PP The program accepts the usual .B \-cfhlm parameters to describe the tape (see .IR mag (I)). The additional .BR \-x -option will cause .I rawtp to continue reading regardless of read-errors or consecutive tape marks (normally .I rawtp stops after 4 consecutive tape marks). .SH SEE ALSO mag(I) <<>EndOfFile<>> if test "11624 1" != "`sum \s\u\r\v\e\y\.\1`" then echo Checksum error; fi echo x \s\u\r\v\e\y\.\c cat >\s\u\r\v\e\y\.\c <<'<<>EndOfFile<>>' #define MSGUSE "Usage is: survey [-cfhlmpx]\n" #include "tp.h" #include <ctype.h> #define WIDTH 64 /* * Name: survey, survey contents of magtape * Author: Dick Grune * Version: 820314 */ int unit = 0; char *nmdns = TP_DENN; char *rx = "r"; TPFILE *tf; extern FILE *tperr; char buff[TP_MAXB]; int size; char pflag = 0; main(argc, argv) char *argv[]; { argc--; argv++; if (argc > 0) { if (argv[0][0] == '-') { char *pp = argv[0]; while (*++pp) switch (*pp) { case 'c': unit = TP_CDEV; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'f': unit = TP_IMAG; if (argc < 2) goto Lbad; nmdns = argv[1]; argc--; argv++; break; case 'h': nmdns = TP_DENH; break; case 'l': nmdns = TP_DENL; break; case 'm': unit = *++pp - '0'; break; case 'p': pflag = 1; break; case 'x': rx = "rx"; break; default: goto Lbad; } argc--; argv++; } } if (argc != 0) goto Lbad; tf = tpopen(unit, nmdns, rx); while ((size = tpread(tf, buff, TP_MAXB)) != EOF) { printf("%6d", size); if (pflag) expose(); printf("\n"); } exit(0); Lbad: fprintf(stderr, MSGUSE); exit(1); } int hex(c) char c; { return "0123456789ABCDEF"[c&017]; } expose() { if (size == 0) printf("\t* * * TAPE MARK * * *\n"); else { int i; printf("\t"); for (i = 0; i < WIDTH && i < size; i++) { char c = buff[i]; printf("%c", isascii(c) && (isprint(c) || c == ' ') ? c : '?'); } printf("\n EBC:\t"); for (i = 0; i < WIDTH && i < size; i++) { char c = ebc2asc(buff[i]); printf("%c", isascii(c) && (isprint(c) || c == ' ') ? c : '?'); } printf("\n HEX:\t"); for (i = 0; i < WIDTH/2 && i < size; i++) { char c = buff[i]; printf("%c%c", hex(c>>4), hex(c)); } printf("\n"); } } <<>EndOfFile<>> if test "33446 2" != "`sum \s\u\r\v\e\y\.\c`" then echo Checksum error; fi echo x \t\p\.\h cat >\t\p\.\h <<'<<>EndOfFile<>>' #ifndef TPFILE #ifndef FILE #include <stdio.h> #endif #define TP_CDEV (-1) #define TP_IMAG (-2) #define _TP_PREF 8 struct tpdes { int _tp_unit; /* unit number or TP_IMAG or TP_CDEV */ char *_tp_nmdns; /* density or filename or filename */ char _tp_rw; /* 'r' for reading, 'w' for writing */ char _tp_x; /* 'x' for persistent, ' ' for normal */ char _tp_fildes; /* file descriptor after `open' */ long _tp_blkc; /* block counter */ int _tp_mkc; /* accumulative TM counter */ int _tp_mc; /* consecutive TM counter */ char _tp_eof; /* EOF-flag */ }; #define TPFILE struct tpdes #define char2int(c) ((c)&0377) #define ebc2asc(c) (_etoa[char2int(c)]) #define english(i) (i), (i) == 1 ? "" : "s" /* plural */ #define n_items(a) (sizeof (a)/sizeof (a)[0]) extern TPFILE *tpopen(); extern char *_tpname(); extern char _etoa[]; extern FILE *tperr; /* for error messages */ #ifdef lint int __void__; /* to tell `lint' not to care */ #define VOID(x) (__void__ = (int)(x)) #else lint #define VOID(x) (x) #endif lint #include "tploc.h" #endif <<>EndOfFile<>> if test "21318 2" != "`sum \t\p\.\h`" then echo Checksum error; fi echo x \t\p\L\O\C\.\h cat >\t\p\L\O\C\.\h <<'<<>EndOfFile<>>' /* #define's which may require local modification */ /* * The macros TP_DEN[LNH] define the names of the low-density, * normal-density and high-density tape devices, as double-strings. * The first string indicates the read name, the second the write name; * a ? is replaced by the unit number. */ #define TP_DENL "/dev/rmt?\0/dev/nrmt?" #define TP_DENN TP_DENL #define TP_DENH "/dev/rmth\0/dev/nrmth" #define TP_MAXB 32766 /* largest size parameter to `read' & `write' */ #define _TP_MOPEN 2 /* maximum number of simultaneously open tape-files */ <<>EndOfFile<>> if test "11998 1" != "`sum \t\p\L\O\C\.\h`" then echo Checksum error; fi echo x \t\p\c\l\o\s\e\.\c cat >\t\p\c\l\o\s\e\.\c <<'<<>EndOfFile<>>' #include "tp.h" tpclose(tf) TPFILE *tf; { VOID(close(tf->_tp_fildes)); if (tf->_tp_rw == 'w') { tf->_tp_rw = 'r'; VOID(close(open(_tpname(tf), 0))); } tf->_tp_fildes = 0; } <<>EndOfFile<>> if test "57249 1" != "`sum \t\p\c\l\o\s\e\.\c`" then echo Checksum error; fi echo x \t\p\l\o\c\.\h cat >\t\p\l\o\c\.\h <<'<<>EndOfFile<>>' /* #define's which may require local modification */ /* * The macros TP_DEN[LNH] define the names of the low-density, * normal-density and high-density tape devices, as double-strings. * The first string indicates the read name, the second the write name; * a ? is replaced by the unit number. */ #define TP_DENL "/dev/rmt0\0/dev/nrmt0" #define TP_DENN TP_DENL #define TP_DENH "/dev/rmt8\0/dev/nrmt8" #define TP_MAXB 32766 /* largest size parameter to `read' & `write' */ #define _TP_MOPEN 2 /* maximum number of simultaneously open tape-files */ <<>EndOfFile<>> if test "46780 1" != "`sum \t\p\l\o\c\.\h`" then echo Checksum error; fi echo x \t\p\n\a\m\e\.\c cat >\t\p\n\a\m\e\.\c <<'<<>EndOfFile<>>' #include "tp.h" char * /* transient */ _tpname(tf) TPFILE *tf; { static char name[20]; int unit = tf->_tp_unit; char *nmdns = tf->_tp_nmdns; char *nm = name; if (unit == TP_IMAG || unit == TP_CDEV) return nmdns; if (tf->_tp_rw == 'w') while (*nmdns++) {} do *nm++ = *nmdns == '?' ? unit + '0' : *nmdns; while (*nmdns++); return name; } <<>EndOfFile<>> if test "46315 1" != "`sum \t\p\n\a\m\e\.\c`" then echo Checksum error; fi echo x \t\p\o\p\e\n\.\c cat >\t\p\o\p\e\n\.\c <<'<<>EndOfFile<>>' #include "tp.h" TPFILE * tpopen(unit, nmdns, rwx) char *nmdns, *rwx; { char *name = NULL, *err; static TPFILE tflist[_TP_MOPEN]; TPFILE *tf; for (tf = &tflist[0]; tf->_tp_fildes != 0; tf++) if (tf == &tflist[_TP_MOPEN-1]) { err = "Too many tapes"; goto Lerr; } tf->_tp_unit = unit; tf->_tp_nmdns = nmdns; tf->_tp_rw = 'r'; tf->_tp_x = ' '; while (*rwx) switch (*rwx++) { case 'r': tf->_tp_rw = 'r'; break; case 'w': tf->_tp_rw = 'w'; break; case 'x': tf->_tp_x = 'x'; break; default: err = "Bad option in tpopen"; goto Lerr; } tf->_tp_blkc = tf->_tp_mkc = tf->_tp_mc = tf->_tp_eof = 0; name = _tpname(tf); if (tf->_tp_rw == 'w') { if ((tf->_tp_fildes = creat(name, 0666)) < 0) { err = "cannot create"; goto Lerr; } } else { if ((tf->_tp_fildes = open(name, 0)) < 0) { err = "cannot open"; goto Lerr; } } return tf; Lerr: if (name != NULL) fprintf(tperr, "%s: ", name); fprintf(tperr, "%s\n", err); exit(1); return NULL; } FILE *tperr = stderr; _tprwerr(msg, tf) char *msg; TPFILE *tf; { fprintf(tperr, "After %d tape mark%s, after %D block%s: %s on %s\n", english(tf->_tp_mkc), english(tf->_tp_blkc), msg, _tpname(tf)); } <<>EndOfFile<>> if test "55927 2" != "`sum \t\p\o\p\e\n\.\c`" then echo Checksum error; fi echo x \t\p\r\d\L\O\C\.\c cat >\t\p\r\d\L\O\C\.\c <<'<<>EndOfFile<>>' #include "tp.h" /* * _tprdloc reads one block from a character device. * It must take care of local restrictions. * * This is the PDP11/45 version (even block size). */ int _tprdloc(tf, buf, size) TPFILE *tf; char *buf; { char ch = buf[size]; int sz = read(tf->_tp_fildes, buf, size % 2 ? size + 1 : size); buf[size] = ch; return sz > size ? size : sz; } <<>EndOfFile<>> if test "24065 1" != "`sum \t\p\r\d\L\O\C\.\c`" then echo Checksum error; fi echo x \t\p\r\d\l\o\c\.\c cat >\t\p\r\d\l\o\c\.\c <<'<<>EndOfFile<>>' #include "tp.h" /* * _tprdloc reads one block from a character device. * It must take care of local restrictions. * * This is the VAX version (anything goes). */ int _tprdloc(tf, buf, size) TPFILE *tf; char *buf; { return read(tf->_tp_fildes, buf, size); } <<>EndOfFile<>> if test "65025 1" != "`sum \t\p\r\d\l\o\c\.\c`" then echo Checksum error; fi echo x \t\p\r\e\a\d\.\c cat >\t\p\r\e\a\d\.\c <<'<<>EndOfFile<>>' #include "tp.h" int tpread(tf, buf, size) TPFILE *tf; char *buf; { int res; if (tf->_tp_eof) return EOF; if (tf->_tp_unit != TP_IMAG && tf->_tp_x == ' ' && tf->_tp_mc >= 4) res = EOF; else res = _tp_rd(tf, buf, size); if (res > 0) { tf->_tp_blkc++; tf->_tp_mc = 0; } else if (res == 0) { tf->_tp_mkc++; tf->_tp_mc++; tf->_tp_blkc = 0; } else if (res == EOF) { tf->_tp_mc = 0; } return size < res ? size : res; } int _tp_rd(tf, buf, size) TPFILE *tf; char *buf; { int sz; char ch; if (size <= 0) { buf = &ch; size = 1; } if (tf->_tp_unit == TP_IMAG) { char pref[_TP_PREF]; int n; char ch; n = read(tf->_tp_fildes, pref, _TP_PREF); if (n == 0) return EOF; if (n != _TP_PREF) goto Lformerr; sz = 0; for (n = 0; n < _TP_PREF; n++) { int dig = pref[n] - '0'; if (dig < 0 || dig > 9) goto Lformerr; sz = sz*10 + dig; } n = sz < size ? sz : size; if (n > 0) if (read(tf->_tp_fildes, buf, n) != n) goto Lformerr; while (sz-- > size) if (read(tf->_tp_fildes, &ch, 1) != 1) goto Lformerr; return n; Lformerr: _tprwerr("tape image error", tf); exit(1); } else { int erc = 0; while ((sz = _tprdloc(tf, buf, size)) < 0) { _tprwerr("garbage", tf); erc++; if ( (tf->_tp_x == ' ' && (tf->_tp_mc > 0 || erc >= 2)) || (tf->_tp_x == 'x' && erc >= 100) ) return EOF; } return sz; } return EOF; /* stupid `lint' */ } <<>EndOfFile<>> if test "27746 2" != "`sum \t\p\r\e\a\d\.\c`" then echo Checksum error; fi echo x \t\p\w\L\O\C\.\c cat >\t\p\w\L\O\C\.\c <<'<<>EndOfFile<>>' #include "tp.h" /* * _tpwloc writes one block of non-zero length to a character device. * It must take care of local restrictions. * * This is the PDP11/45 version (even block size). */ int _tpwloc(tf, buf, size) TPFILE *tf; char *buf; { int sz = write(tf->_tp_fildes, buf, size % 2 ? size + 1 : size); return sz > size ? size : sz; } <<>EndOfFile<>> if test "13756 1" != "`sum \t\p\w\L\O\C\.\c`" then echo Checksum error; fi echo x \t\p\w\l\o\c\.\c cat >\t\p\w\l\o\c\.\c <<'<<>EndOfFile<>>' #include "tp.h" /* * _tpwloc writes one block of non-zero length to a character device. * It must take care of local restrictions. * * This is the VAX version (anything goes). */ int _tpwloc(tf, buf, size) TPFILE *tf; char *buf; { return write(tf->_tp_fildes, buf, size); } <<>EndOfFile<>> if test "64955 1" != "`sum \t\p\w\l\o\c\.\c`" then echo Checksum error; fi echo x \t\p\w\r\i\t\e\.\c cat >\t\p\w\r\i\t\e\.\c <<'<<>EndOfFile<>>' #include "tp.h" tpwrite(tf, buf, size) TPFILE *tf; char *buf; { if (tf->_tp_unit == TP_IMAG) { int i, n = size; char pref[_TP_PREF]; for (i = _TP_PREF; i--; ) { pref[i] = n % 10 + '0'; n = n / 10; } if (write(tf->_tp_fildes, pref, _TP_PREF) != _TP_PREF) goto Lerr; if (size > 0) if (write(tf->_tp_fildes, buf, size) != size) goto Lerr; } else { if (size == 0) _tpwtmloc(tf); else if (_tpwloc(tf, buf, size) != size) goto Lerr; } if (size == 0) { tf->_tp_mkc++; tf->_tp_blkc = 0; } else { tf->_tp_blkc++; } return; Lerr: _tprwerr("write error", tf); exit(1); } <<>EndOfFile<>> if test "61518 1" != "`sum \t\p\w\r\i\t\e\.\c`" then echo Checksum error; fi echo x \t\p\w\t\m\l\o\c\.\c cat >\t\p\w\t\m\l\o\c\.\c <<'<<>EndOfFile<>>' #include "tp.h" /* * _tpwtmloc writes a tape mark to a character device. * It must take care of the local restrictions. */ _tpwtmloc(tf) TPFILE *tf; { VOID(close(tf->_tp_fildes)); tf->_tp_fildes = open(_tpname(tf), 1); } <<>EndOfFile<>> if test "33727 1" != "`sum \t\p\w\t\m\l\o\c\.\c`" then echo Checksum error; fi echo x \t\e\s\t\.\i\m\a\g\e cat >\t\e\s\t\.\i\m\a\g\e <<'<<>EndOfFile<>>' 00000080VOL1222222 dick 100000080HDR1READ_ME.TEST 22222200010001000100 82106 82106 000000Math. Centre 00000080HDR2F0192000080 00 0000000000001920SALES TALK If you have one or more magtape units and want to do more with them than just run `tar', this is for you. On the `shell' level this package offers programs for - getting a quick look at a tape, - making exact copies of tapes even if you've got only one magtape unit, - extracting arbitrary portions from tapes and - the reading and writing of ANSI standard labelled tapes. All these programs work equally well on real tapes and on tape images on disk. On the C-level it supplies routines for handling real tapes and tape images on disk as a unified concept (`generalized magtape'). INSTALLATION Take a look at the 4 small files tploc.h tprdloc.c tpwloc.c tpwtmloc.c and decide if they look reasonable on your system. If not, change them or use the files `tp*LOC.?' which come from the PDP11/45. Then call `make all' and the shell commands as described in mag(I) will appear. 00001200 To install the shell commands, change the macro USR (and possibly BIN, LIB, and INC) in the `makefile' and do `make install'. To install the C-routine library `libt.a', do `make crout'. Now do ansir -fp test.image to get a feel for what it does. (Then do it a second time!). CYBER If you happen to have a Control Data Cyber around, running SCOPE or NOS/BE, call `make NOS' to get `NOSsplit', a program for reading Cyber SI-format tapes, and `NOStr' which converts from various Cyber character codes. 0000000000000080EOF1READ_ME.TEST 22222200010001000100 82106 82106 000002Math. Centre 00000080EOF2F0192000080 00 0000000000000000 <<>EndOfFile<>> if test "11352 4" != "`sum \t\e\s\t\.\i\m\a\g\e`" then echo Checksum error; fi